Sum Zero Problem(三数和为0, 破解三重for循环问题)

Posted Dream_it_possible!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sum Zero Problem(三数和为0, 破解三重for循环问题)相关的知识,希望对你有一定的参考价值。

Question

        Given an array nums of n integers, are there elements  a,b,c ... in nums such that  a+b+c =0?  Find all unique triplets in the array which gives the sum of zero.

example:

input:

nums=[-1,0,1,2,-1,-4]

output:

[
   [-1,0,1],
   [-1,-1,2]
]

        please write a funtion to find all result in array or list.

 Thinking

         It is easy to think of the most straightforward way to use a triple for loop to find all the combinations that add up to zero and then deduplicate them. but the comlexity of the time is o(n3), therefore, the method is not recomended.

        For such a problem, we can reduce the dimension of  the problem by first sorting the array in ascending order, and then using Pointers, setting a left pointer and a right point to the first element and the last element , respectively.

        If nums[left]+nums[right] =sum, sum=0-nums[i], and then nums[left],nums[right], nums[i] are returned,finally  left ++, right--.

        If nums[left] + nums[right]>sum, right --, otherwise, left ++.

        List<List<Integer>> is a good choice to put result, the code is shown below:

package leetcode100;

import java.util.*;

/**
 * @author bingbing
 * @date 2021/8/16 0016 14:48
 * Given an array nums of n integers, are there elements a,b,c...in nums such  that a+b+c=0? Find all  unique triplets in the array which
 * gives the sum of zero.
 * example:  nums=[-1,0,1,2,-1,-4]
 * output:
 * [
 * [-1,0,1],
 * [-1,-1,2]
 * ]
 * 此问题可用三重for 循环暴力破解,但是出题人的关注点是不用三重循环,复杂度过高,不是一个推荐的方法。
 * 思路: 将数组进行排序,[-4, -1, -1, 0, 1, 2]
 * 遍历数组中的每一项作为 left 和right指针指向的和,分别将左指针和右指针分别向中间移动。
 */
public class SumZeroProblem {


    public static void main(String[] args) {
        int[] array = {-1, 0, 1, 2, -1, -4, 3, -2};
        List<List<Integer>> result = findAvailableArray(array);
        System.out.println("The sum equal Zero are :" + result);
    }

    /**
     *
     * @param array
     * @return
     */
    private static List<List<Integer>> findAvailableArray(int[] array) {
        Arrays.sort(array);
        List<List<Integer>> results = new ArrayList<>();
        System.out.println(Arrays.toString(array));
        for (int i = 0; i < array.length - 1; i++) {
            int sum = 0 - array[i];
            int left = i + 1;
            int right = array.length - 1;
            if (array[i] == array[i + 1]) {
                continue;
            }
            while (left < right) {
                if (array[left] + array[right] == sum) {
                    results.add(Arrays.asList(array[left], array[right], array[i]));

                    // 防止重复,相同元素继续移动
                    while (left < right && array[left] == array[left + 1]) {
                        left++;
                    }
                    while (left < right && array[right] == array[right - 1]) {
                        right--;
                    }
                    right--;
                    left++;
                } else if (array[left] + array[right] > sum) {
                    right--;
                } else {
                    left++;
                }

            }
        }
        return results;
    }
}

warning:  The left value should start with i+1, and judge nums[i]==nums[i+1]? otherwise we may get repeat result finally!

Test

 Input:    {-1, 0, 1, 2, -1, -4, 3, -2};

Output:

         To sum up,  we use left and right pointer to reduce the dimension of the problem , the  complexity of the time is o(n).

Extension

        Assume that given a target, find three numbers and the group closest to the group.

    /**
     * 衍生问题:   给定一个target, 找出三数和最接近于target值的一个组合。
     * extension: Given a target, find three numbers and the group closest to the group.
     */
    private static Object[] findClosestGroup(int[] resource, int traget) {
        Arrays.sort(resource);
        int diff = Integer.MAX_VALUE;
        Map<Integer, List<Integer>> map = new HashMap<>(16);
        for (int i = 0; i < resource.length; i++) {
            int left = i + 1;
            int right = resource.length - 1;
            while (left < right) {
                int temp = Math.abs(traget - resource[i] - resource[left] - resource[right]);
                if (temp < diff) {
                    diff = temp;
                    map.put(diff, Arrays.asList(resource[left], resource[right], resource[i]));
                } else {
                    left++;
                    right--;
                }
            }
        }
        return map.get(diff).toArray();
    }

        This requirement is very similar to the above requirement, We only need to sort array, and use left and right pointer to find the group with smallest difference between target and the third number.

以上是关于Sum Zero Problem(三数和为0, 破解三重for循环问题)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode15题: 寻找三数和,附完整代码

[LintCode/LeetCode]——两数和三数和四数和

三数和的问题

[LeetCode] 15. 3Sum ☆☆☆(3数和为0)

Codeforces 1270G Subset with Zero Sum

Codeforces 1270G Subset with Zero Sum