当前位置: 首页 > news >正文

力扣每日一题(二)任务安排问题 + 区间变换问题 + 排列组合数学推式子

目录

1. 任务安排问题

1353. 最多可以参加的会议数目

1235. 规划兼职工作

1488. 避免洪水泛滥

2. 数组区间变换问题

3362. 零数组变换 III    最大堆 + 差分

3480. 删除一个冲突对后最大子数组数目    最小与次小

3. 数学推式子

3154. 到达第 K 级台阶的方案数  

排列组合

记忆化搜索

3495. 使数组元素都变为零的最少操作次数  [ l, r ] 先求 [ 1, n ]

2929. 给小朋友们分糖果 II    排列组合 + 容斥原理


1. 任务安排问题

按开始 / 结束时间排序,堆 or 二分 找上一个。

1353. 最多可以参加的会议数目

给二元组 每个会议的 [开始,结束] 时间(每个会议可以在这个区间的任意一天参加)最多可以参加的会议数

我们从前到后 遍历每一天 看每天该排哪个会议。 能参加需要开始时间早于这天

在此基础,(贪心)我们要选能参加的会议中 最早结束的那个。

于是对于 按开始时间排序的这些会议,对每一天 做三个步骤:

加入日程:如果开始时间早于现在,就添加到 todo中;

踢出过期:结束时间晚于现在的,删掉。

选择最早结束:在加入日程时 记录结束时间的最小堆;

import heapq
class Solution:def maxEvents(self, events: List[List[int]]) -> int:events.sort()n,maxn,ans,j=len(events),max(e[1] for e in events),0,0todo=[]for i in range(1,maxn+1):# 加入可以参加的会议while j<n and events[j][0]<=i:heappush(todo,events[j][1])j+=1# 删除过期会议while todo and cando[0]<i:heappop(todo)# 安排最早结束的会议if todo:heappop(todo)ans+=1return ans

法二:并查集

按照结束时间排序,先安排结束的早的。安排在能安排的最早的一天

安排就向后串联,指向后一天(用并查集实现)

class Solution:def maxEvents(self, events: List[List[int]]) -> int:events.sort(key=lambda e: e[1])mx = events[-1][1]fa = list(range(mx + 2))def find(x: int) -> int:if fa[x] != x:fa[x] = find(fa[x])return fa[x]ans = 0for start_day, end_day in events:x = find(start_day)  # 查找从 start_day 开始的第一个可用天if x <= end_day:ans += 1fa[x] = x + 1  # 标记 x 已占用return ans

1235. 规划兼职工作

给定任务的 [开始时间,结束时间,收益]  问不重合任务的最大收益。

dp[i] 代表做到前 i 个工作的最大收益(单调增的)。

上一个能衔接的任务 根据结束时间。所以按结束时间排序

状态转移 如果做这个任务 就衔接 a[i][0] 前,最后一个 即结束时间最晚的(二分找

class Solution:def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int:n=len(endTime)a=sorted(zip(startTime,endTime,profit),key=lambda p:p[1])dp=[0]*(n+1)for i in range(n):k=bisect_right(a,a[i][0],hi=i,key=lambda p:p[1])dp[i+1]=max(dp[i],dp[k]+a[i][2])return dp[n]

1488. 避免洪水泛滥

输入下雨情况,输出抽水安排。

rains 代表下雨情况,0代表不下(可以抽水),其余代表哪个位置下。

需要安排抽水,使得区域在下一次下雨前被抽过水

先用 full 存满的 { 湖:日期 },dry存可以抽水的日期(有序集合SortedList 方便后续二分找)。

发现当前湖要爆了,在存的日期之后,找最早的可以抽水的时间。(时间晚的灵活度更高 可以抽其他湖)


解释:越晚的抽水日,灵活性越大,可以用于更晚装满的湖。所以越晚的抽水日越应该留到后面再使用。

class Solution:def avoidFlood(self, rains: List[int]) -> List[int]:n = len(rains)ans = [-1] * nfull_day = {}  # lake -> 装满日dry_day = SortedList()  # 未被使用的抽水日for i, lake in enumerate(rains):if lake == 0:ans[i] = 1  # 先随便选一个湖抽干dry_day.add(i)  # 保存抽水日continueif lake in full_day:j = full_day[lake]# 必须在 j 之后,i 之前把 lake 抽干# 选一个最早的未被使用的抽水日,如果选晚的,可能会导致其他湖没有可用的抽水日k = dry_day.bisect_right(j)if k == len(dry_day):return []  # 无法阻止洪水d = dry_day[k]ans[d] = lakedry_day.discard(d)  # 移除已使用的抽水日full_day[lake] = i  # 插入或更新装满日return ans

2. 数组区间变换问题

3362. 零数组变换 III    最大堆 + 差分

q [l,r] 可以把这个区间的数都 -1,最终要把初始数组nums变成 ≤0 。问最多可以删多少 q。

从前往后过 nums,如果这个位置 nums[i] > 0 我们就需要选 i 之前的结束位置尽量靠后的 q

( i 之前 为了能删这个位置,结束位置贪心 越往后影响位置越多)

根据开始时间排序结束时间尽量靠后:把结束时间塞入最大堆(负数最小堆)

区间加减:差分 diff。  需要选用这个 q,把当前 sum +=1,把结束位置后一位 diff -1。

class Solution:def maxRemoval(self, nums: List[int], queries: List[List[int]]) -> int:queries.sort(key=lambda q: q[0])  # 按照左端点从小到大排序h = []diff = [0] * (len(nums) + 1)sum_d = j = 0for i, x in enumerate(nums):sum_d += diff[i]# 维护左端点 <= i 的区间while j < len(queries) and queries[j][0] <= i:heappush(h, -queries[j][1])  # 取相反数表示最大堆j += 1# 选择右端点最大的区间while sum_d < x and h and -h[0] >= i:sum_d += 1diff[-heappop(h) + 1] -= 1if sum_d < x:return -1return len(h)

3480. 删除一个冲突对后最大子数组数目    最小与次小

有1~n的数,给定一些冲突对(可以删除其中的一个)求最多的 不包含冲突对的子数组数目

若没有删除机制,在 i 位置能达到的子数组:要在所有冲突对 a≥i 中最小的 b 前面

讨论不同的 i :倒着往前推 如果这个位置有 冲突对的 a,更新 min b。从 i 开始就有 min b - i 个。

倒着讨论,a 用来判断现在是否需要考虑这个冲突对,b -> 最小和次小 用来看当前 i 最往后到哪个。

每次删最小的 b0,变成次小的 b1,多出来的答案 extra += b1-b0

要看删哪个 q 累积的 extra 最多,有新的最小的 b0 就把 extra = 0 统计新的 q 。

class Solution:def maxSubarrays(self, n: int, conflictingPairs: List[List[int]]) -> int:groups = [[] for _ in range(n + 1)]for a, b in conflictingPairs:if a > b:a, b = b, agroups[a].append(b)ans = max_extra = extra = 0b0 = b1 = n + 1for i in range(n, 0, -1):pre_b0 = b0# 最小和次小for b in groups[i]:if b < b0:b0, b1 = b, b0elif b < b1:b1 = bans += b0 - i # 不考虑删除的统计if b0 != pre_b0:  # 重新统计连续相同 b0 的 extraextra = 0extra += b1 - b0max_extra = max(max_extra, extra)return ans + max_extra

3. 数学推式子

3154. 到达第 K 级台阶的方案数  

从1->k的方案数,可以向上跳2的幂次,也可以向下一级(但不能连续)

排列组合

   把向上向下 分别拿出来 再插空。

     在 j+1 中 插空m  C ( j+1,m )

class Solution:def waysToReachStair(self, k: int) -> int:ans = 0for j in range(30):m = (1 << j) - kif 0 <= m <= j + 1:ans += comb(j + 1, m)return ans

记忆化搜索

(现在位置,之前jump次数,上一次是不是向下跳)

入口(1, 0, False)  如果超过 k+1 之后下不去了,就是0。

分向上 or 向下 两种跳跃方案统计。

class Solution:def waysToReachStair(self, k: int) -> int:@cache  # 缓存装饰器,避免重复计算 dfs 的结果(记忆化)def dfs(i: int, j: int, pre_down: bool) -> int:if i > k + 1:  # 无法到达终点 kreturn 0res = 1 if i == k else 0res += dfs(i + (1 << j), j + 1, False)  # 操作二if not pre_down:res += dfs(i - 1, j, True)  # 操作一return resreturn dfs(1, 0, False)

3495. 使数组元素都变为零的最少操作次数  [ l, r ] 先求 [ 1, n ]

对每个询问 q = [ l, r ] 选两个数变成 除以4 向下取整,都变成0 需要多少次。

f(n) 为 [ 1, n ] 需要除以4的次数,则 [ l, r ] 的次数为 f(r) - f(l-1),  (区间问题 转化为1开始

选两个数操作 因为是连续的区间 不存在一个数超大的情况 可以两两消去,答案为 f(r) - f(l-1) 除以2 向上取整

每个数需要除以4的次数 -> 4进制的位数

设 m 为 n 的二进制位数,k为 ≤ m 的最大偶数

2^k ~ n 的(n-2^k+1)个数 都要 k//2 +1 次 。

k之前的即为:1~3  1次;  4~15  2次 以此类推

化简为    后面减了一个4的等比数列

最终 f(n) 为 

def f(n: int) -> int:if n == 0:return 0m = n.bit_length()k = (m - 1) // 2 * 2res = (k << k >> 1) - (1 << k) // 3  # 前面 2^(k-1) 为了防止 k=0, 先左移k次 再右移1次# 由于 4的幂次%3=1 后面的-1 可以省略return res + (m + 1) // 2 * (n + 1 - (1 << k))class Solution:def minOperations(self, queries: List[List[int]]) -> int:return sum((f(r) - f(l - 1) + 1) // 2 for l, r in queries)

2929. 给小朋友们分糖果 II    排列组合 + 容斥原理

将 n 颗糖果分给 3 位小朋友,确保没有任何小朋友得到超过 limit 颗糖果,总方案数 。

无条件分,隔板法 C(n+2,2) ;减去不符合条件的。

容斥原理 超过 limit:至少一人超过 - 至少两人超过 + 至少三人超过

至少一人:先拿出来 limit +1 ,剩下再分。

def c2(n: int) -> int:return n * (n - 1) // 2 if n > 1 else 0class Solution:def distributeCandies(self, n: int, limit: int) -> int:return c2(n + 2) - 3 * c2(n - limit + 1) + 3 * c2(n - 2 * limit) - c2(n - 3 * limit - 1)
http://www.dtcms.com/a/465086.html

相关文章:

  • LeetCode-33.搜索旋转排序数组-二分查找
  • R语言基础入门详细教程
  • 用wordpress建立学校网站吗人工智能教育培训机构排名
  • 网站及其建设的心得体会wordpress能做大站吗
  • Java SpringMVC(二) --- 响应,综合性练习
  • 【保姆级教程】VMware Workstation Pro 17安装及基础使用
  • 网站开发源代码mvc电子商务网站建设与管理实训报告
  • Bootstrap4 提示框详解
  • 数据分析硬件配置——选购计算机
  • 在Java中,如何实现封装?
  • 【实录】使用 patch-package 修复第三方 npm 包中的 Bug
  • Warm-Flow 1.8.2版本发布|新增功能和优化,体验更稳定
  • 电池组PACK自动化生产线介绍|深圳比斯特自动化
  • 云手机的挂机功能涉及到哪些内容
  • 手机群控软件在游戏运营中的风险管控技术实现
  • js打开网站做欧美市场的网站
  • MongoDB源码delete分析oplog:从删除链路到核心函数实现
  • 运维面试准备——综合篇(一)
  • 线性代数 · 矩阵 | SVD 与 PCA 应用区别
  • 网站漏洞扫描服务个人怎么做公众号
  • 云计算综合标准化体系建设提供系统性指引
  • 阿里云智能集团首席技术官云栖大会要点总结
  • 6. React useState基础使用:useState修改状态的规则;useState修改对象状态的规则
  • 凡科做的网站怎么打不开了天津做再生资源交易的网站
  • AWS Shield 与海外高防服务器的对比分析
  • CTF攻防世界WEB精选基础入门:cookie
  • Vue 中 props 传递数据的坑
  • Descheduler for Kubernetes(K8s 重调度器)
  • Embedding(嵌入):让机器理解世界的通用语言
  • sql练习题单-知识点总结