题目链接/文章讲解/视频讲解: 代码随想录
24. 两两交换链表中的节点
题目要求:两两交换链表的节点,交换的是地址而不是节点中的值。
用dummyhead,交换节点的next指向即可,注意用tmp和tmp1做临时存储,画图能够更好理解。注意,这里在交换之后,cur和1以及2和3之间的链接关系会断开,因此需要中间变量临时村塾1和3的地址。
C++:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;
while (cur->next!=nullptr && cur->next->next!=nullptr){
ListNode* tmp = cur->next;
ListNode* tmp1 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp;
cur->next->next->next = tmp1;
cur = cur->next->next; // cur移位两位,准备下一轮交换
}
return dummyhead->next;
}
};
Python:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
dummyhead = ListNode(next=head)
cur = dummyhead
while cur.next and cur.next.next:
tmp = cur.next
tmp1 = cur.next.next.next
cur.next = cur.next.next
cur.next.next = tmp
cur.next.next.next = tmp1
cur = cur.next.next
return dummyhead.next
Python(递归写法):
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None or head.next is None:
return head
pre = head
cur = head.next
next = head.next.next
cur.next = pre
pre.next = self.swapPairs(next)
return cur
19. 删除链表的倒数第N个节点
题目要求:给出头节点,删除链表的倒数第n个节点,返回头节点。
我的想法:取到倒数第n+1个节点作为cur,然后把cur->next指向cur->next->next,最后处理被删除的节点。
实际上采用双指针的写法,让快指针先动n步然后让快慢指针一起移动直到快指针指向NULL,删除慢指针指向的节点。
C++:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* slow = dummyhead;
ListNode* fast = dummyhead;
while (n-- && fast!=nullptr){
fast = fast->next;
}
fast = fast->next;
while(fast!=nullptr){
slow = slow->next;
fast = fast->next;
}
ListNode* tmp = slow->next;
slow->next = tmp->next;
delete tmp;
return dummyhead->next;
}
};
Python:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
dummyhead = ListNode(next=head)
slow = dummyhead
fast = dummyhead
for i in range(n+1):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummyhead.next
160. 链表相交
题目要求:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null。
双指针curA和curB分别指向headA和headB,求出两个链表的长度并求出差值。让两个链表末尾对其,开始寻找交点,直到curA==curB或者等于NULL返回0。似乎并不存在两个节点的地址相同但是后续节点不同的情况。
C++:
/**
* 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* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA!=nullptr){
lenA++;
curA = curA->next;
}
while (curB!=nullptr){
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
if (lenB > lenA){
swap(lenA, lenB);
swap(curA, curB);
}
int gap = lenA - lenB;
while(gap--){
curA = curA->next;
}
while(curA!=nullptr){
if(curA==curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return nullptr;
}
};
Python:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
curA = headA
curB = headB
lenA = lenB = 0
while(curA!=None):
lenA+=1
curA = curA.next
while(curB!=None):
lenB+=1
curB = curB.next
curA = headA
curB = headB
if lenB > lenA:
lenA, lenB = lenB, lenA
curA, curB = curB, curA
gap = lenA - lenB
while gap:
gap-=1
curA = curA.next
while(curA != None):
if (curA==curB):
return curA
curA = curA.next
curB = curB.next
return None
142. 循环链表II
题目要求:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如何判断链表中是否有环?答:定义快慢指针,fast指针一次走两步,slow指针一次走一步。如果链表中有环则相当于fast在追击slow。如果fast走两步刚好到达slow的位置则相遇,如果fast走两步刚好到达slow的下一个节点,则slow再走一步也会相遇。因此如果链表中有环,则slow和fast一定会相遇。
慢指针slow走过的步数:x+y(一次走一步,长度即步数)
快指针fast走过的步数:(x+y+n(y+z))/2 (一次走两格,步数是长度除以2)
二者走过的步数相等,因此x+y=(x+y+n(y+z))/2,x+y=n(y+z)
我们需要求出x,x=(n-1)(y+z)+z,当n=1时,x=z说明从头节点出发和从相遇节点出发,每次走一个节点,会在入口处相遇。如果n>1,那么也是一样二者依然会在入口处相遇,只不过从相遇节点出发的指针会多走n-1圈。
因此我们只需要让fast和slow指针相遇,再让index1指针和index2指针分别从head和相遇节点出发。当index1和index2相遇时,返回即可得到入口节点的位置。
C++:
/**
* 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!=nullptr && fast->next!=nullptr){
slow = slow->next;
fast = fast->next->next;
if (slow == fast){
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index2;
}
}
return nullptr;
}
};
Python:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
fast = slow = head
while(fast!=None and fast.next!=None):
slow = slow.next
fast = fast.next.next
if(slow==fast):
index1 = fast
index2 = head
while(index1!=index2):
index1 = index1.next
index2 = index2.next
return index2
return None
总结:链表到这里就结束了,了解链表是一种特殊的数据结构(struct),包括了值(val)和指向的下一个节点的地址(next)。
// Python
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
# C++
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
注意如何判断循环链表,注意应用双指针的思路。注意链表的指向,在改变链表指向位置时,可能需要tmp来暂存地址。注意在链表前加一个虚拟dummyhead可以链表操作的效率,但是最后也要delete掉dummyhead。C++中的内存需要手动释放,Python中当一个地址不被其他变量引用时,就会自动释放。大概就是这么多,链表说难也难,说不难也不难,还是需要多加训练!