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