题目描述
给你两个非负整数数组 `rowSum 和 colSum` ,其中 `rowSum[i]` 是二维矩阵中第 i 行元素的和, `colSum[j]` 是第 j 列元素的和。换言之你不知道矩阵里的每个元素,但是你知道每一行和每一列的和。
请找到大小为`rowSum.length` * `colSum.length` 的任意 非负整数 矩阵,且该矩阵满足 `rowSum` 和 `colSum` 的要求。
请你返回任意一个满足题目要求的二维矩阵,题目保证存在 至少一个 可行矩阵
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-valid-matrix-given-row-and-column-sums
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
贪心算法,每次设置元素的时候把它设置成可以用的最大值,即同时使得行和列都不超过上限的最大值`min(rowSum[i], colSum[j])`;同时把rowSum 和 colSum均减少已经设置的值表示该行/该列还剩下多少可以使用,0表示用完了
粗略考虑了一手这个做法的正确性:矩阵的自由度是, 但是给定行列的限制只有 $2*n$的自由度,虽然题目保证了一定有解,但不确定这样的做法是否一定可以得到正确结果。每次操作都会使得一行/一列的可用结果为0,或者使得已成0的行/列保持,因此只会在最后一个值可能遇到行和列剩余值不匹配的情况,但题目保证有解首先是要保证sum(rowSum)与sum(colSum)相等, 并且在每次操作的时候rowSum[i]和colSum[j]是同步减小的,因此到最后剩下的唯一非0元素也应该相等,所以是可以做出来
感觉起来正确性证明的过程就是循环不变量
Initialization :初始的时候 rowSum的和与colSum的和相等
Maintenance:每次迭代rowSum[i]和colSum[j]同步减少ret[i][j],上述两个和仍然相等
Termination :最后一次输入的数据要同时等于上述两个和,即只需要两个和相等即可。
代码
class Solution {
public:
vector<vector<int>> restoreMatrix(vector<int>& rowSum, vector<int>& colSum) {
int x = rowSum.size();
int y = colSum.size();
vector<vector<int>> ret;
for(int i=0; i < x; i++){
vector<int> row(y, 0);
ret.push_back(row);
}
// printf("ret.size = %d, %d\n", ret.size(), ret[0].size());
for(int i=0; i< x; i++){
for(int j=0; j< y; j++){
if(rowSum[i]< colSum[j]){
ret[i][j] = rowSum[i];
else{
ret[i][j] = colSum[i];
}
rowSum[i] -= ret[i][j];
colSum[j] -= ret[i][j];
}
}
return ret;
}
};