zoukankan      html  css  js  c++  java
  • 字符串笔试题

    1、字符串移位包含问题

    //普通解法
    bool contain_check()
    {
        char s[6] = "AABCD";
        char d[5] = "CDAA";
        int len = strlen(s);
        for(int i=0; i<len; ++i)
        {
           char temp = s[0];
           for(int j=0; j<len-1; ++j)
             s[j] = s[j+1];
           s[len-1] = temp;
           if(strstr(s,d) != 0)
             return true;
        }
        return false;
    }

    寻找规律:对S1做循环移位所得到的字符串都是字符串S1S1的子字符串,如果S2可以由S1循环移位得到,那么S2一定在S1S1上。
    字符串循环同构问题:如果字符串s1可以经过有限次循环得到s2,则称s1和s2是循环同构的。S=s1+s1为主串,s2为模式串。如果s1和s2是循环同构的,那么s2就一定可以在S中找到匹配!

    2、求一个字符串中出现频率最高的那个字符及其出现次数

    空间换时间:使用一个额外的数组统计每个字符出现的次数,再扫描一次得到查找的字符,这是O(N)的时间复杂度。得到字符串第一个无重复的字符也可以用这种方法。

    假设处理的是ASCII字符集:需要注意 char的范围是[-128,127]之间,所以数组下标要加上128

    void get_most(char *s, char &ch, int &size)
    {
        ch = '\0';
        size = 0;
        if (NULL != s)
        {
            int n[256];
            memset(n, 0, sizeof(n));
            while(*s != '\0')
            {
                n[*s+128] += 1;
                if((n[*s+128]) > size)
                {
                    size = n[*s+128];
                    ch = *s;
                }
                s++;
            }
        }
    }

    3、给一个字符串,有大小写字母,要求写一个函数把小写字母放在前面,大写字母放在后面,尽量使用最小的空间、时间复杂度。

    void move_char(char* a)
    {
        char* i = a;
        char* j = a+strlen(a)-1;
        while(i < j)
        {
            while(*i && (*i>='a' && *i<='z'))
                ++i;
            if((*i) == '\0') break;
            while(*j>='A' && *j<='Z')
                --j;
            if(i < j)
            {
                char c = *i;
                *i = *j;
                *j = c;
            }
            ++i; --j;
        }
    }

    4、编写字符串处理函数,将字符串中的字符'*'移到串的前部分,前面的非'*'字符后移,但不能改变非'*'字符的先后顺序,函数返回串中字符'*'的数量。如原始串为:ab**cd**e*12,处理后为*****abcde12,函数并返回值为5。(要求使用尽量少的时间和辅助空间)

    int partitionStar(char a[],int len)
    {
        int count = 0;
        int i = len-1;
        int j = len-1; //j指向第一个'*'
        while(i >= 0)
        {
            if (a[i] !=  '*')
            {
                swap(a[i--], a[j--]);
            }
            else
            {
                i--; count++;
            }
        }
        return count;
    }

    5、删除字符串中的数字并压缩字符串。如字符串"abc123de4fg56"处理后变为"abcdefg"。注意空间和效率。

    (下面的算法只需要一次遍历,不需要开辟新空间,时间复杂度为O(N))

    char* delete_digits(char* str)
    {
        char* i = str; // i for cursor, j for the first digit char;
        char* j = str;
        while(*i != '\0')
        {
            if (*i<'0' || *i>'9')
            {
                *j++ = *i++;
            }
            else
            {
                ++i;
            }
        }
        *j ='\0';
        return str;
    }

    6、删除特定字符:写一个高效的函数,删除字符串里给定的字符

    void Remove_chars(char str[], char remove[])
    {
        int remove_arr[256];
        for(int i=0; i<256; ++i)
            remove_arr[i] = 0;
        for(int i=0; remove[i]; ++i)
            remove_arr[remove[i]] = 1;
        int i = 0;
        for(int j=0; str[j]; ++j)
        {
            if(!remove_arr[str[j]])
                str[i++] = str[j];
        }
        str[i]='\0';
    }

    7、编码实现字符串转整型的函数(实现函数atoi的功能)。如将字符串“123”转化为123,“-0123”转化为-123

    int str_to_int(const char* str)
    {
        int is_neg = 0, num = 0;
        const char * p = str;
        if (*str == '-')
        {
            is_neg = 1;
            ++ p;
        }
        while(*p >= '0' && *p <= '9')
        {
            num = num * 10 + (*p-'0');
            ++ p;
        }
        if(is_neg)
            num *= -1;
        return num;
    }

    编码实现整型转字符串的函数

    //整数最大的位数
    #define MAX_DIGITS_NUM 10
    void int_to_str(int num,char str[])
    {
        int i = 0, j = 0, is_neg = 0;
        char temp[MAX_DIGITS_NUM+2];
        if(num < 0)
        {
            num *= -1;
            is_neg = -1;
        }
        //使用do while循环可以处理num为0的情况
        do
        {
            temp[i++] = (num%10)+'0';
            num /= 10;
        }while(num);
    
        if(is_neg)
            temp[i++] = '-';
        while(i > 0)
            str[j++] = temp[--i];
        str[j] = '\0';
    }

    8、翻转句子中单词的顺序

    题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如输入“I am a student.”,则输出“student. a am I”。 分析:先颠倒句子中的所有字符,再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持一致。

    void Reverse(char *pBegin, char *pEnd)
    {
          if(pBegin == NULL || pEnd == NULL)
                return;
          while(pBegin < pEnd)
          {
                char temp = *pBegin;
                *pBegin = *pEnd;
                *pEnd = temp;
                pBegin ++, pEnd --;
          }
    }
    
    char* ReverseSentence(char *pData)
    {
          if(pData == NULL)
                return NULL;
    
          char *pBegin = pData;
          char *pEnd = pData;
    
          while(*pEnd != '\0')
                pEnd ++;
          pEnd--;
    
          // Reverse the whole sentence
          Reverse(pBegin, pEnd);
    
          // Reverse every word in the sentence
          pBegin = pEnd = pData;
          while(*pBegin != '\0')
          {
                if(*pBegin == ' ')
                {
                      pBegin ++;
                      pEnd ++;
                      continue;
                }
                // A word is between with pBegin and pEnd, reverse it
                else if(*pEnd == ' ' || *pEnd == '\0')
                {
                      Reverse(pBegin, --pEnd);
                      pBegin = ++pEnd;
                }
                else
                {
                      pEnd ++;
                }
          }
    
          return pData;
    }

    9、求字符串的最长重复子串:构造字符串的后缀数组,对后缀数组排序,再两两比较得到最长的重复子串

    //compare funciton used by qsort()
    int pstrcmp(const void *p, const void *q)
    {
        return strcmp(*(char **)p, *(char **)q);
    }
    
    //get max common length of string p and q
    int comlen(char *p, char *q)
    {
        int i = 0;
        while (*p && (*p++ == *q++))
            i++;
        return i;
    }
    
    //get max repeat substring of str 
    int find_max_repeat(char* str, char* result, int & len)
    {
        int temlen, maxi, maxlen = -1;
        char *a[99999];
        int n = 0;
    
        while (*str != '\0')
        {
            a[n++] = str++;
        }
        qsort(a, n, sizeof(char *), pstrcmp);
        for (int i = 0; i < n-1; i++)
        {
            temlen = comlen(a[i], a[i+1]);
            if (temlen > maxlen)
            {
                maxlen = temlen;
                maxi = i;
            }
        }
        result = a[maxi];
        len = maxlen;
        printf("%.*s\n", maxlen, result);
        return maxlen;
    }

    10、字符串字母包含问题:有一个各种字母组成的字符串,还有一个字母数目较少的字符串,什么方法能最快的查出所有小字符串里的字母在大字符串里都有?

      最简单的方法:轮询小字符串里的每个字母,看它是否同在第一个字符串里。这需要O(n*m)次操作,其中n是string1的长度,m是string2的长度。

      一个改进的方法:对这两个字符串的字母进行排序,然后同时对两个字串依次轮询。两个字串的排序需要(常规情况)O(mlogm)+ O(nlogn)次操作,之后的线性扫描需要O(m+n)次操作。(随着字串长度的增长,你会发现这个算法的效果会越来越好)

      一个很好的方法:只需要O(n+m)次操作。对第一个长字串进行轮询,把其中的每个字母都放入一个Hashtable里(成本是O(n)次操作)。然后轮询第二个字串,在Hashtable里查询每个字母,看能否找到,如果找不到,说明没有匹配成功,这将消耗掉O(m)次操作。

      一个更有趣的方法:对一个一定个数的字母组成的字串,给每个字母分配一个素数,从2开始,往后类推。这样A将会是2,B将会是3,C将会是5,等等。现在先遍历第一个字串,把每个字母代表的素数相乘,会得到一个很大的整数。然后——轮询第二个字符串,用每个字母代表的素数除它。如果除的结果有余数,这说明有不匹配的字母,如果整个过程中没有余数,你应该知道它是第一个字串恰好的子集了。

    11、求一个字符串的最长的没有重复字符的子串。

    方法一:穷举法,使用2重外循环遍历所有的区间,用2重内循环检验子串是否符合“无重复字符”这一要求。其中外层循环i、j 遍历所有的下标,m、n是内层循环,检查区间[i,j]是否符合要求。空间复杂度是O(1),时间复杂度O(N^4)。

    方法二:对方法一的检验子串是否“无重复字符”进行改进,使用hash表记录字符是否出现过。

    方法三:使用DP,对于最长不重复子串,某个当前的字符,如果它与前面的最长不重复子串中的字符没有重复,那么就可以以它为结尾构成新的最长子串;如果有重复,那么就与某个稍短的子串构成新的子串或者单独成一个新子串。

    方法四:对这个字符串构造后缀数组,在每个后缀数组中,寻找没有重复字符的最长前缀,就是要找的子串。

    详解:http://www.cnblogs.com/luxiaoxun/archive/2012/10/02/2710471.html

    12、求一个字符串中连续出现次数最多的子串

    int count = 0; 
    char sub_str[256]; 
     
    void find_str(char *str) 
    { 
        int str_len = strlen(str); 
        int i, j, k; 
        int tmp_cnt = 0; 
        
        for(i = 0; i < str_len; i++) 
        { 
            for(j = i+1; j < str_len; j++) 
            { 
                int n = j-i;   //sub string length 
                tmp_cnt = 1; 
                if(strncmp(&str[i], &str[j], n) == 0)   //compare n-lengths strings 
                { 
                    tmp_cnt++;                          //they are equal, so add count 
                    for(k = j+n; k < str_len; k += n)  //consecutive checking 
                    { 
                        if(strncmp(&str[i], &str[k], n) == 0) 
                        { 
                            tmp_cnt++; 
                        } 
                        else 
                            break; 
                    } 
                    if(count < tmp_cnt) 
                    { 
                        count = tmp_cnt; 
                        memcpy(sub_str, &str[i], n); //record the sub string 
                    } 
                } 
            } 
        } 
    } 

    13、寻找包含给定字符集合的最短子串:字符串S="abcdefg",字符集合D={'c','f'},那这个最小子串为S'="cdef"。

    //判断hash是否包含所有的hash_sub
    int has_sub(int * hash, int * hash_sub)
    {
        for(int i=0; i<256; ++i)
        {
            if(hash_sub[i] && !hash[i])
                return 0;
        }
        return 1;
    }
    
    //在str中寻找包含dst的最短子串
    int min_substring(char * str, char * dst)
    {
        char * begin = str;
        char * end = str;
        char * begin_index = NULL;
        int minlen = strlen(str);
        int hash[256];
        int hash_sub[256];
        memset(hash,0,sizeof(hash));
        memset(hash_sub,0,sizeof(hash_sub));
        for(int i=0; dst[i]; ++i)
            hash_sub[dst[i]] = 1;
        hash[*begin] = 1;
        while(*end)
        {
            while(!has_sub(hash,hash_sub) && *(end+1))
            {
                ++ end;
                hash[*end] = 1;
            }
            while(has_sub(hash,hash_sub))
            {
                if(end-begin+1 < minlen)
                {
                    minlen = end-begin+1;
                    begin_index = begin;
                }
                if (*begin != *(begin+1))
                {
                    hash[*begin] = 0;
                }
                //hash[*begin] = 0;
                ++ begin;
            }
            if(*(end+1) == '\0') break;
        }
        printf("%.*s\n", minlen, begin_index);
        return minlen;
    }

    14、递归求解一个字符串中连续单个字符出现最多次数字符的个数

    int max_count;
    void count(const char *s)
    {
        if(!(*s)) return;
        const char * p = s+1;
        int n = 1;
        while(*p && *p == *s)
        {
            ++ n;
            ++ p;
        }
        if(n > max_count) max_count = n;
        count(s+1);
    }
  • 相关阅读:
    毫秒级从百亿大表任意维度筛选数据,是怎么做到的...
    编译时异常和运行时异常的区别
    ajax同步与异步的区别
    jdk、jre、jvm三者联系
    java可变参数
    String 堆内存和栈内存
    构造方法
    为什么成员变量不用先初始化
    Javascript 创建对象方法的总结
    Java四种读取和创建XML文档的例子教程
  • 原文地址:https://www.cnblogs.com/luxiaoxun/p/2766095.html
Copyright © 2011-2022 走看看