补一个day4,3h左右
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
正常的基础链表操作,直接写
class Solution(object):
def swapPairs(self, head):
dummy_head = ListNode(next=head)
cur = dummy_head
while cur.next and cur.next.next:
pre = cur.next
cur.next = pre.next
pre.next = cur.next.next
cur.next.next = pre
cur = cur.next.next
return dummy_head.next
19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
重点是倒数……
第一次先写一个扫描两次的,一次找长度,一次删除
class Solution(object):
def removeNthFromEnd(self, head, n):
dummy_head = ListNode(next=head)
cur = dummy_head
size = 0
while cur.next:
size += 1
cur = cur.next
cur = dummy_head
for i in range(size-n):
cur = cur.next
cur.next = cur.next.next
return dummy_head.next
一次扫描思路想不到了,看一眼题解思路
“双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。”
好家伙,上一次看到快慢指针还是原地删除指定元素……感觉对这个方法又有新理解
开写
class Solution(object):
def removeNthFromEnd(self, head, n):
dummy_head = ListNode(next=head)
fast,slow = dummy_head, dummy_head
for i in range(n):
fast = fast.next
while fast.next:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return dummy_head.next
面试题 02.07. 链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
两个链表首先要做的是对其末尾,然后使得AB都从对齐尾部的头指针开始遍历,这样才能通过“==”找到相交的节点。过程中需要注意是虚拟头指针的处理(长的链表在知道短链表的长度n之后,跟上题找到倒数第n个是同一个思路。为了兼容短链表的虚拟头指针,实际上长链表的起始遍历指针应该设置在倒数第n+1个上)
class Solution(object):
def getIntersectionNode(self, headA, headB):
dummy_headA = ListNode(next=headA)
dummy_headB = ListNode(next=headB)
curA = dummy_headA
curB = dummy_headB
min_size = 0
#找到短的那一条链表的长度
while curA.next and curB.next:
min_size += 1
curA = curA.next
curB = curB.next
#使长链表的cur指向倒数第min_size个前一个
if curA.next==None:
long = dummy_headB
short = dummy_headA
else:
long = dummy_headA
short = dummy_headB
slow = fast = long
for i in range(min_size):
fast = fast.next
while fast.next:
fast = fast.next
slow = slow.next
#对齐末尾后遍历
curlong = slow
curshort = short
while curlong.next:
if curlong.next == curshort.next:
return curlong.next
else:
curlong = curlong.next
curshort = curshort.next
return None
上面的方法遍历了三次链表,一次短一次长一次短
代码随想录记录的下面这个方法巧妙地解决了对齐AB末尾的方法!只需要相当于遍历一次长一次短就可以完成任务!很巧妙,思路可以理解为:
class Solution:
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
# 如果相交,指针将位于交点节点,如果没有交点,值为None
return pointerA
142.环形链表II
这题需要思考学习
- 判断链表是否环
- 如果有环,如何找到这个环的入口
- 使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
- 从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
这是自己写的
class Solution(object):
def detectCycle(self, head):
if head==None or head.next==None or head.next.next==None:
return None
slow = head.next
fast = head.next.next
slowstep = 1
faststep = 2
while slow != fast:
if fast==None or fast.next==None:
return None
slow = slow.next
slowstep += 1
fast = fast.next.next
faststep += 2
p1 = fast
p2 = head
while p1 != p2:
p1 = p1.next
p2 = p2.next
return p1
可以简化如下,调整具体为,不重新建立p1和p2;且边界条件的判断更为简洁
class Solution:
def detectCycle(self, head: ListNode) -> 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