力扣 977. 有序数组的平方:双指针法的优雅解法

大家好!今天来分享力扣第 977 题 "有序数组的平方" 的解题思路。这道题看似基础,但想写出高效解法需要结合数组的特性做巧思 ------ 我们从暴力法的局限出发,一步步推导到最优的双指针解法。

一、题目描述

给你一个按非递减顺序排序 的整数数组 nums,返回每个数字的平方组成的新数组,要求新数组也按非递减顺序排序

示例

  • 输入:nums = [-4,-1,0,3,10]

  • 输出:[0,1,9,16,100]

  • 输入:nums = [-7,-3,2,3,11]

  • 输出:[4,9,9,49,121]

二、问题分析:暴力法的局限

首先想到的是暴力解法:先遍历数组计算每个元素的平方,再对结果排序。

暴力法代码如下:

cpp 复制代码
vector<int> sortedSquares(vector<int>& nums) {
    vector<int> res;
    for (int num : nums) res.push_back(num * num);
    sort(res.begin(), res.end());
    return res;
}

暴力法的优点是简单直观,但缺点也很明显:时间复杂度由排序操作主导,达到 O (n log n)(n 为数组长度)。当 n 很大时(比如 10^6 级别),排序的开销会显著拉低效率。

有没有办法避开排序,直接得到有序结果?

三、核心思路:双指针法的妙用

观察原数组的特性:数组是有序的,但负数的平方可能成为最大值 (比如 - 4 的平方 16 比 3 的平方 9 大)。因此,平方后的数组最大值一定出现在原数组的两端(要么最左,要么最右)。

基于这个发现,我们可以用双指针法从两端向中间遍历:

  1. 用指针i指向数组头部,指针j指向数组尾部;
  2. 用指针k指向结果数组的末尾(从后往前填充最大值);
  3. 比较nums[i]²nums[j]²,将较大值放入newNums[k],并移动对应的指针(i++j--),同时k--
  4. 重复上述步骤,直到i > j

四、双指针法代码实现与解读

结合这个思路,我们写出最优解代码(也是题目中给出的解法):

cpp 复制代码
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> newNums(nums.size()); // 初始化结果数组,大小与原数组一致
        int k = nums.size() - 1; // 结果数组的填充指针(从末尾开始)
        
        // 双指针:i指向头部,j指向尾部
        for (int i = 0, j = nums.size() - 1; i <= j; ) {
            if (nums[i] * nums[i] >= nums[j] * nums[j]) {
                newNums[k--] = nums[i] * nums[i]; // 头部平方更大,放入结果末尾
                i++; // 头部指针右移
            } else {
                newNums[k--] = nums[j] * nums[j]; // 尾部平方更大,放入结果末尾
                j--; // 尾部指针左移
            }
        }
        
        return newNums;
    }
};

代码解读:

  • 初始化结果数组newNums的大小与原数组相同,避免动态扩容的开销;
  • 双指针遍历ij分别从两端向中间靠拢,每次处理当前最大的平方值;
  • 从后往前填充k指针从结果数组末尾开始,保证每次放入的是当前最大的平方值,最终结果自然有序。

五、复杂度分析

  • 时间复杂度:O (n)。仅需遍历数组一次,每个元素处理一次;
  • 空间复杂度:O (n)。用于存储结果数组(若允许修改原数组,空间复杂度可优化为 O (1),但题目要求返回新数组)。

这是最优复杂度 ------ 因为至少需要遍历一次数组计算平方,时间复杂度不可能低于 O (n)。

六、总结

这道题的关键是利用原数组的有序性,意识到平方后的最大值出现在数组两端,从而用双指针法 "跳过排序步骤"。这种思路不仅适用于本题,还广泛应用于:

  • 两数之和 II(有序数组);
  • 合并两个有序数组;
  • 反转字符串中的元音字母等。

掌握 "有序数组 + 双指针" 的组合技巧,能大幅提升数组类题目的解题效率。如果有其他思路或疑问,欢迎评论交流!

相关推荐
一只侯子4 小时前
Face AE Tuning
图像处理·笔记·学习·算法·计算机视觉
jianqiang.xue4 小时前
别把 Scratch 当 “动画玩具”!图形化编程是算法思维的最佳启蒙
人工智能·算法·青少年编程·机器人·少儿编程
不许哈哈哈5 小时前
Python数据结构
数据结构·算法·排序算法
J***79395 小时前
后端在分布式系统中的数据分片
算法·哈希算法
天真小巫6 小时前
2025.11.28总结
职场和发展
Dream it possible!6 小时前
LeetCode 面试经典 150_二叉搜索树_二叉搜索树中第 K 小的元素(86_230_C++_中等)
c++·leetcode·面试
sin_hielo7 小时前
leetcode 2872
数据结构·算法·leetcode
dragoooon347 小时前
[优选算法专题八.分治-归并 ——NO.49 翻转对]
算法
AI科技星7 小时前
为什么宇宙无限大?
开发语言·数据结构·经验分享·线性代数·算法