文章目录
- Leetcode3069 将元素分配到两个数组中 I
- Leetcode3070 元素和小于等于k的子矩阵数目
- Leetcode3071 在矩阵上写出字母Y所需的最小操作次数
Leetcode3069 将元素分配到两个数组中 I
题目:给你一个下标从
1
开始、包含 不同 整数的数组nums
,数组长度为n
。
你需要通过n
次操作,将nums
中的所有元素分配到两个数组arr1
和arr2
中。在第一次操作中,将nums[1]
追加到arr1
。在第二次操作中,将nums[2]
追加到arr2
。之后,在第i
次操作中:如果
arr1
的最后一个元素 大于arr2
的最后一个元素,就将nums[i]
追加到arr1
。否则,将nums[i]
追加到arr2
。
通过连接数组 arr1 和 arr2 形成数组result
。例如,如果arr1 == [1,2,3]
且arr2 == [4,5,6]
,那么result = [1,2,3,4,5,6]
。返回数组
result
。
link
题解:
- 很简单,直接按照题目意思,定义一个final
result[]
数组和一个auxiliary arraytemp[]
- 遍历数组,按题意 push_back到不同数组
- 最后在遍历数组
temp
,把所有元素加到result[]
后面
时间复杂度: O ( n ) O(n) O(n) ——只用遍历数组即可
空间复杂度: O ( n ) O(n) O(n) ——虽然一开始开了2个vector,但两个vector的总元素数量是num.size()
代码:
class Solution {
public:vector<int> resultArray(vector<int>& nums) {if (nums.size() <= 2) {return nums;}vector<int> result;vector<int> temp;result.push_back(nums[0]);temp.push_back(nums[1]);int x = nums[0], y = nums[1];for (int i = 2; i < nums.size(); ++i) {if (x > y) {result.push_back(nums[i]);x = nums[i];}else {temp.push_back(nums[i]);y = nums[i];}}for (int i = 0; i < temp.size(); ++i) {result.push_back(temp[i]);}return result;}
};
Leetcode3070 元素和小于等于k的子矩阵数目
题目:给你一个下标从 0 开始的整数矩阵
grid
和一个整数k
。
返回包含grid
左上角元素、元素和小于或等于k
的 子矩阵 的 数目。
link
题解:
当时思路:
- 开一个和
grid
一样大的数组 - 遍历一遍
grid
,同时初始化temp
,
t e m p [ i ] [ j ] = ∑ k = 0 j n u m s [ i ] [ k ] temp[i][j] = \sum_{k=0}^{j}nums[i][k] temp[i][j]=∑k=0jnums[i][k],也就是说temp[i][j]
存放该行第一个元素开始到当前元素的sum - 遍历一遍
temp
,更新temp[i][j]
值并计算符合条件的 submatrices 个数- 显然,如果是第一行的元素的话,第一遍初始化的
temp[i][j]
值就是对应 submatrice 的sum - 如果非1st row 元素的话,
temp[i][j]
等于比他少一行的子矩阵值+自己的初始值
- 显然,如果是第一行的元素的话,第一遍初始化的
时间复杂度: O ( m ⋅ n ) O(m\cdot n) O(m⋅n) ——只用遍历两遍数组
空间复杂度: O ( m ⋅ n ) O(m\cdot n) O(m⋅n) ——建了一个辅助数组
优化:
- 不用遍历2遍,只需一遍每次
temp[i][j] = temp[i - 1][j] + temp[i][j - 1] + grid[i][j] - temp[i - 1][j - 1]
,很容易理解 - 直接在原始数组上更新,不用创建辅助数组
优化后时间复杂度不变,空间复杂度降为 O ( 1 ) O(1) O(1).
看别人的题解说是典型的二位前缀和问题
跟 algorithm final 有一题很像 link
代码:
(未优化前代码,优化的也很容易修正)
class Solution {
public:int countSubmatrices(vector<vector<int>>& grid, int k) {int m = grid.size();int n = grid[0].size();vector<vector<int>> temp(m, vector<int>(n, 1));for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (j == 0)temp[i][j] = grid[i][j];elsetemp[i][j] = temp[i][j - 1] + grid[i][j];}}int count = 0;int sum = 0;for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (i != 0) {temp[i][j] += temp[i - 1][j];}if (temp[i][j] <= k)++count;}}return count;}
};
Leetcode3071 在矩阵上写出字母Y所需的最小操作次数
题目:给你一个下标从
0
开始、大小为n x n
的矩阵grid
,其中n
为奇数,且grid[r][c]
的值为0
、1
或2
。
如果一个单元格属于以下三条线中的任一一条,我们就认为它是字母Y
的一部分:
从左上角单元格开始到矩阵中心单元格结束的对角线。
从右上角单元格开始到矩阵中心单元格结束的对角线。
从中心单元格开始到矩阵底部边界结束的垂直线。
当且仅当满足以下全部条件时,可以判定矩阵上写有字母Y
:属于
Y
的所有单元格的值相等。
不属于Y
的所有单元格的值相等。
属于Y
的单元格的值与不属于Y的单元格的值不同。
每次操作你可以将任意单元格的值改变为0
、1
或2
。返回在矩阵上写出字母Y
所需的 最少 操作次数。
link
题解:
- 思路:hash table,因为单元格值固定,只需要开2个
int[3]
数组即可,分别统计Y中、其他区域每个数字出现次数 - 遍历一遍
grid[][]
,统计次数. - Y坐标特点:
- 正对角线(
i == j
)上半部分 - 反对角线(
i + j == n
)上半部分 - center 列下半部分
- 正对角线(
- 找到
Y[]
和E[]
数组中最大值,即出现频率最大的数.- 如果这两个数不等,则可以计算要改变的次数了,直接返回
- 如果不等,找到两个数组中次大的数,然后分别计算修改次数,选小的返回
时间复杂度: O ( n 2 ) O(n^2) O(n2) ——因为hash table固定,所以复杂度是constant
空间复杂度: O ( k ) O(k) O(k) k is constant
代码:
class Solution {
public:int minimumOperationsToWriteY(vector<vector<int>>& grid) {int n = grid.size();int center = n >> 1;int Y[3] = {};int E[3] = {};int sum1 = 0, sum2 = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {if (i == j && i <= center) {++Y[grid[i][j]];++sum1;}else if (i + j == n - 1 && i < center) {++Y[grid[i][j]];++sum1;}else if (j == center && i > center) {++Y[grid[i][j]];++sum1;}else {++E[grid[i][j]];++sum2;}}}int maxY = 0, maxE = 0;int sY = -1, sE = -1;for (int i = 1; i < 3; ++i) {if (Y[i] > Y[maxY])maxY = i;if (E[i] > E[maxE])maxE = i;}if (maxY != maxE)return sum1 - Y[maxY] + sum2 - E[maxE];else {for (int i = 0; i < 3; ++i) {if (i != maxY) {if (sY == -1 || Y[i] > Y[sY])sY = i;}if (i != maxE) {if (sE == -1 || E[i] > E[sE]) sE = i;}}int costY = sum1 - Y[maxY] + sum2 - E[sE];int costE = sum2 - E[maxE] + sum1 - Y[sY];return min(costY, costE);}}
};
最后一题待补,当场没做出来