本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。
为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。
由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。
给你一个 2
行 n
列的二进制数组:
0
就是 1
。0
行的元素之和为 upper
。1
行的元素之和为 lower
。i
列(从 0
开始编号)的元素之和为 colsum[i]
,colsum
是一个长度为 n
的整数数组。你需要利用 upper
,lower
和 colsum
来重构这个矩阵,并以二维整数数组的形式返回它。
如果有多个不同的答案,那么任意一个都可以通过本题。
如果不存在符合要求的答案,就请返回一个空的二维数组。
示例 1:
输入:upper = 2, lower = 1, colsum = [1,1,1]
输出:[[1,1,0],[0,0,1]]
解释:[[1,0,1],[0,1,0]] 和 [[0,1,1],[1,0,0]] 也是正确答案。
示例 2:
输入:upper = 2, lower = 3, colsum = [2,2,1,1]
输出:[]
示例 3:
输入:upper = 5, lower = 5, colsum = [2,1,2,0,1,0,1,2,0,1]
输出:[[1,1,1,0,1,0,0,1,0,0],[1,0,1,0,0,0,1,1,0,1]]
提示:
1 <= colsum.length <= 10^5
0 <= upper, lower <= colsum.length
0 <= colsum[i] <= 2
我们要求得任意一个 2 2 2 行 n n n 列的二进制数组(其中行和列的序号从 0 0 0 开始),满足数组中的每一个元素不是 0 0 0 就是 1 1 1 ,并且第 0 0 0 行的元素和为 upper \textit{upper} upper ,第 1 1 1 行的元素和为 lower \textit{lower} lower ,第 i i i 列的元素之和为 c o l s u m [ i ] colsum[i] colsum[i] ,若不存在直接返回一个空的二维数组即可。
记 s u m sum sum 为数组 c o l s u m colsum colsum 的元素和, t w o two two 为数组 c o l s u m colsum colsum 中 2 2 2 的个数。明显当 s u m ≠ u p p e r + l o w e r sum≠upper+lower sum=upper+lower 时,一定不存在满足题意的矩阵。然后当第 i i i 列 c o l s u m [ i ] = 2 colsum[i]=2 colsum[i]=2 时,第 i i i 列的两个元素只能都为 1 1 1 。那么如果 two > min { upper , lower } \textit{two} > \min\{\textit{upper}, \textit{lower}\} two>min{upper,lower} 时,此时同样不存在满足题意的矩阵。
否则,一定可以通过下述的方案,构造一个符合题目要求的矩阵。设结果矩阵为 ans [ 2 ] [ n ] \textit{ans}[2][n] ans[2][n] 。当第 i i i 列 c o l s u m [ i ] colsum[i] colsum[i] 等于 0 0 0 或者 2 2 2 时只有一种情况:
所以,现在只关注 c o l s u m [ i ] = 1 colsum[i]=1 colsum[i]=1 的情况。首先将初始的 upper \textit{upper} upper 和 lower \textit{lower} lower 减去数组 c o l s u m colsum colsum 中 2 2 2 的个数 t w o two two(相当于先贪心地处理 c o l s u m [ i ] = 2 colsum[i]=2 colsum[i]=2 的情况),那么现在 u p p e r + l o w e r upper+lower upper+lower 为数组 c o l s u m colsum colsum 中 1 1 1 的个数。那么从左到右遍历 c o l s u m colsum colsum 中的每一列,若第 i i i 列 c o l s u m [ i ] colsum[i] colsum[i] 等于 1 1 1 :
当遍历完成后,就得到了符合题目要求的矩阵 a n s [ 2 ] [ n ] ans[2][n] ans[2][n] 。
现在给出该方案的正确性证明:从上述的构造过程可得,整个数组中除了 1 1 1 就 0 0 0 ,每一列中 1 1 1 的个数完全符合数组 c o l s u m colsum colsum 描述,且在第一行中我们共放置了 u p p e r upper upper 个 1 1 1 ,第二行共放置了 lower \textit{lower} lower 个 1 1 1 。因此这样构造的矩阵 a n s [ 2 ] [ n ] ans[2][n] ans[2][n] 为满足题意的二进制矩阵,正确性得证。
下面是我写的先贪心处理 2 2 2 的情况的代码:
class Solution {
public:
vector<vector<int>> reconstructMatrix(int upper, int lower, vector<int>& colsum) {
int n = colsum.size();
vector<vector<int>> ans(2, vector<int>(n));
for (int j = 0; j < n; ++j) {
if (colsum[j] == 2) {
if (!upper || !lower) return {}; // 不够组成列
ans[0][j] = ans[1][j] = 1;
--upper, --lower;
}
}
for (int j = 0; j < n; ++j) {
if (colsum[j] == 1) {
if (!upper && !lower) return {}; // 不够组成列
if (upper) ans[0][j] = 1, --upper;
else ans[1][j] = 1, --lower;
}
}
if (!lower && !upper) return ans;
return {}; // 不够组成列
}
};
下面是先检查 c o l s u m colsum colsum 是否有解的代码:
class Solution {
public:
vector<vector<int>> reconstructMatrix(int upper, int lower, vector<int>& colsum) {
int n = colsum.size();
vector<vector<int>> ans(2, vector<int>(n));
int sum = 0, two = 0; // two为colsum中2的个数
for (int j = 0; j < n; ++j) {
if (colsum[j] == 2) ++two;
sum += colsum[j];
}
if (sum != upper + lower || min(upper, lower) < two) return {};
upper -= two, lower -= two; // 相当于先处理2的情况
for (int j = 0; j < n; ++j) {
if (colsum[j] == 2) ans[0][j] = ans[1][j] = 1;
else if (colsum[j] == 1) {
if (upper) ans[0][j] = 1, --upper;
else ans[1][j] = 1;
}
}
return ans;
}
};
复杂度分析: