双指针算法习题

本文通过分析LeetCode中的四个问题——两数之和II、最小覆盖子串、最长有效括号和最小栈,深入讲解了双指针算法的应用。针对每个问题,不仅阐述了核心思想,还详细解释了如何利用双指针挖掘单调性、解决字符串匹配、括号匹配和数据结构优化等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode167. 两数之和 II - 输入有序数组

核心:挖掘单调性。(同时题目保证解是唯一的)当两数之和大于target,固定 i 则 j 只有可能往左移,固定 j 则 i 只有可能往右移。
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int t) {
        int n = nums.size();
        for(int i = 0, j = n-1; i < n && j >= 0; i ++){
            while(j > i && nums[i] + nums[j] > t) j --;
            if(nums[i] + nums[j] == t) return {i+1, j+1}; 
        }
        return {-1, -1};
    }
};

LeetCode76. 最小覆盖子串

双指针算法,i 先往右扫描,知道找齐所有字母。当找齐所有字母时,i不断往右走,j也只可能向右走,并丢掉一些冗余的字母。在扫描过程中记录下最小覆盖字串。
class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char, int> mp;
        //mp[c]表示字母c还需要多少个,sum表示t中有多少个不同的字母
        int sum = 0;
        for(auto c: t)
            if(mp[c] ++ == 0) sum ++;
        string res;
         //cnt表示已经找到cnt个字母
        for(int i = 0, j = 0, cnt = 0; i < s.size(); i ++){
            if(--mp[s[i]] == 0) cnt ++;
            //当我已经找齐所有字母,并且还有冗余字母
            while(cnt == sum && mp[s[j]] < 0) mp[s[j ++]] ++;
            if(cnt == sum)
                if(res.empty() || res.size() > i-j+1) 
                    res = s.substr(j, i-j+1);
        }
        return res;
    }
};

LeetCode32. 最长有效括号

‘(’看作1,‘)’看作-1,有效括号<==>任意的前缀和大于等于0。
class Solution {
public:
    int find(string& s){
        int sum = 0, res = 0;
        for(int i = 0, start = 0; i < s.size(); i ++){
            if(s[i] == '(') sum ++;
            else{
                sum --;
                if(sum == 0) res = max(res, i-start+1);
                else if(sum < 0) start = i + 1, sum = 0; 
            }
        }
        return res;
    }

    int longestValidParentheses(string s) {
        string re(s.rbegin(), s.rend());
        for(auto& r: re) r ^= 1;
        cout << re << endl;
        //从左到右找一遍,从右到左找一遍
        int res = max(find(s), find(re));
        return res;
    }

};
状态表示:dp[i]表示以第i个字符结尾的所有子串里的长度最大值。
状态计算:以倒数第二个字符进行划分。若为‘)’,则需要s[i-1-dp[i-1]+1:i-2]是一个有效括号串,并且s(i-f[i-1]-1)是‘(’,此时能找到一个更长的字串。若为‘(’,则在以第i-2个字符结尾的最长字串的基础上增加了两个。
class Solution {
public:
    int longestValidParentheses(string s) {
        vector<int> dp(s.size()+1);
        int res = 0;
        for(int i = 1; i <= s.size(); i ++){
            if (s[i] == ')') {
                if (s[i - 1] == '(') 
                    dp[i] = (i - 2 >= 0 ? dp[i - 2] : 0) + 2;
                else if (i - dp[i - 1] - 1 >= 0 && s[i - dp[i - 1] - 1] == '(') 
                    dp[i] = (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0) + dp[i - 1] +2;
            }
            res = max(res, dp[i]);
        }
        return res;
    }
};

LeetCode155. 最小栈

类似与前缀和,stk_min中存放前缀中的最小值。
class MinStack {
public:
    /** initialize your data structure here. */
    stack<int> stk, stk_min;
    MinStack() {
        
    }
    
    void push(int x) {
        stk.push(x);
        if(stk_min.empty()) stk_min.push(x);
        else stk_min.push(min(stk_min.top(), x));
    }
    
    void pop() {
        stk.pop();
        stk_min.pop();
    }
    
    int top() {
        return stk.top();
    }
    
    int getMin() {
        return stk_min.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值