[977. 有序数组的平方]
「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战」。
题目描述
给你一个按 非递减顺序 排序的整数数组 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) 的算法解决本问题
思路
这道题其实有一个很明显的写法,就是先将数组进行平方,变成一个新的数组,我们称此为平方数组,之后再调用一般的排序函数,就可以实现我们的目的。但是这不是最好的做法,我们观察到,平方数组有一个特点,要么单调递增(1,2,3,4),要么单调递减(-4,-3,-2,-1),要么先递减,再递增(-4,-2,1,3,5)。不难发现最大值的平方会出现再数组的两端。那么我们就可以又用到我们的双指针了。
代码实现
使用双指针,一个指向数组头部,一个指向数组尾部。将他们所指的元素进行比较。将其中的大数写入我们的结果数组中,并将指针进行对应的移动,直到两个指针重合,完成整个数组的排序。这里我们有一个答案数组,能不能实现在原地进行排序呢?
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
vector<int> ans(n);
for (int i = 0, j = n - 1, pos = n - 1; i <= j;--pos) {
if (nums[i] * nums[i] > nums[j] * nums[j]) {
ans[pos] = nums[i] * nums[i];
++i;
}
else {
ans[pos] = nums[j] * nums[j];
--j;
}
}
return ans;
}
};
上面的做法,两个指针都需要移动,有没有什么办法,只移动一个呢?答案是有,我们在需要的时候,不妨交互两个指针的元素,使数组末尾的指针始终指向的数是大数,这样,数组头部的指针就不需要移动了。数组末尾的指针始终指向的数是大数,可以直接在原地进行计算,也就不需要结果数组了。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n=nums.size()-1; //末尾指针
int temp;
while(n>=0){
int min=nums[0]*nums[0]; //被固定的头部指针,其值为指针已经扫过区域的最小值
int cur=nums[n]*nums[n];
if(min>=cur)
swap(nums[0],nums[n]); //需要交换
nums[n]*=nums[n]; //原地修改
n--; //移动末尾指针
}
return nums;
}
};
总结
上述内容使用双指针的算法思想,使用首尾指针,通过首尾两个指针不断的移动,在一个for循环下完成两个for循环的工作,大大优化了时间复杂度,并且进行了进一步优化,将双指针中的一个固定,可以看作一次遍历,即单指针的做法。