并归排序的应用
并归排序的算法实现
def merge_sort(lists):
# 递归结束条件
if len(lists) <= 1:
return lists
# 分治进行递归
middle = len(lists)//2
left = merge_sort(lists[:middle])
right = merge_sort(lists[middle:])
# 将两个有序数组进行合并
result = []
i = j = 0
while i < len(left) and j < len(right):
# 将较小值放入到result中
if left[i] < right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
# 将未被扫描到的直接追加到result后面
if i == len(left): result.extend(right[j:])
else: result.extend(left[i:])
return result
if __name__ == '__main__':
a = [2, 6, 10, 3, 5, 8, 4]
print(merge_sort(a))
并归排序的更改版
def merge_sort(nums):
if len(nums) <= 1:
return nums
middle = len(nums)//2
left = merge_sort(nums[:middle])
right = merge_sort(nums[middle:])
i = j = 0
count = 0
while i < len(left) and j < len(right):
if left[i] < right [j]:
nums[count] = left[i]
i += 1
count += 1
else:
nums[count] = right[j]
j += 1
count += 1
if i == len(left): nums[count:] = right[j:]
else: nums[count:] = left[i:]
return nums
a = [2, 6, 10, 3, 5, 8, 4]
print(a)
并归排序+索引数组解决逆序数问题
这种方法可以用来解决逆序数问题,即选择返回一个List组,每个位置的数代表着该位置上的数后面小于它的数的个数:
实例:
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
通过这种方式可以得到每一个List中每个数分别的逆序数,要实现这种方式需要三个数组,分别是排序数组,索引数组以及结果数组。
实现算法如下:
class Solution:
def countSmaller(self, nums):
size = len(nums)
if size == 0:
return []
if size == 1:
return [0]
temp = [None for _ in range(size)]
indexes = [i for i in range(size)]
res = [0 for _ in range(size)]
self.__helper(nums, 0, size - 1, temp, indexes, res)
return res
def __helper(self, nums, left, right, temp, indexes, res):
if left == right:
return
mid = left + (right - left) // 2
# 计算一下左边
self.__helper(nums, left, mid, temp, indexes, res)
# 计算一下右边
self.__helper(nums, mid + 1, right, temp, indexes, res)
if nums[indexes[mid]] <= nums[indexes[mid + 1]]:
return
self.__sort_and_count_smaller(nums, left, mid, right, temp, indexes, res)
def __sort_and_count_smaller(self, nums, left, mid, right, temp, indexes, res):
# [left,mid] 前有序数组
# [mid+1,right] 后有序数组
# 先拷贝,再合并
for i in range(left, right + 1):
temp[i] = indexes[i]
l = left
r = mid + 1
for i in range(left, right + 1):
if l > mid:
# l 用完,就拼命使用 r
# [1,2,3,4] [5,6,7,8]
indexes[i] = temp[r]
r += 1
elif r > right:
# r 用完,就拼命使用 l
# [6,7,8,9] [1,2,3,4]
indexes[i] = temp[l]
l += 1
# 注意:此时前面剩下的数,比后面所有的数都大
res[indexes[i]] += (right - mid)
elif nums[temp[l]] <= nums[temp[r]]:
# [3,5,7,9] [4,6,8,10]
indexes[i] = temp[l]
l += 1
# 注意:
res[indexes[i]] += (r - mid - 1)
else:
assert nums[temp[l]] > nums[temp[r]]
# 上面两种情况只在其中一种统计就可以了
# [3,5,7,9] [4,6,8,10]
indexes[i] = temp[r]
r += 1