归并排序-K神版本
K神归并排序代码更简单一些,但是上次我只是勉强看懂,今天尝试复现一下,因为后面的315和剑指offer51都要用到归并排序。
def sortArray(self, nums: List[int]) -> List[int]:
def mergesort(left, right, nums):
if left >= right: return
mid = (left + right) // 2
mergesort(left, mid, nums)
mergesort(mid+1, right, nums)
i, j = 0, mid - left + 1
temp = nums[left:right + 1]
for k in range(left, right + 1):
if i == (mid - left + 1):
nums[k] = temp[j]
j += 1
elif j == (right - left + 1) or temp[i] < temp[j]:
nums[k] = temp[i]
i += 1
else:
nums[k] = temp[j]
j += 1
mergesort(0, len(nums)-1, nums)
return nums
剑指 Offer 51. 数组中的逆序对
终于自己写出来了。
def reversePairs(self, nums: List[int]) -> int:
def merge_sort(left, right, nums):
if left >= right: return 0
mid = (left + right) // 2
res = merge_sort(left, mid, nums) + merge_sort(mid + 1, right, nums)
i, j = 0, mid - left + 1
temp = nums[left:right+1]
for k in range(left, right + 1):
if i == mid - left + 1:
nums[k] = temp[j]
j += 1
elif j == right - left + 1 or temp[i] <= temp[j]:
nums[k] = temp[i]
i += 1
else:
nums[k] = temp[j]
res += mid - i - left + 1
j += 1
return res
return merge_sort(0, len(nums) - 1, nums)
315. 计算右侧小于当前元素的个数
我写的递归,又超时了
def countSmaller(self, nums) -> List[int]:
def recur(nums, li):
if len(nums) == 1:
li.append(0)
return li
count = 0
cur = nums.pop(0)
for i in nums:
if cur > i:
count += 1
li.append(count)
return recur(nums, li)
li = []
return recur(nums, li)
下面是参考答案:
记住,你不能理解,你就永远写不出来。你抄答案,今天以为自己会了,其实下次做,你还是不会。最快的捷径就是理解了,然后自己动手可以写出来。再多写几遍,才是真的会了。
from typing import List
class Solution:
def countSmaller(self, nums: List[int]) -> List[int]:
size = len(nums)
if size == 0:
return []
if size == 1:
return [0]
temp = [None for _ in range(size)]
res = [0 for _ in range(size)]
# 索引数组,作用:归并回去的时候,方便知道是哪个下标的元素
indexes = [i for i in range(size)]
self.__merge_and_count_smaller(nums, 0, size - 1, temp, indexes, res)
return res
def __merge_and_count_smaller(self, nums, left, right, temp, indexes, res):
if left == right:
return
mid = left + (right - left) // 2
self.__merge_and_count_smaller(nums, left, mid, temp, indexes, res)
self.__merge_and_count_smaller(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]
i = left
j = mid + 1
for k in range(left, right + 1):
if i > mid:
indexes[k] = temp[j]
j += 1
elif j > right:
indexes[k] = temp[i]
i += 1
res[indexes[k]] += (right - mid)
elif nums[temp[i]] <= nums[temp[j]]:
indexes[k] = temp[i]
i += 1
res[indexes[k]] += (j - mid - 1)
else:
indexes[k] = temp[j]
j += 1
if __name__ == '__main__':
nums = [5, 2, 6, 1]
solution = Solution()
result = solution.countSmaller(nums)
print(result)
下面是我参考答案写的,不对,看不动了,明天再继续看下吧
def countSmaller(self, nums) -> List[int]:
def merge_sort(left, right, nums):
if left >= right: return
mid = (left + right) // 2
i, j = 0, mid - left + 1
temp = nums[left:right + 1]
res = [0 for _ in range(len(nums))]
ind = [i for i in range(len(nums))]
for k in range(left, right + 1):
if i == mid - left + 1:
nums[k] = temp[j]
j += 1
elif j == right - left + 1:
nums[k] = temp[i]
i += 1
res[ind[k]] += right - mid
elif temp[i] <= temp[j]:
nums[k] = temp[i]
i += 1
res[ind[k]] += j - mid + 1
else:
nums[k] = temp[j]
j +=1
return res
return merge_sort(0, len(nums) - 1, nums)