Wednesday, March 29, 2017

Subarray Sum Closest

Given an integer array, find a subarray with sum closest to zero. Return the indexes of the first number and last number.
变化为prefixSum里面找最接近的两个数
如何找最接近?把prefixSum按数值排序,相邻的最有可能最接近,扫一遍之后得到min。因为可以任意返回,所以只有比当前min小才更新,否则不更新。(有一个比较有病的test case,因为最初一般会把min设置成Integer,MAX_VALUE,有一个test case输入就是这个MAX_VALUE,造成min index没有更新,于是IndexOutOfBoundsException)
Key Point是prefixSum中的index代表的是前i个数的和,而不是加到当前index i的和。
在最后譬如
index           4    1    2    3    0    5
prefixSum  -4   -3  -2   -1    0    1
                  left right

minIndex = 1
right = sumList.get(minIndex).index = 1;
left = sumList.get(minIndex - 1).index = 4;
注意它们代表的是前1个数的sum: index = 0 和前4个数的sum: index = 0, 1, 2, 3
相减之后参与的index有 1, 2, 3
也就是说较大的index最后要减1
这部分代码写的比较丑,不过也没有办法。看了九章的答案,也没好到哪里去。

class Tuple {
    public int index;
    public int prefixSum;
    public Tuple(int index, int prefixSum) {
        this.index = index;
        this.prefixSum = prefixSum;
    }
}
class TupleComparator implements Comparator<Tuple> {
    @Override
    public int compare(Tuple t1, Tuple t2) {
        return t1.prefixSum - t2.prefixSum;
    }
}
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number
     *          and the index of the last number
     */
    public int[] subarraySumClosest(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) return new int[]{-1, -1};
        List<Tuple> sumList = new ArrayList<>();
        int sum = 0;
        sumList.add(new Tuple(0, sum));
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            sumList.add(new Tuple(i + 1, sum));
        }
        Collections.sort(sumList, new TupleComparator());
        long minDifference = Long.MAX_VALUE;
        int minIndex = -1;
        for (int i = 1; i < sumList.size(); i++) {
            int difference = Math.abs(sumList.get(i).prefixSum - sumList.get(i - 1).prefixSum);
            if (difference < minDifference) {
                minDifference = difference;
                minIndex = i;
            }
        }
        // left is i - 1, right is i
        //left index sumList.get(i - 1).index
        //right index sumList.get(i).index
        int left = sumList.get(minIndex - 1).index;
        int right = sumList.get(minIndex).index;
        return new int[] {Math.min(left, right), Math.max(left, right) - 1};
    }
}

No comments:

Post a Comment