未验证 提交 ccb4cc19 编写于 作者: X xshahq 提交者: GitHub

Merge pull request #89 from apachecn/master

1
# 132. Palindrome Partitioning II
**<font color=red>难度: Hard</font>**
## 刷题内容
> 原题连接
* https://leetcode.com/problems/palindrome-partitioning-ii/
> 内容描述
```
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.
```
## 解题方案
> 思路 1
******- 时间复杂度: O(N^3)******- 空间复杂度: O(N^2)******
- 我们维护一个一维数组cut,cut[i]代表s[:i+1]最少需要多少次cut
- 然后我们发现对于j<=i, 如果s[j:i+1]是Palindrome则cut[i] = min(cut[i], cut[j-1] + 1) if j > 0 else 0,
因为如果j为0的话说明s[:i+1]都是Palindrome了,完全不需要cut,所以当j==0的时候cut[i] = 0
- 最后返回cut[-1]即可
```python
class Solution:
def minCut(self, s: str) -> int:
cut = list(range(len(s)))
for i in range(len(s)):
for j in range(i+1):
if s[j:i+1] == s[j:i+1][::-1]:
cut[i] = min(cut[i], cut[j-1] + 1) if j > 0 else 0
return cut[-1]
```
> 思路 2
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******
我们发现每次都要算s[j:i+1]是否为Palindrome太浪费时间了, 用一个dp数组记录一下
- 我们维护一个二维数组dp,dp[i][j]代表s[i:j+1]是否为Palindrome
- 然后维护一个一维数组cut,cut[i]代表s[:i+1]最少需要多少次cut
- 然后我们发现对于j<=i, 如果s[j:i+1]是Palindrome则cut[i] = min(cut[i], cut[j-1] + 1) if j > 0 else 0,
因为如果j为0的话说明s[:i+1]都是Palindrome了,完全不需要cut,所以当j==0的时候cut[i] = 0
- 最后返回cut[-1]即可
```python
class Solution:
def minCut(self, s: str) -> int:
dp = [[False] * len(s) for _ in range(len(s))]
cut = [0] * len(s)
for i in range(len(s)):
cut[i] = i
for j in range(i+1):
if s[i] == s[j] and (j+1 >= i-1 or dp[j+1][i-1]):
dp[j][i] = True
cut[i] = min(cut[i], cut[j-1] + 1) if j > 0 else 0
return cut[-1]
```
> 思路 3
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)******
我们在空间上也可以继续优化
- 我们维护一个一维数组cut,cut[i] 代表前i个字符最少需要几次cut
- 然后对于每一个字符s[i],我们分两种情况讨论
- 将s[i]作为palindrome的中间字符(odd length),向两边各扩展j个字符,使得s[i-j:i+j+1]是palindrome,同时保证不越界,
此时cut[i+j+1] = min(cut[i+j+1], cut[i-j] + 1)
- 将s[i]作为palindrome的中间靠前的那个字符(even length),向左边扩展j-1个字符,向右边扩展j个字符,使得s[i-j+1:i+j+1]是palindrome,同时保证不越界,
此时cut[i+j+1] = min(cut[i+j+1], cut[i-j+1] + 1)
- 最后返回cut[-1]
参考[My solution does not need a table for palindrome, is it right ? It uses only O(n) space.](https://leetcode.com/problems/palindrome-partitioning-ii/discuss/42198/My-solution-does-not-need-a-table-for-palindrome-is-it-right-It-uses-only-O(n)-space.)
```python
class Solution:
def minCut(self, s: str) -> int:
cut = list(range(-1, len(s))) # cut[i] 代表前i个字符最少需要几次cut
for i in range(len(s)):
j = 0
while i - j >= 0 and i + j < len(s) and s[i-j] == s[i+j]: # odd length palindrome
cut[i+j+1] = min(cut[i+j+1], cut[i-j] + 1)
j += 1
j = 1
while i - j + 1 >= 0 and i + j < len(s) and s[i-j+1] == s[i+j]: # even length palindrome
cut[i+j+1] = min(cut[i+j+1], cut[i-j+1] + 1)
j += 1
return cut[-1]
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册