【每日三题】连续的子数组和

123 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情 >>


每日三刷,剑指千题

计划简介:

  • 每日三题,以中等题为主,简单题为辅进行搭配。保证质量题1道,数量题3道。
  • 每日早通勤在LeetCode手机端选题,思考思路,没答案的直接看题解。
  • 每日中午进行编码,时间控制在一小时之内。
  • 下班前半小时进行整理总结,并发布到掘金每日更文活动。

说明:

  • 基于以前的刷题基础,本次计划以中等题为主,大部分中等题都可以拆分为多个简单题,所以数量保证3,质量保证一道中等题即可。
  • 刷题顺序按照先刷链表、二叉树、栈、堆、队列等基本数据结构,再刷递归、二分法、排序、双指针等基础算法,最后是动态规划、贪心、回溯、搜索等复杂算法。
  • 刷题过程中整理相似题型,刷题模板。
  • 目前进度 171/1000

今日题型

前缀和

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i])

请返回 nums 的动态和。

示例 1:

输入:nums = [1,2,3,4]
输出:[1,3,6,10]
解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4]

解析

前缀和的简单变形。

Code

class Solution {
    public int[] runningSum(int[] nums) {
        int[] ans = new int[nums.length];
        ans [0] = nums[0];
        for (int i = 1; i < ans.length; i++) {
            ans[i] = ans[i-1]+nums[i];
        }
        return ans;
    }
}

[523]连续的子数组和

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

  • 子数组大小 至少为 2 ,且
  • 子数组元素总和为 k 的倍数。

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

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

示例 1:

输入:nums = [23,2,4,6,7], k = 6
输出:true
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。

解析

Code

class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        // 连续子数组和 = 前缀和的差
        // 先构建前缀和
        int[] sum = new int[nums.length + 1];
        for (int i = 1; i < sum.length; i++) {
            sum[i] = sum[i-1] + nums[i-1];
        }
​
        // 同余定理:如果两个数相减能被 k 整除,则连个数 % k 的余数相同。
        Set<Integer> set = new HashSet<>();
        for (int i = 2; i < sum.length ; i++) {
            set.add(sum[i-2] % k);
            if (set.contains(sum[i] % k)){
                return true;
            }
​
        }
        return false;
    }
}

[1524]和为奇数的子数组数目

给你一个整数数组 arr 。请你返回和为 奇数 的子数组数目。

由于答案可能会很大,请你将结果对 10^9 + 7 取余后返回。

示例 1:

输入:arr = [1,3,5]
输出:4
解释:所有的子数组为 [[1],[1,3],[1,3,5],[3],[3,5],[5]] 。
所有子数组的和为 [1,4,9,3,8,5].
奇数和包括 [1,9,3,5] ,所以答案为 4 。

解析

Code

class Solution {
        public int numOfSubarrays(int[] arr) {
            int m = 1000000007;
            // 前缀和 + 数学
            int[] sum = new int[arr.length + 1];
            for (int i = 1; i < sum.length; i++) {
                sum[i] = sum[i - 1] + arr[i - 1];
            }
​
            // 只有奇数和偶数相减才可能为奇数  [0,1,
            int j = 0, o = 0;
            int ans = 0;
            for (int i = 0; i < sum.length; i++) {
                if (sum[i] % 2 == 0) {
                    ans = (ans + j) % m;
                    o++;
                } else {
                    ans = (ans + o) % m;
                    j++;
                }
            }
            return ans;
        }
    }

\