目录
string-to-integer-atoi(边界条件,中等)
evaluate-reverse-polish-notation(栈,中等)
surrounded-regions(DFS,BFS ,反推,回溯,中等)
string-to-integer-atoi(边界条件,中等)
实现函数 atoi 。函数的功能为将字符串转化为整数
提示:仔细思考所有可能的输入情况。这个问题故意描述的很模糊(没有给出输入的限制),你需要自己考虑所有可能的情况。
思路
此题难就难在要把所有的边界条件考虑清楚,分别是:1.正负号;2.中间存在字母(只取字母前的数字);3.溢出;4.前后空格
所以,顺着代码的思路往下看,先是最基础的,如果字符串为空就直接返回0。
if(*str=='\0') return 0;
接着,设置指针p,指向字符串首位置,开始准备从头开始遍历字符串,接着一个while语句用来提防是否有空格,如果有空格,就直接跳过。这种情况是默认的在字符串之前有空格的话,就这样处理,可以跳过,那字符串之后或者字符串之间要是有空格呢?那就用后面的,isdigit判断来处理。
const char* p =str;
while(*p==' ') ++p;
判断完字符串之前没有空格之后,再来就是判断字符串的开头符号了,这个决定了转换成整型数字的正负。逻辑很精彩,先if判断是否为符号,是的话进入判断体,正符号的话sign置1,负符号的话sign置-1。
if(*p=='+' ||*p=='-') sign=(*p++=='+')?1:-1;
在判断完符号位后,开始进行逐个比较,先生成一个long型的res,用来存放结果,接着开始while循环,如果是数字,就进入循环,
long res=0;
while(isdigit(*p)){
}
再接下来生成数字的过程也很巧妙,用上一次的res乘上10当作进位,将当前p指向的字符转换为整型后(-‘0’)相加。每次还都要判断有没有超过int的最大最小值。这个地方有个隐藏的地方,就是再开始的时候res的类型设置成了long,这是因为,如果设置成int类型,真有if里面的情况发生,里面就报错了,就不存在比较大小了。
res=res*10+(*p++)-'0';
if(res*sign>=INT_MAX) return INT_MAX;
if(res*sign<=INT_MIN) return INT_MIN;
最后,将结果乘上符号位sign,短小精悍!
return res*sign;
完整code
class Solution {
public:
int atoi(const char *str) {
if(*str=='\0') return 0;
const char* p =str;
while(*p==' ') ++p;
int sign=1;
if(*p=='+' ||*p=='-') sign=(*p++=='+')?1:-1;
long res=0;
while(isdigit(*p)){
res=res*10+(*p++)-'0';
if(res*sign>=INT_MAX) return INT_MAX;
if(res*sign<=INT_MIN) return INT_MIN;
}
return res*sign;
}
};
evaluate-reverse-polish-notation(栈,中等)
根据逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: ((2 + 1) * 3) = 9
示例 2:
输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: (4 + (13 / 5)) = 6
示例 3:
输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
输出: 22
解释:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
思路
1.逆波兰表达式求解,定义一个栈辅助计算;
2.当遇到运算符"+"、"-"、"*"、"/"时,从栈中pop出两个数字计算,否则将数字入栈;
3.完结。
首先,定义一个栈的变量store,用来存放。
stack<int> store;
接下来开始一个大的for循环,这个for的方式很值得学习,不需要任何条件,就是之间遍历s里面的每个字符。
for(auto x: s){
}
在循环里面分两个部分,如果是符号位,就执行那么一大坨的东西,如果不是符号位就把当前值给压到store里面。
主要看看当是符号位的时候的操作,因为整个运算的思路就是当遇到运算符"+"、"-"、"*"、"/"时,从栈中pop出两个数字计算,先是一个边界条件的判断,如果压入的数字少于两个,就没法进行计算了,所以直接返回0,否则的话,就把store里面的最上面两个值给弄处理,放到a,b里面暂存且a,b随每次循环而更新。
if(store.size()<2) return 0;
int a=store.top();store.pop();
int b=store.top();store.pop();
然后,执行计算,把计算结果重新给塞到store里面。
int c=0;
if(x=="+")
c=a+b;
else if(x=="-")
c=b-a;
else if(x=="*")
c=b*a;
else if(x=="/")
c=b/a;
store.push(c);
另外补充的是,else语句里面有一个atoi()
是C语言中的字符串转换成整型数的一个函数,toi()
是C语言提供的函数,而C语言中没有string类,字符串使用char指针来实现的。C与C++本身就是一家,为了让它们在一定程度上可以通用,就有了.c_str()
函数。就是在string类型的str后面加上了.c_str()函数,这也就是.c_str()的作用:
.c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同。因为string类本身只是一个C++语言的封装,其实它的string对象内部真正的还是char缓冲区,所以.c_str()指向了这个缓冲区并返回const。简而言之,atoi(x.c_str())是固定搭配,当用atio遍历字符串的时候要搭配.c_str
详情参见:https://blog.csdn.net/chaipp0607/article/details/75371149
store.push(atoi(x.c_str()));
完整code
class Solution {
public:
int evalRPN(vector<string> &s) {
stack<int> store;
for(auto x: s)
{
if(x=="+"||x=="-"||x=="*"||x=="/")
{
if(store.size()<2) return 0;
int a=store.top();store.pop();
int b=store.top();store.pop();
int c=0;
if(x=="+")
c=a+b;
else if(x=="-")
c=b-a;
else if(x=="*")
c=b*a;
else if(x=="/")
c=b/a;
store.push(c);
}
else
{
store.push(atoi(x.c_str()));
}
}
return store.top();
}
};
surrounded-regions(DFS,BFS ,反推,回溯,中等)
给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。
找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
示例:
X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
思路
最开始,先进行边界判断,如果board为空,就直接结束,再把board的横纵长度记录下来。
if(board.size()==0){
return;
}
int rows=board.size(),cols=board[0].size();
再接着下面的两个for循环,一个是从第一行和最后一行,从左向右遍历,一个是从第一列和最后一列,从上往下遍历。因为任何不在边界上,或不与边界上的 'O'
相连的 'O'
最终都会被填充为 'X',所以我就把board四个最外边上的行列作为输入。并且, 只在边界上找,如果发现在边界上,或者不仅在边界上而且,还有与内部相连的‘o’,都把它们置成‘1’,作标记。
for(int i=0;i<rows;i++){
dfs(board,i,0);
dfs(board,i,cols-1);
}
for(int j=1;j<cols-1;j++){
dfs(board,0,j);
dfs(board,rows-1,j);
}
下面分析关键函数dfs,传入的是三个参数,一个是board,一个是行数,一个是列数。每次只要发现边界上有“o”,就先置成1,然后,去找它的上下左右有没有跟它相连的“o”,有的话也置成1,
if(i>=0&&i<board.size()&&j>=0&&j<board[0].size()&&board[i][j]=='O'){
board[i][j]='1';
dfs(board,i-1,j);
dfs(board,i+1,j);
dfs(board,i,j-1);
dfs(board,i,j+1);
}
最后,将原先没置成1的‘o’都置成‘x’,代表可以被填充,置成1的都置换成‘o’,表不可以被填充。
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(board[i][j]=='1'){
board[i][j]='O';
}
else{
board[i][j]='X';
}
}
}
完整code
/*
First, check the four border of the matrix. If there is a element is
'O', alter it and all its nei***or 'O' elements to '1'.
Then ,alter all the 'O' to 'X'
At last,alter all the '1' to 'O'
For example:
X X X X X X X X X X X X
X X O X -> X X O X -> X X X X
X O X X X 1 X X X O X X
X O X X X 1 X X X O X X
*/
class Solution {
public:
void solve(vector<vector<char>>& board) {
if(board.size()==0){
return;
}
int rows=board.size(),cols=board[0].size();
for(int i=0;i<rows;i++){
dfs(board,i,0);
dfs(board,i,cols-1);
}
for(int j=1;j<cols-1;j++){
dfs(board,0,j);
dfs(board,rows-1,j);
}
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(board[i][j]=='1'){
board[i][j]='O';
}
else{
board[i][j]='X';
}
}
}
}
private:
void dfs(vector<vector<char>>& board,int i,int j){
if(i>=0&&i<board.size()&&j>=0&&j<board[0].size()&&board[i][j]=='O'){
board[i][j]='1';
dfs(board,i-1,j);
dfs(board,i+1,j);
dfs(board,i,j-1);
dfs(board,i,j+1);
}
}
};
valid-palindrome(回文,双指针,简单)
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true
示例 2:
输入: "race a car"
输出: false
思路
isalnum 判断字符变量c是否为字母或数字,若是则返回非零,否则返回零。
利用两个指针首位开始遍历,设置i为首指针,j为尾指针,两个方向开始进行遍历,如果遍历到的值不是数字,就i++或者j++,相当于跳过非字母的值,探查下一个字母,而且,每次遇到非字母的值的时候,就会从while中跳出来,i,j仍保持刚刚遍历到的值,然后,开始比较i,j当前比较的值,如果不一样,就返回false了, 否则,就继续循环,for里面也会对i,j进行累加,跳过上次停下来的非字母位置。
for(i=0,j=s.size()-1;i<j;i++,j--)
{
while(i<j&&!isalnum(s[i]))
i++;
while(i<j&&!isalnum(s[j]))
j--;
if(i<j&&tolower(s[i])!=tolower(s[j]))
return false;
}
return true;
完整code
class Solution {
public:
bool isPalindrome(string s) {
if(s.size()==0)
return true;
int i,j;
for(i=0,j=s.size()-1;i<j;i++,j--)
{
while(i<j&&!isalnum(s[i]))
i++;
while(i<j&&!isalnum(s[j]))
j--;
if(i<j&&tolower(s[i])!=tolower(s[j]))
return false;
}
return true;
}
};