(3)字符串相关算法题目

    在Java中,字符串是指由一连串字符组成的序列。字符串是final类,不可变,很适合作为Map中的键。string 在做字符串改变等操作时,实际上是先建一个stringbuffer,改变字符串以后再赋值给string。效率上string builder>string buffer>string,string包含太多对中间过程和临时变量,需要垃圾回收,影响效率。同时Java中也提供了stringtokener这样的字符串处理类。

    注意:String a = “a”+”b”+”c”,在方法区只创建了一个对象。

(1)除去字符串中的空格

        算法思路:先遍历原字符串,求得空格个数和字符串长度。计算替换后字符串长度。从后往前一次赋值。

(2)KMP算法-字符串匹配

        算法思路:从主串S的第pos个字符起和模式的第一个字符比较之,若相等,继续逐个比较后续字符。当一趟匹配过程中出现字符比较不等时,不回溯i指针,而是利用已经得到的“部分匹配”的结果将模式串向右“滑动”尽可能远的一段距离后,继续进行比较。时间效率达到T(n) =O(n+m)

        部分匹配和next 数组

        next数字0和1下标的数据分别时0和1 ,其他的为,当某个字符前的字符串的前缀和后缀一致的数量是n,那么这个字符对应的next数组中的位置数据为n+1;

        使用nextval 数组可以加速运算。

        ”A”,当它不匹配时,按照next行回溯到标号1也为字母A,这时再匹配A是徒劳的,因为已知A不匹配,所以就继续退回到标号1字母A的next(1)=0。为了直接点进行优化,就有了nextval行:        

                j=5,P(5)=A,next(5)=1,P(1)=A=P(5),所以nextval(5)=next(1)=0;

                j=6,P(6)=B,next(6)=2,P(2)=B=P(6),所以nextval(6)=next(2)=1;

                j=7,P(7)=D,next(7)=3,P(3)=C!=P(7),所以nextval(7)=next(7)=3;

        代码见:https://github.com/yuanfuqiang456/LeetCode/blob/master/src/String/KMP.java

(3)strcpy

        字符串复制算法,常见于腾讯面试中:

        char * strcpy(char *dst,const char*src)    

        { 

                   if((dst==NULL)||(src==NULL)) 

                           return NULL;  

                   char *ret = dst; //[1] 

                   while ((*dst++=*src++)!='\0'); //[2] 

                   return ret;//[3] 

            }

        注意:const 修饰:源字符串参数用const修饰,防止修改源字符串;

                   空指针检查:源指针和目的指针都有可能会出现空指针的情况,所以应该对其进行检查;

                   为什么要设置ret 指针以及返回ret指针的位置[3],由于目的指针dst已经在进行移动了,所以用辅助指针ret表明首指针;

                    以上所示[2]处,为简单的字符串的复制过程,正好表明strcpy函数遇到'\0'将会停止;

(4)strncpy

        strncpy的功能和strcpy相似,只是它复制时多了一个终止条件。即是未遇到原串的'\0’,如果已经复制了n个字符(n为提供的参数长度),复制同样会终止。

        char* strncpy(char* dest, const char*src, int len) 

        { 

            assert(dest!=NULL &&src!=NULL); 

            char* temp=dest; 

            int i=0; 

            while(i++ < len && (*temp++ = *src++)!='\0') ;

            if(*(temp)!='\0') 

                       *temp='\0'; 

            return dest; 

        }

(5)memcpy

        strncpy只能复制字符串,但memcpy对类型没有要求;strncpy有两个终止条件,memcpy只有一个终止条件,那就是复制n个字节。(n是memcpy的第三个参数);要特别注意目的地址和源地址重合的问题,拷贝前要加以判断。实现这个函数时一般要把原来的指针类型转换成char*,这样每次移动都是一个字节。

        void* mymemcpy(void* dest, void* src,int len) 

        { 

            int i=0; 

            char* tempdest=(char*)dest; 

            char* tempsrc=(char*)src; 

            if(tempdest(tempsrc+len-1)) 

            { 

                       while(i

                       { 

                                   *tempdest++ =*tempsrc++; 

                                   i++; 

                       } 

            } 

            else 

            { 

                       tempdest+=len; 

                       tempsrc+=len; 

                       i=len; 

                       while(i>0) 

                       { 

                                   *tempdest--= *tempsrc--; 

                                   i--; 

                       } 

            } 

            return dest; 

        } 

(6)字符串翻转

        例如how are you ----you are how

        算法思路:首先整个字符串转一遍,其次,每个单词再转一遍

        代码见:https://github.com/yuanfuqiang456/LeetCode/blob/master/src/String/ReverseString.java

(7)字符串包含

        给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短。请问,如何最快地判断字符串B中所有字母是否都在字符串A里?

        算法思路:方法一:逐个字符比较;方法二:先排序A,B中字符,再逐个扫描;方法三:每个字符用一个素数代替,如果可以整除则包含;方法四:hash表。

(8)判断一个字符串是否是回文

        算法思路:从两边往中间逼近或者从中间往两边转。

        代码见:https://github.com/yuanfuqiang456/LeetCode/blob/master/src/String/HuiWen.java

(9)最长回文子串

        又叫对称子字符串的最大长度,输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。

        算法思路:

         方法一:Manacher算法。

                首先通过在每个字符的两边都插入一个特殊的符号,将所有可能的奇数或偶数长度的回文子串都转换成了奇数长度。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。

                此外,为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#。

                以字符串12212321为例,插入#和$这两个特殊符号,变成了 S[] = "$#1#2#2#1#2#3#2#1#",然后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左或向右扩张的长度(包括S[i])。

                比如S和P的对应关系:

                        S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #

                        P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1

                可以看出,P[i]-1正好是原字符串中最长回文串的总长度,为5。

         方法二:字符串A翻转为B,求A和B最长公共字串的长度

(10)第一个只出现一次的字符

        在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。按出现顺序赋值1,2,3,4。方法一:计数排序。辅助数组中出现次数为1 的第一个。找到对应的字符。方法二:使用LinkedhashMap。

(11)在字符串中删除特定的字符

        输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。

        例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”。

        算法思路:先找到待删除内容,用# 标记。求出除#之外的字符串长度。倒序复制。

(12)字符个数的统计

        char *str = "AbcABca"; 写出一个函数,查找出每个字符的个数,区分大小写,要求时间复杂度是n

        算法思路:使用哈希表,遍历一遍原字符串即可

(13)最小子串

        给一篇文章,里面是由一个个单词组成,单词中间空格隔开,再给一个字符串指针数组,比如char*str[]={"hello","world","good"};        

        求文章中包含这个字符串指针数组的最小子串。注意,只要包含即可,没有顺序要求。

        算法思路:文章也可以理解为一个大的字符串数组,单词之前只有空格,没有标点符号。设置两个范围,当前范围和最小范围。交替更新起始位置和终止位置。

(14)最长重复子串

        一个长度为10000的字符串,写一个算法,找出最长的重复子串,如abczzacbca,结果是bc。

        算法思路:从每个字符开始,分别求其后缀,放入hashmap,key为对应后缀,value为出现次数中,需要两次循环遍历;

(15)字符串的压缩

        算法思路:一个字符串,压缩其中的连续空格为1个后,对其中的每个字串逆序打印出来。比如"abc

efg hij"打印为"cba gfe jih"。

(16)字符串的移动

        字符串为+号和26个字母的任意组合,把+号都移动到最左侧,把字母移到最右侧并保持相对顺序不变,要求时间和空间复杂度最小。

        算法思路:字符串翻转

(17)字符串求MOD

        有N个数,组成的字符串,如012345,求出字串和取MOD3==0的子串,如012 12 123 45。

        算法思路:利用前缀数组和后缀数组,并将字符串转为数字。

(18)括号匹配算法

        可以利用队列,队列前后分别为()则可以出(,而)也不必放入,最后看队列中是否还有(或者)。

(19)改变字符串中一组括号的位置,使其括号匹配。

        依次调整,并利用括号匹配算法。

        代码见:https://github.com/yuanfuqiang456/LeetCode/blob/master/src/String/KuoHao.java

你可能感兴趣的:((3)字符串相关算法题目)