字符串相关算法

一、概述

字符串的处理几乎无处不在,算法的形式各种各样,各种巧妙的算法都有一个共同的特点-抓住问题的特点,一些智力题目也是,跟蜡烛相关的题很可能会用到蜡烛可以两头同时点燃,跟灯泡相关的,会用到灯开时间长了会发热等各种隐含的特点。推广到字符串,字符串有什么特点?

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;

}


 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值