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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章