LeetCode上面的一道算法题
我们定义了一个函数 countUniqueChars(s) 来统计字符串 s 中的唯一字符,并返回唯一字符的个数。例如:s = “LEETCODE” ,则其中 “L”, “T”,“C”,“O”,“D” 都是唯一字符,因为它们只出现一次,所以 countUniqueChars(s) = 5 。本题将会给你一个字符串 s ,我们需要返回 countUniqueChars(t) 的总和,其中 t 是 s 的子字符串。注意,某些子字符串可能是重复的,但你统计时也必须算上这些重复的子字符串(也就是说,你必须统计 s 的所有子字符串中的唯一字符)。由于答案可能非常大,请将结果 mod 10 ^ 9 + 7 后再返回。
解题思路
- 第一种解题思路:拿输入字符串对其每一个字符都去前后分别寻找相同字符,则有[j…i…k]这样的一个区间,前方未找到则j为-1,后方未找到则k为字符串长度。对于这样的一个区间一共存在多少个含有该字符的子集呢?
举个例子比如字符串ABCDE
对于A 它的区间为[-1…0…5],有以下情况A AB ABC ABCD ABCDE
对于B 它的区间为[-1…1…5],有以下情况B BC BCD BCDE / AB ABC ABCD ABCDE
对于C 它的区间为[-1…2…5],有以下情况C CD CDE / BC BCD BCDE / ABC ABCD ABCDE
我们可以发现对于给定区间[j…i…k]它含有唯一字符的子集为(i - j)*(k - i)即可理解为以该唯一字符下标为基准,左边含有的字符数乘以右边含有的字符数即为它们可以组合的只含有一个该字符的子集数
2. 第二种解题思路:对于字符串s,循环遍历得到它全部的子集,分别去统计每一个子集中包含的唯一字符数。
java代码实现
class Solution {
/**
* 最优解:前后搜索比较法
*/
public static int uniqueLetterString(String s) {
long num = 0;
int j, k;
for (int i = 0; i < s.length(); i++) {
j = i - 1;
k = i + 1;
while (j >= 0) {
if (s.charAt(i) == s.charAt(j)) {
break;
}
j--;
}
while (k < s.length()) {
if (s.charAt(i) == s.charAt(k)) {
break;
}
k++;
}
num += (i - j) * (k - i);
}
return (int)num % 1000000007;
}
/**
* 测试一半超时不通过:利用截取获取连续的子字符串,统计 s 的所有子字符串中的唯一字符
*/
public int uniqueLetterString2(String s) {
if(s == null){
return 0;
}
long num = 0;
for(int i = 0 ; i < s.length() ; i++ ){
for(int j = i + 1 ; j < s.length() + 1 ; j++){
String t = s.substring(i , j);
num += countUniqueChars(t);
}
}
return (int)num % 1000000007;
}
/**
* 统计字符串 s 中的唯一字符,并返回唯一字符的个数
*/
public int countUniqueChars(String t){
int num = 0;
Set<Integer> sameIndex = new TreeSet<>();
for(int i = 0; i < t.length(); i++){
if(sameIndex.contains(i) == true){
continue;
}
boolean sameFalg = false;
for(int j = i + 1; j < t.length(); j ++){
if(t.charAt(i) == t.charAt(j)){
sameIndex.add(j);
if(sameFalg == false) sameFalg = true;
}
}
if(sameFalg == false){
num ++;
}
}
return num;
}
}