归并排序
一个数组分成左右两部分,左边排好序,右边排好序,再做一个两个有序数组的合并
23. 合并K个升序链表
对数组归并
冒泡快排归并堆排序_MaYingColdPlay的博客-CSDN博客
看方法2,方法2是和对数组归并排序一样的。不同的是有一个对两个链表排序。
题目描述
#合并k个升序链表
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
if len(lists)==0:
return
if len(lists)==1:
return lists[0]
mid=len(lists)//2
left=self.mergeKLists(lists[:mid])
right=self.mergeKLists(lists[mid:])
return self.merge(left,right)
# 合并两个有序链表
def merge(self,left,right):
dummy=ListNode(0)
tmp=dummy
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
if left:
tmp.next=left
if right:
tmp.next=right
return dummy.next
148.排序链表
常规的快排和归并是对数组进行排序,这个题是对链表进行排序。
(快速排序,归并排序)
LeetCode 148——排序链表 - seniusen - 博客园
为什么要用归并排序。
[LeetCode] 148. Sort List 链表排序 - Grandyang - 博客园
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None or head.next is None:
return head
#左边
left=head
#终点
mid=self.getmid(head)
#右边
right=mid.next
mid.next=None
#递归
return self.merge(self.sortList(left),self.sortList(right))
def merge(self,left,right):
dummy=ListNode(0)
tmp=dummy
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
if left:
tmp.next=left
if right:
tmp.next=right
return dummy.next
#快慢指针找中点
def getmid(self,node):
if node is None:
return None
fast=slow=node
while fast.next and fast.next.next:
fast,slow=fast.next.next,slow.next
return slow
剑指offer51- 数组中的逆序对
冒泡快排归并堆排序_MaYingColdPlay的博客-CSDN博客
对数组归并这个代码是从左到右遍历的,而逆序对得从右往左遍历,方便求count。
class Solution(object):
def __init__(self):
self.count=0
def reversePairs(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
self.mergesort(nums)
return self.count
def mergesort(self,nums):
if len(nums)<=1:
return nums
mid=len(nums)//2
left=self.mergesort(nums[:mid])
right=self.mergesort(nums[mid:])
return self.merge(left,right)
def merge(self,left,right):
#从小到大
result=[]
i=len(left)-1
j=len(right)-1
while i >=0 and j >=0:
if left[i]>right[j]:
self.count=self.count+j+1
result.insert(0,left[i])
i=i-1
elif left[i]<right[j]:
result.insert(0,right[j])
j=j-1
result=left[:i+1]+result
result=right[:j+1]+result
print(result)
return result
二刷
left[i]>right[j]
#从小到大排列,
#由于分冶之后数组是有序的,若left[i]>right[j],则[i,n]的数字都比right[j]大
这种方法可以过,但是没法确定num[i]后面比它小的逆序对有多少,因为在算的时候,是根据若left[i]>right[j],则[i,n]的数字都比right[j]大
class Solution(object):
def __init__(self):
self.count=0
def reversePairs(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
self.mergesort(nums)
return self.count
def mergesort(self,nums):
if len(nums)<=1:
return nums
mid=len(nums)//2
left=self.mergesort(nums[:mid])
right=self.mergesort(nums[mid:])
return self.merge(left,right)
def merge(self,left,right):
#从小到大排列,
#由于分冶之后数组是有序的,若left[i]>right[j],则[i,n]的数字都比right[j]大.
#当left[i]>right[j]时,j+=1 ,所以不会造成重复计算
#分冶合并的时候,把数组分为一块一块的,1和2合并之后为3,3内部不会再进行比较。所以只会产出一次比较,不会造成重复计算。
result=[]
i=0
j=0
while i<len(left) and j<len(right):
if left[i]<=right[j]:
result.append(left[i])
i+=1
else:
result.append(right[j])
self.count+=len(left)-i
j+=1
if i<len(left):
result+=left[i:]
if j<len(right):
result+=right[j:]
return result
left[i]<=right[j]
left[i]<=right[j]时,可以确定在right数组中,[0,j-1]都是比left[i]小的。
可以唯一确定nums[i]后面的逆序对有多少个。可以用这个思路继续做
315. 计算右侧小于当前元素的个数
(315应该要引入一个索引数组,没有索引数组的话直接排元素,找不到数组快之间的先后位置)
注意在最后加上
if i<len(left):
result+=left[i:]
while i<len(left):
self.count += j
i+=1
例子是
left=[4,5]
right=[2,3]
left有几个元素,就要加上j几次。
class Solution(object):
def __init__(self):
self.count=0
def reversePairs(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
self.mergesort(nums)
return self.count
def mergesort(self,nums):
if len(nums)<=1:
return nums
mid=len(nums)//2
left=self.mergesort(nums[:mid])
right=self.mergesort(nums[mid:])
return self.merge(left,right)
def merge(self,left,right):
#从小到大排列,
#left[i]<=right[j]时,可以确定在right数组中,[0,j-1]都是比left[i]小的。
result=[]
i=0
j=0
while i<len(left) and j<len(right):
if left[i]<=right[j]:
result.append(left[i])
self.count+=j
i+=1
else:
result.append(right[j])
j+=1
if i<len(left):
result+=left[i:]
while i<len(left):
self.count += j
i+=1
if j<len(right):
result+=right[j:]
return result
315. 计算右侧小于当前元素的个数
一定要用一个索引数组,不然有重复值区分不出来。
class Solution(object):
def countSmaller(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
arr = []
res = [0] * len(nums)
for idx, num in enumerate(nums):
arr.append((idx, num))
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
# print(left, right)
return merge(left, right)
def merge(left, right):
result = []
i = 0
j = 0
while i < len(left) and j < len(right):
if left[i][1] <= right[j][1]:
result.append(left[i])
res[left[i][0]] += j
i += 1
else:
result.append(right[j])
j += 1
if i < len(left):
result += left[i:]
while i < len(left):
res[left[i][0]] += j
i += 1
if j < len(right):
result += right[j:]
return result
merge_sort(arr)
return res
快速排序
快速排序 - python版超详细讲解_Vince Li的博客-CSDN博客
215. 数组中的第K个最大元素
(也可堆排序)
在最开始要做个处理,k=len(nums)-k,第k大的元素,从最小位开始数是len(nums)-k个。然后就是快排的思想了。
class Solution(object):
def __init__(self):
self.res=0
def quick_sort(self,alist,start,end,k):
mid = alist[start]
low=start
high=end
while low<high:
while low<high and alist[high]>=mid:
high=high-1
alist[low]=alist[high]
while low<high and alist[low]<mid:
low=low+1
alist[high]=alist[low]
alist[low]=mid
print(low)
if low<k:
#右边
self.quick_sort(alist,low+1,end,k)
elif low>k:
self.quick_sort(alist,start,low-1,k)
else:
self.res=mid
print(alist)
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
k=len(nums)-k
self.quick_sort(nums,0,len(nums)-1,k)
return self.res
优化解法
选择基准謉时候随机化,无序数组的话无差别,但是那种 奇怪的测试用例,比如 98111109 这种 有连续值了,随机打乱一下会好点。
class Solution(object):
def __init__(self):
self.res=0
def quick_sort(self,alist,start,end,k):
index = random.randint(start, end)
# mid = alist[start]
low=start
high=end
alist[low], alist[index] = alist[index], alist[low]
mid=alist[start]
while low<high:
while low<high and alist[high]>=mid:
high=high-1
alist[low]=alist[high]
while low<high and alist[low]<mid:
low=low+1
alist[high]=alist[low]
alist[low]=mid
if low<k:
#右边
self.quick_sort(alist,low+1,end,k)
elif low>k:
self.quick_sort(alist,start,low-1,k)
else:
self.res=mid
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
k=len(nums)-k
self.quick_sort(nums,0,len(nums)-1,k)
return self.res
4.寻找两个正序数组的中位数
等价于找第k小元素
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
total = len(nums1) + len(nums2)
# 如果A数组长度+B数组长度total是奇数,则找total/2+1小的元素
# 即为中位数
if total % 2 == 1:
midIndex = total / 2 + 1
res = self.getKthElement(nums1, nums2, midIndex)
return float(res)
# 否则,找total/2,total/2+1这两个元素
else:
midIndex_1 = total / 2
midIndex_2 = total / 2 + 1
a = self.getKthElement(nums1, nums2, midIndex_1)
b = self.getKthElement(nums1, nums2, midIndex_2)
return (a + b) / 2.0
def getKthElement(self,nums1, nums2, k):
len1 = len(nums1)
len2 = len(nums2)
index1 = 0
index2 = 0
while True:
# 边界情况,当index1越界时,直接返回nums2的第k小元素
if index1 == len1:
return nums2[index2 + k -1]
# 边界情况,当index2越界时,直接返回nums1的第k小元素
if index2 == len2:
return nums1[index1 + k - 1]
# 边界情况,k等于1时,返回nums1第一个元素和nums2第一个元素较小者
if k == 1:
return min(nums1[index1], nums2[index2])
new_index1 = min(index1 + k / 2, len1) - 1
new_index2 = min(index2 + k / 2, len2) - 1
pivot1 = nums1[new_index1]
pivot2 = nums2[new_index2]
# 比较nums1[k/2-1]和nums2[k/2-1]
# 如果nums1的小,则忽略掉nums1[0] - nums1[k/2-1]这些元素
# 再更新 k,k 要减去忽略掉的那些元素,index1也要更新,待下轮使用
if pivot1 <= pivot2:
k -= (new_index1 - index1 + 1)
index1 = new_index1 + 1
# 如果nums2的小,则忽略掉nums2[0] - nums2[k/2-1]这些元素
# 再更新 k,k 要减去忽略掉的那些元素,index2也要更新,待下轮使用
else:
k -= (new_index2 - index2 + 1)
index2 = new_index2 + 1
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/duo-tu-xiang-jie-liang-chong-shi-xian-by-75f4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
75. 颜色分类
https://blog.csdn.net/weixin_39853245/article/details/95940448?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-9.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-9.channel_param
241. 为运算表达式设计优先级
class Solution:
def diffWaysToCompute(self, input: str) -> List[int]:
# 如果只有数字,直接返回
if input.isdigit():
return [int(input)]
res = []
for i, char in enumerate(input):
if char in ['+', '-', '*']:
# 1.分解:遇到运算符,计算左右两侧的结果集
# 2.解决:diffWaysToCompute 递归函数求出子问题的解
left = self.diffWaysToCompute(input[:i])
right = self.diffWaysToCompute(input[i+1:])
# 3.合并:根据运算符合并子问题的解
for l in left:
for r in right:
if char == '+':
res.append(l + r)
elif char == '-':
res.append(l - r)
else:
res.append(l * r)
return res
作者:jalan
链接:https://leetcode-cn.com/problems/different-ways-to-add-parentheses/solution/pythongolang-fen-zhi-suan-fa-by-jalan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。