牛客网剑指offer字符串题目总结(共10道)
牛客网剑指offer字符串题目总结(共10道)
1、替换空格(剑指2)
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
解题思路:先计算加了空格的总长度,然后从后往前复制。
class Solution {
public:
void replaceSpace(char *str,int length) {
int i,len=0;
for(i=0;i<length;i++)
if(str[i]==' ') len++;
int j=length+len*2-1;
i=length-1;
while(i>=0){
if(i==j) break;
if(str[i]!=' ')
str[j--]=str[i--];
else{
str[j--]='0';
str[j--]='2';
str[j--]='%';
i--;
}
}
}
};
2、字符串的排列(剑指27)
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思路:递归法,问题转换为先固定第一个字符,求剩余字符的排列;求剩余字符排列时跟原问题一样。
(1) 遍历出所有可能出现在第一个位置的字符(即:依次将第一个字符同后面所有字符交换);
(2) 固定第一个字符,求后面字符的排列(即:在第1步的遍历过程中,插入递归进行实现)。
需要注意的几点:
先确定递归结束的条件,例如本题中可设begin == str.size() - 1;
形如 aba 或 aa 等特殊测试用例的情况,vector在进行push_back时是不考虑重复情况的,需要自行控制;
(3) 输出的排列可能不是按字典顺序排列的,可能导致无法完全通过测试用例,考虑输出前排序,或者递归之后取消复位操作
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> result;
Permutation(str,result,0);
sort(result.begin(),result.end());
return result;
}
void Permutation(string str,vector<string> &result,int begin){
if(begin==str.size()-1){
if(find(result.begin(),result.end(),str)==result.end()){
result.push_back(str);
return;
}
}
else{
for(int i=0;i<str.size();i++){
swap(str[begin],str[i]);
Permutation(str,result,begin+1);
swap(str[begin],str[i]);
}
}
}
void swap(char &a,char &b){
char c=a;
a=b;
b=c;
}
};
3、第一个只出现一次的字符(剑指34,简单题)
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置,如果没有则返回-1(需要区分大小写).(从0开始计数)
class Solution {
public:
int FirstNotRepeatingChar(string str) {
map <char,int> s;
for(int i=0;i<str.size();i++){
s[str[i]]++;
}
for(int i=0;i<str.size();i++){
if(s[str[i]]==1) return i;
}
return -1;
}
};
4、左旋转字符串(剑指43)
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
class Solution {
public:
string LeftRotateString(string str, int n) {
int len=str.size(),i,j;
if(len<=0) return "";
n%=len;
str+=str;
return str.substr(n,len);
}
};
5、翻转单词顺序列(剑指44)
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
class Solution {
public:
//先翻转整个句子,再一次翻转每个单词,最后一个单词单独翻转。
string ReverseSentence(string str) {
reverse(str.begin(),str.end());
int begin=0;
int i=0;
while(str[i]==' ') i++;
for(;i<str.size();i++){
if(str[i]==' '){
reverse(str.begin()+begin,str.begin()+i);
begin=i+1;
}
}
reverse(str.begin()+begin,str.end());
return str;
}
};
6、扑克牌顺子(剑指45)
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
class Solution {
public:
//必须满足 数组包含5个数 除0外没有重复的数 max - min < 5
bool IsContinuous( vector<int> numbers ) {
int len=numbers.size();
if(len!=5) return false;
sort(numbers.begin(),numbers.end());
int i=0;
while(numbers[i]==0) i++;
if(numbers[len-1]-numbers[i]>4) return false;
for(;i<len-1;i++)
if(numbers[i]==numbers[i+1]) return false;
return true;
}
};
7、把字符串转换为整数(剑指49)
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
class Solution {
public:
int StrToInt(string str) {
int flag=1;
long long sum=0;
int i=0;
if(str[0]=='+') i++;
else if(str[0]=='-') {i++;flag=-1;}
for(;i<str.size();i++){
while(str[i]=='0') i++;
if(str[i]>='0'&&str[i]<='9') sum=sum*10+str[i]-'0';
else return 0;
}
if(flag==1&&sum>INT_MAX) return 0;
if(flag==-1&&(-1)*sum<INT_MIN) return 0;
return (int)(sum*flag);
}
};
8、正则表达式匹配(剑指52)
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
方法一:递归方法:
class Solution {
public:
bool match(char* str, char* pattern)
{
if(*str=='\0'&&*pattern=='\0') return true;
if(*str!='\0'&&*pattern=='\0') return false;
if(*(pattern+1)!='*'){
if(*str==*pattern||(*str!='\0'&&*pattern=='.'))
return match(str+1,pattern+1);
else return false;
}
else{
if(*pattern==*str||(*str!='\0'&&*pattern=='.'))
return match(str,pattern+2)||match(str+1,pattern);
else return match(str,pattern+2);
}
return false;
}
};
方法二:动态规划
class Solution {
public:
bool match(char* str, char* pattern)
{
int len1=strlen(str),len2=strlen(pattern);
vector<vector<bool>> dp(len1+1,vector<bool>(len2+1,false));
dp[len1][len2]=true;
int i,j;
for(i=len1;i>=0;i--){
for(j=len2-1;j>=0;j--){
if(j<len2-1&&pattern[j+1]=='*'){
if(i<len1&&(str[i]==pattern[j]||pattern[j]=='.')) dp[i][j]=dp[i][j+2]||dp[i+1][j];
else dp[i][j]=dp[i][j+2];
}
else{
if(i<len1&&(str[i]==pattern[j]||pattern[j]=='.')) dp[i][j]=dp[i+1][j+1];
}
}
}
return dp[0][0];
}
};
9、表示数值的字符串(剑指53)
class Solution {
public:
bool isNumeric(char* string)
{
bool sign=false,decimal=false,flag=false;
for(int i=0;i<strlen(string);i++){
if(string[i]=='e'||string[i]=='E'){
if(i==0||sign) return false;
if(i==strlen(string)-1) return false;
sign=true;
}
else if(string[i]=='+'||string[i]=='-'){
if(flag&&string[i-1]!='e'&&string[i-1]!='E') return false;
if(!flag&&i>0&&string[i-1]!='e'&&string[i-1]!='E') return false;
flag=true;
}
else if(string[i]=='.'){
if(decimal||sign) return false;
if(i==0) return false;
decimal=true;
}
else if(string[i]<'0'||string[i]>'9') return false;
}
return true;
}
};
10、字符流中第一个不重复的字符(剑指54)
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
如果当前字符流没有存在出现一次的字符,返回#字符。
class Solution
{
public:
//Insert one char from stringstream
void Insert(char ch)
{
s.push_back(ch);
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
map<char,int> m;
for(int i=0;i<s.size();i++)
m[s[i]]++;
for(int i=0;i<s.size();i++)
if(m[s[i]]==1) return s[i];
return '#';
}
vector <int> s;
};