leetcode valid parentheses and circular queues

1. Valid brackets

This topic comes from leetcode valid parentheses

1.1 Title Description

Tips

1.1.1 interface function

bool isValid(char * s){

}

1.2 general framework

Although the array can also solve the problem, it is not very good. Some problems will appear later. We try to use the stack to solve the problem

Directly using c must be written by ourselves, because there is no library, so if we want to use c language to realize this problem, we need to write a stack by ourselves

1.2.1 ideas

The title says that there are only left or right parentheses for input, so we don't care about other input possibilities

Using the first in and last out feature of the stack, we can put all the left parenthesis types (with ({[) into the stack, and then the right parenthesis will start matching. If the matching fails, it will be false directly. If it succeeds, we will remove the top one of the stack through StackPop, and then judge whether the next one matches until the last one returns true or false

1.2.2 specific steps

First, you have to implement the stack in c language

statement

#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef char STDataType ;
struct Stack
{
	STDataType* a;
	int capacity;	//Capacity, easy to increase capacity
	int top;	//Stack top
};

typedef struct Stack Stack;

void StackInit(Stack *pst);
void StackDestroy(Stack* pst);
void StackPush(Stack* pst,STDataType x);
//The nature determines the data access at the top of the stack
STDataType StackTop(Stack* pst);
void  StackPop(Stack* pst);

bool StackEmpty(Stack* pst);
int StzckSize(Stack* pst);

function

void StackInit(Stack* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;

}
void StackDestroy(Stack* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->capacity = pst->top = 0;
}
void StackPush(Stack* pst,STDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;//Capacity doubled
		STDataType* tmp = realloc(pst->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail");
			exit(-1);
		}
		pst->a = tmp;
		pst->capacity =newCapacity;
	} 
	pst->a[pst->top] = x;
	pst->top++;
}

STDataType StackTop(Stack* pst)
{
	assert(pst);
	assert(!StackEmpty(pst));
	return pst->a[pst->top - 1];//From high subscript to low subscript  
}
void StackPop(Stack* pst)
{
	assert(pst);
	assert(!StackEmpty(pst));

	pst->top--;
}
bool StackEmpty(Stack* pst)
{
	assert(pst);
	return pst->top == 0;//Boolean to judge
}

int StzckSize(Stack* pst)
{
	assert(pst);
	return pst->top;//It happens to be size
}

Then build isValid(char * s)

matters needing attention:

  • In the loop, a branch should judge whether it is a left bracket or a right bracket. The left bracket enters the stack and the right bracket judges

  • Don't forget to move the s pointer forward after a branch

  • Finally, if it is empty, it indicates that it matches. If it is not empty, it indicates that it does not match. Because the last remaining one is added, it will directly return true. In fact, it should be false, so there should be a judgment in the end, which can be judged by StackEmpty

bool isValid(char * s){
    Stack st;
    StackInit(&st);
    while(*s)
    {
        //Left bracket stack
        //The right bracket matches the nearest one
        if(*s  =='['
           ||*s=='{'
           ||*s=='(')
        {
            StackPush(&st,*s);
            ++s;
        }
        else
        {
              if(StackEmpty(&st))//The description has no leading brackets
            {
                StackDestroy(&st);
                return false;
            }
            char top=StackTop(&st);
            if((top=='['&&*s!=']')
            ||(top=='('&&*s!=')')
            ||(top=='{'&&*s!='}'))
            {
                StackDestroy(&st);
                return false;
            }
            else
            {
                //Matching
                StackPop(&st);
                ++s;
            }
        }
    } 
    bool ret=StackEmpty(&st);
    StackDestroy(&st);
    return ret;
}

1.3 overall realization

#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef char STDataType;
struct Stack
{
	STDataType* a;
	int capacity;	//Capacity, easy to increase capacity
	int top;	//Stack top
};

typedef struct Stack Stack;

void StackInit(Stack *pst);
void StackDestroy(Stack* pst);
void StackPush(Stack* pst,STDataType x);
//The nature determines the data access at the top of the stack
STDataType StackTop(Stack* pst);
void  StackPop(Stack* pst);
bool StackEmpty(Stack* pst);
void StackInit(Stack* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;

}
void StackDestroy(Stack* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->capacity = pst->top = 0;
}
void StackPush(Stack* pst,STDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;//Capacity doubled
		STDataType* tmp = realloc(pst->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail");
			exit(-1);
		}
		pst->a = tmp;
		pst->capacity =newCapacity;
	} 
	pst->a[pst->top] = x;
	pst->top++;
}

STDataType StackTop(Stack* pst)
{
	assert(pst);
	assert(!StackEmpty(pst));
	return pst->a[pst->top - 1];//From high subscript to low subscript  
}
void StackPop(Stack* pst)
{
	assert(pst);
	assert(!StackEmpty(pst));

	pst->top--;
}
bool StackEmpty(Stack* pst)
{
	assert(pst);
	return pst->top == 0;//Boolean to judge
}

bool isValid(char * s){
    Stack st;
    StackInit(&st);
    while(*s)
    {
        //Left bracket stack
        //The right bracket matches the nearest one
        if(*s  =='['
           ||*s=='{'
           ||*s=='(')
        {
            StackPush(&st,*s);
            ++s;
        }
        else
        {
              if(StackEmpty(&st))//The description has no leading brackets
            {
                StackDestroy(&st);
                return false;
            }
            char top=StackTop(&st);
            if((top=='['&&*s!=']')
            ||(top=='('&&*s!=')')
            ||(top=='{'&&*s!='}'))
            {
                StackDestroy(&st);
                return false;
            }
            else
            {
                //Matching
                StackPop(&st);
                ++s;
            }
        }
    } 
    bool ret=StackEmpty(&st);
    StackDestroy(&st);
    return ret;
}

Summary:

This topic will be much simpler if you use c + +, because you can directly call the interface, but the c language has to implement a stack by itself, which will be more troublesome

2. Design cycle queue

This topic comes from leetcode 622. Designing circular queues

This topic may be a little deeper and more difficult

2.1 Title Description

Tips

2.1.1 interface function

typedef struct {

} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {

}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {

}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {

}

int myCircularQueueFront(MyCircularQueue* obj) {

}

int myCircularQueueRear(MyCircularQueue* obj) {

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {

}

bool myCircularQueueIsFull(MyCircularQueue* obj) {

}

void myCircularQueueFree(MyCircularQueue* obj) {

}

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

2.2 general framework

2.2.1 ideas

Implemented with array or linked list

To realize the circular queue, we must use the circular linked list. We can't just use the single linked list, can we? Of course, the array can also be used. The linked list is more like a ring

According to the meaning of the title, the function we want to achieve is to use the previously used space. It is required that the queue can not be inserted when it is full, but after it is not full or deleted when it is full, we can use the previous location to store data

Solve empty and full

Do we need two pointers to complete such a topic

However, with this idea, it is impossible to judge whether the circular queue is empty or full

Therefore, it is necessary to distinguish between two situations: when it is judged to be full and when it is judged to be empty

This problem is solved by clearing a location without saving data. For example, if the queue is full of four data, I only save three. Then it can be judged at this time

  • The following legend shows a linked list at the top and an array at the bottom
  1. Full ` ` tail - > next is front`
  2. Empty tail==front

Then we can also implement pop and push operations at this time

Summary:

When do we usually use this circular queue?

For example, producers and consumers in the operating system

2.2.2 specific steps

We use arrays to implement it, because arrays are a little simpler than linked lists

Note that the functions implemented in the following steps still have problems, which will be solved later when finding and reporting errors. The overall implementation is the correct code

myCircularQueueCreate

typedef struct {
int * a;
int k;//How many data can the queue store at most
int front;  //head
int tail;  //Tail (next to tail data)
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
 MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
 obj->a=(int*)malloc(sizeof(int)*(k+1));//Leave one
 obj->front=0;
 obj->tail=0;
 obj->k=k;
 return obj;
}

myCircularQueueIsEmpty

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front==obj->tail;
}

myCircularQueueIsFull

bool myCircularQueueIsFull(MyCircularQueue* obj) {
	int tailNext = obj->tail + 1;
	if (tailNext == obj->k + 1)//Prevent next from going out
	{
		tailNext = 0;
	}
	return tailNext == obj->front;
}

myCircularQueueEnQueue

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
	if (myCircularQueueIsFull(obj))
	{
		return false;
	}
	else
	{
		obj->a[obj->tail] = value;
		++obj->tail;
		if (obj->tail == obj->k + 1)
		{
			obj->tail = 0;
		}
		return true;
	}
}

myCircularQueueDeQueue

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
	if (myCircularQueueIsEmpty(obj))
	{
		return false;
	}
	else
	{
		++obj->front;
		if (obj->front == obj->k + 1)
		{
			obj->front = 0;
		}
		return true;
	}
}

myCircularQueueFront

int myCircularQueueFront(MyCircularQueue* obj) {
	return obj->a[obj->front];
}

myCircularQueueRear

int myCircularQueueRear(MyCircularQueue* obj) {
	int tailPrev = obj->tail - 1;
	if (tailPrev == -1)//Prevent prev from going out
	{
		tailPrev = obj->k;
	}
	return obj->a[tailPrev];
}

myCircularQueueFree

void myCircularQueueFree(MyCircularQueue* obj) {
	free(obj->a);
	free(obj);
}

2.2.3 finding error reporting problems

It indicates that the problem lies in the Front. According to the valuable input, there is no data in the circular queue before executing the Front, so the returned Front should be empty, so it indicates that this point is not considered. If it is empty, return - 1

myCircularQueueFront

int myCircularQueueFront(MyCircularQueue* obj) {
   if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->a[obj->front] ;
    }
}

Then myCircularQueueRear should be the same. Although there is no prompt, you can think of it

int myCircularQueueRear(MyCircularQueue* obj) {
	int tailPrev = obj->tail - 1;
	if (tailPrev == -1)//Prevent prev from going out
	{
		tailPrev = obj->k;
	}
 if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
      return obj->a[tailPrev];
    }
}

2.3 overall realization

#include<stdbool.h>
typedef struct {
	int* a;
	int k;//How many data can the queue store at most
	int front;  //head
	int tail;  //Tail (next to tail data)
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
	MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	obj->a = (int*)malloc(sizeof(int) * (k + 1));//Leave one
	obj->front = 0;
	obj->tail = 0;
	obj->k = k;
	return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
	return obj->front == obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
	int tailNext = obj->tail + 1;
	if (tailNext == obj->k + 1)//Prevent next from going out
	{
		tailNext = 0;
	}

	return tailNext == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
	if (myCircularQueueIsFull(obj))
	{
		return false;
	}
	else
	{
		obj->a[obj->tail] = value;
		++obj->tail;
		if (obj->tail == obj->k + 1)
		{
			obj->tail = 0;
		}
		return true;
	}
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
	if (myCircularQueueIsEmpty(obj))
	{
		return false;
	}
	else
	{
		++obj->front;
		if (obj->front == obj->k + 1)
		{
			obj->front = 0;
		}
		return true;
	}
}

int myCircularQueueFront(MyCircularQueue* obj) {
	if (myCircularQueueIsEmpty(obj))
	{
		return -1;
	}
	else
	{
		return obj->a[obj->front];
	}
}

int myCircularQueueRear(MyCircularQueue* obj) {
	int tailPrev = obj->tail - 1;
	if (tailPrev == -1)//Prevent prev from going out
	{
		tailPrev = obj->k;
	}
	if (myCircularQueueIsEmpty(obj))
	{
		return -1;
	}
	else
	{
		return obj->a[tailPrev];
	}
}

void myCircularQueueFree(MyCircularQueue* obj) {
	free(obj->a);
	free(obj);
}

Summary:

The difficulty of stack and queue mainly lies in the complex structure, not in a single logic. If you write more, you will feel much better

Later, the more difficult problems of stack and queue will be implemented using c + + stl library

If the old fellow has harvested, I hope to give a key to three links. Thank you.

Keywords: data structure leetcode linked list queue stack

Added by N350CA on Mon, 22 Nov 2021 04:28:16 +0200