Leetcode刷题防忘录(一)

目录

 

string-to-integer-atoi(边界条件,中等)

evaluate-reverse-polish-notation(栈,中等)

surrounded-regions(DFS,BFS ,反推,回溯,中等)

valid-palindrome(回文,双指针,简单)


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;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值