물 웅덩이가 없는 경우 해당 위치까지 똑같은 크기만큼 이동했기 때문에 비교할 필요 없이 더하면 됩니다.
물 웅덩이가 있는 경우 값을 0으로 만들어 제외했습니다.
문제링크
def solution(m, n, puddles):
# 매트릭스 제작.
matrix = [[0] * (m + 1) for _ in range(n + 1)]
# 출발, 집 좌표
matrix[1][1] = 1
# DP 시작
for y in range(1, n + 1):
for x in range(1, m + 1):
# 출발 값
if y == 1 and x == 1:
continue
# 웅덩이가 있는 경우 패쓰
if [x, y] in puddles:
matrix[y][x] = 0
else:
# 해당 위치 값은 이전값 2개의 합.
matrix[y][x] = matrix[y - 1][x] + matrix[y][x - 1]
return matrix[n][m] % 1000000007
문제에서 n이 1이상 100이하인 것과 경기 결과가 1개 이상 4,500개 이하인 것을 보고 완전탐색이 가능하다고 판단했습니다.
입출력 예시에서처럼 5번 선수는 다른 선수와 경기를 하지 않아도 2번 선수를 통해서 결과를 유추할 수 있다는 것을 확인할 수 있습니다.
A선수가 B선수를 이기고 B 선수가 C선수를 이긴다면 A가 C를 이긴다는 조건이 성립합니다.( A>B이고 B > C이면 A>C)
유추를 통해 이길 수 있는 선수와 지는 선수를 set 집합을 통해 저장 후 결과를 추출했습니다.
문제링크
def solution(n, results):
# 선수 경기 결과 hash로 저장
matrix = dict()
# 이기는 사람 집합과 지는 사람 집합
for i in range(1, n + 1):
matrix[i] = [set(), set()]
# 경기 결과 입력
for i in results:
matrix[i[0]][0].add(i[1])
matrix[i[1]][1].add(i[0])
# 만약 A > B 이고 B > C 인경우 A>C인 관계(>는 이긴다)
# 모든 선수를 통해 경기하지 않아도 결과를 아는 경우 저장.
for num, match in matrix.items():
if match[0] and match[1]:
for win in match[0]:
matrix[win][1].update(match[1])
for lose in match[1]:
matrix[lose][0].update(match[0])
# 만약 이기는 경우, 지는 경우, 자기 자신의 합이 모든 선수의 수인 경우 +1
answer = 0
for num, match in matrix.items():
if len(match[0]) + len(match[1]) + 1 == n:
answer += 1
return answer
def solution(tickets):
node_dict = {} # 노드 hash화
# 출발지를 key로 도착지를 value로 지정.
for city in tickets:
# dict.get(a,b) = dict에서 key가 a인 것을 찾고 없으면 b값을 넣겠다.
node_dict[city[0]] = node_dict.get(city[0], []) + [city[1]]
# 알파벳 역순으로 정렬
for city in node_dict:
node_dict[city] = sorted(node_dict[city], reverse=True)
stack = ["ICN"]
answer = []
# 스택에 값이 있는동안 계속 반복
while stack:
now_city = stack[-1]
# 만약 해당 도시 출발 항공표가 없을 때 answer에 추가.
if now_city not in node_dict or node_dict[now_city] == []:
answer.append(stack.pop())
else:
# 해당 도시 출발 항공표가 있을 때 다음 도시 pop해서 스택에 추가
stack.append(node_dict[now_city].pop())
# 역순이므로 다시 정렬
answer.reverse()
return answer
import heapq
def solution(operations):
min_heap = [] # 힙 입력 배열
for i in operations:
# 숫자 입력인 경우
if i[0] == "I":
num = int(i.split()[1])
# 숫자를 heap에 push
heapq.heappush(min_heap, num)
# 최댓값 추출인 경우
elif i == "D 1":
# 배열 안에 값이 없으면 패쓰
if min_heap:
# nlargest로 가장 최댓값 추출
min_heap.remove(heapq.nlargest(1, min_heap)[0])
# 최솟값 추출인 경우
elif i == "D -1":
# 배열 안에 값이 없으면 패쓰
if min_heap:
# pop으로 최솟값 추출
heapq.heappop(min_heap)
# 배열에 값이 있는 경우 최댓값, 최솟값 추출
# 없는 경우 [0,0]추출
if min_heap:
return heapq.nlargest(1, min_heap) + [heapq.heappop(min_heap)]
return [0, 0]
문제를 풀면서 어느 부분에서 이분탐색을 해야하는지 헤매다 최소공배수를 기준으로 잡고 적절한 위치를 이분탐색으로 찾으려했습니다. 해당 알고리즘의 경우 테스트케이스를 만족했지만 다른 케이스에서 전부 시간초과가 발생했습니다. 시간초과가 발생한 요인으로는 최소공배수를 찾고 배열을 만드는 과정에서 발생한다고 생각했습니다.
최대값을 가장 오래걸리는 심사관이 모든 n명을 심사했을 경우로 하고 최소 시간을 탐색하며 진행했습니다.
문제 설명
n명이 입국심사를 위해 줄을 서서 기다리고 있습니다. 각 입국심사대에 있는 심사관마다 심사하는데 걸리는 시간은 다릅니다.
처음에 모든 심사대는 비어있습니다. 한 심사대에서는 동시에 한 명만 심사를 할 수 있습니다. 가장 앞에 서 있는 사람은 비어 있는 심사대로 가서 심사를 받을 수 있습니다. 하지만 더 빨리 끝나는 심사대가 있으면 기다렸다가 그곳으로 가서 심사를 받을 수도 있습니다.
모든 사람이 심사를 받는데 걸리는 시간을 최소로 하고 싶습니다.
입국심사를 기다리는 사람 수 n, 각 심사관이 한 명을 심사하는데 걸리는 시간이 담긴 배열 times가 매개변수로 주어질 때, 모든 사람이 심사를 받는데 걸리는 시간의 최솟값을 return 하도록 solution 함수를 작성해주세요.
제한사항
입국심사를 기다리는 사람은 1명 이상 1,000,000,000명 이하입니다.
각 심사관이 한 명을 심사하는데 걸리는 시간은 1분 이상 1,000,000,000분 이하입니다.
심사관은 1명 이상 100,000명 이하입니다.
입출력 예
n
times
return
6
[7, 10]
28
입출력 예 설명
가장 첫 두 사람은 바로 심사를 받으러 갑니다.
7분이 되었을 때, 첫 번째 심사대가 비고 3번째 사람이 심사를 받습니다.
10분이 되었을 때, 두 번째 심사대가 비고 4번째 사람이 심사를 받습니다.
14분이 되었을 때, 첫 번째 심사대가 비고 5번째 사람이 심사를 받습니다.
20분이 되었을 때, 두 번째 심사대가 비지만 6번째 사람이 그곳에서 심사를 받지 않고 1분을 더 기다린 후에 첫 번째 심사대에서 심사를 받으면 28분에 모든 사람의 심사가 끝납니다.
def solution(n, times):
answer = 0 # 정답값
start = 1 # 최소 시작
end = n * max(times) # 최대 시작
# 이분탐색 시작
while start <= end:
middle = (start + end) // 2
# 해당 시간 동안 몇 명을 심사할 수 있는지
count = 0
for time in times:
count += middle // time
# n명 이상인 경우 end값 조정
if count >= n:
answer = middle
end = middle - 1
# n명 미만인 경우 start값 조정
else:
start = middle + 1
return answer
1. 처음에는 다익스트라 알고리즘을 활용해서 해결하려 했으나 다익스트라로는 답이 나오지 않아 알고리즘 변경했습니다.
2. 찾아보다가 크루스칼이라는 알고리즘(최소비용으로 모든 노드를 연결시키는 알고리즘)이 적절한 알고리즘이라는 것을 찾았습니다.
3. union-find를 하는 방법으로 배열을 사용하는 방법을 생각해서 해결했습니다.
4. set으로도 해결가능할 것 같아 set으로도 해봤습니다.
문제 설명
n개의 섬 사이에 다리를 건설하는 비용(costs)이 주어질 때, 최소의 비용으로 모든 섬이 서로 통행 가능하도록 만들 때 필요한 최소 비용을 return 하도록 solution을 완성하세요.
다리를 여러 번 건너더라도, 도달할 수만 있으면 통행 가능하다고 봅니다. 예를 들어 A 섬과 B 섬 사이에 다리가 있고, B 섬과 C 섬 사이에 다리가 있으면 A 섬과 C 섬은 서로 통행 가능합니다.
제한사항
섬의 개수 n은 1 이상 100 이하입니다.
costs의 길이는((n-1) * n) / 2이하입니다.
임의의 i에 대해, costs[i][0] 와 costs[i] [1]에는 다리가 연결되는 두 섬의 번호가 들어있고, costs[i] [2]에는 이 두 섬을 연결하는 다리를 건설할 때 드는 비용입니다.
같은 연결은 두 번 주어지지 않습니다. 또한 순서가 바뀌더라도 같은 연결로 봅니다. 즉 0과 1 사이를 연결하는 비용이 주어졌을 때, 1과 0의 비용이 주어지지 않습니다.
모든 섬 사이의 다리 건설 비용이 주어지지 않습니다. 이 경우, 두 섬 사이의 건설이 불가능한 것으로 봅니다.
연결할 수 없는 섬은 주어지지 않습니다.
입출력 예
n
costs
return
4
[[0,1,1],[0,2,2],[1,2,5],[1,3,1],[2,3,8]]
4
입출력 예 설명
costs를 그림으로 표현하면 다음과 같으며, 이때 초록색 경로로 연결하는 것이 가장 적은 비용으로 모두를 통행할 수 있도록 만드는 방법입니다.
def solution(n, costs):
answer = 0
# 간선의 크기로 정렬
costs.sort(key=lambda x: x[2])
# union-find를 set으로 설정
routes = set([costs[0][0]])
# 모든 노드를 연결한 경우 멈춤.
while len(routes) != n:
for i, cost in enumerate(costs):
# 만약 시작노드와 마지막 노드가 연결되면 싸이클이 발생하는 경우
if cost[0] in routes and cost[1] in routes:
continue
# 싸이클이 발생하지 않는 경우
if cost[0] in routes or cost[1] in routes:
# set 새로고침
routes.update([cost[0], cost[1]])
answer += cost[2]
# 반영된 간선을 시각적으로 보기 편하게 하기위해 삽입(없어도 됨)
costs[i] = [-1, -1, -1]
break
return answer
def solution(n, costs):
answer = 0
# 간선의 크기로 정렬
costs.sort(key=lambda x: x[2])
# union-find를 배열로 설정
chk_node = [i for i in range(n)]
count = 0 # 크루스칼을 만족하는 경우 간선의 갯수는 노드 -1
for n1, n2, cost in costs:
# 만약 시작노드와 마지막 노드가 연결되면 싸이클이 발생하는 경우
if chk_node[n1] != chk_node[n2]:
# 끝 노드 union-find 실행
temp = chk_node[n2]
for i in range(n):
if chk_node[i] == temp:
chk_node[i] = chk_node[n1]
answer += cost
count += 1
if count == n - 1:
break
return answer
1. 문제를 보고 바로 든 생각은 DP(Dynamic Programming)을 활용해야겠다는 것입니다.
2. 위의 줄의 같은 idx or idx-1 중에서 높은 수를 더해서 더해주면서 내려오고 맨 마지막 줄에서 가장 큰 수를 구하는 방식으로 해결했습니다.
문제 설명
위와 같은 삼각형의 꼭대기에서 바닥까지 이어지는 경로 중, 거쳐간 숫자의 합이 가장 큰 경우를 찾아보려고 합니다. 아래 칸으로 이동할 때는 대각선 방향으로 한 칸 오른쪽 또는 왼쪽으로만 이동 가능합니다. 예를 들어 3에서는 그 아래칸의 8 또는 1로만 이동이 가능합니다.
삼각형의 정보가 담긴 배열 triangle이 매개변수로 주어질 때, 거쳐간 숫자의 최댓값을 return 하도록 solution 함수를 완성하세요.
def solution(triangle):
# DP로 2번째 줄부터 시작
for row in range(1, len(triangle)):
for col in range(len(triangle[row])):
# 비교할 2가지 값.
calculation1, calculation2 = triangle[row][col], triangle[row][col]
# idx -1 위치에서 내려온 것.
if 0 <= col - 1 < len(triangle[row - 1]):
calculation1 += triangle[row - 1][col - 1]
# idx 위치에서 내려온 것.
if 0 <= col < len(triangle[row - 1]):
calculation2 += triangle[row - 1][col]
# 둘 중 큰 값 선택
triangle[row][col] = max(calculation1, calculation2)
# 마지막 줄에서 가장 큰 값 선택
return max(triangle[-1])
1. 처음 문제를 보고 단어가 순차적으로 찾아간다는 것과 최소거리를 구하는 것을 보고 word를 노드, 변환가능한 단어관계를 간선으로 생각했습니다.
2. begin을 포함한 words를 노드와 간선으로 표시한 이후 BFS를 이용해서 답을 구했습니다. DFS보다 BFS가 더 효율적이라 생각했습니다.
문제 설명
두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.
1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다. 2. words에 있는 단어로만 변환할 수 있습니다.
예를 들어 begin이hit, target가cog, words가 [hot,dot,dog,lot,log,cog]라면hit->hot->dot->dog->cog와 같이 4단계를 거쳐 변환할 수 있습니다.
두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.
제한사항
각 단어는 알파벳 소문자로만 이루어져 있습니다.
각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
begin과 target은 같지 않습니다.
변환할 수 없는 경우에는 0를 return 합니다.
입출력 예
begin
target
words
return
hit
cog
[hot,dot,dog,lot,log,cog]
4
hit
cog
[hot,dot,dog,lot,log]
0
입출력 예 설명
예제 #1 문제에 나온 예와 같습니다.
예제 #2 target인cog는 words 안에 없기 때문에 변환할 수 없습니다.
from _collections import deque
def solution(begin, target, words):
answer = 0 # 결과값
length = len(begin) # 단어 길이
word_node = {} # 변환 가능한 단어를 노드로 변환
words.insert(0, begin) # begin값 words에 추가
# words 값들을 노드변환
for idx in range(len(words)):
word_node[idx] = []
# 변환가능한 단어를 간선으로 변환
for idx in range(len(words)):
for idx2 in range(idx + 1, len(words)):
chk_word = 0
for c in range(length):
if words[idx][c] == words[idx2][c]:
chk_word += 1
# 만약 다른 글자가 1개인 경우 변환가능한 단어
if chk_word == length - 1:
word_node[idx].append(idx2)
word_node[idx2].append(idx)
wait_visit = [] # 다음 거리의 노드
visit = deque([0]) # 큐에 넣어서 순차적으로 노드 방문
visited = [0] * len(words) # 노드 방문 여부 체크
visited[0] = 1 # begin값부터 시작
while True:
# 큐에 값이 있을때까지
while visit:
# 방문 노드
now_word = visit.pop()
# word_node에서 간선으로 방문가능한지 확인
for idx in word_node[now_word]:
# 이미 방문한 노드인지 확인
if visited[idx] == 1:
continue
# 만약 해당 노드가 target값이면 종료
if words[idx] == target:
return answer + 1
# 다음 큐 리스트에 추가
wait_visit.append(idx)
# 방문체크
visited[idx] = 1
# 노드간의 거리
answer += 1
# 만약 다음 방문할 노드가 없으면 종료
if wait_visit:
visit = deque(wait_visit)
wait_visit = []
else:
return 0