
本文详解 php 实现「检查数组中是否存在两数满足一数是另一数的两倍」的常见逻辑错误与优化方案,重点剖析双重循环中索引初始化与边界处理的关键陷阱,并提供时间复杂度更优的哈希表解法。
本文详解 php 实现「检查数组中是否存在两数满足一数是另一数的两倍」的常见逻辑错误与优化方案,重点剖析双重循环中索引初始化与边界处理的关键陷阱,并提供时间复杂度更优的哈希表解法。
你在 LeetCode 题目 1346. Check If N and M Exist(即判断数组中是否存在两个不同下标的元素 arr[i] 和 arr[j],使得 arr[j] == 2 * arr[i])中使用的双重循环解法存在两个关键逻辑缺陷,导致测试用例失败:
❌ 原代码的主要问题
内层循环变量未重置
原始代码中$j = 0仅在最外层初始化一次,而内层for($j; $j 在第一次外层迭代后,$j已增至$n,后续所有外层循环中该for循环根本不会执行(因$j初始值已是$n,不满足$j )。这导致仅检查了i=0时的所有j,其余i > 0的情况全部被跳过。内层循环范围不合理(虽非主因,但影响效率与逻辑清晰性)
即使修复$j重置问题,若仍让$j从0开始遍历(如for($j = 0; ...)),会重复检查已比对过的下标对(如(i=1,j=0)与(i=0,j=1)本质相同),且i == j的判断虽存在,但属于冗余防护——更优雅的方式是直接避免自比较。
✅ 正确的双重循环实现(暴力法)
N
-
零的特殊性:
0 * 2 == 0,因此数组中只要有两个0,就满足条件(如[0, 1]不满足,但[0, 0]满足)。哈希解法中isset($seen[0])在首次遇到0时为false,存入后第二次遇到0时,isset($seen[0])为true,正确返回true。 -
负数无影响:数学关系
N == 2*M对负数完全适用(如-4 == 2 * (-2))。 -
整数除法陷阱:PHP 中
$num / 2对奇数会得浮点数(如3/2 → 1.5),但isset($seen[1.5])会自动类型转换为字符串键或整数键?实际测试表明:$seen[1.5]与$seen[1]是不同键。因此更严谨的做法是只检查2*$num(整数),并预先检查$num % 2 == 0 ? $num/2 : null。但 LeetCode 测试用例均为整数输入,且官方题解普遍采用/2判断,故实践中可接受。
✅ 总结
你的原始代码失败主因是内层循环变量 $j 未在每次外层迭代中重置,导致逻辑短路。修正后暴力法可行,但推荐掌握哈希集合解法——它不仅效率更高,也更能体现算法思维。在刷题初期,理解循环变量作用域与生命周期,是避开“看似正确实则失效” bug 的关键一步。










