前缀和:中心下标与数组乘积

文章目录

一、左右信息的统一视角

对于下标 i,可以把数组拆成三部分:

text 复制代码
[0, i) + nums[i] + (i, n)

中心下标比较左右两侧的和;除自身以外数组的乘积则把左右两侧的乘积相乘。两题的共同点是都不需要在处理每个 i 时重新扫描左右区间。

二、寻找数组的中心下标

LeetCode 724. 寻找数组的中心下标

dp[i] 表示下标 i 左侧所有元素的和,那么 dp[nums.length] 就是整个数组的总和。

如果 i 是中心下标,则有:

text 复制代码
左侧和 = 右侧和
dp[i] = dp[nums.length] - dp[i] - nums[i]

移项后可以直接判断:

text 复制代码
dp[i] * 2 + nums[i] == dp[nums.length]

这样只需要一个前缀和数组,不必再建立后缀和数组。代码从左向右检查,因此找到的第一个结果自然是最靠左的中心下标。

java 复制代码
class Solution {
    public int pivotIndex(int[] nums) {
        long[] dp = new long[nums.length + 1];
        for (int i = 1; i < nums.length + 1; i++) {
            dp[i] = dp[i - 1] + nums[i - 1];
        }

        for (int i = 0; i < nums.length; i++) {
            if (dp[i] * 2 + nums[i] == dp[nums.length]) {
                return i;
            }
        }
        return -1;
    }
}

时间复杂度为 O(n),空间复杂度为 O(n)。按照本题约束,int 足以保存总和;这里使用 long 可以降低代码对数值范围的依赖。

三、除了自身以外数组的乘积

LeetCode 238. 除了自身以外数组的乘积

如果先求全部元素的乘积,再除以 nums[i],遇到 0 时就无法处理,而且题目本身也要求不使用除法。可以分别保存左侧前缀积和右侧后缀积:

  • dpleft[i]:下标 0i - 1 的元素乘积;
  • dpright[i]:下标 ilen - 1 的元素乘积。

因此,下标 i 的答案为:

text 复制代码
ret[i] = dpleft[i] * dpright[i + 1]

数组两端没有元素的一侧按乘法单位元 1 处理,所以初始化 dpleft[0] = 1dpright[len] = 1

java 复制代码
class Solution {
    public int[] productExceptSelf(int[] nums) {
        int len = nums.length;
        int[] dpleft = new int[len + 1];
        int[] dpright = new int[len + 1];

        dpleft[0] = 1;
        dpright[len] = 1;
        for (int i = 0; i < len; i++) {
            dpleft[i + 1] = dpleft[i] * nums[i];
        }
        for (int i = len - 1; i >= 0; i--) {
            dpright[i] = dpright[i + 1] * nums[i];
        }

        int[] ret = new int[len];
        for (int i = 0; i < len; i++) {
            ret[i] = dpleft[i] * dpright[i + 1];
        }
        return ret;
    }
}

题目保证相关前缀积、后缀积与答案都在 32 位整数范围内,因此可以使用 int[]。时间复杂度为 O(n),额外空间复杂度为 O(n)

相关推荐
Lazionr1 小时前
list容器详解——双向链表的封装与使用
数据结构·c++·链表·list
windliang1 小时前
Claude Code 源码分析(八):Memory 如何被写入、整理与按需召回
前端·算法·面试
漂流瓶jz1 小时前
UVA-12174 Shuffle的播放记录 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·图论·滑动窗口·算法竞赛入门经典·uva
Forever Nore1 小时前
LeetCode 6 Z 字形变换 - 按行模拟
算法·leetcode
lingran__2 小时前
C++ 高阶数据结构:红黑树万字详解|完整原理推导 + 插入实现 + 完整性校验【STL 底层】
数据结构·c++·面试·红黑树·二叉搜索树·平衡二叉树·stl底层
fkyyly2 小时前
hermes解读
算法·code_agent
过期的秋刀鱼!2 小时前
使用都热编码的分类特征
人工智能·算法·决策树·机器学习·分类·数据挖掘
wabs6663 小时前
关于哈希表【力扣383.赎金信的思考】
算法·leetcode·散列表
moonsims3 小时前
低空量子无人机
前端·数据结构