977. 有序数组的平方
题目:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
1. 暴力解法
最简单的方法就是将数组中的数平方后直接排序,时间复杂度是O(n logn)。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0; i < nums.size(); i++){
nums[i] *= nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
2. 双指针
上述方法没有利用「数组nums 已经按照非降序排序」这个条件。
当 nums 中的每个数都是正数时,平方后数组仍保持非降序;当 nums 中的每个数都是负数时,平方后数组为降序。
因此,可以通过找到负数与非负数之间的分界线,设分界线为 i,平方后我们将得到 nums[0] 到 nums[i] 的降序数组和 nums[i] 到nums[n-1] 的升序数组这两个有序子数组。
使用两个指针分别指向分界线 i 和最后一个负数 j = i - 1,每次比较两个指针对应的数,选择较小的那个放入答案并移动指针。当某一指针移至边界时,将另一指针还未遍历到的数依次放入答案。
时间复杂度为O(n)。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len = nums.size();
vector<int> ans;
int i = 0, j = -1;
//找到负数与非负数之间的分界线
while(i < len){
if(nums[i] < 0){
i++;
}else{
break;
}
}
for(j = i - 1; j >= 0 && i < len;){
int i2 = nums[i] * nums[i];
int j2 = nums[j] * nums[j];
if(i2 <= j2){
ans.push_back(i2);
i++;
}else{
ans.push_back(j2);
j--;
}
}
//非负数还未遍历完
if(i < len){
for(;i < len; i++){
ans.push_back(nums[i] * nums[i]);
}
}
//负数还未遍历完
if(j >= 0){
for(;j >= 0; j--){
ans.push_back(nums[j] * nums[j]);
}
}
return ans;
}
};
上面这一方法是通过找到分界线执行的双指针法,还有一种双指针法是将两个指针分别指向数组的头和尾,由于数组有序,数组平方的最大值只会在数组的两端,
将 i 指向起始位置,j 指向终止位置。定义一个新数组 ans,和 nums 数组一样的大小,让 k 指向ans 数组的终止位置。
- 如果
nums[i] * nums[i] >= nums[j] * nums[j]
,那么ans[k--] = nums[i] * nums[i]
; - 如果
nums[i] * nums[i] < nums[j] * nums[j]
,那么ans[k--] = nums[j] * nums[j]
。
两个指针不断向数组中间移动,直至遍历完整个数组,即i > j
.
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> ans(nums.size(), 0);
int len = nums.size();
for(int i = 0, j = len - 1, k = len - 1; i <= j; k--){
if(nums[i] * nums[i] >= nums[j] * nums[j]){
ans[k] = nums[i] * nums[i];
i++;
}else{
ans[k] = nums[j] * nums[j];
j--;
}
}
return ans;
}
};