LeetCode刷题之栈

面试题 03.04. 化栈为队

实现一个MyQueue类,该类用两个栈来实现一个队列。
.
.
示例:
.
MyQueue queue = new MyQueue();
.
queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); //
返回 1 queue.empty(); // 返回 false
.
说明:
.
你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size 和 is empty
操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
.
来源:力扣(LeetCode)《程序员面试金典(第六版)》
难度:简单
链接:https://leetcode-cn.com/problems/implement-queue-using-stacks-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:队列是一端进行删除(即出队),另一端进行插入(即入队)的数据结构。
题目要求2个栈空间,那么我们使一个限制为只能进行pop操作,一个只能进行push操作,模仿队列的入队和出队操作。
pop栈我们命名为frontStack,push栈我们命名为rearStack,接下来的代码实现中有详细的注释。

#define MAXSIZE 30
#define OK 1
#define ERR 0

typedef struct Stack
{
    int top;
    int data[MAXSIZE];
}Stack, * StackPtr;

typedef struct {
    Stack* rearStack;
    Stack* frontStack; 
} MyQueue, * MyQueuePtr;

bool myQueueEmpty(MyQueue* obj);

/** Initialize your data structure here. */

MyQueue* myQueueCreate() {
    
    //初始化队列空间
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    if (!obj)
        goto err1;
    memset(obj, 0, sizeof(MyQueue));

    //初始化push栈空间
    obj->rearStack = (Stack*)malloc(sizeof(Stack));
    if (!obj->rearStack)
        goto err2;
    memset(obj->rearStack, 0, sizeof(Stack));
    obj->rearStack->top = -1;

    //初始化pop栈空间
    obj->frontStack = (Stack*)malloc(sizeof(Stack));
    if (!obj->frontStack)
        goto err3;
    memset(obj->frontStack, 0, sizeof(Stack));
    obj->frontStack->top = -1;


    return obj;


    //集中处理malloc失败的情况。
err3:
    if (obj->frontStack)
        free(obj->frontStack);
err2:
    if (obj->rearStack)
        free(obj->rearStack);
err1:
    if (obj)
        free(obj);

    return NULL;
}

/** Push element x to the back of queue. */
void myQueuePush(MyQueue* obj, int x) {   
        //判断是否队满
    if (obj->rearStack->top == MAXSIZE - 1)
        return;

    //将pop栈的数据转移到push栈,若没有则直接退出
    while (obj->frontStack->top != -1)
    {
        obj->rearStack->data[++obj->rearStack->top] = obj->frontStack->data[obj->frontStack->top--];
    }
    
    //将数据push
    obj->rearStack->data[++obj->rearStack->top] = x;
}

/** Removes the element from in front of queue and returns that element. */
int myQueuePop(MyQueue* obj) {
    //判断队列是否为空
    if (myQueueEmpty(obj))
        return ERR;
    
    //将push栈的数据转移到pop栈,若没有则直接退出
    while (obj->rearStack->top != -1)
    {
        obj->frontStack->data[++obj->frontStack->top] = obj->rearStack->data[obj->rearStack->top--];
    }

    //pop出去,并返回。
    return obj->frontStack->data[obj->frontStack->top--];
}

/** Get the front element. */
int myQueuePeek(MyQueue* obj) {
    if (myQueueEmpty(obj))
        return ERR;

    //判断现在数据在哪个栈空间。
    if (obj->frontStack->top == -1)
    {
        return obj->rearStack->data[0]; //在rear栈中,此时rear指向rear栈的top次,front指向0处
    }
    else
    {
        return obj->frontStack->data[obj->frontStack->top]; //front栈中,直接返回即可
    }
}

/** Returns whether the queue is empty. */
bool myQueueEmpty(MyQueue* obj) {
    return (obj->frontStack->top == -1 && obj->rearStack->top == -1) ? true : false;
}

//逐一free内存
void myQueueFree(MyQueue* obj) {
    free(obj->frontStack);
    free(obj->rearStack);
    free(obj);
}


面试题09. 用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

来源:力扣(LeetCode)《剑指offer(第二版)》
难度:简单
链接:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:我们定义2个栈空间,rear和front分别作为其中的栈顶指针。我们限定rear栈空间只能进行push也就是入队,而front栈只能进行pop也就是出队以此来用两个栈来模仿队列。
下面的代码关键地方都给予了注释。

#define MAXSIZE 300
#define REAR 1
#define FRONT 0

typedef struct CQueue
{
    //设置2个数组,即2个栈空间,分别定义2个宏REAR,FRONT现性的指明。
	int data[2][MAXSIZE];
	int front, rear;
} CQueue;


CQueue* cQueueCreate() {
	
	CQueue* obj = (CQueue*)malloc(sizeof(CQueue));
	if (!obj)
		return NULL;
	memset(obj, 0, sizeof(CQueue));
	obj->rear = obj->front = -1;	//rear和front分别为一个栈空间的栈顶指针,初始化指向栈底。

	return obj;
}

void cQueueAppendTail(CQueue* obj, int value) {
	//判断是否满队
	if (obj->rear == MAXSIZE - 1 || obj->front == MAXSIZE - 1)
		return;

	//如果数据在front栈,则转移数据到rear栈中
	while (obj->front != -1)
	{
		obj->data[REAR][++obj->rear] = obj->data[FRONT][obj->front--];
	}
	obj->data[REAR][++obj->rear] = value;
}

int cQueueDeleteHead(CQueue* obj) {
	if (obj->rear == obj->front)
		return -1;

	//如果数据在rear栈,则转移数据到front栈中
	while (obj->rear != -1)
		obj->data[FRONT][++obj->front] = obj->data[REAR][obj->rear--];

	return obj->data[FRONT][obj->front--];
}

void cQueueFree(CQueue* obj) {
	free(obj);
}


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

编辑于:2020年3月17日22:10:39

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

输入:“abbaca” 输出:“ca” 解释: 例如,在 “abbaca” 中,我们可以删除 “bb”
由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa”
可以执行重复项删除操作,所以最后的字符串为 “ca”。

提示:

1 <= S.length <= 20000 S 仅由小写英文字母组成。

来源:力扣(LeetCode)
难度:简单
链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路1我最初的思路非常简单。维护一个栈,不断将数据读入栈中,如果栈中数据有重复的相邻数据则出栈。
感悟:但是写完出来,有点不满意,看见了一个大佬的提醒,顿悟了。感觉优化了下代码。
思路2:我们可以利用遍历下标总是不小于栈底top作为下标的值这个性质将S指向的内存空间作为栈空间。
原因很简单一开始栈空间膨胀和遍历速度是相同的,但是我们不断入栈的途中会有出栈,这就使得栈膨胀的速度永远不可能超过遍历的速度。
所谓遍历就是集合中所有元素都访问一遍。也就是说top只能操作我们访问过的数据,而不能没有操作我们未访问过的数据,因此这并不影响遍历。

//最初的版本
#define MAXSIZE 20000

char* removeDuplicates(char* S) {
    //设立栈
    int top = -1;
    char data[MAXSIZE] = { 0 };

    for (int i = 0; S[i]; i++)
    {
        //判断栈是否满。加1是为了预留'\0'字符
        if (top + 1 == MAXSIZE - 1)
            return NULL;

        data[++top] = S[i];     //字符串s字符逐一入栈
        if (top > 0 && data[top] == data[top - 1])  //查找是否有重复,若有出栈
            top -= 2;
        if(top >= 0)
            S[top] = data[top];
    }
    S[top + 1] = '\0';

    return S;
}

//优化后的C代码

char* removeDuplicates(char* S) {
    int top = 0;
    for (int read = 0; S[read]; read++, top++)
    {
        S[top] = S[read];     //字符串s字符逐一入栈
        if (top > 0 && S[top] == S[top - 1])  //查找是否有重复,若有出栈
            top -= 2;
    }
    S[top] = '\0';

    return S;
}

发布了19 篇原创文章 · 获赞 2 · 访问量 2536

猜你喜欢

转载自blog.csdn.net/SC_king/article/details/104928462