물 웅덩이가 없는 경우 해당 위치까지 똑같은 크기만큼 이동했기 때문에 비교할 필요 없이 더하면 됩니다.
물 웅덩이가 있는 경우 값을 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]
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
1. 처음에는 단순하게 진입 지점과 진출 시점을 기준으로 카메라를 설치하려했습니다. 해당 방법으로 했더니 정답 자체가 아니어서 알고리즘이 틀린 것으로 알게 됐다.
2. 2번째로는 나가는 시점을 기준으로 카메라를 설치했다. 메모이제이션을 통해 미리 최대 길이(60,000)만큼 배열을 만들고 나가는 지점에 카메라를 기록하는 방식으로 했다. 정확성에서는 통과했지만 효율성에서 케이스 한 개가 안됐다.
3. 3번째로 새로운 카메라가 추가된 경우 미리 나머지 차량을 확인하는 방식을 선택했다. 해당 알고리즘으로 했을 때 효율성 또한 만족하는 것으로 나왔다.
문제 설명
고속도로를 이동하는 모든 차량이 고속도로를 이용하면서 단속용 카메라를 한 번은 만나도록 카메라를 설치하려고 합니다.
고속도로를 이동하는 차량의 경로 routes가 매개변수로 주어질 때, 모든 차량이 한 번은 단속용 카메라를 만나도록 하려면 최소 몇 대의 카메라를 설치해야 하는지를 return 하도록 solution 함수를 완성하세요.
제한사항
차량의 대수는 1대 이상 10,000대 이하입니다.
routes에는 차량의 이동 경로가 포함되어 있으며 routes[i][0]에는 i번째 차량이 고속도로에 진입한 지점, routes[i][1]에는 i번째 차량이 고속도로에서 나간 지점이 적혀 있습니다.
차량의 진입/진출 지점에 카메라가 설치되어 있어도 카메라를 만난것으로 간주합니다.
차량의 진입 지점, 진출 지점은 -30,000 이상 30,000 이하입니다.
입출력 예
routes
return
[[-20,15], [-14,-5], [-18,-13], [-5,-3]]
2
입출력 예 설명
-5 지점에 카메라를 설치하면 두 번째, 네 번째 차량이 카메라를 만납니다.
-15 지점에 카메라를 설치하면 첫 번째, 세 번째 차량이 카메라를 만납니다.
def solution(routes):
chk_camera = [0] * len(routes) # 총 확인해야하는 차량 수
count = 0 # 결과값
routes.sort(key=lambda x:x[1]) # 진출 지점으로 정렬
for car in range(len(routes)):
# 만약 해당 차량이 카메라 테스트에서 통과한 경우 패스
if chk_camera[car]:
continue
# 해당 차량이 지나가는 카메라가 없으므로 새로 만듬.
camera = routes[car][1]
count +=1
# 새로 만든 카메라가 이후 차량 중에서 지나가는 차량이 있는지 확인
for num in range(car + 1, len(routes)):
if routes[num][0] <= camera <= routes[num][1]:
chk_camera[num] = True
return count