LeetCode997:有序数组的平方
题目:
给你一个按非递减顺序 排序的整数数组 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 已按 非递减顺序 排序
链接:997.有序数组的平方
双指针法:
- 数组其实是有序的,只不过负数平方之后可能成为最大的数。
- 那么数组的平方最大值就在两端,不是左边就是右边,不可能是中间。
- 此时就可以考虑双指针法了,left在最左侧,right在最右侧,新建一个列表用来存最大的数。
方法一:
双指针法,用绝对值来比较大小(推荐)
此时的时间复杂度为O(n)
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
left,right=0,len(nums)-1
res=[]
while left<=right:
if abs(nums[left])<abs(nums[right]): #绝对值比较
res.append(nums[right]**2)
right-=1
else:
res.append(nums[left]**2)
left+=1
res.reverse()
return res
方法二:
双指针法(推荐)
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
l, r, i = 0, len(nums)-1, len(nums)-1
res = [float('inf')] * len(nums) # 需要提前定义列表,存放结果
while l <= r:
if nums[l] ** 2 < nums[r] ** 2: # 左右边界进行对比,找出最大值
res[i] = nums[r] ** 2
r -= 1 # 右指针往左移动
else:
res[i] = nums[l] ** 2
l += 1 # 左指针往右移动
i -= 1 # 存放结果的指针需要往前平移一位
return res
方法三:
暴力解法(不推荐)
这个时间复杂度是 O(n + nlogn), 可以说是O(nlogn)的时间复杂度,但为了和下面双指针法算法时间复杂度有鲜明对比,我记为 O(n + nlog n)。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
for i in range(len(nums)):
nums[i]*=nums[i]
nums.sort()
return nums
方法四:
暴力解法排序+列表推导
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(x*x for x in nums)
总结:
- 当题目是有序数组且要排序时,可以考虑双指针的方法
- 还有,力扣的运行速度和打败多少用户数字不用太在意,这个不准确,看看玩就行
- 有人会问,为何在‘方法二’里面要加上res = [float(‘inf’)] * len(nums),而不是res=[ ] ?
答:因为因为在循环中我们需要通过索引来访问和修改结果数组res的元素,而res = [ ]来创建一个空列表是不行的,如果res是一个空列表,那么在循环中无法直接通过索引来访问和修改res的元素,因为在循环开始之前,res没有任何元素。
因此,我们需要提前定义一个与给定数组长度相同的结果数组res,并将其初始化为正无穷大在循环中通过索引来访问和修改res的元素,最终返回结果数组res作为最终的结果
- 又有人会问,为什么‘方法一’就可以直接res=[ ]?
答:这是因为我们在循环中不需要直接通过索引来访问和修改结果数组res的元素,而是将平方值逐个添加到结果数组res的末尾最后,我们使用res.reverse()将结果数组res倒序排列,得到最终的升序平方数组.