24. 两两交换链表中的节点
方法一:迭代
思路:首先我们把虚拟头节点定义出来:
ListNode* dummyhead=new ListNode(0);
dummyhead->next=head;
然后,假如结点至少两个:
实质上就是对pre,one,two,last这四个结点操作,
pre->next=two;
pre->next->next=one;
pre->next->next->next=last;
这样在至少有两个结点的情况下就完成了一次交换,那么如果后面还有很多个结点,就只需要让pre=pre->next->next,然后继续用这种方式,先重新定义one,two,last,再改变顺序
而若链表中只有1个结点或者链表为空,则不用交换:
if(pre->next==null||pre->next->next==null)
pre一开始就在dummyhead,这样就很好判断
至少两个结点的情况:最后终止的情况是只剩下一个结点或者没有结点,那么终止条件其实也是上面那个if判断
所以最后可以把if直接写成while
while结束后再创一个指针用来表示头结点:
ListNode* ans=dummyhead->next;
delete dummyhead;
return ans;
因为之前的头结点肯定变了,而虚拟头节点还是在那里,指向新的头结点
最后还要记得释放dummyhead的内存
完整代码:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* pre = dummyHead;
while(pre->next != nullptr && pre->next->next != nullptr) {
ListNode* one = pre->next;
ListNode* two = pre->next->next;
ListNode* three=pre->next->next->next;
//这里我就直接写成one,two,three了
pre->next =two;
pre->next->next = one;
pre->next->next->next =three;
pre = pre->next->next;
}
ListNode* ans = dummyHead->next;
delete dummyHead;
return ans;
}
};
当然,其实two这个指针是没有必要设置的,因为它是第一个操作点,链表的初始顺序没有改变,
pre->next=two等价于pre->next=pre->next->next;
方法二:递归:
递归就是要把握两点:一是递归的终止条件,二是递归的式子
在这里:函数名为:ListNode* swapPairs(ListNode* head)
终止条件:head==nullptr||head->next=nullptr;
递归:我们定义一个newhead,newhead=head->next;
这个结点是交换之后的新的头结点,各个结点的指针指向的改变过程是
head->next=swapPairs(newhead->next),
newhead->next=head;
return newhead;
完整代码:
struct ListNode* swapPairs(struct ListNode* head){
if(!head || !head->next)
return head;
struct ListNode *newHead = head->next;
head->next = swapPairs(newHead->next);
newHead->next = head;
return newHead;
}
19.删除链表的倒数第N个节点
方一:栈
我觉得这个思路挺巧妙的,刚好栈的第n个结点就是倒数第n个:
1.cur指针遍历链表来入栈,
2.删除结点要找前一个结点,所以pop了n次,再pop一次
3.因为不知道倒数第n个结点是不是头结点,所以还是要虚拟头结点和ans:ans = dummy->next;
4.记得删dummyhead
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
stack<ListNode*> stk;
ListNode* cur = dummy;
while (cur) {
stk.push(cur);
cur = cur->next;
}
for (int i = 0; i < n; ++i) {
stk.pop();
}
ListNode* prev = stk.top();
prev->next = prev->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};
方二:双指针
用fast,slow,只要fast在slow前面n个结点,那么都一起往后移一个点,直到fast==nullptr
这里复制的leetcode上面的题解,之所以要让first=head;原因是要让second指向被删除结点的前一个结点
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
ListNode* first = head;
ListNode* second = dummy;
for (int i = 0; i < n; ++i) {
first = first->next;
}
while (first) {
first = first->next;
second = second->next;
}
ListNode* temp=second->next;
second->next=temp->next;
delete temp;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};
160链表相交
先算出两个链表的长度m,n,再让长的链表的指针向前移动|m-n|个位置,然后两个链表同时一步一步移动,若相交,则必定两个指针会相遇
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* pA=headA;int lengthA=0;
ListNode* pB=headB;int lengthB=0;
while(pA){
lengthA++;
pA=pA->next;
}
while(pB){
lengthB++;
pB=pB->next;
}
pA=headA;
pB=headB;
if(lengthA<lengthB){
swap(lengthA,lengthB);
swap(pA,pB);
}
int gap=lengthA-lengthB;
while(gap--){
pA=pA->next;
}
while(pB){
if(pA==pB)
return pA;
pA=pA->next;
pB=pB->next;
}
return NULL;
}
};
142.环形链表II
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};
2*(x+y)=x+y+n*(z+y)
x+y=n*(y+z)
x=(n-1)*(y+z)+z;
n==1时x=z;
n>1,x=z+(n-1)*圈
index1=head;
index2=fast;
有环就会相遇在交点处,n=1,index2走的路程是z,n>1,index2多走了(n-1)圈也会在开口处相遇