139.最接近零的子数组和

描述

给定一个整数数组,找到一个和最接近于零的子数组。返回第一个和最有一个指数。你的代码应该返回满足要求的子数组的起始位置和结束位置

样例

给出[-3, 1, 1, -3, 5],返回[0, 2],[1, 3], [1, 1], [2, 2] 或者 [0, 4]

思路

求完和之后排个序,值接近的两个子数组和就相邻了

代码

class Pair {
    int sum;
    int index;
    public Pair(int s, int i) {
        sum = s;
        index = i;
    }
}
    
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) {
        int[] res = new int[2];
        if (nums == null || nums.length == 0) {
            return res;
        } 
        
        int len = nums.length;

        // 只有一个数时起始下标为0;
        if(len == 1) {
            res[0] = res[1] = 0;
            return res;
        }

        Pair[] sums = new Pair[len+1];
        // 前0个数之和
        // 这里是为只有第一个元素的子数组准备的 
        int prev = 0;
        // 在sums起始位置多添加一组数sums[0],方便计算
        sums[0] = new Pair(0, 0);
        // 给sum[]数组赋值
        // 无论是nums[]数组还是sums数组都是从下标0开始
        for (int i = 1; i <= len; i++) {
            // sums.sum表示前i个数之和,从nums开始数到第i-1个数
            sums[i] = new Pair(prev + nums[i-1], i);
            // prev后移一位
            prev = sums[i].sum;
        }

        // 自定义排序,sums是需要排序的数组,new Comparator(){}是自定义的排序方式,按照sums.sum大小排序
        Arrays.sort(sums, new Comparator() {
           public int compare(Pair a, Pair b) {
               return a.sum - b.sum;
           } 
        });

        int ans = Integer.MAX_VALUE;
        for (int i = 1; i <= len; i++) {
            // 排序后sums[i].sum - sums[i-1].sum一定是正值,满足if时更新ans
            if (ans > sums[i].sum - sums[i-1].sum) {
                // 寻找ans的最小值,即最接近于0的子数组和
                ans = sums[i].sum - sums[i-1].sum;
                // temp将得到的index排序,保证起始点的index不大于结束点的index
                int[] temp = new int[]{sums[i].index - 1, sums[i - 1].index - 1};
                // 调用默认的ASCII码排序
                Arrays.sort(temp);
                /* 因为sum的index是原数组中index为(0, i-1)的和,
                 * 存入temp的时候,index要减1才是真正的index;假如i > j ,
                 * 那么sum(0, i) - sum(0, j)表示的是(j + 1, i)这一段的和,所以要给小的那个加1
                 */
                res[0] = temp[0] + 1;
                res[1] = temp[1];
            }
        }
        
        return res;
    }
}

问:

为什么需要一个 (0,0) 的初始 Pair?

答:

我们首先需要回顾一下,在 subarray 这节课里,我们讲过一个重要的知识点,叫做 Prefix Sum
比如对于数组 [1,2,3,4],他的 Prefix Sum 是 [1,3,6,10]
分别表示 前1个数之和,前2个数之和,前3个数之和,前4个数之和
这个时候如果你想要知道 子数组 从下标 1 到下标 2 的这一段的和(2+3),就用前 3个数之和 减去 前1个数之和 = PrefixSum[2] - PrefixSum[0] = 6 - 1 = 5
你可以看到这里的 前 x 个数,和具体对应的下标之间,存在 +-1 的问题
第 x 个数的下标是 x - 1,反之 下标 x 是第 x + 1 个数
那么问题来了,如果要计算 下标从 0~2 这一段呢?也就是第1个数到第3个数,因为那样会访问到 PrefixSum[-1]
所以我们把 PrefixSum 整体往后面移动一位,把第0位空出来表示前0个数之和,也就是0. => [0,1,3,6,10]
那么此时就用 PrefixSum[3] - PrefixSum[0] ,这样计算就更方便了。
此时,PrefixSum[i] 代表 前i个数之和,也就是 下标区间在 0 ~ i-1 这一段的和
那么回过头来看看,为什么我们需要一个 (0,0) 的 pair 呢?
因为 这个 0,0 代表的就是前0个数之和为0
一个 n 个数的数组, 变成了 prefix Sum 数组之后,会多一个数出来

关于自定义Arrays.sort:

    Arrays.sort(objects, new Comparator() {  
            public int compare(Object object1, Object object2) {  
  
                    return object1.num - object2.num;  
            
        });  

比如这样,主要是重写compare方法,返回一个你需要的值来进行排序,这个返回值就是排序 的依据,比如要按object的num进行升序排序,就可以根据object1.num - object2.num来排序,如果返回的是object2.num - object1.num的话实际效果就是降序

你可能感兴趣的:(139.最接近零的子数组和)