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

力扣每日一题(三)划分题 + 思路题

目录

1. 划分题&记忆化搜索 @cache

3003. 执行操作后的最大分割数量 -- 记忆化搜索

3144. 分割字符频率相等的最少子字符串 -- 记忆化搜索

698. 划分为k个相等的子集

3117. 划分数组得到最小的值之和

2963. 统计好分割方案的数目

2. 执行操作 思路题

3347. 执行操作后元素的最高频率 II

3397. 执行操作后不同元素的最大数量

2273. 移除字母异位词后的结果数组 -- 快慢指针

56. 合并区间

1553. 吃掉 N 个橘子的最少天数


1. 划分题&记忆化搜索 @cache

3003. 执行操作后的最大分割数量 -- 记忆化搜索

对字符串s 可以最多修改一个字符,然后进行规则划分(前缀不能超过k个不同字符)

记忆化搜索:( i, mask, changed)

现在到第几个字符;这一段前面出现了哪些字符 用位运算进行mask;有没有changed过。

mask : 26个字母是否出现;

不修改:加上 i ,mask中的数量超过 k,就要在 i-1 分割,分割+1;否则接着mask。

如果 changed 可以修改,枚举改成哪个字母,找 max。

class Solution:def maxPartitionsAfterOperations(self, s: str, k: int) -> int:@cachedef dfs(i: int, mask: int, changed: bool) -> int:if i == len(s):return 1# 不改 s[i]bit = 1 << (ord(s[i]) - ord('a'))new_mask = mask | bitif new_mask.bit_count() > k:# 分割出一个子串,这个子串的最后一个字母在 i-1# s[i] 作为下一段的第一个字母,也就是 bit 作为下一段的 mask 的初始值res = dfs(i + 1, bit, changed) + 1else:  # 不分割res = dfs(i + 1, new_mask, changed)if changed:return res# 枚举把 s[i] 改成 a,b,c,...,zfor j in range(26):new_mask = mask | (1 << j)if new_mask.bit_count() > k:# 分割出一个子串,这个子串的最后一个字母在 i-1# j 作为下一段的第一个字母,也就是 1<<j 作为下一段的 mask 的初始值res = max(res, dfs(i + 1, 1 << j, True) + 1)else:  # 不分割res = max(res, dfs(i + 1, new_mask, True))return resreturn dfs(0, 0, False)

3144. 分割字符频率相等的最少子字符串 -- 记忆化搜索

对每个位置 i,往后枚举找可划分区间 (i,j)

在循环找末端点位置 j 的时候,用 Counter 计数,并用 all 判断是否次数都同。

class Solution:def minimumSubstringsInPartition(self, s: str) -> int:n = len(s)@cachedef dfs(i:int)->int:if i==n:return 0# Counter 进行计数c=Counter()ans=inffor j in range(i,n):c[s[j]]+=1# 优化不用判断,字母种类不是字母数目的因数的话 不可能都相等了if (j-i+1)%len(c)!=0:continuecc=c[s[j]]# 可划分就 dfsif all(cc==ac for ac in c.values()):ans=min(ans,dfs(j+1)+1)return ansreturn dfs(0)

698. 划分为k个相等的子集

记忆化搜索

判断能不能把 n 个数 划分为 k 个相等的子集。 先看因数和最大值判断。

二进制 mask 表示有没有使用过。 从 2^n-1 -> 0

dfs (s, p) 代表对当前状态 s,当前余数 p,是否可以继续成功划分。

nums.sort() 从小到大,如果 nums[i] 塞到 p 会爆,后面更大的也会爆(减少判断次数)。

class Solution:def canPartitionKSubsets(self, nums: List[int], k: int) -> bool:all = sum(nums)if all % k:return Falseper = all // knums.sort()  # 方便下面剪枝if nums[-1] > per:return Falsen = len(nums)@cachedef dfs(s, p):if s == 0:return Truefor i in range(n):if nums[i] + p > per:breakif s >> i & 1 and dfs(s ^ (1 << i), (p + nums[i]) % per):  # p + nums[i] 等于 per 时置为 0return Truereturn Falsereturn dfs((1 << n) - 1, 0)

动态规划 dp[s] 存状态 s 当前的余数。

(因为不管什么顺序放,最后剩下来的一个桶(余数)是一定的)

没塞过,且不爆的 -> 转换为可达状态。

class Solution:def canPartitionKSubsets(self, nums: List[int], k: int) -> bool:all = sum(nums)if all % k:return Falseper = all // knums.sort()if nums[-1] > per:return Falsen = len(nums)dp = [-1] * (1 << n)dp[0] = 0for i in range(0, 1 << n):if dp[i] == -1:continuefor j in range(n):if dp[i] + nums[j] > per:breakif (i >> j & 1) == 0:next = i | (1 << j)if dp[next] == -1:dp[next] = (dp[i] + nums[j]) % perreturn dp[(1 << n) - 1] != -1

3117. 划分数组得到最小的值之和

目标划分为 每一段的& 和给出的第二个数组 对应相等。   数组的“值”定义为 数组最后一个元素。

dfs(i, j,  _and) 现在在位置 i,正在划分第 j 段,第 j 段累积的&值为 _and。

当前 _and 与对应值相等则可以进行划分。

class Solution:def minimumValueSum(self, nums: List[int], andValues: List[int]) -> int:n, m = len(nums), len(andValues)@cachedef dfs(i: int, j: int, and_: int) -> int:if n - i < m - j:  # 剩余元素不足return infif j == m:  # 分了 m 段return 0 if i == n else infand_ &= nums[i]res = dfs(i + 1, j, and_)  # 不划分if and_ == andValues[j]:  # 划分,nums[i] 是这一段的最后一个数res = min(res, dfs(i + 1, j + 1, -1) + nums[i])return resans = dfs(0, 0, -1)return ans if ans < inf else -1

2963. 统计好分割方案的数目

所有相同数字必须出现在一段的分割。分割的方案数。

先看哪些位置是必须划分在一起的,如果 m 段,中间有 m-1 个位置是可拼接的,结果即为 2^(m-1)

出现过的数都要被包含,要到最右端 max_r。

先第一遍循环,使用覆盖,得到 r[x] 为 x 出现的最右边位置。

class Solution:def numberOfGoodPartitions(self, nums: List[int]) -> int:r = {}for i, x in enumerate(nums):r[x] = im = max_r = 0for i, x in enumerate(nums):max_r = max(max_r, r[x])if max_r == i:  # 区间无法延长m += 1return pow(2, m - 1, 1_000_000_007)

2. 执行操作 思路题

3347. 执行操作后元素的最高频率 II

可以对 numOperations 个元素调整 [-k,k],最多可以多少相同的数。

nums[i] 可以变成 nums[i] - k ~ nums[i] + k 区间里的数,只需要知道哪个位置被最多的区间包含。

区间+1用差分实现,后一轮统计时 sum += diff

还有修改元素个数条件,用 cnt[x] 记录 x 本身有多少个。上界是 cnt[x] + numOperations。

所以为 min(sum_x,cnt[x] + numOperations) 

由于这个值 sum_x 只受diff影响,后一项只受 cnt[x] 影响。

所以最后结果的最大值位置 只可能出现在 x,x-k,x+k+1。只需要记录、比较这些位置。

class Solution:def maxFrequency(self, nums: List[int], k: int, numOperations: int) -> int:cnt = defaultdict(int)diff = defaultdict(int)for x in nums:cnt[x] += 1diff[x]  # 把 x 插入 diff,以保证下面能遍历到 xdiff[x - k] += 1  # 把 [x-k,x+k] 中的每个整数的出现次数都加一diff[x + k + 1] -= 1ans = sum_d = 0for x, d in sorted(diff.items()):sum_d += dans = max(ans, min(sum_d, cnt[x] + numOperations))return ans

3397. 执行操作后不同元素的最大数量

可以把每个数上下调整k,问最多可以有多少不同的数。

可以建模为军训站队,这个区域最多可以站多少人?最左边的同学会移动到最左边,方便右边的同学好站。

把数从小到大安排,每次安排到能放到的(x-k,x+k)区间,最左边的空位(前一个人pre 之后)。

class Solution:def maxDistinctElements(self, nums: List[int], k: int) -> int:nums.sort()ans = 0pre = -inf  # 记录每个人左边的人的位置for x in nums:x = min(max(x - k, pre + 1), x + k)if x > pre:ans += 1pre = xreturn ans

2273. 移除字母异位词后的结果数组 -- 快慢指针

一个词如果和前一个词异位(同样的单词组成 只是顺序不同)就删掉。

快慢指针的思想:快指针遍历,慢指针把要保留的单词存下来。(实现原空间覆盖)

class Solution:def removeAnagrams(self, words: List[str]) -> List[str]:k = 1for s, t in pairwise(words): # 快指针遍历 pairwise取连续两个词if sorted(s) != sorted(t): # 慢指针存words[k] = tk += 1 del words[k:] # 删掉后面的return words

56. 合并区间

开始位置从前到后排序,和前一个区间不重叠就添加,重叠就通过max结束位置进行合并。

class Solution:def merge(self, intervals: List[List[int]]) -> List[List[int]]:intervals.sort(key=lambda x: x[0])ans = []for interval in intervals:# 不重叠 添加新区间if not ans or ans[-1][1] < interval[0]:ans.append(interval)# 与最后一个区间合并else:ans[-1][1] = max(ans[-1][1], interval[1])return ans

1553. 吃掉 N 个橘子的最少天数

只吃一个橘子,在 n 比较大的时候一定是比较劣的选择。

实际从 除以2和除以3 中选,吃一个只是为了吃掉对应的余数。

开记忆化 + 函数自我调用。

class Solution:@cachedef minDays(self, n: int) -> int:if n<=1:return nreturn min(n%2+1+self.minDays(n//2), n%3+1+self.minDays(n//3))

http://www.dtcms.com/a/519878.html

相关文章:

  • Python爬虫第10课:分布式爬虫架构与Scrapy-Redis
  • 2025年运维部网络安全工作小结1025
  • 基于 Python 的坦克大战小程序,使用 Pygame 库开发
  • 做网站前期需求分析收费么互联网营销是做什么
  • 在 MacOS 中安装 MySQL 8
  • 宿迁网站建设宿迁网站域名的组成
  • Gartner发布AI安全创新指南:用集成的模块化AI安全平台赢得AI安全之战
  • FastGateway 核心技术原理拆解手册
  • vue3中实现渐变三层柱状图
  • 7.IXM6U系统时钟
  • 算子相关通用概念整理
  • Java 操作 PDF 图像:轻松驾驭 PDF 文档中的图片
  • OS_2 进程与线程(进程管理)
  • 网站规划 评价谷歌三件套一键安装
  • 腾讯云服务器如何建设网站百度关键词排名突然没了
  • 【论文笔记】LTX-Video极致速度的视频生成模型
  • 安科瑞防逆流解决方案:物联网技术赋能光伏能源高效管理
  • 如何根据不同的场景选择YOLO相应的基座模型
  • 【OJ】二叉树的经典OJ题
  • Excel 重磅更新 AI技术走进公式
  • div嵌套影响网站收录建设公司需要网站吗
  • VBA技术资料MF383:处理Excel中存储为文本的数据
  • 注册网站的公司名字网站项目建设流程图
  • 大数据存储组件分别位于数据仓库的哪一层
  • Dubbo应用开发之RPC直连开发
  • 坦电容做电源滤波,放在陶瓷电容的前面还是后面好
  • 北京城建亚泰建设集团有限公司网站首页wordpress中文教程 下载
  • 虚幻引擎5 GAS开发俯视角RPG游戏 P06-13 属性菜单 - 边框值
  • Bash 括号:()、{}、[]、$()、$(() )、${}、[[]] 到底有什么区别?
  • bash执行脚本 CondaError: Run ‘conda init‘ before ‘conda activate‘