标签:int 个数 length ++ 算法 pArr charArr 回文
问题
- 给定一个字符串 s ,请计算这个字符串中有多少个回文子字符串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
解决
//1、遍历统计(双指针),时间复杂度O(n^3)
class Solution {
public int countSubstrings(String s) {
int low,heigh;
int count=0;
for(int i=0;i<s.length();i++){
low=i;
for(int j=i;j<s.length();j++){
heigh=j;
if(isVaild(s,low,heigh)){
count++;
}
}
}
return count;
}
public boolean isVaild(String s,int l,int r){
while(l<r){
if(s.charAt(l)!=s.charAt(r))
{
return false;
}
l++; //记住判断以后要移位
r--;
}
return true;
}
}
// 2、遍历统计(中心拓展),时间复杂度O(n^2)
class Solution {
public int countSubstrings(String s) {
int n = s.length(), ans = 0;
for (int i = 0; i < 2 * n - 1; ++i) {
int l = i / 2, r = i / 2 + i % 2; //从回文中心开始拓展,分奇偶。一样是遍历所有子串
while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {
--l;
++r;
++ans;
}
}
return ans;
}
}
//3、Manacher算法,时间复杂度O(nlogn)
class Solution {
public int countSubstrings(String s) {
//处理字符串
int n = s.length();
StringBuffer t = new StringBuffer("$#");
for (int i = 0; i < n; ++i) {
t.append(s.charAt(i));
t.append('#');
}
n = t.length();
t.append('!');
//创建对应的最大回文半径数组
int[] f = new int[n];
int iMax = 0, rMax = 0, ans = 0; //回文中心,回文半径,子回文数
for (int i = 1; i < n; ++i) { //每个回文中心的回文半径
// 初始化 f[i],要么是1,要么是
f[i] = i <= rMax ? Math.min(rMax - i + 1, f[2 * iMax - i]) : 1;
// 中心拓展
while (t.charAt(i + f[i]) == t.charAt(i - f[i])) {
++f[i];
}
// 动态维护 iMax 和 rMax
if (i + f[i] - 1 > rMax) {
iMax = i;
rMax = i + f[i] - 1;
}
// 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
ans += f[i] / 2;
}
return ans;
}
}
//4、Manacher算法修整版
class Solution{
public static char[] manacherString(String str) {
char[] charArr = str.toCharArray();
char[] res = new char[str.length() * 2 + 1];
int index = 0;
for (int i = 0; i != res.length; i++) {
res[i] = (i & 1) == 0 ? '#' : charArr[index++]; //让字符串中的字符于#交替存储
}
return res; //返回处理好的字符数组
}
public static int countSubstrings(String str) {
if (str == null || str.length() == 0) {
return 0;
}
char[] charArr = manacherString(str); //项原始字符串添加虚拟(辅助)字符'#'
int[] pArr = new int[charArr.length]; //用来存储charArr每一位对应的最大回文长度
int C = -1; //回文中心
int R = -1; //最大回文半径
int sum=0;
for (int i = 0; i != charArr.length; i++) { //以数组中每个字符为中心
pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1; //当i被R包主时,pArr的取值
while (i + pArr[i] < charArr.length && i - pArr[i] > -1) { //当前位置+/-最大半径数都在charArr数组长度里
if (charArr[i + pArr[i]] == charArr[i - pArr[i]]) //暴力扩最大半径
pArr[i]++;
else {
break;
}
}
if (i + pArr[i] > R) { //如果i的最大半径大于R
R = i + pArr[i]; //将R扩到当前位置+最大半径
C = i; //C也移到i位置
}
sum+=pArr[i]>>1; //使用位运算更快
}
return sum;
}
}
标签:int,个数,length,++,算法,pArr,charArr,回文 来源: https://www.cnblogs.com/zhangsanM/p/16545155.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。