zoukankan      html  css  js  c++  java
  • Palindrome II

    Problem Statement

    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.

    First we need to give some definitions. Then

    Define

    • $cut[k]$ to indicate the minimum number of cuts of the first $k$ characters in string $s$, {$s_0, s_1, ..., s_{k-1}$}.
    • Thus, the index of cut is one more than index of s, which means the number of minimum cut of {$s_0, ..., s_i$} will be stored at $cut[s_i]$, or $cut[i+1]$. For simplicity, we use the terminology minimum cut of $s_i$ to indicate minimum cut of {$s_0, ..., s_i$}.
    • So the problem can be expressed to compute $cut[n]$. 

    Obviously, the initial $cut[i]$ should be $i - 1$. Because every node itself is a palindrome. Thus $n$ nodes at most need $n-1$ partitions:

    for(int i = 0; i < n; ++i)
        cut[i] = i - 1; 
    

    At first sight, the assignment $cut[0] = -1$ seems like a garbage value, but later we will explain it's very useful to assign $cut[0]$ to -1 to complete our problem.

    In order to find some intuitions, let's think about the minimum cut of string {$s_0, s_1, ..., s_i$} with $cut[i+1]$ partitions.

    Denote the cut like: {$s_0, s_1, ..., s_i$} = {$P_1, P_2, ..., P_k$} =
    {
    {$s_0, s_1, ..., s_{n_1}$},
    {$s_{n_1+1}, s_{n_1+2}, ..., s_{n_2}$},
    {...},
    ....,
    {$s_{n_{k-2}+1}, s_{n_{k-2}+2}, ..., s_{n_{k-1}}$},
    {$s_{n_{k-1}+1}, s_{n_{k-1}+2}, ..., s_{n_k}$}
    }.

    Immediately, we can get

    1. The node $s_i$ must be in $P_k$ with $s_i = s_{n_k}$. And $P_k$ is a palindrome.
    2. Also, consider the node $s_{n_{k-1}}$. We can state that {$P_1, P_2, ..., P_{k-1}$} is also the minimum cut of string {$s_0, s_1, ..., s_{n_{k-1}}$}.
      (Otherwise, we can use {$s_0, s_1, ..., s_{n_{k'}}$}'s minimum cut {$P_1', P_2', ..., P_{k-1}'$} $cup$ {$P_k$} to get {$s_0, s_1, ..., s_i$}'s smaller cut, which contradicates to {$P_1, P_2, ..., P_k$}'s minimum.)
    3. Based on the above two statements, we also get $k = (k-1) + 1$, which means $cut[s_i] = cut[s_{n_{k-1}}] + 1$, or $cut[i+1] = cut[n_{k-1}+1] + 1$.
    4. The situation that the whole string {$s_0, ..., s_i$} is palindrome, i.e., $P_k =$ {$ s_0, ..., s_i $}, $P_{k-1} = emptyset$ and $cut[i] = 0$, is also included.
      As the deductions above, $cut[i] = cut[s_{-1}] + 1 = cut[0] + 1 = -1 + 1 = 0$, which matches the result of our problem.
    5. Point 4 also explains that the initial assignment of cut[0] = -1 is useful and meaningful.

    From these insights, we can get that for every minimum partition, let's say node $s_i$'s minimum cut, there exists some $j$, where $j leq i$, such that

    $s_i$'s minimum cut =

    {$s_0, s_1, ..., s_{j-1}$}'s minimum cut

    $cup$

    {$s_j, ..., s_i$}, where {$s_j, ..., s_i$} is a palindrome.

    Thus, if we test a palindrome {$s_p, ..., s_q$}, it may be the minimum partition's last part $P_k$. So we may have a chance to update $s_q$'s minimum cut, i.e. updating cut[q+1] by $cut[s_q] = min(cut[s_q], cut[s_{p-1}]+1)$

    if(isPalindrome(s, p, q))
        cut[q+1] = max(cut[q+1], cut[p]+1)
    

    As every node $s_i$'s $cut[i+1]$ can only be affected by its previous nodes, we can systematically detect palindrome and then update $cut[i+1]$ from the beginning of string s.

    for(int point = 0; point < n; ++point){
        //detect palindrome and update cut[i]
        ...
    }
    

    For every node $s_i$, we consider palindrome centralized at $s_i$. Of course, there may be two cases of palindrome centralized at $s_i$:

    • [$s_{i-j}, ..., s_i, ..., s_{i+j}$] with odd length $2j+1$.
    • [$s_{i-(j-1)}, ..., s_i, s_{i+1}, ..., s_{i+j}$] with even length $2j$

    We can expand the half length $j$ from zero until it reaches the boundary $s_0$ or $s_{n-1}$. And once the expansion of length stops at some length $j'$, there won't exist palindrome centralized at $i$ with length greater than $j'$.

    // odd length
    for(int halfLength = 0; point-halfLength >= 0 && point+halfLength < n && s[point-halfLength] == s[point+halfLength])
        cut[point+halfLength+1] = min(cut[point+halfLength+1], cut[point-halfLength]+1);
        
    // even length
    for(int halfLength = 1; point-halfLength+1 >= 0 && point+halfLength < n && s[point-halfLength+1] == s[point+halfLength])
        cut[point+halfLength+1] = min(cut[point+halfLength+1], cut[point-halfLength+1]+1)
    

    or if we use $i$ denote central point, and $j$ denote half length, we can get a piece of simply code:

    for (int i = 0; i < n; ++i){
        //odd length
    	for (int j = 0; i-j >= 0 && i+j < n && s[i-j] == s[i+j]; ++j)
    	    cut[i+j+1] = min(cut[i+j+1], cut[i-j]+1);
    
    	//even length
    	for (int j = 1; i-j+1 >= 0 && i+j < n && s[i-j+1] == s[i+j]; ++j)
            cut[i+j+1] = min(cut[i+j+1], cut[i-j+1]+1);
    }
    

    The complete code is:

    int minCut(string s) {
        int n = s.size();
    	if(n <= 1) return 0;
    
    	vector<int> cut(n+1, 0);
    
    	for (int i = 0; i <= n; i++) 
    		cut[i] = i-1;
    
    	for (int i = 0; i < n; ++i)
    	{
    		//odd length, i.e. i is the middle point, [i-j, ..., i, ..., i+j];
    		for (int j = 0; i-j >= 0 && i+j < n && s[i-j] == s[i+j]; ++j)
    		    cut[i+j+1] = min(cut[i+j+1], cut[i-j]+1);
    
    		//even length, i.e. i is left side's endpoint, [i-(j-1), ..., i, i+1, ..., i+j];
    		for (int j = 1; i-j+1 >= 0 && i+j < n && s[i-j+1] == s[i+j]; ++j)
    		    cut[i+j+1] = min(cut[i+j+1], cut[i-j+1]+1);
    	}
    
    	return cut[n];
    }
    

    The running time is about two parts. The first is the assignment of $cut[i]$, $O(n)$.

    The second part is divided by two for loop:

    • $O(1 + 2 + 3 + 4 + ... + n/2) = O(n^2)$ 
    • $O(1 + 2 + 3 + 4 + ... + n/2) = O(n^2)$

    So the total running time is $O(n^2)$.

    And obviously the space is $O(n)$.

  • 相关阅读:
    【Rollo的Python之路】Python 编码与解码
    【Rollo的Python之路】Python 队列 学习笔记 queue
    【Rollo的Python之路】Python 同步条件 学习笔记 Event
    【Rollo的Python之路】Python 条件变量同步 学习笔记 Condition
    【Rollo的Python之路】Python 信号量 学习笔记 Semaphore
    十天冲刺-09
    十天冲刺-08
    十天冲刺-07
    十天冲刺-06
    十天冲刺-05
  • 原文地址:https://www.cnblogs.com/kid551/p/4114989.html
Copyright © 2011-2022 走看看