LintCode 解题记录 字符串处理1.0 17.7.29

Before: 按照难度做的
————————-Easy———————————

LintCode Add Binary

二进制求和。给定两个用字符串表示的二进制序列,求其和序列,同样以字符串表示。
1.思路
按照加法的规则来,从两个字符串的末尾(相当于最低位)开始加,维护进位位,把每次得到的结果顺序加在结果字符串上,最后利用reverse函数将结果字符串颠倒即为正确答案。
2.注意
要注意判断最高位是否有进位
3.代码

    string addBinary(string& a, string& b) {
        // Write your code here
        string res;
        if (a.size() < b.size()) swap(a, b); //确保a是较长的那个字符串
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        int i =  0;
        int c = 0, sum = 0;
        for (; i < b.size(); i++) {
            sum = (a[i]-'0') + (b[i]-'0') + c;
            c = sum / 2;
            sum %= 2;
            res += sum + '0';
        }
        while (i < a.size()) {
            sum = (a[i++]-'0') + c;
            c = sum / 2;
            sum %= 2;
            res += sum + '0';
        }
        if (c) res += c + '0'; //判断最终的进位位
        reverse(res.begin(), res.end());
        return res;
    }

LintCode Compare String

比较字符串A和B,判断是不是A包含B
思路
典型的hash应用。用hash数组存储字符串A中字符出现的次数,先遍历一遍A更新hash,然后再遍历B,每遍历到一次字符其相应的hash值就减1。如果发现其hash值小于0,就说明A不包含B,返回false。
代码

    bool compareStrings(string A, string B) {
        // write your code here
        unordered_map<char, int> hash;
        for (auto c: A) {
            hash[c]++;
        }
        for (auto c: B) {
            hash[c]--;
            if (hash[c] < 0) return false;
        }
        return true;
    }

LintCode Count and Say

对于一个字符串表示的数字序列”122123”,出现了一次1,即”11”,然后出现两次2,即”22”,接着一次1,一次2,一次3,即”111213”,得到下一个字符串是”1122111213”。再对新字符按照上面描述的规则”读”,即可得到又一新字符串,依次循环。
现在给定第一个字符串是”1”,问你第n个字符串是什么?
思路
按照上述读的规则进行。从第一个字符串开始计算,一直计算到第n个字符串即可。每次统计某一位出现字符串的次数,然后拼接形成新的字符串。
注意
C++字符串流stringstream在字符串转int,int转字符串的作用
代码

    string int2string(int cnt) {
        stringstream ss;
        ss << cnt;
        string temp;
        ss >> temp;
        return temp;
    }
    string GenerateString(string res) {
        string temp;
        char pre = res[0];
        int cnt = 1;
        for (int i = 1; i < res.size(); i++) {
            if (res[i] == pre) cnt++;
            else {
                temp += cnt + '0';
                temp += pre;
                pre = res[i];
                cnt = 1;
            }
        }
        temp += int2string(cnt);
        temp += pre;
        return temp;
    }
    string countAndSay(int n) {
        // Write your code here
        string res = "1";
        while (--n) {
            res = GenerateString(res);
        }
        return res;
    }

LintCode Length of Last Word

给定一个字符串包含大小写字母和空格,返回最后一个单词的长度
思路
从末尾往前遍历,先去掉末尾空格,然后遍历到下一个空格或者字符串头结束,返回计数值。
代码

        int res = 0;
        int p = s.size()-1;
        while (p >= 0 && s[p] == ' ') p--;
        for (; p >= 0; p--) {
            if (s[p] != ' ') {
                res++;
            }
            else {
                break;
            }
        }
        return res;
    }

LintCode Longest Word

给定一些单词,返回最长的单词的集合。要求一次遍历。
思路
用一个vector存储当前为止的最长单词集合。如果下一个单词的长度大于当前的长度,就把容器清空,把该单词加进去,如果相等则直接把该单词添加进去。最后返回该容器。
代码

    vector<string> longestWords(vector<string> &dictionary) {
        // write your code here
        vector<string> res;
        for (int i = 0; i < dictionary.size(); i++) {
            if (res.empty() || dictionary[i].size() > res[0].size()) {
                res.clear();
                res.push_back(dictionary[i]);
            } else if (dictionary[i].size() == res[0].size())
                res.push_back(dictionary[i]);
        }
        return res;
    }

LintCode Palindrome Number

判断一个正数是不是回文数
思路
先把该数转换为字符串,然后从两边注意比较即可
代码

    bool palindromeNumber(int num) {
        // Write your code here
        string res;
        while (num) {
            res += num % 10 + '0';
            num /= 10;
        }
        bool flag = true;
        for (int i = 0; i < res.size()/2; i++) {
            if (res[i] != res[res.size()-1-i]) {
                flag = false;
                break;
            }
        }
        return flag;
    }

LintCode Reverse Words in a String

给定一个输入字符串,按照单词反转单词
思路
两次反转,先整体翻转,然后再单独把单词翻转,即能达到要求
注意
字符串有前导0与末尾0,但是翻转之后应该去掉。每个单词之间有可能有多个空格,翻转之后要求只有一个
代码

        reverse(s.begin(), s.end());
        string res,temp;
        int p = 0, first = 0;
        while (p < s.size() && s[p] == ' ') p++; //jump the leading zeroes.

        while (p < s.size()) {
            if (s[p] != ' ') {
                temp += s[p++];
                first = true;
            } else if (first) { //遇到第一个空格
                reverse(temp.begin(), temp.end());
                res += temp + s[p++];
                temp = "";
                first = false;
            } else
                p++;
        }
        reverse(temp.begin(), temp.end());
        res += temp;
        return res;
    }

后来想到了可以用stringstream从一个带空格的单词序列读取每一个单词,放在vec里,然后倒序遍历再拼接起来就好了。

    string reverseWords(string s) {
        // write your code here
        string res;
        //if (s == "") return res;
        stringstream ss(s);
        vector<string> vec;
        string temp;
        while (ss >> temp) {
            vec.push_back(temp);
        }
        //vector的倒序迭代器rbegin(),rend()
        for (auto ite = vec.rbegin(); ite != vec.rend(); ite++) {
            if (ite != vec.rbegin()) res += " ";
            res += *ite;
        }
        return res;
    }

LintCode Rotate String

从左向右循环移动字符串n次,要求O(1)空间
思路
本来还在找移动了n次的规律,后来发现只需要每次移动一位,循环n次就可以了
代码

    void rotateString(string &str,int offset){
        //wirte your code here
        if (str.size() == 0) return;
        offset %= str.size();
        for (int i = 0; i < offset; i++) {
            char temp = str[str.size()-1];
            for (int j = str.size()-2; j >= 0; j--) {
                str[j+1] = str[j];
            }
            str[0] = temp;
        }

    }

LintCode Space Replacement

将一个字符串中所有空格替换成”%20”,返回修改后的字符串的长度。
要求O(1)空间复杂度
思路
遍历,当遍历到一个空格后将空格后的有效字符均向右移动两位,然后添加”%20”,由于题目说明了空间是足够的,所以不用慌。
代码

    int replaceBlank(char string[], int length) {
        // Write your code here
        int cnt = 0, i = 0;
        while (cnt < length) {
            if (string[i] != ' ') {
                cnt++;
                i++;
            } else {
                for (int j = length-cnt-1; j > 0; j--) {
                    string[i+2+j] = string[i+j];
                }
                string[i] = '%';
                string[i+1] = '2';
                string[i+2] = '0';
                i += 3;
                cnt++;
            }
        }
        return i;
    }

九章做法是先求得新的长度,然后从原字符串的末尾开始遍历,同时修改新申请的长度空间。
代码

   int replaceBlank(char string[], int length) {
        // Write your code here
        if(string == NULL && length <= 0)
            return 0;

        /*originalLength 为字符串string的实际长度*/
        int originalLength = 0;
        int numberOfBlank = 0;
        int i = 0;
        while(string[i] != '\0')
        {
            ++ originalLength;

            if(string[i] == ' ')
                ++ numberOfBlank;

            ++ i;
        }

        /*newLength 为把空格替换成'%20'之后的长度*/
        int newLength = originalLength + numberOfBlank * 2;

        int indexOfOriginal = originalLength;
        int indexOfNew = newLength;
        while(indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
        {
            if(string[indexOfOriginal] == ' ')
            {
                string[indexOfNew --] = '0';
                string[indexOfNew --] = '2';
                string[indexOfNew --] = '%';
            }
            else
            {
                string[indexOfNew --] = string[indexOfOriginal];
            }

            -- indexOfOriginal;
        }
        return newLength;
    }

LintCode String Permutation

给定两个字符串,判断其中一个是不是另一个的排列组合
思路
将两个字符串排序,若排序后相等就说明符合题意,否则就不符合。复杂度O(nlogn)
或者用hash统计字符出现次数,复杂度O(n)
代码

    bool Permutation(string A, string B) {
        // write your code here
        sort(A.begin(), A.end());
        sort(B.begin(), B.end());
        return A == B;
    }

LintCode Two Strings Are Anagrams

Anagrams: They can be same after change the order of characters.
Challenge: O(n)时间复杂度,O(1)空间复杂度
思路
之前提到的是O(n)的时间复杂度,O(n)空间复杂度的方法,这里只不过将开辟的数组换成一个大小固定为26的数组,然后做同样的事情。

    bool anagram(string s, string t) {
        // write your code here
        vector<int> hash(26, 0);
        for (auto c: s) {
            c = tolower(c);
            hash[c-'a']++;
        }
        for (auto c: t) {
            c = tolower(c);
            hash[c-'a']--;
            if (hash[c-'a'] < 0) return false;
        }
        return true;
    }

LintCode Valid Palindrome

给定一个字符串,判断其是不是一个有效的回文串,只考虑英文数字字母(alphanumeric characters)且忽略大小写。
Challenge: O(n) time without extra memory.
思路:
用两个指针从两端向中间遍历,只有在都是字母或数字的时候才判断其是否满足相等,相等则继续判断,不相等则不满足回文串要求。
代码

    bool isPalindrome(string& s) {
        // Write your code here
        int l = 0, r = s.size()-1;
        while (l < r) {
            if (!isalpha(s[l]) && !isdigit(s[l])) l++;
            else if (!isalpha(s[r]) && !isdigit(s[r])) r--;
            else if (tolower(s[r]) == tolower(s[l])) {
                l++;
                r--;
            } else
                return false;
        }
        return true;
    }

LintCode strStr

对于一个给定的source string和一个target string,返回target string在source string中的起始下标,若source string不包含target,则返回-1。
思路:
这就是字符串查找的KMP算法,可以以O(n)的方式解决此问题。KMP算法我并不熟,所以这道题暂时是以O(n2)做的,有时间学习了KMP算法在来更新这道题。
代码

    int strStr(const char *source, const char *target) {
        // write your code here
        if (source == NULL || target == NULL) return -1;
        if (target[0] == '\0') return 0;
        for (int i = 0; source[i] != '\0'; i++) {
            if (source[i] == target[0]) {
                bool find = true;
                for (int j = 1; target[j] != '\0'; j++) {
                    if (source[i+j] == '\0' || source[i+j] != target[j]) {
                        find = false;
                        break;
                    }
                }
                if (find) return i;
            }
        }
        return -1;
    }

LintCode Big Interger Multiplication

给定另个非负大整数(用字符串表示),求他们的乘积,结果也以字符串表示。
思路
按照正常乘法的思路,用一个vector存储所有的因子,最后把这些因子加起来就是想要的答案。
另外可以用一个result数组存储相乘得到的每一位,这种方法代码上更清晰一点。

    string multiply(string& num1, string& num2) {
        // Write your code here
        if (num1 == "0" || num2 == "0") return "0";
        int len1 = num1.size(), len2 = num2.size();
        vector<char> result(len1+len2, '0');
        int c;
        for (int i = len1-1; i >= 0; i--) {
            c = 0;
            for (int j = len2-1; j >= 0; j--) {
                int temp = (result[i+j+1]-'0')+(num1[i]-'0')*(num2[j]-'0')+c;
                c = temp/10;
                result[i+j+1] = temp%10 + '0';
            }
            result[i] += c;
        }
        string res = "";
        int cnt = 0;
        for (; cnt < len1+len2; cnt++) {
            if (result[cnt] != '0') break;
        }
        for (; cnt < len1+len2; cnt++) {
            res += result[cnt];
        }
        return res;
    }

LintCode Decode Ways

给定一种编码方式,比如’A’ to ‘1’, ‘B’ to ‘2’,…,’Z’ to ‘26’,现在给你一数字序列,问你有多少种译码方式。
思路
从前往后遍历,假设当前位置i,既可以选择i+1位的单字符编码,也可以选择i+1、i+2位组成的双字符编码。当然存在组成的字符编码无法译码的情况,比如单字符为’0’就无法译码,或者双字符组成的数大于26或者’0x’这样的形式。这道题很像上楼梯问题:一共n个楼梯,一次可以选择走一步,也可以选择走两步,问一共有多少种上楼方式。
总结一下递推公式:
dp[i] = dp[i-1](if s[i] != ‘0’) + dp[i+2] (if 10*(s[i-1]-‘0’) + s[i]-‘0’ < 26 && s[i-1] != ‘0’)
初始条件 如果s != null && s[0] != ‘0’,那么s[0] = 1; s[1]的判断同理。
代码

    int numDecodings(string& s) {
        // Write your code here
        if (s.size() == 0 || s[0] == '0') return 0;
        if (s.size() == 1) return 1;
        vector<int> res(s.size(), 0);
        res[0] = 1;
        int sum = 10*(s[0]-'0')+(s[1]-'0');
        if (sum >= 1 && sum <= 26) res[1]++;
        if (s[1] != '0') res[1]++;
        for (int i = 2; i < s.size(); i++) {
            int sum = 10*(s[i-1]-'0')+(s[i]-'0');
            if (s[i] != '0')
                res[i] += res[i-1];
            if (sum >= 1 && sum <= 26 && s[i-1] != '0') {
                res[i] += res[i-2];
            }
        }
        return res[s.size()-1];

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值