leetcode
leetcode 851 ~ 900
有序数组的平方

有序数组的平方

难度:

标签:

题目描述

代码结果

运行时间: 28 ms, 内存: 18.4 MB


/*
题目思路:
1. 使用 Java Stream 对数组进行处理。
2. 首先将数组 nums 转换为 IntStream。
3. 使用 map 对每个元素进行平方操作。
4. 使用 sorted 对平方后的数组进行排序。
5. 将结果转换为 int 数组并返回。
*/
import java.util.Arrays;
import java.util.stream.IntStream;

public int[] sortedSquares(int[] nums) {
    return Arrays.stream(nums)
                 .map(x -> x * x)
                 .sorted()
                 .toArray();
}

解释

方法:

题解采用了双指针技术来解决问题。数组`nums`已经是非递减排序的,但平方后的值可能改变元素的相对顺序,特别是负数的平方可能变得比原有的正数大。解决方案中,使用了两个指针`left`和`right`分别指向数组的开头和结尾。一个辅助数组`tmp`被用来从后向前填充结果,以保证平方后也是非递减顺序。每次比较`left`和`right`处的数的平方,将较大的平方数放入`tmp`中,并移动相应的指针,直到所有元素都处理完毕。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在双指针方法中,为什么选择从数组的两端开始而不是从中间向两边扩展?
在这个问题中,主要考虑的是平方后值的大小和排序。由于输入数组是非递减的,数组两端的值的绝对值往往是最大的,尤其是当包含负数时。从两端开始可以直接比较两端数的平方,直接决定哪个数的平方应该放在结果数组的末尾。如果从中间开始向两边扩展,虽然中间的数平方后可能小,但需要额外的逻辑来确定每个平方值的正确位置,这会增加算法的复杂性和执行时间。
🦆
当两个指针指向的数的平方相等时,选择移动哪一个指针,这样的选择对结果有何影响?
当左右指针指向的数的平方相等时,选择移动哪一个指针实际上并不会影响最终结果的排序,因为相等的平方值填入结果数组的顺序并不影响结果数组的非递减属性。在解决方案中可以选择移动任一指针,通常出于简化代码的考虑,可以优先移动右指针(或左指针),这样做主要是为了保持代码的一致性和可读性。
🦆
数组`tmp`是如何确保在填充时保持非递减顺序的,特别是在处理有大量重复元素时?
数组`tmp`是从后向前填充的,始终将当前最大的平方数放在数组的后部未填充的最前面。由于`nums`数组是非递减的,其平方后的最大值一定出现在原数组的两端。通过比较两端的平方,可以确保每次填充的都是目前未处理的最大平方数,保持`tmp`数组的非递减顺序。即使存在重复元素,只要按照这种方法填充,就能确保填充过程中的顺序性,因为相同的数平方后仍然相同,填充顺序不影响最终结果的顺序。
🦆
在算法中,如何处理特殊情况,例如数组中只有一个元素或所有元素都是负数?
对于只有一个元素的数组,由于双指针`left`和`right`初始化时指向同一个位置,循环会正常执行一次,正确地计算出这个元素的平方并填充到`tmp`数组中,返回的结果也会是正确的。如果所有元素都是负数,这些元素的平方会变成正数,由于原数组是非递减的,平方后的数组实际上应该是非递增的。但是由于我们从两端向中心比较并填充,所以最大的平方数(位于原数组左端的数的平方)会首先被处理,保证了`tmp`数组填充的非递减顺序。

相关问题

合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n

 

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

 

提示:

  • nums1.length == m + n
  • nums2.length == n
  • 0 <= m, n <= 200
  • 1 <= m + n <= 200
  • -109 <= nums1[i], nums2[j] <= 109

 

进阶:你可以设计实现一个时间复杂度为 O(m + n) 的算法解决此问题吗?

有序转化数组

有序转化数组