求教,信息题目,给出一个字符串,求其不相同的子串个数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求教,信息题目,给出一个字符串,求其不相同的子串个数相关的知识,希望对你有一定的参考价值。

描述 Description
现在有一个字符串,请求出这个字符串不相同的子串个数。
YXY现在不会做,请你来帮忙……
输入格式 Input Format
第一行有一个正整数n,表示字符串的长度。
下面是这个长度为n的字符串,每行80个字符(最后一行可能少于80个)。
输出格式 Output Format
一个正整数,表示不相同子串的个数
样例输入 Sample Input
5

ababa

样例输出 Sample Output [复制数据]
9

时间限制 Time Limitation
每个测试点1s
注释 Hint
n <= 200000
字符串由小写英文字母组成
样例解释:
总共9个不相同子串:a, b, ab, ba, aba, bab, abab, baba, ababa

本人花了2天看懂了后缀数组及LCP的计算,不需赘述
请讲述求出后缀数组rank[]与height[]之后应该怎么做!

给出最高分200,回答后再追加50,望高手帮帮忙,诚心求教!
高手们,不知能不能这样想:
得出了所有的height[],相当于得出了一个序列
a1,a2,a3,...,an
然后统计:
n*(n+1) div 2 - sum( sum( min(ai..aj)j=i..n ) i=1..n)
但是,这样貌似还是需要n^2才能做,不好维护
是不是要利用height数组的特点呢?

这个规模暴力法是明显没希望了.
此题关键是数数的顺序. 假设你已经得到各后缀的lcp. 那么可以这样数:
用 s[i..n] 表示字符串 s 的第 i 位开始的后缀(这里下标从 1 开始).
假设已知 s[i+1..n] 的所有子串数目 u[i+1], 那么有
u[i] = u[i+1] + (n-i+1) - lcp[i]
显然 u[n] = 1
就是说从串末数起, 逐个往前添字符, 数子串数. u[1] 就是结果.追问

同学,这样似乎不对
对于SA[]数组
sa[i],sa[i+1]之间重复的后缀你的确统计了
但你没有统计sa[i]与sa[i+2]以及其他后缀之间的重复!

追答

Oh, sorry, 我错了.
看看下面这个算法行不行? 串长 n
(#A 表示集合 A 的元素个数)
g[l] := #r | LCP[r-1, r] == l, r=1..n-1
num = 0;
m = 0;
for l = n to 1

m += 1 - g[l];
num += m;

output(num);

追问

这样吧,麻烦你了,给你题目地址,你把它做出来然后告诉我,回来再给你追加50分!
www.tyvj.cn P1515 字串统计, 神题啊!

追答

测试过了, 这个算法可以. (tyvj 开放注册的吗??? 怎么不能注册?)

感觉你好像是用 pascal 的, 嗯 我不写 pascal 很久了, 所以还是用了 C

我找了两个后缀数组的代码, 都不能直接应付只有一个字符组成的串(如 aaaaaaaaaaaa), 所以末尾又添了一个特殊字符.

e... 有回复长度限制...只给关键代码了.

// 统计不同子串的个数
// note: 需保证 sizeof(int)>=4 (byte)
unsigned long CountSubStr(const char *st, int n)

int S[MAX_LEN], R[MAX_LEN], H[MAX_LEN], g[MAX_LEN];

suffixArray(st, n, S, R); // 求后缀数组
CalculateHeight(st, n, S, R, H); // 求 Height

for (int r=1; r0; l--)
m += 1 - g[l]; // 长 l 的子串的个数
cnt += m;


return cnt;


int main()

int n;
char st[MAX_LEN];

ReadData("in.txt", st, &n);
// st[n] = '$'; // 标示结尾, 也可用 '\0' 标示
n++;
st[n] = '\0'; // ...安全起见
unsigned long cnt = CountSubStr(st, n) - n;
OutputData("out.txt", cnt);

return 0;

参考技术A 考虑几各情况:
Case 1:abcabeabfabgabhabi dab de df
Case 2:abcabeabfabgabhabi dab dg
Case 3:abcabeabfabgabhabi dab di
从上例可以看出本题字符串的个数多于两个便不能使用贪心选择,因其不能导致最优解(你的面试题是不是还有什么可以简化题目的条件没有说出来?
如果没有简化条件而一定要求出最优解来,那我觉得只能用 "brute force "了。
参考技术B 太简单了 参考技术C 4864646

题目地址(647. 回文子串)

题目地址(647. 回文子串)

https://leetcode-cn.com/problems/palindromic-substrings/

题目描述

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

 

示例 1:

输入:s = "abc"
输出:3
解释:三个回文子串: "a", "b", "c"


示例 2:

输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

 

提示:

1 <= s.length <= 1000
s 由小写英文字母组成

关键点

  • 区间动态规划

代码

  • 语言支持:Java

Java Code:


class Solution 
    public int countSubstrings(String s) 
        
        char[] data = s.toCharArray();
        int[][] dp = new int[data.length][data.length];  // 是否回文数
        int sum = 0;
        for(int i=0;i<s.length();i++)
             dp[i][i] = 1;
             sum++;
        
        int n = s.length();
        for(int i = n-2; i >= 0; i--)
            for(int len = 1; len < (n - i); len++)
                dp[i][i+len] = (len==1 ||  dp[i+1][i+len-1] == 1) ? (data[i] ==  data[i+len] ? 1 :0) :0 ;
                sum += dp[i][i+len];
            
        
        return sum;
    


以上是关于求教,信息题目,给出一个字符串,求其不相同的子串个数的主要内容,如果未能解决你的问题,请参考以下文章

647. Palindromic Substrings

[LintCode] 最小子串覆盖 Java

2018.12.16-dtoj-1166-不相同的子串的个数

找出两个字符串中相同的子串,用java语言实现

HDU 6194 string string string(后缀自动机)

spoj8222 Substrings