Leetcode_1278. Palindrome Partitioning III_[DP]
You are given a string s
containing lowercase letters and an integer k
. You need to :
- First, change some characters of
s
to other lowercase English letters. - Then divide
s
intok
non-empty disjoint substrings such that each substring is palindrome.
Return the minimal number of characters that you need to change to divide the string.
Example 1:
Input: s = "abc", k = 2 Output: 1 Explanation: You can split the string into "ab" and "c", and change 1 character in "ab" to make it palindrome.
Example 2:
Input: s = "aabbc", k = 3 Output: 0 Explanation: You can split the string into "aa", "bb" and "c", all of them are palindrome.
Example 3:
Input: s = "leetcode", k = 8 Output: 0
Constraints:
1 <= k <= s.length <= 100
.s
only contains lowercase English letters.
解法:
由Leetcode_132. Palindrome Partitioning II解法,这道题可以有一个比较清晰的思路。
动态规划:dp[idx][k]表示将s[idx : s.size())这个子串划分为k个非空回文子串最少需要改变的字符数。
递归关系:dp[0][k] = min( f(0,idx-1) + dp[idx][k-1]), for idx in [0, s.size()-1],
其中 f(0,idx-1) == 0 if(s[0,idx-1] is palendrome),else f(0,idx-1) == number of chars that have to change.
需要注意,对于dp[idx][k],如果s.size()-idx < k,那么无论如何也不能将s[idx, s.size()-1]划分为k个回文子串。
class Solution { public: vector<vector<bool>> is_palindrome; vector<vector<int>> dp; int palindromePartition(string s, int k) { int len = s.size(); is_palindrome = std::move(vector<vector<bool>>(len, vector<bool>(len, false))); dp = std::move(vector<vector<int>>(len, vector<int>(k+1, INT_MAX))); for(int l=1; l<=len; l++) for(int head=0; head+l-1<len; head++){ int tail = head+l-1; if(l == 1) is_palindrome[head][head] = true; else if(l == 2) is_palindrome[head][tail] = s[head]==s[tail]; else is_palindrome[head][tail] = (s[head]==s[tail] && is_palindrome[head+1][tail-1]); } dfs(s, 0, k); return dp[0][k]; } int dfs(string &s, int idx, int k){ if(idx == s.size()) return k==0 ? 0 : s.size(); if(dp[idx][k]<INT_MAX) return dp[idx][k]; int ret = s.size()+1; for(int l=1; idx+l-1+k-1<s.size(); l++){ int behind = dfs(s, idx+l, k-1), use = 0; if(!is_palindrome[idx][idx+l-1]){ for(int head=idx, tail=idx+l-1; head<tail; head++, tail--) use += s[head]!=s[tail] ? 1 : 0; } ret = min(ret, use+behind); } return dp[idx][k] = ret; } };