LeetCode题解–76. Minimum Window Substring

链接

LeetCode题目:https://leetcode.com/problems/minimum-window-substring/

难度:Hard

题目

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = “ADOBECODEBANC”
T = “ABC”
Minimum window is “BANC”.

分析

这题的难点在于时间复杂度要在O(n),而暴力或者动态规划需要的时间复杂度都在O(n^2)以上,所以考虑用贪心算法。
具体做法是用双指针动态维护匹配的字符串区间,尾指针不断移动,当匹配成功且实际匹配数大于预期匹配时可以移动头指针,并用另外2个变量记录匹配到的最短字符串开头下标以及长度。

代码

#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>

using namespace std;

class Solution {
public:
    string minWindow(string s, string t) {
        auto t_set = get_t_set(t);
        auto t_pos = get_t_pos(s, t_set);
        auto expect_cnt_map = get_expect_cnt_map(t);
        auto match_cnt_map = get_match_cnt_map(t);

        if (s.size() < t.size()) return "";
        if (t.size() == 0) return "";

        int min_len = INT32_MAX, min_start = 0;
        int left_pos = 0;
        int match_cnt = 0;
        for (int right_pos = 0; right_pos < t_pos.size(); right_pos++) {
            char right_c = s[t_pos[right_pos]];

            match_cnt_map[right_c] += 1;
            if (match_cnt_map[right_c] <= expect_cnt_map[right_c]) {
                match_cnt++;
            }
            if (match_cnt == t.size()) {
                while (match_cnt_map[s[t_pos[left_pos]]] > expect_cnt_map[s[t_pos[left_pos]]]) {
                    match_cnt_map[s[t_pos[left_pos]]] -= 1;
                    left_pos++;
                }
                int match_len = t_pos[right_pos] - t_pos[left_pos] + 1;
                if (match_len < min_len) {
                    min_len = match_len;
                    min_start = left_pos;
                }
            }
        }
        if (min_len == INT32_MAX) return "";
        else return s.substr((unsigned long) t_pos[min_start], (unsigned long) min_len);
    }

private:
    unordered_set<char> get_t_set(string t) {
        unordered_set<char> t_set;
        for (auto c:t) {
            t_set.insert(c);
        }
        return t_set;
    }

    vector<int> get_t_pos(string s, unordered_set<char> t_set) {
        vector<int> t_pos;
        for (int i = 0; i < s.size(); i++) {
            if (t_set.find(s[i]) != t_set.end()) {
                t_pos.push_back(i);
            }
        }
        return t_pos;
    }

    unordered_map<char, int> get_expect_cnt_map(string t) {
        unordered_map<char, int> cnt_map;
        for (auto c:t) {
            if (cnt_map.find(c) == cnt_map.end()) {
                cnt_map.insert({c, 1});
            } else {
                cnt_map[c] += 1;
            }
        }
        return cnt_map;
    };

    unordered_map<char, int> get_match_cnt_map(string t) {
        unordered_map<char, int> cnt_map;
        for (auto c:t) {
            cnt_map[c] = 0;
        }
        return cnt_map;
    };

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值