把数组排成最小的数
- 自定义排序:
- 如果x+y > y+x, 那么x>y -> x放在y的后面
快速排序
https://www.runoob.com/python3/python-quicksort.html
- 对于 i ··· l ··· j,如果 strs[j] + strs[l] >= strs[l] + strs[j],不需要换位,j 指针前移;
- 对于 I ··· l ··· j,
class Solution:
def minNumber(self, nums: List[int]) -> str:
def quick_sort(l , r):
if l >= r: return
i, j = l, r
while i < j:
while strs[j] + strs[l] >= strs[l] + strs[j] and i < j:
j -= 1 # 不需要换位
while strs[i] + strs[l] <= strs[l] + strs[i] and i < j:
i += 1 # 不需要换位
# 需要互换位置
strs[i], strs[j] = strs[j], strs[i]
strs[i], strs[l] = strs[l], strs[i] # piovt归位
quick_sort(l, i - 1) # 左子序列
quick_sort(i + 1, r) # 右子序列
strs = [str(num) for num in nums]
quick_sort(0, len(strs) - 1) # 快速排序
return ''.join(strs) # 拼接输出
内置排序函数
- 通过定义一个sort_rule函数,对于两个输入参数xy,x<y输出-1,x>y输出1
- 常用 b = sorted(a, key=f),但是该方法只能用于function输入一个参数,入f(x) = len(x)
- 本题的function需要两个输入,即x,y;并且需要比较他俩组成的数字大小关系,所以使用老版本方法 b = sorted(a, key=functools.cmp_to_key(f) )
class Solution:
def minNumber(self, nums: List[int]) -> str:
def sort_rule(x,y):
xy = x+y
yx = y+x
if xy > yx: #应该输出yx,也就是x比较大,sorted给放到后面去
return 1
if xy< yx: # 应该输出xy,排序结果是x小,放到前面
return -1
else:
return 0
strs = [str(num) for num in nums]
sorted_strs = sorted(strs, key=functools.cmp_to_key(sort_rule))
return ''.join(sorted_strs)
扑克牌中的顺子
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
- 不考虑大小王,顺子牌应该满足的条件:(如[1,2,3,4,5])
- 无重复的牌;最大和最小之差<5(最大只能为4)
class Solution:
def isStraight(self, nums: List[int]) -> bool:
joker = 0
nums.sort() # 数组排序
for i in range(4):
if nums[i] == 0: joker += 1 # 统计大小王数量
# 最终返回的最小牌为nums[joker],因为要剔除前面大小王的数量
elif nums[i] == nums[i + 1]: return False # 若有重复,提前返回 false
return nums[4] - nums[joker] < 5 # 最大牌 - 最小牌 < 5 则可构成顺子
最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
快速排序,返回有序数组的切片[:k]即可
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
# 快速排序,返回数组的切片
def quick_sort(arr,l,r):
# l: left index,实际上当前的基准元素
# r: right index,界
if l >= r :return
# 初始化两个指针 i,j
i,j = l,r
while i<j:
# 从右向左找第一个小于基准的 arr[j]
# 从左向右找第一个大于基准的 arr[i]
while i<j and arr[j] >= arr[l]: j -= 1
while i<j and arr[i] <= arr[l]: i += 1
# 把所有这种情况的pairs进行换位
arr[i],arr[j] = arr[j],arr[i]
# 最终i,j相遇,所有小的都在左侧,大的都在右侧
# 把基准元素arr[l]放到当前的位置arr[i]
arr[i],arr[l] = arr[l],arr[i]
# 再分别对左右子序列进行排序 (当前arr[i]不需要考虑了)
quick_sort(arr,l,i-1)
quick_sort(arr,i+1,r)
quick_sort(arr,0,len(arr)-1)
return arr[:k]
优化
- 检查基准元素当前的index,判断接下来需要排序左边还是右边
- 如果k=i,直接返回它的左子序列就可
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
# 快速排序,返回数组的切片
def quick_sort(arr,l,r):
if l >= r :return
i,j = l,r
while i<j:
while i<j and arr[j] >= arr[l]: j -= 1
while i<j and arr[i] <= arr[l]: i += 1
arr[i],arr[j] = arr[j],arr[i]
# 把基准元素arr[l]放到当前的位置arr[i]
arr[i],arr[l] = arr[l],arr[i]
# 判断当前基准元素所在的index,如果刚好是k,直接返回它左边的子序列
if k == i:
return(arr[:i])
if k<i:
quick_sort(arr,l,i-1)
if k>i:
quick_sort(arr,i+1,r)
quick_sort(arr,0,len(arr)-1)
return arr[:k]
数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
["MedianFinder","addNum","addNum","findMedian","addNum","findMedian"]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]
有序列表
给定一长度为 N 的无序数组,其中位数的计算方法:首先对数组执行排序(使用 O(NlogN)时间),然后返回中间元素即可(使用 O(1) 时间)。
针对本题,根据以上思路,可以将数据流保存在一个列表中,并在添加元素时 保持数组有序 。此方法的时间复杂度为 O(N),其中包括: 查找元素插入位置 O(logN)(二分查找)、向数组某位置插入元素 O(N)(插入位置之后的元素都需要向后移动一位)。
双堆定义
- 堆A存储比较大的一半元素,堆顶是其中最小的一个元素
- 堆B存储比较小的一半元素,堆顶是其中最大的一个元素
- 如果N为奇数,保证堆A里面元素多一个,这样返回中位数只返回A的堆顶即可
- 如果N为偶数,中位数 = A顶+B顶/2
插入元素
- 为了保证上面说的AB两个堆的元素个数:
- 如果这是第奇数个(A本身比B多一个,现在让他们一样多),向A插,再把A顶推给B,这样A个数不变,B增加了
- 如果这是第偶数个(两边一样多,现在要让A多一个),向B插,再把B堆顶推给A,这样B个数不变,A增加了一个
复杂度
- 查找中位数 O(1) : 获取堆顶元素使用O(1) 时间;
- 添加数字 O(logN) 堆的插入和弹出操作使用 O(logN)时间。
- 空间复杂度 O(N):元素数量
通过自带的heapq库完成
由于默认堆顶最大,实现A堆顶为最小的元素,需要全部取负值
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.a = [] # 放大的一半
self.b = [] # 放小的一半
def addNum(self, num: int) -> None:
if len(self.a) == len(self.b):
# AB等长,往B加,堆顶推给A
heappush(self.b, num)
heappush(self.a, -heappop(self.b))
else:
# A比B多1,往A加,堆顶推给B
heappush(self.a, -num)
heappush(self.b, -heappop(self.a))
def findMedian(self) -> float:
if len(self.a) == len(self.b):
return (-self.a[0]+self.b[0])/2.0
return -self.a[0]