LeetCode刷题08

本文详细解析了如何判断回文数,包括双指针方法和利用栈,以及如何使用暴力算法、中心扩散法和动态规划解决LeetCode第5题——找到给定字符串的最长回文子串。
摘要由CSDN通过智能技术生成

这一篇,目的只有一个,将回文数这个概念解析明白(之前自己也是半懂状态),希望这一篇可以加深对此的理解和问题的解决。

一.判断回文数

1.概念

首先什么是回文数呢?
121,aba,ababa…这种形式就是了,反转过来还是一样的,这里我们统一看回文字符串就行了。

2.双指针方法

  1. 双指针,一头一尾,逐一比较是否相等,相等的话,指针进行移动,直到两个指针相遇,不等的话直接返回flase。

  2. 示例代码如下:

 //判断回文串的双指针方法
    public static boolean isPalindrome(String str) {
        int left = 0;
        int right = str.length() - 1;
        while (left < right) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

3.利用栈

  1. 首先,栈是一种特殊的数据结构,先进去的沉入底部,先进去的后出来,类似于一口井。
    我们只需要判断进去的字符串和出来的字符串相等即可。因为进去和出来相当于做了一次字符串的翻转。
  2. 栈的常用方法:
    push()进栈
    pop()出栈,并返回出来的字符
    peek()取栈最顶部的值,但不出栈
    isEmpty():判断栈是否为空,返回true和flase
    在这里插入图片描述

示例代码如下:

 // 进栈字符=出栈字符
    public static boolean isPalindrome2(String str) {
        Stack<Character> stack = new Stack<>();

        for (int i = 0; i < str.length(); i++) {
            stack.push(str.charAt(i));
        }

        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) != stack.pop()) {
                return false;
            }
        }
        return stack.isEmpty();
    }

二.第5题.最长回文子串

知道了上面的回文字符串的基本判断方法,我们开始走进这到力扣的中等题。

题目要求如下:
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例:
在这里插入图片描述

2.1暴力算法

  1. 首先,这个写一个方法isPalindrome(char [] chars,int left,int right),用来判断字符数组left到right是否为回文字符串。
  2. 说是暴力,自然是一一比较,双for循环,一个是起点一个是终点,一个个找回文子串,然后更新一个起点能够找到的最长回文子串。
  3. 起点从第一个字符开始移动,移动到倒数第二个字符,防止越界。
  4. 其中边界条件是:只有一个字符或者是空字符,那就是它本身。
  5. 示例代码和注释如下:
//1. 暴力算法,时间O(n^3)
    public String longestPalindrome1(String s) {
        //边界条件
        int len=s.length();
        if(len<2) return s;

        //初始化,转化为字符串数组(防止越界)
        int MaxLen=1;   //最长回文子串的长度
        char[]chars=s.toCharArray();
        int begin=0;    //起始位置
        //双循环+回文数判断爆破解决
        //起点i,遍历的字符串终点j
        for(int i=0;i<len-1;i++){
           for (int j=i+1;j<len;j++){
               //如果i,j之间的字符串为回文字符串的话
               // 并且最长长度更新的话进入判断,进行数据更新
               if(isPalindrome(chars,i,j)&& j-i+1>MaxLen){
                   MaxLen=j-i+1;
                   begin=i;
               }
           }
        }
        //截取最长子串,起始,终止(起点+长度)
        return s.substring(begin,begin+MaxLen);
    }

   //判断字符串数组中,左右两边中的字符串是否为回文字符串
        public static boolean isPalindrome(char [] chars,int left,int right) {
            while (left < right) {
                if (chars[left] != chars[right]) {
                    return false;
                }
                left++;
                right--;
            }
            return true;
        }

2.2中心发散法

  1. 因为一个字符串是回文字符串,那么它的子串(取两边)也是回文字符串,是一种天然的递归思想。

  2. 所以这次的目标就是找到中心点,向外扩散,找到最长的字符串,然后刚刚中心点的最长字符串再比较。

  3. 其中 expandAroundCenter(String s,int left,int right)用来寻找中心点的最长字符串长度,其中将奇数和偶数的状况统一了,left=right为奇数状态,right=left+1为偶数状态。

  4. 时间复杂度:O(n^2),空间复杂度:O(1),其中力扣官方的示例图如下:
    在这里插入图片描述

  5. 示例代码如下:

  //2.中心扩散法,时间O(2n)
    public String longestPalindrome2(String s) {
        //边界条件
        if(s.length()<1 ||s==null) return "";

       //初始化起始点和终止点
        int start=0,end=0;

        //主要逻辑代码
        for(int i=0;i<s.length();i++){
            //回文长度为偶数和奇数
            int oddLen=expandAroundCenter(s,i,i);
            int envLen=expandAroundCenter(s,i,i+1);
            //两种情况都概括了,求较大值
            int length=Math.max(oddLen,envLen);

            //更新起始点和终止点
            if(length>end-start){
                //其中(length-1)/2目的是向下取整,奇偶数统一
                start=i-(length-1)/2;
                end=i+length/2;
            }

        }
        //截取最长子串,起始,终止(起点+长度)
        return s.substring(start,end+1);
    }


    //中心扩散方法:先找到中心,左右扩散对比,找到最长的回文字符串
   public int expandAroundCenter(String s,int left,int right){
        //在边界条件内,满足回文条件,继续向外扩散找到最长的位置
        while (left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
            --left;
            ++right;
        }
        //返回长度,left和right为指针,不包括他们所指向的字符串
        //长度=r-l+1-2
        return right-left-1;
   }

2.3 动态规划

  1. 回文字符串,和上面的思想类型,它要是一个回文字符串,那它去掉两边后的子串也要是回文字符串。
  2. 状态转移方程:dp[i][j]=dp[i+1][j-1]&&s[i]==s[j](字符串相等)
  3. 边界条件:j-i+1<4;字符串长度为2和3,不需要检验子串是否是回文,肯定是,因为单个字符和空不需要验证。
  4. 对角线表示当个字符,所以dp[]i[i]=true
  5. 这一部分没有具体的图,不方便理解,所以这是官方讲解中的ppt示例:
    在这里插入图片描述
  6. 代码示例:
 //方法3:动态规划
    public String longestPalindrome(String s) {
        int n = s.length(); // 字符串长度
        boolean[][] dp = new boolean[n][n]; // 动态规划数组,记录子问题的结果
        String res = ""; // 存储结果的字符串
        int begin = 0; // 最长回文子串的起始位置
        int maxLen = 0; // 最长回文子串的长度

        for (int L = 1; L <= n; L++) { // 遍历子字符串的长度
            for (int i = 0; i < n; i++) { // 遍历起始索引
                int j = i + L - 1; // 结束索引
                if (j >= n) { // 如果结束索引超出字符串长度,跳出当前循环
                    break;
                }

                if (s.charAt(i) != s.charAt(j)) { // 如果首尾字符不相等,不是回文
                    dp[i][j] = false;
                } else {
                    // 判断内部子串是否为回文,其中长度为1看定为回文
                    dp[i][j] = L <= 2 || dp[i + 1][j - 1]; 
                }
                  // 如果当前子串是回文且长度大于最长回文子串长度
                if (dp[i][j] && L > maxLen) { 
                    begin = i; // 更新起始位置
                    maxLen = L; // 更新最长长度
                }
            }
        }
                // 根据起始位置和最长长度提取回文子串并返回
        return s.substring(begin, begin + maxLen); 
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱笑的蓝孩子~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值