用兩個棧實現隊列 3/4
參考:https://www.cnblogs.com/silentteller/p/11827215.html
思路:
隊列先進先出,棧先進後出
棧1:模擬入隊;棧2:模擬出隊;res:保存出隊結果
實現入隊:將元素壓入棧1
實現出隊:如果棧2非空,將棧2元素彈出,存到res
如果棧2空,棧1非空,將棧1彈出,存到棧2,將棧2棧頂元素彈出,存到res
【隊列】【棧】
class Solution
{
public:
void push(int node) {//有元素入隊 直接壓入stack1
stack1.push(node);
}
int pop() {
int res;
if(stack2.empty()){//如果棧2空,則壓入棧1棧頂元素,否則直接輸出棧2棧頂元素
while(!stack1.empty()){//當棧1非空,將棧1棧頂元素壓入棧2;否則兩個棧都空,那啥也不做,直接輸出空的res
stack2.push(stack1.top());
stack1.pop();
}
}
res = stack2.top();//將棧2棧頂元素存入res
stack2.pop();
return res;//輸出int型res
}
private:
stack<int> stack1;//模擬入隊
stack<int> stack2;//模擬出隊
};
包含 min函數的棧
“每入棧一次,就與輔助棧頂比較大小,如果小就入棧,如果大就入棧當前的輔助棧頂
當出棧時,輔助棧也要出棧
這種做法可以保證輔助棧頂一定都當前棧的最小值
”參考:https://www.nowcoder.com/questionTerminal/4c776177d2c04c2494f2555c9fcc1e49?f=discussion
【輔助棧】
題目要求O(1),必須使用輔助棧min,使得min棧頂元素保存棧s的最小值
【易錯】:我沒想到min棧也要pop
【易錯】:在最小元素彈出後還能得到次小元素, 次小的彈出後, 還要能得到次次小的. 所以不能用成員變量
class Solution {
public:
//每入棧一次,就與輔助棧頂比較大小,如果小就入棧,如果大就入棧當前的輔助棧頂
void push(int value) {//入棧
s.push(value);
if(s_min.size() == 0)//如果min爲空,將s棧頂存入min
s_min.push(s.top());
else{//如果min非空,將s棧頂與min中元素比較
if(s_min.top() > s.top())
s_min.push(s.top());
else
s_min.push(s_min.top());
}
}
//當出棧時,輔助棧也要出棧
//這種做法可以保證輔助棧頂一定都當前棧的最小值
void pop() {
s.pop();
s_min.pop();
}
int top() {
return s.top();
}
int min() {
return s_min.top();//返回最小棧的棧頂
}
private:
stack<int> s;
stack<int> s_min;//輔助棧,保存最小元素
};
棧的壓入、彈出序列
參考:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106?f=discussion
參考:https://www.cnblogs.com/silentteller/p/11918863.html
補充出棧順序:https://blog.csdn.net/qq_26286193/article/details/80216479
思路:
設:入棧序列A,出棧序列B,臨時變量的保存temp
將A出棧結果壓入temp,校驗B和temp是否相同
1 掃描A,出棧結果壓入temp;
2 掃描B,如果temp[i] == B[i], 第i元素相同,向下一位移動
-對於temp,彈出棧頂元素
-對於B,i+1
如果temp[i] != B[i],第i個元素不同,跳出循環
3 檢查temp是否爲空,空則說明已經檢查完了,結果爲真
temp非空,則說明檢查到某一位,對不上,結果爲假
爲了省時(魯棒性),A出棧一個元素進入temp,就校驗一個元素
則需要兩重循環
【入棧出棧】
【我暫時沒理解如果45321的話,壓入4需要彈出,再壓入5這在代碼裏怎麼體現的呢】
我理解了:while循環如果循環條件不成立,s會一直將pushV元素壓進去,知道遇到4的時候,s.top() =popV[4];
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if(pushV.size() == 0) return false;//如果入棧序列爲空,則輸出false
for(int i = 0,j = 0 ;i < pushV.size();){//當入棧序列掃描了一遍則跳出循環
stack.push(pushV[i++]);//將入棧序列的出棧保存進輔助堆棧stack;stack保存的是出棧順序
//校驗stack和出棧序列是否相同
while(j < popV.size() && stack.top() == popV[j]){//跳出循環:出棧隊列掃描完了,數組最後一個元素不等於出棧序列當前元素
stack.pop();//堆棧彈出棧頂元素
j++;//向後掃描
}
}
return stack.empty();//如果堆棧裏元素都被掃描完了,數組爲空,則是它的出棧序列;否則不是
}
private:
stack<int> stack;//輔助堆棧
};
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if(pushV.size() == 0) return false;//如果入棧序列爲空,則輸出false
vector<int> stack;//新建一個數組(矢量),保存臨時變量
for(int i = 0,j = 0 ;i < pushV.size();){//當入棧序列掃描了一遍則跳出循環
stack.push_back(pushV[i++]);//將入棧序列保存進數組
while(j < popV.size() && stack.back() == popV[j]){//跳出循環:出棧隊列掃描完了,數組最後一個元素不等於出棧序列當前元素
stack.pop_back();//數組刪除最後元素
j++;//向後掃描
}
}
return stack.empty();//如果數組裏元素都被掃描完了,數組爲空,則是它的出棧序列;否則不是
}
};
刪除鏈表中的重複結點
leetcode上做過
印象中要注意的有:插入一個假頭指針,因爲第一個元素可能就是重複的
有兩種方法:遞歸, 非遞歸(循環)
遞歸:終止條件是到達鏈表結尾
1 指針*head指向鏈表頭結點,指針*p指向鏈表頭結點的next
2 p存在:比較head->val 與 p->val是否相等,
2.1 相等,新建臨時變量*temp temp=p;p=p->next;delete p;刪除了這一個重複的元素,且p向下移動,遞歸刪除p
2.2不相等,遞歸刪除head->next
p不存在,返回head
3 返回頭結點head
非遞歸:
維護兩個指針,pre負責向後遍歷,cur負責連接不重複的元素(遇到重複的向後走)
1 插入假的頭結點dummy,新建指針pre指向dummy,
2 當pre->next存在,即鏈表非空,新建指針cur指向頭結點,在cur->next存在前提下,比較二者值,
相同,cur後移;如果第一個元素重複(cur = pre->next),那pre後移;如果不是,那將pre和cur->next連接起來
不同,cur和pre都後移
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(!pHead || !pHead->next) return pHead;
ListNode* dummy = new ListNode(-1);
dummy->next = pHead;
ListNode* pre = dummy;
while(pre->next){
ListNode* cur = pre ->next;
while(cur->next && cur->next->val == cur->val){
cur = cur->next;
}
if(cur != pre->next)
pre->next = cur->next;
else pre = pre->next;
}
return dummy->next;
}
};
鏈表中環的入口 3/5
參考:https://www.cnblogs.com/yorkyang/p/10876604.html
一開始沒理解上面鏈接中的公式5,後來自己畫圖理解了
這題主要在於推算規律,編程不難
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode* fast = pHead, *slow = pHead, *pos = nullptr;
//循環鏈表
while(fast && slow){
fast = fast->next;
slow = slow -> next;
if(fast){//fast走兩步,如果鏈表沒有環,一定fast先遇到
fast = fast ->next;
}
else
return nullptr;//出口A,如果fast遇到null則沒有環,返回nullptr
if(fast == slow){
pos = slow;//鏈表相遇,地點pos,說明有環
break;
}
}
ListNode* start = pHead;//鏈表起點
if(pos != nullptr){
while(pos && start){
if(pos == start)//二者相遇
return start;//出口B找到環入口
pos = pos->next;
start = start-> next;
}
}
else{//這個else部分可以不加
return nullptr;
}
}
};
兩個鏈表的第一個公共結點
參考:https://www.cnblogs.com/lishanlei/p/10707681.html
因爲共享尾巴部分,所以想辦法比較尾巴,也就是倒着比較,倒着的話考慮堆棧/數組
思路:
1 創建兩個輔助堆棧A,B
2 分別將鏈表中值壓入堆棧,此時尾巴在棧頂
3 比較棧頂元素,相同則存進臨時變量temp,然後AB都pop出棧頂,再次進入循環,比較下一對元素
不同,跳出比較的循環
【公共結點】【堆棧】
編程不難,主要是能想到堆棧
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
if(pHead1 == nullptr || pHead2 == nullptr)
return nullptr;//出口A若其中一個鏈表或兩個鏈表都爲空,則返回nullptr
while(pHead1 != nullptr){//將鏈表1節點壓入棧a
a.push(pHead1);
pHead1 = pHead1->next;
}
while(pHead2 != nullptr){//將鏈表2節點壓入棧b
b.push(pHead2);
pHead2 = pHead2 ->next;
}
ListNode* temp = nullptr;//新建一個ListNode*類型的臨時變量,用來保存最一個相同節點,即公共節點
while(!a.empty() && ! b.empty()){//循環出口,其中一個/兩個棧都空,則返回temp。此時temp = nullptr;
if(a.top()->val == b.top()->val){
temp = a.top();//找到相同節點,保存到temp,當遇到下一個相同節點,更新temp
//
}
a.pop();//若有一個節點相同,則兩個棧都彈出,比較下一個,即新的棧頂元素的值
b.pop();
}
return temp;
}
private:
stack<ListNode*> a;//輔助棧a,保存鏈表1節點
stack<ListNode*> b;//輔助棧b,保存鏈表2節點
};
複雜鏈表的複製
參考:https://www.cnblogs.com/silentteller/p/11931355.html(哈希表映射)
參考:https://blog.csdn.net/qq_41562704/article/details/89478626(自己寫複製函數)
參考:https://blog.csdn.net/m0_37428263/article/details/99446872
參考:http://blog.sina.com.cn/s/blog_a1ce3d4b0102wjgn.html
思路:
1 複製節點,插在該節點後面
2 複製random指針
3 拆分
解決問題 | 提交時間 | 狀態 | 運行時間 | 佔用內存 | 使用語言 |
複雜鏈表的複製(自己寫複製節點random的函數) | 2020-03-06 | 答案正確 | 2 ms | 488K | C++ |
複雜鏈表的複製(哈希表) | 2020-03-06 | 答案正確 | 4 ms | 504K | C++ |
由上表知哈希慢,但是查找方便O(1)
要是想不到hashmap,代碼量翻倍
代碼待補充