• leetCode 30.串联所有单词的子串


    给定一个字符串 s 和一个字符串数组 words words 中所有字符串 长度相同s 中的 串联子串 是指一个包含  words 中所有字符串以任意顺序排列连接起来的子串。

    • 例如,如果 words = ["ab","cd","ef"], 那么 "abcdef", "abefcd""cdabef", "cdefab""efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。

    返回所有串联子串在 s 中的开始索引。你可以以 任意顺序 返回答案。

    示例 1:

    输入:s = "barfoothefoobarman", words = ["foo","bar"]
    输出:[0,9]
    
    解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
    子串 "barfoo" 开始位置是 0。它是 words 中以 ["bar","foo"] 顺序排列的连接。
    子串 "foobar" 开始位置是 9。它是 words 中以 ["foo","bar"] 顺序排列的连接。
    输出顺序无关紧要。返回 [9,0] 也是可以的。

    示例 2:

    输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
    输出:[]
    
    解释:因为 words.length == 4 并且 words[i].length == 4,所以串联子串的长度必须为 16。
    s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接。
    所以我们返回一个空数组。

    示例 3:

    输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
    输出:[6,9,12]
    解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。
    子串 "foobarthe" 开始位置是 6。它是 words 中以 ["foo","bar","the"] 顺序排列的连接。
    子串 "barthefoo" 开始位置是 9。它是 words 中以 ["bar","the","foo"] 顺序排列的连接。
    子串 "thefoobar" 开始位置是 12。它是 words 中以 ["the","foo","bar"] 顺序排列的连接。
    
    (1)情况一,子串完全匹配

    (2)情况二,遇到了不匹配的单词,直接将 left 移动到该单词的后边

      (3)情况三,遇到了符合的单词,但是次数超了

    1. class Solution {
    2. public:
    3. vector<int> findSubstring(string s, vector& words) {
    4. vector<int> res;
    5. if (s.size() == 0 || words.size() == 0) {
    6. return res;
    7. }
    8. int wordsNum = words.size();//words的个数
    9. int wordLen = words[0].size();//word的长度
    10. int width = wordsNum*wordLen;
    11. if(s.size()return res;// 长度不符合预期
    12. // 将单词数组构建成哈希表
    13. unordered_mapint> words_map;
    14. // unordered_map tmp_map;
    15. string word="";
    16. for (string str : words) {
    17. words_map[str]+=1;
    18. }
    19. // 只遍历 0 ~ wordLen 即可,因为滑动窗口都是按照 wordLen 的倍数进行滑动的
    20. for(int i=0;i
    21. unordered_mapint> tmp_map;
    22. // 滑动窗口
    23. int left=i,right=i,count=0;
    24. while(right + wordLen <= s.length()) {
    25. string word = s.substr(right,wordLen);
    26. // cout<<"word : " << word<
    27. right += wordLen;
    28. if(words_map.find(word)!=words_map.end()) {
    29. int num = tmp_map[word]+1;
    30. // 有效单词数+1
    31. tmp_map[word]+=1;
    32. count++;
    33. // 出现情况三,遇到了符合的单词,但是次数超了
    34. if(words_map[word] < num) {
    35. // 一直移除单词,知道次数符合
    36. while(words_map[word] < tmp_map[word]) {
    37. string deleteWord = s.substr(left,wordLen);// 要移除的单词
    38. tmp_map[deleteWord]--;// 更新tmp_map
    39. left+=wordLen;// 同时移动左指针
    40. count--;// count数目-1
    41. }
    42. }
    43. } else {
    44. // 出现情况二,遇到了不匹配的单词,直接将 left 移动到该单词的后边
    45. tmp_map.clear();// 清空tmp_map
    46. count=0;// 清空count
    47. left=right;
    48. if(left+width>s.size()) break;
    49. }
    50. if(count == wordsNum) {
    51. res.push_back(left);
    52. // 出现情况一,子串完全匹配,我们将上一个子串的第一个单词从tmp中移除,窗口后移wordLen
    53. string firstWord = s.substr(left,wordLen);
    54. tmp_map[firstWord]--;
    55. count--;
    56. left += wordLen;
    57. }
    58. }
    59. }
    60. return res;
    61. }
    62. };

    改进一下:

    1. class Solution {
    2. public:
    3. vector<int> findSubstring(string s, vector& words) {
    4. vector<int> res;
    5. if (s.size() == 0 || words.size() == 0) {
    6. return res;
    7. }
    8. int wordsNum = words.size();//words的个数
    9. int wordLen = words[0].size();//word的长度
    10. int width = wordsNum*wordLen;
    11. if(s.size()return res;// 长度不符合预期
    12. // 将单词数组构建成哈希表
    13. unordered_mapint> words_map;
    14. // unordered_map tmp_map;
    15. string word="";
    16. for (string str : words) {
    17. words_map[str]+=1;
    18. }
    19. if(wordLen==1 && words_map.size()==1) {
    20. char c=words[0][0];
    21. for(int i=0;i<=s.size()-width;i++) {
    22. if(s[i]==c)
    23. res.push_back(i);
    24. }
    25. return res;
    26. }
    27. // 只遍历 0 ~ wordLen 即可,因为滑动窗口都是按照 wordLen 的倍数进行滑动的
    28. for(int i=0;i
    29. unordered_mapint> tmp_map;
    30. // 滑动窗口
    31. int left=i,right=i,count=0;
    32. while(right + wordLen <= s.length()) {
    33. string word = s.substr(right,wordLen);
    34. // cout<<"word : " << word<
    35. right += wordLen;
    36. if(words_map.find(word)!=words_map.end()) {
    37. int num = tmp_map[word]+1;
    38. // 有效单词数+1
    39. tmp_map[word]+=1;
    40. count++;
    41. // 出现情况三,遇到了符合的单词,但是次数超了
    42. if(words_map[word] < num) {
    43. // 一直移除单词,知道次数符合
    44. while(words_map[word] < tmp_map[word]) {
    45. string deleteWord = s.substr(left,wordLen);// 要移除的单词
    46. tmp_map[deleteWord]--;// 更新tmp_map
    47. left+=wordLen;// 同时移动左指针
    48. count--;// count数目-1
    49. }
    50. }
    51. } else {
    52. // 出现情况二,遇到了不匹配的单词,直接将 left 移动到该单词的后边
    53. tmp_map.clear();// 清空tmp_map
    54. count=0;// 清空count
    55. left=right;
    56. if(words_map.find(s.substr(right,wordLen))==words_map.end()) {
    57. right+=wordLen;
    58. left=right;
    59. }
    60. if(left+width>s.size()) break;
    61. }
    62. if(count == wordsNum) {
    63. res.push_back(left);
    64. // 出现情况一,子串完全匹配,我们将上一个子串的第一个单词从tmp中移除,窗口后移wordLen
    65. string firstWord = s.substr(left,wordLen);
    66. tmp_map[firstWord]--;
    67. count--;
    68. left += wordLen;
    69. }
    70. }
    71. }
    72. return res;
    73. }
    74. };

    参考文章:30. 串联所有单词的子串 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/substring-with-concatenation-of-all-words/solutions/9092/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-6/?envType=study-plan-v2&envId=top-interview-150

  • 相关阅读:
    cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容。应以 ‘{layoutlib}‘ 之一开头
    rabbitmq简记
    Linux之(14)shell(6)gawk进阶
    【Python】Django Web 框架
    项目管理中,如何使用进度猫管理项目里程碑
    一文介绍回归和分类的本质区别 !!
    【CSS颜色指南】:看完这一篇就明白CSS常见颜色表示方法
    go语言数组、切片和指针
    Java服务假死后续之内存溢出
    pytorch环境搭建(GPU)+Anaconda+CUDA+离线安装
  • 原文地址:https://blog.csdn.net/weixin_41987016/article/details/133975766