栈&队列&哈希表&堆-python https://blog.csdn.net/qq_19446965/article/details/102982047
1、丑数 II
编写一个程序,找出第 n 个丑数。
丑数就是只包含质因数 2, 3, 5 的正整数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:
1 是丑数。
n 不超过1690。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number-ii
先回忆一下《丑数 I》
编写一个程序判断给定的数是否为丑数。
https://leetcode-cn.com/problems/ugly-number-ii/
class Solution(object): def isUgly(self, num): """ :type num: int :rtype: bool """ if num <= 0: return False if num == 1: return True while num >= 2 and num % 2 == 0: num /= 2 while num >= 3 and num % 3 == 0: num /= 3 while num >= 5 and num % 5 == 0: num /= 5 return num == 1
丑数 II有点相反
class Solution(object): def nthUglyNumber(self, n): """ :type n: int :rtype: int """ import heapq heap = [1] visited = set([1]) num = None for i in range(n): num = heapq.heappop(heap) for factor in [2, 3, 5]: if num * factor not in visited: visited.add(num * factor) heapq.heappush(heap, num * factor) return num
2、Top k largest Number
例:n个数值选出最大k个数(3<k<n)的最小算法复杂度是( O(n) )
1.最简单的方法:将n个数排序,排序后的前k个数就是最大的k个数,这种算法的复杂度是O(nlogn)
2.O(n)的方法:
解法1:利用快排的patition思想,从数组S中随机找出一个元素X,把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素小于X。这时有两种情况:
1. Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数;
2. Sa中元素的个数大于等于k,则返回Sa中的第k大数。时间复杂度近似为O(n),但最坏情况下复杂度为O(n^2)。
解法2:利用hash保存数组中元素Si出现的次数,利用计数排序的思想,线性从大到小扫描过程中,前面有k-1个数则为第k大数,平均情况下时间复杂度O(n)
3.O(nlogk)的方法:先创建一个大小为k的最小堆,接下来我们每次从输入的n个整数中读入一个数,如果这个数比最小堆的堆顶元素还要大,那么替换这个最小堆的堆顶并调整。
两种方法的优缺点:
堆排序适用于海量数据,即它不需要所有的数据都加载进内存,只需要维护一个大小为m的小顶堆,这是其一个巨大的优势。
快排方法速度快,但是面对海量数据是就显得无能为力了,因为他需要维护整个数组。
4..O(n)查找第K小的数 BFPRT算法 - warm3snow - 博客园 https://www.cnblogs.com/informatics/p/5092741.html
算法的思想是修改快速选择算法的主元选取方法,提高算法在最坏情况下的时间复杂度。其主要步骤为:
- 首先把数组按5个数为一组进行分组,最后不足5个的忽略。对每组数进行排序(如插入排序)求取其中位数。
- 把上一步的所有中位数移到数组的前面,对这些中位数递归调用BFPRT算法求得他们的中位数。
- 将上一步得到的中位数作为划分的主元进行整个数组的划分。
- 判断第k个数在划分结果的左边、右边还是恰好是划分结果本身,前两者递归处理,后者直接返回答案。
其预算法不作实现,本次只关注堆
class Solution: def get_top_k(k, nums): import heapq heap = [] for num in nums: heapq.heappush(heap, num) if len(heap) > k: heapq.heappop(heap) return sorted(heap, reverse=True)
3、合并k个排序链表
合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。
class ListNode(object): def __init__(self, val, next=None): self.val = val self.next = next
方法一:归并算法
class Solution: """ @param lists: a list of ListNode @return: The head of one sorted list. """ def mergeKLists(self, lists): if not lists: return None return self.merge_range_lists(lists, 0, len(lists) - 1) def merge_range_lists(self, lists, start, end): if start == end: return lists[start] mid = (start + end) // 2 left = self.merge_range_lists(lists, start, mid) right = self.merge_range_lists(lists, mid + 1, end) return self.merge_two_lists(left, right) def merge_two_lists(self, head1, head2): tail = dummy = ListNode(0) while head1 and head2: if head1.val < head2.val: tail.next = head1 head1 = head1.next else: tail.next = head2 head2 = head2.next tail = tail.next if head1: tail.next = head1 if head2: tail.next = head2 return dummy.next
方法二:使用 heap
1、将所有元素加入到堆
2、遍历,一个一个取出最小值,连接起来
import heapq ListNode.__lt__ = lambda x, y: (x.val < y.val) class Solution: """ @param lists: a list of ListNode @return: The head of one sorted list. """ def mergeKLists(self, lists): if not lists: return None dummy = ListNode(0) tail = dummy heap = [] for head in lists: # 1、将所有元素加入到堆 if head: heapq.heappush(heap, head) while heap: # 2、遍历,一个一个取出最小值,连接起来 head = heapq.heappop(heap) tail.next = head tail = head if head.next: heapq.heappush(heap, head.next) return dummy.next
———————————————————
参考:九章算法讲解 https://www.jiuzhang.com/solution/