1.有序数组的平方
代码:(暴力解法)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0; i < nums.size(); i++){
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(),nums.end());
return nums;
}
};
代码: (双指针)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
int k = nums.size() - 1;
vector<int> result(nums.size(),0);
while(left <= right){
if(nums[left] * nums[left] > nums[right] * nums[right]){
result[k--] = nums[left] * nums[left];
left++;
}else{
result[k--] = nums[right] * nums[right];
right--;
}
}
return result;
}
};
note:
做这道题的时候一直纠结于怎么找到正负交界,只要找到正负交界就可以从这里出发去从绝对值小的地方出发,去比较着来填新数组了。
但其实,我完全可以找数组的起点和终点,它们一定分布着绝对值最大的元素。因此,只要用双指针从数组两端一起向中间遍历就好了。然后谁的平方大,就把谁填到新数组的末尾。
2.长度最小的子数组
代码: (暴力法,超时)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum = 0;
int result = INT_MAX;
for(int i = 0; i < nums.size(); i++){
sum = 0;
for(int j = i; j < nums.size(); j++){
sum += nums[j];
if(sum >= target){
int sublength = j - i + 1;
result = min(result,sublength);
break;
}
}
}
if(result == INT_MAX) return 0;
return result;
}
};
代码:双指针(滑动窗口)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum = 0;
int result = INT_MAX;
int i = 0; // 窗口的起始位置
for(int j = 0; j < nums.size(); j++){ // 只能去遍历窗口的终止位置
sum += nums[j];
while(sum >= target){
int sublength = j - i + 1;
result = min(result,sublength);
sum -= nums[i];
i++;
}
}
if(result == INT_MAX) return 0;
return result;
}
};
note:关键就是记住——滑动窗口固定的是右边界!!因为只是固定了起始位置,终止位置就还得再需要一个循环。
当我们的总和不小于target时,就是缩小我们窗口的时机。
相关题目练习:
class Solution {
public:
int totalFruit(vector<int>& fruits) {
unordered_map<int,int> cnt; // 记录水果种类和数目的映射关系
int left = 0;
int result = 0;
for(int right = 0; right < fruits.size(); right++){
cnt[fruits[right]]++;
while(cnt.size() > 2){
auto it = cnt.find(fruits[left]);
it->second--;
if(it->second == 0){
cnt.erase(it);
}
left++;
}
result = max(right - left + 1,result);
}
return result;
}
};
note:
首先是自己根本不知道怎么用这个滑动窗口。我觉得规律是,滑动窗口是在满足一个要求的情况下,尽量去追求另一种要求(内层的while循环)。 这道题是尽量追求数量多的水果,在这个前提下,当不满足水果种类在2以内时,把左边界的水果剔除出去。
这道题犯了好多低级错误,首先是erase拼写错误,还有内层循环的剔除的左边界的元素写成右边界了。。
class Solution {
private:
unordered_map<char,int> map_window,map_base;
bool check(){
for(auto &it : map_base){
if(map_window[it.first] < it.second){
return false;
}
}
return true;
}
public:
string minWindow(string s, string t) {
for(char c:t){
map_base[c]++;
}
int left = 0;
int result = INT_MAX;
int res_start_index = -1;
for(int right = 0; right < s.size(); right++){
map_window[s[right]]++;
while(check()){
// 更新结果
if(right - left + 1 < result){
result = right - left + 1;
res_start_index = left; // 记录该覆盖子串的起始索引。最后直接通过起始索引+最小长度来求结果,避免这里重复的拷贝复制
}
}
// 缩小窗口
map_window[s[left]]--;
left++;
}
}
if(res_start_index == -1) return "";
return s.substr(res_start_index,result);
}
};
note:脑壳疼。
主要难点在于,如何判断“覆盖”。
s 的子串 BANC 中每个字符的个数,都大于等于 t=ABC 中每个字符的个数,这就叫「覆盖」。其实看字面意思就能理解,这里之所以专门强调下,是为了将「覆盖」转化为数学表达式,为的是方便转为代码语言。
作者:sca
链接:https://leetcode.cn/problems/minimum-window-substring/solutions/2796027/jie-he-ge-wei-da-lao-ti-jie-xie-ge-ge-re-d40w/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.螺旋矩阵2
代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int loop = n / 2;
int mid = n / 2;
int offset = 0;
int value = 1;
vector<vector<int>> matrix(n,vector<int>(n,0));
while(loop--){ // 左闭右开
int i,j;
for(j = offset; j < n - 1 - offset; j++){
matrix[offset][j] = value++;
}
for(i = offset; i < n - 1 - offset; i++){
matrix[i][n - 1 - offset] = value++;
}
for(j = n - 1 - offset; j > offset; j--){
matrix[n - 1 - offset][j] = value++;
}
for(i = n - 1 - offset; i > offset; i--){
matrix[i][offset] = value++;
}
offset++;
}
if(n % 2) matrix[mid][mid] = value;
return matrix;
}
};
note:
这次我直接用offset来确定每次绕圈的边界值,具体的确定方式其实很简单——就是用第一圈来看,哪个的坐标是小的直接写成offset,如果是大的边界直接写成 n - 1 - offset就好了。(感觉和以前做的数学应用题很像。。)
相关题目练习
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
// 左闭右开
int m = matrix.size();
int n = matrix[0].size();
int cnt = 0;
vector<int> result(m * n, 0);
int offset = 0;
int loop = min(m,n) / 2;
int mid = loop;
while(loop--){
for(int j = offset; j < n - 1 - offset; j++){
result[cnt++] = matrix[offset][j];
}
for(int i = offset; i < m - 1 - offset; i++){
result[cnt++] = matrix[i][n - 1 - offset];
}
for(int j = n - 1 - offset; j > offset; j--){
result[cnt++] = matrix[m - 1 - offset][j];
}
for(int i = m - 1 - offset; i > offset; i--){
result[cnt++] = matrix[i][offset];
}
offset++;
}
if(m == n && m % 2){
result[cnt] = matrix[mid][mid];
}
if(m < n && m % 2){
for(int j = offset; j <= n - 1 - offset; j++){
result[cnt++] = matrix[offset][j];
}
}else if(n < m && n % 2){
for(int i = offset; i <= m - 1 - offset; i++){
result[cnt++] = matrix[i][offset];
}
}
return result;
}
};
note:思路和上面的一样,圈数由矩形的短的那条边决定,通过offset来调整每次转圈的起点和终点。我的错误就是写0写习惯了。。。第三四个循环应该是和offset比较,我写成大于0了。。
转完圈后,还要看较短边是不是二的倍数,如果不是我们还是需要额外地遍历中间的元素。
这题和上题一样,就不写了。
4.总结
文章链接:代码随想录