第二十五题
第二十五题是k个一组翻转链表,意思是给定一个链表,将每k个结点化成一组,对它们进行翻转操作,在对每一组都进行翻转操作之后,将它们重新连接起来,返回这个新的链表。所以代码思路也很好想,首先需要对链表的结点数量进行检查,如果链表结点的数量不足k个即无法进行分组,也就直接返回原链表。如果检查之后可以进行分组,就对前k个结点使用头插法进行翻转操作,最后将翻转后的链表与原链表相连,重复以上操作就可以完成对k个一组链表的翻转。
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
dummy = ListNode(0)
dummy.next = head
pre = dummy
while True:
tail = pre
# 检查剩余节点是否够 k 个
for i in range(k):
tail = tail.next
if not tail:
return dummy.next
nex = tail.next
# 翻转 k 个节点
prev, curr = tail.next, pre.next
for i in range(k):
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp
# 连接翻转后的部分
tmp = pre.next
pre.next = tail
pre = tmp
在这里对头插法翻转链表的过程进行一些解释,一开始我在理解的时候产生了一些混乱。这里一共有两个指针,还有一个临时指针用于进行交换,整个翻转的过程用一个表格来进行展示应该会更加清晰。在最开始检查链表结点数量是否足够k个的时候,将tail指针已经向后移动了k步。
步骤 | curr | prev | tmp | 操作 | 结果链表(已翻转部分用粗体) |
---|---|---|---|---|---|
1 | 1 | 4 | 2 | 1.next=4 | 1→4 2→3→4→5 |
2 | 2 | 1 | 3 | 2.next=1 | 2→1→4 3→4→5 |
3 | 3 | 2 | 4 | 3.next=2 | 3→2→1→4 4→5 |
- prev 初始为 tail.next(即4),curr 初始为 pre.next(即1)
- 每次把 curr 插到 prev 前面,prev向前推进,curr向后推进
这里的curr指的是当前需要操作的结点,prev指的是已经翻转好后链表的头结点,temp是用来暂存当前要操作结点的下一结点以防断链。每次把当前结点插到已经翻转后的结点的最前面就是头插法的思想。
第二十六题
第二十六题是删除有序数组中的重复项,这题可以使用双指针即快慢指针,快指针用来遍历数组,当快指针的值与慢指针的值不相等时,移动慢指针,并将快指针的值赋予移动后慢指针所指位置。慢指针用来保存不重复的部分,最后需要返回不含重复项数组的长度,因此返回慢指针+1即为数组长度,故有如下代码:
class Solution:
def removeDuplicates(self, nums: list[int]) -> int:
if not nums:
return 0
slow = 0
for fast in range(1, len(nums)):
if nums[fast] != nums[slow]:
slow += 1
nums[slow] = nums[fast]
return slow + 1