详细见:leetcode.com/problems/palindrome-partitioning-ii
Java Solution: github
package leetcode;
/**
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.
For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"]
could be produced using 1 cut.
*/
/**
* @author zxwtry
* @email zxwtry@qq.com
* @project OJ
* @package leetcode
* @file P132_PalindromePartitioningII.java
* @type P132_PalindromePartitioningII
* @date 2016年12月13日 下午7:49:29
* @details Solution1: AC 52ms 14.09%
*/
public class P132_PalindromePartitioningII {
static class Solution {
public int minCut(String s) {
if (s == null || s.length() < 2) return 0;
int[] m = manacher(s);
int[] ndp = new int[s.length()];
for (int i = 0; i < s.length(); i ++) {
if (isPalindrome(m, i, 0)) {
ndp[i] = 0;
continue;
}
ndp[i] = Integer.MAX_VALUE-1;
for (int j = 1; j <= i; j ++)
if (isPalindrome(m, i, j))
ndp[i] = Math.min(ndp[j-1] + 1, ndp[i]);
}
return ndp[ndp.length - 1];
}
private boolean isPalindrome(int[] m, int maxIndex, int minIndex) {
return m[minIndex + maxIndex + 1] > maxIndex - minIndex;
}
private int[] manacher(String s) {
int mn = 2 * (s == null ? 0 : s.length()) + 1;
int[] m = new int[mn];
int ti = 0, ci = 0, mi = 0, li = 0, ri = 0;
for (int i = 0; i < mn; i ++) {
mi = 2 * ci - i;
if (i >= ti || m[mi] == ti-i) {
li = ri = i;
while (li-1 > -1 && ri+1 < mn && access(s, li-1) == access(s, ri+1)) {
li --;
ri ++;
}
ti = ri;
ci = i;
m[i] = (ri - li) / 2;
} else m[i] = Math.min(m[mi], ti-i);
}
return m;
}
private char access(String s, int i) {
return i % 2 == 0 ? 0 : s.charAt(i/2);
}
}
}
C Solution: github
#pragma warning(disable:4786)
/*
url: leetcode.com/problems/palindrome-partitioning-ii
Solution1: TLE
Solution2: AC 6ms 76.37%
*/
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <stdio.h>
using namespace std;
class Solution1 {
public:
int _min(int a, int b) {
return a < b ? a : b;
}
int convert(int a, int b) {
return a * 100000 + b;
}
int isP(string& s, int i, int j) {
while (i < j) {
if (s[i] != s[j]) return 0;
i ++;
j --;
}
return 1;
}
int minCut(string s) {
int sn = s.size(), ans = INT_MAX;
int ** dp = new int* [sn];
int ** sa = new int* [sn];
for (int dpi = 0; dpi < sn; dpi ++) {
dp[dpi] = new int[sn];
sa[dpi] = new int[sn];
}
for (int len = 1; len <= sn; len ++) {
for (int i = 0; i <= sn - len; i ++) {
if (s[i] == s[i+len-1] && (len < 3 || (dp[i+1][i+len-2]) == 1988)) {
dp[i][i+len-1] = 1988;
sa[i][i+len-1] = 1;
} else {
int min_val = INT_MAX;
for (int klen = 1; klen < len; klen ++) {
min_val = _min(sa[i][i+klen-1] + sa[i+klen][i+len-1], min_val);
}
sa[i][i+len-1] = min_val;
}
}
}
return sa[0][sn-1]-1;
}
};
class Solution2 {
public:
char access(string s, int i) {
return i%2 == 0 ? '#' : s[i/2];
}
int _max(int a, int b) {
return a < b ? b : a;
}
int _min(int a, int b) {
return a < b ? a : b;
}
int* manacher(string& s, int& sn) {
int nn = 2 * sn + 1;
int* m = new int[nn];
int mi = 0, li = 0, ti = 0, left = 0, right = 0;
for (int i = 0; i < nn; i ++) {
mi = 2 * li - i;
if (i >= ti || m[mi] + i >= ti) {
left = i;
right = i;
while (left > 0 && right < nn-1 && access(s, left-1) == access(s, right+1)) {
left --;
right ++;
}
li = i;
ti = right;
m[i] = (right - left + 2) / 2;
} else m[i] = _min(ti - i, m[mi]);
}
return m;
}
int isPalindrome(int* m, int minIndex, int maxIndex) {
return m[(maxIndex + minIndex + 1)] > maxIndex - minIndex + 1;
}
int minCut(string s) {
int sn = s.size();
int ans = 0;
int* m = manacher(s, sn);
int* rec = new int[sn];
for (int i = 0; i < sn; i ++) {
if (isPalindrome(m, 0, i)) {
rec[i] = 0;
continue;
}
rec[i] = INT_MAX - 1;
for (int j = 1; j <= i; j ++) {
if (isPalindrome(m, j, i)) {
rec[i] = _min(rec[i], rec[j-1] + 1);
}
}
}
delete(m);
ans = rec[sn-1];
delete(rec);
return ans;
};
};
void swap(int* a, int *b ) {
int t = *a;
*a = *b;
*b = t;
}
void swap2(int& a, int &b) {
int t = a;
a = b;
b = t;
}
int main() {
string s = "cadfdsdfefbvabadfafsbcbc";
cout<<Solution1().minCut(s)<<endl;;
cout<<Solution2().minCut(s)<<endl;;
return 0;
}
Python Solution: github
#coding=utf-8
'''
url: leetcode.com/problems/palindrome-partitioning-ii
@author: zxwtry
@email: zxwtry@qq.com
@date: 2017年5月15日
@details: Solution: 792ms 29.31%
'''
class Solution(object):
def index(self, s, i):
return "#" if i % 2 == 0 else s[i // 2]
def manacher(self, s, sn):
nn = 2 * sn + 1
m = [0] * nn
ti = 0
mi = 0
ci = 0
for i in range(nn):
mi = 2 * ci - i
if i >= ti or m[mi] == ti-i:
li = i
ri = i
while li-1 > -1 and ri+1 < nn and \
self.index(s, li-1) == self.index(s, ri+1):
li, ri = li-1, ri+1
ti = ri
ci = i
m[i] = (ri-li) // 2
else: m[i] = min(m[mi], ti-i)
return m
def isP(self, m, i, j):
return m[i+j+1] > abs(i-j)
def minCut(self, s):
"""
:type s: str
:rtype: int
"""
sn = 0 if s == None else len(s)
if sn < 1: return 0
m = self.manacher(s, sn)
s = [1 << 30] * sn
for i in range(sn):
if (self.isP(m, i, 0)): s[i] = 0
else:
for j in range(i):
if (not self.isP(m, i, j+1)):
continue
s[i] = min(s[i], s[j]+1)
return s[sn-1]
if __name__ == "__main__":
s = "abbab"
print(Solution().minCut(s))