关于字符串的笔试、面试题

1,验证一个字符串是否是回文串。
需要一个指向头部的变量和指向尾部的变量,从字符串的两边来遍历,遇到除字母和数字以外的字符则跳过,如果遍历完整个字符串后前后字母都能匹配上,则是回稳返回true.注意:空串也是回文。

需要注意的几点:(1)、对大小写不敏感,需要把所有字母小写都转换成大写,或者大写都转换成小写,用toupper()函数。
(2)、遇到非字母、数字要跳过,用到isalnum()函数

bool IsPalindrom(string s)
{
    int first = 0, last = s.size() - 1;
    while (first <= last)
    {
        while (!isalnum(s[first]) && first < last)
        {
            first++;
        }
        while (!isalnum(s[last]) && first < last)
        {
            last--;
        }
        if (toupper(s[first]) != toupper(s[last]))
            return false;
        first++;
        last--;
    }
    return true;
}

2,模拟实现strstr.(找子串)

int strStr(string haystack, string needle)
{
    int m = haystack.size(), n = needle.size();
    if (n == 0)
        return 0;
    for (int i = 0; i < m - n + 1;i++)
    {
        int j = 0;
        while(haystack[i + j] == needle[j])
        {
            j++;
            if (j == n)
                return i;
        }
        j++;
    }
    return -1;
}

3,模拟实现atoi

int my_atoi(const char* str)
{
    int num = 0;
    int sign = 1;
    const int n = strlen(str);
    int i = 0;

    while (str[i] == ' ' && i < n)
        i++;
    if (str[i] == '+')
        i++;
    else if (str[i] == '-')
    {
        sign = -1;
        i++;
    }
    for (; i < n; i++)
    {
        if (str[i] < '0' || str[i] > '9')
            break;
        if (num > INT_MAX / 10 || (num == INT_MAX / 10 && (str[i] - '0') > INT_MAX % 10))
            return sign == -1 ? INT_MIN : INT_MAX;
        num = num * 10 + str[i] - '0';
    }
    return num * sign;
}

4,二进制数相加。
比如:a = “11” b = “1” return 100
二进制数想加,并且保存在string中,要注意的是如何将string和int之间互相转换,并且每位相加时,会有进位的可能,会影响之后相加的结果。而且两个输入string的长度也可能会不同。这时我们需要新建一个string,它的长度是两条输入string中的较大的那个,并且把较短的那个输入string通过在开头加字符‘0’来补的较大的那个长度。这时候我们逐个从两个string的末尾开始取出字符,然后转为数字,想加,如果大于等于2,则标记进位标志carry,并且给新string加入一个字符‘0’。

//二进制数相加
string addBinary(string a, string b)
{
    string result;
    const size_t n = a.size() > b.size() ? a.size() : b.size();
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    int carry = 0;
    for (size_t i = 0; i < n; ++i)
    {
        const int ai = i < a.size() ? a[i] - '0' : 0;
        const int bi = i < b.size() ? b[i] - '0' : 0;
        const int val = (ai + bi + carry) % 2;
        carry = (ai + bi + carry) / 2;
        result.insert(result.begin(), val + '0');
    }
    if (carry == 1)
        result.insert(result.begin(), '1');
    return result;
}

5,找出最长回文子串
方法一:以字符串中的每一个字符为中心遍历字符串。

思路:本题的解决方法是从头到尾的遍历字符串S,以每个字符为中心,向两端不停的扩展,同时判断以当前字符为中心的两端字符是否相等,在判断的过程中找到最大的回文串长度,并记录下回文串开始的最左端,这样就找到了最大的回文串。但是这样做就遇到了一个问题:“abcab”这种个数为奇数的回文串可以计算出来,但是若是”abba”这样个数为偶数的情况,该如何计算?遇到这种情况,则,可以判断相邻两字符是否相等来判断是否为回文串,针对s=“abba”,我们发现 i=1时,s[i]==s[i+1],然后同时向两端扩,发现s[ 0]=s[ 2],这样该串也为回文串,所以,在判断以某字符为中心的时候,要分两种情况,即,回文串中字符的个数为奇数和为偶数的情况。时间复杂度是O(n*n)。

//最长回文串
string longestPalindrome(string s)
{
    string res = "";
    int len = s.size();
    if (len == 1)
        return s;
    int maxlen = 0, curlen = 0, sbegin;
    int left, right;
    for (int i = 0; i < len; ++i)
    {
        if (len % 2 == 0)
        {
            left = i - 1;
            right = i + 1;
        }
        else
        {
            left = i;
            right = i + 1;
        }
        while (left >= 0 && right < len && s[left] == s[right])
        {
            curlen = right - left;
            if (curlen > maxlen)
            {
                maxlen = curlen;
                sbegin = left;
            }
            left--;
            right++;
        }
    }
    res = s.substr(sbegin, maxlen + 1);  //substring()为前闭后开
    return res;
}

还有一种O(N)的解法:
http://www.cnblogs.com/love-yh/p/7072161.html

6,求字符串中最后一个单词的长度。
比如:“Hello world” return 5

//求最后一个单词的长度 顺序扫描字符串,求出每个单词的长度
int lengthOflastWord(const char* s)
{
    int len = 0;
    while (*s)
    {
        if (*s != ' ')
            ++len;
        else
            len = 0;
    }
    return len;
}

7,Regular Expression Matching (正则表达式匹配)
实现支持“.”和“*”的正则表达式匹配。

“.” 匹配支持单个字符
“*” 匹配零个或多个前面的元素

匹配应该覆盖到整个输入的字符串(而不是局部的)

比如:
isMatch(“aa”,”a”) → false
isMatch(“aa”,”aa”) → true
isMatch(“aaa”,”aa”) → false
isMatch(“aa”, “a”) → true
isMatch(“aa”, “.”) → true
isMatch(“ab”, “.”) → true
isMatch(“aab”, “c*a*b”) → true

bool IsMatch(const char* s, const char* p)
{
    if (*p == '\0')
        return *s == '\0';
    //next char is not '*',then must match current character
    if (*(p + 1) != '*')
    {
        if (*p == *s || *p == '.' && *s != '\0')
        {
            return IsMatch(s + 1, p + 1);
        }
        else
            return false;
    }
    else
    {//next char is '*'
        while (*p == *s || (*p == '.' && *s != '\0'))
        {
            if (IsMatch(s, p + 2))
                return true;
            s++;
        }
        return IsMatch(s, p + 2);
    }
}

8, 给定一个String类型数组,要求写一个方法,返回数组中这些字符串的最长公共前缀。举个例子:假如数组为[“123”,”12”,”4”],经过这个方法返回的结果就应该是”“。因为”123”,”12”,”4”并没有共同的前缀,虽然”123”,”12”的公共最长前缀是”12”,但是这个公共前缀”12”与”4”没有公共前缀,所以最后返回的结果就是”“。

最简单的思路就是将str[0],当作临时最长公共前缀,然后用这个前缀依次和剩下的字符串进行前缀比较,都比较完后,就将最后得到的最新公共最长前缀返回即可。

//Longest Common Prefix
string longestCommonPrefix(vector<string> &str)
{
    if (str.empty())
        return "";
    int right_most = str[0].size() - 1;
    for (size_t i = 1; i < str.size(); ++i)
    {
        for (int j = 0; j <= right_most; j++)
        {
            if (str[i][j] != str[0][j])
                right_most = j - 1;
        }
    }
    return str[0].substr(0, right_most + 1);
}

9,给你一个字符串数组,返回所有的回文构词法的字符串。
Anagram(回文构词法)是指由颠倒字母顺序组成的单词,比如“dormitory”颠倒字母顺序会变成“dirty room”,“tea”会变成“eat”。回文构词法有一个特点:单词里的字母的种类和数目没有改变,只是改变了字母的排列顺序。
Input:  [“tea”,”and”,”ate”,”eat”,”den”]
Output: [“tea”,”ate”,”eat”]

vector<string> anagrams(vector<string>& strs)
{
    unordered_map<string, vector<string>> group;
    for (const auto &s : strs)
    {
        string key = s;
        sort(key.begin(), key.end());
        group[key].push_back(s);
    }
    vector<string> result;
    for (auto it = group.cbegin(); it != group.cend(); ++it)
    {
        if (it->second.size() > 1)
            result.insert(result.end(), it->second.begin(), it->second.end());
    }
    return result;
}

这里写图片描述

10,简化UNIX下的路径。
题目的要求是输出Unix下的最简路径,Unix文件的根目录为”/”,”.”表示当前目录,”..”表示上级目录。

例如:

输入1:

/../a/b/c/./..

输出1:

/a/b

模拟整个过程:

  1. “/” 根目录

  2. “..” 跳转上级目录,上级目录为空,所以依旧处于 “/”

  3. “a” 进入子目录a,目前处于 “/a”

  4. “b” 进入子目录b,目前处于 “/a/b”

  5. “c” 进入子目录c,目前处于 “/a/b/c”

  6. “.” 当前目录,不操作,仍处于 “/a/b/c”

  7. “..” 返回上级目录,最终为 “/a/b”

使用一个栈来解决问题。遇到’..’弹栈,遇到’.’不操作,其他情况下压栈。

 string simplifyPath(string path)
 5     {
 6         stack<string> ss; // 记录路径名
 7         for(int i = 0; i < path.size(); )
 8         {
 9             // 跳过斜线'/'
10             while(i < path.size() && '/' == path[i])
11                 ++ i;
12             // 记录路径名
13             string s = "";
14             while(i < path.size() && path[i] != '/')
15                 s += path[i ++];
16             // 如果是".."则需要弹栈,否则入栈
17             if(".." == s && !ss.empty())
18                 ss.pop();
19             else if(s != "" && s != "." && s != "..")
20                 ss.push(s);
21         }
22         // 如果栈为空,说明为根目录,只有斜线'/'
23         if(ss.empty())
24             return "/";
25         // 逐个连接栈里的路径名
26         string s = "";
27         while(!ss.empty())
28         {
29             s = "/" + ss.top() + s;
30             ss.pop();
31         }
32         return s;
33     }

11,Count and Say
本题是将数字从1开始,将当前数字转化为口语对应的数字。比如1口语是1个1,记作11;11读作2个1,记作21;21读作1个2,1个1,记作1211……
这道题算就是字符串处理的问题,序列中第一个字符串是“1”,接下来依次统计前一个字符串中连续相同字符的数量,并添加到下一字符串中。前15字符串如下(LeetCode上貌似只有18测试用例):

1
11
21
1211
111221
312211
13112221
1113213211
31131211131221
13211311123113112211
11131221133112132113212221
3113112221232112111312211312113211
1321132132111213122112311311222113111221131221
11131221131211131231121113112221121321132132211331222113112211
311311222113111231131112132112311321322112111312211312111322212311322113212221

string countAndSay(int n)
{
    string s = "1";
    for (int i = 1; i < n; ++i)
    {
        int count = 1;
        string temp = "";
        for (int j = 1; j < s.size(); ++j)
        {
            if (s[j] == s[j - 1])
            {
                ++count;
            }
            else
            {
                temp = temp + (char)(count + '0') + s[j - 1];
                count = 1;
            }
        }
        s = temp + (char)(count + '0') + s[s.size() - 1];
    }
    return s;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值