寻找p有多少个非空子串在s中出现(s为a~z字符的循环)

本文介绍了一种算法,用于计算一个特定字符串在无限循环的英文字母字符串中的所有非空子串数量。通过分析字符串特性,文章提供了一个高效的解决方案,并给出了两个不同版本的Java代码实现。

Unique Substrings in Wraparound String

问题:

Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz", so s will look like this: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....".

Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s.

Note: p consists of only lowercase English letters and the size of p might be over 10000.

Example 1:

Input: "a"
Output: 1
Explanation: Only the substring "a" of string "a" is in the string  s.

Example 2:

Input: "cac"
Output: 2
Explanation: There are two substrings "a", "c" of string "cac" in the string s.

Example 3:

Input: "zab"
Output: 6
Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.

解决:

【题意】

字符串s是小写字母"abcdefghijklmnopqrstuvwxyz"的无限循环,s看起来像这样:"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...."

现在我们有另外一个字符串p。你需要寻找p有多少个非空子串在s中出现。输入p,你需要输出s中有多少个不同的p的非空子串。

① 由于封装字符串是26个字符按顺序无限循环组成的,那么满足题意的p的子字符串要么是单一的字符,要么是按字母顺序的子字符串。

我们看abcd这个字符串,以d结尾的子字符串有abcd, bcd, cd, d,那么我们可以发现bcd或者cd这些以d结尾的字符串的子字符串都包含在abcd中,那么我们知道以某个字符结束的最大字符串包含其他以该字符结束的字符串的所有子字符串。那么题目就可以转换为分别求出以每个字符(a-z)为结束字符的最长连续字符串就行了,我们用一个数组count记录下来,最后在求出数组count的所有数字之和就是我们要的结果了。

class Solution { //18ms
    public int findSubstringInWraproundString(String p) {
        if (p == null || p.length() == 0) return 0;
        int[] count = new int[26];//记录以每个字符为结尾的字符串的长度
        int len = 0;//记录子串的长度
        char[] pchar = p.toCharArray();
        for (int i = 0;i < pchar.length;i ++){
            if (i > 0 && (pchar[i] == pchar[i - 1] + 1 || pchar[i - 1] - pchar[i] == 25)){
                len ++;
            }else {
                len = 1;
            }
            count[pchar[i] - 'a'] = Math.max(count[pchar[i] - 'a'],len);
        }
        int res = 0;
        for (int i = 0;i < count.length;i ++){
            res += count[i];
        }
        return res;
    }
}

② 进化版

class Solution { //17ms
    public int findSubstringInWraproundString(String p) {
        if (p == null || p.length() == 0){
            return 0;
        }
        int[] count = new int[26];
        int res = 0;
        int len = 0;
        char[] pchar = p.toCharArray();
        for (int i = 0;i < pchar.length;i ++){
            int cur = pchar[i] - 'a';
            if (i > 0 && pchar[i - 1] != (cur + 26 - 1) % 26 + 'a'){
                len = 0;
            }
            if (++ len > count[cur]){
                res += len - count[cur];
                count[cur] = len;
            }
        }
        return res;
    }
}

转载于:https://my.oschina.net/liyurong/blog/1603308

题目 2866: 改写 aoi2025xx 题目描述 小可可在学习字符算法! 一个长度为 m 的字符 r 是回文的,当且仅当 ri=rm+1-i 对所有 1≤i≤m 均成立。例如 aaabaaa, abba 都是回文,但 aaabaa 不是回文。 给定一个字符 s,把 s 分成若干个空子段,使得每一个子段都不是回文的, 同时最大化划分出的子段数目,请你输出最大划分数,无解则输出 -1。 子段的定义为: 一个字符保留任意连续字符后形成的字符。 由于字符 s 可能很长,我们将会按照 c, len 的形式给出整个字符, 具体含义见输入格式。 输入格式 第一行一个整数 T 表示数据组数。 对于每组数据,第一行输入一个数 n 表示极长连续相同字母段的数量。 接下来 n 行中,第 i 行包括一个 a 到 z 之间的小写字母 ci 和一个整数 leni,分别 表示该段的数字以及长度,保证对于所有大于 1 的 i,均满足 ci-1≠ci。 输出格式 输出共 T 行,每行输出一个整数,表示最大的划分段数,若无解则输出 -1。 样例输入1 5 2 b 1 a 1 1 b 4 7 a 2 b 2 a 1 b 2 a 1 b 1 a 1 5 a 2 b 1 a 2 c 2 a 2 3 a 1 b 1 a 1 样例输出1 1 -1 4 3 -1 注释说明 样例解释 样例1中,对于第一组数据,序列为 ba,且只存在 ba 这一种划分方案,因此答案为 1。 对于第二组数据,序列为 bbbb,显然没有合法方案。 对于第三组数据,序列为 aabbabbaba,存在一种划分出四段的方案:aabb,ab,ba,ba, 可以证明没有答案更优的划分方式。 对于第四组数据,序列为 aabaaccaa,存在一种划分出三段的方案: aaba,ac,caa, 可以证明没有答案更优的划分方式。 对于第五组数据,序列为 aba,容易发现无论怎么划分,都至少有一个回文,所以无解。 数据范围 对于100%的数据,1≤T≤10,1≤n≤105,1≤leni≤109。
05-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值