LintCode Generate Parentheses
给定n对括号,写一个函数去产生所有符合要求的括号组合。
思路
递归+回溯。
如何判断一个序号组合序列是有效的呢?我最先想到的是堆栈。左括号就入栈,右括号就出栈(前提栈不为空),如果空了就说明此时的组合不是合法的,就结束此次搜索。
还有一种简单的方法。针对从1~2n的序列,我们发现如下规则始终成立:左括号的个数大于等于右括号的个数。那么用两个指针leftNum和rightNum来表示左括号和右括号的余下的个数。如果leftNum > 0,那么此时添加一个左括号可以;如果 rightNum > leftNum && rightNum > 0,才可以添加一个右括号。如果leftNum=rightNum=0,说明搜索结束,此时产生的序列就是符合题意的。
代码
/**** version 1 ****/
void dfs(vector<string> &res, string tmp, int cnt, stack<int> s, int n) {
if (cnt == 2*n) {
if (s.empty()) res.push_back(tmp);
return;
}
for (int i = 0; i < 2; i++) {
if (i == 0) {
s.push(cnt);
dfs(res, tmp + '(', cnt+1, s, n);
s.pop();
} else {
if (s.empty()) break;
s.pop();
dfs(res, tmp + ')', cnt+1, s, n);
s.push(cnt);
}
}
}
vector<string> generateParenthesis(int n) {
// Write your code here
vector<string> res;
stack<int> s;
string tmp = "";
dfs(res, tmp, 0, s, n);
return res;
}
/**** version 2 **** better version ****/
vector<string> generateParenthesis(int n) {
// Write your code here
int leftNum, rightNum;
leftNum = rightNum = n;
vector<string> res;
string tmp = "";
generate(res, tmp, leftNum, rightNum);
return res;
}
void generate(vector<string> &res, string tmp, int leftNum, int rightNum) {
if (leftNum == 0 && rightNum == 0) {
res.push_back(tmp);
return;
}
if (leftNum > 0) {
generate(res, tmp+'(', leftNum-1, rightNum);
}
if (rightNum > leftNum) {
generate(res, tmp+')', leftNum, rightNum-1);
}
}
LintCode Integer to Roman
把一个数字转成罗马数字的写法。该数字大小不会超过3999。
思路
弄清楚罗马数字的写法,这题就很简单了。
代码
string intToRoman(int n) {
// Write your code here
char c1[][5] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
char c2[][5] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
char c3[][5] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
char c4[][5] = {"M", "MM", "MMM"};
string res = "";
int cnt = 0;
while (n) {
if (n >= 1000) {
res += c4[n/1000-1];
n %= 1000;
} else if (n >= 100) {
res += c3[n/100-1];
n %= 100;
} else if (n >= 10) {
res += c2[n/10-1];
n %= 10;
} else if (n >= 1) {
res += c1[n-1];
break;
}
}
return res;
}
LintCode Letter Combinations of a Phone Number
给定一个数字序列(不包含01),问你可以翻译成多少种字母组合。数字和字母的映射关系就是九宫格输入法。
思路
dfs
代码
const vector<string> num2letter{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs",
"tuv", "wxyz"};
vector<string> letterCombinations(string& digits) {
// Write your code here
vector<string> res;
string tmp = "";
int n = digits.size();
if (n) dfs(res, tmp, 0, digits, n);
return res;
}
void dfs(vector<string> &res, string tmp, int idx, string digits, int n) {
if (idx == n) {
res.push_back(tmp);
return;
}
int curr = digits[idx] - '0';
for (int i = 0; i < num2letter[curr].size(); i++) {
tmp += num2letter[curr][i];
dfs(res, tmp, idx+1, digits, n);
tmp.pop_back();
}
}
LintCode Longest Common Prefix
求k个字符串的最长公共前缀
思路
直接暴力搜索就可以。因为LCP一定是每一个字符串的子串。所以就可以选取某一字符串,逐个比较其字符和剩下所有字符串的字符是否相等,相等就跳到下一个字符,如果不相等或者发现一个长度更小的字符串,就返回当前结果。
其实我做的时候我最先想到了Merge K Sorted List这道题,于是也把这道题往这方面想了,当然也能做出来,算是又温习了一下这种问题的分治方法吧。
代码
string longestCommonPrefix(vector<string> &strs) {
// write your code here
if (strs.size() == 0) return "";
string res = "";
res = findPrefix(strs, 0, strs.size()-1);
return res;
}
string findPrefix(vector<string> &strs, int l, int r) {
if (l == r) return strs[l];
int mid = (l+r) >> 1;
string pre1 = findPrefix(strs, l, mid);
string pre2 = findPrefix(strs, mid+1, r);
string res = findTwoPrefix(pre1, pre2);
return res;
}
string findTwoPrefix(string str1, string str2) {
string ret = "";
for (int i = 0; i < min(str1.size(), str2.size()); i++) {
if (str1[i] == str2[i]) ret += str1[i];
else break;
}
return ret;
}
LintCode Longest Common Substring
求两个字符串的最长公共子串。同理最长公共子序列。
正如题中提到了substring differs with subsequences.
思路
动态规划来解决。我们考虑状态dp[i][j]来表示字符串1的前i个字符和字符串2的前j个字符的最长公共子串(包含第i个字符和第j个字符)。其实这道题的思路有点像最大子序列和。接下来考虑str1[i-1]和str2[j-1],如果str1[i-1]==str2[j-1],那么dp[i][j] = dp[i-1][j-1]+1,如果不相等那么dp[i][j] = 0。然后我们只要在这个过称中寻找到dp[i][j]的最大值即可。
代码
int longestCommonSubstring(string &A, string &B) {
// write your code here
int m = A.size(), n = B.size();
vector<vector<int> > local(m + 1, vector<int>(n + 1, 0));
int maxx = 0;
for (int i = 1; i < m + 1; i++) {
for (int j = 1; j < n + 1; j++) {
local[i][j] = A[i - 1] == B[j - 1] ? local[i - 1][j - 1] + 1 : 0;
maxx = max(maxx, local[i][j]);
}
}
return maxx;
}
同理,我们也来研究一下最大子序列的问题。这道题仍然是动态规划,我们用dp[i][j]来表示字符串1的前i位和字符串2的前j位的最大子序列长度。同样考虑str1[i-1]是否和str2[j-1]相等。如果相等,那么分别加上这一位一定形成了更长的子序列,所以此时dp[i][j] = dp[i-1][j-1]+1。如果不想等,那么思考从哪几个子状态中可以一步跳转到该状态呢?于是我们得到如下递推 dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
LintCode Longest Palindromic Substring
求给定字符串的最长回文子串
思路
O(n2)的方法
从回文串的中心向两边遍历来寻找最长回文串,注意回文串有偶数长度的也有奇数长度的。所以对于每一位都要考虑这个因素。
代码
string longestPalindrome(string s) {
// write your code here
if (s.size() == 0) return "";
int l = 0, r = 0;
int startIdx = 0, len = 0;
for (int i = 0; i < s.size(); i++) {
if (i < s.size()-1 && s[i] == s[i+1]) { //偶数长度
l = i;
r = i+1;
SearchPalindrome(s, l, r, startIdx, len);
}
l = r = i; //奇数长度
SearchPalindrome(s, l, r, startIdx, len);
}
return s.substr(startIdx, len);
}
void SearchPalindrome(string s, int left, int right, int &startIdx, int &len) {
int step = 1;
bool tag = true;
while (left-step >= 0 && right+step < s.size()) {
if (s[left-step] == s[right+step]) {
step++;
} else {
tag = false;
if (right-left+2*step-1 > len) {
len = right-left+2*step-1;
startIdx = left-step+1;
}
break;
}
}
if (tag) {
if (right-left+2*step-1 > len) {
len = right-left+2*step-1;
startIdx = left-step+1;
}
}
}
思路2
此题也可以用动态规划的方法来解决。维护变量dp[i][j]表示字符串从i到j之间是否为回文串。那么如果i == j,意思就是单个字符,肯定是回文串。如果i和j之间相差为1,意思就是两个字符,就判断这两个字符是否相等来决定是否为回文串。如果i和j之间相差为2,那么dp[i][j] = dp[i+1][j-1] && s[i] == s[j]。
代码就不写了,提及此思路的原因就是想多跟动态规划套套近乎:D
思路3
O(n)的解法,是马拉车算法Manachers’ Algorithm。
算法介绍参考博客 :http://www.cnblogs.com/grandyang/p/4475985.html
代码
string longestPalindrome(string s) {
string t ="$#";
for (int i = 0; i < s.size(); ++i) {
t += s[i];
t += '#';
}
int p[t.size()] = {0}, id = 0, mx = 0, resId = 0, resMx = 0;
for (int i = 0; i < t.size(); ++i) {
p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
while (t[i + p[i]] == t[i - p[i]]) ++p[i];
if (mx < i + p[i]) {
mx = i + p[i];
id = i;
}
if (resMx < p[i]) {
resMx = p[i];
resId = i;
}
}
return s.substr((resId - resMx) / 2, resMx - 1);
}
};