Leetcode 专题训练 递归和分治(五)

归并排序-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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值