Three_Sum问题

三数求和为0,返回动态数组问题

输入:一个数组
输出:相加为0的三个元素组成的 ArrayList<Integer>
要求:输出不能还有重复
用例:[-1, 0, 1, 2, -1, -4] ====> [ [-1, 0, 1], [-1, -1, 2] ]


分析

这个很简单想到穷举法,O(n^3)。三重循环即可以做。至于重复的部分可以用 HashSet 来处理(相当于python中的set)。但是提交,Runtime Error。

思路

排序双指针法

这种方法不能穷举所有可能的三个数的组合,是有目的 移动(知道下一个向大/小方向移动),会逼近给定的和。

将 3Sum 问题看做是 扩展的 2Sum 问题。
首先,要做的是将给定数组排序,用到 Arrays.sort() 方法。
之后,将第一个数字给定,用两个指针遍历后面的数字,和为0时,同时移动两个指针;否则,只移动一个。(因为已经排序了)
最后,先写到 hs 中缓存来去重。

排序nlog(n),循环n^2,整体时间复杂度为 O(n^2)

代码

package day_3;
import java.util.*;
// 给定一个数组,返回加和为0 的三个元素列表
// 穷举法   --- O(n^3) 这个 TLE了
// 双指针法 --- O(n^2)
public class ThreeSums {
    public List<List<Integer>> threeSum(int[] nums){
        int count = nums.length;
        List<List<Integer>> list = new ArrayList<List<Integer>>(); 
        if(count<3 || nums == null){
            System.out.println("无效输入");
            return list;
        }
        Arrays.sort(nums);
        
        // 用作去重的 hs
        HashSet<ArrayList<Integer>> hs = new HashSet<ArrayList<Integer>>();
        for(int i=0;i<count-2;i++){
            int low = i+1;
            int high = count-1;  // 两个指针
            while(low<high){
            int sum = nums[i]+nums[low]+nums[high];
            if(sum == 0){
                ArrayList<Integer> aList = new ArrayList<Integer>();
                aList.add(nums[i]);
                aList.add(nums[low]);
                aList.add(nums[high]);
                if(!hs.contains(aList)){
                    hs.add(aList);
                    list.add(aList);
                }
                low++;
                high--;
            }
            else if(sum < 0)
            low++;
                else 
                high--;
            }
        }
        return list;
    }
    
public static void main(String args[]){
    int a[] = {0,0,0};
    ThreeSums t = new ThreeSums();
    System.out.println(t.threeSum(a));
    }   
}


4Sum问题

对于4Sum问题,我们也可以按照这个思路来解答,不过多加一个元素,还是双指针。
具体代码要自己调整一下。

其实还有一个思路,对于 kSum 的拓展问题,通过回溯法来实现。
参考别人的代码。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        if (nums == null || nums.length < 4) return new ArrayList<>();
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> ans = new ArrayList<>();
        helper(nums, target, res, ans, 0, 4);  // 如果你想五数之和,将这里的4改成5即可,另外上面的判断条件也需要改一下,依次类推.....6 sum 7 sum .... 都可以解决。
        return res;
    }
    private void helper(int[] nums, int target, List<List<Integer>> res, List<Integer> ans, int cur, int kSum) {
        if (target < kSum * nums[cur] || target > kSum * nums[nums.length - 1]) return ;  // 不可能存在相应的kSum数组
        if (kSum == 2) help2Sum(nums, target, res, ans, cur);
        else {
            for (int i = cur, len = nums.length; i <= len - kSum; i++) {
                if (i > cur && nums[i - 1] == nums[i]) continue;  // 去重
                ans.add(nums[i]);
                helper(nums, target - nums[i], res, ans, i + 1, kSum - 1);  // 回溯
                ans.remove(ans.size() - 1);
            }
        }
    }
    private void help2Sum (int[] nums, int target, List<List<Integer>> res, List<Integer> ans, int cur) {
        int lo = cur;
        int hi = nums.length - 1;
        while (lo < hi) {
            int sum = nums[lo] + nums[hi];
            if (sum < target) {
                lo++;
            } else if (sum > target) {
                hi--;
            } else {
                ans.add(nums[lo]); ans.add(nums[hi]);
                res.add(new ArrayList<Integer>(ans));
                ans.remove(ans.size() - 1); ans.remove(ans.size() - 1);
                while (lo < hi && nums[lo + 1] == nums[lo++]) ;
                while (lo < hi && nums[hi - 1] == nums[hi--]) ;
            }
        }
    }
}

作者:clthinking-2
链接:https://leetcode-cn.com/problems/4sum/solution/java-4ms-ji-bai-liao-100-ke-kuo-zhan-zi-ksumzhi-he/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 13,116评论 0赞 33
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 4,207评论 0赞 2
  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,688评论 3赞 44
  • 基本的 alertdialog 使用 3 个按钮 参考文章android 8 种对话框(Dialog)使用方法汇总...
    Pengoing阅读 1,245评论 0赞 0
  • 为了什么呢 患得患失 辗转反侧 为那个失色的誓言 还是为了自己小心翼翼 呵护的泡泡 不被戳破 不说 不说 每个人窗...
    何事乱翻书阅读 213评论 10赞 2

友情链接更多精彩内容