排序题目:有序数组的平方

文章目录

题目

标题和出处

标题:有序数组的平方

出处:977. 有序数组的平方

难度

2 级

题目描述

要求

给定按非递减顺序 排序的整数数组 nums \texttt{nums} nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。

示例

示例 1:

输入: nums = [-4,-1,0,3,10] \texttt{nums = [-4,-1,0,3,10]} nums = [-4,-1,0,3,10]

输出: [0,1,9,16,100] \texttt{[0,1,9,16,100]} [0,1,9,16,100]

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

示例 2:

输入: nums = [-7,-3,2,3,11] \texttt{nums = [-7,-3,2,3,11]} nums = [-7,-3,2,3,11]

输出: [4,9,9,49,121] \texttt{[4,9,9,49,121]} [4,9,9,49,121]

数据范围

  • 1 ≤ nums.length ≤ 10 4 \texttt{1} \le \texttt{nums.length} \le \texttt{10}^\texttt{4} 1≤nums.length≤104
  • -10 4 ≤ nums[i] ≤ 10 4 \texttt{-10}^\texttt{4} \le \texttt{nums[i]} \le \texttt{10}^\texttt{4} -104≤nums[i]≤104
  • nums \texttt{nums} nums 已按非递减顺序排序

进阶

计算每个元素的平方并对新数组排序的解法很简单,你可以使用不同的方法找到时间复杂度 O(n) \texttt{O(n)} O(n) 的解法吗?

解法一

思路和算法

最直观的解法是依次计算数组 nums \textit{nums} nums 中的每个元素的平方并存入新数组中,然后对新数组按非递减顺序排序,即可得到排序后的新数组。

代码

java 复制代码
class Solution {
    public int[] sortedSquares(int[] nums) {
        int length = nums.length;
        int[] squares = new int[length];
        for (int i = 0; i < length; i++) {
            squares[i] = nums[i] * nums[i];
        }
        Arrays.sort(squares);
        return squares;
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 nums \textit{nums} nums 的长度。计算数组 nums \textit{nums} nums 中的每个元素的平方并存入新数组需要 O ( n ) O(n) O(n) 的时间,对新数组排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,因此时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)。

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。对新数组排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间。注意返回值不计入空间复杂度。

解法二

思路和算法

解法一没有利用到数组 nums \textit{nums} nums 已经按非递减顺序排序的条件,因此需要对新数组排序,时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)。如果利用数组 nums \textit{nums} nums 已经按非递减顺序排序的条件,则不需要对新数组排序,将时间复杂度降低到 O ( n ) O(n) O(n)。

由于一个数的平方大小与这个数的绝对值有关,因此考虑数组 nums \textit{nums} nums 中的绝对值最大元素与绝对值最小元素可能出现的位置。

数组 nums \textit{nums} nums 按非递减顺序排序,可能有以下三种情况:

  • 数组 nums \textit{nums} nums 的所有元素都是非负数,元素顺序为绝对值非递减顺序,首个元素的绝对值最小,末尾元素的绝对值最大;

  • 数组 nums \textit{nums} nums 的所有元素都是非正数,元素顺序为绝对值非递增顺序,首个元素的绝对值最大,末尾元素的绝对值最小;

  • 数组 nums \textit{nums} nums 中既有正数也有负数,首个元素或末尾元素的绝对值最大。

对于上述三种情况中的任意一种情况,绝对值最大的元素一定是数组 nums \textit{nums} nums 的首个元素或末尾元素。因此可以从数组 nums \textit{nums} nums 的两端向中间遍历,按照绝对值从大到小的顺序依次遍历数组 nums \textit{nums} nums 的元素,计算每个元素的平方,反向填入新数组。

具体做法是,维护两个下标 index 1 \textit{index}_1 index1 和 index 2 \textit{index}_2 index2,初始时 index 1 \textit{index}_1 index1 指向数组 nums \textit{nums} nums 的首个元素, index 2 \textit{index}_2 index2 指向数组 nums \textit{nums} nums 的末尾元素。遍历过程中,比较 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 和 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 这两个元素的绝对值:

  • 如果 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 的绝对值大于 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 的绝对值,则将 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 的平方填入新数组,将 index 1 \textit{index}_1 index1 加 1 1 1;

  • 如果 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 的绝对值小于等于 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 的绝对值,则将 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 的平方填入新数组,将 index 2 \textit{index}_2 index2 减 1 1 1。

由于遍历数组 nums \textit{nums} nums 的过程中,每次遍历的元素都是尚未遍历的元素中的绝对值最大的元素,因此遍历元素的顺序是绝对值非递增顺序,即元素的平方非递增顺序。将遍历的元素的平方反向填入新数组,新数组中的元素顺序为非递减顺序。

代码

java 复制代码
class Solution {
    public int[] sortedSquares(int[] nums) {
        int length = nums.length;
        int[] squares = new int[length];
        int index1 = 0, index2 = length - 1;
        for (int i = length - 1; i >= 0; i--) {
            if (Math.abs(nums[index1]) > Math.abs(nums[index2])) {
                squares[i] = nums[index1] * nums[index1];
                index1++;
            } else {
                squares[i] = nums[index2] * nums[index2];
                index2--;
            }
        }
        return squares;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 中的每个元素一次。

  • 空间复杂度: O ( 1 ) O(1) O(1)。注意返回值不计入空间复杂度。

相关推荐
u6063 小时前
常用排序算法核心知识点梳理
算法·排序
梁辰兴4 天前
数据结构:排序
数据结构·算法·排序算法·c·插入排序·排序·交换排序
Tisfy4 天前
LeetCode 3027.人员站位的方案数 II:简单一个排序O(n^2)——ASCII图解
leetcode·题解·思维·排序·hard
hzhzh~1 个月前
【C++】神秘-希尔排序
c++·希尔排序·排序·sort
Alfred king1 个月前
Leetcode 四数之和
算法·leetcode·职场和发展·数组·排序·双指针
junjunyi1 个月前
【LeetCode 148】算法进阶:排序链表 ( 归并排序、快速排序、计数排序 )
链表·排序·分治·归并
Alfred king1 个月前
面试150 IPO
面试·职场和发展·贪心·数组··排序
今天背单词了吗9802 个月前
算法学习笔记:29.拓扑排序——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·笔记·算法·拓扑排序·排序
NuyoahC2 个月前
HOT100——排序篇Leetcode215. 数组中的第K个最大元素
c++·leetcode·排序算法·排序
初级代码游戏2 个月前
WinUI3入门16:Order自定义排序
自定义·排序·order·winui3