情感丰富的文字

标签: 数组 双指针 字符串

难度: Medium

有时候人们会用重复写一些字母来表示额外的感受,比如 "hello" -> "heeellooo", "hi" -> "hiii"。我们将相邻字母都相同的一串字符定义为相同字母组,例如:"h", "eee", "ll", "ooo"。

对于一个给定的字符串 S ,如果另一个单词能够通过将一些字母组扩张从而使其和 S 相同,我们将这个单词定义为可扩张的(stretchy)。扩张操作定义如下:选择一个字母组(包含字母 c ),然后往其中添加相同的字母 c 使其长度达到 3 或以上。

例如,以 "hello" 为例,我们可以对字母组 "o" 扩张得到 "hellooo",但是无法以同样的方法得到 "helloo" 因为字母组 "oo" 长度小于 3。此外,我们可以进行另一种扩张 "ll" -> "lllll" 以获得 "helllllooo"。如果 s = "helllllooo",那么查询词 "hello" 是可扩张的,因为可以对它执行这两种扩张操作使得 query = "hello" -> "hellooo" -> "helllllooo" = s

输入一组查询单词,输出其中可扩张的单词数量。

示例:

输入: 
s = "heeellooo"
words = ["hello", "hi", "helo"]
输出:1
解释:
我们能通过扩张 "hello" 的 "e" 和 "o" 来得到 "heeellooo"。
我们不能通过扩张 "helo" 来得到 "heeellooo" 因为 "ll" 的长度小于 3 。

提示:

  • 1 <= s.length, words.length <= 100
  • 1 <= words[i].length <= 100
  • s 和所有在 words 中的单词都只由小写字母组成。

Submission

运行时间: 31 ms

内存: 16.2 MB

class Solution:
    def expressiveWords(self, s: str, words: List[str]) -> int:
        def traversal(s):
            cache = []
            for char in s:
                if not cache or cache[-1][0] != char:
                    cache.append(char)
                else:
                    cache[-1] += char
            return cache
        cache = traversal(s)

        ans = 0
        length = len(cache)
        for word in words:
            word_cache = traversal(word)
            i = 0
            j = 0
            word_length = len(word_cache)
            if word_length == length:
                while i<length:
                    if cache[i] == word_cache[j]:
                        i += 1
                        j += 1
                        continue
                    if cache[i][0] == word_cache[j][0] and len(cache[i])>=3 and len(cache[i])>=len(word_cache[j]):
                        i += 1
                        j += 1
                        continue
                    break
                if i == length and j == length:
                    ans += 1
        return ans

Explain

该题解的核心思路是首先将输入字符串S和比较的单词列表words中的每个单词分解成字母组的形式。字母组是指相邻的并且相同的字母序列。例如,'heeellooo' 会被分解为 ['h', 'eee', 'll', 'ooo']。分解后,对于每个单词,检查其分解形式是否可以通过扩展操作与S的分解形式匹配。扩展操作允许将一个字母组扩展到至少3个相同字符,前提是原始字母组至少有1个字符。题解通过遍历words列表中每个单词的字母组,逐个比较每个字母组的字符和长度,以判断是否可以通过扩展变为目标字母组。如果一个单词的所有字母组都能匹配,那么这个单词被认为是可扩张的。

时间复杂度: O(n + m*k + m*l)

空间复杂度: O(n + k)

class Solution:
    def expressiveWords(self, s: str, words: List[str]) -> int:
        def traversal(s):
            cache = []
            for char in s:
                if not cache or cache[-1][0] != char:
                    cache.append(char)
                else:
                    cache[-1] += char
            return cache
        cache = traversal(s)

        ans = 0
        length = len(cache)
        for word in words:
            word_cache = traversal(word)
            i = 0
            j = 0
            word_length = len(word_cache)
            if word_length == length:
                while i<length:
                    if cache[i] == word_cache[j]:
                        i += 1
                        j += 1
                        continue
                    if cache[i][0] == word_cache[j][0] and len(cache[i])>=3 and len(cache[i])>=len(word_cache[j]):
                        i += 1
                        j += 1
                        continue
                    break
                if i == length and j == length:
                    ans += 1
        return ans

Explore

在算法中,确保字母组正确分割的关键在于使用一个循环来检查当前字符是否与上一个字符相同。如果相同,则将当前字符添加到当前字母组中;如果不同,则开始一个新的字母组。这种方法可以确保如 'aaa' 被正确分割为 ['aaa'] 而不是 ['a', 'aa']。在题解中,这一逻辑通过检查是否有前一个元素以及前一个元素的字符是否与当前字符相同来实现。

是的,根据题解的逻辑,要进行扩展操作,S中的字母组不仅需要比word中的相应字母组长,并且S中的字母组长度必须至少为3或者更多。这确保了只有当S中的字母组足够长时,才能通过添加相同字符来进行有效的扩展。如果word中的某个字母组比S中的相应字母组长,或者S中的字母组长度少于3而word中的字母组长度为3或更多,则这种扩展是不可能的。

在这种情况下,如果两个字母组的长度相同且字符相同,但长度小于3,这意味着无法进行扩展操作,但这并不影响两个字母组的匹配性。只要字符和长度都相同,就认为这两个字母组是匹配的。因此,在题解中,这种情况下仍然会视两个字母组为相匹配,不需要额外的处理。