LeetCode-792-匹配子序列的单词数

在这里插入图片描述

1、字典树

我们可以对字符串 s s s进行字典树的建模,而后我们在查询 w o r d s words words时只需要在字典树结构内进行查询即可。

class Solution {
    struct trie {
        array<std::unique_ptr<trie>, 26> arr;
        int cnt = 0;
        void build(std::string::iterator begin, std::string::iterator end) {
            if (begin == end) {
                ++cnt;
                return;
            }
            int x = *begin - 'a';
            if (!arr[x]) {
                arr[x] = std::make_unique<trie>();
            }
            arr[x]->build(++begin, end);
        }

        void merge(std::unique_ptr<trie> node) {
            if (node == nullptr) {
                return;
            }
            cnt += node->cnt;
            for (int i = 0; i < 26; ++i) {
                if (node->arr[i]) {
                    if (!arr[i]) {
                        arr[i] = std::move(node->arr[i]);
                    } else {
                        arr[i] -> merge(std::move(node->arr[i]));
                    }
                }
            }
        }
    };
public:
    int numMatchingSubseq(string s, vector<string>& words) {
        trie root;
        for (auto& word : words) {
            root.build(word.begin(), word.end());
        }
        for (char c: s) {
            root.merge(std::move(root.arr[c-'a']));
        }
        return root.cnt;
    }
};

2、二分查找

我们可以利用一个二维数组来记录字符串 s s s中每一个字符对应的位置,并将其进行升序排列。当我们在比较两个字符串是否为匹配子序列时,我们对于 w o r d s words words中的第 j j j位字符查询其在二维数组中对应的数组,我们只需要证明在每一次查找中查找到的值都大于上一次查找的位置即可确定两个字符串匹配子序列。我们在这里可以使用二分搜索来代替遍历进行优化。

class Solution {
public:
    int numMatchingSubseq(string s, vector<string> &words) {
        vector<vector<int>> pos(26);
        for (int i = 0; i < s.size(); ++i) {
            pos[s[i] - 'a'].push_back(i);
        }
        int res = words.size();
        for (auto &w : words) {
            if (w.size() > s.size()) {
                --res;
                continue;
            }
            int p = -1;
            for (char c : w) {
                auto &ps = pos[c - 'a'];
                auto it = upper_bound(ps.begin(), ps.end(), p);
                if (it == ps.end()) {
                    --res;
                    break;
                }
                p = *it;
            }
        }
        return res;
    }
};

3、多指针

我们可以使用指针让字符串 s s s一对多的进行匹配从而提升搜索速度。

class Solution {
public:
    int numMatchingSubseq(string s, vector<string> &words) {
        vector<queue<pair<int, int>>> queues(26);
        for (int i = 0; i < words.size(); ++i) {
            queues[words[i][0] - 'a'].emplace(i, 0);
        }
        int res = 0;
        for (char c : s) {
            auto &q = queues[c - 'a'];
            int size = q.size();
            while (size--) {
                auto [i, j] = q.front();
                q.pop();
                ++j;
                if (j == words[i].size()) {
                    ++res;
                } else {
                    queues[words[i][j] - 'a'].emplace(i, j);
                }
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值