惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
T
The Blog of Author Tim Ferriss
U
Unit 42
Microsoft Security Blog
Microsoft Security Blog
WordPress大学
WordPress大学
Vercel News
Vercel News
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
I
InfoQ
Y
Y Combinator Blog
F
Full Disclosure
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
Google Developers Blog
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
博客园 - 叶小钗
S
SegmentFault 最新的问题
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
F
Fortinet All Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
Hugging Face - Blog
Hugging Face - Blog
T
Threatpost
GbyAI
GbyAI
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
L
LangChain Blog
T
Tenable Blog
C
Cisco Blogs
T
Threat Research - Cisco Blogs
Google Online Security Blog
Google Online Security Blog

博客园 - Grandyang

[LeetCode] 1372. Longest ZigZag Path in a Binary Tree 二叉树中的最长交错路径 [LeetCode] 1371. Find the Longest Substring Containing Vowels in Even Counts 每个元音包含偶数次的最长子字符串 [LeetCode] 1370. Increasing Decreasing String 上升下降字符串 [LeetCode] 1368. Minimum Cost to Make at Least One Valid Path in a Grid 使网格图至少有一条有效路径的最小代价 [LeetCode] 1367. Linked List in Binary Tree 二叉树中的链表 [LeetCode] 1366. Rank Teams by Votes 通过投票对团队排名 [LeetCode] 1365. How Many Numbers Are Smaller Than the Current Number 有多少小于当前数字的数字 [LeetCode] 1363. Largest Multiple of Three 形成三的最大倍数 [LeetCode] 1362. Closest Divisors 最接近的因数 [LeetCode] 1361. Validate Binary Tree Nodes 验证二叉树 [LeetCode] 1360. Number of Days Between Two Dates 日期之间隔几天 [LeetCode] 1359. Count All Valid Pickup and Delivery Options 有效的快递序列数目 [LeetCode] 1357. Apply Discount Every n Orders 每隔n个顾客打折 [LeetCode] 1356. Sort Integers by The Number of 1 Bits 根据数字二进制下1 的数目排序 [LeetCode] 1354. Construct Target Array With Multiple Sums 多次求和构造目标数组 [LeetCode] 1353. Maximum Number of Events That Can Be Attended 最多可以参加的会议数目 [LeetCode] 1352. Product of the Last K Numbers 最后 K 个数的乘积 [LeetCode] 1351. Count Negative Numbers in a Sorted Matrix 统计有序矩阵中的负数 [LeetCode] 1349. Maximum Students Taking Exam 参加考试的最大学生数
[LeetCode] 1358. Number of Substrings Containing All Three Characters 包含所有三种字符的子字符串数目
Grandyang · 2023-10-30 · via 博客园 - Grandyang

Given a string s consisting only of characters ab and c.

Return the number of substrings containing at least one occurrence of all these characters ab and c.

Example 1:

Input: s = "abcabc"
Output: 10
Explanation: The substrings containing at least one occurrence of the characters ab and c are "abc", "abca", "abcab", "abcabc", "bca", "bcab", "bcabc", "cab", "cabc" and "abc" (again).

Example 2:

Input: s = "aaacb"
Output: 3
Explanation: The substrings containing at least one occurrence of the characters ab and c are "aaacb", "aacb" and "acb".

Example 3:

Input: s = "abc"
Output: 1

Constraints:

  • 3 <= s.length <= 5 x 10^4
  • s only consists of ab or *c *characters.

这道题给了一个只有 a,b,c 三个字母构成的字符串s,现在让找出三个字母均至少出现一次的子串的个数。一般玩字符串的题目无外乎就是滑动窗口 Sliding Window 和动态规划 Dynamic Programming 用的比较多。这道题不太适合用 DP,状态转移方程不太好找。来看看能否用滑动窗口来做吧,如果题目让求的是三个字母都只出现一次的话,想必大家应该都没啥问题,这里的至少出现一次也算是个难点了,就拿例子1来分析,当滑动窗口套住第一个 abc 的时候,此时除了其本身是符合要求的,其后面的每个字母都可以跟窗口里的字母组成符合要求的子串,组成 abca, abcab, abcabc,这样统计的个数世纪上就是 n-i,n是原字符串s的总长度,i是当前滑动窗口的右边界,整个步骤如下所示:

[a b c] a b c
abc, abca, abcab, ababc

a [b c a] b c
bca, bcab, bcabc

a b [c a b] c
cab, cabc

a b c [a b c]
abc

通过上面这种计数方法,我们就可以不重复的统计出所有满足情况的子串。当然这种统计方法也不是唯一的,比如 lee215 大神用的就是另一种统计方法,其主要是统计左边界前面的字母个数,也是可以的,参见代码如下:

解法一:

class Solution {
public:
    int numberOfSubstrings(string s) {
        int res = 0, n = s.size(), left = 0;
        vector<int> cnt(3);
        for (int i = 0; i < n; ++i) {
            ++cnt[s[i] - 'a'];
            while (cnt[0] && cnt[1] && cnt[2]) {
                res += n - i;
                --cnt[s[left++] - 'a'];
            }
        }
        return res;
    }
};

再来看一种更加简洁的解法,这里记录 a,b,c 最后出现的位置,初始化为-1,然后每次取其中最小的数字,再加上1就是当前范围内符合要求的子串的个数。当最小值为初始的 -1 时,说明某个字母没有出现过,则加上0不影响结果,而当最小的大于等于0了,说明每个字母都出现过了,而最小的那个值就相当于滑动窗口的左边界,其实还是统计左边界前面的字母个数,参见计数过程如下:

a b c a b c

i = 0, [0, -1, -1], min = -1
i = 1, [0, 1, -1], min = -1
i = 2, [0, 1, 2], min = 0 -> abc
i = 3, [3, 1, 2], min = 1 -> abca, bca
i = 4, [3, 4, 2], min = 2 -> abcab, bcab, cab
i = 5, [3, 4, 5], min = 3 -> abcabc, bcabc, cabc, abc

解法二:

class Solution {
public:
    int numberOfSubstrings(string s) {
        int res = 0, n = s.size();
        vector<int> last(3, -1);
        for (int i = 0; i < n; ++i) {
            last[s[i] - 'a'] = i;
            res += 1 + min({last[0], last[1], last[2]});
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1358

类似题目:

Vowels of All Substrings

参考资料:

https://leetcode.com/problems/number-of-substrings-containing-all-three-characters

https://leetcode.com/problems/number-of-substrings-containing-all-three-characters/solutions/516977/java-c-python-easy-and-concise/

https://leetcode.com/problems/number-of-substrings-containing-all-three-characters/solutions/3459766/explained-w-images-made-easy-c/

LeetCode All in One 题目讲解汇总(持续更新中...)