剑指offer C++ 字符串
1.替换空格
解法1:STL
有已有的函数还是很舒服的,没什么好说的
class Solution {
public:
string replaceSpace(string s) {
for(int i=0;i<s.size();i++)
{
if(s[i]==' ') //有时候用惯了python,注意这里只能用单引号,C++里不一样的
{
s.replace(i,1, "%20");//这句话的意思从i位置开始的第一个字符进行替换
}
}
return s;
}
};
解法2:正常写法
创建一个新的数组
用这个新的函数遍历s字符串,如果遇到空格就添加3个新字符(%20)
把这个数组变成字符串
class Solution {
public:
string replaceSpace(string s) {
string s1(3*s.size(),0);//别忘了设置新字符串的大小
int j=0;
for(int i=0;i<s.size();i++)
{
if(s[i]!=' ')
{
s1[j++]=s[i];
}
else{//最好一个个写进去
s1[j++]='%';
s1[j++]='2';
s1[j++]='0';
}
}
return s1;
}
};
其实也可以
for(int i=0;i<s.size();i++)
{
if(s[i]==' '){
a+="%20";
}else{
a+=s[i];
}
}
用 += 的话会频繁进行字符数组空间开辟和拷贝,每次都会产生一个新的String对象。s1(3*s.size(),0)直接给他分配一个需要的内存,虽然可能会占用多点内存,还是这样好点
解法3:python偷懒
s.replace(" ", "%20")//haha,这是不是作弊
2.第一个只出现一次的字符
解法1:哈希法
小tip:
for(char &c:str ), ### 法 1
for(char c:str ) ###法2
中遍历都可以,但法2会复制一个s字符串再进行遍历操作,法1直接引用原字符串进行遍历操作.法1用起来会更优,在内存or时间上
class Solution {
public:
int FirstNotRepeatingChar(string str) {
unordered_map<char, int> mp;//建立哈希
for(char &c:str )//先遍历一边所有字符,并统计出现次数
mp[c]++;
for(int i=0;i<str.size();i++)//因返回的是位置,所以要用i遍历
{
if(mp[str[i]]==1)
return i;
}
return -1;
}
};
3.左旋转字符串
解法1:暴力破解
2个循环分别遍历从n开始和0-n部分
class Solution {
public:
string LeftRotateString(string str, int n) {
if (n > str.size()) return str;
string string2="" ;
for(int i=0;i<(str.size()-n);i++){//从n开始的部分
string2[i] = str[i+n];
}
for(int i=0;i<n;i++)//n之前的部分
string2[str.size()-n+i] = str[i];
return string2;
}
};
解法2:采用标准库
形式 : s.substr(pos, len)
返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos)
class Solution {
public:
string LeftRotateString(string str, int n) {
if(str.empty()) return str;
string string2;
int j = str.size();
n=n%j; //应对移位大于字符串长度这种情况
string2 = str.substr(n)+str.substr(0,n);
return string2;
}
};
4. 字符流中第一个不重复的字符
解法一:哈希法
感觉和上面第二题有点像,就是在哈希的基础上又加了一个创建了一个字符串。因为是字符流,不能确定字符串大小。只能来一个放进去一个。剩下的和第二题思路一样
class Solution
{
public:
//Insert one char from stringstream
string str;
unordered_map<char, int> mp;
void Insert(char ch) {
str+=ch;//向字符串中插入字符流
++mp[ch];//统计出现次数
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce() {
for(int i=0;i<str.size();i++)//遍历
{
if(mp[str[i]]==1)
return str[i];
}
return '#';
}
};
解法二:哈希+队列
来自https://blog.nowcoder.net/n/23f5c7b86af64c62b811c2e9ec2cf5b1?f=comment
感觉就是把字符串数组变成了队列
class Solution
{
public:
//Insert one char from stringstream
queue<char> q;
unordered_map<char, int> mp;
void Insert(char ch)
{
// 如果是第一次出现, 则添加到队列中
if (mp.find(ch) == mp.end()) {
q.push(ch);
}
// 不管是不是第一次出现,都进行计数
++mp[ch];
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
while (!q.empty()) {
char ch = q.front();
// 拿出头部,如果是第一次出现,则返回
if (mp[ch] == 1) {
return ch;
}
// 不是第一次出现,则弹出,然后继续判断下一个头部
else {
q.pop();
}
}
return '#';
}
};
5. 字符串的排列
解法一:递归法
递归的话就很简单了,以{1,2,3}为例,它的排列是:
以1开头,后面接着{2,3}的全排列,
以2开头,后面接着{1,3}的全排列,
以3开头,后面接着{1,2}的全排列.
class Solution {
public:
vector<string> Permutation(string str) {
if(str.empty()) return{};
set<string> ret;//set可以进行去重,且可以按字母顺序排序
perm(0,str,ret);
return vector<string>({ret.begin(),ret.end()});
}
void perm(int index,string str,set<string> &ret)
{
if(index==str.length())//完成了一次全排列
{
ret.insert(str);
return;
}
for(int i=index;i<str.size();i++)
{
swap(str[index],str[i]);
perm(index+1,str, ret);// 回溯:比如第二次交换后是"BAC",需要回溯到"ABC"
swap(str[index],str[i]);
}
}
};
解法二:字典法
这里比较偷懒用了
next_permutation:对于当前的排列,如果在字典序中还存在下一个排列,返回真,并且将下一个排列赋予当前排列,如果不存在,就把当前排列进行递增排序。
class Solution {
public:
vector<string> Permutation(string str) {
vector<string>ans;
if(str.size()==0)return ans;
sort(str.begin(),str.end());//将str里的按字典序排序
do{
ans.push_back(str);
}while(next_permutation(str.begin(),str.end()));
return ans;
}
};
6.把字符串转换成整数
解法1:随便什么方法
注释应该写的清除了。核心很简单,就是要注意各种范围的界定。
class Solution {
public:
int StrToInt(string str) {
int num=0,a;
if(str.size()<=0) return 0;//防止其为空
if(str[0]=='-') //有-号情况
{
a=-1;
str.erase(0,1);
}
else if(str[0]=='+') //有+号情况
{
a=1;
str.erase(0,1);
}
else a=1;//没有号情况
for(int j=0;j<str.size();j++)
{
if(!(str[j]>='0' && str[j]<='9'))//排除含有字母情形
return 0;
num = num*10+str[j]-'0';//核心语句
}
return num*a;
}
};
7.正则表达式匹配
解法一:动态规划
参考链接:https://blog.csdn.net/gatieme/article/details/51542072?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162851058416780255294343%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162851058416780255294343&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-2-51542072.pc_search_download_positive&utm_term=%E7%89%9B%E5%AE%A2%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8DC%2B%2B&spm=1018.2226.3001.4187
class Solution
{
public:
bool match(string s, string p) {
int m = s.size(), n = p.size();
vector<vector<bool>> f(m + 1, vector<bool>(n + 1, false));
f[0][0] = true;
for (int i = 1; i <= m; i++)
f[i][0] = false;
// p[0.., j - 3, j - 2, j - 1] matches empty iff p[j - 1] is '*' and p[0..j - 3] matches empty
for (int j = 1; j <= n; j++)
f[0][j] = j > 1 && '*' == p[j - 1] && f[0][j - 2];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (p[j - 1] != '*')
f[i][j] = f[i - 1][j - 1] && (s[i - 1] == p[j - 1] || '.' == p[j - 1]);
else
// p[0] cannot be '*' so no need to check "j > 1" here
f[i][j] = f[i][j - 2] || (s[i - 1] == p[j - 2] || '.' == p[j - 2]) && f[i - 1][j];
return f[m][n];
}
};
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size();
int n = p.size();
auto matches = [&](int i, int j) {
if (i == 0) {
return false;
}
if (p[j - 1] == '.') {
return true;
}
return s[i - 1] == p[j - 1];
};
vector<vector<int>> f(m + 1, vector<int>(n + 1));
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '*') {
f[i][j] |= f[i][j - 2];
if (matches(i, j - 1)) {
f[i][j] |= f[i - 1][j];
}
}
else {
if (matches(i, j)) {
f[i][j] |= f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/regular-expression-matching/solution/zheng-ze-biao-da-shi-pi-pei-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
8.表示数值的字符
解法一:一般解法
class Solution {
public:
bool isNumeric(string str) {
while(str.size()>0&&str[0]==' ') str.erase(0,1);//删除空格
while(str.size()>0&&str[str.size()-1]==' ') str.erase(str.size()-1,1);
bool a=false;
bool b=false;
bool c=false;
for(int i=0;i<str.size();i++)
{
if(str[i]=='e'||str[i]=='E')//判断eE
{
if(b||!a){return false;}
else{a=false;b=true;}
}
else if(str[i]=='.')//判断.
{
if(b||c) return false;
c=true;
}
else if(str[i]>='0'&&str[i]<='9')//判断是否出现数字
{
a=true;
}
else if(str[i]=='+'||str[i]=='-')//判断正负号
{
if(i!=0&&(str[i-1]!='e'&&str[i-1]!='E')) return false;
}
else return false;
}
return a;
}
};
解法二:正则表达式
#include <regex>
class Solution {
public:
bool isNumeric(string str) {
regex reg("([+-])?([0-9]*)?([0-9]+|\\d+\\.\\d*|\\.\\d+)(([eE])[+-]?\\d+)?$");
//regex reg("[+-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)([eE][+-]?[0-9]+)?");
return regex_match(str,reg);
}
};
不知道为什么39个案例总是只能通过34个左右
java
class Solution {
public boolean isNumber(String s) {
if(s == null || s.length() == 0){
return false;
}
//面向测试用例编程,末尾有空格算数字?不解
s = s.trim();
try{
double a = Double.parseDouble(s);
}catch (Exception e){
return false;
}
char c = s.charAt(s.length()-1);
//特,末尾有f,d,D这些不算,但是3.算数字(面向测试用例编程)
return (c >= '0' && c <= '9') || c == '.';
}
}
9.翻转单词序列
解法一:类似于栈
来源:https://www.nowcoder.com/profile/899694
根据空格获得单词的字符串,不断从前面插入反转后的语句中。从后往前遍历
class Solution {
public:
string ReverseSentence(string str) {
string tmp="";//单词
string sent="";//反转后语句
for(int i=0;i<str.size();i++)
{
if(str[i]==' ') sent = " "+tmp+sent,tmp="";
else tmp = tmp+str[i];
}
if(tmp.size()) sent = tmp+sent;
return sent;
}
};
sent = " “+tmp+sent,tmp=”"这句不知道想表达什么意思
解法二:常规做法
常规,建立一个反转函数
先把整个字符串翻转,再对字符串中每个单词翻转,单词翻转2次再此变成正常顺序
class Solution {
public:
void Reverse(string &str,int ben,int end)//翻转
{
while(ben<end)
swap(str[ben++],str[end--]);
}
string ReverseSentence(string str) {
int i=0,end=0,ben=0;//一定要初始化
Reverse(str,0, str.size()-1);//把str整个字符串都翻转
while(i<str.size())
{
while(i<str.size()&&str[i]==' ') i++;
end=ben=i;//每个单词第一个字位置
while(i<str.size()&&str[i]!=' ')
{
end++;i++;
}
Reverse(str, ben,end-1);//在单词内部翻转,变成原来正常的单词
}
return str;
}
};
注意void Reverse(string &str,int ben,int end)这里字符串是取地址符,否则会出错