Friday, February 25, 2011

an array contain +ve and -ve element, find subarray whose sum =0;

an array contain +ve and -ve element, find subarray whose sum =0;

Lets take input array as a[]={-3,2,4,-6,-8,10,11}



Working JAVA Code
---------------------------

import java.util.Comparator;


public class Index implements Comparable{
Integer start;
Integer end;
public Integer getStart() {
    return start;
}
public void setStart(Integer start) {
    this.start = start;
}
public Integer getEnd() {
    return end;
}
public void setEnd(Integer end) {
    this.end = end;
}


public int compareTo(Object index1) {
 
    index1 = (Index) index1;
    Index index2 = (Index) this;
    Integer  index1Distance = ((Index) index1).getEnd().intValue() -  ((Index) index1).getStart().intValue();
    Integer index2Distance = ((Index) index2).getEnd().intValue() -  ((Index) index2).getStart().intValue();
    if (index1Distance > index2Distance)
        return 1;
    else if (index1Distance == index2Distance)
        return 0;
    else
        return -1;
}
}

import java.util.HashMap;
import java.util.Map;


public class SubarraywithSumZero {

    public Index findLongestSubArraywithSumZero(long[] inputArray) {
        // 1. Generate a cummulative array
        for (int i=1; i < inputArray.length; i++) {
            inputArray[i] += inputArray[ (i-1)];
        }
        //2. Read the array, store it in map
        // For a subraary with 0 there should + and - numbers
        // we need to figure the longest distance indexes which have same numbers
        // since our array is cummulative postives and negatives which sum to 0 will bring the
        // intermittent array back to same number where it started
        // eg intermittent array = -6, -8, -10, -6, -4, 1, 2, 3, 4, 1
        // now from -6 we again reach -6
        // and later from 1 back to 1 which implies these two arrays are summing to 0
        // we just need the longest one
        Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
        Index maxIndex = null;
        for (int i=0; i < inputArray.length; i++) {
            Integer index = new Integer(i);
            Integer val = new Integer((int) inputArray[i]);
            if (indexMap.get(val) == null) {
                indexMap.put(val, index);
            }
            else {
                if (maxIndex == null) {
                    maxIndex = new Index();
                    //collosion found the subarray
                    maxIndex.setStart(indexMap.get(val));
                    maxIndex.setEnd(new Integer(i));
                }
                else  {
                    Index index1 = new Index();
                    index1.setStart(indexMap.get(val));
                    index1.setEnd(new Integer(i));
                    if (maxIndex.compareTo(index1) <= 0) {
                        maxIndex = index1;
                    }
                }
            }
        }
            return maxIndex;       
    }
   
    public static void main(String[] args) {
        long inputArray[] = {3,2,4,-6,-8,10,11};
       
        SubarraywithSumZero subarraywithSumZero = new SubarraywithSumZero();
        Index maxIndex = subarraywithSumZero.findLongestSubArraywithSumZero(inputArray);
        System.out.println("Longgest Subarray with sum starts at [" + maxIndex.getStart() + " ] and ends at [" + maxIndex.getEnd() + "]");
    }
}


4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Hi Inder,

    In the above solution one corner case might be missing. If the first 5 elements of the array forms the largest sub sequence, example,
    long inputArray[] = { 3, -2, 4, -5, -8, 10, 2, 4, 5, 6, 7 };

    In this array the longest sub sequence that sum up to 0 is [3, -2, 4, -5]

    In the cumulative array the 4th element would be 0. As the Map does not have a entry with key 0, code would miss the first occurrence. You may initialize the

    indexMap with initial key value pairs,

    Integer k0 = new Integer(0);
    Integer v0 = new Integer(0);

    Thanks,
    Gautam

    ReplyDelete
  4. The output from your program is :
    Longgest Subarray with sum starts at [0 ] and ends at [3]
    how the hell do u get the above solution with your input array:{ 3, 2, 4, -6, -8, 10, 11 }
    The correct solution should be from index 2 to index 5.

    Can't you even check your program whether its giving correct answer or not.
    Please dont publish any unchecked code over here as it leads to unnecessary wastage of time.

    ReplyDelete