代码随想录算法训练营第四十七天 | leetcode:回文子串,最长回文子序列

647. 回文子串

解题方法

  1. dp数组的含义:dp[i][j]:表示从s[i]到s[j]这段字符串是否为回文子串 其中:i<=j
  2. 确定递推公式:主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同
    • if(s[i] == s[j])有三种情况:
      • i == j: 指向同一个字符。即:if(i==j)dp[i][j] = true;
      • j-i = 1: 此时为2个字符。即:if(j-i == 1)dp[i][j] = true;可以和上一种情况合并为:if(j-i <= 1)dp[i][j] = true;
      • j-i > 1: 此时大于2个字符,因为对比顺序是从中间往两边扩散,需要从前一个字符,i+1,j-1推出,如果前一个字符相等,那么当前i,j也是回文子串。即:if(j-i > 1 && dp[i+1][j-1] == true)dp[i][j] = true
        代码随想录算法训练营第四十七天 | leetcode:判断子序列,不同的子序列
  3. 初始化dp数组:dp[i][j] = false。
  4. 遍历顺序:dp[i][j]依赖与[i+1][j-1],所以遍历顺序外层从后往前,内层从前往后

code

动态规划解法1

class Solution {

    /**
     * @param String $s
     * @return Integer
     */
    function countSubstrings($s) {
        $dp = [];
        $len = strlen($s);
        $res = 0;
        for($i = $len-1; $i > 0; $i--){
            for($j = $i; $j < $len; $j++){
                $dp[$i][$j] = false;
            }
        }
        for($i = $len-1; $i >= 0; $i--){
            for($j = $i; $j < $len; $j++){
                if($s[$i] == $s[$j]){
                    if($j-$i <= 1){
                        $dp[$i][$j] = true;
                        $res++;
                    }elseif($dp[$i+1][$j-1] == true){
                        $dp[$i][$j] = true;
                        $res++;
                    }
                }
            }
        }
        //print_r($dp);
        return $res;
    }
}

复杂度

时间复杂度

O(n^2)

空间复杂度

O(n^2)

双指针解法

class Solution {

    protected $num = 0;
    protected $len = 0;

    function countSubstrings($s) {
        $this->len = strlen($s);
        for ($i = 0; $i < $this->len; $i++) { 
            $this->getRes($s, $i, $i);// 以i为中心
            $this->getRes($s, $i, $i+1);// 以i+1为中心
        }
        return $this->num;
    }

    protected function getRes($s, $left, $right) {
        while($left >= 0 && $right <= $this->len && $s[$left] == $s[$right]) {
            $this->num++;
            $left--;
            $right++;
        }
    }
}

复杂度

时间复杂度

O(n^2)

空间复杂度

O(1)

516. 最长回文子序列

解题方法

  1. dp数组的含义:dp[i][j] :字符串s在[i, j]范围内最长的回文子序列的长度
  2. 确定递推公式:
    • if(s[i] == s[j]) dp[i][j] = dp[i+1][j-1] + 2
      如果遍历前一段字符为回文子串,那么当s[i] == s[j]时,那么这段字符串也是回文子串,所以当前遍历字符串的最长回文子序列长度就是在前端字符的最长回文子序列长度基础上+2。
      代码随想录算法训练营第四十七天 | leetcode:判断子序列,不同的子序列
    • if(s[i] != s[j]) dp[i][j] = min(dp[i+1][j],dp[i][j-1])
      如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。
      加入s[j]的回文子序列长度为dp[i + 1][j]。
      加入s[i]的回文子序列长度为dp[i][j - 1]。
      那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
      代码随想录算法训练营第四十七天 | leetcode:判断子序列,不同的子序列
  3. 初始化dp数组:当i=j时,初始化为1,即代指单个字符也是回文串的情况。其他初始化为0;
  4. 遍历顺序:dp[i][j]依赖与[i+1][j-1],所以遍历顺序外层从后往前,内层从前往后

code

class Solution {

    /**
     * @param String $s
     * @return Integer
     */
    function longestPalindromeSubseq($s) {
         $len = strlen($s);
         if($len <= 1) return $len;

         $dp = array_fill(0, $len, array_fill(0, $len, 0));
         for($i = 0; $i < $len; $i++){
            $dp[$i][$i] = 1;
         }
         for($i = $len - 1; $i >= 0; $i--){
            for($j = $i + 1; $j < $len; $j++){
                if($s[$i] == $s[$j]){
                    $dp[$i][$j] = $dp[$i+1][$j-1] + 2;
                }else{
                    $dp[$i][$j] = max($dp[$i+1][$j], $dp[$i][$j-1]);
                }
            }
         }
         return $dp[0][$len-1];
    }
}

复杂度

时间复杂度

O(n^2)

空间复杂度

O(n^2)

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!