1 #23-合并K个升序链表
-
题目:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。- 示例1:
输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6
-
分析:
-
答案:
代码 # 思路:每个链表的第一个结点入堆,进行比较 # 最小的出堆,然后找出堆链表中的后续入堆 # 在python3的堆中链表无法比较大小,我们传入的是val和他所在的list(这是第几个链表)方便查找后续 from heapq import * class Solution: def mergeKLists(self, lists: List[ListNode]) -> ListNode: minHeap = [] for index, node in enumerate(lists): # index 用来记录这是第几个链表, node 是每个链表的头结点 if node != None: # 只要头结点不空 heappush(minHeap ,(node.val, index)) # 将当前头结点的value以及该头结点所在的链表index入堆 linkedlistHead = ListNode(-1) # 创建用来存放结果的链表 linkedlistTail = linkedlistHead # 这个是尾结点 while minHeap: val, index = heappop(minHeap) # 堆内链表value最小的出堆,找到他是第几个链表,好找他的下一个位置 linkedlistTail.next = lists[index] # 加入到了结果集合中 linkedlistTail = linkedlistTail.next # 开始加下一个位置 lists[index] = lists[index].next # 找到当前链表的下一个元素 if lists[index] != None: # 如果不空的话就让他入堆 heappush(minHeap, (lists[index].val, index)) # 下一个元素入堆 return linkedlistHead.next # 返回链表
2 #26-删除排序数组中的重复项
- 题目:
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成- 示例1:
给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 你不需要考虑数组中超出新长度后面的元素。
- 示例2:
给定 nums = [0,0,1,1,1,2,2,3,3,4], 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 你不需要考虑数组中超出新长度后面的元素。
- 分析:
双指针的应用:在数组排序后,放置两个指针i和j,i
是慢指针,而j
是快指针。只要nums[i]
=nums[j]
,就增加j
以跳过重复项。当nums[i]
和nums[j]
不等时,则把nums[j]
的值复制给nums[i+1]
,然后递增i
,再重复之前的操作,直到j
到达数组的末尾 - 答案:
class Solution: def removeDuplicates(self, nums: List[int]) -> int: # 数组是空,则返回0 if not nums: return 0 i = 0 # 慢指针 for j in range(1, len(nums)): # 快指针遍历数组 if nums[i] != nums[j]: i += 1 nums[i] = nums[j] return i + 1
3 #33-搜索旋转排序数组
- 题目:
升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。- 示例1:
输入:nums = [4,5,6,7,0,1,2], target = 0 输出:4
- 示例2:
输入:nums = [4,5,6,7,0,1,2], target = 3 输出:-1
- 分析:
二分法:在数组中随便选择一个点,以此点分为前后两部分,一定有一部分是有序的。
先在数组中找出mid
数,根据mid
数判断有序部分。如果mid
数小于第一个数,则mid
数在右边有序部分;若mid
数大于第一个数,则mid
数在左边有序部分。
然后判断目标数在那一部分,比较目标数和有序部分的边界关系即可。 - 答案:
class Solution: def search(self, nums: List[int], target: int) -> int: """用二分法,先判断左右两边哪一边是有序的,再判断是否在有序的列表之内""" if len(nums) <= 0: return -1 left = 0 right = len(nums) - 1 while left < right: mid = (right - left) // 2 + left #得出`mid`数 if nums[mid] == target: return mid # 如果中间的值大于最左边的值,说明左边是有序部分 if nums[mid] > nums[left]: # 若目标数在左边,右边界为`mid`数;不在左边,左边界为`mid`数+1 if nums[left] <= target <= nums[mid]: right = mid else: # 这里 +1,因为上面是 <= 符号 left = mid + 1 # 否则右边有序 else: # 注意:这里必须是 mid+1,因为根据我们的比较方式,mid属于左边的序列 if nums[mid+1] <= target <= nums[right]: left = mid + 1 else: right = mid return left if nums[left] == target else -1