首页 / 资讯中心 / 文章详情

有序数组平方的双指针优化解法

有序数组平方的双指针优化解法 ★ FEATURED ARTICLE
1. 问题背景与核心思路在处理数组相关算法问题时有序数组的平方是一个经典的基础题目。给定一个按非递减顺序排序的整数数组要求返回每个数字的平方组成的新数组并且这个新数组也需要按非递减顺序排序。这个问题的关键在于如何处理负数平方后的排序。因为负数的平方会变成正数可能打乱原有的顺序。例如原始数组[-4,-1,0,3,10]平方后会变成[16,1,0,9,100]需要重新排序为[0,1,9,16,100]。2. 暴力解法与优化思路最直观的解法是先平方后排序def sortedSquares(nums): return sorted([x*x for x in nums])这种方法的时间复杂度是O(n log n)因为排序操作占主导。但我们可以利用原数组已经有序的特性找到O(n)的解法。3. 双指针解法详解更优的解法是使用双指针从数组两端向中间遍历def sortedSquares(nums): n len(nums) result [0] * n left, right 0, n - 1 for i in range(n - 1, -1, -1): if abs(nums[left]) abs(nums[right]): result[i] nums[left] * nums[left] left 1 else: result[i] nums[right] * nums[right] right - 1 return result3.1 算法步骤解析初始化左右指针分别指向数组首尾准备一个与输入数组等长的结果数组从结果数组末尾开始填充比较左右指针所指元素的绝对值大小将较大的平方值放入当前结果位置移动相应的指针直到所有位置填充完毕3.2 时间复杂度分析这种方法只需要一次线性遍历时间复杂度是O(n)空间复杂度也是O(n)用于存储结果。相比暴力解法有了明显优化。4. 边界条件与特殊处理在实际实现时需要注意以下边界情况全为正数的数组[1,2,3] → [1,4,9]全为负数的数组[-3,-2,-1] → [1,4,9]包含零的数组[-2,0,1] → [0,1,4]空数组[] → []单元素数组[5] → [25] 或 [-5] → [25]5. 算法优化技巧对于某些语言或特定场景还可以考虑以下优化提前计算平方值避免重复计算使用原地操作减少空间复杂度但会破坏原数组对于小数组n100简单排序可能更快6. 实际应用场景这种双指针技巧在以下场景中也很常见合并两个有序数组两数之和问题移除元素问题盛水容器问题掌握这种模式可以解决一大类数组处理问题。7. 代码实现示例以下是几种不同语言的实现Java版本public int[] sortedSquares(int[] nums) { int n nums.length; int[] result new int[n]; int left 0, right n - 1; for (int i n - 1; i 0; i--) { if (Math.abs(nums[left]) Math.abs(nums[right])) { result[i] nums[left] * nums[left]; left; } else { result[i] nums[right] * nums[right]; right--; } } return result; }JavaScript版本function sortedSquares(nums) { const result new Array(nums.length); let left 0, right nums.length - 1; for (let i nums.length - 1; i 0; i--) { if (Math.abs(nums[left]) Math.abs(nums[right])) { result[i] nums[left] * nums[left]; left; } else { result[i] nums[right] * nums[right]; right--; } } return result; }8. 测试用例设计完整的测试应该包含以下情况test_cases [ ([-4,-1,0,3,10], [0,1,9,16,100]), ([-7,-3,2,3,11], [4,9,9,49,121]), ([1,2,3], [1,4,9]), ([-3,-2,-1], [1,4,9]), ([-2,0,1], [0,1,4]), ([], []), ([5], [25]), ([-5], [25]) ]9. 性能对比实测在Python中对比两种解法的性能差异import timeit nums list(range(-10000, 10000)) def test_naive(): return sorted([x*x for x in nums]) def test_two_pointers(): n len(nums) result [0] * n left, right 0, n - 1 for i in range(n - 1, -1, -1): if abs(nums[left]) abs(nums[right]): result[i] nums[left] * nums[left] left 1 else: result[i] nums[right] * nums[right] right - 1 return result print(Naive:, timeit.timeit(test_naive, number100)) print(Two pointers:, timeit.timeit(test_two_pointers, number100))实测结果单位秒暴力解法1.23双指针解法0.4510. 常见错误与调试技巧新手在实现时容易犯的错误包括指针移动方向错误应该从后往前填充绝对值比较写成值比较边界条件处理不全如空数组结果数组初始化大小错误调试时可以打印每次循环的指针位置和结果数组状态对小规模输入手动演算添加断言检查不变量11. 算法扩展思考这个问题可以扩展为立方而不是平方如何处理如果允许结果降序排列如何修改如果输入是链表而非数组如何解决并行化处理超大数组的可能性12. 实际工程应用在实际工程中这种技巧可用于信号处理中的幅度计算图像处理中的像素值转换金融数据标准化处理任何需要保持有序性的数值转换场景13. 不同语言实现注意事项各语言实现时需要注意C/C注意整数溢出问题Java数组初始化语法JavaScript动态数组与类型转换Python列表推导式的效率Go切片的使用方式14. 教学与学习建议对于初学者建议先理解暴力解法手动演算小例子画出指针移动示意图尝试自己实现后再看解答多做变种练习巩固15. 历史与相关算法这种双指针技巧最早出现在归并排序的合并步骤中后来被广泛应用于快速排序的分区滑动窗口问题多指针问题数组旋转问题理解这个基础问题有助于掌握更复杂的算法模式。
阅读完成 · 觉得有帮助?
咨询建站