题目:
给你一个按 非递减顺序 排序的整数数组 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)
的算法解决本问题
解答:
偷懒解法:
我写的版本,可以看到额外弄一个squ是不必要的
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
squ = sorted([i**2 for i in nums])
return squ
官方的偷懒解法:
对于一般的平方,直接num*num性能会稍微快一点的,可以学一下
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(num * num for num in nums)
好了回归这道题的主题,也就是双指针:
我自己的思路一开始是从中间找从距离0最近的开始弄,但是考虑到找要额外消耗时间,改变策略,从两边往中间找,自己写的版本:
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
new = []
i,j = 0,len(nums)-1
while i <= j:
if nums[i]**2>nums[j]**2:
new.insert(0,nums[i]**2) #insert方法虽然可行但是调用的时候比较慢
i +=1
else:
new.insert(0,nums[j]**2)
j -=1
return new
最后跑出来的性能反而非常差,追溯原因是insert在数组头部插入进行额外挪动实在浪费时间
官方的实现有些巧妙,就是知道数组的长度了,那么倒着从尾部进行插入
那就先申请一个全是0长度为n的数组,反着往前修改值,可以借鉴一下
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
n = len(nums)
ans = [0] * n
i, j, pos = 0, n - 1, n - 1
while i <= j:
if nums[i] * nums[i] > nums[j] * nums[j]:
ans[pos] = nums[i] * nums[i]
i += 1
else:
ans[pos] = nums[j] * nums[j]
j -= 1
pos -= 1
# 避免insert挪动的方法:已经知道了数组的长度,那就倒着插入就好了!
return ans
除此之外,那个一开始是从中间找从距离0最近的开始弄的想法官方也给出了比较好的实现,那就是先找一遍最大的非负数,确定位置之后再来比较,双指针从中间往两侧跑:
毕竟3/2n也是O(n)不是嘛
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
n = len(nums)
negative = -1
for i, num in enumerate(nums):
if num < 0:
negative = i
else:
break
ans = list()
i, j = negative, negative + 1
while i >= 0 or j < n:
if i < 0:
ans.append(nums[j] * nums[j])
j += 1
elif j == n:
ans.append(nums[i] * nums[i])
i -= 1
elif nums[i] * nums[i] < nums[j] * nums[j]:
ans.append(nums[i] * nums[i])
i -= 1
else:
ans.append(nums[j] * nums[j])
j += 1
return ans
题目比较简单,也要多思考!