73、矩阵置零
题目:
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
示例 1:
输入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
示例 2:
输入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
输出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]
进阶:
一个直接的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个常数空间的解决方案吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/set-matrix-zeroes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
三种方法,空间复杂度分别是
1、O(MN)
2、O(M+N)
3、O(2)
完整代码:
class Solution {
public:
// //1、O(mn)空间
// void setZeroes(vector<vector<int>>& matrix)
// {
// int m = matrix.size();
// int n = matrix[0].size();
// //保存标志
// vector<vector<int>> flag(m, vector<int>(n, 1));
// for(int i = 0; i < m; i++) {
// for(int j = 0; j < n; j++) {
// //若当前值为0,则设置行和列的标志位为0
// if(matrix[i][j] == 0) {
// setZero(matrix, flag, i, j);
// } else if(flag[i][j] == 0) {
// matrix[i][j] = 0;
// }
// }
// }
// }
// void setZero(vector<vector<int>>& matrix, vector<vector<int>>& flag, int i, int j)
// {
// int top = 0;
// while(top < i) {
// matrix[top][j] = 0;
// top++;
// }
// int left = 0;
// while(left < j) {
// matrix[i][left] = 0;
// left++;
// }
// int bottom = flag.size() - 1;
// while(bottom > i) {
// flag[bottom][j] = 0;
// bottom--;
// }
// int right = flag[0].size() - 1;
// while(right > j) {
// flag[i][right] = 0;
// right--;
// }
// }
// //2、O(m + n)空间
// void setZeroes(vector<vector<int>>& matrix)
// {
// int m = matrix.size();
// int n = matrix[0].size();
// //保存标志
// vector<int> row;
// vector<int> col;
// for(int i = 0; i < m; i++) {
// for(int j = 0; j < n; j++) {
// //若当前值为0,则设置行和列的标志位为0
// if(matrix[i][j] == 0) {
// row.push_back(i);
// col.push_back(j);
// }
// }
// }
// for(int i = 0; i < m; i++) {
// for(int j = 0; j < n; j++) {
// //若当前值为0,则设置行和列的标志位为0
// if(count(row.begin(), row.end(), i) > 0 || count(col.begin(), col.end(), j) > 0) {
// matrix[i][j] = 0;
// }
// }
// }
// }
//3、O(1)空间
void setZeroes(vector<vector<int>>& matrix)
{
int m = matrix.size();
int n = matrix[0].size();
int row_flag = false; // 用于保存第一行是否有0
int col_flag = false; // 用于保存第一列是否有0
// 判断第一行是否有0
for(int j = 0; j < n; j++) {
if(matrix[0][j] == 0) {
row_flag = true;
}
}
//判断第一列是否有0
for(int i = 0; i < m; i++) {
if(matrix[i][0] == 0) {
col_flag = true;
}
}
//除第一行、第一列外,若当前值为0,则设置行和列的标志位为0
for(int i = 1; i < m; i++) {
for(int j = 1; j < n; j++) {
if(matrix[i][j] == 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
// 将第一行值为0的设置所在列为0
for(int j = 1; j < n; j++) {
if(matrix[0][j] == 0) {
for(int i = 0; i < m; i++) {
matrix[i][j] = 0;
}
}
}
// 将第一列值为0的设置所在行为0
for(int i = 1; i < m; i++) {
if(matrix[i][0] == 0) {
for(int j = 0; j < n; j ++) {
matrix[i][j] = 0;
}
}
}
//若row_flag为true,设置第一行的值为0
if(row_flag) {
for(int j = 0; j < n; j ++) {
matrix[0][j] = 0;
}
}
//若col_flag为true,设置第一列的值为0
if(col_flag) {
for(int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
}
};
74、搜索二维矩阵
题目:
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:输入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 3
输出: true
示例 2:输入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 13
输出: false来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-a-2d-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
二分
完整代码:
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target)
{
int m = matrix.size(); // 行数
if(m == 0) {
return false;
}
int n = matrix[0].size(); //列数
int l = 0;
int r = m * n - 1;
// 二分查找
while(l <= r) {
int mid = (l + r) / 2;
int i = mid / n;
int j = mid % n;
if(matrix[i][j] == target) {
return true;
} else if(matrix[i][j] < target) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return false;
}
};
75、颜色分类
题目:
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
进阶:一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
你能想出一个仅使用常数空间的一趟扫描算法吗?来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-colors
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
一次遍历
完整代码:
class Solution {
public:
void sortColors(vector<int>& nums) {
int l = 0;
int r = nums.size() - 1;
int i = 0;
while(i <= r) {
if(nums[i] == 0) {
swap(nums[i], nums[l]);
i++; // 换过来的值肯定不是0或者2,所以i++
l++;
} else if(nums[i] == 2) {
swap(nums[i], nums[r]);
r--;
} else {
i++;
}
}
}
};
76、最小覆盖子串
题目:
给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入:S = "ADOBECODEBANC", T = "ABC"
输出:"BANC"
提示:
如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
滑动窗口
完整代码:
// 滑动窗口,两个指针,1个用于延伸,另一个用于收缩
class Solution {
private:
unordered_map<char, int> ori, idx; // 用于存储字符串中每个字符的个数
public:
//用于判断是否满足要求
bool check()
{
for(const auto &s: ori) {
if(idx[s.first] < s.second) {
return false;
}
}
return true;
}
string minWindow(string s, string t)
{
for(auto str: t) {
ori[str]++;
}
int l = 0;
int r = 0;
int len = INT_MAX;
int l_len = -1;
while(r < s.size()) {
if(ori.find(s[r]) != ori.end()) {
idx[s[r]] ++;
}
while(check() && l <= r) {
if(r - l + 1 < len) {
len = r - l + 1;
l_len = l;
}
if(ori.find(s[l]) != ori.end()) {
idx[s[l]] --;
}
l++;
}
r++;
}
return l_len == -1 ? "" : s.substr(l_len, len);
}
};