有序数组平方排序
主要用来练习排序算法。
问题描述:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
算法分析:
- 方案一:直接平方后,再进行排序
class Solution{
public:
vector<int> sortedSquares(vector<int>& nums){
vector<int> abs;
for(int num:nums){
abs.push_back(num*num); //在push_back()函数是在尾部添加值
}
sort(abs.begin(),abs.end());//排序,从容器第一个数开始,到最后一个数,默认升序
return abs;
}
};
复杂度分析
时间复杂度:
O
(
n
log
n
)
O(n \log n)
O(nlogn),其中 n 是数组
n
u
m
s
nums
nums 的长度。
空间复杂度:
O
(
log
n
)
O(\log n)
O(logn)。除了存储答案的数组以外,但是需要
O
(
log
n
)
O(\log n)
O(logn) 的栈空间进行排序。
链接:来源
- 方案二:使用双指针
方法一没有利用数组已经按照升序排序这个条件。显然,数组分为正负两部分,而且每部分都是有序的,这样就可以转换成两个有序数组进行<归并排序>的方法。
思路:
先找出数组的分界线zero,然后 n u m s [ 0 ] nums[0] nums[0]到 n u m s [ z e r o ] nums[zero] nums[zero]全为负数,平方后, z e r o zero zero左边的数组降序排序,右边数组为升序排序,使用<归并排序>排序更有效。具体地,使用两个指针分别指向位置 z e r o zero zero和 z e r o + 1 zero+1 zero+1,每次比较两个指针对应的数,选择较小的那个放入答案并移动指针。当某一个指针移至边界时,将另一个指针按序放入答案。
class Solution {
public vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
int negative = -1;
for(int i = 0;i < n; ++i) {
if (nums[i] < 0)
negative = i;
else
break; //找到分解点
}
//归并排序
vector<int> ans;
int i = negativel
int j = negative + 1;
while (i>=0 || j<n) {
if(i < 0) {//全是正数
ans.push_back(nums[j] * nums[j]);
j++;
}
else if (j==n){//全为负数
ans.push_back(nums[i] * nums[i];
i--;
}
else if(nums[i] * nums[i] < nums[j] * nums[j]){
ans.push_back(nums[i] * nums[i]);
i--;
}
else {
ans.push_back(nums[j] * nums[j]);
j++;
}
}
}
};
复杂度分析:
时间复杂度:
O
(
n
)
O(n)
O(n),其中 n是数组
n
u
m
s
nums
nums的长度。
空间复杂度:
O
(
1
)
O(1)
O(1)。除了存储答案的数组以外,只需要维护常量空间。
另一个思路是,可以使用两个指针分别指向位置 0 和 n-1,每次比较两个指针对应的数,选择较大的那个逆序放入答案并移动指针,这种方法无需处理某一指针移动至边界的情况。
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;){
if (nums[i] * nums[i] > nums[j] * nums[j]){
ans[pos] = nums[i] * nums[i];
i++;
}
else {
ans[pos] = nums[j] * nums[j];
j--;
}
pos--;
}
return ans;
}
};