三数之和&&四数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
1.Java
排序+双指针

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        // 枚举 a
        for (int first = 0; first < n; ++first) {
            // 需要和上一次枚举的数不相同
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            // c 对应的指针初始指向数组的最右端
            int third = n - 1;
            int target = -nums[first];
            // 枚举 b
            for (int second = first + 1; second < n; ++second) {
                // 需要和上一次枚举的数不相同
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                // 需要保证 b 的指针在 c 的指针的左侧
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }
                // 如果指针重合,随着 b 后续的增加
                // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == target) {
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    ans.add(list);
                }
            }
        }
        return ans;
    }
}

2.C#
法1:双指针

 public IList<IList<int>> ThreeSum(int[] nums)
    {
        IList<IList<int>> result = new List<IList<int>>();
        int len = nums.Length;
        if (len < 3) return result;
        Array.Sort(nums);
        for (int i = 0; i < len - 2; i++)
        {
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
            int left = i + 1;
            int right = len - 1;
            while (left < right)
            {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0)
                {
                    result.Add(new List<int>() { nums[i], nums[left], nums[right] });
                    while (left < right && nums[left] == nums[left + 1]) left++; // 去重
                    while (left < right && nums[right] == nums[right - 1]) right--; // 去重
                    left++;
                    right--;
                }
                else if (sum < 0) left++;
                else if (sum > 0) right--;
            }
        }
        return result;
    }

法2:哈希表

 public IList<IList<int>> ThreeSum(int[] nums)
    {
        int len = nums.Length;
        var result = new List<IList<int>>();
        if (len < 3) return result;
        Array.Sort(nums);
        //map<值,lastIndex>
        var map = new Dictionary<int, int>();
        for (int i = 0; i < len; i++)
        {
            if (map.ContainsKey(nums[i])) map[nums[i]] = i;
            else map.Add(nums[i], i);
        }
        for (int i = 0; i < len - 2; i++)
        {
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < len - 1; j++)
            {
                if (j != i + 1 && nums[j] == nums[j - 1]) continue;
                int numsK = 0 - nums[i] - nums[j];
                if (map.ContainsKey(numsK) && map[numsK] > j)
                    result.Add(new List<int>() { nums[i], nums[j], numsK });
            }
        }
        return result;
    }

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
1.java

public List<List<Integer>> fourSum(int[] nums,int target){
        /*定义一个返回值*/
        List<List<Integer>> result=new ArrayList<>();
        /*当数组为null或元素小于4个时,直接返回*/
        if(nums==null||nums.length<4){
            return result;
        }
        /*对数组进行从小到大排序*/
        Arrays.sort(nums);
        /*数组长度*/
        int length=nums.length;
        /*定义4个指针k,i,j,h  k从0开始遍历,i从k+1开始遍历,留下j和h,j指向i+1,h指向数组最大值*/
        for(int k=0;k<length-3;k++){
            /*当k的值与前面的值相等时忽略*/
            if(k>0&&nums[k]==nums[k-1]){
                continue;
            }
            /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏*/
            int min1=nums[k]+nums[k+1]+nums[k+2]+nums[k+3];
            if(min1>target){
                break;
            }
            /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
            int max1=nums[k]+nums[length-1]+nums[length-2]+nums[length-3];
            if(max1<target){
                continue;
            }
            /*第二层循环i,初始值指向k+1*/
            for(int i=k+1;i<length-2;i++){
                /*当i的值与前面的值相等时忽略*/
                if(i>k+1&&nums[i]==nums[i-1]){
                    continue;
                }
                /*定义指针j指向i+1*/
                int j=i+1;
                /*定义指针h指向数组末尾*/
                int h=length-1;
                /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略*/
                int min=nums[k]+nums[i]+nums[j]+nums[j+1];
                if(min>target){
                    continue;
                }
                /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/
                int max=nums[k]+nums[i]+nums[h]+nums[h-1];
                if(max<target){
                    continue;
                }
                /*开始j指针和h指针的表演,计算当前和,如果等于目标值,j++并去重,h--并去重,当当前和大于目标值时h--,当当前和小于目标值时j++*/
                while (j<h){
                    int curr=nums[k]+nums[i]+nums[j]+nums[h];
                    if(curr==target){
                        result.add(Arrays.asList(nums[k],nums[i],nums[j],nums[h]));
                        j++;
                        while(j<h&&nums[j]==nums[j-1]){
                            j++;
                        }
                        h--;
                        while(j<h&&i<h&&nums[h]==nums[h+1]){
                            h--;
                        }
                    }else if(curr>target){
                        h--;
                    }else {
                       j++;
                    }
                }
            }
        }
        return result;
    }

2.C#。四数之和其实就是在三数之和题目的基础上再多做一层循环嵌套,本质的算法思想是一致,都是采用双指针的解法。
测试用例:nums:[1, 0, -1, 0, -2, 2],target:0
先对nums做一个升序的排序得到[-2,-1,0,0,1,2]
利用两层循环首先是:i=-2,j=-1,然后剩下的区间为:[0,0,1,2],利用双指针进行遍历。即有:i=-2,j=-1,L=0,R=2,四数相加等于:-1,不等于且小于target,左指针加一位,即:L++,否则右指针减一位:R–。若等于target,就存储在结果中,并对左右指针相邻重复的数做去重操作,继续上面的步骤

public class Solution {
    public IList<IList<int>> FourSum(int[] nums, int target) {
        IList<IList<int>> resultList=new List<IList<int>>();
        int Length=nums.Length;
        if(nums==null||Length<4) return resultList;
        Array.Sort(nums);
        for(int i=0;i<Length;i++){
            if(i>0&&nums[i]==nums[i-1]) continue;//去重
            for(int j=i+1;j<Length;j++){
                if(j>i+1&&nums[j]==nums[j-1]) continue;//去重
                int L=j+1;
                int R=Length-1;
                while(L<R){
                    int sum=nums[i]+nums[j] + nums[L] + nums[R];
                    if(sum==target){
                        resultList.Add(new List<int>{nums[i],nums[j],nums[L],nums[R]});
                        while(L<R&&nums[L]==nums[L+1]) L++;//去重
                        while(L<R&&nums[R]==nums[R-1]) R--;//去重
                        L++;
                        R--;
                    }
                    else if(sum>target) R--;
                    else if(sum<target) L++;
                }
            }
        }
        return resultList;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值