JS性能异常现象:双条件与单条件判断的性能差异
LeetCode两数之和解法性能差异解析
问题背景
给定整数数组nums和整数target,需返回两个数的下标,使它们的和等于target。已知输入必有唯一解,且不能使用同一元素两次。我写出两种解法:
- 解法一判断条件:
nums.includes(remaining) && nums.lastIndexOf(remaining) > index - 解法二仅保留:
nums.lastIndexOf(remaining) > index
实际运行时,解法一耗时130140ms,解法二却需要240250ms,想搞清楚这一差异的原因。
解法一代码
const twoSum = function(nums, target) { let solution = [] nums.forEach((number, index) => { if (solution.length !== 0) { return } const remaining = target - number if (nums.includes(remaining) && (nums.lastIndexOf(remaining) > index)) { solution = [index, nums.lastIndexOf(remaining)] } }) return solution };
解法二代码
const twoSum = function(nums, target) { let solution = [] nums.forEach((number, index) => { if (solution.length !== 0) { return } const remaining = target - number if (nums.lastIndexOf(remaining) > index) { solution = [index, nums.lastIndexOf(remaining)] } }) return solution };
性能差异原因
遍历逻辑的本质区别
includes从数组头部开始查找目标值,一旦找到就立即返回true,找不到则遍历完数组返回false。lastIndexOf从数组尾部开始向前查找,找到目标值返回最后出现的下标,找不到则必须遍历完整个数组才返回-1。
无效操作的过滤效率
解法一中,includes先做了前置判断:如果remaining不在数组里,直接跳过后续的lastIndexOf调用。而解法二中,无论remaining是否存在,每一轮循环都会执行lastIndexOf——哪怕最终结果是-1,这意味着大量无意义的全数组遍历,直接拉高了整体耗时。重复调用的额外开销
两种解法中,找到符合条件的remaining时都会调用两次lastIndexOf(一次判断、一次赋值),但解法一通过includes提前过滤了绝大多数不需要执行lastIndexOf的场景,而解法二在每一轮循环都要执行至少一次lastIndexOf,累积下来的耗时差被进一步放大。
额外优化建议
可以通过缓存lastIndexOf的结果,避免重复调用,进一步提升性能:
const twoSum = function(nums, target) { let solution = [] nums.forEach((number, index) => { if (solution.length !== 0) { return } const remaining = target - number const lastIdx = nums.lastIndexOf(remaining) if (lastIdx > index) { solution = [index, lastIdx] } }) return solution };
内容的提问来源于stack exchange,提问作者Fox
相关产品推荐
相关产品推荐

