字符串算法

来源:互联网 发布:海尔阿里云电视刷机包 编辑:程序博客网 时间:2024/05/21 22:57

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

方法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 zeroint 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 LEN50int 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算法不好讲解清楚,自己理解的也不好



原创粉丝点击