maximum subarray whose sum equals 0

后端 未结 12 1331
礼貌的吻别
礼貌的吻别 2020-12-04 08:14

An array contains both positive and negative elements, find the maximum subarray whose sum equals 0.

相关标签:
12条回答
  • 2020-12-04 08:50

    This is one the same lines as suggested by Gevorg but I have used a hash map for quick lookup. O(n) complexity used extra space though.

    private static void subArraySumsZero()
    {
        int [] seed = new int[] {1,2,3,4,-9,6,7,-8,1,9};
        int currSum = 0;
        HashMap<Integer, Integer> sumMap = new HashMap<Integer, Integer>();
        for(int i = 0 ; i < seed.length ; i ++)
        {
            currSum += seed[i];
            if(currSum == 0)
            {
                System.out.println("subset : { 0 - " + i + " }");
            }
            else if(sumMap.get(currSum) != null)
            {
                System.out.println("subset : { " 
                                    + (sumMap.get(currSum) + 1) 
                                    + " - " + i + " }");
                sumMap.put(currSum, i);
            }
            else
                sumMap.put(currSum, i);
        }
        System.out.println("HASH MAP HAS: " + sumMap);
    }
    

    The output generated has index of elements (zero based):

    subset : { 1 - 4 }
    subset : { 3 - 7 }
    subset : { 6 - 8 }
    
    0 讨论(0)
  • 2020-12-04 08:55

    Following solution finds max length subarray with a given sum k without using dynamic programming, but using simple rescursion. Here i_s is start index and i_e is end index for the current value of sum

    ##Input the array and sum to be found(0 in your case)
    a = map(int,raw_input().split())
    k = int(raw_input())
    
    ##initialize total sum=0
    totalsum=0
    
    ##Recursive function to find max len 0
    def findMaxLen(sumL,i_s,i_e):
        if i_s<len(a)-1 and i_e>0: 
            if sumL==k:
                print i_s, i_e
                return (i_s,i_e)
            else:
                x = findMaxLen(sumL-a[i_s],i_s+1,i_e)
                y = findMaxLen(sumL-a[i_e],i_s,i_e-1)
                if x[1]-x[0]>y[1]-y[0]:
                    return x
                else:
                    return y
        else:
            ##Result not there
            return (-1,-1)
    
    
    ## find total sum
    for i in range(len(a)):
        totalsum += a[i]
    
    ##if totalsum==0, max array is array itself
    if totalsum == k:
        print "seq found at",0,len(a)-1
    
    ##else use recursion
    else:
        print findMaxLen(totalsum,0,len(a)-1)
    

    Time complexity is O(n) and space complexity is O(n) due to recursive memory stack

    0 讨论(0)
  • 2020-12-04 09:02

    Here's my implementation, it's the obvious approach so it's probably sub-optimized, but at least its clear. Please correct me if i'm wrong.

    Starts from each index of the array and calculates and compares the individual sums (tempsum) with the desired sum (in this case, sum = 0). Since the integers are signed, we must calculate every possible combination.

    If you don't need the full list of sub-arrays, you can always put conditions in the inner loop to break out of it. (Say you just want to know if such a sub-array exists, just return true when tempsum = sum).

    public static string[] SubArraySumList(int[] array, int sum)
    {
        int tempsum;
        List<string> list = new List<string>();
        for (int i = 0; i < array.Length; i++)
        {
            tempsum = 0;
            for (int j = i; j < array.Length; j++)
            {
                tempsum += array[j];
                if (tempsum == sum)
                {
                    list.Add(String.Format("[{0}-{1}]", i, j));
                }
            }
        }
        return list.ToArray();
    }
    

    Calling the function:

    int[] array = SubArraySumList(new int { 0, -1, 1, 0 }, 0));
    

    Printing the contents of the output array:

    [0-0], [0-2], [0-3], [1-2], [1-3], [3-3]
    
    0 讨论(0)
  • 2020-12-04 09:03

    Here's an O(n) implementation in java

    The idea is to iterate through the given array and for every element arr[i], calculate sum of elements form 0 to i, store each sum in HashMap.

    • If an element is 0, it's considerd as a a ZeroSum sub array.

    • if sum became 0, then there is a ZeroSum sub array, from 0 to i.

    • If the current sum has been seen before in HashMap, then there is a ZeroSum sub array, from that point to i.

    Code:

    import java.util.*;
    import java.lang.*;
    
    class Rextester
    {  
        private static final int[] EMPTY = {};
        // Returns int[] if arr[] has a subarray with sero sum
        static int[] findZeroSumSubarray(int arr[])
        {
            if (arr.length == 0) return EMPTY;
            // Creates an empty hashMap hM
            HashMap<Integer, Integer> hM = new HashMap<Integer, Integer>();
            // Initialize sum of elements
            int sum = 0;        
            for (int i = 0; i < arr.length; i++)
            {   
                sum += arr[i]; 
                if (arr[i] == 0)   //Current element is 0
                {
                   return new int[]{0}; 
                }
                else if (sum == 0)  // sum of elements from 0 to i is 0
                {
                    return Arrays.copyOfRange(arr, 0, i+1);
                }
                else if (hM.get(sum) != null) // sum is already present in hash map
                {
                    return Arrays.copyOfRange(arr, hM.get(sum)+1, i+1);
                }
                else
                {
                    // Add sum to hash map
                    hM.put(sum, i);
                }
            }    
            // We reach here only when there is no subarray with 0 sum
            return null;
        }        
    
        public static void main(String arg[])
        {
            //int arr[] = {};
            int arr[] = { 2, -3, 1, 4, 6}; //Case left
            //int arr[] = { 0, 2, -3, 1, 4, 6}; //Case 0
            //int arr[] = { 4, 2, -3, 1, 4}; // Case middle
            int result[] = findZeroSumSubarray(arr);
            if (result == EMPTY){
                System.out.println("An empty array is ZeroSum, LOL"); 
            }
            else if ( result != null){
                System.out.println("Found a subarray with 0 sum :" );
                for (int i: result) System.out.println(i);
            }
            else
                System.out.println("No Subarray with 0 sum");            
        }           
    }
    

    Please see the experiment here: http://rextester.com/PAKT41271

    0 讨论(0)
  • 2020-12-04 09:03

    Another solution to this problem could be: 1. Calculate sum for entire array 2. Now follow following formula to get the largest subarray with sum zero:

    Math.max(find(a,l+1,r,sum-a[l]), find(a,l,r-1,sum-a[r]));
    where l=left index, r= right index, initially their value=0 and a.length-1
    

    Idea is simple, max size we can get with sum=0, is the size of array then we start skipping elements from left and right recursively, the moment we get sum=0 we stop. Below is the code for same:

    static int find(int a[]) {
        int sum =0;
        for (int i = 0; i < a.length; i++) {
            sum = sum+a[i];
        }
    
        return find(a, 0, a.length-1, sum);
    }
    
    
    static int find(int a[], int l, int r, int sum) {
        if(l==r && sum>0) {
            return 0;
        }
        if(sum==0) {
            return r-l+1;
        }
        return Math.max(find(a,l+1,r,sum-a[l]), find(a,l,r-1,sum-a[r]));
    
    }
    
    0 讨论(0)
  • 2020-12-04 09:04

    The link in the current accepted answer requires to sign up for a membership and I do not its content.

    This algorithm will find all subarrays with sum 0 and it can be easily modified to find the minimal one or to keep track of the start and end indexes. This algorithm is O(n).

    Given an int[] input array, you can create an int[] tmp array where tmp[i] = tmp[i - 1] + input[i]; Each element of tmp will store the sum of the input up to that element(prefix sum of array).

    Now if you check tmp, you'll notice that there might be values that are equal to each other. Let's say that this values are at indexes j an k with j < k, then the sum of the input till j is equal to the sum till k and this means that the sum of the portion of the array between j and k is 0! Specifically the 0 sum subarray will be from index j + 1 to k.

    • NOTE: if j + 1 == k, then k is 0 and that's it! ;)
    • NOTE: The algorithm should consider a virtual tmp[-1] = 0;
    • NOTE: An empty array has sum 0 and it's minimal and this special case should be brought up as well in an interview. Then the interviewer will say that doesn't count but that's another problem! ;)

    The implementation can be done in different ways including using a HashMap with pairs but be careful with the special case in the NOTE section above.

    Example:

    int[] input = {4,  6,  3, -9, -5, 1, 3, 0, 2}
    int[] tmp =   {4, 10, 13,  4, -1, 0, 3, 3, 5}
    
    • Value 4 in tmp at index 0 and 3 ==> sum tmp 1 to 3 = 0, length (3 - 1) + 1 = 3
    • Value 0 in tmp at index 5 ==> sum tmp 0 to 5 = 0, length (5 - 0) + 1 = 6
    • Value 3 in tmp at index 6 and 7 ==> sum tmp 7 to 7 = 0, length (7 - 7) + 1 = 1

    ****UPDATE****

    Assuming that in our tmp array we end up with multiple element with the same value then you have to consider every identical pair in it! Example (keep in mind the virtual '0' at index '-1'):

    int[] array = {0, 1, -1, 0}
    int[] tmp = {0, 1, 0, 0}
    

    By applying the same algorithm described above the 0-sum subarrays are delimited by the following indexes (included):

    [0] [0-2] [0-3] [1-2] [1-3] [3]

    Although the presence of multiple entries with the same value might impact the complexity of the algorithm depending on the implementation, I believe that by using an inverted index on tmp (mapping a value to the indexes where it appears) we can keep the running time at O(n).

    0 讨论(0)
提交回复
热议问题