描述
给你一个字符串 word ,返回 word 的所有子字符串中 元音的总数 ,元音是指 'a'、'e'、'i'、'o' 和 'u' 。
子字符串 是字符串中一个连续(非空)的字符序列。
注意:由于对 word 长度的限制比较宽松,答案可能超过有符号 32 位整数的范围。计算时需当心。
示例:
输入:word = "aba" 输出:6 解释: 所有子字符串是:"a"、"ab"、"aba"、"b"、"ba" 和 "a" 。
- "b" 中有 0 个元音
- "a"、"ab"、"ba" 和 "a" 每个都有 1 个元音
- "aba" 中有 2 个元音 因此,元音总数 = 0 + 1 + 1 + 1 + 1 + 2 = 6 。 提示:
1 <= word.length <= 10^5
word
由小写英文字母组成
思路
失败的思路
这道题,我一开始的思路是用 dp数组记录所有元字母所在的下标,然后不断的比较以 两个元字母下标为边界(两个下标一直是则只有一个字母)向两边扩展,直到遇到其他元字母。统计两个元字母左右两边的非元字母个数,再计算得到包括边界在内的元字母个数。左右两边相乘得到有多少子串个数,再乘以边界内元字母个数,得到 这两个下标所在扩展得到的所有字符串中元音字母总数,但是这种方法,在遇到最后一个基本全是元音字母的10000长度的数据时超时了。这种方法复杂度 由字母串中,元音字母个数决定,所有最坏能达到O(n^2),
class Solution {
public long countVowels(String word) {
int len = 0;
int[] dp =new int[word.length()];
char ch;
long sum = 0;
int count = 0;
int leftNum,rightNum;
for(int i = 0 ;i<word.length();i++){
ch = word.charAt(i);
if('a' == ch || 'e' == ch || 'i' == ch || 'o' == ch || 'u' == ch){
dp[len++] = i;
}
}
for(int i = 0; i< len;i++){
for(int j = i;j<len;j++){
count = j-i+1;
if(i == 0){
leftNum = dp[i];
}else{
leftNum = dp[i] - dp[i-1] - 1;
}
if(j == len - 1){
rightNum = word.length() - dp[j] -1;
}else {
rightNum = dp[j+1] - dp[j] -1;
}
sum+= (leftNum+1)*(rightNum+1) * count;
}
}
return sum;
}
}
改进后
后来思考了下,其实可以简化成O(n)算法,对于单个元字母而言,其实其只需要计算它在所有可能存在的子串的总数就可以了,不必考虑它所在的子串中可能含有的其他元字母,因为都只考虑自己,就不会产生重复计算某个字符中元字母个数的。 优化后代码
class Solution {
public long countVowels(String word) {
long sum = 0;
long len = word.length();
char ch;
for(int i = 0 ;i<len;i++){
ch = word.charAt(i);
if('a' == ch || 'e' == ch || 'i' == ch || 'o' == ch || 'u' == ch){
sum+= (i+1)*(len-i);// 每个字符只用考虑自己在所有字符串中可能中出现的次数即可,不必去思考一个字符串中有多少个字符
}
}
return sum;
}
}