[LC优选算法#18] 前缀和 | 除⾃⾝以外数组的乘积 | 和为K的⼦数组 | 和可被K整除的⼦数组

1. 除⾃⾝以外数组的乘积

除⾃⾝以外数组的乘积

解题思路:

由于题目限制了不能使用除法,因此不能采用全部相乘在除以nums[i]的方式解题。从暴力解法出发,我们只能将除nums[i]以外的元素相乘后逐个放入数组,但这样重复的操作太多,不符合O(N)的时间复杂度。因此,我们采用前缀和思想优化暴力解法。

  1. 前缀和 O(N):对于返回数组中的每一个结果ret[i],都是由两部分组成的:前面 元素的乘积 * 后面 元素的乘积。因此,我们可以预处理出两个前缀和数组,一个数组存储每个数之前元素的乘积,另一个存之后元素的乘积。
cpp 复制代码
class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums)
    {
        int n = nums.size();
        vector<int> fx(n, 1);
        vector<int> gx(n, 1);

        for(int i=1; i<n; i++)
        {
            fx[i] = fx[i - 1] * nums[i - 1];
        }

        for(int i=n-2; i>=0; i--)
        {
            gx[i] = gx[i + 1] * nums[i + 1];
        }

        vector<int> ret;
        for(int i=0; i<n; i++)
        {
            int left = fx[i];
            int right = gx[i];

            ret.push_back(left * right);
        }

        return ret;
    }
};

2. 和为K的⼦数组

和为 k 的⼦数组

解题思路:

  1. 暴力 O(N^2):固定起始位置向后枚举,每次加到末尾,统计数组中和为K的子数组个数。
  2. 前缀和 + 哈希表 时O(N)空O(N):这道题和前缀和的例题类似,但如果只是单单预处理一个前缀和数组,后续还需要进行多次相减才能找到和为K的连续子数组个数,和暴力枚举貌似没区别。对此,我们引入哈希表 存储,这样问题就转化为在数组中查找和为sum[i] - k的前缀和了。
cpp 复制代码
class Solution {
public:
    int subarraySum(vector<int>& nums, int k)
    {
        unordered_map<int, int> hash;
        int sum = 0, cnt = 0;
        hash[0] = 1;
        
        for(auto x : nums)
        {
            sum += x;
            if(hash.count(sum - k) == 1)
            {
                cnt += hash[sum - k];
            }

            hash[sum]++;
        }

        return cnt;
    }
};

3. 和可被K整除的⼦数组

和可被K整除的⼦数组

前置知识

  • 同余定理 :如果 (a - b) % n == 0,那么我们可以得到一个结论:a % n == b % n,反过来也成立。⽤⽂字叙述就是,如果两个数相减的差能被 n 整除,当且仅当这两个数对 n 取模的结果相同。
  • 负数取模修正 :C++中对负数取模,结果还会返回负数(取模结果加上符号)。我们需要对取模结果进行修正,以(a % n + n) % n的形式输出保证为正。例如:-1 % 3 = (-1 % 3 + 3) % 3 = 2

解题思路:

  1. 前缀和 + 哈希表 时O(N)空O(N):本题解题思路和上题类似,都是用哈希表+前缀和 解决。根据同余定理,如果s1 % ksum % k的余数相同,那么所求的子区间(sum - s1) % k == 0。这样问题就变为:找到在[0, i - 1]区间内,有多少前缀和的余数等于sum[i] % k的区间即可。
cpp 复制代码
class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k)
    {
        unordered_map<int, int> hash; //存储余数+出现次数

        int sum = 0, ret = 0;
        hash[0] = 1; //0位置初始化为1,因为0是可以整除任何数的元素

        for(auto x : nums)
        {
            sum += x;
            int r = (sum % k + k) % k;
            if(hash.count(r))
            {
                ret += hash[r]; //sum范围内所有余数为r的子区间都满足
            }

            hash[r]++;
        }

        return ret;
    }
};

// 本期内容就到这里啦,如果对你有帮助,请三连支持!我是青云,我们下期见^_~

相关推荐
罗西的思考24 分钟前
DreamZero 与 DreamDojo:世界模型与策略的分层协同综合分析与对比
人工智能·算法·机器学习
玖玥拾1 小时前
LeetCode 219 存在重复元素 II
算法·leetcode·哈希算法·散列表
知无不研2 小时前
c语言中循环的介绍与简单应用
c语言·开发语言·算法·循环·for·while
a187927218313 小时前
【算法】动态规划第四篇:背包收官——min 哨兵、计数世界与组合排列分水岭
算法·leetcode·动态规划·dp·01背包·算法讲解·决策合并
2601_962297483 小时前
在python3中、下列输出变量a的正确写法是_2020超星大数据Python免费答案
数据结构·python·算法·编程·字符串操作
辰烨chenye3 小时前
LeetCode Hot 100 题解 · 子串篇
算法·leetcode·职场和发展
辰烨chenye4 小时前
LeetCode Hot 100 题解 · 堆篇
java·算法·leetcode
手写码匠4 小时前
华为云Flexus+DeepSeek征文|DeepSeek 应用监控告警体系实战:从“用户投诉才知道“到“故障前就发现“
人工智能·深度学习·算法·aigc
shehuiyuelaiyuehao4 小时前
算法29,前缀和,除自身以外的数组的乘积
java·数据结构·算法
智购科技自动售货机厂家4 小时前
2026自动售货机设备清洁效果自动验证:从图像比对到评分算法的工程实践~YH
人工智能·算法·计算机视觉