字符串笔试题

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);
}

 

作者:阿凡卢

出处:http://www.cnblogs.com/luxiaoxun/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

http://www.cnblogs.com/luxiaoxun/archive/2012/11/12/2766095.html

时间: 2024-08-28 03:32:48

字符串笔试题的相关文章

一道有趣的字符串笔试题 以及队列问题笔试题

问题描述 1. 请完成函数,该函数输入一个纯英文字符串,请打印出该字符串中每个字符(区分大小写)出现的次数,并按照出现的次数从大到小排列,如输入"asisaB",则打印出a=2,s=2,i=1,B=1. 注:要求不能使用如Map,List等集合类. 2.使用Java实现阻塞队列BlockQueue,请插入数据调用Offer,如果已满则等待.获取数据调用take,如果队列为空,则等待.请完成该类 请高人写出程序代码 加有些详细注解更佳 谢谢!!!!!!!!!!!!!!!!! 解决方案 第

C++笔试题汇总(45题)

本文转自:<程序员必看c++笔试题汇总>,经过整理正文如下: 本文通过对程序员笔试过程的总结,对程序员c++笔试题进行了汇总.希望能与大家共同分享.下面是一些常见题型: 1.求下面函数的返回值(微软) { int countx = 0; while(x) { countx ++; x = x&(x-1); } return countx; } 假定x = 9999. 答案:8 思路:将x转化为2进制,看含有的1的个数. 2. 什么是"引用"?申明和使用"引

程序员必看 c++笔试题汇总

本文通过对程序员笔试过程的总结,对程序员c++笔试题进行了汇总.希望能与大家共同分享.下面是一些常见题型: 1.求下面函数的返回值(微软) {   int countx = 0;   while(x)   {   countx ++;   x = x&(x-1);   }   return countx;   }  假定x = 9999. 答案:8 思路:将x转化为2进制,看含有的1的个数. 2. 什么是"引用"?申明和使用"引用"要注意哪些问题? 答:引用

一道阿里巴巴海量数据笔试题

问题描述 在看到的一道笔试题:搜索引擎的日志要记录所有查询串,有一千万条查询,不重复的不超过三百万.要统计最热门的10条查询串.内存<1G.字符串长0-255(1)主要解决思路(2)算法及其复杂度分析 解决方案 解决方案二:我能想到的就是哈希+堆排序了

java 笔试题-微软4月笔试题第二题,为什么本地运行没错,提交是RE,实在想不出来,求救!!

问题描述 微软4月笔试题第二题,为什么本地运行没错,提交是RE,实在想不出来,求救!! import java.util.ArrayList; import java.util.Scanner; public class Main { int allowS = 0;//rules allow数组大小 int denyS = 0; ArrayList<String> allow = new ArrayList<>();//用来存放动态变化的rules,整个类都要使用,则定义为实例变量

JS经典正则表达式笔试题汇总_javascript技巧

本文实例总结了JS经典正则表达式笔试题.分享给大家供大家参考,具体如下: 一.复习字符串的传统操作 如何获取一个字符串中的数字字符,并按数组形式输出,如 dgfhfgh254bhku289fgdhdy675gfh 输出[254,289,675] 分析:循环用charAt()的方法获取到每一个子字符串,判断他是不是在0~9之间,是就把他扔到准备好的数组里 var str="dgfhfgh254bhku289fgdhdy675gfh"; findNum(str); function fin

JS前端笔试题分析_javascript技巧

本文实例分析了JS前端笔试题.分享给大家供大家参考,具体如下: 1.如何根据逗号分隔的字符串创建数组呢?请为下面的字符串创建一个数组,并访问第三个元素:"cats,dogs,birds,horses" 知识点:数组和字符串的转换.考察split() 方法.把一个字符串分割成字符串数组(将字符串按某个字符切割成若干个字符串,并以数组形式返回) var animalString="cats,dogs,birds,horses"; var animalArray=anim

经典算法(9) 从归并排序到数列的逆序数对(微软笔试题)

首先来看看原题 微软2010年笔试题 在一个排列中,如果一对数的前后位置与大小顺序相反 ,即前面的数大于后面的数,那么它们就称为一个逆序数对.一个排列中逆序的总数就称为这个排列的逆序 数.如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序数对,因此整个数组的逆序数对个数为4,现在给定 一数组,要求统计出该数组的逆序数对个数. 计算数列的逆序数对个数最简单的方便就最从前向后依 次统计每个数字与它后面的数字是否能组成逆序数对.代码如下: #include <stdio.h> int ma

网页转换-请问设计了一套笔试题(word2007版),如何转换成网页格式并具备倒计时功能?

问题描述 请问设计了一套笔试题(word2007版),如何转换成网页格式并具备倒计时功能? 我设计了一套人格测试题,都是选择题,用的是word07版,希望将答题时间限定在15分钟内,在候选人点击进去时便开始倒计时,咨询了一位IT朋友,她说要转换成网页格式并下一个插件,请教各位大神,应该如何做才能实现计划功能?谢谢! 解决方案 http://www.officezu.com/a/word/6203.html 解决方案二: 网页的话,js有很多第三方计时库