方法1:自己想的,当时看到就想到了可以看组合数,然后根据有没有剩余元素加1和不加1,因为是字母,所以我不想用hashmap,而是用的数组,类似于计数排序的思想,速度非常快,打败了百分之百
class Solution {
public int longestPalindrome(String s) {
int res=0;
int[] nums=new int['z'-'A'+1];
char[] ch=s.toCharArray();
for(char c:ch){
nums[c-'A']++;
}
for(int i=0;i<nums.length;i++){
res+=nums[i]/2;
}
res=res*2;
if(res!=ch.length){
res++;
}
return res;
}
}
同样的方法不同的代码:
class Solution {
public int longestPalindrome(String s) {
int[] nums=new int[s.length()];
char[] ch=s.toCharArray();
for(int i=0;i<ch.length;i++){
nums[i]=ch[i]-'a';
}
Arrays.sort(nums);
int zuhe=0;
for(int i=0,j=1;j<nums.length;){
if(nums[i]==nums[j]){
zuhe++;
i=i+2;
j=j+2;
}else{
i++;
j++;
}
}
zuhe=zuhe*2;
if(zuhe!=nums.length){
zuhe++;
}
return zuhe;
}
}
leetcode125 验证回文
方法1:
class Solution {
public boolean isPalindrome(String s) {
String a=s.replaceAll("[^0-9A-Za-z]","").toLowerCase();
return (new StringBuilder(a).reverse()+"").equals(a);
}
}
方法2:
class Solution {
public boolean isPalindrome(String s) {
char[] arr=s.replaceAll("[^0-9A-Za-z]","").toLowerCase().toCharArray();
int i=0;
int j=arr.length-1;
while(i<j){
if(arr[i]==arr[j]){
i++;
j--;
continue;
}else{
return false;
}
}
return true;
}
}
leetcode5
方法1:左神交的暴力法(非直接暴力,而是添加东西,中心扩回文),我自己写的,所以有点丑。。
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==1||s.length()==0){
return s;
}
char[] ch=s.toCharArray();
char[] ch1=new char[ch.length*2+1];
for(int i=0,k=0;i<ch.length*2+1;i++){
if(i%2==0) ch1[i]='.';
else ch1[i]=ch[k++];
}
int max=1;
int index=0;
for(int i=0;i<ch1.length;i++){
int max1=1;
int k=i-1;
int j=i+1;
while(k>=0&&j<ch1.length){
if(ch1[k--]==ch1[j++]){
max1+=2;
}else{
break;
}
}
if(max1>max){
index=i;
}
max=Math.max(max,max1);
}
int start=index-(max-1)/2;
int end=index+(max-1)/2;
String s1="";
for(int i=start;i<=end;i++){
s1+=ch1[i];
}
return s1.replace(".","");
}
}
方法2:暴力法改动态规划(算吧。。)
其实就是从长度为1的开始找,1和2是直接算的,其他s(i,j)都是根据s(i+1,j-1),算的
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==1||s.length()==0){
return s;
}
char[] ch=s.toCharArray();
boolean[][] help=new boolean[s.length()][s.length()];
String maxstr="";
for(int len=1;len<=s.length();len++){
for(int start=0;start<s.length();start++){
int end=start+len-1;
if(end>=s.length()){
break;
}
help[start][end]=(len==1||len==2||help[start+1][end-1])&&s.charAt(start)==s.charAt(end);
if(help[start][end]){
maxstr=s.substring(start,end+1);
}
}
}
return maxstr;
}
}
方法3:运用最长公共子串,先逆序,然后对比,但是注意是当前的翻转过来的
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==1||s.length()==0){
return s;
}
String s1=new StringBuilder(s).reverse().toString();
int max=0;
int index=0;
String res="";
int[][] help=new int[s.length()][s.length()];
for(int i=0;i<s.length();i++){
for(int j=0;j<s1.length();j++){
if(s.charAt(i)==s1.charAt(j)){
if(i==0||j==0){
help[i][j]=1;
}else{
help[i][j]=help[i-1][j-1]+1;
}
}
if(help[i][j]>max&&((s.length()-i-1)==(j-help[i][j]+1))){
max=help[i][j];
index=i;
}
}
}
return s.substring(index - max + 1, index + 1);
}
}
这个速度贼慢看图:
leetcode718 最长子序列
方法1:动态规划(暴力递归是好写,但是真的好改)
class Solution {
public int findLength(int[] A, int[] B) {
int[][] help=new int[A.length][B.length];
int max=0;
for(int i=0;i<A.length;i++){
for(int j=0;j<B.length;j++){
if(A[i]==B[j]){
if(i==0||j==0){
help[i][j]=1;
}else{
help[i][j]=help[i-1][j-1]+1;
}
}
max=Math.max(max,help[i][j]);
}
}
return max;
}
}
方法2
class Solution {
public int findLength(int[] A, int[] B) {
//也不知道为啥我写了这么多,下面贴了大神的,爱,我不想看,我怕伤心
//首先方法的核心是利口的大神(看到他的滑动二字我就明白了,就来了)
//首先就是看A,B哪个大,相等那就都行
int a=A.length;//让a为大的
int b=B.length;
if(a<b){
int temp=a;
a=b;
b=temp;
}
int k=1-b;//用来区分三个阶段的
int start=0;
int end=0;
int max=0;
int max1=0;
while(k<a){
//第一个阶段,小的进来
if(k<0){
max1=max(start,end,A,B,k,b-1);
max=Math.max(max1, max);
end++;
k++;
}else if(k<a-b){
max1=max(start,end,A,B,k,b-1);
max=Math.max(max1, max);
end++;
start++;
k++;
}else{
max1=max(start,end,A,B,k,b-1);
max=Math.max(max1, max);
start++;
k++;
}
}
return max;
}
public int max(int i,int j,int[] A,int[] B,int k,int b){
int max=0;
int count=0;
int len=j-i;
int h=b-len;
int h1=0;
for(int m=i;m<=j;m++){
if(k<=0&&A[m]==B[h++]){
count++;
max=Math.max(count,max);
}else if(k>0&&A[m]==B[h1++]){
count++;
max=Math.max(count,max);
}else{
count=0;
}
}
return max;
}
}
大神如下:
public int findLength(int[] A, int[] B) {
return A.length < B.length ? findMax(A, B) : findMax(B, A);
}
int findMax(int[] A, int[] B) {
int max = 0;
int an = A.length, bn = B.length;
for(int len=1; len <= an; len++) {
max = Math.max(max, maxLen(A, 0, B, bn - len, len));
}
for(int j=bn-an; j >= 0;j--) {
max = Math.max(max, maxLen(A, 0, B, j, an));
}
for(int i=1;i<an;i++) {
max = Math.max(max, maxLen(A, i, B, 0, an - i));
}
return max;
}
int maxLen(int[] a, int i, int[] b, int j, int len) {
int count = 0, max = 0;
for(int k = 0; k < len; k++) {
if(a[i+k] == b[j+k]) {
count++;
} else if(count > 0) {
max = Math.max(max, count);
count = 0;
}
}
return count > 0 ? Math.max(max, count) : max;
}
作者:stg
链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/wu-li-jie-fa-by-stg-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法3:从中间按奇数偶数扩展(很好,我自己写的话不可能这么写,代码很精简)
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==1||s.length()==0){
return s;
}
int start=0;
int end=0;
for(int i=0;i<s.length()-1;i++){
//下面这里,人家就能放到一起处理(虽然很容易想到,但是我真没想到),还有就是放到这一个循环,处理了这两件事,这个东西我也没想到,真的和别人差距还是有的。而且很大,多练把
int len1=kuo(s,i,i);
int len2=kuo(s,i,i+1);
int len=Math.max(len1,len2);
if(len>end-start){
//下面这个也是个点,(i-1)/2的妙用
start=i-(len-1)/2;
end=i+len/2;
}
}
return s.substring(start,end+1);
}
public int kuo(String s,int i,int j){
while(i>=0&&j<s.length()&&s.charAt(i)==s.charAt(j)){
i--;
j++;
}
return j-i-1;
}
}
代码看下面的把,注释看上面的
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==0){
return s;
}
int start=0;
int end=0;
for(int i=0;i<s.length()-1;i++){
int len1=expand(i,i,s);
int len2=expand(i,i+1,s);
int len=Math.max(len1,len2);
if(len>end-start){
start=i-(len-1)/2;
end=i+len/2;
}
}
return s.substring(start,end+1);
}
public int expand(int left,int right,String s){
while(left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
left--;
right++;
}
return right-1-left;
}
}
马拉车算法(Manacher):其实和暴力搜索(填充字符串的暴力搜索),只有一个不同,就是从哪里开始扩,对于暴力搜索当然是当前点,但是马拉车不是,他不一定是当前点,他记录了一些信息,这些信息可以帮助他直接跳过某些位置,接下来从两个方面(思想一个,就是分类不同以及清晰度细粒程度不同)
首先:最少的代码,分最少的情况(当然内心还是要分多一些,代码上合并了)
Runtime: 11 ms, faster than 60.20% of Java online submissions for Longest Palindromic Substring
正确的版本,包括center和right我挨个跟的,记住有的时候这个程序可以通过,但是right可能是不对的,但是就是可以通过,神奇不,所以一定要保证right的正确性,因为有的时候他的变种要用到
class Solution {
public String longestPalindrome(String s) {
//进行字符串的填充,解决奇偶的问题
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
s=sb.toString();
//Manacher 开始
int rightb=-1;//定义右边界
int center=-1;//中心点 伴随右边界
int[] help=new int[s.length()];//存储每个点的回文半径
for(int i=0;i<s.length();i++){
if(i<rightb){
help[i]=Math.min(rightb-i,help[2*center-i]);//这个可以当公式背下来,2*center-i
}
int left=i-help[i];
int right=i+help[i];
while(left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
left--;
right++;
}
help[i]=right-i-1;//不要忘了-1 因为right多算了一个位置
if(right-1>rightb){
center=i;
rightb=right-1;
}
}
//找出help数组中的最大值,然后输出即可
int a=0;//表示最大值对应的索引
int b=help[0];//表示最大值
for(int i=1;i<help.length;i++){
if(b<help[i]){
a=i;
b=help[i];
}
}
return s.substring(a-b,a+b+1).replaceAll("#","");//这离记住 replace对于‘/’和‘$’ 这两个字符是
}
}
进行细分,方便理解版本,两大类,一大类一种,二大类三种情况
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==0){
return s;
}
//进行s的扩充
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
s=sb.toString();
//Manacher开始
int rightB=-1;
int center=-1;
int[] help=new int[s.length()];
for(int i=0;i<s.length();i++){
if(i<rightB){
if(i+help[2*center-i]<rightB){
help[i]=help[2*center-i];
continue;
}
if(i+help[2*center-i]>rightB){
help[i]=rightB-i;
continue;
}
help[i]=rightB-i;
}
int left=i-help[i];
int right=i+help[i];
while(left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
left--;
right++;
}
help[i]=right-i-1;
if(right-1>rightB){
rightB=right-1;
center=i;
}
}
int a=0;
int b=help[0];
for(int i=1;i<help.length;i++){
if(help[i]>b){
a=i;
b=help[i];
}
}
return s.substring(a-b,a+b+1).replaceAll("#","");
}
}
最后最后 我把马拉车又实现了一遍,这次又有新的收获
感觉还是多多的做吧。
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()==0||s==""){
return s;
}
//首先一定是把s扩展成一个奇数形式,否则奇偶不同,要分情况。
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
s=sb+"";
//准备工作结束,manacher开始。
int[] help = new int[s.length()];//回文半径数组
int rightb=-1;//有边界,先定义一个无意义的值
int center=-1;//回文有边界 对应的回文中心。也是开始定义一个无定义的值,这个后面会变的。
//上面那俩情况说明,一定要定义负数,后面修改的时候要比较值的。
int zeng = 0;//增量,刚开始一定是0
for(int i=0;i<s.length();i++){
//首先就要判断是不是可以直接写答案,也就是小三种,i<rightb的时候
//这时候要去找关于回文中心的对称点。
if(i<rightb){
//找回文中心的对称点 其实就是 2*center-i 这个记一下。
if(i+help[2*center-i]<rightb){
help[i]=help[2*center-i];
continue;
}
if(i+help[2*center-i]>rightb){
help[i]=rightb-i;
continue;
}
//这个就是如果i+help[2*center-i]==rightb的时候,这时候修改增量就可以
zeng=rightb-i;//记住这个增量如果不进这个循环是必须为0,也就是每一次for循环都要最后吧zeng编程0.
}
int left=i-zeng;
int right=i+zeng;
zeng=0;//用完变0
while(left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
left--;
right++;
}
//跟新center和rightb 跟新回文中心和回文有边界
if(right-1>rightb){//这里的right-1 一定一定注意,我犯错了,一定要减一
center=i;
rightb=right-1;
}
help[i]=right-i-1;
}
int index=0;
int max=help[0];
for(int i=1;i<help.length;i++){
if(help[i]>max){
max=help[i];
index=i;
}
}
return s.substring(index-max,index+max+1).replace("#","");//substring函数,最后一个数不接,这个别忘了啊,要不然你一定错,而且这个错不调试不容易发现。
}
}