持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情。
LeetCode每日一题打卡专栏正式启动!不出意外将日更LeetCode的每日一题,敬请期待。
个人博客链接:bbstudy.net/
5.26:环绕字符串中唯一的子字符串
LeetCode 467,点击题目可直接跳转至LeetCode
把字符串 s 看作 "abcdefghijklmnopqrstuvwxyz" 的无限环绕字符串,所以 s 看起来是这样的:
-
"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...."。现在给定另一个字符串
p。返回s中 不同 的p的 非空子串 的数量 。
示例 1:
输入:p = "a"
输出:1
解释:字符串 s 中只有 p 的一个 "a" 子字符。
示例 2:
输入:p = "cac"
输出:2
解释:字符串 s 中只有 p 的两个子串 ("a", "c") 。
示例 3:
输入:p = "zab"
输出:6
解释:在字符串 s 中有 p 的六个子串 ("z", "a", "b", "za", "ab", "zab") 。
提示:
- 1 <= p.length <= 105
p由小写英文字母组成
题目分析: 这个题目的核心思想是dp
首先要明白子串的概念:子串为连续且非空的字符串。定义dp[p[i]]表示以p[i]结尾的子串有dp[p[i]]个,在遍历的过程中,如果当前字符是上一个字符的下一个字母,那么便将k加一,如果不是,那么就把k重新置为1。然后用k去更新dp[p[i]]的最大值,表示以p[i]结尾的字符串最大长度为多少。举个例子,如果需要遍历的字符串为abcd,遍历到abc的时候dp[c]=3,那么dp[d]=4。增加的以d结尾的四个字符串分别为abcd,bcd,cd,d。其余的同理。
最后要把所有的子串个数加起来,只需要遍历26个字母即可。每次遍历加上以当前字母结尾的子串的个数就是最终答案。
注意:代码中先加26再对26取模是为了避免负数对结果产生影响,因为字符串中有环出现,故这样处理。
至于为什么dp[p[i]]要取k和dp[p[i]]中的最大值,这是因为如果当前遍历的字符之前已经出现过的话,那么以当前字符结尾的最大长度要在之前的dp[p[i]]中和现在的k中取最大值,否则就会出现错误。
C++代码:
class Solution {
public:
int findSubstringInWraproundString(string p) {
vector<int>dp(26);
int ls=p.size();
int k=1;
for(int i=0;i<ls;++i){
if(i&&(p[i]-p[i-1]+26)%26==1)
++k;
else
k=1;
dp[p[i]-'a']=max(dp[p[i]-'a'],k);
}
int ans=0;
for(int i=0;i<26;++i)
ans+=dp[i];
return ans;
}
};