力扣977 有序数组的平方

116 阅读2分钟

力扣977.有序数组的平方(977.有序数组的平方)

1. 题目描述

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

示例 1:

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

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

解释:平方后,数组变为 [16,1,0,9,100] 排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 已按 非递减顺序 排序

进阶:

  • 请你设计时间复杂度为 O(n) 的算法解决本问题

2. 写前思路

  1. 非递减顺序意思是不是递减的,可能递增,可能无序,看例子应该是递增的意思
  2. 要求时间复杂度为O(n),即只能遍历一遍数组,一旦使用排序算法,基本上都会变成O(nlogn),所以不能使用排序算法。
  3. 由于计算的是数字的平方,所以负数会变成正数,那么最终最小的数应该是数组中间位置的某个数。是否可以考虑0?但是不能这么猜,不过如果找到某个分界点,左边是负数,右边是正数,似乎可以。
  4. 思路萎靡,寻求gpt,提示双指针,left和right,遂思路打开。遍历原数组是O(n),遍历结果数组也是O(n) 。既然不知道最小的,但是可以通过数组第一个和最后一个的结果得到最大的,依次类推,可以倒序填充结果数组。即从两头开始挪动指针,依次获取最大值,倒着插入结果数组

3. 实现代码

分析:时间复杂度为O(n),空间复杂度为O(n)

时间复杂度为O(n):是因为只将数组循环了一次,即最耗时的操作花了O(n)。

空间复杂度为O(n):left,right指针占了2个基本变量的空间,即O(1),结果数组占用了n个基本变量的空间,即O(n),综合来看为O(n)

public class Solution977 {

    public static int[] sortedSquares(int[] nums) {
        int[] result = new int[nums.length];
        //双指针
        int left = 0;
        int right = nums.length -1;

        //倒序填充result
        for (int i = nums.length-1;i>-1;i--){
            int leftNumber = nums[left] * nums[left];
            int rightNumber = nums[right] * nums[right];
            if (leftNumber>rightNumber){
                result[i] = leftNumber;
                left = left +1;
            }else{
                result[i] = rightNumber;
                right = right -1;
            }
        }

        return result;
    }

    public static void main(String[] args) {
        int[] nums = {-4,-1,0,3,10};
        int[] ints = sortedSquares(nums);
        for (int anInt : ints) {
            System.out.println(anInt);
        }
    }

}

4. 运行结果

5. 官方题解分析(leetcode.cn/problems/sq…)

  1. 参考某条评论:我理解的非递减的意思是数组中有可能存在相同的值,然后这两个值不能称为是递减关系。大概可以解释非递减的意思。
  2. 官方给了三个答案,第一个思路即一开始设想的计算结果后排序,显然时间复杂度为O(nlogn),不符合结果;第二个思路类似于一开始所想的找最小值,将负数正数分为两组,依次向两边移动指针,符合时间复杂度O(n),但是需要考虑左边界和右边界,比较麻烦。第三个思路和实现思路一样,从两边往中间移动指针,依次填充最大值,符合时间复杂度O(n),由于是两边往中间移动,所以无需考虑边界问题,最后一次循环时,left=right,取谁的值无所谓。但是官方提供的空间复杂度为O(1),应该是没有包含结果的存储空间(翻看下面的回复后发现确实如此)。

6. 感悟

算法确实是考验思维的活跃度,即脑子灵不灵活,这题挺典型了,并没有涉及复杂的数据结构,但是考虑从小到大排序时,一般的思路都是从最小的排起,从而陷入了思维误区。如果能换个方向思考,从小到大排序,等于将数组倒着从大到小排序,问题就迎刃而解了。下次遇到同类型的题应该发挥思维,从不同角度考虑下。