132. 分割回文串 II(Palindrome Partitioning II)

132. 分割回文串 II(Palindrome Partitioning II)

  • 题解
    • 动态规划
      • 复杂度分析
      • Python
      • Java(待完成)
    • 记忆化回溯
      • 复杂度分析
      • Python
      • Java(待完成)

题解

动态规划

  1. 初始化最小分割次数数组 m i n _ c u t = { 0 , 1 , 2 , ⋯   , n − 1 } min\_cut=\{0,1,2,\cdots,n-1\} min_cut={0,1,2,,n1},长度为字符串的长度 n n n。其中 m i n _ c u t [ i ] min\_cut[i] min_cut[i]表示 s [ 0 , ⋯   , i ] s[0,\cdots,i] s[0,,i]每个子串都是回文串的分割次数。初始化的含义为, s [ 0 ] s[0] s[0]只有一个字符,不需要分割,因此 m i n _ c u t [ 0 ] = 0 min\_cut[0]=0 min_cut[0]=0 s [ 0 , 1 ] s[0,1] s[0,1]最多需要1次,分成两个单独的字符。 s [ 0 , 1 , 2 ] s[0,1,2] s[0,1,2]需要三次。以此类推。

  2. 初试化 d p = [ [ F a l s e , ⋯   , F a l s e ] , ⋯   , [ F a l s e , ⋯   , F a l s e ] ] dp=[[False,\cdots,False],\cdots,[False,\cdots,False]] dp=[[False,,False],,[False,,False]],为 n ∗ n n*n nn维数组。其中 d p [ i ] [ j ] dp[i][j] dp[i][j]表示 s [ i , ⋯   , j ] s[i,\cdots,j] s[i,,j]是否为回文串。

  3. 遍历 d p dp dp,子串结束索引 i i i,遍历区间 [ 0 , n ) [0,n) [0,n)

    • 子串开始索引 i i i,遍历区间 [ 0 , j + 1 ) [0,j+1) [0,j+1)
      • s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j]并且 j − i < 2   o r   d p [ i + 1 ] [ j − 1 ] = = T r u e j-i<2\ or\ dp[i+1][j-1]==True ji<2 or dp[i+1][j1]==True。解释:动态规划方程含义为,若 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j]表示子串 s [ i , ⋯   , j ] s[i,\cdots,j] s[i,,j]的两端相同,则该子串是否为回文串取决于 d p [ i + 1 ] [ j − 1 ] dp[i+1][j-1] dp[i+1][j1]即( s [ i + 1 , ⋯   , j − 1 ] s[i+1,\cdots,j-1] s[i+1,,j1])是否为回文串。特殊情况是 j − i < 2 j-i<2 ji<2,表示长度小于 3 3 3,此时也是满足的。
        • d p [ i ] [ j ] dp[i][j] dp[i][j] s [ i , ⋯   , j ] s[i,\cdots,j] s[i,,j]为回文子串)为 T r u e True True .此时,若 i = = 0 i==0 i==0,开始位置为 0 0 0,说明 s [ 0 , ⋯   , j ] s[0,\cdots,j] s[0,,j]为回文串,则此时 m i n _ c u t [ j ] = 0 min\_cut[j]=0 min_cut[j]=0,表示到 j j j位置的子串不需要进行切割,自身就是回文子串。
        • i ! = 0 i!=0 i!=0,说明开始的位置不是 0 0 0,此时 m i n _ c u t [ j ] = m i n ( m i n _ c u t [ j ] , m i n _ c u t [ i − 1 ] + 1 ) min\_cut[j]=min(min\_cut[j],min\_cut[i-1]+1) min_cut[j]=min(min_cut[j],min_cut[i1]+1)。表示始终为到上一回文串位置的切割次数加1中的最小值。
  4. 返回 m i n _ c u t [ − 1 ] min\_cut[-1] min_cut[1]

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^{2}) O(n2)
  • 空间复杂度: O ( n 2 ) O(n^{2}) O(n2)

Python

class Solution:
    def minCut(self, s: str) -> int:
        min_cut = list(range(len(s)))
        n = len(s)
        dp = [[False] * n for _ in range(n)]
        for j in range(n):
            for i in range(j+1):
                if s[i] == s[j] and (j - i < 2 or dp[i + 1][j - 1]):
                    dp[i][j] = True
                    if i == 0:
                        min_cut[j] = 0
                    else:
                        min_cut[j] = min(min_cut[j], min_cut[i - 1] + 1)
        return min_cut[-1]



Java(待完成)

记忆化回溯

132. 分割回文串 II(Palindrome Partitioning II)_第1张图片

  1. 定义回溯函数 m i n C u t ( s ) minCut(s) minCut(s)
    • s s s为回文串,则返回 0 0 0,表示当前子串不需要切割。
    • 初试化当前子串的最小切割次数 r e s = M a x res=Max res=Max
    • 遍历结束索引 i i i,遍历区间 [ 1 , n + 1 ) [1,n+1) [1,n+1)
      • s [ 0 , ⋯   , i − 1 ] s[0,\cdots,i-1] s[0,,i1]为回文串: r e s = m i n ( r e s , m i n C u t ( s [ i , ⋯   , n − 1 ] ) + 1 ) res=min(res,minCut(s[i,\cdots,n-1])+1) res=min(res,minCut(s[i,,n1])+1)。解释:始终保存最小的切割次数。
    • 返回 r e s res res

复杂度分析

  • 时间复杂度: O ( n ! ) O(n!) O(n!)
  • 空间复杂度: O ( n ! ) O(n!) O(n!)

Python

import functools
class Solution:
    @functools.lru_cache(None)
    def minCut(self, s: str) -> int:
        if s == s[::-1]:
            return 0
        ans = float("inf")
        for i in range(1, len(s) + 1):
            if s[:i] == s[:i][::-1]:
                ans = min(self.minCut(s[i:]) + 1, ans)
        return ans

Java(待完成)

你可能感兴趣的:(#,动态规划(Dynamic,Programming),#)