【LeetCode每日一题】LeetCode 467:环绕字符串中唯一的子字符串

167 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
    }
};