给出一个句子,统计句子中有多少单词
方法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对应的字符出现过一次。
假定以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]
相等或者不相等。
最长公共连续子串可以从任意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算法不好讲解清楚,自己理解的也不好