LeetCode 分割回文串II(動態規劃)

hestyle發表於2019-02-22

給定一個字串 s,將 s 分割成一些子串,使每個子串都是迴文串。
返回符合要求的最少分割次數。
示例:

輸入: "aab"
輸出: 1
解釋: 進行一次分割就可將 s 分割成 ["aa","b"] 這樣兩個迴文子串。

請先翻閱 LeetCode 分割回文子串
此題就是在上一題將所有分割方法修改為最少的分割次數。
方法一:回溯法。繼續使用上一題的程式碼,只是在dfs函式中新增一個變數記錄分割的次數,並尋找到分割次數最少的分割方法。(但是超時了。。。)

class Solution {
public:
	int minResult = INT_MAX;
	int minCut(string s) {
		if (s == "") {
			return 0;
		}
		dfs(s, 0, 0);//開始搜尋
		return minResult;
	}
	//從beginIndex開始,尋找回文子串
	void dfs(string &str, int beginIndex, int steps) {
		int strSize = str.size();
		if (beginIndex == strSize) {//如果擷取到了尾端,說明尋找到了一個解
			minResult = min(minResult, steps - 1);
			return;
		}
		//對擷取長度進行窮舉
		int endIndex = strSize - 1;
		while (endIndex >= beginIndex) {
			if (isPalindrome(str, beginIndex, endIndex)) {//如果當前擷取的[beginIndex, endIndex]段是迴文串
				dfs(str, endIndex + 1, steps + 1);//以endIndex + 1下標為起始,繼續尋找
			}
			--endIndex;
		}
	}
	//判斷在str串中擷取[beginIndex, endIndex]段是否是迴文串
	bool isPalindrome(string &str, int beginIndex, int endIndex) {
		while (beginIndex < endIndex) {
			if (str[beginIndex++] != str[endIndex--]) {
				return false;
			}
		}
		return true;
	}
};

在這裡插入圖片描述
方法二:動態規劃。

class Solution {
public:
	int minCut(string s) {
		if (s == "") {
			return 0;
		}
		int strSize = s.size();
		vector<vector<bool>> judge(strSize, vector<bool>(strSize, false));//judge[j][i]用於記錄s串[i,j]是否是迴文
		vector<int> dp(strSize, INT_MAX);//dp[i]用於記錄s串中[0, i]需要分割的次數
		for (int i = 0; i < strSize; ++i) {
			for (int j = 0; j <= i; ++j) {//從[j, i]
				if (s[i] == s[j] && (i - j <= 1 || judge[j + 1][i - 1])) {
					judge[j][i] = true;
					if (j != 0) {//如果j == 0,說明[0, i]都是迴文
                        //dp[j - 1] + 1 表示的分割[0, j - 1] + [j, i]需要分割的次數一個解
						dp[i] = min(dp[i], dp[j - 1] + 1);
					}
					else {
						dp[i] = 0;
					}
				}
			}
		}
		return dp[strSize - 1];
	}
};

在這裡插入圖片描述

相關文章