[python刷题模板] LogTrick

[python刷题模板] LogTrick

    • 一、 算法&数据结构
      • 1. 描述
      • 2. 复杂度分析
      • 3. 常见应用
      • 4. 常用优化
    • 二、 模板代码
      • 1. 特定或值的最短子数组
      • 2. 找特定值
      • 3. 找位置j的最后一次被谁更新
      • 4. 问某个或和的数量
    • 三、其他
    • 四、更多例题
    • 五、参考链接

一、 算法&数据结构

1. 描述

LogTrick可以用来计算子段区间的可重复贡献问题(即op(x,x) = x, 通常就是指ior、iand、gcd)信息。
通常会关注整个数组的信息,而不仅仅是某一个位置上的答案。
下文描述以或和为例。
# 	模板1
def log_trick_vs(nums: List[int], op=and_):"""获取nums的所有子段的'与值',返回所有值,共nlogU个。由于不计算个数,不需要计算左右边界,因此常数低,快1/3左右---注意会直接修改原数组,可酌情拷贝使用-----"""res = set()for i, v in enumerate(nums):res.add(v)  # 在这行做你想做的事for j in range(i - 1, -1, -1):if op(nums[j], v) == nums[j]: breaknums[j] = op(nums[j], v)res.add(nums[j])  # 在这行做你想做的事return res
  • 解释上述代码:
  1. 向右遍历nums到i时,更新前边访问过的位置j,在j上储存的信息为nums[j]=op(j…i),发现这个信息是从i-1层转移过来的,因此可以递推。
  2. 当遇到op(nums[j], v) == nums[j]时,即无法使op(j…i)超过op(j…i-1)时,可以退出,继续向前也无法更新nums[j]了。证明,以或运算为例:
    1. 由于离i越远,或和越大,可以证明左边的数字一定大于等于右边,且一定包含右边,即nums[i]∈nums[i-1]。
    2. 若nums[i]|v==nums[i],证明nums[i]一定包含了v,那么nums[i-1]肯定也包含了v。即v∈nums[i]∈nums[i-1]。
  3. 同时由于j是从i向左遍历的,可以发现这样可以完整无遗漏的遍历到所有以i为右端点的子段的或和所有可能值的右半部分。而左半部分由于i无法更新到,会有i-1、i-2…或其他更新到。
# 模板2
def log_trick_v_cnt(nums: List[int], op=and_):"""获取nums的所有子段'与值',返回所有值的个数,共nlogU个。时间复杂度O(nlogU)"""res = defaultdict(int)dp = []  # 顺序储存 [左边界,右边界),值for pos, cur in enumerate(nums):for v in dp:v[2] = op(v[2], cur)dp.append([pos, pos + 1, cur])ptr = 0for v in dp[1:]:  # 双指针向前合并去重if dp[ptr][2] != v[2]:ptr += 1dp[ptr] = velse:dp[ptr][1] = v[1]# dp = dp[: ptr + 1]del dp[ptr + 1:]for l, r, v in dp:res[v] += r - lreturn res
  • 这是另一种写法,显式创建了每一层的dp数组,并记录了左右边界。
  • 由于每一层只有logU种可能性,且是单调的,用了双指针的技巧维护扩缩容。

2. 复杂度分析

  1. 时间复杂度整体O(nlog2U);gcd的话再多一个gcd的log。证明:
    分析每个i向前能走多远比较困难,我们分析Nums[j],每个数字被更新多少次。
    由于每个位置被更新时一定会变大,或这个动作会保证数字变大时,至少会多一个位置的0变成1。因此每个数字至多变大log(U)次
  2. 空间复杂度:如果要存所有子段或和,那共有O(nlogU)个;否则通常可以复用nums原数组,则额外空间只需要O(1)

3. 常见应用

  1. (找值)枚举所有区间子段的or、and、gcd,找最大、最小、最近值等。
  2. (找段)以每个位置i为右(左)端点,不同子段与的左端点起止位置,以此也可以计算子段数量。

4. 常用优化

  1. 如果只关心值信息本身,那么可以复用nums数组,原地修改,效率极高。
  2. 找段时,可以用字典储存每个信息对应的段首尾,显式储存以当前位置为结尾的或和这个dp数组。
  3. 更新过程中,截止当前位置的左边数字是单调的,可以二分。

二、 模板代码

1. 特定或值的最短子数组

例题: 3097. 或值至少为 K 的最短子数组 II

  • 题目要求子段的或值至少为k,直接套模板,当判断超过k时,i-j+1就可以更新以i为右端点的答案。
class Solution:def minimumSubarrayLength(self, nums: List[int], k: int) -> int:ans = inf for i, v in enumerate(nums):if v >= k:return 1 for j in range(i-1,-1,-1):if (nums[j]|v) >= k:ans = min(ans, i-j+1)if (nums[j]|v) == nums[j]:break nums[j] |= v return ans if ans < inf else -1

2. 找特定值

链接: 3171. 找到按位或最接近 K 的子数组

  • 本地直接问所有或值中最接近k的是几,那么贴模板,把所有值遍历一次就行
class Solution:def minimumDifference(self, nums: List[int], k: int) -> int:ans = inffor i, x in enumerate(nums):ans = min(ans, abs(x - k))for j in range(i - 1, -1, -1):if nums[j] | x == nums[j]:breaknums[j] |= xans = min(ans, abs(nums[j] - k))return ans

3. 找位置j的最后一次被谁更新

链接: 2411. 按位或最大的最小子数组长度

  • 题目问以每个i为左端点,向右达到最大或的位置。
  • 考虑logTrick时间复杂度的证明:每个nums[j]只会被变大logU次
class Solution:def smallestSubarrays(self, nums: List[int]) -> List[int]:n = len(nums) ans = [1]*nfor i, v in enumerate(nums):for j in range(i-1,-1,-1):             if nums[j] | v == nums[j]:break nums[j] |= v ans[j] = i-j+1           return ans

4. 问某个或和的数量

链接: [3209. 子数组按位与值为 K 的数目]https://leetcode.cn/problems/number-of-subarrays-with-and-value-of-k/description/)

  • 贴模板2
def log_trick_v_cnt(nums: List[int], op=and_):res = defaultdict(int)dp = []  # 顺序储存 [左边界,右边界),值for pos, cur in enumerate(nums):for v in dp:v[2] = op(v[2], cur)dp.append([pos, pos + 1, cur])ptr = 0for v in dp[1:]:  # 双指针向前合并去重if dp[ptr][2] != v[2]:ptr += 1dp[ptr] = velse:dp[ptr][1] = v[1]# dp = dp[: ptr + 1]del dp[ptr + 1:]  # little fasterfor l, r, v in dp:res[v] += r - lreturn res
class Solution:def countSubarrays(self, nums: List[int], k: int) -> int:res = log_trick_v_cnt(nums)return res[k]

三、其他

  1. 之所以算trick,这个做法其实不太通用,应对的场景比较局限。
  2. 当固定某个端点时,向一侧的子段值是单调的,因此以上所有题目都可以用st表+二分解决。如果觉得logTrick不好理解,可以先尝试本方法解决以上问题。

四、更多例题

  • 2447. 最大公因数等于 K 的子数组数目

五、参考链接

  • 链接: 灵神的位运算题单

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93416.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93416.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vim与VS Code

Vim is a clone, with additions, of Bill Joys vi text editor program for Unix. It was written by Bram Moolenaar based on source for a port of the Stevie editor to the Amiga and first released publicly in 1991.其实这个本身不是 IDE &#xff08;只有在加入和配置…

[2025CVPR-图象分类方向]CATANet:用于轻量级图像超分辨率的高效内容感知标记聚合

​1. 研究背景与动机​ ​问题​&#xff1a;Transformer在图像超分辨率&#xff08;SR&#xff09;中计算复杂度随空间分辨率呈二次增长&#xff0c;现有方法&#xff08;如局部窗口、轴向条纹&#xff09;因内容无关性无法有效捕获长距离依赖。​现有局限​&#xff1a; SPI…

课题学习笔记3——SBERT

1 引言在构建基于知识库的问答系统时&#xff0c;"语义匹配" 是核心难题 —— 如何让系统准确识别 "表述不同但含义相同" 的问题&#xff1f;比如用户问 "对亲人的期待是不是欲&#xff1f;"&#xff0c;系统能匹配到知识库中 "追名逐利是欲…

在Word和WPS文字中把全角数字全部改为半角

大部分情况下我们在Word或WPS文字中使用的数字或标点符号都是半角&#xff0c;但是有时不小心按错了快捷键或者点到了输入法的全角半角切换图标&#xff0c;就输入了全角符号和数字。不用担心&#xff0c;使用它们自带的全角、半角转换功能即可快速全部转换回来。一、为什么会输…

数据结构的基本知识

一、集合框架1、什么是集合框架Java集合框架(Java Collection Framework),又被称为容器(container),是定义在java.util包下的一组接口(interfaces)和其实现类(classes).主要表现为把多个元素(element)放在一个单元中,用于对这些元素进行快速、便捷的存储&#xff08;store&…

WebStack-Hugo | 一个静态响应式导航主题

WebStack-Hugo | 一个静态响应式导航主题 #10 shenweiyan announced in 1.3-折腾 WebStack-Hugo | 一个静态响应式导航主题#10 ​编辑shenweiyan on Oct 23, 2023 6 comments 7 replies Return to top shenweiyan on Oct 23, 2023 Maintainer Via&#xff1a;我给自己…

01 基于sklearn的机械学习-机械学习的分类、sklearn的安装、sklearn数据集、数据集的划分、特征工程中特征提取与无量纲化

文章目录机械学习机械学习分类1. 监督学习2. 半监督学习3. 无监督学习4. 强化学习机械学习的项目开发步骤scikit-learn1 scikit-learn安装2 sklearn数据集1. sklearn 玩具数据集鸢尾花数据集糖尿病数据集葡萄酒数据集2. sklearn现实世界数据集20 新闻组数据集3. 数据集的划分特…

携全双工语音通话大模型亮相WAIC,Soul重塑人机互动新范式

近日&#xff0c;WAIC 2025在上海隆重开幕。作为全球人工智能领域的顶级盛会&#xff0c;本届WAIC展览聚焦底层能力的演进与具体垂类场景的融合落地。坚持“模应一体”方向、立足“AI社交”的具体场景&#xff0c;Soul App此次携最新升级的自研端到端全双工语音通话大模型亮相&…

第2章 cmd命令基础:常用基础命令(1)

Hi~ 我是李小咖&#xff0c;主要从事网络安全技术开发和研究。 本文取自《李小咖网安技术库》&#xff0c;欢迎一起交流学习&#x1fae1;&#xff1a;https://imbyter.com 本节介绍的命令有目录操作&#xff08;cd&#xff09;、清屏操作&#xff08;cls&#xff09;、设置颜色…

Java 10 新特性解析

Java 10 新特性解析 文章目录Java 10 新特性解析1. 引言2. 本地变量类型推断&#xff08;JEP 286&#xff09;2.1. 概述2.2. 使用场景2.3. 限制2.4. 与之前版本的对比2.5. 风格指南2.6. 示例代码2.7. 优点与注意事项3. 应用程序类数据共享&#xff08;JEP 310&#xff09;3.1. …

【WRF工具】服务器中安装编译GrADS

目录 安装编译 GrADS 所需的依赖库 conda下载库包 安装编译 GrADS 编译前检查依赖可用性 安装编译 GrADS 参考 安装编译 GrADS 所需的依赖库 以统一方式在 $HOME/WRFDA_LIBS/grads_deps 下安装所有依赖: # 选择一个目录用于安装所有依赖库 export DIR=$HOME/WRFDA_LIBS库包1…

数据结构之队列(C语言)

1.队列的定义&#xff1a; 队列&#xff08;Queue&#xff09;是一种基础且重要的线性数据结构&#xff0c;遵循先进先出&#xff08;FIFO&#xff09;​​ 原则&#xff0c;即最早入队的元素最先出队&#xff0c;与栈不同的是出队列的顺序是固定的。队列具有以下特点&#xff…

C#开发基础之深入理解“集合遍历时不可修改”的异常背后的设计

前言 欢迎关注【dotnet研习社】&#xff0c;今天我们聊聊一个基础问题“集合已修改&#xff1a;可能无法执行枚举操作”背后的设计。 在日常 C# 开发中&#xff0c;我们常常会操作集合&#xff08;如 List<T>、Dictionary<K,V> 等&#xff09;。一个新手开发者极…

【工具】图床完全指南:从选择到搭建的全方位解决方案

前言 在数字化内容创作的时代&#xff0c;图片已经成为博客、文档、社交媒体等平台不可或缺的元素。然而&#xff0c;如何高效、稳定地存储和分发图片资源&#xff0c;一直是内容创作者面临的重要问题。图床&#xff08;Image Hosting&#xff09;作为专门的图片存储和分发服务…

深度学习篇---PaddleDetection模型选择

PaddleDetection 是百度飞桨推出的目标检测开发套件&#xff0c;提供了丰富的模型库和工具链&#xff0c;覆盖从轻量级移动端到高性能服务器的全场景需求。以下是核心模型分类、适用场景及大小选择建议&#xff08;通俗易懂版&#xff09;&#xff1a;一、主流模型分类及适用场…

cmseasy靶机密码爆破通关教程

靶场安装1.首先我们需要下载一个cms靶场CmsEasy_7.6.3.2_UTF-8_20200422,下载后解压在phpstudy_pro的网站根目录下。2.然后我们去访问一下安装好的网站&#xff0c;然后注册和链接数据库3.不知道自己数据库密码的可以去小皮面板里面查看4.安装好后就可以了来到后台就可以了。练…

【C语言】指针深度剖析(一)

文章目录一、内存和地址1.1 内存的基本概念1.2 编址的原理二、指针变量和地址2.1 取地址操作符&#xff08;&&#xff09;2.2 指针变量和解引用操作符&#xff08;*&#xff09;2.2.1 指针变量2.2.2 指针类型的解读2.2.3 解引用操作符2.3 指针变量的大小三、指针变量类型的…

半导体企业选用的跨网文件交换系统到底应该具备什么功能?

在半导体行业的数字化转型过程中&#xff0c;跨网文件交换已成为连接研发、生产、供应链的关键纽带。半导体企业的跨网文件交换不仅涉及设计图纸、工艺参数等核心知识产权&#xff0c;还需要满足跨国协同、合规审计等复杂需求。那么&#xff0c;一款适合半导体行业的跨网文件交…

影刀RPA_初级课程_玩转影刀自动化_网页操作自动化

声明&#xff1a;相关内容来自影刀学院&#xff0c;本文章为自用笔记&#xff0c;切勿商用&#xff01;&#xff08;若有侵权&#xff0c;请联络删除&#xff09; 1. 基本概念与操作 1.1 正确处理下拉框元素&#xff08;先判断页面元素&#xff0c;后进行流程编制&#xff09;…

Spark初探:揭秘速度优势与生态融合实践

更多推荐阅读 Spark与Flink深度对比&#xff1a;大数据流批一体框架的技术选型指南-CSDN博客 LightProxy使用操作手册-CSDN博客 Sentry一看就会教程_sentry教程-CSDN博客 微前端架构解析&#xff1a;核心概念与主流方案特性对比_微前端方案对比-CSDN博客 目录 Spark为何比Hadoo…