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

算法题避坑指南:数组/循环范围的 `+1` 到底什么时候加?

在算法题的刷题过程中,你是否遇到过这样的场景:

  • 动态规划数组明明逻辑对了,却总是报IndexError: list index out of range
  • 循环遍历字符串/数组时,要么漏掉最后一个元素,要么多走一步?
  • 调试了半小时,最后发现只是少写了一个+1

如果这些问题你都遇到过,那么这篇博客就是为你准备的。我们将从核心原则常见场景实战步骤三个维度,彻底讲透算法题中数组/循环范围的+1判断逻辑,帮你避开90%的维度错误。


一、核心判断原则(先记住这句话)

判断是否需要+1,本质是看你的“计数/状态定义”是否包含“边界情况”,主要分为两种核心场景:

场景类型判断依据是否需要+1
空状态型状态变量表示“前i个元素/字符”(包含i=0,即“空”的情况)✅ 必须+1
左闭右开型循环/切片遵循“左闭右开”规则(如 Python 的range、列表切片),需要覆盖到最后一个元素✅ 必须+1

接下来我们逐个场景拆解,结合经典算法题和代码对比,让你彻底理解。


二、场景一:空状态型+1(动态规划重灾区)

这是算法题中最常见的+1场景,90%的字符串/数组类动态规划题都需要它,核心原因是:动态规划的“初始状态”通常是“空”

1. 什么是“空状态”?

假设我们定义状态dp[i][j]

  • 如果i表示“s的第i个字符”(索引从0开始),那么i的范围是0~m-1,没有“空字符串”的概念;
  • 如果i表示“s的前i个字符”,那么i的范围是0~m,其中i=0对应“前0个字符”(即空字符串),这就是“空状态”。

动态规划几乎都用“前i个”的定义,因为“空状态”是推导后续状态的基础(比如空字符串匹配空正则、空字符串转换成另一个空字符串的编辑距离为0)。

2. 经典例子1:正则表达式匹配(LeetCode 10)

状态定义

dp[i][j]:表示s的前i个字符和p的前j个字符是否匹配。

  • i的取值:0,1,2,...,mms的长度,i=0对应空s
  • j的取值:0,1,2,...,nnp的长度,j=0对应空p
数组维度判断
  • im+1个取值,jn+1个取值;
  • 所以dp数组的维度必须是(m+1) × (n+1)
错误 vs 正确代码对比
# 错误代码:少了 +1,无法处理空状态,会报索引越界m,n=len(s),len(p)dp=[[False]*nfor_inrange(m)]# 维度是 m×n,没有 i=0/j=0dp[0][0]=True# 直接报错:索引超出范围# 正确代码:维度 +1,覆盖空状态m,n=len(s),len(p)dp=[[False]*(n+1)for_inrange(m+1)]# 维度是 (m+1)×(n+1)dp[0][0]=True# 空字符串匹配空正则,正确初始化

3. 经典例子2:编辑距离(LeetCode 72)

状态定义

dp[i][j]:表示将s的前i个字符转换成p的前j个字符所需的最小操作数。

  • i=0:空s转换成p的前j个字符,需要j次插入操作;
  • j=0s的前i个字符转换成空p,需要i次删除操作。
数组维度

同样需要(m+1) × (n+1),否则无法初始化i=0j=0的边界情况。

4. 空状态型+1的判断步骤

遇到动态规划题,按这3步走:

  1. 明确状态定义:你的i/j是“前i个”还是“第i个”?
    → 优先用“前i个”,因为方便处理空状态;
  2. 确定取值范围i需要从 0 到m吗?
    → 如果需要(通常都需要),则取值个数是m+1
  3. 推导数组维度:数组长度 = 取值个数 →m+1

三、场景二:左闭右开型+1(循环/切片常见坑)

这种场景和动态规划无关,而是由编程语言的语法规则决定的——Python、Java等语言的循环、切片通常遵循“左闭右开”原则(即包含起始索引,不包含结束索引)。

1. 什么是“左闭右开”?

以 Python 为例:

  • range(a, b):生成的整数是a, a+1, ..., b-1不包含b
  • s[a:b]:取字符串s的第a到第b-1个字符,不包含b

如果我们需要覆盖到最后一个元素,就必须在结束索引上+1

2. 经典例子1:统计 1~n 的和

需求

计算从 1 到 n(包含 n)的所有整数的和。

错误 vs 正确代码对比
n=10# 错误代码:range(1, n) 只到 9,漏掉了 10sum_wrong=0foriinrange(1,n):sum_wrong+=iprint(sum_wrong)# 输出 45,错误(正确结果是 55)# 正确代码:range(1, n+1) 包含 10sum_correct=0foriinrange(1,n+1):sum_correct+=iprint(sum_correct)# 输出 55,正确

3. 经典例子2:遍历字符串的所有字符

需求

遍历字符串s的每一个字符并打印。

错误 vs 正确代码对比
s="abc"# 错误代码:range(len(s)-1) 只到 1,漏掉了最后一个字符 'c'print("错误遍历:")foriinrange(len(s)-1):print(s[i])# 只打印 'a' 和 'b'# 正确代码1:range(len(s)) 到 len(s)-1,刚好覆盖所有字符print("正确遍历1:")foriinrange(len(s)):print(s[i])# 打印 'a'、'b'、'c'# 正确代码2:如果需要遍历“前 i 个字符”(i 从 1 到 len(s)),则需要 +1print("正确遍历2(前 i 个字符):")foriinrange(1,len(s)+1):print(s[:i])# 打印 'a'、'ab'、'abc'

4. 左闭右开型+1的判断步骤

遇到循环/切片时,按这2步走:

  1. 明确你的目标范围:你需要包含的最后一个索引/值是什么?
    → 比如统计 1~n,最后一个值是 n;
  2. 调整结束索引:因为左闭右开,结束索引 = 目标最后一个值 + 1。

四、新手避坑:两种+1的混淆与区分

很多新手会把“空状态型+1”和“左闭右开型+1”搞混,我们用一个表格清晰区分:

维度空状态型+1左闭右开型+1
原因状态定义包含“前0个”(空)语法规则是左闭右开
常见场景动态规划(正则匹配、编辑距离、LCS)循环(range)、切片(s[:]
例子dp = [[False]*(n+1) for _ in range(m+1)]range(1, n+1)
+1的后果索引越界、无法初始化空状态漏掉最后一个元素

五、实战演练:用判断步骤解决一道题

我们以**最长公共子序列(LeetCode 1143)**为例,完整走一遍判断流程:

题目

给定两个字符串text1text2,返回它们的最长公共子序列的长度。

步骤1:明确状态定义

dp[i][j]:表示text1的前i个字符和text2的前j个字符的最长公共子序列长度。
→ 用“前i个”,需要包含i=0/j=0(空字符串的最长公共子序列长度为0)。

步骤2:确定取值范围

  • i的取值:0,1,2,...,mmtext1的长度)
  • j的取值:0,1,2,...,nntext2的长度)
    → 取值个数分别是m+1n+1

步骤3:推导数组维度

dp数组的维度是(m+1) × (n+1)

步骤4:循环范围(左闭右开型)

  • i需要从 0 到m,所以range(m+1)
  • j需要从 0 到n,所以range(n+1)

最终代码框架

deflongestCommonSubsequence(text1:str,text2:str)->int:m,n=len(text1),len(text2)# 空状态型 +1:数组维度 (m+1)×(n+1)dp=[[0]*(n+1)for_inrange(m+1)]# 左闭右开型 +1:range(m+1) 覆盖 0~mforiinrange(1,m+1):forjinrange(1,n+1):iftext1[i-1]==text2[j-1]:dp[i][j]=dp[i-1][j-1]+1else:dp[i][j]=max(dp[i-1][j],dp[i][j-1])returndp[m][n]

六、总结:记住这两点,再也不踩+1的坑

  1. 动态规划优先想“空状态”:如果状态是“前i个”,数组维度必须+1
  2. 循环/切片注意“左闭右开”:如果要包含最后一个元素,结束索引必须+1

算法题中的+1看似是小细节,实则是逻辑严谨性的体现。只要你在写代码前多花10秒钟,按我们的步骤判断一下状态定义和目标范围,就能轻松避开这个高频坑。

http://www.jsqmd.com/news/405800/

相关文章:

  • Neo4j学习笔记1
  • upload
  • 2026年生产力革命:实测上百款AI工具后,这5款真正重塑了我的工作流
  • 别再手动重复工作了!Skills技术让AI自动执行你的任务,收藏这篇就够了
  • AI记忆革命!MemOS开源框架实战:基于Graph的记忆图谱如何赋能LangChain智能体
  • 状压DP之棋盘放置类
  • 收藏级干货:10种AI产品形态全解析,2026年AI产品经理必备指南
  • JAVA WEB学习5
  • AI Agent开发者必看!三大推理框架深度解析与落地选型指南(收藏版)
  • 揭秘AI Agent:一个循环搞定所有任务,技术人必备,建议收藏反复阅读
  • 【必看收藏】企业AI Agent频频失败?90%的人都忽略了这一关键“语义层“构建技巧
  • 【GitHub项目推荐--Planning with Files:基于Manus AI工作流的智能任务管理革命】⭐⭐⭐⭐⭐
  • 微服务架构:Python 开发者的实践指南
  • 简单,但不显然
  • 在AI时代如何高效学习
  • 施耐德citect f(x)功能初试
  • VS Code/Antigravity Remote SSH 连接要求输入密码?明明已经配了 SSH 密钥
  • 2026年上海别墅防水公司推荐榜:三大知名品牌公司实力解析与选择指南 - shruisheng
  • 上海别墅防水哪家好?2026企业推荐及选择指南,口碑实力 + 案例分享 + 避坑推荐 - shruisheng
  • 2月23日鲜花
  • Java面试实战:从Spring Boot入门到微服务架构
  • 2026 AI 论文生成软件封神合集(省时 80%+,查重稳过)
  • 零基础自学网安必藏!6个干货网站,从入门到精通全搞定
  • 谁说网安只是修防火墙?他们才是数字世界的守护者
  • 基于安卓的智能垃圾分类助手系统
  • 2026计算机卷到窒息,普通毕业生别硬刚!这个缺口炸了的行业,现在上车刚刚好
  • 2026 最新|计算机大学生 CTF 参赛实战指南:入门路径 + 冲奖策略 + 分阶段时间规划_
  • GEO兴起:AI时代品牌必争的营销新阵地
  • GPU算力出租兴起,低成本破解AI算力困局
  • 门店系统怎么选?多维度测评帮你找对数字管家