目录
用两个栈实现队列 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
![链表公共结点:从某一结点开始,两个链表共享子链表](https://i-blog.csdnimg.cn/blog_migrate/5d0c9abe9e92cef643b2a1686c658e20.png)
因为共享尾巴部分,所以想办法比较尾巴,也就是倒着比较,倒着的话考虑堆栈/数组
思路:
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,代码量翻倍
代码待补充