链表内指定区间反转
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode* dummy=new ListNode(0);
dummy->next=head;
ListNode* result=dummy;
stack<ListNode*> st;
for(int i=1;i<m;i++) dummy=dummy->next;
ListNode* left=dummy;
for(int i=m;i<=n;i++){
dummy=dummy->next;
st.push(dummy);
}
ListNode* right=dummy->next;
while(!st.empty()){
left->next=st.top();
st.pop();
left=left->next;
}
left->next=right;
return result->next;
}
};
全链表反转用递归几行代码就能解决,而这题是在限定区间里反转所以用栈来做代码更简洁,把链表划分为区间外左边,区间,区间外右边,三部分,只操作其中区间部分,首先求出链表到达区间的前一位left,然后用stack储存区间内指针,并求出区间外后边第一位right,然后再用while循环,left指向st.top()依次反转区间内指针指向,最后输出表头,注意不能输出head,head可能被反转到后面。
总结,用栈来处理反转区间,以及左右两边衔接处的处理
合并两个排序的链表
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
ListNode* p=new ListNode(0);
ListNode* q=new ListNode(0);
p->next=pHead1;
q->next=pHead2;
ListNode* result=p;
while(p->next!=NULL&&q->next!=NULL){
if(p->next->val<q->next->val){
p=p->next;
}else{
ListNode* temp1=p->next;
ListNode* temp2=q->next->next;
p->next=q->next;
p->next->next=temp1;
p=p->next;
q->next=temp2;
}
}
if(p->next==NULL) p->next=q->next;
return result->next;
}
这道题我的解法是在原链表基础上合并链表,不用格外空间,首先创建两个拟头分别指向两个头结点,本题我选用head1作为母表,再创建一个指针copy head1拟头,然后进入while循环判断,逻辑就是大于head1的值p往后走,小于head1就要把q插入p,然后改变q的指向,对于q来说就是删除节点,不用后移,只能改变指向。
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
// write code here
if(pHead1==NULL) return pHead2;
if(pHead2==NULL) return pHead1;
if(pHead1->val<pHead2->val){
pHead1->next=Merge(pHead1->next, pHead2);
return pHead1;
}else{
pHead2->next=Merge(pHead1, pHead2->next);
return pHead2;
}
}
};
这道题用合并二叉树的思路也很简洁,用递归几行代码解决,谁小就返回谁,并根据该节点向下递归
合并k个已排序的链表
class Solution {
public:
struct cmp{
public:
bool operator()(ListNode* a,ListNode* b){
return a->val>b->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
// write code here
priority_queue<ListNode*,vector<ListNode*>,cmp> que;
for(int i=0;i<lists.size();i++){
if(lists[i]!=NULL) que.push(lists[i]);
}
ListNode* result=new ListNode(0);
ListNode* head=result;
while(!que.empty()){
ListNode* node=que.top();
que.pop();
head->next=node;
head=head->next;
if(node->next!=NULL) que.push(node->next);
}
return result->next;
}
};
大顶堆的堆顶为最大元素,其余更小的元素在堆下方,小顶堆与其刚好相反。优先级队列默认是大顶堆,重载小顶堆,里面是逻辑是大于。首先遍历一遍链表数组,小顶堆优先级队列储存所有链表的头结点,然后新建链表储存优先级队列的栈顶,被储存节点的下一个节点不为空,则优先级队列储存该节点下一个节点,直到优先级队列为空