【算法】前缀和(二)使用

文章目录

一、问题直化前缀和

1.拆拼

二、问题转用前缀和

1.模减消实质

2.同余定理

2.1证明

3.取模%

3.1计算机

[3.1.1向零取整 相除](#3.1.1向零取整 相除)

3.1.2符号

3.2数学

[3.2.1向下取整 相除](#3.2.1向下取整 相除)

3.2.2符号

3.3两者关系

3.3.1差异

3.3.2转化


上篇:【算法】前缀和(一)原理

一、问题直化前缀和

238. 除自身以外数组的乘积 - 力扣(LeetCode)

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

不要使用除法, 且在 O(n) 时间复杂度内完成此题。

示例 1:

复制代码
输入: nums = [1,2,3,4]

输出: [24,12,8,6]

示例 2:

复制代码
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 输入 保证 数组 answer[i]32 位 整数范围内

1.拆拼

整体 拆分能同类累积部分 拼合

java 复制代码
public int[] productExceptSelf(int[] nums) {
    int n = nums.length;
    int[] f = new int[n], g = new int[n], ret = new int[n];
    f[0] = g[n - 1] = 1;
    for (int i = 1; i < n; i++)
        f[i] = f[i - 1] * nums[i - 1];
    for (int i = n - 2; i >= 0; i--)
        g[i] = g[i + 1] * nums[i + 1];
    for (int i = 0; i < n; i++)
        ret[i] = f[i] * g[i];
    return ret;
}

二、问题转用前缀和

974. 和可被 K 整除的子数组 - 力扣(LeetCode)

给定一个整数数组 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

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • 2 <= k <= 104

1.模减消实质

(a + p*k) % p = a % p


2.同余定理

差被++整++除 ++(a - b) % p = 0++ or (a - b) / p = k

=> 减数 模 除数 ++相等++ ++a % p = b % p++

2.1证明

(a - b) / p = k

-> a - b = p*k

-> a = b + p*k

-> a % p = (b + p*k) % p

-> a % p = b % p


3.取模%

3.1计算机

3.1.1向零取整 相除

余数绝对值 最接近0 地相除

3.1.2符号

同被除数


3.2数学

3.2.1向下取整 相除

余数正值 最接近0 地相除

3.2.2符号

正数


3.3两者关系

3.3.1差异

只有 负 % 正负数取模结果会不同 (计算机为负、数学为正)

3.3.2转化

计算机 相同等效、不同转化 为 数学 的模结果:(a % p + p) / p

java 复制代码
public int subarraysDivByK(int[] nums, int k) {
    Map<Integer,Integer> map = new HashMap<>();
    int sum = 0, ret = 0;
    map.put(0,1); // sum = k,sum % k = 0,自己整的区间可以被k整除的是结果,自己整的就是结果,但往前减区间来得 是得不到的,得特判为就是结果地 就开始累积
    for (int i = 0; i < nums.length; i++) {
        sum += nums[i];
        int r = (sum % k + k) % k;
        // 找满足的前缀和:
        ret += map.getOrDefault(r,0); // (sum - x) % k = 0 => sum % k = x % k,往前找 已存进哈希表里的 前缀和x % k的模 有多少个 等于 当前总区间前缀和sum % k的模
        // 存前缀和:
        map.put(r, map.getOrDefault(r,0) + 1);
    }
    return ret;
}
相关推荐
落羽的落羽几秒前
【Linux系统】从零实现一个简易的shell!
android·java·linux·服务器·c++·人工智能·机器学习
We་ct1 分钟前
LeetCode 1. 两数之和:两种高效解法(双指针 + Map)
前端·算法·leetcode·typescript·哈希算法
云小逸4 分钟前
【Nmap源码学习】Nmap 网络扫描核心技术深度解析:从协议识别到性能优化
网络·学习·性能优化
代码游侠4 分钟前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
aini_lovee5 分钟前
基于MATLAB的材料晶粒组织生长与变化模拟:方法、实现与应用
开发语言·算法·matlab
1104.北光c°5 分钟前
【黑马点评项目笔记 | 优惠券秒杀篇】构建高并发秒杀系统
java·开发语言·数据库·redis·笔记·spring·nosql
t198751287 分钟前
基于MATLAB的Copula对数似然值计算与参数验证
人工智能·算法·matlab
ruleslol8 分钟前
普通流(Stream<T>)和原始类型特化流(IntStream, LongStream, DoubleStream)的区别
java
隐退山林8 分钟前
JavaEE初阶:文件操作和IO
java·java-ee
2501_907136829 分钟前
PDF增效工具 Quite imposing plus6
java·开发语言