3. 无重复字符的最长子串 30. 串联所有单词的子串 滑动窗口

3. 无重复字符的最长子串

题目

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

思路

模拟查找最长子串,依次以较左边起点为开始,找子串直到遇见有重复字符,然后依次起点右移,重复步骤。

  • 抽象出一个滑动窗口,子串以左边为起点,右边指针扩展至第一个不重复字符或者最后一个不重复字符,采用hash集合简化窗口内字符的查找
  • 细节处理:左起点右移的元素删除,右指针的边界和元素定义(是否归属子串,决定子串长度的计算式)

解法:滑动窗口,hashset

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.length();
        if (len < 2)
            return len;

        int maxLen = 0;
        int right = 0;                                  //滑动窗口的右指针
        unordered_set<char> set;
        for (int i = 0; i < len; ++i) {                 //滑动窗口的左起点
            if (i != 0)                                 //窗口右移时,删除旧起点的元素
                set.erase(s[i-1]);

            while(right < len && !set.count(s[right])) {//向右扩展窗口
                set.insert(s[right]);
                ++right;
            }
            maxLen = max(right-i, maxLen);              //右指针减左起点即长度,用max()
        }

        return maxLen;
    }
};

30. 串联所有单词的子串

给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

示例 1:

输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:

输入:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
输出:[]

思路

示例中有两个细节没有体现

1:匹配的子串可能重叠,并不是严格不相交。

2:子串并不是以单词长度为移动步长找到的。

          移动窗口做,找符合条件的起点,再往后延伸找整个子串。在找到符合的起点之后才操作窗口的内容,每个新窗口都有新的hashmap记录窗口内容,所以移动窗口时无需删除旧窗口的无效内容。因为每个有效起点重建一个hash_map,数据量太大时,可能会引起超时,但此题没有该问题。

       毋庸置疑,本题涉及string的一系列操作,需要适时使用容器的函数,极其相关函数的区别,博文后已附上必要的函数使用方法。

解法:移动窗口,两个unordered_map对比匹配子串

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
        int num = words.size();
        if (num == 0)
            return res;
        int wordLen = words[0].length();
        int len = s.length();
        if (len < wordLen*num) 
            return res;
        
        unordered_map<string, int> wordMap;
        for (string & str : words)
            ++wordMap[str];

        for (int i = 0; i <= len - wordLen*num; ++i) {       //有等于号!,每次移动一格而不是一个单词长度
            string current = s.substr(i, wordLen);
            if (!wordMap.count(current))                     //words里没有该单词
                continue;
            
            unordered_map<string, int> resMap;               //记录res中单词情况
            ++resMap[current];

            int right = i+wordLen, resNum = 1;
            while (resNum < num) {
                string next = s.substr(right, wordLen);
                if (!wordMap.count(next)                     //words里没有该单词
                    || resMap[next] == wordMap[next])        //words里有该单词,但是个数已够
                    break;

                ++resMap[next];
                right += wordLen;
                ++resNum;
            }
            if (resNum == num)                              //符合条件,左窗口右移一个单词长度
                res.push_back(i);
        }

        return res;
    }
};

 附

获取子串:

s.substr(startIndex, subLen); 取得s从startIndex下标开始的subLen个的字符作为子串

容易混淆的查找函数:

1. size_t find (const char* s, size_t pos = 0) const;

//在当前字符串的pos索引位置开始,查找子串s,返回找到的位置索引, -1表示查找不到子串

2. size_t find (char c, size_t pos = 0) const;

//在当前字符串的pos索引位置开始,查找字符c,返回找到的位置索引, -1表示查找不到字符

3. size_t rfind (const char* s, size_t pos = npos) const;

//在当前字符串的pos索引位置开始,反向查找子串s,返回找到的位置索引, -1表示查找不到子串

4. size_t rfind (char c, size_t pos = npos) const;

//在当前字符串的pos索引位置开始,反向查找字符c,返回找到的位置索引,-1表示查找不到字符

5. size_t find_first_of (const char* s, size_t pos = 0) const;

//在当前字符串的pos索引位置开始,查找子串s的字符,返回找到的位置索引,-1表示查找不到字符

6. size_t find_first_not_of (const char* s, size_t pos = 0) const;

//在当前字符串的pos索引位置开始,查找第一个不位于子串s的字符,返回找到的位置索引,-1表示查找不到字符

7. size_t find_last_of(const char* s, size_t pos = npos) const;

//在当前字符串的pos索引位置开始,查找最后一个位于子串s的字符,返回找到的位置索引,-1表示查找不到字符

8. size_t find_last_not_of (const char* s, size_t pos = npos) const;

//在当前字符串的pos索引位置开始,查找最后一个不位于子串s的字符,返回找到的位置索引,-1表示查找不到子串

#include <iostream>
#include <vector>
using namespace std;

int main() {
	string s = "wordgoodgoodgoodbestword" , str = "good";
	int i = s.find_first_of(str, 0) ;
	int j = s.find(str, 0) ;
	cout<< i << endl << j<<endl;
	return 0;
}

输出是

1                     //查的是good中字符o第一次出现在第1位

4                    //查的是good子串第一次出现在第4位

猜你喜欢

转载自blog.csdn.net/sy_123a/article/details/109035694