【每日一题Day30】LC792匹配子序列的单词数 | 哈希表+ 二分 多指针+队列

简介: 使用双指针扫描两个字符串时,对于原串的扫描,会有大量的字符串会被跳过–>如何快速定位到下一个字符的位置?

匹配子序列的单词数【LC792】


给定字符串 s 和字符串数组 words, 返回 words[i] 中是s的子序列的单词个数 。


字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是none),而不改变其余字符的相对顺序。


  • 例如, “ace” 是 “abcde” 的子序列。


Given a string s and an array of strings words, return the number of words[i] that is a subsequence of s.


A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.


  • For example, "ace" is a subsequence of "abcde".


2022/11/17


  • 思路:dp或者双指针求解每个单词是否是s的子序列–>超时


。双指针复杂度


  • 时间复杂度:O ( ( n + m ) ∗ s i z e ),n为字符串长度,m为单词平均长度,size为字符串数量


  • 空间复杂度:O ( 1 ) O(1)O(1)


。怎么优化单个单词的判定操作?


  • 使用双指针扫描两个字符串时,对于原串的扫描,会有大量的字符串会被跳过–>如何快速定位到下一个字符的位置?


–>使用哈希表存储每个字母在原串中的位置,即哈希表的key为字母,value为对应的下标[递增顺序],那么可以通过二分法查找下一个字符对应的位置


  • 将所有单词和字符串s同时进行匹配,存储words,然后遍历s,每个位置字母把对应的word往后移动,如果已经到word长度了,那就证明是word是s的子序列,遍历结束没匹配完的就不是子序列


哈希表+二分


  • 实现


class Solution {
    public int numMatchingSubseq(String s, String[] words) {
        int res = 0;
        int lenS = s.length();
        Map<Character,List<Integer>> charToIndex = new HashMap<>();
        for (int i = 0; i < lenS; i++){
            List<Integer> list = charToIndex.getOrDefault(s.charAt(i),new ArrayList<>());
            list.add(i);
            charToIndex.put(s.charAt(i),list);
        }
        for (String word : words){
            int wordLen = word.length();
            int index = -1;// 记录下一个下标
            boolean  isFound = true;
            for (int i = 0; i < wordLen && isFound; i++){
                // 二分查找下一个下标
                List<Integer> list = charToIndex.getOrDefault(word.charAt(i),new ArrayList<>());
                int l = 0, r = list.size() - 1;
                while (l < r){
                    int mid = l + r >> 1;
                    if (list.get(mid) > index){
                        r = mid;
                    }else{
                        l = mid + 1;
                    }
                }
                if (r < 0 || list.get(r) <= index){
                    isFound = false; // 没有合法的下一个下标
                }else{
                    index = list.get(r);
                }             
            }
            if (isFound){
                res++;
            }
        }
        return res;
    }
}


。复杂度


  • 时间复杂度:O ( n + m ∗ s i z e ∗ l o g n ),n为字符串长度,m为单词平均长度,size为字符串数量


  • 空间复杂度:O ( n )


多指针+队列


  • 实现:


。使用栈或者队列存储每个字符对应的单词二元组[单词下标,遍历到的下标]


。每遍历一个字符,将其对应的栈中的元素出栈,如果二元组遍历到的下标已经单词末尾,那么证明该word是s的子序列,res++


  • 代码


class Solution {
    public int numMatchingSubseq(String s, String[] words) {
        int res = 0;
        int lenS = s.length();
        Deque<int[]>[] deque = new LinkedList[26];
        for (int i = 0; i < deque.length; i++){
            deque[i] = new LinkedList<>();
        }
        for (int i = 0; i < words.length; i++){
            deque[words[i].charAt(0) - 'a'].addLast(new int[]{i,0});
        }
        for (int i = 0; i < lenS; i++){
            char c = s.charAt(i);
            Deque<int[]> wordList = deque[c - 'a'];
            int size = wordList.size();
            for (int j = 0; j < size; j++){
                int[] word = wordList.pollFirst();
                int index = word[0];
                if (word[1] == words[index].length() - 1){
                    res++;
                }else{
                    word[1]++;
                    deque[words[index].charAt(word[1]) - 'a'].addLast(word);
                }
            }
        }
        return res;
    }
}


。复杂度


  • 时间复杂度:O ( n + m ∗ s i z e ) ,n为字符串长度,m为单词平均长度,size为字符串数量


  • 空间复杂度:O ( s i z e ),主要为存储字符串数组中每一个字符串现在的对应匹配指针的空间开销。
目录
相关文章
|
7月前
|
算法 C语言
OJ刷题:求俩个数组的交集(没学哈希表?快排双指针轻松搞定!)
OJ刷题:求俩个数组的交集(没学哈希表?快排双指针轻松搞定!)
|
7月前
|
存储
【每日一题Day132】LC23633合并相似的物品 | 哈希表 排序+双指针
【每日一题Day132】LC23633合并相似的物品 | 哈希表 排序+双指针
52 0
|
7月前
DAY-2 | 哈希表、指针与区间划分:字符种数统计问题
```markdown ## 题干 [牛客网链接](https://www.nowcoder.com/practice/eb94f6a5b2ba49c6ac72d40b5ce95f50) ## 题解 1. **查表法(哈希表)**:利用数组标记出现过的 ASCII 值小于127的字符,首次出现计数,重复则忽略。 2. **指针与区间划分(回头法)**:遍历字符串,对每个字符检查其前所有字符是否重复,重复则不计数。 ## 方法总结 - 哈希表在去重问题中非常实用,可多做相关练习。 - 使用`continue`时注意避免死循环,确保循环变量会改变。 - 多回顾此类问题以巩固理解。 ```
44 2
|
7月前
|
算法
"刷题记录:哈希表+双指针 | leetcode-2465. 不同的平均值数目 "
该文段是一篇关于编程题目的解答,主要讨论如何找到数组中所有不同平均值的个数。作者首先使用排序和哈希集来解决,将数组转为列表排序后,通过双指针计算平均值并存入哈希集以去重。然后,作者发现可以优化方案,通过双指针在排序后的数组中直接计算两数之和,用哈希集记录不重复的和,从而避免实际计算平均值,提高了算法效率。最终代码展示了这两种方法。
57 0
|
7月前
|
算法 索引
LeetCode刷题--- 138. 复制带随机指针的链表(哈希表+迭代)
LeetCode刷题--- 138. 复制带随机指针的链表(哈希表+迭代)
|
7月前
【每日一题Day303】统计点对的数目 | 哈希表+双指针
【每日一题Day303】统计点对的数目 | 哈希表+双指针
42 0
|
7月前
|
索引
【每日一题Day281】LC142链表 Ⅱ| 快慢指针 哈希表
【每日一题Day281】LC142链表 Ⅱ| 快慢指针 哈希表
40 0
|
7月前
|
存储 索引
【每日一题Day280】LC141环形链表 | 快慢指针 哈希表
【每日一题Day280】LC141环形链表 | 快慢指针 哈希表
34 0
|
索引
力扣142 - 环形链表||【二重双指针+哈希表】
灵活运用双指针,带您一探环形链表的奥秘
101 0
力扣142 - 环形链表||【二重双指针+哈希表】
|
C++ 容器
力扣349 - 两个数组的交集【哈希表+数组+双指针】
对应力扣349.两个数组的交集,三种思路三个方向,带你玩转LeetCode
134 0
力扣349 - 两个数组的交集【哈希表+数组+双指针】