【LeetCode】467. 环绕字符串中唯一的子字符串

467. 环绕字符串中唯一的子字符串


原题链接: 467. 环绕字符串中唯一的子字符串

题目大意

把字符串 s 看作是 “abcdefghijklmnopqrstuvwxyz” 的无限环绕字符串,所以 s 看起来是这样的:

“…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd…” .
现在给定另一个字符串 p 。返回 s 唯一p非空子串 的数量 。

示例:

输入: p = "a"
输出: 1
解释: 字符串 s 中只有一个"a"子字符。
输入: p = "cac"
输出: 2
解释: 字符串 s 中的字符串“cac”只有两个子串“a”、“c”。
输入: p = "zab"
输出: 6
解释: 在字符串 s 中有六个子串“z”、“a”、“b”、“za”、“ab”、“zab”。

数据范围:

1 <= p.length <= 105
p 由小写英文字母构成

思路

  1. 双指针算法,将字符串划分为几段,每段内字符“连续”,不同段之间字符不“连续”
    例如"cac"可分为"c",“a”, "c"共三段,"zab"可分为"zab"共一段。
  2. 题目要求唯一非空连续字符串。考虑唯一性,一个字符串可由其开头字符以及字符串长度唯一确定。本题只需求出每类字母(最多26类)开头的字符串的最大长度,用哈希表或数组存储与更新,最终累加即可得到答案。(若存在以’a’开头的长度为n的连续字符串,则由’a’开头的满足条件的连续字符串共有n个)。
    例如"c",“a”, "c"可得到cnt[‘a’]=1,cnt[‘c’]=1,累加得答案为2;
    例如"zab"可得到:
    cnt[‘z’]=3 (zab, za, z)
    cnt[‘a’]=2 (ab, a)
    cnt[‘b’]=1 (b)
    累加得答案为6.
  3. 若题目不要求唯一性,则直接对1中的每个连续分段累加,设每个连续分段的长度为k,则该分段可贡献1+2+…+k=k(k+1)/2个子字符串数量。
    例如"cac"可分为"c",“a”, "c"共三段:
    ‘c’:12/2=1
    ‘a’:1
    2/2=1
    ‘b’:1*2/2=1 共3个

代码

class Solution {
public:
    int findSubstringInWraproundString(string p) {
        unordered_map<char, int> cnt;
        for(int i = 0; i < p.size(); ){
        	// 分段,j用来指向下一段的开头字符
            int j = i + 1;
            while(j < p.size() && p[j] - p[j - 1] == 1 || p[j] == 'a' && p[j - 1] == 'z') j ++; // 连续字符串
            // 更新各类字母开头的连续字符串的最大长度
            while(i < j) cnt[p[i]] = max(cnt[p[i]], j - i), i ++ ;
        }
        int res = 0;
        for(auto [k, v] : cnt){
            res += v;
        }

        return res;
    }
};

复杂度

时间复杂度:双指针需要 O ( n ) O(n) O(n)
空间复杂度:哈希表存26个字母开头的最大长度,仅需要常数的额外空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值