zoukankan      html  css  js  c++  java
  • leecode---05---字符串,回文,动态规划---查找最长的回文子串

     
    题意
    目的是找到最长的回文子串,必须记录好子串的起点,子串的长度这两个参量,然后将子串返回。
     
     
    分析
    方法1:时间换空间
    对于每个点,做两个指针往两边跑,跑的过程中判断是否刷新最长回文的长度。遍历的过程中注意区分一下奇数偶数就可以了,区分奇偶数的方式就是指针要么同时从一个数走,要么同时从当前数和后一个数字走起。
     
    方法二:动态规划
    空间换时间的类型
     
    代码

     
    class Solution {
        
        int max;
        int start;//因为最后要返回结果所以要记录最长回文子串的开始位置
        
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) return null;
            if (s.length() == 1) return s;
            
            //遍历的时候分成奇数和偶数,奇数对应的位置相同,偶数的话就是两端相同
            for (int i = 0; i < s.length(); i++) {
                getMaxPalindrome(s,i,i);
                getMaxPalindrome(s,i,i+1);
            }
            
            //最后返回结果值
            return s.substring(start,start+max);
        }
        
        //写一个函数,更新从Left往左以及right往右的最大回文
        public void getMaxPalindrome(String s,int left,int right) {
            //如果左右相等并且没有超出边界的话就继续移动
            while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            }
            //循环的结果就是左右两边的参数是不相等的
            if (max < right - left + 1 -2) {
                start = left + 1;
                max = right - left - 1;
            }
        }
    }
     
     

    空间换时间的方式计算
    假设dp[i][j]表示从i到j个字符串是回文字符串。
    那么 dp[i][j] = dp[i+1][j-1] && (s.charAt(i) == s.charAt(j))
    其中dp[i +1][j-1]涉及到i和j.可能的极限情况就是 i+1==j-1或者两个参数值相邻。那么这就涉及到初始化。
    1.dp[i][i]==true
    2.dp[i][i+1] == true
     
    第一种动态规划写法是错误的:
    class Solution {
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) return null;
            if (s.length() ==1) return s;
            
            String result = null;
            int max = 1;
            int[][] dp = new int[s.length()][s.length()];
            
            //初始化,相邻状态和相等状态
            for (int i = 0; i < s.length(); i++) {
                dp[i][i] = 1;
                result = String.valueOf(s.charAt(i));
            }
            for (int i = 0; i < s.length() - 1; i++) {
                if (s.charAt(i) == s.charAt(i + 1)) {dp[i][i + 1] = 1;max = 2;result = s.substring(i,i+2);}
            }
            
            //这边的写法是错误的!!!假设从i=0开始,j从2开始往右边跑直到4。但是一开始bcb的dp值是0,因为是从左往右遍历的,所以在判断abcba的时候虽然头尾都是相等的,但是bcb的dp值是0,也就是说abcba也是0,所以不能够从左往右遍历!!!!
            //然后进行动态规划判断普通情况dp[i][j]从i到j的值
            //1.第一层循环的终点是左边在length - 2的位置
            //2.第二层循环的点j从i+2开始,因为相邻和相等情况之前判断过了
            //3.判断i和j指向的值是否是相等的,如果相等更新下最大值
            for (int i = 0; i < s.length() -2; i++) {
                for (int j = i + 2; j < s.length(); j++) {
                    if (s.charAt(i) == s.charAt(j)) {
                        dp[i][j] = dp[i + 1][j - 1];
                        if (dp[i][j] == 1 && (j - i + 1) > max) {
                            max = j - i + 1;
                            result = s.substring(i,j+1);
                        }
                    } else {
                        dp[i][j] = 0;
                    }
                }
            }
            
            //返回结果
            return result;
        }
    }
     
     

     
    动态规划的正确解法,应该按照长度大小来设置普通情况下的字符串长度。
     
    class Solution {
        public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) return null;
            if (s.length() ==1) return s;
            
            String result = null;
            int max = 1;
            int[][] dp = new int[s.length()][s.length()];
            
            //初始化,相邻状态和相等状态
            for (int i = 0; i < s.length(); i++) {
                dp[i][i] = 1;
                result = String.valueOf(s.charAt(i));
            }
            for (int i = 0; i < s.length() - 1; i++) {
                if (s.charAt(i) == s.charAt(i + 1)) {dp[i][i + 1] = 1;max = 2;result = s.substring(i,i+2);}
            }
            
            //然后进行动态规划判断普通情况dp[i][j]从i到j的值
            //必须从长度开始判断,长度从3开始处理
            for (int l = 3; l <= s.length(); l++) {
                for (int i = 0; i + l - 1 < s.length(); i++) {
                    int j = i + l - 1;//就是加上长度之后的右边的值
                    if (s.charAt(i) == s.charAt(j)) {
                        dp[i][j] = dp[i + 1][j - 1];
                        if (dp[i][j] == 1 && l > max) {
                            max = l;
                            result = s.substring(i,j + 1);
                        }
                    } else {
                        dp[i][j] = 0;
                    }
                }
            }
            
            //返回结果
            return result;
        }
    }
  • 相关阅读:
    (C/C++学习笔记) 十四. 动态分配
    (C/C++学习笔记) 十三. 引用
    (C/C++学习笔记) 十二. 指针
    (C/C++学习笔记) 十一. 数组
    (C/C++学习笔记) 十. 函数
    (C/C++学习笔记) 九. 变量的存储类型
    (C/C++学习笔记) 八. 程序控制语句
    并发编程之多进程
    网络编程之Socket
    异常处理
  • 原文地址:https://www.cnblogs.com/buptyuhanwen/p/8862421.html
Copyright © 2011-2022 走看看