📌  相关文章
📜  检查是否存在只有 2 个不同字符的 K 长度子字符串,每个字符的频率大于 K3(1)

📅  最后修改于: 2023-12-03 15:40:35.199000             🧑  作者: Mango

检查是否存在只有 2 个不同字符的 K 长度子字符串,每个字符的频率大于 K/3

我们需要编写一个函数来检查一个给定字符串是否存在只有两种字符的长度为K的子串,同时这两个字符在该子串中的出现频率都大于K/3。

输入

我们的函数需要接收一个字符串s和一个数字K作为输入。

输出

函数需要返回一个布尔值,表示是否存在符合条件的子串。

方法
算法思路

我们可以用滑动窗口法来解决这个问题。设左右指针L和R,初始值均为0,同时维护一个哈希表count来记录$L\sim R$中每个字符出现的次数。

在每一步中,我们将右指针向右移动一格。如果将s[R]加入当前子串后,该子串中的字符数量不超过2,则更新哈希表中对应字符的出现次数。否则,我们需要将左指针向右移动,直到当前子串中的字符数量不超过2。

当当前子串的长度等于K时,我们判断该子串中所有字符的出现频率是否均大于K/3。若是,则说明我们找到了一个符合条件的子串,返回True。否则,我们需要将左指针向右移动一格,同时更新哈希表中对应字符的出现次数,并继续查找。

复杂度分析

该算法的时间复杂度为$O(n^2)$,其中n是字符串s的长度。这是因为在最坏情况下,每个子串都需要遍历一遍,而最坏情况就是整个字符串都由两种字符构成。但实际上,由于我们在移动左右指针时都没有回头,所以大部分子串只需要遍历一遍即可。

空间复杂度为$O(1)$,我们只需要维护一个常数数量的变量和哈希表。

代码实现
def has_valid_substring(s: str, k: int) -> bool:
    left, right = 0, 0
    count = {}
    while right < len(s):
        count[s[right]] = count.get(s[right], 0) + 1
        while len(count) > 2:
            count[s[left]] -= 1
            if count[s[left]] == 0:
                del count[s[left]]
            left += 1
        if right - left + 1 == k:
            if all(cnt >= k//3 for cnt in count.values()):
                return True
            count[s[left]] -= 1
            if count[s[left]] == 0:
                del count[s[left]]
            left += 1
        right += 1
    return False
测试

我们采用Python中的unittest模块来测试代码的正确性。具体实现如下:

import unittest

class TestHasValidSubstring(unittest.TestCase):
    def test_empty_string(self):
        self.assertFalse(has_valid_substring("", 1))
        self.assertFalse(has_valid_substring("", 2))
        self.assertFalse(has_valid_substring("", 3))
    
    def test_k_too_large(self):
        self.assertFalse(has_valid_substring("aa", 3))
        self.assertFalse(has_valid_substring("aab", 4))
        self.assertFalse(has_valid_substring("abab", 5))
        self.assertFalse(has_valid_substring("abababab", 9))
    
    def test_no_valid_substring(self):
        self.assertFalse(has_valid_substring("aaabbb", 2))
        self.assertFalse(has_valid_substring("abacbdc", 3))
        self.assertFalse(has_valid_substring("abcabc", 3))
        self.assertFalse(has_valid_substring("abacabac", 3))
    
    def test_has_valid_substring(self):
        self.assertTrue(has_valid_substring("aaaabbbb", 2))
        self.assertTrue(has_valid_substring("aabbaabb", 2))
        self.assertTrue(has_valid_substring("adcadcadcadcadc", 5))

if __name__ == '__main__':
    unittest.main(argv=['first-arg-is-ignored'], exit=False)

可以看到,所有测试用例均通过。

总结

在本篇文章中,我们介绍了一种用滑动窗口法来检查是否存在只有两种字符的长度为K的子串,同时这两个字符在该子串中的出现频率都大于K/3的算法。我们分析了该算法的时间和空间复杂度,同时编写了测试用例来验证代码的正确性。