Linear Data Structure
05. Array
032. 두 수의 합
덧셈하여 타겟을 만들 수 있는 배열의 두 숫자 인덱스를 리턴.
1
2
3
4
5
6
7
8
9
10
11
nums = [2, 7, 11, 15]
target = 9 # [0, 1]
def two_sum(nums, target):
nums_map = {}
for i, num in enumerate(nums):
if target - num in nums_map:
return [nums_map[target - num], i]
nums_map[num] = i
print(two_sum(nums, target))
033. 빗물 트래핑
높이를 입력받아 비 온 후 얼마나 많은 물이 쌓일 수 있는지 계산.
- 투 포인터를 최대로 이동.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
def trap(height):
if not height:
return 0
volume = 0
left, right = 0, len(height) - 1
left_max, right_max = height[left], height[right]
while left < right:
left_max, right_max = max(height[left], left_max), max(height[right], right_max)
# 더 높은 쪽을 향해 투 포인터 이동
if left_max <= right_max:
volume += left_max - height[left]
left += 1
else:
volume += right_max - height[right]
right -= 1
return volume
print(trap(height))
034. 세 수의 합
배열을 입력받아 합으로 0을 만들 수 있는 3개의 엘리먼트를 출력.
- 투 포인터로 합 계산
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
26
27
28
29
30
31
32
33
34
35
nums = [-1, 0, 1, 2, -1, -4]
def three_sum(nums):
results = []
nums.sort()
for i in range(len(nums) - 2):
# 중복된 값 건너뛰기
if i > 0 and nums[i] == nums[i - 1]:
continue
# 간격을 좁혀가며 합 sum 계산
left, right = i + 1, len(nums) - 1
while left < right:
sum = nums[i] + nums[left] + nums[right]
if sum < 0:
left += 1
elif sum > 0:
right -= 1
else:
# sum = 0인 경우이므로 정다 및 스킵 처리
results.append((nums[i], nums[left], nums[right]))
while left < right and nums[left] == nums[left + 1]:
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
left += 1
right -= 1
return results
print(three_sum(nums))
---------------------
[(-1, -1, 2), (-1, 0, 1)]
- 투 포인터: 시작점과 끝점 또는 왼쪽 포인터와 오른쪽 포인터 두 지점을 기준으로 하는 문제 풀이 전략.
035. 배열 파티션 1
n개의 페어를 이용한 min(a, b)의 합으로 만들 수 있는 가장 큰 수를 출력.
- 파이썬 다운 방식
1
2
3
4
5
6
7
8
nums = [1, 4, 3, 2]
def array_pair_sum(nums):
return sum(sorted(nums)[::2])
print(array_pair_sum(nums))
---------------------------
4
036. 자신을 제외한 배열의 곱
배열을 입력받아 output[i]가 자신을 제외한 나머지 모든 요소의 곱셈 결과가 되도록 출력. 나눗셈을 하지 않고 O(n)에 풀이.
- 왼쪽 곱셈 결과에 오른쪽 값을 차례대로 곱셈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
nums = [1, 2, 3, 4]
def produce_except_self(nums):
out = []
p = 1
# 왼쪽 곱셈
for i in range(0, len(nums)):
out.append(p)
p = p * nums[i]
p = 1
# 왼쪽 곱셈 결과에 오른쪽 값을 차례대로 곱셈
for i in range(len(nums) - 1, 0 - 1, -1):
out[i] = out[i] * p
p = p * nums[i]
return out
print(produce_except_self(nums))
-------------------------------
[24, 12, 8, 6]
037. 주식을 사고팔기 가장 좋은 시점
한 번의 거래로 낼 수 있는 최대 이익 산출.
- 저점과 현재 값과의 차이 계산
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
prices = [7, 1, 5, 3, 6, 4]
def max_profit(prices):
profit = 0
min_price = sys.maxsize
# 최솟값과 최댓값을 계속 갱신
for price in prices:
min_price = min(min_price, price)
profit = max(profit, price - min_price)
return profit
print(max_profit(prices))
-------------------------
5
06. Linked List
038. 팰린드롬 연결 리스트
연결 리스트가 팰린드롬 구조인지 판별.
- 런너를 이용한 우아판 풀이
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
26
27
class ListNode():
def __init__(self, x):
self.val = x
self.next = None
def is_palindrome(head):
rev = None
slow = fast = head
while fast and fast.next:
fast = fast.next.next
rev, rev.next, slow = slow, rev, slow.next
if fast:
slow = slow.next
# 팰린드롬 여부 확인
while rev and rev.val == slow.val:
slow, rev = slow.next, rev.next
return not rev
l = ListNode(1)
l.next = ListNode(2)
l.next.next = ListNode(2)
l.next.next.next = ListNode(1)
print(is_palindrome(l))
- 런너 기법
- 연결 리스트를 순회할 때 2개의 포인터를 동시에 사용하는 기법.
- 한 포인터가 다른 포인터보가 앞서게 하여 병합 지점이나 중간 위치, 길이 등을 판별할 때 유용하게 사용.
- 연결 리스트를 순회할 때 2개의 포인터를 동시에 사용하는 기법.
- 다중 할당(Multiple Assignment): 2개 이상의 값을 2개 이상의 변수에 동시에 할당.
039. 두 정렬 리스트의 병합.
정렬되어 있는 두 연결 리스트를 합쳐라.
- 재귀 구조로 연결
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
26
27
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def mergeTwoLists(l1, l2):
if (not l1) or (l2 and l1.val > l2.val):
l1, l2 = l2, l1
if l1:
l1.next = mergeTwoLists(l1.next, l2)
return l1
l1 = ListNode(1)
l1.next= ListNode(2)
l1.next.next = ListNode(4)
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)
answer = mergeTwoLists(l1, l2)
while answer is not None:
print(f'{answer.val} ->', end=" ")
answer = answer.next
040. 역순 연결 리스트
연결 리스트를 뒤집어라.
- 반복 구조로 뒤집기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list(head):
node, prev = head, None
while node:
next, node.next = node.next, prev
prev, node = node, next
return prev
head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
answer = reverse_list(head)
while answer is not None:
print(f'{answer.val} ->', end=" ")
answer = answer.next
041. 두 수의 덧셈
역순으로 저장된 연결 리스트의 숫자를 더하라.
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
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def add_two_numbers(l1, l2):
root = head = ListNode(0)
carry = 0
while l1 or l2 or carry:
sum = 0
# 두 입력값의 합 계산
if l1:
sum += l1.val
l1 = l1.next
if l2:
sum += l2.val
l2 = l2.next
# 몫(자리올림수)과 나머지(값) 계산
carry, val = divmod(sum + carry, 10)
head.next = ListNode(val)
head = head.next
return root.next
숫자형 리스트를 단일 값으로 병합하기.
1 2 3
>>> a = [1, 2, 3, 4, 5] >>> functools.reduce(lambda x, y: 10 * x + y, a, 0) 12345
042. 페어의 노드 스왑
연결 리스트를 입력받아 페어pair 단위로 스왑.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 입력: 1->2->3->4
# 출력: 2->1->4->3
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def swap_pairs(head):
if head and head.next:
p = head.next
# 스왑된 값 리턴 받음
head.next = swap_pairs(p.next)
p.next = head
return p
return head
043. 홀짝 연결 리스트
연결 리스트를 홀수 노드 다음에 짝수 노드가 오도록 재구성. 공간 복잡도 O(1), 시간 복잡도 O(n)에 풀이.
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
# 입력: 2->1->3->5->6->4->7->NULL
# 출력: 2->3->6->7->1->5->4->NULL
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def odd_even_list(head):
# 예외 처리
if head is None:
return None
odd = head
even = head.next
even_head = head.next
# 반복하면서 홀짝 노드 처리
while even and even.next:
odd.next, even.next = odd.next.next, even.next.next
odd, even = odd.next, even.next
# 홀수 노드의 마지막을 짝수 헤드로 연결
odd.next = even_head
return head
044. 역순 연결 리스트 2
인덱스 m에서 n까지를 역순으로 만들어라. 인덱스 m은 1붙터 시작.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 입력: 1->2->3->4->5->NULL, m = 2, n = 4
# 출력: 1->4->3->2->5->NULL
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def reverse_between(head, m, n):
# 예외 처리
if not head or m == n:
return head
root = start = ListNode(None)
root.next = head
# start, end 지정
for _ in range(m - 1):
start = start.next
end = start.next
for _ in range(n - m):
tmp, start.next, end.next = start.next, end.next, end.next.next
start.next.next = tmp
return root.next