华为机试在线训练-牛客网(20)【中级】字符串运用-密码截取
2017-02-09 21:37
393 查看
题目描述
Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?输入描述:
输入一个字符串
输出描述:
返回有效密码串的最大长度
输入例子:
ABBA
输出例子:
4
此题实际上是一个求字符串中最长回文长度问题,最常见的是manacher算法。为便于处理,将原字符串中其它非英文、数字字符全部去掉(可以不要这步):
for(auto &c:str){ if((c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9')) continue; else//非英文和数字字符标记 c='~'; } auto iter=remove(str.begin(),str.end(),'~'); str.erase(iter,str.end());//删除接下来就是实现manacher()并调用,完整AC过的代码:
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; //manacher算法求回文,返回最长回文字符串 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 str; while(getline(cin,str)){ for(auto &c:str){ if((c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9')) continue; else//非英文和数字字符 c='~'; } auto iter=remove(str.begin(),str.end(),'~'); str.erase(iter,str.end()); //cout<<str<<endl; cout<<manacher(str).size()<<endl; } return 0; }
补:回文串的判断方法,判断一个字符串是否是回文串:
bool judgeHuiwen(string str){ int size=str.size(); for(int j=0;j<(size+1)/2;j++){ if(str[j]!=str[size-1-j]){ return false; } } return true; }
判断方法很简单,从两头开始比较字符,出现不等则非回文串,但是注意循环结束条件,两头向中间靠拢时只需遍历(size+1)/2次,size为字符串的长度。
根据该方法写了个暴力枚举算法:长度由长到短,对字符串取对应长度的所有可能子串,依次判断是否为回文串,若是则直接返回,该串一定是第一个最长的回文子串。
可惜该方法因算法复杂度过高,牛客OJ上未能AC。
#include <iostream>
using namespace std;
bool judgeHuiwen(string str){ int size=str.size(); for(int j=0;j<(size+1)/2;j++){ if(str[j]!=str[size-1-j]){ return false; } } return true; }
string findMaxHuiWenSubStr(string str){
string res;
for(int len=str.size();len>2;len--){
for(int i=0;i<=str.size()-len;i++){
string subStr=str.substr(i,len);
auto size=subStr.size();
if(judgeHuiwen(subStr)){//是回文串
res=subStr;
goto Res;
}
}
}
Res:
return res;
}
int main()
{
string str;
while(cin>>str){
string res;
res=findMaxHuiWenSubStr(str);
cout<<res.size()<<endl;
}
return 0;
}
-----------------------------2017/2/24 更新----------------------------
上次自己写的一个判断方法复杂度过高,今天发现一种新的解法成功通过OJ,比较容易理解:
保存原字符串的副本,将其反转后按长度递减取子串(跟前面介绍的思路类似,不过是先反转后取子串),再判断原串中是否包含该子串,一旦成功则直接返回结果一定是最长回文子串。
string getMaxHuiwenStrLen(string str){ string res; string temp=str; reverse(temp.begin(),temp.end()); //获取所有子串,查看翻转后的字符串是否包含该子串 for(int len = temp.length(); len >= 1 ;len--){ //len为子串的长度 for(int j = 0; j <= temp.length()-len;j++){ string subStr = temp.substr(j,len); if(str.find(subStr)!=string::npos){ return subStr; } } } return res; }
另外,此题也是一道经典动态规划问题(与最长公共子串有相似之处),后补。
相关文章推荐
- 华为【中级】字符串运用-密码截取
- 华为oj中级 【中级】字符串运用-密码截取
- 华为OJ中级题-字符串运用-密码截取
- 华为oj中级 字符串运用-密码截取
- 华为OJ基础题-字符串运用-密码截取
- 华为OJ——字符串运用-密码截取
- 【华为oj】字符串运用-密码截取
- 华为OJ——字符串运用-密码截取
- 华为机试在线训练-牛客网(38)在字符串中找出连续最长的数字串
- 华为机试在线训练-牛客网(30)查找两个字符串a,b中的最长公共子串
- 华为机试在线训练-牛客网(13)简单密码
- 华为机试在线训练-牛客网(19)【中级】单词倒排
- 【中级】字符串运用-密码截取
- 【中级】字符串运用-密码截取
- 字符串运用-密码截取(华为oj)
- 【华为OJ】【057-字符串运用-密码截取】
- 华为测试 字符串运用-密码截取
- 华为机试-字符串运用密码截取
- 华为OJ 字符串运用-密码截取
- 牛客网华为机试在线训练字符串最后一个单词的长度