python算法题:2sum, 3sum, 4sum, nsum

two sum

思路:
一次哈希,边哈希边检测另一个数字是否已经在dict中(二次哈希也可)

时间复杂度O(n) 空间复杂度O(n)

PS: 其实还可以先排序再双指针(沿用3sum的思路),这样操作时间复杂度O(nlogn)空间复杂度O(1)

import copy
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        d = {}
        for i in range(len(nums)):
            complement = target - nums[i]
			# hash的时候检测另一个数字是否已存在,即使是重复数字还未覆盖也不影响
            if complement in d.keys():
                return [d[complement], i]
            d[nums[i]] = i
        return -1

three sum

思路:

  1. 排序
  2. 第一个数字从头到尾扫描,
  3. 剩下两个数双指针得到。

时间复杂度 O(n^2) 空间复杂度O(1)

注意:题目中要求结果不重复,所以需要加上重复数字判断

(做的时候也有考虑过双指针+二分查找最后一个数,但是这样哪个指针移动无法判断)

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = []
        if len(nums) < 3 or nums[0]>0:
            return []
        
        for i in range(len(nums)-2):
        	# 防止重复重复数字出现
            if i != 0 and nums[i] == nums[i-1]:
                continue
            a = nums[i]
            l = i + 1
            r = len(nums) - 1
            while l < r:
                if nums[l] + nums[r] == 0 - a:
                    res.append([a, nums[l], nums[r]])
                    # 防止重复数字出现(只用于sum==target时)
                    while l 0:
                    r -= 1
                else:
                    l += 1

        return res

four sum

思路:
沿用3sum的思想

  1. 排序
  2. 两个数从头到尾暴力扫描
  3. 剩下两个数双指针

时间复杂度 O(n^3) 空间复杂度O(1)

注意:题目中要求结果不重复,所以需要加上重复数字判断

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        res = []
        for i in range(n-3):
            if i!=0 and nums[i-1] == nums[i]:
                continue
            for j in range(i+1, n-2):
                if j > i+1 and nums[j-1] == nums[j]:
                    continue
                twosum = target - nums[i] - nums[j]
                l = j+1
                r = n-1
                while l twosum:
                        r -= 1
                    else:
                        l += 1
        return res

n sum

类似 3sum 的方法:

  1. 首先还是排序
  2. 当 n > 2 的时候深度优先搜索可能的解
  3. 然后当 n == 2 的时候利用双指针求出结果

时间复杂度O(N^(K-1)) 注:k为k sum
空间复杂度O(1)

python版本:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        return self.nSum(nums, target, 4)

    def nSum(self, nums, target, n):
    
        def dfs(pos: int, cur: List[int], n: int, target: int):
        
        	# 双指针
            if n == 2:
                j = pos
                k = len(nums) - 1
                while j < k:
                    sum = nums[j] + nums[k]
                    if sum < target:
                        j += 1
                    elif sum > target:
                        k -= 1
                    else:
                       # 结果添加前面n-2位数字
                        solution = cur[:] + [nums[j], nums[k]]
                        ans.append(solution)
                        while j < k and nums[j] == nums[j+1]:
                            j += 1
                        while j < k and nums[k] == nums[k-1]:
                            k -= 1
                        j += 1
                        k -= 1
                return
                
            i = pos
            while i < len(nums) - n + 1:
                # 剪枝的一种情况
                if nums[i] * n > target or nums[-1] * n < target:
                    break
                # 排除重复数字
                if i > pos and nums[i] == nums[i-1]:
                    i += 1
                    continue
                #回溯法取到全部数字
                cur.append(nums[i])
                dfs(i+1, cur, n-1, target-nums[i])  # 回溯
                cur.pop()
                i += 1

        ans = []
        nums.sort()
        dfs(0, [], n, target)
        return ans

c++ 版本:

class Solution {
public:
    vector> res;
    vector nums;
    vector> fourSum(vector& nums, int target) {
        int len = nums.size();
        if(len < 4){
            return res;
        }
        sort(nums.begin(),nums.end());
        this->nums = nums;
        vector cur;
        dfs(0, target, 4, cur);
        return res;
    }
    
    void dfs(int pos, int target, int n, vector& cur){
        if(n == 2){
            int left = pos;
            int right = nums.size() - 1;
            while(left < right){
                long sum = (long)nums[left] + (long)nums[right];
                if(sum < target){
                    left++;
                }else if (sum > target){
                    right--;
                }else{
                    //此处重新赋值可以使得参数cur使用引用,从而避免大量的无用复制,大幅度提高效率。
                    vector tmp(cur.begin(),cur.end());
                    tmp.push_back(nums[left]);
                    tmp.push_back(nums[right]);
                    res.push_back(tmp);
                    while(left < right && nums[left] == nums[left + 1])
                        left++;
                    while(left < right && nums[right] == nums[right - 1])
                        right--;
                    left++;
                    right--;
                }
            }
            return;
        }
        int i = pos;
        while(i < nums.size() - n + 1){
            if(nums[i] * n > target && nums[nums.size() - 1] * n < target){
                break;
            }
            if(i > pos && nums[i] == nums[i - 1]){
                i++;
                continue;
            }
            cur.push_back(nums[i]);
            dfs(i + 1, target - nums[i],n - 1,cur);
            cur.pop_back();
            i++;
        }
    }  
};

你可能感兴趣的:(leetcode)