Skip to content

Latest commit

 

History

History
217 lines (173 loc) · 5.44 KB

File metadata and controls

217 lines (173 loc) · 5.44 KB
comments difficulty edit_url rating source tags
true
简单
1248
第 53 场双周赛 Q1
哈希表
字符串
计数
滑动窗口

English Version

题目描述

如果一个字符串不含有任何重复字符,我们称这个字符串为  字符串。

给你一个字符串 s ,请你返回 s 中长度为 3 的 好子字符串 的数量。

注意,如果相同的好子字符串出现多次,每一次都应该被记入答案之中。

子字符串 是一个字符串中连续的字符序列。

 

示例 1:

输入:s = "xyzzaz"
输出:1
解释:总共有 4 个长度为 3 的子字符串:"xyz","yzz","zza" 和 "zaz" 。
唯一的长度为 3 的好子字符串是 "xyz" 。

示例 2:

输入:s = "aababcabc"
输出:4
解释:总共有 7 个长度为 3 的子字符串:"aab","aba","bab","abc","bca","cab" 和 "abc" 。
好子字符串包括 "abc","bca","cab" 和 "abc" 。

 

提示:

  • 1 <= s.length <= 100
  • s​​​​​​ 只包含小写英文字母。

解法

方法一:滑动窗口

我们可以维护一个滑动窗口,使得窗口内的字符不重复。初始时,我们用一个长度为 $26$ 的二进制整数 $\textit{mask}$ 表示窗口内的字符,其中第 $i$ 位为 $1$ 表示字符 $i$ 在窗口内出现过,否则表示字符 $i$ 在窗口内没有出现过。

然后,我们遍历字符串 $s$,对于每一个位置 $r$,如果 $\textit{s}[r]$ 在窗口内出现过,我们需要将窗口的左边界 $l$ 右移,直到窗口内不再有重复的字符。在这之后,我们将 $\textit{s}[r]$ 加入窗口内,此时如果窗口的长度大于等于 $3$,那么我们就找到了一个以 $\textit{s}[r]$ 结尾的长度为 $3$ 的好子字符串。

遍历结束后,我们就找到了所有的好子字符串的数量。

时间复杂度 $O(n)$,其中 $n$ 为字符串 $s$ 的长度。空间复杂度 $O(1)$

该解法可以拓展到长度为 $k$ 的好子字符串的数量。

Python3

class Solution:
    def countGoodSubstrings(self, s: str) -> int:
        ans = mask = l = 0
        for r, x in enumerate(map(lambda c: ord(c) - 97, s)):
            while mask >> x & 1:
                y = ord(s[l]) - 97
                mask ^= 1 << y
                l += 1
            mask |= 1 << x
            ans += int(r - l + 1 >= 3)
        return ans

Java

class Solution {
    public int countGoodSubstrings(String s) {
        int ans = 0;
        int n = s.length();
        for (int l = 0, r = 0, mask = 0; r < n; ++r) {
            int x = s.charAt(r) - 'a';
            while ((mask >> x & 1) == 1) {
                int y = s.charAt(l++) - 'a';
                mask ^= 1 << y;
            }
            mask |= 1 << x;
            ans += r - l + 1 >= 3 ? 1 : 0;
        }
        return ans;
    }
}

C++

class Solution {
public:
    int countGoodSubstrings(string s) {
        int ans = 0;
        int n = s.length();
        for (int l = 0, r = 0, mask = 0; r < n; ++r) {
            int x = s[r] - 'a';
            while ((mask >> x & 1) == 1) {
                int y = s[l++] - 'a';
                mask ^= 1 << y;
            }
            mask |= 1 << x;
            ans += r - l + 1 >= 3 ? 1 : 0;
        }
        return ans;
    }
};

Go

func countGoodSubstrings(s string) (ans int) {
	mask, l := 0, 0
	for r, c := range s {
		x := int(c - 'a')
		for (mask>>x)&1 == 1 {
			y := int(s[l] - 'a')
			l++
			mask ^= 1 << y
		}
		mask |= 1 << x
		if r-l+1 >= 3 {
			ans++
		}
	}
	return
}

TypeScript

function countGoodSubstrings(s: string): number {
    let ans = 0;
    const n = s.length;
    for (let l = 0, r = 0, mask = 0; r < n; ++r) {
        const x = s.charCodeAt(r) - 'a'.charCodeAt(0);
        while ((mask >> x) & 1) {
            const y = s.charCodeAt(l++) - 'a'.charCodeAt(0);
            mask ^= 1 << y;
        }
        mask |= 1 << x;
        ans += r - l + 1 >= 3 ? 1 : 0;
    }
    return ans;
}

PHP

class Solution {
    /**
     * @param String $s
     * @return Integer
     */
    function countGoodSubstrings($s) {
        $ans = 0;
        $n = strlen($s);
        $l = 0;
        $r = 0;
        $mask = 0;

        while ($r < $n) {
            $x = ord($s[$r]) - ord('a');
            while (($mask >> $x) & 1) {
                $y = ord($s[$l++]) - ord('a');
                $mask ^= 1 << $y;
            }
            $mask |= 1 << $x;
            if ($r - $l + 1 >= 3) {
                $ans++;
            }
            $r++;
        }

        return $ans;
    }
}