【算法训练】n数之和 模板解法 python JavaScript

由于JavaScript部分只是为了练习自己对js语法的掌握,所以算法的思路和python完全一样(所以没有写注释),可以忽略不看~

一、三数之和 15

在这里插入图片描述

1、分析

先考虑两数之和,我们先将数组排序,然后采用头尾双指针,相向逼近找到符合条件的数对。其中很重要的一点,在于去重,如果有重复值,我们应该采用while循环滤掉。
对于n数之和,我们可以层层递归到找n-1数之和,一直到n=2的情况。然后层层添加即可。
具体见代码中的注释。

2、代码

class Solution:
    def targetSum(self,nums,n,start,target): #用于寻找n数之和的递归函数
        sz = len(nums)
        res = []
        if n<2 or sz<n: #递归出口
            return res
        if n==2:  #最基础的情况
            lo,hi = start,sz-1 #首尾双指针相向而行进行寻找
            while lo<hi:
                temp = nums[lo]+nums[hi]
                left = nums[lo]  #用于后续去重
                right = nums[hi]
                if temp < target:
                    while lo<hi and nums[lo]==left: #用while循环滤除重复值
                        lo += 1
                elif temp>target:
                    while lo<hi and nums[hi]==right:
                        hi -= 1
                elif temp == target:
                    res.append([nums[lo],nums[hi]]) #找到符合条件的数对,加入结果集
                    while lo<hi and nums[lo]==left: #同样要进行while循环滤除重复
                        lo += 1
                    while lo<hi and nums[hi]==right:
                        hi -= 1
        else: 
            i = start #当n大于2时,进行递归求解
            while i<sz:
                origin = nums[i]
                sub = self.targetSum(nums,n-1,i+1,target-nums[i]) #递归找到n-1数之和的结果集
                for t in sub: #加入当前值,即为完整n数之和结果集
                    t.append(nums[i])
                    res.append(t[:])
                while i<sz and nums[i]==origin: #由于结果集层层返回的都是没有重复的,此处枚举的时候也要保证无重复,从而保证每个环节都没有重复
                    i += 1
                
        return res
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort() #记住先对数组进行排序
        return self.targetSum(nums,3,0,0) #要求的是三数之和,起点为0,目标和为0

JS

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    nums.sort((a,b)=> a-b); #注意js的排序
    return targetSum(nums,3,0,0);

};

var targetSum = function(nums,n,start,target) {
    let sz = nums.length;
    let res = [];
    if(n<2 || n>sz){
        return res;
    }
    if(n == 2){
        let lo=start;
        let hi = sz-1;
        while(lo<hi){
            let sum_ = nums[lo]+nums[hi];
            let left = nums[lo],right = nums[hi];
            if(sum_<target){
                while(lo<hi && nums[lo]==left){
                    lo ++;
                }
            }else if(sum_ > target){
                while(lo<hi && nums[hi]==right){
                    hi --;
                }
            }else{
                res.push([nums[lo],nums[hi]]);
                while(lo<hi && nums[lo]==left){
                    lo ++;
                }
                while(lo<hi && nums[hi]==right){
                    hi --;
                }
            }
        }
        
        
    }else {
        let i = start;
        while(i<sz){
            let old = nums[i]
            let sub = targetSum(nums,n-1,i+1,target-nums[i]);
            for(let temp of sub){
                temp.push(nums[i])
                res.push(temp)
            }
            while(i<sz && nums[i]==old){
                i ++;
            }
        }
    }
    return res;
}

二、四数之和

在这里插入图片描述

1、分析

本题完全可以直接复用上一题的代码,思路完全相同。采用递归解法即可。

2、代码

class Solution:
    def targetSum(self,nums,n,start,target): #功能函数与上一题完全相同
        sz = len(nums)
        res = []
        if n<2 or n>sz:
            return res
        if n==2:
            lo,hi = start,sz-1
            while lo<hi:
                sum_ = nums[lo]+nums[hi]
                left,right = nums[lo],nums[hi]
                if sum_<target:
                    while lo<hi and nums[lo]==left:
                        lo += 1
                elif sum_>target:
                    while lo<hi and nums[hi]==right:
                        hi -= 1
                else:
                    res.append([left,right])
                    while lo<hi and nums[lo]==left:
                        lo += 1
                    while lo<hi and nums[hi]==right:
                        hi -= 1
        else:
            i = start
            while i<sz:
                old = nums[i]
                sub = self.targetSum(nums,n-1,i+1,target-nums[i])
                for temp in sub:
                    temp.append(nums[i])
                    res.append(temp)
                while i<sz and nums[i]==old:
                    i += 1
        return res
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        return self.targetSum(nums,4,0,target) #只是此处调用的时候指定了target而已

js

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[][]}
 */
var fourSum = function(nums, target) {
    nums.sort((a,b)=>a-b);
    return targetSum(nums,4,0,target);
};

var targetSum = function(nums,n,start,target){
    let sz = nums.length;
    let res = [];
    if(n<2 || n>sz){
        return res;
    }
    if(n==2){
        let lo=start,hi = sz-1;
        while(lo<hi){
            let sum_ = nums[lo]+nums[hi];
            let left=nums[lo],right=nums[hi];
            if(sum_<target){
                while(lo<hi && nums[lo]==left){
                    lo ++;
                }
            }else if(sum_>target){
                while(lo<hi && nums[hi]==right){
                    hi --;
                }
            }else{
                res.push([left,right]);
                while(lo<hi && nums[lo]==left){
                    lo ++;
                }
                while(lo<hi && nums[hi]==right){
                    hi --;
                }
            }
        }
    }else{
        let i = start;
        while(i<sz){
            let old = nums[i]
            let sub = targetSum(nums,n-1,i+1,target-nums[i]);
            
            for(let temp of sub){
                temp.push(old);
                res.push(temp);
            }
            while(i<sz && nums[i]==old){
                i ++;
            }
        }
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值