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

《算法通关之路》chapter17一些通用解题模板

《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。

1 二分法

1.1 普通二分法

# 查找nums数组中元素值为target的下标。如果不存在,则返回-1def bs(nums: list[int], target: int) -> int :l, h = 0, len(nums) - 1while l <= h:mid = l + (h - l) // 2if nums[mid] == target:return midelif nums[mid] < target:l = mid + 1else:h = mid - 1return -1nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
nums[bs(nums, 8)]
8

1.2 二分法变种

有些二分法类型的题目,在二分时无法直接判断中间元素是否为目标元素,这类问题被称作二分法变种问题。

例如:在有序数组里面查找第1个大于或等于5的元素,每次判断中间元素时,无法直接断定这个元素是否是第1个大于或等于5的元素,它可能是第2个或第3个大于或等于5的元素。

二分法变种问题大致分为两种情况:

  • 查找第一个满足条件的元素
  • 查找最后一个满足条件的元素

此外需要注意边界问题,这是二分法变种问题最容易出错的地方

# 查找第1个大于等于x的元素
# 左边界更新为l = mid + 1,不会产生死循环,当剩下1个元素时跳出即可def bs(nums: list[int], target: int) -> int :l, h = 0, len(nums) - 1while l <= h:mid = l + (h - l) // 2if l == h: # 边界条件breakelif nums[mid] < target:l = mid + 1else:h = midreturn lnums = [1, 2, 3, 4, 5, 6, 7, 9, 10]
nums[bs(nums, 8)]
9
# 查找最后1个小于等于x的元素
# 左边界更新为l = mid,会产生死循环,当剩下2个元素时跳出即可def bs(nums: list[int], target: int) -> int :l, h = 0, len(nums) - 1while l <= h:mid = l + (h - l) // 2if l == h or l + 1 == h: # 边界条件breakelif nums[mid] <= target:l = midelse:h = mid - 1return nums[h] if nums[h] <= target else nums[l]nums = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11]
nums[bs(nums, 8)]
10

2 回溯法

回溯法的本质是回溯思想,通常使用递归实现。
递归的实现需要考虑3个方面:搜索的设计递归的状态递归的结束条件

搜索的设计
对求解空间进行划分,让每一层递归都去尝试搜索一部分解空间,直至搜索完所有可能的解空间。

递归的状态
状态是用来区分不同递归的,一般来说,我们至少携带一种状态-当前位置idx,它用于找到当前可以继续前进的搜索空间,以此进入下一层递归。

递归的结束状态
通常包括两个方面:找到可行解,提前结束搜索;搜索完毕,已经没有搜索的解空间。

# ------
ans = []
target = 0
n = 0
nums = []
error = 0
visited = set()
# ------# idx表示当前位置,cur表示当前路径的某个信息,path表示路径
def dfs(idx, cur, path):# -------------结束条件# 1 找到解if cur == target:ans.append(path.copy())return# 2 搜索完毕if idx == n:return# --------------------# 考虑可能的解,进入下一层递归for num in nums:if num == error or num in visited:continue# 更新状态visited.add(num)dfs(idx + 1, cur + num, path + [num])# 恢复状态visited.remove(num)

3 并查集

使用parent数组记录每个节点的父节点,在初始情况下每个节点的父结点为本身,并使用rank记录每个节点为根的树的权值(树的节点数)。

  • find§:当parent[p]不为p时,表示存在非本身的父节点,此时让p等于parent[p],即向上寻找祖先节点,不断寻找祖先节点,不断重复这个过程直到parnet[p]等于p。
  • union(p, q):通过find(p,q)找到p和q的共同祖先节点,然后将权值小的祖先节点树合并到较高的树中。理论证明,这种算法能够保证合并后的树高度为O(logn)。

可以使用find§ == find(q)来判断两个节点是否属于同一个祖先。

class UnionFind:'''加权快速合并'''def __init__(self, n: int) -> None:self.parent = [i for i in range(n)] # 每个节点的父节点self.rank = [0 for _ in range(n)] # 以该节点为根的树权值(树的节点数)self.cnt = n # 连通区域数量def find(self, p: int) -> int: while p != self.parent[p]:p = self.parent[p]return pdef union(self, p: int, q: int) -> None: # 按秩合并root_p, root_q = self.find(p), self.find(q)if root_p == root_q:returnif self.rank[root_p] > self.rank[root_q]:self.parent[root_q] = root_pelif self.rank[root_p] < self.rank[root_q]:self.parent[root_p] = root_qelse:self.parent[root_q] = root_pself.rank[root_p] += 1self.cnt -= 1
class UnionFind:'''路径压缩加权快速合并'''def __init__(self, n: int) -> None:self.parent = [i for i in range(n)] # 每个节点的父节点self.rank = [0 for _ in range(n)] # 以该节点为根的树权值(树的节点数)self.cnt = n # 连通区域数量def find(self, p: int) -> int:  # 路径压缩if p != self.parent[p]:self.parent[p] = self.find(self.parent[p])return self.parent[p]def union(self, p: int, q: int) -> None: # # 按秩合并root_p, root_q = self.find(p), self.find(q)if root_p == root_q:returnif self.rank[root_p] > self.rank[root_q]:self.parent[root_q] = root_pelif self.rank[root_p] < self.rank[root_q]:self.parent[root_p] = root_qelse:self.parent[root_q] = root_pself.rank[root_p] += 1self.cnt -= 1

4 BFS

基于队列的广度优先遍历,将起始节点放入队列中,循环遍历队列中的节点。扩展节点相邻的有效节点,并将其放入队列中。

from collections import dequegrid = [0 * 5 for _ in range(5)] # n * m的矩阵def bfs(grid):m, n = len(grid), len(grid[0])directions = [(0, 1), (0, -1), (-1, 0), (1, 0)] # 扩展方向visited = [[False] * n for _ in range(m)] # 记录节点是否被访问queue = deque()level = 0 # 深度queue.append((0, 0))visited[0][0] = Truewhile len(queue) > 0:sz = len(queue)for _ in range(sz):top = queue.popleft()x, y = top# 扩展节点for d in directions:next_x, next_y = x + d[0], y + d[1]# 判断相邻节点是否有效if next_x < 0 or next_x >= m or next_y < 0 or next_y >= n:continuequeue.append((next_x, next_y))visited[next_x][next_y] = Truelevel += 1return level

5 滑动窗口

借助双指针表示窗口的左边界和右边界,并非根据题目要求不断移动指针。

根据窗口大小是否固定,以及最优解为最大或最小窗口,可以将滑动窗口分为3种类型。

5.1 窗口大小固定,最优解与窗口大小无关

nums = [] # 题目给定数组
cnt = {x : 0 for x in nums} #字典记录出现次数
ans = 0 # 答案
init_len = 0 # 窗口大小def check(cnt): # 题目所述条件passdef get(left, right): # 题目要求的答案pass# 初始化大小为init_len的窗口
for i in range(init_len):num = nums[i]cnt[num] += 1left, right = 0, init_len# 检查是否满足题目要求
if check(cnt):ans = get(left, right)while right < len(nums):num, num2 = nums[left], nums[right]cnt[num] -= 1cnt[num2] += 1# 检查是否满足题目要求if check(cnt):# 优化答案ans = max(ans, get(left, right))left += 1right += 1

5.2 窗口大小不固定,最优解为最小窗口

初始化大小为0的滑动窗口;然后循环移动窗口直到抵达边界,每次右指针right向右移动一步,并检查窗口是否满足条件,如果是,则循环向右移动左指针left,每移动一步,不断尝试缩小窗口直到窗口不满足条件,更新最优解。

left, right = 0, 0
nums = [] # 题目给定数组
cnt = {x : 0 for x in nums} #字典记录出现次数
ans = len(nums) # 初始值while right < len(nums):cnt[nums[right]] += 1# 满足题目要求,尽可能缩小窗口while left <= right and check(cnt):# 优化答案ans = min(ans, right - left + 1)# 尝试缩小窗口cnt[nums[left]] -= 1left += 1right += 1

5.3 窗口大小不固定,最优解为最大窗口

初始化大小为0的滑动窗口;然后循环移动窗口直到抵达边界,每次右指针right向右移动一步,并检查窗口是否不满足条件,如果是,则循环向右移动左指针left,每移动一步直到满足条件,更新最优解。

left, right = 0, 0
nums = [] # 题目给定数组
cnt = {x : 0 for x in nums} #字典记录出现次数
ans = 0 # 初始值while right < len(nums):cnt[nums[right]] += 1# 不满足题目要求,需要缩小窗口while not check(cnt):cnt[nums[left]] -= 1left += 1ans = max(ans, right - left + 1)right += 1

6 数学

6.1 判断素数

def isPrime(n: int) -> bool:if n <= 1:return Falsei = 2while i * i <= n:if n % i == 0:return Falsei += 1return TrueisPrime(121)
False

6.2 最大公约数

欧几里得算法: 两个整数的最大公约数等于其中较小的那个数两数相除余数的最大公约数。

def gcd(a: int, b: int) -> int:return a if b == 0 else gcd(b, a % b)

6.3 最小公倍数

两个数的乘积等于这两个数最大公约数和最小公倍数的乘积,最小公倍数 = 两数乘积 / 两数最大公约数

def lcm(a, int, b: int) -> int:return a * b // gcd(a, b)

相关文章:

《算法通关之路》chapter17一些通用解题模板

《算法通关之路》学习笔记&#xff0c;记录一下自己的刷题过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 1 二分法 1.1 普通二分法 # 查找nums数组中元素值为target的下标。如果不存在&#xff0c;则返回-1def bs(nums: list[int], target: int) -> int :l, h …...

常用求解器安装

1 建模语言pyomo Pyomo是一个Python建模语言&#xff0c;用于数学优化建模。它可以与不同的求解器&#xff08;如Gurobi&#xff0c;CPLEX&#xff0c;GLPK&#xff0c;SCIP等&#xff09;集成使用&#xff0c;以求解各种数学优化问题。可以使用Pyomo建立数学优化模型&#xf…...

第三章:最新版零基础学习 PYTHON 教程(第一节 - Python 运算符)

在Python编程中,运算符一般用于对值和变量进行操作。这些是用于逻辑和算术运算的标准符号。在本文中,我们将研究不同类型的Python 运算符。 运算符:这些是特殊符号。例如- + 、 * 、 / 等。操作数:它是应用运算符的值。目录 Python 中的运算符类型 Python 中的算术运算符…...

细粒度特征提取和定位用于目标检测:PPCNN

1、简介 近年来&#xff0c;深度卷积神经网络在计算机视觉上取得了优异的性能。深度卷积神经网络以精确地分类目标信息而闻名&#xff0c;并采用了简单的卷积体系结构来降低图层的复杂性。基于深度卷积神经网络概念设计的VGG网络。VGGNet在对大规模图像进行分类方面取得了巨大…...

【STM32单片机】数学自动出题器设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用按键、IIC OLED模块等。 主要功能&#xff1a; 系统运行后&#xff0c;OLED液晶显示出题器开机界面&#xff0c;默认结果范围为100&#xff0c;可按…...

C语言之动态内存管理篇(1)

目录 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 今天收假了&#xff0c;抓紧时间写几篇博客。我又来赶进度了。今天我们来讲解动态内存管理。&#x1f197;&#x1f197; 为什么存在动态内存分配 假设我们去实现一个…...

React18入门(第二篇)——React18+Ts项目配置husky、eslint、pretttier、commitLint

前言 我的项目版本如下&#xff1a; React&#xff1a; V18.2.0Node.js: V16.14.0TypeScript&#xff1a;最新版工具&#xff1a; VsCode 本文将采用图文详解的方式&#xff0c;手把手带你快速完成在React项目中配置husky、prettier、commitLint&#xff0c;实现编码规范的统…...

【VINS】苹果手机采集单目相机+IMU数据离线运行VINS-Mono

0.准备工作 开个新坑&#xff0c;之前用Android手机做过离线采集数据的实验&#xff0c;这次用IPhone来测试&#xff01; 1.虚拟机配置Mac OS 下载一个Mac OS 的ios镜像&#xff0c;打开虚拟机按照跟Ubuntu差不多的方式安装&#xff0c;但是发现没有Mac OS的入口。 因为VMwa…...

数据结构 2.1 单链表

1.单链表 线性表&#xff1a;1.有限的序列 2.序列中的每一个元素都有唯一的前驱和后继&#xff0c;除了开头和结尾的两个节点。 顺序表&#xff1a;分配一块连续的内存去存放这些元素&#xff0c;eg、数组 链表&#xff1a;内存是不连续的&#xff0c;元素会各自被分配一块内…...

[Machine Learning]pytorch手搓一个神经网络模型

因为之前虽然写过一点点关于pytorch的东西&#xff0c;但是用的还是他太少了。 这次从头开始&#xff0c;尝试着搓出一个神经网络模型 &#xff08;因为没有什么训练数据&#xff0c;所以最后的训练部分使用可能不太好跑起来的代码作为演示&#xff0c;如果有需要自己连上数据…...

KdMapper扩展实现之Dell(pcdsrvc_x64.pkms)

1.背景 KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动&#xff0c;本文是利用其它漏洞&#xff08;参考《【转载】利用签名驱动漏洞加载未签名驱动》&#xff09;做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称pcds…...

python和go相互调用的两种方法

前言 Python 和 Go 语言是两种不同的编程语言&#xff0c;它们分别有自己的优势和适用场景。在一些项目中&#xff0c;由于团队内已有的技术栈或者某一部分业务的需求&#xff0c;可能需要 Python 和 Go 相互调用,以此来提升效率和性能。 性能优势 Go 通常比 Python 更高效&…...

c# 分部视图笔记

Html.Partial("**", 1) public ActionResult **(int page) { ViewBag.page page; return PartialView("**"); }...

Vue3最佳实践 第七章 TypeScript 中

Vue组件中TypeScript 在Vue组件中&#xff0c;我们可以使用TypeScript进行各种类型的设置&#xff0c;包括props、Reactive和ref等。下面&#xff0c;让我们详细地探讨一下这些设置。 设置描述设置props在Vue中&#xff0c;props本身就具有类型设定的功能。但如果你希望使用Ty…...

(三)行为模式:8、状态模式(State Pattern)(C++示例)

目录 1、状态模式&#xff08;State Pattern&#xff09;含义 2、状态模式的UML图学习 3、状态模式的应用场景 4、状态模式的优缺点 &#xff08;1&#xff09;优点 &#xff08;2&#xff09;缺点 5、C实现状态模式的实例 1、状态模式&#xff08;State Pattern&#x…...

nginx的配置文件概述及简单demo(二)

默认配置文件 当安装完nginx后&#xff0c;它的目录下通常有默认的配置文件 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connection…...

Apollo Planning2.0决策规划算法代码详细解析 (2): vscode gdb单步调试环境搭建

前言: apollo planning2.0 在新版本中在降低学习和二次开发成本上进行了一些重要的优化,重要的优化有接口优化、task插件化、配置参数改造等。 GNU symbolic debugger,简称「GDB 调试器」,是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端…...

flex 布局:元素/文字靠右

前言 略 使用flex的justify-content属性控制元素的摆放位置 靠右 <view class"more">展开更多<text class"iconfont20231007 icon-zhankai"></text></view>.more {display: flex;flex-direction: row;color: #636363;justify-co…...

java基础-第1章-走进java世界

一、计算机基础知识 常用的DOS命令 二、计算机语言介绍 三、Java语言概述 四、Java环境的搭建 JDK安装图解 环境变量的配置 配置环境变量意义 配置环境变量步骤 五、第一个Java程序 编写Java源程序 编译Java源文件 运行Java程序 六、Java语言运行机制 核心机制—Java虚拟机 核…...

jvm 堆内存 栈内存 大小设置

4种方式配置不同作用域的jvm的堆栈内存。 1、Eclise 中设置jvm内存: 改动eclipse的配置文件,对全部project都起作用 改动eclipse根文件夹下的eclipse.ini文件 -vmargs //虚拟机设置 -Xms40m //初始内存 -Xmx256m //最大内存 -Xmn16m //最小内存 -XX:PermSize=128M //非堆内…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...

深入解析 ReentrantLock:原理、公平锁与非公平锁的较量

ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...