1. lc 23 - 合并K个升序链表
题目来源
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
1.1 解题思路
分治合并 - 将 k 个链表配对并将同一对中的链表合并; - 第一轮合并以后,k 个链表被合并成了 k/2 个链表 - 重复这一过程,链表合并为 k/4, k/8, 直到我们得到了最终的有序链表。
具体流程图:

1.2 时间复杂度
- 时间复杂度:考虑递归「向上回升」的过程——第一轮合并 k/2 组链表,每一组的时间代价是 O(2n);第二轮合并 k/4 组链表,每一组的时间代价是 O(4n) ...... 递归的每一层是O(kn), 一共log(k)层。所以总的时间代价是 O (∑ k/2^i × 2^i*n) = O(kn×logk),故渐进时间复杂度为 O(kn×logk)。
- 空间复杂度:一共log(k)层递归。递归会使用到 O(logk) 空间代价的栈空间。
1.3 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 
 | 
 
 
 
 class Solution:
 def mergeKLists(self, lists: List[ListNode]) -> ListNode:
 if len(lists)==0  :
 return None
 res = lists
 
 while len(res) > 1:
 merge_time = len(res)//2
 if len(res)%2 == 1: merge_time += 1
 tmp = []
 for i in range(merge_time):
 if (i+1)*2 <= len(res):
 
 tmp.append(self.merge(res[i*2],res[i*2+1]))
 else:
 
 tmp.append(res[-1])
 
 res = tmp
 return res[0]
 
 
 def merge(self, l1: List[ListNode],l2: List[ListNode] ):
 move = dummy_node = ListNode(10086)
 while l1 or l2:
 
 if not l1:
 move.next = l2
 l2 = l2.next
 elif not l2:
 move.next = l1
 l1 = l1.next
 elif l1.val <= l2.val and l1 and l2:
 move.next = l1
 l1 = l1.next
 elif l1.val > l2.val and l1 and l2:
 move.next = l2
 l2 = l2.next
 move = move.next
 
 return dummy_node.next
 
 | 
2. lc 26 - 删除排序数组中的重复项
题目来源
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
2.1 解题思路
简单题。删除重复元素,返回改动后列表长度。
2.2 时间复杂度
2.3 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | class Solution:def removeDuplicates(self, nums: List[int]) -> int:
 pointer = 0
 tmp = float('inf')
 while pointer < len(nums):
 if nums[pointer] != tmp:
 tmp = nums[pointer]
 pointer += 1
 else:
 del nums[pointer]
 return len(nums)
 
 | 
3. lc 33 - 搜索旋转排序数组
题目来源
3.1 解题思路
看到排序问题,就想到二分查找。二分查找 难就难在,arr[mid]跟谁比。我们的目的是:当进行一次比较时,一定能够确定答案在mid的某一侧。
由于数组由两部分组成,左边递增区域,和右边递增区域。可以感知到,分2种情况讨论。
第一种情况:mid的值在左边区域内,我们可以判断,1)当target在left值和mid值之间时,target在一个显示的递增区间。我们将在left值和mid值之间进行二分查找;2)否则,我们在mid值到right值之间进行二分查找。
第二种情况:mid的值在右边区域内,我们可以判断,1)当target在mid值和right值之间时,target在一个显示的递增区间。我们将在mid值和right值之间进行二分查找;2)否则,我们在left值到mid值之间进行二分查找。
3.2 时间复杂度
3.3 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | class Solution:def search(self, nums: List[int], target: int) -> int:
 if not nums: return -1
 left, right = 0, len(nums)-1
 while  left <= right:
 mid = (left + right)//2
 if target == nums[mid]:
 return mid
 if nums[mid] < nums[left]:
 if nums[mid] <= target and target <= nums[right]:
 left = mid + 1
 else:
 right =  mid - 1
 elif nums[mid] >= nums[left]:
 if nums[left] <= target and target <= nums[mid]:
 right =  mid - 1
 else:
 left = mid + 1
 return -1
 
 
 |