programmers.co.kr/learn/courses/30/lessons/42578

 

코딩테스트 연습 - 위장

 

programmers.co.kr


문제설명

1. 리스트에 1개 이상의 [의상의 이름, 의상의 종류]이 주어집니다.

ex) [[yellow_hat, headgear], [blue_sunglasses, eyewear], [green_turban, headgear]]

 

2. 최소 한 개 이상의 옷을 착용 한다고 했을 때, 착용 가능한 옷의 조합 수를 구해야 합니다.

 - 동일한 종류의 의상은 착용이 불가능합니다.

ex) 위의 예시에서 yellow_hat과 green_turban은 동시착용이 불가능합니다.

 

문제 풀이

1. 다음과 같은 테스트 케이스가 주어졌다고 가정합니다.

2. 입력받은 데이터는 딕셔너리로 표현될 수 있습니다. 

3. 착용할 수 있는 의상을 종류에 따라 트리로 정리하면 아래와 같습니다.

- 의상 종류별로 입을 수 있는 경우의 수는 "총 개수 + 1" 입니다.

  - 예를 들어, headgear에 관한 경우의 수는 "yellow_hat", "green_turban", "착용X"이 있습니다.

 

따라서 모든 종류의 의상을 착용하지 않는 경우의 수를 제외하면

(headergear의 개수+1) * (eyewear의 개수+1) -1이 정답으로 출력 됩니다.

 

코드

def solution(clothes):
    types = {}
    for v, k in clothes:
        types[k] = types.get(k, 0) + 1

    cnt = 1
    for _, v in types.items():
        cnt *= v+1
    return cnt-1

programmers.co.kr/learn/courses/30/lessons/43165

 

코딩테스트 연습 - 타겟 넘버

n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다. -1+1+1+1+1 = 3 +1-1+1+1+

programmers.co.kr


문제 설명

1. 배열 변수인 numbers가 주어진다. ex) [1, 3, 4, 5, 2]

2. int형 변수인 target이 주어진다.

3. 각 numbers를 무작위로 더하거나 빼서 target 값과 같은 개수는?

 

문제 풀이

1. 모든 경우의 수를 찾아야 하므로 완전 탐색 문제 입니다.

2. 더하거나 뺐을 때 나오는 값을 재귀적으로 실행시킵니다.

3. 경우의 수가 만들어질 때 마다 target 값과 sum 값이 같은지 비교후 리턴 합니다.

  - 같다면, cnt를 1씩 올려줍니다.

4. cnt를 정답으로 제출합니다.

 

코드

def solution(numbers, target):
    def DFS(L, sum):
        nonlocal cnt
        if L == len(numbers):
            if sum == target:
                cnt += 1
            return
        else:
            plus = sum + numbers[L]
            DFS(L + 1, plus)
            minus = sum - numbers[L]
            DFS(L + 1, minus)
            
    cnt = 0
    DFS(0, 0) 
    return cnt

 

'코딩 테스트' 카테고리의 다른 글

[백준] 9009 피보나치  (0) 2021.02.10
[백준] 11967 불켜기  (0) 2021.02.10
[백준, 7490] 0 만들기  (0) 2021.02.02
[백준 9576] 책 나눠주기  (0) 2021.02.02
[백준 1946] 신입사원  (0) 2021.02.02

 

 

코딩테스트 연습 - 구명보트

무인도에 갇힌 사람들을 구명보트를 이용하여 구출하려고 합니다. 구명보트는 작아서 한 번에 최대 2명씩 밖에 탈 수 없고, 무게 제한도 있습니다. 예를 들어, 사람들의 몸무게가 [70kg, 50kg, 80kg, 5

programmers.co.kr


문제

1. 구명보트에 탈 사람들의 몸무게가 리스트(people)로 주어진다. 

2. 구명보트는 최대 2명이 탑승할 수 있다. (단, 구명보트의 최대 탑승 무게(limit) 보다 적어야 한다.)

3. 모든 사람들이 구명보트를 통해 탈출해야 한다.

4. 항상 사람의 무게는 구명보트의 최대 무게보다 작다.

 

문제 특징

1. 효율성 테스트가 상당히 엄격했다. 반드시 1개의 반복문을 통해서만 코드를 작성해야 한다.

2. people이 [30, 40, 60, 70]인 반례 상황이 존재한다. 

[30+40, 60, 70]으로 배를 탈 수도 있지만, [30+70, 40+60]으로 배를 탈 수도 있다. 후자가 문제에서 요구하는 정답이다.

 

알고리즘

- people을 정렬시킨다. 

- 리스트(people)의 맨 앞에서 뒤쪽으로 이동하는 변수를 만든다(front)

- 리스트(people)의 맨 뒤에서 앞쪽으로 이동하는 변수를 만든다(back)

- 반복문에서 back은 항상 왼쪽으로 한 칸씩 움직인다.

- people의 front 번째 값과 back번 째 값을 더해서 limit보다 작거나 같다면 front를 한 칸 오른쪽으로 이동시킨다.

- front보다 back이 작아질 때까지 진행한다.

 

1번 테스트 케이스

people = [70, 50, 80]

limit =  100

 

1. people을 정렬시킨다.

[70, 50, 80] -> [50, 70, 80]

 

2. 

- back과 front를 더하면 limit인 100보다 크므로 front는 가만히 있는다.

- back을 왼쪽으로 한 칸 움직이자

 

3.

- back과 front를 더하면 limit인 100보다 크므로 front는 가만히 있는다.

- back을 왼쪽으로 한 칸 움직이자.

 

- back과 front를 더하면 limit인 100보다 크므로 front는 가만히 있는다.

- back을 왼쪽으로 한 칸 움직이자. (back을 왼쪽으로 움직이면 front보다 앞에 위치하므로, 반복문을 종료한다.)

 

2번 테스트 케이스

people = [30, 40, 50, 60]

limit =  100

 

1. people 정렬한다. [30, 40, 50, 60] -> [30, 40, 50, 60]

 

2.

- back과 front를 더하면 limit인 100보다 작으므로 front도 오른쪽으로 한 칸 움직이자.

- back을 왼쪽으로 한 칸 움직이자. 

 

3.

- back과 front를 더하면 limit인 100보다 작으므로 front도 오른쪽으로 한 칸 움직이자.

- back을 왼쪽으로 한 칸 움직이자. (back이 front보다 앞으로 가게 되므로 반복문이 종료된다.)

 

코드

def solution(people, limit):
    answer = 0
    people = sorted(people)
    front = 0
    back = len(people)-1
    while front < back:
        answer += 1
        if people[front] + people[back] <= limit:
            front += 1
        back -= 1
    return answer

 

 

10282번: 해킹

최흉최악의 해커 yum3이 네트워크 시설의 한 컴퓨터를 해킹했다! 이제 서로에 의존하는 컴퓨터들은 점차 하나둘 전염되기 시작한다. 어떤 컴퓨터 a가 다른 컴퓨터 b에 의존한다면, b가 감염되면

www.acmicpc.net


문제 설명

다익스트라 알고리즘을 사용하는 문제입니다.

 

- 첫 줄의 3 3 1는 각각 컴퓨터 수(n), 의존성 수(d), 감염원번호(c)를 의미합니다.

- 두 번째 줄부터 의존성 수(d)만큼 데이터가 주어집니다.

- 각각은 a, b, s로 "b는 a에 의존하며 s초 후에 감염된다"는 의미를 가지고 있습니다.

- 감염의 시작 c입니다.

 

 

왼쪽과 같은 그림에서 감염이 일어나는 순서는 다음과 같습니다.

- 1은 감염원이므로, 0초 후에 감염이 됩니다.

- 2는 2초 후에 감염이 됩니다

- 3은 8초가 아닌 6초 후에 감염이 됩니다.

 

 

 

각 변수의 조건 범위는 다음과 같습니다.

(1 ≤ n ≤ 10,000, 1 ≤ d ≤ 100,000, 1 ≤ c ≤ n)

(1 ≤ a, b ≤ n, a ≠ b, 0 ≤ s ≤ 1,000)

 

리턴하고자 하는 답은 감염된 컴퓨터의 수와 감염되는데 걸리는 시간입니다.

 

알고리즘 설명

1. 다익스트라 알고리즘으로 문제를 해결하기 위해 아래와 같은 형식으로 데이터를 입력 받습니다.

이 리스트를 data라고 부르겠습니다.

 

 

- 1번 컴퓨터를 2와 3이 의존합니다. 각각은 2초와 8초 후에 감염됩니다.

- 0번 컴퓨터는 없습니다. 문제풀이 편의상 1~(N+1)의 리스트를 만들었습니다.

 

 

2. 각 노드로 갈 수 있는 최소시간을 갱신할 리스트를 만듭니다. 이 리스트를 dy라고 부르겠습니다.

 

dy

 

- timepassed는 x초 후에 감염되는 컴퓨터(a)를 의미합니다.

- 0번 컴퓨터는 없습니다. 문제풀이. 편의상 만들었습니다.

 

다익스트라 알고리즘은 각 노드로 가는 최소값을 구하는 문제입니다.

각 노드는 반복적으로 실행됨으로써 최소값으로 갱신됩니다.

 

문제에서 주어진대로 반복의 시작점은 감염원 번호(c)인 1번 컴퓨터입니다.

따라서 1번 컴퓨터를 0으로 설정합니다.

나머지는 10,000,000으로 설정합니다.

 

10,000,000인 이유는 문제 조건에서 최대 컴퓨터의 개수는 10,000, 감염에 걸리는 최대 시간은 1000이라고 했습니다.

따라서 최종적으로 감염에 걸릴 수 있는 최대 시간은 10,000*1,000인 10,000,000입니다.

 

3. Heap 자료구조를 사용할 리스트를 만듭니다. 이 리스트를 q라고 부르겠습니다.

 

q

 

Heap을 위해 사용할 리스트에 (s+timePassed, a) 형태로 값을 입력받습니다.

s+timePassed는 a번 컴퓨터가 감염될 때까지 걸릴 최종 시간을 의미합니다.

 

 

예를 들어 왼쪽 그림의 경우에는,

2번 컴퓨터는 2초 후에 감염됩니다.

3번 컴퓨터는 2초 + 4초인 6초 후에 감염됩니다.

 

 

 

 

4. 반복문을 수행합니다.

(1) 1번 컴퓨터에서 감염이 시작됩니다.

 

dy

 

(2) data의 1번 컴퓨터에 있는 (2,2), (3,8)를 모조리 꺼냅니다.

 

data

 

(2-1) 2번 컴퓨터의 감염시간인 2초와 dy[1]를 더한 값은 10,000,000보다 작으므로, 

dy[2]를 2+dy[1]인 2로 갱신합니다.

 

dy

 

(2-2) 최소 값을 우선으로 리턴하기 위해 q에 값을 넣습니다.

 

q

 

(2-3) 3번 컴퓨터의 감염시간인 8초와 dy[1]를 더한 값은 10,000,000보다 작으므로, 

dy[3]을 8+dy[1]인 8로 갱신합니다.

 

dy

 

(2-4) 힙 큐 알고리즘을 위한 q에 값을 추가합니다.

 

q

 

(3) q에 있는 최소시간은 2이므로, 힙 큐 알고리즘에 의해 (2,2)를 꺼냅니다.

 

q

 

(3-1) data[2]의 값은 (3,4)입니다. 2초 + 4초인 6초는 dy[3]인 8초보다 작으므로, dy[3]을 6초로 갱신합니다.

 

dy

 

(3-2) q에 값을 추가합니다.

 

q

 

(4) q에 있는 최소시간은 6이므로 (6,3)을 꺼냅니다.

 

q

 

(4-1) data[3]에는 비교대상이 없으므로 dy, queue 리스트의 변화가 없습니다.

 

(5) q에 있는 (8,3)은 이미 dy[3]보다 크므로, 비교/갱신을 진행하지 않고 꺼냅니다.

 

(6) 답을 리턴합니다.

- 1000000을 제외하고 가장 큰 값은 최종 감염시간을 나타냅니다 : 6

- 1000000을 제외한 값의 개수는 감염된 컴퓨터의 수를 나타냅니다 : 3

 

dy

문제풀며 작성한 구상도

문제 풀면서 작성했던 구상도입니다. 혹시 위의 설명으로 부족하신 분은 참고해서 봐주세요

코드

import sys
import heapq

# sys.stdin = open("C:/Users/JIn/PycharmProjects/coding_Test/input.txt", "rt")
numTestcase = int(input())

for _ in range(numTestcase):
    n, d, c = map(int, input().split())    # n : 컴퓨터 수, d : 의존성 수, c : 감염원
    data = [[] for _ in range(n+1)]  # '인덱스'는 의존받는 대상(b), '값'은 [(x초 후 감염, 의존하는 대상(a))]
    for _ in range(d):
        a, b, s = map(int, input().split())    # 감염 방향: b -> a, s초 후 감염
        data[b].append((s, a))

    # 다익스트라 알고리즘
    dy = [100000000] * (n+1)    # 몇 초 후에 감염되는지 저장
    dy[c] = 0    # 감염원(c)은 0초 후에 감염
    q = [(0, c)]
    while q:
        timePassed, infectedCp = heapq.heappop(q)
        if dy[infectedCp] < timePassed:
            continue
        for s, a in data[infectedCp]:
            if dy[a] > s + timePassed:
                dy[a] = s + timePassed
                heapq.heappush(q, (s+timePassed, a))
    time = -1
    nCp = 0
    for i in range(1, n+1):
        if dy[i] != 100000000:
            time = max(time, dy[i])
            nCp += 1
    print(nCp, time)

 

 

programmers.co.kr/learn/courses/30/lessons/42860

 

코딩테스트 연습 - 조이스틱

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA 조이스틱을 각 방향으로 움직이면 아래와 같습니다. ▲ - 다

programmers.co.kr


풀이 전략

조이 스틱 문제는 두 단계의 알고리즘으로 구성된다.

1. 알파벳 올리기 2. 옆으로 이동

 

* 참고로 옆으로 이동하는 알고리즘으로 구현할 때,

왼쪽 방향으로만 이동하거나, 오른쪽 방향으로만 이동할 수 있는 것이 아니다.

- 이런 알고리즘으로 구현하면 11번 테스트 케이스에서 틀린다.

 

왼쪽으로 가다가 오른쪽으로 갈 수도 있다.

ABABAAAAAAABA를 예시로 들 수 있다.

- ABAABAB가 정답이다.

 

1. 알파벳 올리기

- 주어진 문자열을 아스키코드로 변환한다.

    JAN  -> [74, 65, 78]  

- 대문자 A의 아스키코드는 65이므로 각 문자열의 아스키 코드에 65씩 빼준다. 

  [74, 65, 78]  => [9, 0 , 18]

 

- 13보다 작으면, 해당 인덱스의 값만큼 CNT에 더해준다.

- 13보다 크다면, 해당 26에서 해당 인덱스의 값을 빼서 CNT에 더해준다.

 

*13이 기준이 된 이유

- A~Z를 아래와 같이 나열했을 때, 제일 가운데가 되는 숫자가 13이다.

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

 

- 문제 조건에서 알파벳을 A,B,C 순서만이 아니고 A,Z,Y와 같이 역순으로도 셀 수 있다고 했다.

따라서 최소 CNT가 되기 위해 13을 기준으로 한다.

 

2. 옆으로 이동

반복문을 돌며, 각 자리에서 좌측 또는 오른쪽으로 갔을 때 최소의 움직임 횟수를 구한다.

- 0번 인덱스는 중앙에 위치한다.

- 파란색 동그라미를 시작으로 0번 인덱스 왼쪽 방향에 위치한다.

- 0번 인덱스 오른쪽 방향에는 빨간색 동그라미까지 인덱스 값이 위치된다.

- 0번 인덱스의 값을 기준으로, 왼쪽 끝까지 탐색하고 오른쪽 끝까지 위치했을 때 움직임 횟수를 구한다.

- 0번 인덱스의 값을 기준으로, 오른쪽 끝까지 탐색하고 왼쪽 끝까지 위치했을 때 움직임 횟수를 구한다.

- 왼쪽과 오른쪽 중 더 짧은 움직임으로 답을 갱신한다.  (비교될 움직임 횟수의 초기 값은 전체길이 - 1) 

코드

import sys


def solution(name):
    s = name
    r = list()
    
    # 알파벳 올리기/내리기
    for c in s:
        print(ord(c))
        r.append(ord(c) - 65)
    cnt = 0
    for i in r:
        if i <= 13:
            cnt += i
        else:
            cnt += (26 - i)
            
    # 옆으로 이동
    min_movement = len(r) - 1
    for red in range(len(r)):
        blue = red + 1
        while blue < len(r) and r[blue] == 0:
            blue += 1
        center = len(r) + red - blue
        LR, RL = red, len(r) - blue
        min_movement = min(min_movement, center + min(LR, RL))
    return min_movement + cnt

if __name__ == '__main__':
    R = input()
    print(solution(R))

+ Recent posts