字符串问题—其四

文章目录

  • 数组中两个字符串的最小距离
    • 题目
    • 代码
  • 添加最少字符使字符串整体都是回文字符串
    • 题目
    • 代码
  • 括号字符串的有效性和最长有效长度
    • 题目
    • 代码
  • 公式字符串求值
    • 题目
    • 代码

数组中两个字符串的最小距离

题目

给定一个字符串数组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;
} //整个过程的逻辑稍微有点复杂,需要进一步梳理

你可能感兴趣的:(字符串)