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

来源:互联网 发布:数组词有哪些 编辑:程序博客网 时间:2024/05/18 13:27

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];    }
原创粉丝点击