算法精讲-leetcode18-四数之和**

题目描述

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

给定数组 ints = [1, 0, -1, 0, -2, 2],和 target = 0。
输出:[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]].

解题思路

请先参考 算法精讲-leetcode15-三数之和为0 ,思路为leetcode15解题思路,其余细节在代码注释中。

代码示例

public class Test {
    public static void main(String[] args) {
        int[] ints = {1, 0, -1, 0, -2, 2};
        int target = 0;
        List<List<Integer>> lists = findFourNum(ints, target);
        System.out.println(lists);
    }

    private static List<List<Integer>> findFourNum(int[] ints, int target) {
        List<List<Integer>> lists = new ArrayList<>();
        int length = ints.length;
        if (length < 4){
            return lists;
        }
        Arrays.sort(ints);

        /*遍历时定义四个指针i,j,start,end,并且保证四个指针指向得数组索引一定不相同
            其中i,j从左向右遍历,start,end从剩余部分两端向中间遍历

        重要点1:去重需要注意:同一指针不可指向相同值的数据,则会产生重复数据
                    但是不同指针,在索引不同的前提下,值可以相同
                    比如:ints={0,0,0,0,1};target=1,则符合条件的集合为[0,0,0,1],该情况下:i==j==start
        */
        for (int i=0; i< length - 3; i++){
            /*
                该处不可用这种方式判断,因为i后面有指针j,start,end
            for循环中限制了i<length-3,在最后留出了剩余三个指针的位置,
            如果以下面这种方式去重,则会遍历到i+1,侵占了j的位置,不满足上述:重要点1
            if (ints[i] == ints[i+1]){
                continue;
            }*/
            //去重
            if (i > 0 && ints[i] == ints[i-1]){
                continue;
            }
            //当最小结果都比target大时退出当前循环
            if ((ints[i] + ints[i+1] + ints[i+2] +ints[i+3]) > target){
                break;
            }
            //当最大结果都比target小时退出当前循环
            if ((ints[i] + ints[length-3] + ints[length-2] + ints[length-1]) < target){
                break;
            }
            //遍历j指针,从i+1开始,留下start、end两个指针的位置
            for (int j = i+1; j< length - 2; j++){
                //去重,与i指针去重注意点相同
                if (j > i+1 && ints[j] == ints[j-1]){
                    continue;
                }
                //当最小结果都比target大时退出当前循环
                if ((ints[i] + ints[j] + ints[j+1] + ints[j+2]) > target){
                    break;
                }
                //当最大结果都比target小时退出当前循环
                if ((ints[i] + ints[j] + ints[length-2] + ints[length-1]) < target){
                    break;
                }
                //定义start、end两个指针,指向剩余部分的两端
                int start = j+1;
                int end = length - 1;

                while (start < end){
                    //计算和
                    int sum = ints[i] + ints[j] + ints[start] +ints[end];
                    if (sum < target){
                        start++;
                    }else if (sum > target){
                        end--;
                    }else {
                        //去重
                        //为什么不再while循环的最开始去重,而当sum==target时才去重呢?
                        //假设ints={-1,0,1,2,3,3,3},target=6时
                        //当遍历到i=-1,j=1,start=2,end=3[指向末尾的3]
                        //如果此时在刚进入while循环进行去重的话,去重结果后将会是:i=-1,j=1,start=2,end=3[指向最开始的3]
                        //这样【-1,1,3,3】这个结果就无法获得
                        if (ints[start] == ints[start +1] && start+1<end){
                            start++;
                            continue;
                        }
                        //去重
                        if (ints[end] == ints[end-1] && end - 1 > start){
                            end--;
                            continue;
                        }
                        List<Integer> list = Arrays.asList(ints[i], ints[j], ints[start], ints[end]);
                        lists.add(list);
                        //移动指针
                        start++;
                        end--;
                    }
                }
            }
        }
        return lists;
    }
}

运行结果

在这里插入图片描述

▄█▀█●各位同仁,如果我的代码对你有帮助,请给我一个赞吧,为了下次方便找到,也可关注加收藏呀
如果有什么意见或建议,也可留言区讨论

发布了26 篇原创文章 · 获赞 59 · 访问量 4391

猜你喜欢

转载自blog.csdn.net/weixin_43954926/article/details/104256031
今日推荐