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

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

文章目录

 一、问题直化前缀和

1.拆拼

二、问题转用前缀和

1.模减消实质

2.同余定理

2.1证明

3.取模%

3.1计算机

3.1.1向零取整 相除

3.1.2符号

3.2数学

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.拆拼

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

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

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; }

Read more

重生之我在异世界学编程之算法与数据结构:深入静态顺序表篇

重生之我在异世界学编程之算法与数据结构:深入静态顺序表篇

大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在ZEEKLOG这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 * 引言 * 正文 * 一、顺序表的概念及结构 * 1. 顺序表的定义 * 2. 顺序表的结构 * 3. 顺序表的初始化 * 二、顺序表的基本操作(静态) * 1. 插入操作 * 2. 删除操作 * 3. 查找操作 * 4. 更新操作 * 5. 获取元素操作 * 6. 遍历操作 * 7. 求顺序表的长度 * 8. 判断顺序表是否为空 * 快乐的时光总是短暂,咱们下篇博文再见啦!!!在下一篇博文,小编将会带着宝子们学习动态顺序表,敬请期待吧!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!! 引言 C语言顺序表(Sequential List)是一种线性表的存储结构,

By Ne0inhk
进阶数据结构: AVL树

进阶数据结构: AVL树

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go! 我的博客:yuanManGan 我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记  闲言碎语小记坊 题山采玉 领略算法真谛 目录 AVL相关概念:  AVL树的结构 Insert  旋转 右旋: 编辑 左单旋:  右左双旋: 左右双旋:  完整的插入: 其他简单的操作:  测试: AVL相关概念: AVL树是由二叉搜索树加上一定的限制而形成的树,AVL树:它的左右子树都是AVL树,且左右子树的高度差的绝对值不超过1。AVL树是⼀颗⾼度平衡搜索⼆叉树, 通过控制⾼度差去控制平衡。

By Ne0inhk
C++ 核心数据结构:Stack 与 Queue 类深度解析

C++ 核心数据结构:Stack 与 Queue 类深度解析

🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟     目录 💯前言 💯Stack 类 (一)Stack 类的概念与特点 (二)Stack 类的使用 (三)Stack 类的内部实现(手动实现) (四)Stack 类的应用场景 💯Queue 类 (一)Queue 类的概念与特点 (二)Queue 类的使用 (三)Queue 类的内部实现(手动实现) (四)Queue 类的应用场景 💯总结 💯前言 在 C++ 编程领域,数据结构的合理运用是构建高效、可靠程序的关键因素之一。Stack(栈)和 Queue(队列)作为两种基础且重要的数据结构,

By Ne0inhk
Redis Hash 全解析:从入门到精通,解锁高性能对象存储的钥匙

Redis Hash 全解析:从入门到精通,解锁高性能对象存储的钥匙

前言 在现代应用开发中,我们无时无刻不在与“对象”打交道——用户信息、商品详情、配置项、会话数据……如何高效、清晰地在缓存或数据库中存储这些结构化数据,是每一个开发者都需要面对的课题。 你可能会想到将一个对象序列化成 JSON 字符串,然后用一个简单的 Key-Value 方式存入 Redis。这确实是一种方法,但当你只想修改对象的某一个属性(比如用户的积分)时,就不得不读取整个 JSON 字符串,反序列化成对象,修改属性,再序列化回 JSON,最后整个写回 Redis。这个过程不仅繁琐,而且在并发环境下极易引发数据覆盖问题,性能开销也相当可观。 那么,有没有一种更原生、更高效的方式来处理这种“对象”存储呢?答案是肯定的。Redis 为我们提供了一种强大的数据结构,它天生就是为了解决这类问题而生——Hash(哈希/散列)。 本文将带领你深入探索 Redis Hash

By Ne0inhk