优化删除一个元素得到严格递增序列判断代码的执行效率
问题描述
接收一个未排序数组,需要判断是否可以通过从该数组中移除恰好一个元素,使其成为严格递增序列。
判定规则:
- 序列
a0, a1, ..., an满足a0 < a1 < ... < an时即为严格递增序列 - 仅包含单个元素的序列也属于严格递增序列
示例: - 输入
[1,3,5,1,7]返回true - 输入
[1,78, 23, 42, 102]返回false
现有可正确运行的代码在传入大规模数组时执行时间超过4秒时限,已定位到性能瓶颈大概率是每次校验时使用展开运算符复制数组的操作,需要不依赖数组复制的优化实现方案。
原有实现代码
const isBigger = (a,b) => b > a; const checksSequence = function (array) { isItaSequence = true; for(let i=0; i !== array.length - 1 && isItaSequence; i++ ){ isItaSequence = isBigger(array[i],array[i+1]); } return isItaSequence } function solution(sequence) { let sequenceRemoving1 = false; for (let i = 0; i !== sequence.length && !sequenceRemoving1 ; i++){ let modifiedArray = [...sequence] modifiedArray.splice(i, 1) sequenceRemoving1 = checksSequence(modifiedArray); } return sequenceRemoving1 }
配套HTML代码(不影响核心逻辑):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="index.js"></script> </head> <body> </body> </html>
性能问题根因
原有实现时间复杂度为O(n²),数据规模大时必然超时:
- 外层循环遍历每个位置尝试删除元素,共执行n次
- 每次删除前用展开运算符全量复制数组,消耗O(n)时间
- 每次复制完成后全量遍历数组校验是否严格递增,又消耗O(n)时间
当数组长度达到1e5级别时,总操作量会达到1e10量级,远超出JS单线程4秒内可处理的操作上限。
优化方案
不需要复制数组,也不需要遍历每个位置做全量校验,仅需一次遍历即可完成判断,时间复杂度降到O(n),空间复杂度O(1):
- 遍历数组过程中记录遇到的非递增位置次数,一旦超过1次直接返回false
- 当遇到
arr[i] >= arr[i+1]的冲突位置时,只需要判断两种删除可能是否成立:- 删除位置i的元素:判断
arr[i-1] < arr[i+1]是否成立(i为0时直接成立,无左邻元素) - 删除位置i+1的元素:判断
arr[i] < arr[i+2]是否成立(i+1为末尾时直接成立,无右邻元素)
- 删除位置i的元素:判断
- 两种删除可能都不成立时,直接返回false;遍历完成后冲突次数不超过1则返回true
优化后的代码:
function solution(sequence) { // 边界处理:长度<=2时删1个元素最多剩1个元素,必然符合要求 if (sequence.length <= 2) return true; let removedCount = 0; const n = sequence.length; for (let i = 0; i < n - 1; i++) { if (sequence[i] >= sequence[i + 1]) { removedCount++; if (removedCount > 1) return false; // 校验两种删除方案是否可行 const canRemoveCurrent = i === 0 || sequence[i - 1] < sequence[i + 1]; const canRemoveNext = i + 1 === n - 1 || sequence[i] < sequence[i + 2]; if (!canRemoveCurrent && !canRemoveNext) return false; } } return true; }
若题目要求不允许原数组直接符合严格递增(即必须真的删除一个元素才能满足要求),只需要把返回条件调整为
return removedCount === 1 || sequence.length === 1即可,其余逻辑不变。
内容的提问来源于stack exchange,提问作者Lexxidon
相关产品推荐
相关产品推荐

