一、概述
字符串的处理几乎无处不在,算法的形式各种各样,各种巧妙的算法都有一个共同的特点-抓住问题的特点,一些智力题目也是,跟蜡烛相关的题很可能会用到蜡烛可以两头同时点燃,跟灯泡相关的,会用到灯开时间长了会发热等各种隐含的特点。推广到字符串,字符串有什么特点?
1. 由固定数目的字符组成
即使加上各种奇形怪状的符号,最大也不会超过256个。0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),32~126(共95个)是字符(32sp是空格),其中48~57为0到9十个阿拉伯数字,65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。
2.每个字符有对应的ascii值
3.以'\0'结尾(有长度)
貌似是绝大多数人都知道的3个特点,如果把握住有很多问题就会很好的解决,下面一部分举出相关的例子。
上ascii表
二、相关算法
1)删除一个字符串中在另外一个字符串中出现的字符,例如字符串1 ”hello world“,字符串2 “oo”,删除1中的两个o字符,则删除后,字符串1变为"hell wrld"
利用字符串的第一个特点“有限的字符组成”,可以用一个大小为256(128也可以,一般可显示的都在128之内)整型的数组,存储的时候用到字符串的第二个特点,“每个字符都有对应的ascii”,统计出字符串2中各各字符的个数,然后按照这个统计的数目来删除字符串中特定的字符。
删除某个字符的时候,一般想法就是后面一个字符向前面一个一个的拷贝一直到'\0',但是这样效率有点底下,这时可以利用字符串第三个特点“有长度”,计算出字符串的长度(特别注意,并不是每次都计算一遍,而是计算一遍之后存储来下,维护这个变量,如果每次都用strlen()计算长度,那么在strlen()中也是一个一个数一直数到'\0'的,效率也低),然后用利用一个memcpy()函数一次性整体拷贝,效率就大大的提高了,代码如下:
#include <stdio.h>
#include <string.h>
#include <assert.h>
int delete_from_str(char *src, char *delete);
int main(int argc, char *argv[])
{
char src[] = "hello world";
char delete[] = "oo";
delete_from_str(src, delete);
printf("after delete src is %s\n", src);
return 0;
}
int delete_from_str(char *src, char *delete)
{
assert((src !=NULL) && (delete != NULL));
char delete_count[256] = {0};
while(*delete)
{
delete_count[*delete]++;
delete++;
}
int i=0;
int src_len = strlen(src)+1;
while(src[i])
{
if(delete_count[src[i]] > 0)
{
delete_count[src[i]]--;
memcpy(&src[i], &src[i+1], src_len);//memcpy后,src[i]需要重新判断是否要删除,因为是以前src[i+1]的字符,所以这里面不需要i++
src_len--;
}
else
{
i++;
src_len--;
}
}
return 0;
}
这个题目用到了全部的三个特点,但不不是三个特点就只能这样运用。还有一些题目也差不多,像什么统计一个字符串中字符的个数。下面一个题目将介绍一种对特点的另外一种用法。
2)大概是这样的,如果有字符串"hello"和字符串"hlelo",它们组成的字符完全相同只是顺序不同,那么说这两个字符串是相似的,写一个函数判断两个字符串是不是相似的,要求尽量少的使用存储空间。
也可以按照第一题的方法,求出两个字符串对应的每个整型的每个字母出现的次数的数组,然后在比较这两个数组是不是完全的相等,但是还是要了两个存储的空间。还有一种方法,利用第二个特征,每个字符都对应着一个ascii,也就是一个正整数,那么,如果是整数的话就可以按照数的操作来判断了,这时后就有了一个非常重要的特性,字符串可以排序,所以算法出来了,可以把每个字符串都排序,比较两个字符串排序后是否相等,这时候可采用就地排序的算法从而对存储空间使用减少。代码如下:
#include <stdio.h>
#include <assert.h>
#include <string.h>
void maopao_sort(char *str, int len);
int str_similar(char *str1, char *str2);//返回0相似,-1不相似
int main(int argc, char *argv[])
{
char str1[] = "worldhello";
char str2[] = "whloorldel";
if(0 == str_similar(str1, str2))
printf("the two strings are similar\n");
else
printf("the two strings are not similar\n");
return 0;
}
void maopao_sort(char *str, int len)
{
int i;
int j;
for(j = len-1; j>0; j--)
for(i = 0; i<j; i++ )
{
if(str[i] > str[i+1])
{
char temp;
temp = str[i+1];
str[i+1] = str[i];
str[i] = temp;
}
}
}
int str_similar(char *str1, char *str2)
{
int len_str1 = strlen(str1);
int len_str2 = strlen(str2);
maopao_sort(str1, len_str1);
maopao_sort(str2, len_str2);
if(0 == strcmp(str1, str2))
return 0;
return -1;
}