24. 两两交换链表中的节点 - 力扣(LeetCode)
1. 文章链接
2. 看到题目的第一想法
还是用指针操作。
起初pre_pt, cur_pt, next_pt三个按照顺序指向数组前三个节点。
pre_pt和cur_pt之间的连接做反向。
pre_pt.next指向next。
pre_pt和cur_pt移动到next和next.next。
但是问题的难点在于,有可能是奇数个节点的链表。
那就要判断了,在pre_pt和cur_pt整体移动时:
先移动pre_pt, 如果pre_pt为None的话,就是偶数个节点,且已经遍历完了,所以也直接结束。
再移动cur_pt, 如果cur_pt为None的话,就是奇数个节点,直接结束。
3. 实现过程中遇到的困难
cur_pt.next指向pre_pt,pre_pt.next指向next_pt后,没有指针指向cur_pt。
需要上一对pre_pt和cur_pt翻转完成后,pre_pt.next指向的是next_pt.next,而非next_pt。
链表这个题非常麻烦。
必须要想清楚pre_pt, cur_pt, next_pt三个指针之间的关系。
而且要使用dummy_head。
pre_pt:指向互换节点对的前一个节点。
cur_pt:指向互换节点对的第一个节点。
next_pt:指向互换节点对的第二个节点。
互换的循环体中:
pre_pt.next指向next_ptcur_pt.next指向next_pt.nextnext_pt.next指向cur_pt这里需要着重注意的是这三步的顺序,一定要先做2.再做3.。否则会丢失next_pt.next。
另外向前移动指针时,pre_pt, cur_pt两个都要移动。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head == None:
return head
dummy_head = ListNode(val=-1, next=head)
pre_pt = dummy_head
cur_pt = pre_pt.next
while cur_pt.next:
next_pt = cur_pt.next
pre_pt.next = next_pt
cur_pt.next = next_pt.next
next_pt.next = cur_pt
pre_pt = cur_pt
cur_pt = pre_pt.next
if cur_pt == None:
break
return dummy_head.next
4. 看完代码随想录之后的想法
我觉得文档中使用的两个判断条件更简单。
而且做法更符合人类思维。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy_head = ListNode(val=-1, next=head)
cur_pt = dummy_head
while (cur_pt.next != None) and (cur_pt.next.next != None):
# 有两个节点就满足交换条件了。
num1 = cur_pt.next
num2 = cur_pt.next.next.next # 之后节点对的num1
cur_pt.next = cur_pt.next.next
cur_pt.next.next = num1
num1.next = num2
# 移动cur_pt
cur_pt = cur_pt.next.next
return dummy_head.next
5. 学习时长
初次实现:2小时。
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
1. 文章链接
2. 看到题目的第一想法
我觉的一个简单的想法是:
- 先遍历一遍,统计链表的总长度。
- 计算是正数第几个元素。
- 再遍历到那个元素的位置,然后删除该元素即可。
3. 实现过程中遇到的困难
4. 看完代码随想录之后的想法
我隐约感觉我的第一个想法不是最好的。 所以先看了文档再实现。 果然:
- 快慢指针
- 快指针和慢指针差步。 使得当快指针走到None的时刻,慢指针就刚好到了要删除节点的前一个节点。 举个例子:
[1, 2, 3, 4, 5] n=2
Slow=1, fast=4
Slow=2, fast=5
Slow=3, fast=None
Delete 4
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy_head = ListNode(val=0, next=head)
fast_pt = dummy_head
slow_pt = dummy_head
for i in range(n + 1):
fast_pt = fast_pt.next
while fast_pt:
fast_pt = fast_pt.next
slow_pt = slow_pt.next
# delete
slow_pt.next = slow_pt.next.next
return dummy_head.next
5. 学习时长
40分钟。
面试题 02.07. 链表相交 - 力扣(LeetCode)
1. 文章链接
2. 看到题目的第一想法
至少应该要从headA和headB发出两个指针,用来向前推进。
统计两条路的长度,做差得到一条路比另一条路多多少节点。
让路长的那个先走完多出的节点个数。
然后再一起推进,判断id()是否一致,一致说明有交点,返回即可,否则返回None。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
a_pt = headA
b_pt = headB
is_a_longer = False
is_b_longer = False
diff = 0
while a_pt and b_pt:
a_pt = a_pt.next
b_pt = b_pt.next
while a_pt:
a_pt = a_pt.next
diff += 1
is_a_longer = True
while b_pt:
b_pt = b_pt.next
diff += 1
is_b_longer = True
a_pt = headA
b_pt = headB
if is_a_longer:
while diff > 0:
a_pt = a_pt.next
diff -= 1
if is_b_longer:
while diff > 0:
b_pt = b_pt.next
diff -= 1
while a_pt:
if id(a_pt) == id(b_pt):
break
a_pt = a_pt.next
b_pt = b_pt.next
return a_pt
3. 实现过程中遇到的困难
无。
4. 看完代码随想录之后的想法
跟我思路一样,只不过是后期固定了较长链表为a_pt。
5. 学习时长
40分钟。
142. 环形链表 II - 力扣(LeetCode)
1. 文章链接
2. 看到题目的第一想法
快慢指针,一个快指针一次走两步,一个慢指针一次走一步。
根据这个速度差一只做,如果两个指针在快指针为None前碰到了,那就说明有环。
碰到的点就是入环的第一个节点。(❌)
3. 实现过程中遇到的困难
相遇点并不是环的入口!!!
4. 看完代码随想录之后的想法
相遇点时刻:
slow_pt的路程=
fast_pt的路程=
两个路程是二倍的关系。
所以最后得到
所以只要有一个指针从相遇点出发,一个指针从head出发,两个指针同速一直往前走,从相遇点出发的指针在转了若干圈并额外走了一个之后,一定会遇从head出发的指针在距离head为的位置相遇。
即我们所求的号节点位置。
# 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]:
fast_pt = head
slow_pt = head
while fast_pt and fast_pt.next:
fast_pt = fast_pt.next.next
slow_pt = slow_pt.next
if id(fast_pt) == id(slow_pt):
break
if fast_pt == None or fast_pt.next == None:
return None
a_pt = head
b_pt = fast_pt
while a_pt:
if id(a_pt) == id(b_pt):
break
a_pt = a_pt.next
b_pt = b_pt.next
return a_pt
5. 学习时长
1小时。