博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
37:密码截取(回文串manacher算法)
阅读量:6268 次
发布时间:2019-06-22

本文共 2702 字,大约阅读时间需要 9 分钟。

题目描述:Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?

输入描述:输入一个字符串

输出描述:返回有效密码串的最大长度

输入例子:

ABBA

输出例子:

4

思路:最长回文串的长度

Manacher算法O(n)

因为对于偶回文,是需要从虚轴扩充,ab,ba,所以如下:

先把原字符串处理,都加上一个标记符,比如#(特殊字符任何都可以,对于计算结果不会有影响)

1221-->#1#2#2#1#

121-->#1#2#1#

按照处理后的字符串求它的最长回文串长度m,所以原始字符串最长子回文串的长度是m/2

 

变量:

1:PArra[] 存放回文半径:某个位置能扩充的回文半径的长度,例如 #1#2#2#1#,2位置PArra[3] = 4

2:int PR 能够扫到的最右的回文的位置   #1#2#1# 在位置3   PR = 6

3:int  index   当 PR更新的时候,index也要更新,指向当前最中心的位置   2中index=3

过程:

当要求位置i的时候的回文半径   分析如下:

1:第一种情况可以直接确定i的回文半径,PR不变,因为没有扩

  

 

 

2:第二种情况,i'的左边在index左边的左边,PR不用变化,(没有扩)也可以直接确定i位置的回文半径

3:第三种情况,i'的左边喝index的左边重复,需要从  “右大位置开始继续扩”

如何算复杂度:

如果扩成功了,说明,超过了目前的右大更新PR

4:第四种情况必须暴力扩

 

 

每一次检查的时候,要么失败,要么成功扩,只要成功扩了,PR必须更新,而且最长扩也就2n,所以“扩”的动作和PR高度相关;

通过变量优化这个算法的时候,一般这个复杂度和这个变量的增量有关。

 

1 import java.util.Scanner; 2  3 public class Main { 4  5     public static void main(String[] args) { 6         Scanner in  = new Scanner(System.in); 7         while(in.hasNextLine()) 8         { 9             String input = in.nextLine();10             char[] inputChar = input.toCharArray();11             StringBuilder sb = new StringBuilder();12             sb.append("#");13             //重新构造原来字符串14             for(int i = 0; i < input.length(); i++)15             {16                 sb.append(inputChar[i]);17                 sb.append("#");18             }19             int length = sb.length();20             char[] newChar = new char[length];//21             int pArray[] = new int[length];//记录以每个新的字符为中心的最大回文串长度22             newChar = sb.toString().toCharArray();23             int pr = 0;//当前回文串最右边的字符的下标,同时也是一个最大值,因为每一次针对i位置的回文串长度都可以利用上一步的结果,所以pr一直在增加24             int index = 0;//当前回文串的中间值下标 25             int count = 0;//记录最大回文26             for(int i = 0; i< newChar.length; i++)27             {28                 //如果i位置在当前pr之内(左边),可以不用扩充,直接得知i位置的最长回文串29                 if(pr > i)30                 {31                     //两个参数代表两种情况,一种i对应index的左边的i'的回文串最左在index最左的左边,一种是在右边32                     pArray[i] = Math.min(pArray[2*index - i], pr-i);33                 }34                 //否则初始化为135                 else36                 {37                     pArray[i] = 1;38                 }39                 //到位置i,往前往后判断是否是回文,不断更新pArray[i]40                 while(i-pArray[i] >= 0 && i+pArray[i] < newChar.length &&  newChar[i-pArray[i]] == newChar[i+pArray[i]])41                 {42                     pArray[i]++;43                 }44                 //更新最右下标和index45                 if(pr

 

 

转载于:https://www.cnblogs.com/newcoder/p/5815389.html

你可能感兴趣的文章
Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)
查看>>
Java-Spring-获取Request,Response对象
查看>>
opencv项目报错_pFirstBlock==pHead解决办法
查看>>
MySQL日志
查看>>
Oracle性能优化之Oracle里的执行计划
查看>>
电脑如何连接远程服务器?听语音
查看>>
使用Xcode 查看objective-C的汇编代码
查看>>
Vue.js——60分钟快速入门
查看>>
设计模式 - 模板方法模式(template method pattern) 具体解释
查看>>
mysql判断一个字符串是否包含某子串 【转】
查看>>
a bad dream
查看>>
FD_CLOEXEC用法及原因_转
查看>>
element UI 的学习一,路由跳转
查看>>
RabbitMQ三种Exchange模式(fanout,direct,topic)的性能比较
查看>>
Spring JavaBean属性值的注入方式( 属性注入, 特殊字符注入 <![CDATA[ 带有特殊字符的值 ]]> , 构造器注入 )...
查看>>
【Linux】Linux下统计当前文件夹下的文件个数、目录个数
查看>>
Hibernate_14_数据连接池的使用
查看>>
Codeforces Round #271 (Div. 2) D. Flowers (递推 预处理)
查看>>
jacky自问自答-java并发编程
查看>>
Struts2+JSON数据
查看>>