【2023/2/22~2/25 Leetcode】差分数组练习集锦+滑动窗口

学习链接:

题目来源:
翻转字符串里的单词

class Solution {
public:
    string reverseWords(string s) {
        // 反转整个字符串
        reverse(s.begin(), s.end());

        int n = s.size();
        int idx = 0;
        for (int start = 0; start < n; ++start) {
            if (s[start] != ' ') {
                // 填一个空白字符然后将idx移动到下一个单词的开头位置
                if (idx != 0) s[idx++] = ' ';

                // 循环遍历至单词的末尾
                int end = start;
                while (end < n && s[end] != ' ') s[idx++] = s[end++];

                // 反转整个单词
                reverse(s.begin() + idx - (end - start), s.begin() + idx);

                // 更新start,去找下一个单词
                start = end;
            }
        }
        s.erase(s.begin() + idx, s.end());
        return s;
    }
};

一、差分数组

1.螺旋矩阵

题目来源:54. 螺旋矩阵
题解:

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector <int> ans;
        if(matrix.empty()) return ans; //若数组为空,直接返回答案
        int u = 0; //赋值上下左右边界
        int d = matrix.size() - 1;
        int l = 0;
        int r = matrix[0].size() - 1;
        while(true)
        {
            for(int i = l; i <= r; ++i) ans.push_back(matrix[u][i]); //向右移动直到最右
            if(++ u > d) break; //重新设定上边界,若上边界大于下边界,则遍历遍历完成,下同
            for(int i = u; i <= d; ++i) ans.push_back(matrix[i][r]); //向下
            if(-- r < l) break; //重新设定有边界
            for(int i = r; i >= l; --i) ans.push_back(matrix[d][i]); //向左
            if(-- d < u) break; //重新设定下边界
            for(int i = d; i >= u; --i) ans.push_back(matrix[i][l]); //向上
            if(++ l > r) break; //重新设定左边界
        }
        return ans;
    }
};
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> matrix(n,vector<int>(n));
        int u=0,d=n-1,l=0,r=n-1;
        int cnt=n*n;
        int val=1;
        while(val<=cnt){
            if (u <= d) {
            // 在顶部从左向右遍历
            for(int i=l;i<=r;i++)
                matrix[u][i]=val++;
            // 上边界下移
            u++;
            }
            if(l<=r)//向下
            {
            for(int i=u;i<=d;i++)
                matrix[i][r]=val++;
             r--;   
            }
            //向左
            if(u<=d){
            for(int i=r;i>=l;i--)
                matrix[d][i]=val++;
            d--;
            }
            if(l<=r){//向上
            for(int i=d;i>=u;i--)
                matrix[i][l]=val++;
            l++;
            }
        }
        return matrix;
    }
};

2.二维网格迁移

题目来源:
https://leetcode.cn/problems/shift-2d-grid/

二、滑动窗口框架

/* 滑动窗口算法框架 */
void slidingWindow(string s) {
    unordered_map<char, int> window;
    
    int left = 0, right = 0;
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 增大窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        // 注意在最终的解法代码中不要 print
        // 因为 IO 操作很耗时,可能导致超时
        printf("window: [%d, %d)\n", left, right);
        /********************/
        
        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 缩小窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

3 最大连续1的个数III

题目来源:https://leetcode.cn/problems/max-consecutive-ones-iii/solution/zui-da-lian-xu-1de-ge-shu-iii-by-leetcod-hw12/
题解:

//前缀和+二分法
class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> P(n + 1);
        for (int i = 1; i <= n; ++i) {
            P[i] = P[i - 1] + (1 - nums[i - 1]);
        }

        int ans = 0;
        for (int right = 0; right < n; ++right) {
        	//lower_bound():返回第一个大于等于 P[right + 1] - k的位置
            int left = lower_bound(P.begin(), P.end(), P[right + 1] - k) - P.begin();
            ans = max(ans, right - left + 1);
        }
        return ans;
    }
};

//滑动窗口
class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n=nums.size();
        int left=0,lsum=0,rsum=0;
        int ans=0;
        for(int right=0;right<n;right++){
            rsum+=1-nums[right];
            while(lsum<rsum-k){
                lsum+=1-nums[left];
                left++;
            }
            ans=max(ans,right-left+1);
        }
        return ans;
    }
};

4.绝对差不超过限制的最长连续子数组

题目来源:绝对差不超过限制的最长连续子数组
知识点:

函数名功能
my_map.insert()或按照数组直接赋值插入
my_map.find()查找一个元素
my_map.clear()清空
my_map.erase()删除一个元素
my_map.size()map的长度大小
my_map.begin()返回指向map头部的迭代器
my_map.end()返回指向map末尾的迭代器
my_map.rbegin()返回一个指向map尾部的逆向迭代器
my_map.rend()返回一个指向map头部的逆向迭代器
my_map.empty()map为空时返回true
swap()交换两个map,两个map中所有元素都交换

题解:

class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) {
        map<int,int> map;
        int left=0,right=0;
        int n=nums.size();
        int ans=0;
        while(right<n){
            map[nums[right]]++;
            if(map.rbegin()->first-map.begin()->first<=limit){
                ans=max(ans,right-left+1);
            }
            else{
                map[nums[left]]--;
                if(map[nums[left]]==0)
                    map.erase(nums[left]);
                left++;
            }
            right++;
        }
        return ans;
    }
};

5.将x减到0的最小操作数

题目来源:https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/solution/jiang-x-jian-dao-0-de-zui-xiao-cao-zuo-s-hl7u/**
题解:

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int left=-1,right=0;
        int lsum=0,rsum=0;
        int n=nums.size();
        for(int i=0;i<n;i++) 
            rsum+=nums[i];
        if(rsum<x)
            return -1;
        int ans=n+1;
        for(;left<n;++left){
            if(left!=-1)
                lsum+=nums[left];
            while(right<n&&lsum+rsum>x){
                rsum-=nums[right];
                right++;
            }
            if(lsum+rsum==x)
                ans=min(ans,(left+1)+(n-right));
        }
        return ans>n?-1:ans;
    }
};

6.存在重复元素Ⅱ

题目来源:219.存在重复元素Ⅱ
知识点:C++中set用法详解

  • s.lower_bound() 返回第一个大于或等于给定关键值的元素
  • s.upper_bound() 返回第一个大于给定关键值的元素
  • s.equal_range() 返回一对定位器,分别表示 第一个大于或等于给定关键值的元素 和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于s.end()

题解:

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        int n=nums.size();
        unordered_set<int> s;
        for(int left=0;left<n;left++){
            if(left>k)
                s.erase(nums[left-k-1]);
            if(s.count(nums[left]))
                return true;
            s.emplace(nums[left]);
        }
        return false;
    }
};

7.存在重复元素Ⅲ

题目来源:220.存在重复元素Ⅲ
题解:

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int indexDiff, int valueDiff) {
        int n=nums.size();
        set<int> s;
        for(int left=0;left<n;left++)
        {
            if(left>indexDiff)
                s.erase(nums[left-indexDiff-1]);
            auto iter=s.lower_bound(nums[left]-valueDiff);
            if(iter!=s.end()&&*iter<=nums[left]+valueDiff)
                return true;
            s.emplace(nums[left]);
        }
        return false;
    }
};

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        int n=nums.size();
        set<int> s;
        for(int i=0;i<n;i++){
            if(i>k)
            {
                s.erase(nums[i-k-1]);
            }
            auto iter=s.lower_bound(max(nums[i],INT_MIN+t)-t);
            if(iter!=s.end()&& *iter<=min(nums[i],INT_MAX-t)+t)//有时不这样会溢出
                return true;
            s.emplace(nums[i]);
        }
        return false;
    }
};

8.至少有 K 个重复字符的最长子串

题目来源:395.至少有 K 个重复字符的最长子串
题解:【分治法】

class Solution {
public:
    int longestSubstring(string s, int k) {
        int n=s.size();
        int res=0;
        vector<int> num(26);
        for(int i=0;i<n;i++){
            num[s[i]-'a']++;
        }
        for(int i=0;i<n;i++){
            if(num[s[i]-'a']<k){
                int len1=longestSubstring(s.substr(0,i),k);
                int len2=longestSubstring(s.substr(i+1,n),k);
                return max(len1,len2);
            }
        }
        return n;
    }
};

9. 和至少为K的最短子数组【没懂】

题目来源:和至少为K的最短子数组
题解:https://cloud.tencent.com/developer/article/1505345
C++ STL deque容器(详解版)

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) {
        int n=nums.size();
        vector<long> preSum(n+1);
        preSum[0]=0;
        for(int i=1;i<=n;i++)
        {
            preSum[i]=preSum[i-1]+nums[i-1];
        }
        int res=n+1;
        deque<int> dq;
        for(int i=0;i<=n;i++){
            long curSum=preSum[i];
            while(!dq.empty()&&curSum-preSum[dq.front()]>=k){
                res=min(res,i-dq.front());
                dq.pop_front();
            }
            while(!dq.empty()&&preSum[dq.back()]>=curSum){
                dq.pop_back();
            }
            dq.push_back(i);
        }
        return res<n+1?res:-1;
    }
};

10. 数组中第k大的数字【*****】

题目来源:数组中第k大的数字
题解:【用到了大顶堆的方法:建堆、调整、删除】

class Solution {
public:
    void maxHeapify(vector<int>& a,int i,int heapSize){
        int l = i * 2 + 1, r = i * 2 + 2, largest = i;
        if (l < heapSize && a[l] > a[largest]) {
            largest = l;
        } 
        if (r < heapSize && a[r] > a[largest]) {
            largest = r;
        }
        if (largest != i) {
            swap(a[i], a[largest]);
            maxHeapify(a, largest, heapSize);
        }
    }
    void buildMaxHeap(vector<int>& a, int heapSize) {
        for (int i = heapSize / 2; i >= 0; --i) {
            maxHeapify(a, i, heapSize);
        } 
    }
    int findKthLargest(vector<int>& nums, int k) {
        int heapSize = nums.size();
        buildMaxHeap(nums, heapSize);
        for (int i = nums.size() - 1; i >= nums.size() - k + 1; --i) {
            swap(nums[0], nums[i]);
            --heapSize;
            maxHeapify(nums, 0, heapSize);
        }
        return nums[0];
    }
};

未解决

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值