1. 求选择方案的最大价值
给定两个数组,如下:
low = [2, 3, 1, 7], high = [4, 6, 5, 8], 数组长度一样
第i次只能从low[i] 和 hight[i] 里面取一个数。如果从low[i] 取,则第i+1次依然可以从low[i]取;如果第i次从hight[i]取,则第i+1次只能从low[i+1]中取,请给出一个选择方案,使得最终选择方案的和最大。
思路
从第i-1次到第i次,只有2中方案。一是第i-1次选择low的,第i次继续选择low,二是第i-2次选择high的,第i次选择high.
解法
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int maxValue(vector<int>& low, vector<int>& high) {
int a[3] = {0};
if (low.size() == 1) return low[0];
if (low.size() == 2) return max(low[0] + low[1], high[1]);
a[0] = low[0];
a[1] = max(low[0] + low[1], high[1]);
for (int i = 2; i < low.size(); i++) {
a[2] = max(a[0] + high[i], a[1] + low[i]);
a[0] = a[1];
a[1] = a[2];
}
return a[2];
}
int main() {
vector<int> low{2, 3, 5, 1, 7};
vector<int> high{4, 6, 8, 23, 12};
cout << "Max Value:" << maxValue(low, high) << endl;
}
2. Edit Distance 2个字符串的最短距离
Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.
You have the following 3 operations permitted on a word:
- Insert a character
- Delete a character
- Replace a character
Example 1:
Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation:
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')
Example 2:
Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation:
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')
思路
当 word1[i] == word2[j] 时,dp[i][j] = dp[i - 1][j - 1],其他情况时,dp[i][j] 是其左,左上,上的三个值中的最小值加1,其实这里的左,上,和左上,分别对应的增加,删除,修改操作,具体可以参见解法一种的讲解部分,那么可以得到状态转移方程为:
解法
#include <iostream>
#include <map>
#include <list>
#include <string>
using namespace std;
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
int dp[m+1][n+1];
for (int i = 0; i <= m; ++i) dp[i][0] = i;
for (int i = 0; i <= n; ++i) dp[0][i] = i;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
}
}
}
return dp[m][n];
}
int main() {
string a("basdfeydfer");
string b("dkjfsfdseder");
int ret = minDistance(a, b);
cout << ret << endl;
return 1;
}
3. 求最大回文串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"
思路
思路一:Manacher's Algorithm 马拉车算法
由一个叫 Manacher 的人在 1975 年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性,这是非常了不起的。对于回文串想必大家都不陌生,就是正读反读都一样的字符串,比如 "bob", "level", "noon" 等等,那么如何在一个字符串中找出最长回文子串呢,可以以每一个字符为中心,向两边寻找回文子串,在遍历完整个数组后,就可以找到最长的回文子串。但是这个方法的时间复杂度为 O(n*n),并不是很高效,下面我们来看时间复杂度为 O(n)的马拉车算法。
由于回文串的长度可奇可偶,比如 "bob" 是奇数形式的回文,"noon" 就是偶数形式的回文,马拉车算法的第一步是预处理,做法是在每一个字符的左右都加上一个特殊字符,比如加上 '#',那么
bob --> #b#o#b#
noon --> #n#o#o#n#
这样做的好处是不论原字符串是奇数还是偶数个,处理之后得到的字符串的个数都是奇数个,这样就不用分情况讨论了
#include <vector>
#include <iostream>
#include <string>
using namespace std;
string Manacher(string s) {
// Insert '#'
string t = "$#";
for (int i = 0; i < s.size(); ++i) {
t += s[i];
t += "#";
}
// Process t
vector<int> p(t.size(), 0);
int mx = 0, id = 0, resLen = 0, resCenter = 0;
for (int i = 1; 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 (resLen < p[i]) {
resLen = p[i];
resCenter = i;
}
}
return s.substr((resCenter - resLen) / 2, resLen - 1);
}
int main() {
string s1 = "12212";
cout << Manacher(s1) << endl;
string s2 = "122122";
cout << Manacher(s2) << endl;
string s = "waabwswfd";
cout << Manacher(s) << endl;
}
思路二:动态规划拆解问题,设状态dp[j][i]表示索引j到索引i的子串是否是回文串。则转移方程为:
解法
#include <iostream>
#include <cstring>
using namespace std;
string longestPalindrome(string s)
{
const int n = s.size();
bool dp[n][n];
memset(dp, 0, sizeof(dp));
int maxlen = 1; //保存最长回文子串长度
int start = 0; //保存最长回文子串起点
for(int i = 0; i < n; ++i)
{
for(int j = 0; j <= i; ++j)
{
if(i - j < 2)
{
dp[j][i] = (s[i] == s[j]);
}
else
{
dp[j][i] = (s[i] == s[j] && dp[j + 1][i - 1]);
}
if(dp[j][i] && maxlen < i - j + 1)
{
maxlen = i - j + 1;
start = j;
}
}
}
return s.substr(start, maxlen);
}
int main()
{
string s;
cout << "Input source string: ";
cin >> s;
cout << "The longest palindrome: " << longestPalindrome(s) << endl;
return 0;
}
4. 最长公共连续子序列
戳我
5. 整数拆分
题目:给定一个整数n,将其拆分成至少2个正整数的和,并使这些整数的乘积最大化。
实例:输入 2 , 输出 1; 输入10, 输出 3*3*4=36
思路:dp(n) = max(dp(n-1)*1, dp(n-2)*2, ... , dp(1)*(n-1))