前缀和 差分数组编程题集合

简介: 前缀和 差分数组编程题集合

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。


示例 1:


输入:nums = [1,1,1], k = 2

输出:2

示例 2:


输入:nums = [1,2,3], k = 3

输出:2


来源:力扣(LeetCode)

链接:https://leetcode.cn/problems/subarray-sum-equals-k


前缀和加哈希表优化,单纯的使用前缀和本题会超过时间限制,所以在前缀和的基础上加上哈希表进行优化。


 public int subarraySum(int[] nums, int k) {
        int pre=0;
        int result=0;
        Map<Integer,Integer> map=new HashMap<>();
        map.put(0,1);
       for(int i=0;i<nums.length;i++){
          pre+=nums[i];
          if(map.containsKey(pre-k))
              result+=map.get(pre-k);
          map.put(pre,map.getOrDefault(pre,0)+1);
       }
       return result;
    }

滑动窗口,本题我也考虑过使用滑动窗口,但是提交的时候发现很多的问题,对于类似的题数组的值必须是全是正数或负数的可以使用滑动窗口,既有正数也有负数的此类题目并不适用滑动窗口。

下面是动态规划解法,但是数据量很大的时候就会时间超时。代码如下

//dp[i][j]表示数组中i索引到j的元素的和
    public int subarraySum(int[] nums, int k) {
        int dp[][]=new int[nums.length][nums.length];
        int result=0;
        for(int i=0;i<nums.length;i++){
            for(int j=i;j<nums.length;j++){
                if(i==j)
                dp[i][i]=nums[i];
                else
                dp[i][j]=dp[i][j-1]+nums[j];
                if(dp[i][j]==k)
                    result++;
            }
        }
        return result;
    }

给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:


子数组大小 至少为 2 ,且

子数组元素总和为 k 的倍数。

如果存在,返回 true ;否则,返回 false 。


如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。0 始终视为 k 的一个倍数。


示例 1:


输入:nums = [23,2,4,6,7], k = 6

输出:true

解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。

示例 2:


输入:nums = [23,2,6,4,7], k = 6

输出:true

解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。

42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。

示例 3:


输入:nums = [23,2,6,4,7], k = 13

输出:false

 public static boolean checkSubarraySum(int[] nums, int k) {
        int pre=0;
        if(nums.length<2)
            return false;
        Map<Integer,Integer> map=new HashMap<>();
        map.put(0,-1);
        for(int i=0;i<nums.length;i++){
            pre+=nums[i];
            if(map.containsKey(pre%k)){
              if(i-map.get(pre%k)>=2){
                  return true;
              }
            }
            else
            map.put(pre%k,i);
        }
        return false;
    }

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。


示例 1:


输入: nums = [0,1]

输出: 2

说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。

示例 2:


输入: nums = [0,1,0]

输出: 2

说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。

public static int findMaxLength(int[] nums) {
      if(nums.length<2)
        return 0;
     int pre=0;
     int max=0;
     Map<Integer, Integer> map=new HashMap<>();
     map.put(0, -1);
     for(int i=0;i<nums.length;i++) {
       if(nums[i]==0)
         pre=pre-1;
       else
           pre=pre+nums[i];
       if(map.containsKey(pre)) {
         max=Math.max(max, i-map.get(pre));
       }
       else {
         map.put(pre, i);
       }
     }
     return max;
      }

给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。


子数组 是数组的 连续 部分。


示例 1:


输入:nums = [4,5,0,-2,-3,1], k = 5

输出:7

解释:

有 7 个子数组满足其元素之和可被 k = 5 整除:

[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

示例 2:


输入: nums = [5], k = 9

输出: 0

 public int subarraysDivByK(int[] nums, int k) {
          int pre=0;   
        Map<Integer,Integer> map=new HashMap<>();
        map.put(0,1);
        int result=0;
        for(int i=0;i<nums.length;i++){
            pre+=nums[i];
            int key=(pre%k+k)%k;
            if(map.containsKey(key)){
              result+=map.get(key);
            }
            map.put(key,map.getOrDefault(key, 0)+1);
        }
        return result;
    }

差分数组:


对于数组a[i],我们令d[i]=a[i]-a[i-1]  (特殊的,第一个为d[1]=a[1]),则d[i]为一个差分数组。


我们发现统计d数组的前缀和sum数组,有


sum[i]=d[1]+d[2]+d[3]+...+d[i]=a[1]+a[2]-a[1]+a[3]-a[2]+...+a[i]-a[i-1]=a[i],即前缀和sum[i]=a[i];


因此每次在区间[l,r]增减x只需要令d[l]+x,d[r+1]-x,就可以保证[l,r]增加了x,而对[1,l-1]和[r+1,n]无影响。 复杂度则是O(n)的


1109. 航班预订统计


难度中等453收藏分享切换为英文接收动态反馈


这里有 n 个航班,它们分别从 1 到 n 进行编号。


有一份航班预订表 bookings ,表中第 i 条预订记录 bookings[i] = [firsti, lasti, seatsi] 意味着在从 firsti 到 lasti (包含 firsti 和 lasti )的 每个航班 上预订了 seatsi 个座位。


请你返回一个长度为 n 的数组 answer,里面的元素是每个航班预定的座位总数。


示例 1:


输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5

输出:[10,55,45,25,25]

解释:

航班编号        1   2   3   4   5

预订记录 1 :   10  10

预订记录 2 :       20  20

预订记录 3 :       25  25  25  25

总座位数:      10  55  45  25  25

因此,answer = [10,55,45,25,25]


 public  int[] corpFlightBookings(int[][] bookings, int n) {
     int arr[]=new int[n+2];
     for(int i=0;i<bookings.length;i++) {
       int m=bookings[i][0];
       int nn=bookings[i][1];
       int x=bookings[i][2];
       arr[m]+=x;
       arr[nn+1]-=x;
     }
     int sum[]=new int[n];
     sum[0]=arr[1];
     for(int i=1;i<n;i++)
       sum[i]=sum[i-1]+arr[i+1];
     return sum;
   }
相关文章
|
4月前
|
算法
【算法】前缀和——除自身以外数组的乘积
【算法】前缀和——除自身以外数组的乘积
|
7月前
|
算法 测试技术 C++
【分解质因数 差分数组】2584. 分割数组使乘积互质
【分解质因数 差分数组】2584. 分割数组使乘积互质
|
存储 Java 索引
Java数组长度和增强遍历数组
Java数组长度和增强遍历数组
58 0
|
7月前
|
算法 C++
枚举与尺取法 差分与前缀和
枚举与尺取法 差分与前缀和
42 0
|
算法 测试技术 C#
C++前缀和算法:构造乘积矩阵
C++前缀和算法:构造乘积矩阵
剑指offer_数组---构建乘积数组
剑指offer_数组---构建乘积数组
63 0
|
算法 索引
LeetCode算法小抄--数组(双指针、差分数组、前缀和)
LeetCode算法小抄--数组(双指针、差分数组、前缀和)
|
人工智能 Java 算法框架/工具
二维前缀和数组&二维差分数组
二维差分数组div中的每一个格子记录的是「以当前位置为区域的左上角(区域右下角恒定为原数组的右下角)的值的变化量」【应该不固定 可以倒转】
374 0
二维前缀和数组&二维差分数组
|
算法 Go C++
leetcode-2321. 拼接数组的最大分数(差分+枚举)
但其实是在找两个数组之间[Left:Right]区间最大差值,差值我们自然而然的就可以想到差分,但是我们这里求的差分数组并不是两个数组前后元素的差值,而是两个数组同一下标的元素差值,这样我们只要找这段差分区间和的最大值就行了
83 0
leetcode-2321. 拼接数组的最大分数(差分+枚举)