977. 有序数组的平方
题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/squares-of-a-sorted-array/
题目
给定一个按非递减顺序排序的整数数组 A
,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
示例 1:
输入:[-4,-1,0,3,10]
输出:[0,1,9,16,100]
示例 2:
输入:[-7,-3,2,3,11]
输出:[4,9,9,49,121]
提示:
1 <= A.length <= 10000
-10000 <= A[i] <= 10000
A
已按非递减顺序排序。
解题思路
思路:双指针
先审题,题目给定整数数组(非递减排序),要求返回数组中每个数字的平方组成的新数组,但这里要求新数组最终也按非递减顺序排序。
这里看题目中的提示部分:
-10000 <= A[i] <= 10000
数组元素存在负数,而题目最终的要求是将新数组进行排序。
那么,我们可以想到先对数组中的数字进行平方处理,然后对得到的数组进行排序。这里代码如下:
class Solution:
def sortedSquares(self, A: List[int]) -> List[int]:
return sorted([num * num for num in A])
上面的代码就是遍历的同时,对数组中的数字进行平方处理,得到新数组进行排序。
双指针
这里主要说一下双指针的方法如何去实现题目的要求?
数组 A 是按非递减顺序排序的,而且 A 中的元素可能存在负数。当 A 中的元素存在负数时,直接对数组中的元素进行平方处理,我们可以发现,此时数组中数字会是两边大,中间小的情况。就以题目中示例 1 来说明:
[-4, -1, 0, 3, 10]
当对其进行平方处理后,得到:
[16, 1, 0, 9, 100]
这就是两边数字比中间大的情况。因为数组原本是有序的,如果像上面存在负数的情况,那么负数部分平方之后,得到是按非递增顺序排序;非负数部分不变还是按非递减顺序排序。
那么根据这个现象,我们就可以定义双指针,分别指向数组首尾,往中间逼近。比较两边数字平方后的大小,将较大的数字放到结果数组中的末尾,移动指针,往前填充数组。
这里说下具体的做法:
- 定义指针 left,right 分别指向数组首尾;
- 定义长度为 n 的结果数组 ans 以及游标 cur,其中 cur 指向结果数组末尾,用以从后往前填充数组;
- 遍历数组,对双指针指向的数字进行平方,然后比较两者的大小:
- 若
A[left] * A[left] > A[right] * A[right]
,那么将A[left] * A[left]
放到结果数组 cur 指向的位置。 - 否则将
A[right] * A[right]
放到结果数组 cur 指向的位置。
- 若
- 重复上面的步骤,直至指针 left > right。这里需要注意维护更新指针 left,right 及游标 cur。
具体的实现代码如下。
class Solution:
def sortedSquares(self, A: List[int]) -> List[int]:
n = len(A)
# 定义指针 left,right
left = 0
right = n-1
# 定义长度为 n 的新数组,以及游标 cur,用以从后往前填充新数组
# n 这里是原数组的长度
ans = [0] * n
cur = n - 1
# 开始遍历
while left <= right:
# 比较 A[left] * A[left] 和 A[right] * A[right]
# 将较大值放到结果数组中,
if A[left] * A[left] > A[right] * A[right]:
ans[cur] = A[left] * A[left]
# 当 left 指向的元素平方后放到结果数组后,向右移动 left
left += 1
else:
ans[cur] = A[right] * A[right]
# 当 right 指向的元素平方后放到结果数组后,向左移动 right
right -= 1
# 数字填充后,cur 往左移动,等待下次填充
cur -= 1
return ans
欢迎关注
公众号 【书所集录】
如有错误,烦请指正,欢迎指点交流。