首页 > 编程语言 >C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例

时间:2023-10-24 16:04:47浏览次数:39  
标签:前缀 int res vPreSum C++ 源码 long preSum left


相关

源码测试用例下载
包括4个压缩包,初始代码,实现前缀和,实现前缀积,实现前缀异或。都是在前者的基础上修改的。

原理

长度为n的数组nums,共有n+1个以nums[0]开始的子数组。索引范围分别为[0,i),i取值区间[0,n]。preSum[i]记录子数组[0,i)的和。比如:nums = {1,2,3,4},则preSum = {0,1,3,6,10}。通过preSum,我们可以求任意nums的子数组和。子数组[i,j)等于子数组[0,j)减去[0,i),也就是子数组[i,j)的和等于preSum[j] – preSum[i]。如果i等于j,则preSum[i]-preSum[i],和为0,符合计算公式。如果i大于j,则非法,需要提前排除。

暴力法

时间复杂度O(n*n)。

核心代码

class CPreSum
 {
 public:
 //左闭右开空间
 long long SumO2(int left, int r)
 {
 long long llRet = 0;
 for (; left < r; left++)
 {
 llRet += m_sums[left];
 }
 return llRet;
 }
 vector m_sums; 
 };

测试代码

template
 void Assert(const vector& v1, const vector& v2)
 {
 if (v1.size() != v2.size())
 {
 assert(false);
 return;
 }
 for (int i = 0; i < v1.size(); i++)
 {
 assert(v1[i] == v2[i]);
 }
 }template
 void Assert(const T& t1, const T& t2)
 {
 assert(t1 == t2);
 }void Test1()
 {
 CPreSum preSum;
 preSum.m_sums = { 1,2,3,4 };
 vector ans = { 0,1,3,6,10 };
 auto res = preSum.SumO2(0, 4);
 Assert(10LL, res);
 res = preSum.SumO2(0, 3);
 Assert(6LL, res);
 res = preSum.SumO2(0, 2);
 Assert(3LL, res);
 res = preSum.SumO2(0, 1);
 Assert(1LL, res);
 res = preSum.SumO2(0, 0);
 Assert(0LL, res);
 res = preSum.SumO2(1, 4);
 Assert(9LL, res);
 res = preSum.SumO2(1, 3);
 Assert(5LL, res);
 }void Test2()
 {
 srand(time(nullptr));
 int n = rand() % 10 + 1;
 CPreSum preSum;
 for (int i = 0; i < n; i++)
 {
 preSum.m_sums.emplace_back(rand() % 10000);
 }
 preSum.Init();
 for (int left = 0; left < n; left++)
 {
 for (int r = left; r <= n; r++)
 {
 long long res1 = preSum.SumO1(left, r);
 long long res2 = preSum.SumO2(left, r);
 assert(res1==res2);
 }
 }
 }
 int main()
 {
 Test1();
 Test2();
 }

前缀和

时间复杂度O(n),预处理O(n),每次查询O(1)。

代码

void Init()
 {
 m_vPreSum.emplace_back(0);
 for (const auto& n : m_nums)
 {
 m_vPreSum.emplace_back(n + m_vPreSum.back());
 }
 }
 long long SumO1(int left, int r)
 {
 return m_vPreSum[r] - m_vPreSum[left];
 }
 vector m_vPreSum;

前缀乘积

只需要修改三处m_vPreSum[0]=1,+变成*,-变成除。

修改后的代码

class CPreSum
 {
 public:
 //左闭右开空间
 long long SumO2(int left, int r)
 {
 long long llRet = 1;
 for (; left < r; left++)
 {
 llRet *= m_nums[left];
 }
 return llRet;
 }
 void Init()
 {
 m_vPreSum.emplace_back(1);
 for (const auto& n : m_nums)
 {
 m_vPreSum.emplace_back(n * m_vPreSum.back());
 }
 }
 long long SumO1(int left, int r)
 {
 return m_vPreSum[r] / m_vPreSum[left];
 }
 vector m_vPreSum;
 vector m_nums;};

前缀异或

C语言异或的符合是,初始0,也就是m_vPreSum.emplace_back(0)。异或的逆运算是本身,所以乘除都换成


测试环境

操作系统:win7 开发环境: VS2019 C++17

相关下载

如果你想观其大略,建设下载《闻缺陷则喜算法册》doc版

博主想队大家说的话

墨家名称的来源:有所得以墨记之。

闻缺陷则喜的来由:早发现,早修改问题,成本更低

程序是龙,算法是睛

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例_前缀和


标签:前缀,int,res,vPreSum,C++,源码,long,preSum,left
From: https://blog.51cto.com/u_15724537/8005198

相关文章

  • C++前缀和算法应用:和至少为 K 的最短子数组的原理、源码及测试用例
    题目给你一个整数数组nums和一个整数k,找出nums中和至少为k的最短非空子数组,并返回该子数组的长度。如果不存在这样的子数组,返回-1。子数组是数组中连续的一部分。示例1:输入:nums=[1],k=1输出:1示例2:输入:nums=[1,2],k=4输出:-1示例3:输入:nums=......
  • C++前缀和算法:构造乘积矩阵
    题目给你一个下标从0开始、大小为n*m的二维整数矩阵grid,定义一个下标从0开始、大小为n*m的的二维矩阵p。如果满足以下条件,则称p为grid的乘积矩阵:对于每个元素p[i][j],它的值等于除了grid[i][j]外所有元素的乘积。乘积对12345取余数。返回grid的乘积......
  • C++算法:二叉树的序列化与反序列化
    #题目序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列/反序列化算法执行逻......
  • C++算法前缀和的应用:得分最高的最小轮调的原理、源码及测试用例
    题目给你一个数组nums,我们可以将它按一个非负整数k进行轮调,这样可以使数组变为[nums[k],nums[k+1],…nums[nums.length-1],nums[0],nums[1],…,nums[k-1]]的形式。此后,任何值小于或等于其索引的项都可以记作一分。例如,数组为nums=[2,4,1,3,0],我们按k=2进行......
  • C++算法:数据流的中位数
    题目中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。例如arr=[2,3,4]的中位数是3。例如arr=[2,3]的中位数是(2+3)/2=2.5。实现MedianFinder类:MedianFinder()初始化MedianFinder对象。voidaddNum(int......
  • C++算法前缀和的应用:分割数组的最大值的原理、源码及测试用例
    分割数组的最大值二分过些天整理基础知识题目给定一个非负整数数组nums和一个整数m,你需要将这个数组分成m个非空的连续子数组。设计一个算法使得这m个子数组各自和的最大值最小。示例1:输入:nums=[7,2,5,10,8],m=2输出:18解释:一共有四种方法将nums分割为2个......
  • C++算法:给表达式添加运算符
    题目给定一个仅包含数字0-9的字符串num和一个目标值整数target,在num的数字之间添加二元运算符(不是一元)+、-或*,返回所有能够得到target的表达式。注意,返回表达式中的操作数不应该包含前导零。示例1:输入:num=“123”,target=6输出:[“1+2+3”,“123......
  • C++数位算法:数字1的个数
    题目给定一个整数n,计算所有小于等于n的非负整数中数字1出现的个数。示例1:输入:n=13输出:6示例2:输入:n=0输出:0提示:0<=n<=1092023年1月版classSolution{public:intcountDigitOne(intn){intiNum=0;intiMul=1;for(inti=0;i<9;i++){......
  • C++桶排序算法的应用:存在重复元素 III
    题目给你一个整数数组nums和两个整数indexDiff和valueDiff。找出满足下述条件的下标对(i,j):i!=j,abs(i-j)<=indexDiffabs(nums[i]-nums[j])<=valueDiff如果存在,返回true;否则,返回false。示例1:输入:nums=[1,2,3,1],indexDiff=3,valueDiff=0输出......
  • C++前缀和算法应用:矩形区域不超过 K 的最大数值和
    题目给你一个mxn的矩阵matrix和一个整数k,找出并返回矩阵内部矩形区域的不超过k的最大数值和。题目数据保证总会存在一个数值和不超过k的矩形区域。示例1:输入:matrix=[[1,0,1],[0,-2,3]],k=2输出:2解释:蓝色边框圈出来的矩形区域[[0,1],[-2,3]]的数值和是......