字符串算法

给出一个句子,统计句子中有多少单词

方法1:设计一个标志变量inword表示是否在单词中,如果inword从false变为

true,表明遇到一个单词,统计值count++,每当碰到一个单词的字符,将
inword设置为true,并且在设置之前判断inword是否为false,为false,则将
count++,当碰到空格或者标点符号,将inword设置为false

进一步优化该方法,就是当inword为false并且遇到单词字符,将inword设置为
true,并且count++,否则,如果遇到非单词字符,将inword设置为false。,这
种问题,将所有的情况列举出来,很容易设计。代码写了两种方法,实际上是一

样的。

#include <iostream>
#include <string.h>

int count(const char *str)
{
	if(str == NULL)
		return 0;

	int count = 0;
	bool begin = false;

	while(*str != '\0'){
		if(!begin && isalpha(*str)){
			begin = true;
			count++;
		}

		if(!isalpha(*str))
			begin = false;

		str++;
	}
	return count;
}
int count2(const char *text)
{
	if(text == NULL)
		return 0;

	int count = 0;
	bool inword = false;

	while(*text){
		if(inword == false && isalpha(*text)){
			count++;
			inword = true;
		}else if(!isalpha(*text)){
			inword = false;
		}
		text++;
	}
	return count;
}


int main()
{
	using namespace std;
	const char *str = "haha        xxxxxxxxxxxxx 1aaaa2ccccckkkk.bc";
	char tmp[100];
	strcpy(tmp, str);
	cout<<count(tmp)<<endl;
	cout<<count2(tmp)<<endl;
	getchar();
	return 0;
}


给出单词W1,W2,从W1删除W2中出现的所有字符 

     设计的算法为O(N),将W2中的单词使用hash表存储起来,遍历W1中的字
      符,如果在W2中出现,则不管,否则追加到新的字符串中。本算法采用的
      是128位的bitset,不是hash表。

#include <string>
#include <iostream>
#include <bitset>

void DelCopy(std::string &dest, 
		const std::string &src, const std::string &del) {
	std::bitset<128> cbs; //default construct all bits set zero
	int i = 0;
	for ( i = 0; static_cast<unsigned>(i) < del.size(); i += 1 ) {
		cbs.set(del[i]);
	}

	for ( i = 0; static_cast<unsigned>(i) < src.size(); i += 1 ) {
		if(cbs.test(src[i]) == false) {
			dest.append(1, src[i]);
		}
	}
}

int main ( int argc, char *argv[] )
{
	using namespace std;
	string del = "fuck";
	string src = "abcdefghigkffffffffffffsssssssssuuuuuuuuuuuuuccccccccccckkkkkkkkkkkkki";
	string dest;
	DelCopy(dest, src, del);
	cout << dest << std::endl;
	getchar();
	return 0;
}				/* ----------  end of function main  ---------- */

求字符串的最小回文分割

      问题:给出一个字符串,将其分割成子串,要求每个子串都是回文,子串
      最少是多少个。
      | F[i,j] | 结果                | 结果                              |
      |---------+---------------------+------------------------------|
      |         | 1如果str[i...j]回文 | min{F[i,k]+ F[k+1, j]} |
  
      显然需要从长度最小的字符串开始计算,因为长字符串的回文分割依赖于
短字符串。首先设计一个函数,用于计算str[k+1....j]是否是回文的,然后依次
计算长度为2,长度为3,长度为4的所有字符串的最小回文分割。代码中使用了
Common.h头文件,使用该头文件可以直接打印vector。

//to demeonstrate 
#include <iostream>
#include <vector>
#include <string>
#include <limits.h>
#include "../../Common.h"

bool isP( const char *s, const char *e ) {
	while( s < e ) { 
		if( *s != *e )
			return false;
		s++, e--;
	}
	return true;
}
int minimumPartitionPalindrome( const char *str ) {
	std::string  s(str);
	std::vector<std::vector<int> > mv( 
		s.size(), std::vector<int>( s.size(), 0 ) );

	for( int i = 0; static_cast<unsigned>(i) < s.size(); i++ ) 
		mv[i][i] = 1;

	for( int gap = 1; static_cast<unsigned>(gap) < s.size(); gap++ ) {
		for( int i = 0; static_cast<unsigned>(i) < s.size() - gap; i++ ) {
			if( isP( &s[i], &s[i+gap] ) ) {
				mv[i][i+gap] = 1;
			} else {
				int min = INT_MAX;
				for( int j = i; j < i + gap; j++ ) {
					if( min > mv[i][j] + mv[j+1][i+gap])
						min = mv[i][j] + mv[j+1][i+gap];
				}
				mv[i][i+gap] = min;		
			}
		}
	}
 
	std::cout << mv << std::endl;
	return mv[0][s.size()-1];
}

int main() {
	const char *str = "abacadacd";
	std::cout << minimumPartitionPalindrome( str );
	return 0;
}

移除字符串中的空格

      一、移除所有的空格
      一般的设计都是快慢指针,一个指针指向待插入的位置,一个指针变量字
      符串,忽略空格,将非空格放入待插入的位置。
      二、如果有多个空格,将多个空格变为一个空格
      设置一个标志位inword,当从一个单词字符遇到空格时,inword从true变
      为false,这个时候需要复制空格,其他的情况不需要复制空格,然后遇
      到单词字符,都需要复制

#include <iostream>
#include <string.h>

void removeSpace(char *str)
{
	char *p1 = str, *p2 = str;
	while(1){
		while(*p2 == ' ')
			p2++;
		*p1 = *p2;
		if(*p2 == '\0')
			break;
		p1++, p2++;
	}
}


void removeSpace3(char *str)
{
	char *p = str;

	if(str == NULL)
		return ;

	while(*p){
		if(*p != ' ')
			*str++ = *p;
		p++;
	}
	*str = *p;
}

void remove2Space(char *str)
{
	bool inSpace = false;
	char *cur = str;
	if(str == NULL)
		return ;

	while(*str){
		if(inSpace == false && *str == ' '){
			inSpace = true;
			*cur++ = *str;
		}else if(*str != ' '){
			inSpace = false;
			*cur++ = *str;
		}
		str++;
	}
	*cur = *str;

}

int main()
{
	using namespace std;
	const char *str1 = "    aaaa     ccccccc ";
	char tmp[200];

	strcpy(tmp, str1);
	removeSpace3(tmp);
	cout<<tmp<<endl;
	cout<<str1<<endl;

	strcpy(tmp, str1);
	remove2Space(tmp);
	cout<<tmp<<endl;
	getchar();
	return 0;
}

最长非重复子串

给定字符串S,求解最长没有重复字符的子串。
      假定以j结束的最长子串为S[i..j], 则以j+1的最长非重复子串其开始位
      置不会在i之前,因为如果S[k...j+1],k<i是非重复子串,则S[k...j]必
      定也是非重复子串。
      这样可以通过两个i,j来计算,需要一个长度为128的标志位记录i,,j
      之间出现的字符,前进j,如果j+1所对应的字符已经出现过,则前进i,
      知道j+1对应的字符出现过一次。

#include <iostream>
#include <string>
using namespace std;
string LswithoutRepeat( string &s ) {
	char tmp[128] = { 0 };
	int i = 0;
	int max = 0, start = 0;
	
	for( int j = 0; j < s.size(); j++ ) {
          tmp[s[j]]++;
          while( tmp[s[j]] > 1 ) {
                 tmp[s[i]]--;
                 i++;
          }
          if( max < j - i + 1 ) {
              max = j - i + 1;
              start = i;
          }
	}
	return s.size() == 0 ? "" : s.substr(start, max);
}
int main()
{
	string str = "abcabcbb";
	string str1 = "aabcd";
	string str2 = "";
	cout<<LswithoutRepeat(str)<<endl;
	cout<<LswithoutRepeat(str1)<<endl;
	cout<<LswithoutRepeat(str2)<<endl;
	getchar();
	return 0;
}

最长回文子串

给出一个字符串,求其最长回文连续子串。因为回文子串的对称中心可能
      为S[i],或者S[i],S[i+1],这个主要取决于回文子串的长度为奇数还是
      偶数。由此遍历一遍字符串即可。
int expandAroundMiddle( const string &s, int left, int right )
{
    if( left < 0 || right >= s.size() ) 
        return -1;
    
	while( left >= 0 && right < s.size() && 
           s[left] == s[right] ) {
		left--, right++;
	}
	return right - left - 1;
}

string longestPalindromeSimple( string &s )
{
	int start = -1, longest = 0;
	for( int i = 0; i < s.size(); i++ ){
		int first = expandAroundMiddle( s, i, i );
		int start1 = i - (first - 1) / 2;
		if( first > longest ) {
			longest = first;
			start = start1;
		}
		int second = expandAroundMiddle( s, i, i + 1 );
		int start2 = i - second / 2 + 1;
		if( second > longest ) {
			longest = second;
			start = start2;
		}
	}
	return s.size() == 0 ? "" : s.substr(start, longest);
}

最长公共连续子串

      给定字符串S1,S2,求解最长公共连续子串,可以使用暴力搜索,因为
      最长公共连续子串可以从任意S1[i],S2[j]开始,列举所有S1[i],S2[j]
      开始的最长公共子串即可

      使用动态规划F[i][j]= 1+F[i-1][j-1]或者0,条件分别是S1[i]和S2[j]
      相等或者不相等。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

int bruteForce(const char *a, const char *b, int *max)
{
	assert( a != NULL && b != NULL && max != NULL );
	int maxstart = -1, maxLen = 0;
	int La = strlen(a), Lb = strlen(b);
	
	for( int i = 0; i < La; i++ ) {
		for( int j = 0; j < Lb; j++ ) {
		     int ab = i, bb = j;
		     while( ab < La && bb < Lb && 
					a[ab] == b[bb] ) {
				ab++;
				bb++;
			}
			int curLen = ab - i;
			if( maxLen < curLen ) {
				maxLen = curLen;
				maxstart = i;
			}
		}
	}
	*max = maxLen;
	return maxstart;
}
#define LEN		50
int matrix[LEN][LEN];
void DP(const char *a, const char *b)
{
	assert(a != NULL && b != NULL);
	memset(matrix, 0, sizeof(matrix));
	int La = strlen(a), Lb = strlen(b);
	
	for( int i = 0; i < La; i++ ){
		for( int j = 0; j < Lb; j++ ){
			if( a[i] == b[j] )
			    matrix[i][j] = 1 + (i>0&&j>0 ? 
                             matrix[i - 1][j - 1] : 0);
		}
	}
}


测试代码

void collectOutput(const char *a, const char *b)
{
	assert(a != NULL);
	int max = 0, end = -1;
	int La = strlen(a), Lb = strlen(b);
	
	for( int i = 0; i < La; i++ ) {
		for( int j = 0; j < Lb; j++ ) {
			if( matrix[i][j] > max ){
				max = matrix[i][j];
				end = i;
			}
		}
	}	
	for(int i = 0; i < max; i++){
		printf("%c", a[end - max + 1+ i]);
	}
	printf("\n");
}

void cal(const char *a, const char *b)
{
	int maxLen, maxstart;
	maxstart = bruteForce(a, b, &maxLen);
	for(int i = 0; i < maxLen; i++)
		printf("%c", a[maxstart + i]);
	printf("\n");
}
int main()
{
	const char *a = "caba";
	const char *b = "abac";
	const char *a1 = "abacdfgdcaba";
	const char *b1 = "abacdgfdcaba";
	cal(a, b);
	cal(a1, b1); 
	DP(a, b);
	collectOutput(a, b);
	DP(a1, b1);
	collectOutput(a1, b1);
    getchar();
	return 0;
}

扩展

      类比最长公共子序列,这个问题不要去连续,递推公式
      为:F[i][j]=1+F[i-1][j-1](S1[i]=S2[j])或者
      max{F[i-1][j],F[i][j-1]}

KMP算法

一直想回避这个问题,KMP算法不好讲解清楚,自己理解的也不好



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值