題目在leetcode上的鏈接爲:
https://leetcode-cn.com/problems/4sum/
題目描述
解題思路
這一題與第15題 三數之和 的解題思路類似。先對數組進行從小到大的排序,然後使用兩重循環遍歷數組,再使用雙指針遍歷一遍即可。
具體步驟爲:
- 首先如果 nums 爲 None,或者 nums 長度小於4,那麼返回空列表
- 將 nums 按照從小到大進行排序
- 使用變量 i 循環遍歷 nums:
- 如果 i>0 且 nums[i]=nums[i-1],說明前一步中已經考慮了這一步可能存在的四個數的結果,那麼 continue 不執行之後的代碼,以此進行去重操作(第一次去重)
- 使用變量 j 循環遍歷 nums[i+1:]
- 如果 j>i+1 且 nums[j]=nums[j-1],則 continue 不執行之後的代碼,以此進行去重操作(第二次去重)
- 令左指針 left 爲 j+1,右指針 right 爲 len(nums)-1
- 以 left<right 作爲判斷條件進入循環:
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 等於 target:
- 將找到的四個數添加到結果中
- 循環判斷如果左右指針位置的數等於它門下一個位置的數時,就將指針移到下一個位置進行去重操作 (第三次去重)
- 將左右指針都移到下一個位置重新找下一個可能的結果
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 小於 target,說明太小了,則將左指針向右移動一步
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 大於 target,說明太大了,則將右指針向左移動一步
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 等於 target:
ps: 要注意算法中標明的三次去重操作,其中第一次和第三次的去重操作與 三數之和 中的一樣,特別注意第二次去重操作中的條件 j>i+1,因爲當 j=i+1 時,nums[j-1]=nums[i],此時比較的 nums[j]=nums[j-1]=nums[i] 是將 i 與 j 位置的數進行比較,但我們需要比較的是 j 位置的數與它之前自己走過的前一步的數是否相同,所以需要條件 j>i+1,讓 j 與 i 不相鄰時再比較決定是否對 j 進行去重操作
複雜度分析:
排序操作的時間複雜度爲 o(nlog(n)),三重循環的複雜度爲 o(n3),由於這兩步操作是順序執行,所以總的時間複雜度爲 o(nlog(n))+o(n3),即爲 o(n3)。
由於只需要常數級的存儲空間,所以空間複雜度爲 o(1)
python代碼
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
if not nums or len(nums) < 4:
return []
nums.sort()
if (target >= 0 and nums[0] > target) or (target < 0 and nums[len(nums) - 1] < target):
return []
res = []
for i in range(len(nums)):
if target >= 0 and nums[i] > target:
return res
if i > 0 and nums[i] == nums[i - 1]:
continue
for j in range(i + 1, len(nums)):
if j > i + 1 and nums[j] == nums[j - 1]:
continue
left = j + 1
right = len(nums) - 1
while left < right:
if nums[i] + nums[j] + nums[left] + nums[right] == target:
res.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[i] + nums[j] + nums[left] + nums[right] > target:
right -= 1
else:
left += 1
return res