Question Given a string s , partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s . Example: Input:"aab" Output: 1 Explanation: The palindrome partitioning
Question
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
Example:
Input: "aab" Output: 1 Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.
Solution
第一个思路是和Palindrome Partitioning解答思路相似,先用二维DP得到palindrome结果,然后用DFS.
时间复杂度O(N^2) 空间复杂度O(N^2)
1 class Solution: 2 def check(self, s: str) -> None: 3 n = len(s) 4 self.dp = [[False for i in range(n)] for j in range(n)] 5 for i in range(n): 6 self.dp[i][i] = True 7 for i in range(n - 1): 8 if s[i] == s[i + 1]: 9 self.dp[i][i + 1] = True 10 for k in range(3, n + 1): 11 for i in range(n - k + 1): 12 j = i + k - 1 13 if s[i] == s[j] and self.dp[i + 1][j - 1]: 14 self.dp[i][j] = True 15 16 def dfs(self, s: str, start: int, record: List[str], result: List[int]) -> None: 17 n = len(s) 18 if start == n: 19 cut_num = len(record) - 1 20 result[0] = min(cut_num, result[0]) 21 return 22 for end in range(start, n): 23 if self.dp[start][end]: 24 record.append(s[start: end + 1]) 25 self.dfs(s, end + 1, record, result) 26 record.pop() 27 28 def minCut(self, s: str) -> int: 29 self.check(s) 30 result = [len(s) - 1] 31 self.dfs(s, 0, [], result) 32 return result[0] 33
但是这个方法在大数据测试的时候超时了,这时候需要思考怎样可以减少时间。
一个重要的方法是再次使用DP。用一维DP:cut[i]表示从0到i-1的min cut数量。
1 class Solution: 2 def check(self, s: str) -> None: 3 n = len(s) 4 self.dp = [[False for i in range(n)] for j in range(n)] 5 # one or two chars 6 for i in range(n - 1): 7 self.dp[i][i] = True 8 self.dp[i][i + 1] = True if s[i] == s[i + 1] else False 9 self.dp[n - 1][n - 1] = True 10 # more chars 11 for k in range(3, n + 1): 12 for i in range(n - k + 1): 13 j = i + k - 1 14 self.dp[i][j] = True if s[i] == s[j] and self.dp[i + 1][j - 1] else False 15 16 def minCut(self, s: str) -> int: 17 self.check(s) 18 n = len(s) 19 # cut[i] means minimal cut number for s[0:i-1] 20 cut = [len(s) - 1] * (n + 1) 21 # notice here we need to set cut[0] = -1 so that if self.dp[0][n-1] is true, there is no cut needed 22 cut[0] = -1 23 for i in range(1, n + 1): 24 for j in range(i - 1, -1, -1): 25 if self.dp[j][i - 1]: 26 cut[i] = min(cut[i], cut[j] + 1) 27 return cut[n]
尽管时间空间复杂度不变,但是在计算最小切割数时我们通过DP减少了很多重复计算的时间。