20. 有效的括号
题目链接/文章讲解/视频讲解:代码随想录
给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
分析及思路
首先分析什么叫匹配,什么叫不匹配。当我们碰到'(','[','{'时我们直接入栈,当碰到')',']','}'时弹出栈,看出栈的数据是否和该括号匹配。
期间有一个不匹配则直接返回不匹配。
代码及注释
// 定义元素类型为int
#define ElemType int
// 定义栈节点结构体
typedef struct StackNode{
ElemType data; // 数据
struct StackNode* next; // 指向下一个节点的指针
}StackNode,*LinkStack; // 定义栈节点类型和指向栈节点的指针类型
// 初始化栈
LinkStack initialize(void){
LinkStack temp = (StackNode*)malloc(sizeof(StackNode)); // 为栈节点分配内存
temp->next = NULL; // 将栈节点的指针域置空
return temp; // 返回初始化后的栈
}
// 入栈操作
void StackPush(LinkStack Stack,ElemType data){
StackNode* temp = (StackNode*)malloc(sizeof(StackNode)); // 为新节点分配内存
temp->data = data; // 将数据存入新节点
temp->next = Stack->next; // 将新节点插入到栈顶
Stack->next = temp;
}
// 出栈操作
ElemType StackPop(LinkStack Stack){
if(StackEmpty(Stack)){ // 如果栈为空
return -1; // 返回-1表示出栈失败
}
StackNode* temp = Stack->next; // 指向栈顶节点
Stack->next = temp->next; // 栈顶指针指向下一个节点
int temp_data = temp->data; // 保存栈顶数据
free(temp); // 释放栈顶节点内存
return temp_data; // 返回栈顶数据
}
// 判断栈是否为空
bool StackEmpty(LinkStack Stack){
return Stack->next == NULL; // 如果栈顶指针为空,表示栈为空
}
// 判断括号序列是否有效
int isValid(char* s) {
LinkStack Stack = initialize(); // 初始化栈
int s_len = strlen(s); // 获取字符串长度
ElemType data1; // 用于保存出栈的数据
for(int i=0;i<s_len;i++){ // 遍历输入的字符串
switch(s[i]){ // 判断字符类型
case '(':case '[':case '{': // 如果是左括号
StackPush(Stack,s[i]); // 入栈
break;
case ')': // 如果是右圆括号
data1 = StackPop(Stack); // 出栈
if( data1 != '(' ) // 判断出栈的括号类型是否匹配
return 0; // 不匹配,返回0
break;
case ']': // 如果是右方括号
data1 = StackPop(Stack); // 出栈
if( data1 != '[' ) // 判断出栈的括号类型是否匹配
return 0; // 不匹配,返回0
break;
default: // 如果是右花括号
data1 = StackPop(Stack); // 出栈
if( data1 != '{' ) // 判断出栈的括号类型是否匹配
return 0; // 不匹配,返回0
}
}
if(StackEmpty(Stack)) // 判断最终栈是否为空
return 1; // 如果为空,返回1表示括号序列有效
return 0; // 如果不为空,返回0表示括号序列无效
}
卡哥思路实现
int isValid(char* s) { // 定义一个函数isValid,参数为字符串s
LinkStack Stack = initialize(); // 初始化一个链栈Stack
int s_len = strlen(s); // 获取字符串s的长度
ElemType data1; // 定义一个元素类型data1
for(int i=0;i<s_len;i++){ // 循环遍历字符串s
switch(s[i]){ // 判断当前字符
case '(':StackPush(Stack,')');break; // 如果是'(',将')'压入栈中
case '[':StackPush(Stack,']');break; // 如果是'[',将']'压入栈中
case '{':StackPush(Stack,'}');break; // 如果是'{',将'}'压入栈中
default:if( (StackEmpty(Stack)) || (StackPop(Stack)!=s[i]) )return 0; // 如果是其他字符,且栈为空或弹出的元素与当前字符不匹配,则返回0
}
}
if(StackEmpty(Stack)) // 如果栈为空
return 1; // 返回1
return 0; // 否则返回0
}
1047. 删除字符串中的所有相邻重复项
题目链接/文章讲解/视频讲解:代码随想录
给出由小写字母组成的字符串
S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
分析及思路
分析相邻的就消掉,也就是最后一个访问的时候,看上一个字母是不是和它一样,推出最近最新访问的就是我们要寻找的元素,符合栈的特点,我们用栈来解决问题。
代码及注释
// 定义一个函数,输入参数为字符指针,返回类型为字符指针
char* removeDuplicates(char* s) {
// 获取输入字符串的长度
int s_len = strlen(s);
// 创建一个字符数组作为栈,长度为输入字符串长度加1
char* stack = (char*)malloc(sizeof(char)*s_len+1);
// 初始化栈顶指针为-1
int StackTop = -1;
// 遍历输入字符串
for(int i=0;i<s_len;i++){
// 如果栈为空或者栈顶字符与当前字符不相等,则将当前字符入栈
if( (StackTop == -1) || (stack[StackTop] != s[i]) )
stack[++StackTop] = s[i];
// 如果栈顶字符与当前字符相等,则将栈顶字符出栈
else
StackTop--;
}
// 在栈顶指针位置添加字符串结束符
stack[++StackTop] = '\0';
// 返回去重后的字符串
return stack;
}
150. 逆波兰表达式求值
题目链接/文章讲解/视频讲解:代码随想录
给你一个字符串数组
tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
分析及思路
就是后缀表达式,遇到数字就压入栈中 ,遇到运算符就弹出两个元素,进行运算,先弹出的元素在左,后弹出的元素在右。
代码及注释
#define ElemType int // 定义元素类型为整数
typedef struct StackNode{ // 定义栈节点结构
ElemType data; // 数据域
struct StackNode* next; // 指针域
}StackNode, *LinkStack; // 栈节点类型定义为指向栈节点的指针
LinkStack initialize(void){ // 初始化栈
LinkStack temp = (StackNode*)malloc(sizeof(StackNode)); // 分配内存
temp->next = NULL; // 初始化栈顶指针
return temp; // 返回栈顶指针
}
void StackPush(LinkStack Stack, ElemType data){ // 入栈操作
StackNode* temp = (StackNode*)malloc(sizeof(StackNode)); // 创建新节点
temp->data = data; // 赋值
temp->next = Stack->next; // 新节点入栈
Stack->next = temp; // 栈顶指针指向新节点
}
bool StackEmpty(LinkStack Stack){ // 判断栈是否为空
if(Stack->next == NULL) // 栈顶指针为空
return true; // 栈为空
return false; // 栈非空
}
bool StackPop(LinkStack Stack, ElemType* data){ // 出栈操作
if(StackEmpty(Stack)) // 判断栈是否为空
return false; // 栈空,出栈失败
*data = Stack->next->data; // 获取出栈数据
StackNode* temp = Stack->next; // 临时保存出栈节点
Stack->next = temp->next; // 栈顶指针指向下一个节点
free(temp); // 释放出栈节点内存
return true; // 出栈成功
}
int evalRPN(char** tokens, int tokensSize) { // 逆波兰表达式求值
int number1, number2; // 临时变量
LinkStack stack = initialize(); // 初始化栈
for(int i = 0; i < tokensSize; i++){ // 遍历表达式
if( strcmp(tokens[i], "-") == 0 ){ // 减法
StackPop(stack, &number1); // 出栈操作
StackPop(stack, &number2); // 出栈操作
StackPush(stack, number2 - number1); // 入栈操作
}
else if( strcmp(tokens[i], "+") == 0 ){ // 加法
StackPop(stack, &number1); // 出栈操作
StackPop(stack, &number2); // 出栈操作
StackPush(stack, number2 + number1); // 入栈操作
}
else if( strcmp(tokens[i], "*") == 0 ){ // 乘法
StackPop(stack, &number1); // 出栈操作
StackPop(stack, &number2); // 出栈操作
StackPush(stack, number2 * number1); // 入栈操作
}
else if( strcmp(tokens[i], "/") == 0 ){ // 除法
StackPop(stack, &number1); // 出栈操作
StackPop(stack, &number2); // 出栈操作
StackPush(stack, number2 / number1); // 入栈操作
}
else{ // 数字
int number = atoi(tokens[i]); // 将字符串转换为整数
StackPush(stack, number); // 入栈操作
}
}
int result; // 最终结果
StackPop(stack, &result); // 获取栈顶元素
return result; // 返回结果
}