Description

URL: https://oj.leetcode.com/problems/palindrome-partitioning-ii/

Difficulty: 3.0/5.0

Solution

, where . Here $ starts from 1 and min_cut[0] = -1.

The key is that when we use to update , the must already be computed.

The intuitive solution is to first use a 2-D array isPalin[i][j] to record the if is a palindrome, which is in both time and space complexity. Then we compute the min_cut[i] sequentially, the time complexity of which is . So this is a solution with time complexity and space complexity.

class Solution{
private:
	void palinSolver(const string &s, vector<vector<int>>& palin){
		// char as the mid		
		for (int mid = 0, s_end = s.length(); mid < s_end; ++mid){
			int right = mid + 1;
			for (int left = mid -1; left >= 0 && right < s_end; left --, right ++){
				if (s[left] != s[right])
					break;
				palin[right+1].push_back(left+1);
			}
		}
		// gap as the mid
		for (int mid = 1, s_end = s.length(); mid < s_end; ++mid){
			int right = mid;
			for (int left = mid -1; left >= 0 && right < s_end; left --, right ++){
				if (s[left] != s[right])
					break;
				palin[right+1].push_back(left+1);
			}
		}

	}
public:
	int minCut(string s) {
		int num_char = s.length();

		// compute the adjacent list of palindrome
		vector<vector<int>> palin_adj(num_char+1, vector<int>());		
		for (int i = 0; i < num_char+1; ++ i)
			palin_adj[i].push_back(i);
		palinSolver(s, palin_adj);

		vector<int>min_cut(num_char + 1, INT_MAX);
		min_cut[0] = -1;
		for (int i = 1; i < num_char + 1; ++ i){			
			for (int j = 0, end = palin_adj[i].size(); j < end; j ++){				
				if (min_cut[palin_adj[i][j]-1] != INT_MAX)
					min_cut[i] = min(min_cut[i], min_cut[palin_adj[i][j]-1] + 1);
			}
		}
		return min_cut[num_char];

	}
};

Note that instead of using the DP thought isPalin[i][j] = isPalin[i+1][j-1] && (S[i] == S[j]). We can also enumerate the centering position and go to both ends, while checking if S[left] == S[right]. By checking palindrome in this way, we can check if is palindrome for every pair of in time without extra space. The question is: can we embed the min_cut[] computation in this procedure.

In the following code, in the iteration of mid, we only use min_cut[< mid] to update min_cut[>= mid], and after iteration of mid, we will never update min_cut[<= mid]. This guarantees that our computation is right.

This solution is in time complexity and in space complexity.

class Solution {
public:
	int minCut(string s){
		// char as the mid		
		int n_char = s.size();
		vector<int>min_cut(n_char+1, n_char + 1);
		min_cut[0] = -1;

		for (int mid = 0, s_end = s.length(); mid < s_end; ++mid){
			//odd number of chars
			for (int left = mid, right = mid; left >= 0 && right < s_end; left --, right ++){
				if (s[left] != s[right])
					break;				
				//is palin
				min_cut[right+1] = min(min_cut[left]+1, min_cut[right+1]);
			}

			//even number of chars
			for (int left = mid, right = mid+1; left >= 0 && right < s_end; left --, right ++){
				if (s[left] != s[right])
					break;
				//is palin
				min_cut[right+1] = min(min_cut[left]+1, min_cut[right+1]);
			}			
		}
		return min_cut[n_char];

	}
};

Comments