2021-12-07 每日打卡:腾讯精选50题
写在前面
“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,遵循LeetBook 列表/腾讯的刷题顺序,所有代码已通过。每日3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。
148. 排序链表
- 递归的归并排序:
class Solution:
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 归并排序的合并
def merge(left,right):
head = tmp = ListNode(0)
while left and right:
if left.val < right.val:
tmp.next, left = left, left.next
else:
tmp.next, right = right, right.next
tmp = tmp.next
tmp.next = left if left else right
return head.next
# 空元素,一个元素的情况,直接返回
if not head or not head.next: return head
# 通过快慢指针找到中点!
slow = fast = head
while fast.next and fast.next.next:
slow, fast = slow.next, fast.next.next
# 分成两部分,分别排序+合并
left, right = head, slow.next
slow.next = None
left, right = self.sortList(left), self.sortList(right)
return merge(left,right)
- 迭代的归并排序【第一遍未写出】:
class Solution:
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
tmp, lenth, intv = head, 0, 1
# 统计链表长度
while tmp:
tmp, lenth = tmp.next, lenth+1
# 头结点
res = ListNode(0)
res.next = head
while intv< lenth:
pre, tmp = res, res.next
while tmp:
# 根据i的长度确定每个小块的头部位置
left, i = tmp, intv
while i and tmp:
tmp, i = tmp.next, i-1
# 链表长度不够,而不是小块划分完毕:right为空,无须考虑
if i: break
# 根据i的长度确定每个小块的头部位置
right, i = tmp, intv
while i and tmp:
tmp, i = tmp.next, i-1
len_l, len_r = intv, intv-i
while len_l and len_r:
if left.val <right.val:
pre.next, left, len_l = left, left.next, len_l-1
else:
pre.next, right, len_r = right, right.next, len_r-1
pre = pre.next
# 整个划分小块的过程并没有真正指向next,而是使用长度界定的
# 所以此处也需要用长度作为循环结束条件
pre.next = left if len_l else right
# 将剩余部分顺过去,下一组成对小块需要接上
while len_l>0 or len_r>0:
pre, len_l, len_r = pre.next, len_l-1, len_r-1
pre.next = tmp
intv *= 2
return res.next
33. 搜索旋转排序数组
- 有序想二分:
class Solution:
def search(self, nums: List[int], target: int) -> int:
if not nums:
return -1
# 排序+旋转数组问题:一定存在某一部分是有序
# 另一部分无序(无序的部分可以为0个,当K=0时候)
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
return mid
if nums[0] <= nums[mid]:
if nums[0] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
else:
if nums[mid] < target <= nums[len(nums) - 1]:
l = mid + 1
else:
r = mid - 1
return -1
215. 数组中的第K个最大元素
- 仿快排,建议熟背!快排中partition的结果就是该数应该插入的下标位置!
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
n = len(nums)
k = n-k
def quick_find(start, end):
# 一定要使用pivot,使得最后比较的数交换过去
pivot = start
left, right = start, end
# 这里的判定条件要加上等号!否则会出现4,6,5(key=5)而排序不正确问题
while left < right:
while left < right and nums[right] >= nums[pivot]: right -= 1
while left < right and nums[left] <= nums[pivot]: left += 1
nums[left], nums[right] = nums[right], nums[left]
nums[pivot], nums[right] = nums[right], nums[pivot]
if right == k:
return nums[right]
elif right < k:
return quick_find(right + 1, end)
else:
return quick_find(start, right - 1)
return quick_find(0, n - 1)