双指针法思想:27.移除元素(py)-CSDN博客
题目
给你一个按 非递减顺序 排序的整数数组 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) 的算法解决本问题
题解
暴力排序:每个数平方之后,排个序。
双指针法:数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的长度,让k指向result数组终止位置(倒序填充)。
如果A[i] * A[i] < A[j] * A[j]
那么result[k--] = A[j] * A[j];
。
如果A[i] * A[i] >= A[j] * A[j]
那么result[k--] = A[i] * A[i];
。
Pycharm
#(版本一)双指针法
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) 空间复杂度:O (n)
注:res = [float('inf')] * len(nums) 这一行的作用是 预先初始化一个长度与输入数组相同的列表,并用无穷大(float('inf'))填充。这是因为双指针法需要从后向前填充结果数组,而 Python 中列表的长度是固定的,无法直接通过索引赋值(如 res[i] = ...)来添加元素,除非列表已经有足够的长度。 更常见的写法:
res = [None] * len(nums) # 使用 None 作为占位符
详细解释:
①为什么需要初始化列表?
Python 的列表不像数组那样有固定长度,直接通过索引赋值(如 res[3] = 10)会引发 IndexError,除非列表已经至少有 4 个元素。因此,需要先创建一个足够长的列表。
②为什么用 float('inf') 填充?
这里填充的值实际上无关紧要,因为后续双指针遍历时会覆盖每个位置的值。使用无穷大只是一种占位符,强调这些值会被替换。实际上,使用 None、0 或其他任意值都可以。
#(版本二)暴力排序法
from typing import List
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
for i in range(len(nums)):
nums[i] *= nums[i]
nums.sort()
return nums
#时间复杂度:O (n log n) 空间复杂度:O (n)
注:在 Python 中,nums.sort() 是列表(list)对象的一个原地排序方法,用于将列表中的元素按照升序排列。
功能解释:
①直接修改原列表
nums.sort() 会直接修改原列表 nums 的元素顺序,使其变为有序,不会返回新列表(返回值为 None)。
②默认升序排列
对于数字,从小到大排序;对于字符串,按字典序排序。
③可选参数
reverse=True:降序排列。reverse=False:升序排列。
key=函数:自定义排序规则(例如按绝对值排序)。
nums = [5, 3, 1, 4, 2]
nums.sort(reverse=True)
print(nums) # 输出: [5, 4, 3, 2, 1]
#(版本三)暴力排序法+列表推导法
from typing import List
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(x*x for x in nums)
#(双指针优化版本) 三步优化
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
"""
整体思想:有序数组的绝对值最大值永远在两头,比较两头,平方大的插到新数组的最后
优 化:1. 优化所有元素为非正或非负的情况
2. 头尾平方的大小比较直接将头尾相加与0进行比较即可
3. 新的平方排序数组的插入索引可以用倒序插入实现(针对for循环,while循环不适用)
"""
# 特殊情况, 元素都非负(优化1)
if nums[0] >= 0:
return [num ** 2 for num in nums] # 按顺序平方即可
# 最后一个非正,全负有序的
if nums[-1] <= 0:
return [x ** 2 for x in nums[::-1]] # 倒序平方后的数组
# 一般情况, 有正有负
i = 0 # 原数组头索引
j = len(nums) - 1 # 原数组尾部索引
new_nums = [0] * len(nums) # 新建一个等长数组用于保存排序后的结果
# end_index = len(nums) - 1 # 新的排序数组(是新数组)尾插索引, 每次需要减一(优化3优化了)
for end_index in range(len(nums)-1, -1, -1): # (优化3,倒序,不用单独创建变量)
# if nums[i] ** 2 >= nums[j] ** 2:
if nums[i] + nums[j] <= 0: # (优化2)
new_nums[end_index] = nums[i] ** 2
i += 1
# end_index -= 1 (优化3)
else:
new_nums[end_index] = nums[j] ** 2
j -= 1
# end_index -= 1 (优化3)
return new_nums
运行结果
进程已结束,退出代码为 0
LeetCode
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
a,b,c=0,len(nums)-1,len(nums)-1
res=[None]*len(nums)
while a<=c:
if nums[a]**2<nums[c]**2:
res[b]=nums[c]**2
c-=1
else:
res[b]=nums[a]**2
a+=1
b-=1
return res
链接
双指针法经典题目 | LeetCode:977.有序数组的平
方_哔哩哔哩_bilibili
时间:2025.6.9
不爱学习的大学生