给定一个字符串数组strs,再给定两个字符串str1和str2,返回在strs中str1和str2的最小距离,如果str1和str2为NULL,或不在strs中,返回-1。
进阶题目:如果查询发生的次数较多,如何把每次查询的时间复杂度将为O(1)?
原问题使用map进行记录依次更新即可,进阶问题在书中的方法是使用了一个map
#include
#include
#include
#include
using namespace std;
int minDistance(string strs, string s1, string s2)
{
if (s1.size() < 1 || s2.size() < 1)
return -1;
if (s1 == s2)
return 0;
int last1 = -1;
int last2 = -1;
int len = strs.size();
int MIN = INT_MAX;
for (int i = 0; i < len; i++)
{
if (strs[i] == *s1.c_str())
{
MIN = min(MIN, last2 == -1 ? MIN : i - last2);
last1 = i;
}
if (strs[i] == *s2.c_str())
{
MIN = min(MIN, last1 == -1 ? MIN : i - last1);
last2 = i;
}
}
return MIN == INT_MAX ? -1 : MIN;
}
class record
{
private:
map<string, map<string, int>> recordD;
void update(map<string, int> &indexMap, string str, int i);
public:
record(string str);
int minDistance(string str1, string str2);
};
record::record(string str)
{
map<string, int> indexMap;
for (int i = 0; i != str.size(); i++)
{
string curStr = str.substr(i, 1);
update(indexMap, curStr, i);
indexMap[curStr] = i;
}
}
void record::update(map<string, int> &indexMap, string str, int i)
{
if (indexMap.find(str) == indexMap.end())
{
map<string, int> newSubMap;
recordD.insert(pair<string, map<string, int>>(str, newSubMap));
}
map<string, int>strMap = recordD[str];
//map::iterator my_it = strMap.begin();
for (pair<string, int> m: strMap)
{
string key = m.first;
int index = m.second;
if (key != str)
{
map<string, int> lastMap = recordD[key];
int curMin = i - index;
if (strMap.find(key) != strMap.end())
{
int preMin = strMap[key];
if (curMin < preMin)
{
strMap[key] = curMin;
lastMap[str] = curMin;
}
}
else
{
strMap[key] = curMin;
lastMap[str] = curMin;
}
}
}
}
int record::minDistance(string str1, string str2)
{
if (str1.size() < 1 || str2.size() < 1)
return -1;
if (str1 == str2)
return 0;
if (recordD.find(str1) != recordD.end() && recordD[str1].find(str2) != recordD[str1].end())
return recordD[str1][str2];
return -1;
}
//多次查询使得时间复杂度为O(1)的方法是以上类中的方法,逻辑上是按照书中思路进行实现,未进行测试
int main()
{
string str, s1, s2;
getline(cin, str);
getline(cin, s1);
getline(cin, s2);
int res = minDistance(str, s1, s2);
cout << res << endl;
getchar();
return 0;
}
给定一个字符串str,如果可以在str的任意位置添加字符,请返回在添加字符最少的情况下,让str整体都是回文字符串的一种结果。
进阶题目:给定一个字符串str,再给定str的最长回文子序列字符串strlps,请返回在添加字符最少的情况下,让str整体都是回文字符串的一种结果。进阶问题比原问题多了一个参数,请做到时间复杂度比原问题的低的实现方法。
原问题可使用动态规划求解添加最少字符的数目,进一步找到最短回文字符串,时间复杂度为O(N2)。进阶问题书中的方法类似于剥洋葱,详细分析参看书籍271页
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
using namespace std;
vector<vector<int>> getdp(string str)
{
int len = str.size();
vector<vector<int>> dp(len, vector<int>(len, 0));
for (int i = 1; i < len; i++)
{
dp[i - 1][i] = str[i - 1] == str[i] ? 0 : 1;
for (int j = i - 2; j > -1; j--)
{
if (str[i] == str[j])
dp[j][i] = dp[j + 1][i - 1];
else
dp[j][i] = min(dp[j + 1][i], dp[j][i - 1]) + 1;
}
}
return dp;
}
string getPalindrome1(string str)
{
if (str == "" || str.size() < 1)
return str;
vector<vector<int>> dp = getdp(str);
int len = str.size();
int len1 = dp[0][len - 1];
char* sp = new char[len + len1];
int i = 0;
int j = len - 1;
int resl = 0;
int resr = len + len1 - 1;
while (i <= j)
{
if (str[i] == str[j])
{
sp[resl++] = str[i++];
sp[resr--] = str[j--];
}
else if (dp[i][j - 1] < dp[i + 1][j])
{
sp[resl++] = str[j];
sp[resr--] = str[j--];
}
else
{
sp[resl++] = str[i];
sp[resr--] = str[i++];
}
}
string res = sp;
return res;
}
//进阶问题
void set(char* res, int resl, int resr, char* str, int ls, int le, int rs, int re)
{
for (int i = ls; i < le; i++)
{
res[resl++] = str[i];
res[resr--] = str[i];
}
for (int i = re; i > rs; i--)
{
res[resl++] = str[i];
res[resr--] = str[i];
}
}
string getPalindrome2(string str, string strlps)
{
if (str.size() < 1 || str == "")
return "";
int len1 = str.size();
int len2 = strlps.size();
char* strc = new char[len1 + 1];
char* strlpsc = new char[len2 + 1];
strcpy(strc, str.c_str());
strcpy(strlpsc, strlps.c_str());
char* res = new char[2 * len1 - len2];
int strl = 0;
int strr = len1 - 1;
int lpsl = 0;
int lpsr = len2 - 1;
int resl = 0;
int resr = 2 * len1 - len2 - 1;
int tmpl = 0;
int tmpr = 0;
while (lpsl <= lpsr)
{
tmpl = strl;
tmpr = strr;
while (strc[strl] != strlpsc[lpsl])
strl++;
while (strc[strr] != strlpsc[lpsr])
strr--;
set(res, resl, resr, strc, tmpl, strl, strr, tmpr);
resl += strl - tmpl + tmpr - strr;
resr -= strl - tmpl + tmpr - strr;
res[resl++] = strc[strl++];
res[resr--] = strc[strr--];
lpsl++;
lpsr--;
}
string resF = res;
return resF;
}
int main()
{
string s, slps;
getline(cin, s);
getline(cin, slps);
//string res = getPalindrome1(s);
string res = getPalindrome2(s, slps);
cout << res << endl;
getchar();
return 0;
}
给定一个字符串str,判断是不是整体有效的括号字符串。
补充题目:给定一个括号字符串str,返回最长的有效括号子串。
#include
#include
#include
#include
using namespace std;
bool isValid(string str)
{
if (str == "" || str.size() < 1)
return false;
int status = 0;
int len = str.size();
for (int i = 0; i < len; i++)
{
if (str[i] != '(' && str[i] != ')')
return false;
if (str[i] == ')' && --status < 0)
return false;
if (str[i] == '(')
status++;
}
return status == 0;
}
int maxLen(string str)
{
if (str == "" || str.size() < 1)
return 0;
int len = str.size();
vector<int> dp(len, 0);
int pre = 0;
int res = 0;
for (int i = 1; i < len; i++)
{
if (str[i] == ')')
{
pre = i - dp[i - 1] - 1;
if (pre >= 0 && str[pre] == '(')
dp[i] = dp[i - 1] + 2 + (pre > 0 ? dp[pre - 1] : 0);
}
res = max(res, dp[i]);
}
return res;
}
int main()
{
string s;
getline(cin, s);
bool valid = isValid(s);
if (valid)
cout << "The string is valid!" << endl;
else
cout << "Not valid!" << endl;
int len = maxLen(s);
cout << len << endl;
getchar();
return 0;
}
给定一个字符串str,str表示一个公式,公式可能有整数、加减乘除符号和左右括号,返回公式的计算结果。
说明:
1、可认为给定的字符串一定是正确的公式,不需要对str公式做有效性检查。
2、如果是负数,需要用括号括起来,比如4*(-3)。但是如果负数作为公式的开头或括号部分的开头,则可以没有括号,如”-34“和"(-34)"都是合法的。
3、不用考虑溢出的问题。
略复杂,参考原书详细分析(实际上是因为菜)
#include
#include
#include
#include
#include
using namespace std;
int getNum(deque<string> &dq)
{
int res = 0;
bool add = true;
string cur = "";
int num = 0;
while (!dq.empty())
{
cur = dq.front();
dq.pop_front();
if (cur == "+")
add = true;
else if (cur == "-")
add = false;
else
{
num = atoi(cur.c_str());
res += add ? num : (-num);
}
}
return res;
}
void addNum(deque<string> &dq, int num)
{
if (!dq.empty())
{
int cur = 0;
string top = dq.back();
dq.pop_back();
if (top == "+" || top == "-")
dq.push_back(top);
else
{
cur = atoi(dq.back().c_str());
dq.pop_back();
num = top == "*" ? (cur * num) : (cur / num);
}
}
dq.push_back(to_string(num));
}
vector<int> value(string str, int i)
{
deque<string> dq;
int pre = 0;
vector<int> bra(2);
while (i < str.size() && str[i] != ')')
{
if (str[i] >= '0' && str[i] <= '9')
pre = pre * 10 + str[i++] - '0';
else if (str[i] != '(')
{
addNum(dq, pre);
dq.push_back(str.substr(i, 1));
i++;
pre = 0;
}
else
{
bra = value(str, i + 1);
pre = bra[0];
i = 1 + bra[1];
}
}
addNum(dq, pre);
return vector<int> {
getNum(dq), i };
}
//大致了解了整个过程,不过要实现还是有很多地方的细节需要考虑,目前还是照搬,浪费了不少时间
int getValue(string str)
{
return value(str, 0)[0];
}
int main()
{
string s;
getline(cin, s);
int res = getValue(s);
cout << res << endl;
getchar();
return 0;
} //整个过程的逻辑稍微有点复杂,需要进一步梳理