(有马拉车)leetcode409 最长回文串 125

方法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函数,最后一个数不接,这个别忘了啊,要不然你一定错,而且这个错不调试不容易发现。
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值