目录
24. 两两交换链表中的节点
用虚拟头结点,这样会方便很多。
本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。
题目链接/文章讲解/视频讲解: 代码随想录
方法一:递归法
def swapPairs(self, head: Optional[ListNode]) -> Optional[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
方法二:循环法
自己写的代码:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if (not head):
return None
if (not head.next):
return head
dummy = ListNode(next=head)
pre = dummy
cur = head
while(cur and cur.next):
nxt = cur.next
print('nxt:', nxt)
pre.next = nxt
cur.next = nxt.next
nxt.next = cur
pre = cur
cur = cur.next
return dummy.next
代码随想录的代码:
cur从虚拟节点开始,循环条件判断为cur.next and cur.next.next, 用临时节点保存值,保存cur.next 和cur.next.next, 本质逻辑是一样的,但是代码逻辑更顺畅一些,不需要思考太多。迭代cur使用cur = cur.next.next
重点参考如下图即可
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy_head = ListNode(next = head)
current = dummy_head
while current.next and current.next.next:
temp = current.next
temp1 = current.next.next.next
current.next = current.next.next
current.next.next = temp
temp.next = temp1
current = current.next.next
return dummy_head.next
19.删除链表的倒数第N个节点
双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
题目链接/文章讲解/视频讲解:代码随想录
第一想法:使用双指针法获得链表的长度,减去n后得到倒数第n个节点的位置,计算链表的长度废了一些功夫
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
fast = head
slow = head
dummy = ListNode(next = head)
if not (head):
return None
length = 0
while(fast and fast.next):
slow = slow.next
fast = fast.next.next
length += 1
if fast:
length = length*2 + 1
else:
length = length*2
pre = dummy
for i in range(length - n):
pre = head
head = head.next
pre.next = head.next
print(head.next)
return dummy.next
代码随想录解法:
也是快慢指针,但是设定快指针比慢指针快n+1步,这样同时移动时,slow才能指向删除节点的上一节点。
时间复杂度O(n) 空间复杂度 O(1)
dummy_head = ListNode(0, head)
slow = fast = dummy_head
for i in range(n+1):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy_head.next
c++代码不一样的点:
1. 头结点的创建
ListNode * dummyHead = new ListNode(0);
2. 判断条件
while(n-- && fast != NULL){
fast = fast->next
}
fast = fast->next //需要再提前走一步,因为需要让slow指向删除节点的上一个节点
总结:
两种方法
1: 先计算链表长度,再找到要删除的点的前一个节点
2. 快慢指针相差n+1个位置,找到要删除的点的前一个节点。时间复杂度O(n) 空间复杂度 O(1)
面试题 02.07. 链表相交
本题没有视频讲解,大家注意 数值相同,不代表指针相同。
题目链接/文章讲解:代码随想录
一开始没什么思路,看了代码随想录
方法1:先求出两个链表各自的长度,求出链表长度的差值,然后让curA移动到curB末尾对齐的位置,则后续如果两个值相同,则为交点。
方法2:两个链表都遍历一遍,走一圈之后会到达交点(这个方法之前看过,后来又忘记了)
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
pointerA = headA
pointerB = headB
while pointerA != pointerB:
pointerA = pointerA.next if pointerA else headB
pointerB = pointerB.next if pointerB else headA
return pointerA
142.环形链表II
算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
题目链接/文章讲解/视频讲解:代码随想录
使用快慢指针法,当两个指针相遇的时候,slow走过的节点数为(x+y), fast走过的节点数:
两边消除(x+y)得到:
当n是1时,x = z
此时,从头结点和相遇的节点都出发一个指针,当两个指针相遇时,就是环形入口的节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = head
fast = head
while(fast and fast.next):
slow = slow.next
fast = fast.next.next
if slow == fast:
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
return None
写过好几遍的题目一直记不住,本质还是没有理解到位