代码随想录算法训练营第11天|20. 有效的括号 、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值

20. 有效的括号

题目链接:link
文章讲解:link
视频讲解:link

一、做题感受&第一想法

用栈保存暂未匹配的左括号。
①每当扫描到一个右括号,弹出栈顶元素,看是否是与该右括号匹配的左括号,不是则匹配失败,返回false。如果栈已空,匹配失败,返回false。
②整个字符串扫描完毕,如果栈不空,则说明有未匹配的左括号,匹配失败,返回false。如果栈空,则所有括号完成匹配,返回true。

#define MAX_SIZE 10000
bool isValid(char* s) {
    char stack[MAX_SIZE];
    int top = 0;
    for(int i = 0; s[i] != '\0'; i++){
        if(s[i]=='(' || s[i] == '[' || s[i] == '{' ){
            stack[top] = s[i];
            top++;
        }
        else if(s[i] == ')'){
            if(top != 0){ //不要忘记判断top是否等于0,否则top--会error。
                top--;
            }
            else{
                return false;
            }
            if(stack[top] != '('){
                return false;
            }
        }
        else if(s[i] == ']'){
            if(top != 0){
                top--;
            }
            else{
                return false;
            }
            if(stack[top] != '['){
                return false;
            } 
        }
        else if(s[i] == '}'){
            if(top != 0){
                top--;
            }
            else{
                return false;
            }
            if(stack[top] != '{'){
                return false;
            } 
        }
    }
    if(top == 0){
        return true;
    }
    else{
        return false;
    }
}

二、学习文章后收获

1.括号不匹配的三种情况

要充分考虑这三种情况是否在编程中体现:
①括号类型不匹配
②左端多了左括号
③右端多了右括号


1047. 删除字符串中的所有相邻重复项

题目链接:link
文章讲解:link
视频讲解:link

一、做题感受&第一想法

一开始没有想到栈,但是因为这是栈与队列的题目,所以还是想到了。这说明对栈的应用场景还是不熟悉!

#define MAX_SIZE 200000

char* removeDuplicates(char* s) {
    char* stack = (char*)malloc(sizeof(char)*MAX_SIZE);
    int top = 0, i = 0;
    for(i = 0; s[i] != '\0'; i++){
        if(top != 0 && s[i] == stack[top - 1]){ //如果和栈顶元素相同,则删除栈顶元素
            top--;
        }
        else{
            stack[top] = s[i];
            top++;
        }
    }
    stack[top] = '\0';
    printf("%d",i);
    return stack;
}

二、学习文章后收获

1.栈的经典应用: 删除字符串中的所有相邻重复项

要知道栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。


150. 逆波兰表达式求值

题目链接:link
文章讲解:link
视频讲解:link

一、做题感受&第一想法

一开始把逆波兰式求值和前缀求值搞混了,上来就定义了两个栈,然后写着写着发现并不需要(笑丝)。

#define MAX_SIZE 10000
int operation(char op,int left,int right){
    printf("operation:%d %c %d\n",left,op,right);
    switch(op){
        case '+': return left+right;
        case '-': return left-right;
        case '*': return left*right;
        case '/': return left/right;
    }
    return -1;
}

int backIntoNum(char* s){
    int num = 0, i = 0;
    if(s[0] == '-'){ //先判断是否为负数
        i++;
    }
    for(; s[i] != '\0';i++){
        num *= 10;
        num += s[i] - '0';
    }
    return (s[0]=='-'? (-1)*num : num); //如果是负数,则需要乘-1
}

int evalRPN(char** tokens, int tokensSize) {
    int numStack[MAX_SIZE];
    int numTop = 0;
    int left = 0, right = 0, result = 0;

    for(int i = 0; i < tokensSize ;i++){
        if((tokens[i][0] == '+' || tokens[i][0] == '-' || tokens[i][0] == '*' || tokens[i][0] == '/') && tokens[i][1] == '\0'){
            numTop--;
            right = numStack[numTop]; //右操作数出栈
            numTop--;
            left = numStack[numTop]; //左操作数出栈
            result = operation(tokens[i][0],left,right); //得到运算结果
            numStack[numTop] = result; //运算结果入栈
            numTop++;
        }
        else{ //如果是数字
            numStack[numTop] = backIntoNum(tokens[i]); //字符串转换成数字
            numTop++; //数字入栈
        }
    }
    return numStack[numTop-1]; //返回栈顶元素(是栈里唯一一个元素)
}

二、学习文章后收获

1.逆波兰式是二叉树的后序序列

三、过程中遇到的问题

1.switch语句的语法淡忘了

switch(){
	case xxx: 
			语句1;
			语句2;
			...
			breakcase yyy:
			语句1;
			...
			break;
	default:
			语句1;
			...
			break;
}

2.一开始对char**的理解不清楚。

token[i]对应的是一个char*指针,即后面存的是一个字符串。token[i][j]是字符串里的各个元素。
②如果字符串token[i]是运算符:(tokens[i][0] == '+' || tokens[i][0] == '-' || tokens[i][0] == '*' || tokens[i][0] == '/') && tokens[i][1] == '\0'
不能忘记判断token[i][1],因为如果是负数那么第一个字符也是运算符(减号)。
③如果字符串token[i]是数字:要把字符串转成数字(注意先判断是否是负数)

int backIntoNum(char* s){
    int num = 0, i = 0;
    if(s[0] == '-'){ //先判断是否为负数
        i++;
    }
    for(; s[i] != '\0';i++){
        num *= 10;
        num += s[i] - '0';
    }
    return (s[0]=='-'? (-1)*num : num); //如果是负数,则需要乘-1
}

3.数字字符的ASCII码

数字字符的ASCII码不是从0开始的!
比如,数字0的ASCII码是48(后面的数字依次加一)。
所以由数字字符转成数字真值,可以用s[i] - '0'的方式,减掉0的ASCII码。

4.分清楚:“逆波兰式求值”、“中缀表达式转逆波兰式”、“中缀表达式求值”

(1)逆波兰式求值:

①一个栈,数字栈。
②每扫描到数字,入栈;每扫描到运算符,把栈顶两个元素和运算符做运算,再将结果入栈。
③最后,栈中只剩一个数字,即为结果。

(2)中缀转逆波兰:(考虑括号)

①一个栈,运算符栈。
②扫描中缀表达式。每扫描到数字,输出。
③每扫描到运算符,先将运算符栈中优先级“高于和等于”它的运算符依次弹出栈(到优先级小于它、或左括号、或栈空,为止),再把当前运算符压入栈。④遇到“(”,则压入栈。遇到“)”,将栈中运算符依次弹出,直到弹出“(”为止。

(3)中缀求值:(上述二者的结合)

①两个栈。一个数字栈numStack,一个运算符栈opStack。
②扫描中缀表达式。每扫描到数字,压入数字栈。
③每扫描到运算符,先将运算符栈中优先级“高于和等于”它的运算符依次弹出栈(到优先级小于它、或左括号、或栈空,为止),每弹出一个运算符,要从数字栈弹出两个运算数,把运算结果压入数字栈。最后把当前运算符压入运算符栈。
④遇到“(”,则压入栈。遇到“)”,将栈中运算符依次弹出并做运算,直到弹出“(”为止。
⑤扫描完毕后,运算符栈如果不为空,则依次弹出运算符并做运算。
⑥最终,运算符栈为空。数字栈只剩一个数字,即为结果。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值