面试题 17.18. 最短超串

难度中等23

假设你有两个数组,一个长一个短,短的元素均不相同。找到长数组中包含短数组所有的元素的最短子数组,其出现顺序无关紧要。

返回最短子数组的左端点和右端点,如有多个满足条件的子数组,返回左端点最小的一个。若不存在,返回空数组。

示例 1:

输入:
big = [7,5,9,0,2,1,3,5,7,9,1,1,5,8,8,9,7]
small = [1,5,9]
输出: [7,10]

示例 2:

输入:
big = [1,2,3]
small = [4]
输出: []

提示:

  • big.length <= 100000
  • 1 <= small.length <= 100000
class Solution {
public:
	vector<int> shortestSeq(vector<int>& big, vector<int>& small) {
		int left = 0, right = 0;
		vector<int>res;
		int min_l = INT32_MAX;
		if (big.size() == 0)
			return res;
		unordered_map<int, int>doom;
		int N = small.size();
		for (auto i : small){
			doom[i] = 1;
        }
		while (right < big.size()) {
			while (left < big.size() && doom.find(big[left]) == doom.end())
				left++;
			if (left >= big.size())
				break;
			right = max(right, left);
			while (right < big.size()) {
				if (doom.find(big[right]) == doom.end())
					right++;
				else{
                    doom[big[right]]--;
                    if(doom[big[right]]==0){
                        N--;
                    }
					if (N == 0 && right - left < min_l) {
                        //cout << "min = " << left << ' ' <<right<<endl;
						min_l = right - left;
						res.resize(2);
						res[0]=(left);
						res[1]=(right);
					}
                    if(N == 0 ){
                        doom[big[left]]++;
                        if(doom[big[left++]] == 1){
                            N++;
                        }
                        doom[big[right]]++;
                        if(doom[big[right]] == 1)
                            N++;
                        break;
                    }
                    else
                        right++;
				}
			}
		}
		return res;
	}
};

可参考滑动窗写法如下:引自https://leetcode-cn.com/problems/shortest-supersequence-lcci/solution/xiang-xi-tu-jie-hua-dong-chuang-kou-chao-qi7g/

一般滑动窗口维护两个指针,左指针和右指针。

当窗口内的元素未达到题目条件时,右指针右移,探索未知的区间来满足条件
当窗口内的元素达到题目条件时,左指针右移,压缩区间,使窗口尽可能短得满足题目条件

class Solution {
public:
    vector<int> shortestSeq(vector<int>& big, vector<int>& small) {
        int n = big.size();
        vector<int> res;
        // need:记录滑动窗口内需要覆盖的数字,及其对应的个数
        unordered_map<int, int> need;
        // diff:记录滑动窗口一共需要覆盖的数字个数
        int minLen = n, diff = 0;
        // 数据预处理:统计需要覆盖的字符有多少个
        for (auto& e : small) {
            need[e]++;
            diff++;
        }

        // 滑动窗口:l指向窗口左边界,r指向窗口右边界
        int l = 0, r = 0;
        for (; r < n; ++r) {
            // need中存在,diff减一
            if (need.find(big[r]) != need.end() && --need[big[r]] >= 0) --diff;
            // 如果diff = 0,收缩窗口,左指针右移
            while (diff == 0) {
                if (r - l < minLen) {
                    minLen = r - l;
                    res = {l, r};
                }
                if (need.find(big[l]) != need.end() && ++need[big[l]] > 0) ++diff;
                ++l;
            }
        }

        return res;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值