C++前缀和算法:构造乘积矩阵

这篇具有很好参考价值的文章主要介绍了C++前缀和算法:构造乘积矩阵。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基础知识点

C++算法:前缀和基础

题目

给你一个下标从 0 开始、大小为 n * m 的二维整数矩阵 grid ,定义一个下标从 0 开始、大小为 n * m 的的二维矩阵 p。如果满足以下条件,则称 p 为 grid 的 乘积矩阵 :
对于每个元素 p[i][j] ,它的值等于除了 grid[i][j] 外所有元素的乘积。乘积对 12345 取余数。
返回 grid 的乘积矩阵。

示例 1:
输入:grid = [[1,2],[3,4]]
输出:[[24,12],[8,6]]
解释:p[0][0] = grid[0][1] * grid[1][0] * grid[1][1] = 2 * 3 * 4 = 24
p[0][1] = grid[0][0] * grid[1][0] * grid[1][1] = 1 * 3 * 4 = 12
p[1][0] = grid[0][0] * grid[0][1] * grid[1][1] = 1 * 2 * 4 = 8
p[1][1] = grid[0][0] * grid[0][1] * grid[1][0] = 1 * 2 * 3 = 6
所以答案是 [[24,12],[8,6]] 。
示例 2:

输入:grid = [[12345],[2],[1]]
输出:[[2],[0],[0]]
解释:p[0][0] = grid[0][1] * grid[0][2] = 2 * 1 = 2
p[0][1] = grid[0][0] * grid[0][2] = 12345 * 1 = 12345. 12345 % 12345 = 0 ,所以 p[0][1] = 0
p[0][2] = grid[0][0] * grid[0][1] = 12345 * 2 = 24690. 24690 % 12345 = 0 ,所以 p[0][2] = 0
所以答案是 [[2],[0],[0]] 。

感悟

原以为和MOD = 1000000007一样,直接使用封装好的此类,发现错误。赛场上时间紧急,来不及分析是两个不同的问题,还是我封装错误。只好使用笨办法。我记得1000000007是质数,才能转除为乘。考虑过12345是否是质数,当时觉判断烦恼,所以没判断。现在觉得很简单:以5结尾,就是5的倍数,不是质数。

分析

前缀和后缀和。第一轮的preRow记录[0,r) 所有元素的乘积,vLeft[r][c] 记录本行左边各元素的乘积,vRight[r][c]记录本行右边各元素的乘积。vRet[r][c]记录这三个的乘积。第二轮preRow记录[r+1,m_r)所有元素的乘积。第二轮vRet[r][c]乘以preRow就是结果。

测试用例

1 2 3
4 5 6
7 8 9

结果

当前数 前面行的乘积 前面行的乘积 左边乘积 右边乘积
1 1 4…9 1 6
2 1 4…9 1 3
3 1 4…9 2 1
4 6 7…9 1 30
5 6 7…9 4 6
6 6 7…9 20 1
7 1…6 1 1 72
8 1…6 1 7 9
9 1…6 1 56 1

解释

对{4,5,6}而言第一轮preRow是123=6,第二轮preRow是789。对4而言,left是1,right是30。对5而言,left是4,right是6。对6而言,left是20,right是1。

时间复杂度

O(n^2) 2轮,每轮2层循环,每层循环是O(n)。

代码

class Solution {
public:
vector<vector> constructProductMatrix(vector<vector>& grid) {
m_r = grid.size();
m_c = grid.front().size();
//vLeft记录当前行,左边的成绩
vector<vector> vLeft(m_r, vector(m_c)), vRight(m_r, vector(m_c)), vRet(m_r, vector(m_c));
int iPreRow = 1;
for (int r = 0; r < m_r; r++)
{
int pre = 1;
for (int c = 0; c < m_c; c++)
{
vLeft[r][c] = pre;
MulSelf(pre, grid[r][c]);
}
pre = 1;
for (int c = m_c-1 ; c >= 0 ; c-- )
{
vRight[r][c] = pre;
MulSelf(pre, grid[r][c]);
}
for (int c = 0; c < m_c; c++)
{
vRet[r][c] = 1;
MulSelf(vRet[r][c], iPreRow);
MulSelf(vRet[r][c], vLeft[r][c]);
MulSelf(vRet[r][c], vRight[r][c]);
}
MulSelf(iPreRow, pre);
}
iPreRow = 1;
for (int r = m_r-1; r >= 0 ; r-- )
{
int pre = 1;
for (int c = 0; c < m_c; c++)
{
MulSelf(vRet[r][c], iPreRow);
MulSelf(pre, grid[r][c]);
}
MulSelf(iPreRow, pre);
}
return vRet;
}
void MulSelf(int& self, int other)
{
const int MOD = 12345;
self = ((long long)self * other) % MOD;
}
int m_r, m_c;
};

一维化降低复杂度

分析

vLeft[r][c]记录 [0,r)行所有元素及r行[0,c)列元素的乘积,第二轮的pre记录(r,m_c)行所有元素及r行(c,m_c)列元素的乘积。
vLeft[1][1] = 1234 第二轮的pre = 9876

代码

class Solution {
public:
vector<vector> constructProductMatrix(vector<vector>& grid) {
m_r = grid.size();
m_c = grid.front().size();
vector < vector> vLeft(m_r, vector(m_c));
int pre = 1;
for (int r = 0; r < m_r; r++)
{
for (int c = 0; c < m_c; c++)
{
vLeft[r][c] = pre;
MulSelf(pre, grid[r][c]);
}
}
vector<vector> vRet(m_r, vector(m_c));
pre = 1;
for (int r = m_r-1 ; r >= 0 ;r–)
{
for (int c = m_c-1 ; c >= 0 ; c-- )
{
const int index = m_c * r + c;
vRet[r][c] = pre;
MulSelf(vRet[r][c], vLeft[r][c]);
MulSelf(pre, grid[r][c]);
}
}
return vRet;
}
void MulSelf(int& self, int other)
{
const int MOD = 12345;
self = ((long long)self * other) % MOD;
}
int m_r, m_c;
};

测试用例

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);
}
int main()
{
vector<vector>grid = { {1,2,3},{4,5,6} };
vector<vector> ans = { {720,360,240},{180,144,120} };
auto res = Solution().constructProductMatrix(grid);
Assert(res, ans);
grid = { {1,2,},{3,4},{5,6 }};
ans = { {720,360},{240,180},{144,120} };
res = Solution().constructProductMatrix(grid);
Assert(res, ans);
grid = { { 1,2,3,4,5,6 } };
ans = { { 720,360,240,180,144,120} };
res = Solution().constructProductMatrix(grid);
Assert(res, ans);
grid = { { 1},{2},{3},{4},{5},{6} };
ans = { { 720},{360},{240},{180},{144},{120} };
res = Solution().constructProductMatrix(grid);
Assert(res, ans);
CConsole::Out(res);
}
C++前缀和算法:构造乘积矩阵,# 算法题,c++,算法,矩阵,前缀和,后缀和,前缀积

其它

视频课程

要是你认为本篇难道较大,不好入手,推荐你先学习基础算法的课程,我已完成部分,余下部分持续更新中,就在CSDN学院。
https://edu.csdn.net/course/detail/38771

C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

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

相关下载

如果你想观其大略,建设下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

博主想队大家说的话
墨家名称的来源:有所得以墨记之。
闻缺陷则喜的来由:早发现,早修改问题,成本更低
程序是龙,算法是睛

C++前缀和算法:构造乘积矩阵,# 算法题,c++,算法,矩阵,前缀和,后缀和,前缀积文章来源地址https://www.toymoban.com/news/detail-712732.html

到了这里,关于C++前缀和算法:构造乘积矩阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构与算法】【12】前缀表达式、中缀表达式、后缀表达式

    什么是前缀表达式、中缀表达式、后缀表达式 前缀表达式、中缀表达式、后缀表达式,是通过树来存储和计算表达式的三种不同方式 以如下公式为例 ( a + ( b − c ) ) ∗ d ( a+(b-c) )*d ( a + ( b − c ) ) ∗ d 通过树来存储该公式,可以表示为 那么问题就来了,树只是一种抽象的数据

    2024年02月08日
    浏览(47)
  • C++ 二维前缀和 子矩阵的和

    输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2 ,表示一个子矩阵的左上角坐标和右下角坐标。 对于每个询问输出子矩阵中所有数的和。 输入格式 第一行包含三个整数 n,m,q 。 接下来 n 行,每行包含 m 个整数,表示整数矩阵。 接下来

    2024年02月21日
    浏览(54)
  • 【前缀和】238. 除自身以外数组的乘积

    前缀与后缀的思路 对于给定索引i,将它左边的所有数字乘积乘以右边所有数字的乘积 初始化两个数组L R 计算L[i] = L[i - 1] * nums[i - 1] 也就是左侧所有数字的乘积 计算R[i] = R[i + 1] * nums[i + 1] 也就是右侧所有数字的成绩 计算L[I] * R[i]

    2024年02月15日
    浏览(38)
  • C++ 二维差分 二维前缀和逆运算 差分矩阵

    输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c ,其中 (x1,y1) 和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。 每个操作都要将选中的子矩阵中的每个元素的值加上 c 。 请你将进行完所有操作后的矩阵输出。 输入格式 第一行包含整数

    2024年02月21日
    浏览(55)
  • 283.除自身以外数组的乘积(前缀积、C解法)

    给你一个整数数组  nums ,返回 数组  answer  ,其中  answer[i]  等于  nums  中除  nums[i]  之外其余各元素的乘积  。 题目数据 保证 数组  nums 之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。 请  不要使用除法, 且在  O( n ) 时间复杂度内完成此题。 示

    2024年01月23日
    浏览(40)
  • 【组合数学】【动态规划】【前缀和】1735生成乘积数组的方案数

    【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II 动态规划汇总 C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 组合数学 给你一个二维整数数组 queries ,其中 queries[i] = [ni, ki] 。第 i 个查询 queries[i] 要求构造长度为 ni 、每个

    2024年02月19日
    浏览(51)
  • C++ 构造0-1随机矩阵

    沿用传统C语言的构造方法,使用双重for循环。 输出结果: srand() 用于初始化随机数发生器,包含于 stdlib.h 头文件,用于设置 rand() 的随机数种子 seed ,原型为 void srand(unsigned seed) 。 rand() 是随机数发生器,包含于 stdlib.h 头文件,可根据当前的 seed 返回均匀分布的介于 0 和

    2024年02月06日
    浏览(33)
  • [Kadane算法,前缀和思想]元素和最大的子矩阵

    题目描述 输入一个n级方阵,请找到此矩阵的一个子矩阵,此子矩阵的各个元素的和是所有子矩阵中最大的,输出这个子矩阵及这个最大的和。 关于输入 首先输入方阵的级数n, 然后输入方阵中各个元素。 关于输出 输出子矩阵, 最后一行输出这个子矩阵的元素的和。 例子输

    2024年02月03日
    浏览(35)
  • 算术表达式:前缀、中缀表、后缀表达式相互转换

    概念: 三者的区别在于运算符相对于操作数的位置有所不同   前缀表达式 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。   中缀表达式  中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于

    2024年02月05日
    浏览(93)
  • 蓝桥杯统计子矩阵前缀和C++(附图文超详细讲解)(保姆级)

    给定一个 N × M 的矩阵 A,请你统计有多少个子矩阵 (最小 1 × 1,最大 N × M) 满足子矩阵中所有数的和不超过给定的整数 K?  第一行包含三个整数 N, M 和 K.  之后 N 行每行包含 M 个整数,代表矩阵 A. 一个整数代表答案。 满足条件的子矩阵一共有 19,包含: 大小为 1 × 1 的有

    2023年04月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包