【Leetcode每日一题(Days8)】第133场周赛题Ⅱ

【碎碎念:我终于看懂并且理解3193这道题的代码了,我滴天了,不愧是“困难”的题,看灵神的解析我都看了好几遍才懂,中间实在是烦了,我就停了几天又重新看,才理解代码为啥要那样写(主要是那个j的范围啥的没看懂,大体框架还是很好理解)】

3193. 统计逆序对的数目

在这里插入图片描述
(个人觉得,此题看英文挺好理解些)
3193. 统计逆序对的数目

学习视频

灵茶山艾府:3193.统计逆序对的数目详细讲解
讲解之神!!全靠讲解才能理解啊!太感谢灵神了!!!/(ㄒoㄒ)/~~

学习笔记

  • 逆序对【之前从来没听过,第一次看题,一脸懵】:整数数组nums满足i<j并且nums[i]>nums[j] (i,j为nums的index)则称为逆序对
# 用暴力的方法找逆序对的代码
count = 0
# ①正向查找nums
for i in range(len(nums)-1):
	for j in range(i+1,len(nums)-1):
		if nums[i] > nums[j]:
			count += 1

# ②逆向查找nums,就是统计index为j的左边有多少个大于nums【j】的个数
for j in range(len(nums)-1, 0, -1):
	for i in range(j):
		if nums[i] > nums[j]:
			count += 1

  • 确定状态定义和状态转移方程
    【分析】
    假设n = 4,即对perm = 【0,1,2,3】进行排序,j = 5(假设perm可以排序产生5个逆序对)
    现在有四个空位置【①】,【②】,【③】,【④】,(用上面的逆向思维) 假设④号位上为数字3,那么也就是说产生了 k=0个逆序对,间接说明前面 ① 号位 到 ③ 号位需要产生 j - k = 5个逆序对。
    由此得到dfs(i, j) 表示构造排列perm[0] ~ perm[i] 能构造出多少个逆序对 = j的排列
    状态转移方程:dfs(i, j) += dfs(i-1 , j-k )
    i-1:往前移一个位置,对应上面就是④号位结束之后,开始考虑③号位的情况
    j-k:① 号位 到 ③ 号位需要产生的逆序对

  • r的范围
    一直纠结这道题也是因为代码中r<=j<=i+r始终没有理解,后来耐下心捋一遍就懂了
    j<r: 因为j一直就是减少的状态,所以如果 j 比要求的 逆序对数量 r 还要小,无法满足条件,故此时的dfs(i,j) = 0
    j - i > r : 极端的想,在最后一个位置放最小的值,形成的逆序对为i个,如果剩余的逆序对数量 j 减去剩余元素排列后最大逆序对数量 还是大于规定的r那么此时的dfs(i,j) = 0

【题解】

class Solution:
    def numberOfPermutations(self, n: int, requirements: List[List[int]]) -> int:
        MOD = 1_000_000_007
        req = [-1] * n
        req[0] = 0
        for end,cnt in requirements:
            req[end] = cnt
        if req[0]:
            return 0
        @cache 
        def dfs(i,j):
            if i==0:
                return 1
            r = req[i-1]
            # 如果对前面排序的逆序对数量有要求
            if r>=0:
                # j < r 因为j一定是不断变小的,如果一开始j就小于规定的r那么就return 0 
                # j - i > r 在最后一个位置放最小的值,形成的逆序对为i个,如果剩余的逆序对数量j减去
                # 剩余元素排序后最大逆序对数量 还是大于规定的r那么也要return 0 
                return dfs(i-1, r) if r<=j<=i+r else 0
            return sum(dfs(i-1, j-k) for k in range(min(i,j)+1)) % MOD
        return dfs(n-1, req[-1])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值