剑指offer
字符串
前几天确实进度有些慢了,三天刷了30+,一半左右,希望能挑战成功。
1.字符串的排列
全排列问题,用回溯的方法。在之前知乎的文章中有详细介绍。方法基本是一模一样的,这里就是要去重和字典序排列,那么用set可以去重和排列。
class Solution {
public:
set <string> res;
//标记访问
vector<bool> used;
//回溯
void backtrack(string &p, string str){
//p的长度等于str
if(p.size()==str.size()){
res.insert(p);
return;
}
for(int i=0;i<str.size();i++){
if(!used[i]){
//选择
p.push_back(str[i]);
used[i]=true;
backtrack(p,str);
//回撤
p.pop_back();
used[i]=false;
}
}
return;
}
vector<string> Permutation(string str) {
used=vector<bool>(str.size(),false);
string p;
vector<string> ret;
if(str.size()==0)return ret;
backtrack(p,str);
for(auto &e:res)
ret.push_back(e);
return ret;
}
};
2.翻转单词顺序列
思路一:先整体翻转,再确定每个单词的位置,单个儿翻转:
class Solution {
public:
string ReverseSentence(string str) {
string s;
if(str.size()==0)return s;
reverse(str.begin() , str.end());
for(int i=0; i < str.size(); i++){
int j=i;
while (j< str.size() && str[j]!=' ')j++;
reverse(str.begin()+i, str.begin()+j);
//注意翻转完之后,需要i=j
i=j;
}
return str;
}
};
3.扑克牌顺子
这道题啰啰嗦嗦半天,我实在是没读懂……看了一下题解才明白……关键点就是五张牌的max-min<5;因为还有大小王,可以看做任何数,所以若差小于4,且无重复牌,说明摸到了大小王,可以当做顺子~
class Solution {
public:
bool IsContinuous( vector<int> numbers ) {
if (numbers.empty()) return false;
int max1=0,min1=14;
set<int> q;
for(int c:numbers){
//如果摸到大小王,则为0,继续,不管
if(c>0){
if(q.count(c)>0)return false;
q.insert(c);
max1=max(max1,c);
min1=min(min1,c);
}
}
return max1-min1<5;
}
};
4.把字符串转换成整数
这道题需要考虑溢出的情况:
class Solution {
public:
int StrToInt(string str) {
int num = 0,i=0,flag=1;
//去掉空格
while(str[i]==' ')i++;
//记录符号
if(str[i]=='-'){flag=-1;i++;}
else if(str[i]=='+'){flag=1;i++;}
while(i<str.size()){
if(isdigit(str[i])){
num= num* 10 + (str[i]-'0');
i++;
//溢出考虑
if(num > INT_MAX && flag==1) return INT_MAX;
else if(num > INT_MAX && flag==-1)
return INT_MIN;
}else{
return 0;
break;
}
}
return num*flag;
}
};
牛客上的题与之类似,但是有不太一样,如果出现字母就不再转:
class Solution {
public:
int strToInt(string str) {
int i=0;long res=0; int flag=1;
while(str[i]==' ')i++;
if(str[i]=='-')flag=-1;
if(str[i]=='-' || str[i] == '+')i++;
while(i<str.size() && isdigit(str[i])){
res = res * 10 + (str[i] - '0');
if(res > INT_MAX && flag == 1)return INT_MAX;
else if(res > INT_MAX && flag == -1)return INT_MIN;
i++;
}
return res*flag;
}
};
5.字符流中第一个不重复的字符
队列,先进先出,hashmap记录次数:
class Solution
{
public:
queue<char> q;
unordered_map<char,int> map;
//Insert one char from stringstream
void Insert(char ch)
{
if (map[ch]==0) {
q.push(ch);
}
map[ch]++;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
while(!q.empty()){
char ch = q.front();
if(map[ch]==1)return ch;
else q.pop();
}
return '#';
}
};
6.表示数值的字符串
1.+、-只能出现在开头或者e之后
2.e前出现e是错误的,且之前之后都必须出现数字
3. .前不能出现.或者e
4.用几个标记记录出现与否
class Solution {
public:
//1.+-只能出现在开头或者e之后
//2.e前出现e是错误的,且之前之后都必须出现数字
//3. .前不能出现.或者e
bool isNumeric(char* string)
{
if(string == nullptr) return false;
bool dot =false, e=false, num =false;
for(int i=0; i<strlen(string); i++){
if(string[i] == '.'){
if(e==true || dot==true){
return false;
}
dot = true;
}
else if(string[i] == 'e'|| string[i] == 'E'){
if(e==true || num==false){
return false;
}
e = true;
//防止12e这种情况发生
num = false;
}
else if(string[i] >= '0' && string[i] <= '9'){
num = true;
}
else if(string[i] == '+' || string[i] == '-'){
if(i!=0 && string[i-1] != 'e'
&& string[i- 1]!='E')
{
return false;
}
}
else{
return false;
}
}
//最后一位一定是数字,并且肯定出现过数字
return num;
}
};
数字
7.字符流中第一个不重复的字符
按位与找到进位位、左移进位、按位异或、递归。
class Solution {
public:
int Add(int num1, int num2)
{
int n1=(num1 & num2) <<1;
int n2 = num1 ^ num2;
return n1 == 0? n2 : Add(n1, n2);
}
};
堆
8.数据流中的中位数
两个堆:
class Solution {
public:
int size=0;
void Insert(int num)
{
size++;
minp.push(num);
maxp.push(minp.top());
minp.pop();
if(minp.size() < maxp.size()){
minp.push(maxp.top());
maxp.pop();
}
}
double GetMedian()
{ if(size == 0) return -1;
if(size%2==0) return (minp.top()+maxp.top())*0.5;
else return minp.top();
}
priority_queue<int,vector<int>,greater<int>> minp;
priority_queue<int,vector<int>,less<int>> maxp;
};