1.Minimal Number of Palindromes on a String(dp)

题目描述:题目来自http://codercareer.blogspot.com/2013/02/no-43-minimal-number-of-splits-on-string.html

Problem: 

A string can be partitioned into some substrings, such that each substring is a palindrome. For example, there are a few strategies to split the string “abbab” in to palindrome substrings, such as: “abba”|”b”, “a”|”b”|”bab” and “a”|”bb”|”a”|”b”.


Given a string str, please get the minimal numbers of splits to partition it into palindromes. The minimal number of splits to partition the string “abbab” into a set of palindromes is 1.


本人代码:

#include <iostream>
#include <string>
#include <string.h>
using namespace std;

bool isP(const string str,int i,int j)
{
	while(i<j)
	{
		if(str[i++]!=str[j--])
			return false;
	}
	return true;
}

int dp[100];

int main()
{
	string str;
	cin>>str;
	memset(dp,0,sizeof(dp));

	int end=str.size()-1;
	for(int i=0;i<=end;i++)
	{
		if(isP(str,0,i))
		{
			dp[i]=0;
		}
		else
		{
			int min=0x7FFFFFFF;
			for(int j=1;j<=i;j++)
			{
				if(isP(str,j,i))
				{
					if(min>dp[j-1]+1)
						min=dp[j-1]+1;
				}
			}
			dp[i]=min;
		}
	}
	cout<<dp[end]<<endl;
	return 0;
}







Harry He 的分析:

Analysis: This is a typical problem which can be solved by dynamic programming. We have two strategies to analyze and solve this problem

Solution 1: Split at any space between two characters

Given a substring of  str, starting from the index  i and ending at the index  (denoted as  str[ i: j]), we define a function  f( ij) to denote the minimal number of splits to partition the substring  str[ i: j] into a set of palindromes. If the substring is a palindrome itself, we don’t have to split so  f( ij) is 0. If the substring is not a palindrome, the substring is split between two characters  k and  k+1.  f( ij)=  f( i, k)+  f( k+1,  j)+1 under such conditions. Therefore,  f( ij) can be defined with the following equation:

<!--[if !msEquation]--> <!--[if !vml]--><!--[endif]--><!--[endif]-->



The value of  f(0,  n-1) is the value of the minimal number of splits to partition  str into palindromes, if n is the length of  str.

If the equation is calculated recursively, its complexity grows exponentially with the length  n. A better choice is to calculate in bottom-up order with a 2D matrix with size  n× n. The following C++ code implements this solution:

int minSplit_1( const string& str)
{
     int length = str.size();
     int* split =  new  int[length * length];
   
     for( int i = 0; i < length; ++i)
        split[i * length + i] = 0;

     for( int i = 1; i < length; ++i)
    {
         for( int j = length - i; j > 0; --j)
        {
             int row = length - i - j;
             int col = row + i;
             if(isPalindrome(str, row, col))
            {
                split[row * length + col] = 0;
            }
             else
            {
                 int min = 0x7FFFFFFF;
                 for( int k = row; k < col; ++k)
                {
                     int temp1 = split[row * length + k];
                     int temp2 = split[(k + 1) * length + col];
                     if(min > temp1 + temp2 + 1)
                        min = temp1 + temp2 + 1;
                }
                split[row * length + col] = min;
            }
        }
    }

     int minSplit = split[length - 1];
     delete[] split;
     return minSplit;
}

Solution 2: Split only before a palindrome

We split the string  str with another strategy. Given a substring ending at the index  istr[0, i], we do not have to split if the substring is a palindrome itself. Otherwise it is split between two characters at index  j and  j+1 only if the substring  str[ j+1, i] is a palindrome. Therefore, an equation  f( i) can be defined as the following:
<!--[if !msEquation]--> <!--[if !vml]--><!--[endif]--><!--[endif]-->




The value of  f( n-1) is the value of the minimal number of splits to partition  str into palindromes, if  nis the length of  str.

We could utilize a 1D array to solve this equation in bottom-up order, as listed in the following code:

int minSplit_2( const string& str)
{
     int length = str.size();
     int* split =  new  int[length];
     for( int i = 0; i < length; ++i)
        split[i] = i;

     for( int i = 1; i < length; ++i)
    {
         if(isPalindrome(str, 0, i))
        {
            split[i] = 0;
             continue;
        }

         for( int j = 0; j < i; ++j)
        {
             if(isPalindrome(str, j + 1, i) && split[i] > split[j] + 1)
                split[i] = split[j] + 1;
        }
    }

     int minSplit = split[length - 1];
     delete[] split;
     return minSplit;
}

Optimization to verify palindromes:

Usually it costs O( n) time to check whether a string with length  n is a palindrome, and the typical implementation looks like the following code:

bool isPalindrome( const string& str,  int begin,  int end)
{
     for( int i = begin; i < end - (i - begin); ++i)
    {
         if(str[i] != str[end - (i - begin)])
             return  false;
    }

     return  true;
}

Both solutions above cost O( n 3) time. The first solution contains three nesting for-loops. The function isPalindrome is inside two nesting for-loops.

If we could reduce the cost of isPalindrome to O(1), the time complexity of the second solution would be O( n 2).

Notice that the substring  str[ i, j] is a palindrome only if the characters at index  i and  j, and  str[ i+1, j-1] is also a palindrome. We could build a 2D table accordingly to store whether every substring of str is a palindrome or not during the preprocessing. With such a table, the function isPalindrome can verify the substring  str[ i, j] in O(1) time.

More coding interview questions are discussed in my book <Coding Interviews: Questions, Analysis & Solutions>. You may find the details of this book on  Amazon.com, or  Apress.

The author Harry He owns all the rights of this post. If you are going to use part of or the whole of this ariticle in your blog or webpages, please add a reference to http://codercareer.blogspot.com/. If you are going to use it in your books, please contact him via zhedahht@gmail.com . Thanks.










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值