【LeetCode刷题笔记】(四)前缀和

479 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情 这也是第38篇文章

前言

这篇文章总结的专题是前缀和。

“前缀和”可以理解为沿着树的根节点到某个子节点的路线。这个思想很重要也很实用,它避免了很多不必要的搜索,降低了时间复杂度。


先来一道剑指offer的经典题

剑指 Offer II 012. 左右两边子数组的和相等

题目

给你一个整数数组 nums ,请计算数组的 中心下标

数组 中心下标 ****是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

思路

这题是前缀和系列题的简单题,其实只要理解了题意,对其中的公式稍加变化就可以。 设数组中心下标前的部分的和为pre,中心下标为i,数组总和为sum。由于后半部分与前半部分相等,则有:

pre+nums[i]+pre=sumpre+nums[i]+pre=sum

简单变形后得:

2pre=sumnums[i]2*pre=sum-nums[i]

这就是判断条件。

代码实现

class Solution {
    public int pivotIndex(int[] nums) {
        int n=nums.length;
        int sum=Arrays.stream(nums).sum();
        int pre=0;
        for(int i=0;i<n;i++){
            if(2*pre==sum-nums[i]) return i;
            pre+=nums[i];
        }
        return -1;
    }
}

接下来再看另外一道剑指offer中关于前缀和的经典题

剑指 Offer II 008. 和大于等于 target 的最短子数组

题目

给定一个含有 n 个正整数的数组和一个正整数 target。

找出该数组中满足其和 ≥ target的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 如果不存在符合条件的子数组,返回 0 。

思路

这次需要记录数组中每个元素的前缀和并且找最小的,所以要用一个数组来记录所有前缀和的结果。然后通过二分查找找出符合条件的、长度最小的连续子数组。

代码实现

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n=nums.length;
        if(n==0) return 0;
        int [] pre=new int [n+1];
        for(int i=1;i<=n;i++){
            pre[i]=pre[i-1]+nums[i-1];
        }
        int res=Integer.MAX_VALUE;
        for(int i=1;i<=n;i++){
            int goal=target+pre[i-1];
            int bound=binarySearch(goal,pre);
            if(bound<0) bound=-bound-1;
            if(bound<=n)
                res=Math.min(res,bound-i+1);
        }
        return res==Integer.MAX_VALUE?0:res;
    }

    public int binarySearch(int target,int[] nums){
        int n=nums.length;
        int mid=0,res=n;
        int left=0,right=n-1;
        while(left<=right){
            mid=left+(right-left)/2;
            if(target<=nums[mid]){
                res=mid;
                right=mid-1;
            }else left=mid+1;
        }
        return res;
    }
}