面試題 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;
}