编程总结
每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧
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: 准备两个栈,一个存括号,一个存星号
- 星号变成右括号的情况:当左括号栈空时,从星号栈取来匹配右括号;(其实这里按理说也要判断下星号的下标在右括号之前)
- 星号变成左括号的情况:为了将每个左括号匹配,需要将星号看成右括号,且每个左括号必须出现在其匹配的星号之前,这里需要对下标进行判断;
#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]

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





