侧边栏壁纸
博主头像
GabrielxD

列車は必ず次の駅へ。では舞台は?私たちは?

  • 累计撰写 471 篇文章
  • 累计创建 108 个标签
  • 累计收到 9 条评论

目 录CONTENT

文章目录

【双指针, 前缀树, API, STL】检查单词是否为句中其他单词的前缀

GabrielxD
2022-08-21 / 0 评论 / 0 点赞 / 41 阅读 / 1,448 字 / 正在检测是否收录...

题目

1455. 检查单词是否为句中其他单词的前缀


给你一个字符串 sentence 作为句子并指定检索词为 searchWord ,其中句子由若干用 单个空格 分隔的单词组成。请你检查检索词 searchWord 是否为句子 sentence 中任意单词的前缀。

如果 searchWord 是某一个单词的前缀,则返回句子 sentence 中该单词所对应的下标(下标从 1 开始)。如果 searchWord 是多个单词的前缀,则返回匹配的第一个单词的下标(最小下标)。如果 searchWord 不是任何单词的前缀,则返回 -1

字符串 s前缀s 的任何前导连续子字符串。

示例 1:

输入:sentence = "i love eating burger", searchWord = "burg"
输出:4
解释:"burg" 是 "burger" 的前缀,而 "burger" 是句子中第 4 个单词。

示例 2:

输入:sentence = "this problem is an easy problem", searchWord = "pro"
输出:2
解释:"pro" 是 "problem" 的前缀,而 "problem" 是句子中第 2 个也是第 6 个单词,但是应该返回最小下标 2 。

示例 3:

输入:sentence = "i am tired", searchWord = "you"
输出:-1
解释:"you" 不是句子中任何单词的前缀。

提示:

  • 1 <= sentence.length <= 100
  • 1 <= searchWord.length <= 10
  • sentence 由小写英文字母和空格组成。
  • searchWord 由小写英文字母组成。

解题

方法一:Java API(split() + startsWith())

思路

如果用上 Java API,那这题就再简单不过了:

直接把字符串按照空格分割(split())为字符串数组然后遍历数组,如果某个元素以 serachWord 为前缀(startWith()),那么就直接返回对应下标加一。遍历完成后还没返回说明没有符合的单词,直接返回 -1

代码

class Solution {
    public int isPrefixOfWord(String sentence, String searchWord) {
        String[] words = sentence.split(" ");
        for (int i = 0; i < words.length; ++i) {
            if (words[i].startsWith(searchWord)) return i + 1;
        }
        return -1;
    }
}

方法二:双指针 Java API / C++ STL

思路

由于 C++ 没有像 Java 那么好用的用来分割字符串 API(split()),所以我们来自己实现一个。

也很简单,维护一个计数(count)表示目前单词的位置,两个指针:一个应该指向单词开头(start / begin),另一个应该指向单词结尾的下一个字符(也就是空格)(end)。初始化前指针指向 s[0],后指针指向下一个字符(毕竟单词再短也至少有一个字符),然后开始遍历:

对于每一次循环,后指针先向后推找到最近的一个空格,那么 [begin/start,end)[begin / start, end) 就是一个单词,判断这个单词前缀是否含有 searchWord 如果有就直接返回计数,否则计数自增,前指针和后指针都移动到后指针的下一个元素上继续下一次遍历。

这里判断前缀可以使用 Java API(startWith()) 或 C++ STL(find())(如果在字串中找到前缀的位置为 0 那就说明包含前缀)。也可以写个方法一个字符一个字符比较。

代码

class Solution {
public:
    int isPrefixOfWord(string sentence, string search_word) {
        int count = 1;
        for (auto begin = sentence.begin(), end = begin + 1; begin < sentence.end();) {
            while (end < sentence.end() && *end != ' ') ++end;
            string word(begin, end);
            if (word.find(search_word) == 0) return count;
            ++count;
            begin = ++end;
        }
        return -1;
    }
};

isSectionValid() 用来判断前缀是否存在于该字串。

class Solution {
    char[] sentence, searchWord;
    int searchWordLen;

    public int isPrefixOfWord(String _sentence, String _searchWord) {
        sentence = _sentence.toCharArray();
        searchWord = _searchWord.toCharArray();
        int n = sentence.length;
        searchWordLen = searchWord.length;
        for (int start = 0, end = 1, count = 1; start < n;) {
            while (end < n && sentence[end] != ' ') ++end;
            if (isSectionValid(start, end)) return count;
            ++count;
            start = ++end;
        }
        return -1;
    }

    boolean isSectionValid(int start, int end) {
        if (end - start < searchWordLen) return false;
        for (int i = 0; i < searchWordLen; ++i) {
            if (sentence[start + i] != searchWord[i]) return false;
        }
        return true;
    }
}

方法三:双指针 前缀树(字典树)

思路

要想把这题变得更复杂一点的话(虽然它本身只是个简单题)就上前缀树(Trie)吧。

具体前缀树的作用和实现见:【前缀树】实现 Trie (前缀树)

(当然,再往复杂处用 KMP 什么的做也可以,但是没必要了)

(这题我看到单词前缀就想都没想上前缀树了,后来才看到解题里大家都是用 API 直接做的 ヽ(*。>Д<)o゜)

代码

class Trie {
public:
    bool is_end;
    Trie* children[26];

    Trie() : is_end(false) {
        for (int i = 0; i < 26; ++i) children[i] = nullptr;
    }

    void insert(string& word) {
        Trie* node = this;
        for (char ch : word) {
            int idx = ch - 'a';
            if (!node->children[idx]) node->children[idx] = new Trie();
            node = node->children[idx];
        }
        node->is_end = true;
    }

    Trie* searchPrefix(string& word) {
        Trie* node = this;
        for (char ch : word) {
            int idx = ch - 'a';
            if (!node->children[idx]) return nullptr;
            node = node->children[idx];
        }
        return node;
    }

    bool startsWith(string& word) {
        return searchPrefix(word);
    }
};

class Solution {
public:
    int isPrefixOfWord(string sentence, string search_word) {
        Trie trie;
        int count = 1;
        for (auto begin = sentence.begin(), end = begin + 1; begin < sentence.end();) {
            while (end < sentence.end() && *end != ' ') ++end;
            string word(begin, end);
            trie.insert(word);
            if (trie.startsWith(search_word)) return count;
            ++count;
            begin = ++end;
        }
        return -1;
    }
};
class Solution {
    public int isPrefixOfWord(String sentence, String searchWord) {
        String[] words = sentence.split(" ");
        Trie trie = new Trie();
        for (int i = 0; i < words.length; ++i) {
            trie.insert(words[i]);
            if (trie.startsWith(searchWord)) return i + 1;
        }
        return -1;
    }

    static class Trie {
        boolean isEnd;
        Trie[] children;

        public Trie() {
            isEnd = false;
            children = new Trie[26];
        }

        void insert(String word) {
            Trie node = this;
            for (char ch : word.toCharArray()) {
                int idx = ch - 'a';
                if (node.children[idx] == null) node.children[idx] = new Trie();
                node = node.children[idx];
            }
            node.isEnd = true;
        }

        Trie searchPrefix(String word) {
            Trie node = this;
            for (char ch : word.toCharArray()) {
                int idx = ch - 'a';
                if (node.children[idx] == null) return null;
                node = node.children[idx];
            }
            return node;
        }

        boolean startsWith(String word) {
            return searchPrefix(word) != null;
        }
    }
}
0

评论区