1.2 LeetCode总结(线性表)_栈

本文深入探讨了多种编程技巧和算法实现,包括用栈实现队列的双栈法,有效括号字符串的判断,基本计算器的计算逻辑,以及二叉树的层次遍历等。通过具体实例讲解了算法设计思想和C语言实现细节。

编程总结

每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧

232. 用栈实现队列

在这里插入图片描述

要点就是,先要有栈的数据结构及其实现,然后用两个栈,一个作in stack,一个作out stack来实现队列的先入先出:
a. 进队列,都默认进到 in stack里;
b. 查队列首元素,要求先入先出,那就得先将 in stack 的数据都放到 out stack 里去,这时 out stack 里的top元素就是队列要出的元素;
c. 出队列时,先判断 out stack是否为空,为空则in2out搬运,否则,直接出out stack的top即可;

// 1. 栈数据结构的实现
typedef struct {
   
   
	int *stk;
	int stkSize;
	int stkCapacity;
} Stack;
Stack *stackCreate(int capacity)
{
   
   
	Stack *ret = (Stack *)malloc(sizeof(Stack));
	ret->stk   = (int *)malloc(sizeof(int) * capacity);
	ret->stkSize = 0;
	ret->stkCapacity = capacity;
	return ret;
}
void stackPush(Stack *obj, int x)
{
   
   
	obj->stk[obj->stkSize++] = x;
}
void stackPop(Stack *obj)
{
   
   
	obj->stkSize--;
}
int stackTop(Stack *obj)
{
   
   
	return obj->stk[obj->stkSize - 1];
}
bool stackEmpty(Stack *obj)
{
   
   
	return obj->stkSize == 0; // size为0,则满足条件为空,返回1
}
void stackFree(Stack *obj)
{
   
   
	free(obj->stk);
}
---------------------------------------------------------
// 2. 队列数据结构的实现
typedef struct {
   
   
	Stack *inStack;
	Stack *outStack;
} MyQueue;
// in stack -> out stack.
void in2out(MyQueue *obj) {
   
   
	while (!stackEmpty(obj->inStack)) {
   
   
		stackPush(obj->outStack, stackTop(obj->inStack));
		stackPop(obj->inStack);
	}
}
// 1. 建立两个栈
MyQueue *myQueueCreate() {
   
   
	MyQueue *ret  = (MyQueue *)malloc(sizeof(MyQueue));
	ret->inStack  = stackCreate(100);
	ret->outStack = stackCreate(100);
	return ret;
}
// 2. 进入到 in栈
void myQueuePush(MyQueue *obj, int x) {
   
   
	stackPush(obj->inStack, x);      // 直接入栈即可
}
// 3. 出队列的队首元素为 out栈的栈顶元素
int myQueuePop(MyQueue *obj) {
   
   
	if (stackEmpty(obj->outStack)) {
   
    // 这三行是精髓的部分,判断out是否为空,若不为空,则直接出栈Top,若为空,则将in stack搬运过来
		in2out(obj);
	}
	int x = stackTop(obj->outStack);
	stackPop(obj->outStack);
	return x;
}
// 4. 返回队列开头的元素,先判断如果out栈为空,就更新in的元素过去,最后返回out栈的栈顶元素
int myQueuePeek(MyQueue *obj) {
   
   
	if (stackEmpty(obj->outStack)) {
   
   
		in2out(obj);
	}
	return stackTop(obj->outStack);
}
bool myQueueEmpty(MyQueue *obj) {
   
   
	return stackEmpty(obj->inStack) && stackEmpty(obj->outStack);
}
void myQueueFree(MyQueue *obj) {
   
   
	stackFree(obj->inStack);
	stackFree(obj->outStack);
}

020.有效括号_一刷(80%)

思路:左括号则入栈,右括号判断并出栈

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串

思路:将字符串都判断如果是左括号(‘(’,‘[’,‘{’,‘(’)都进行入栈,遇到其他括号符号则:1)取出栈顶元素,2)同时将栈顶元素的match括号匹配上,3)然后Pop栈顶元素和match元素进行比对,如果一致继续循环判断,否则退出,直到遍历完所有的字符串长度。
在这里插入图片描述

a. 遇到左括号放入栈顶
b. 遇到右括号,取出栈顶的左括号并判断它们是否是相同类型的括号; 如果不是相同的类型,或者栈中并没有左括号,那么字符串无效,返回 False(先入栈也行,最后判断栈里是否都清空了)

C语言实现一个栈往往较为复杂,多数解题是通过一个数组来模拟栈
下面给出用数组模拟上述算法的代码:

bool isValid(char *s)
{
   
   
	char stack[10001] = {
   
   0};
	int top = 0;
	int len = strlen(s);
  	for (int i = 0; i < len; i++) {
   
   
		if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
   
    // 1. 如果是左括号则入栈
			stack[top] = s[i];
			top++;
		} else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
   
    // 2. 如果是右括号则判断
			if (top == 0) {
   
    // else 分支里有top-1,这里先判断top==0情况
				return false;
			} else if ((s[i] == ')') && (stack[top - 1] == '(')) {
   
   
				top--;
			} else if ((s[i] == ']') && (stack[top - 1] == '[')) {
   
   
				top--;
			} else if ((s[i] == '}') && (stack[top - 1] == '{')) {
   
   
				top--;
			} else {
   
    // 如果上述都不相等,则返回不匹配,false
				return false;
			}
		}
	}
	if (top == 0) {
   
   
		return true;
	} else {
   
   
		return false;
	}
}
int main()
{
   
   
	bool ret = isValid("(])");
	printf("ret = %d ", ret);
	return 0;
}

顺带提一句在LeetCode平台的 False== 0; True == 1;在这里插入图片描述

678. 有效的括号字符串_*刷(20%)

在这里插入图片描述
在这里插入图片描述

思路:关键是 * 号的处理,给题目来了不一样的处理 – 双栈

A. 将当前下标存入左括号栈。
B. 如果遇到星号,则将当前下标存入星号栈。
C. 如果遇到右括号,则需要有一个左括号或星号和右括号匹配,由于星号也可以看成右括号或者空字符串,因此当前的右括号应优先和左括号匹配,没有左括号时和星号匹配:
C1)如果左括号栈不为空,则从左括号栈弹出栈顶元素;
C2)如果左括号栈为空且星号栈不为空,则从星号栈弹出栈顶元素;
C3)如果左括号栈和星号栈都为空,则没有字符可以和当前的右括号匹配,返回 false。
D. 遍历结束之后,左括号栈和星号栈可能还有元素。
为了将每个左括号匹配,需要将星号看成右括号,且每个左括号必须出现在其匹配的星号之前。当两个栈都不为空时,每次从左括号栈和星号栈分别弹出栈顶元素,对应左括号下标和星号下标,判断是否可以匹配,匹配的条件是左括号下标小于星号下标,如果左括号下标大于星号下标则返回 false。
E. 最终判断左括号栈是否为空
如果左括号栈为空,则左括号全部匹配完毕,剩下的星号都可以看成空字符串,此时 s 是有效的括号字符串,返回 true。如果左括号栈不为空,则还有左括号无法匹配,此时 s 不是有效的括号字符串,返回 false。

此题是上一题的变种,手法类似,但处理起来有个星号的出现有点变化
手法1: 准备两个栈,一个存括号,一个存星号

  1. 星号变成右括号的情况:当左括号栈空时,从星号栈取来匹配右括号;(其实这里按理说也要判断下星号的下标在右括号之前)
  2. 星号变成左括号的情况:为了将每个左括号匹配,需要将星号看成右括号,且每个左括号必须出现在其匹配的星号之前,这里需要对下标进行判断;
#define STACK_SIZE 101
bool checkValidString(char *s)
{
   
   
	int stack1[STACK_SIZE] = {
   
    0 }; // 存左括号下标,是int类数组,存下标,非字符
	int stack2[STACK_SIZE] = {
   
    0 }; // 存星号下标,是int类数组,存下标,非字符
	int top1 = 0;
	int top2 = 0;
	int len = strlen(s);
	int i = 0;
	while (i < len) {
   
   
		if (s[i] == '(') {
   
    // A. 左括号入栈,下标存储下来
			stack1[top1] = i;
			top1++;
		} else if (s[i] == '*') {
   
    // B. 星号入栈,下标存储下来
			stack2[top2] = i;
			top2++;
		} else if (s[i] == ')') {
   
    // C. 遇到右括号处理:
			if (top1 > 0) {
   
    // C1:如果左括号栈不为空,则从左括号栈弹出栈顶元素;
				top1--;
			} else if ((top1 == 0) && (top2 > 0)) {
   
    // C2:如果左括号栈为空且星号栈不为空,则从星号栈弹出栈顶元素;
				top2--;
			} else {
   
    // C3:如果左括号栈和星号栈都为空,则没有字符可以和当前的右括号匹配,返回 false
				return false;
			}
		}
		i++;
	}
	// D. 遍历结束之后,左括号栈和星号栈可能还有元素
	// 当两个栈都不为空时,每次从左括号栈和星号栈分别弹出栈顶元素
	// 对应左括号下标和星号下标,判断是否可以匹配,匹配的条件是左括号下标小于星号下标,如果左括号下标大于星号下标则返回 false。
	if (top2 != 0 && top1 != 0) {
   
   
		while (top1 > 0 && top2 > 0) {
   
   
			top1--;
			top2--;
			if (stack1[top1] 
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值