Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- hash table
- easy
- dfs
- 미디움
- Python
- matrix
- DP
- Medium
- Array
- 이진트리
- leetcode
- 문자열
- Binary
- 재귀
- backtracking
- list
- two pointers
- recursive
- 쉬움
- sorting
- binary tree
- binary search
- HashTable
- math
- string
- tree
- Depth-first Search
- 리트코드
- linked list
- 중간
Archives
- Today
- Total
부부의 코딩 성장 일기
LeetCode 18(4Sum, Python) 본문
1. 문제 링크
4Sum - LeetCode
Can you solve this real interview question? 4Sum - Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that: * 0 <= a, b, c, d < n * a, b, c, and d are distinct. * nums[a] + nums[b] +
leetcode.com
2. 문제 설명
- 정수로 구성된 nums라는 array가 주어졌을 때,
- nums[a] + nums[b] + nums[c] + nums[d] == target이 되는 unique한 모든 조합을 반환
- 예시) nums = [1,0,-1,0,-2,2], target = 0일 때, 네 수의 합이 0이 되는 [[-2,-1,1,2], [-2,0,0,2], [-1,0,0,1]]을 반환
3. 처음 풀이
- 지난번에 풀었던 3Sum 방법(two pointer, sorting)을 응용
- 3Sum에서는 첫번째 index에 대해 for문을 돌리고, left end index를 two pointer로 조정했다면,
- 4Sum은 첫번째, 두번째 index에 대해 for문을 돌리고, third, end index를 two pointer로 조정하는 것으로 수정
- 변수명이 길어져서, 첫번째, 두번째는 i,j로 두고, third, end index는 left, right로 변수화
- left, right는 현재의 sum과 target sum을 비교하면서, 같으면 append,
- 현재 sum이 더 크면 작아지는 방향으로 (right를 좌로 한칸 이동)
- 현재 sum이 더 작으면 커지는 방향으로 (left를 우로 한칸 이동) 움직이면서 left < right 동안 while문 수행
- 같은 output이 나오는 케이스를 제거해줘야 runtime이 조금 더 올라갔음
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
output = []
for i in range(len(nums)-3):
if i > 0 and nums[i] == nums[i - 1]:
continue # 중복된 값을 건너뛰기
for j in range(1, len(nums)-2):
if j > i+1 and nums[j] == nums[j-1]:
continue # 중복된 값을 건너뛰기
if j > i:
left = j+1
right = len(nums) -1
cur_target = target -nums[i] - nums[j]
while left < right:
if nums[left] + nums[right]==cur_target:
output.append([nums[i], nums[j], 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
elif nums[left] + nums[right] < cur_target:
left +=1
else:
right -=1
return output
- runtime 65% beats
- 신기했던건, cur_sum = nums[i]+nums[j]+nums[left]+nums[right] 으로 놓고, cur_sum과 target을 비교하는 방식으로 코드를 짰을 땐, runtime 이 45% 정도 beats이었음.
- nums가 엄청 커졌을 때, 특정 index의 값을 반환하는 게 시간이 소요되서 그런듯 함
4. 다른 풀이
- 대부분이, 내가 접근한 방식으로 풀었음.
- 거의 비슷한데 두가지 정도 속도 개선 포인트가 존재했음
- 우선 나는 output 을 빈 list로 두었는데, 여기선 set()으로 빈 집합으로 두고, 반환 시에만 list로 변경해주었음
- set으로 두면 set.add했을 때 이미 있는 값이라면, 중복되서 add되지 않고 고유한 한개의 값으로 존재하기 때문에, 자동으로 중복이 제거됨
- break rule이 하나 더 추가 되어있음
- 만약 nums[i] > target/4 면 break하는 조건을 추가
- nums는 오름차순으로 sorting이 되어있는데, start index를 4배한 것이 이미 target보다 커버리면, for문을 계속 돌릴 이유가 없어져서 break를 걸면 불필요한 while문이 안돌게 됨!
- 만약 nums[i] > target/4 면 break하는 조건을 추가
- 이 풀이로 submission을 하면 runtime 기준 35% 정도 개선이 되고, 82.79% beats!
- 우선 나는 output 을 빈 list로 두었는데, 여기선 set()으로 빈 집합으로 두고, 반환 시에만 list로 변경해주었음
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
res = set()
for i in range(len(nums) - 3):
if i > 0 and nums[i] == nums[i - 1]:
continue
if nums[i] > target / 4:
break
for j in range(i + 1, len(nums) - 2):
l, r = j + 1, len(nums) - 1
while l < r:
sm = nums[i] + nums[j] + nums[l] + nums[r]
if sm < target: l += 1
elif sm > target: r -= 1
elif (nums[i], nums[j], nums[l], nums[r]) not in res:
res.add((nums[i], nums[j], nums[l], nums[r]))
else: l, r = l + 1, r - 1
return [list(t) for t in res]
5. 배운 점
- 핵심을 파악해서 풀 되, 불필요한 for문 while문이 도는 케이스가 있는지 파악해서 runtime 개선하기!
'Algorithm > LeetCode' 카테고리의 다른 글
LeetCode 22(Generate Parentheses, Python) (1) | 2023.12.19 |
---|---|
LeetCode 19(Remove Nth Node From End of List, Python) (1) | 2023.12.18 |
LeetCode 17(Letter Combinations of a Phone Number, Python) (0) | 2023.12.16 |
LeetCode 16(3Sum Closest, Python) (1) | 2023.12.15 |
LeetCode 15(3Sum, Python) (0) | 2023.12.14 |