LintCode 解题记录 17.8.7 字符串处理3
来源:互联网 发布:网络课程培训心得 编辑:程序博客网 时间:2024/05/17 22:32
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); }};
- LintCode 解题记录 17.8.7 字符串处理3
- LintCode 解题记录17.8.4 字符串处理2
- LintCode 解题记录17.8.8 字符串处理4
- LintCode解题记录17.8.9 字符串处理5
- LintCode 解题记录17.8.19 字符串处理6
- LintCode 解题记录 字符串处理1.0 17.7.29
- LintCode解题记录 17.5.3
- LintCode 解题记录 2017.6.3
- LintCode 解题记录 17.8.30 两个指针
- LintCode 解题记录17.4.27
- LintCode解题记录17.4.28
- LintCode 解题记录 7.11 ~ 7.16
- LintCode 解题记录 Matrix专题
- LintCode解题记录17.9.9
- LintCode解题记录-Catalan Number
- LintCode 解题记录17.10.21
- LintCode 解题记录 17.11.11
- LintCode 解题记录 17.5.15 (tag: 哈希表)
- Java生成随机数
- 中缀表达式转后缀表达式
- js数据放入缓存,需要再调用
- Docker 运行 Tomcat7.0.79 命令
- 分解质因数
- LintCode 解题记录 17.8.7 字符串处理3
- 移动端meta
- 接口服务化问题
- datatable用法
- Hadoop2.x编程入门实例:MaxTemperature
- Java语言基础(一)
- 微信小程序地图api开发真机预览崩溃
- 2017日照夏令营 day1 t3 等式 洛谷P1955 程序自动分析
- Java数组小结