持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
题目
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
解题思路
关键词:非递减排序;平方;保持排序非递减
关键信息:数组有负数;平方计算后大小排序会变;计算结果会有变化
API耍流氓解法
如果数组中存在负数,当平方计算后数组中负数部分字段排序就会发生变化。输出新数组结果必须满足非递减排序就需要将负数部分前移翻转。最省事解决办法先将数组每个数进行平方计算然后调用api中Arrays.sort进行数组重排即可。(一个偷懒算法完成)
public int[] sortedSquares(int[] nums) {
int[] ans = new int[nums.length];
for (int i = 0; i < nums.length; ++i) {
ans[i] = nums[i] * nums[i];
}
Arrays.sort(ans);
return ans;
}
双指针解法
双指针算法思路先找到正负数边界(默认排好序但正负平方之后大小会变),正负两端大小比较后重新填充到新数组中得出结果。
- 首先遍历数组当数值大于0时表示数组中存在负数。
- 若数组中不存在负数情况,直接遍历数组计算平方数即可。
- 有负数的情况下设置两个指针,r表示正数部分,l表示负数部分,两个指针分别向右边和左边移动。
- 创建新数组保存排序结果,循环比较l和r对应值大小,小的入队并移动该指针。
- 预设前提条件任何一方指针位移结束遍历另外指针剩余值直到结束。
public int[] sortedSquares(int[] nums) {
int r = 0;
int length = nums.length;
if(length == 1){
nums[0] *= nums[0];
return nums;
}
while(nums[r] < 0 && r < length - 1){ // 找到小数部分临界点
r++;
}
if(r > 0 && nums[0] < 0){
int[] newNums = new int[length]; // 新建数组用空间
int l = r - 1; // l是小数部分起点
int index = 0;
while(l >= 0 || r < length){
// 右边剩余遍历填充
if(l < 0){
newNums[index++] = nums[r] * nums[r];
r++;
continue;
}
// 左边剩余遍历填充
if(r >= length){
newNums[index++] = nums[l] * nums[l];
l--;
continue;
}
// 左边小于右边
if(-nums[l] <= nums[r]){
newNums[index++] = nums[l] * nums[l];
l--;
}else if(-nums[l] > nums[r]){
newNums[index++] = nums[r] * nums[r];
r++;
}
}
nums = newNums;
}else{
while(r < length){
nums[r] *= nums[r];
r ++;
}
}
return nums;
}
代码优化版本
根据上述算法其实可以优化为双指针首尾遍历(实时上找到正负边界还是对数组做全量遍历)。因此可将算法替换成从数组左右开始做比较(负数越小平方后越大)
public int[] sortedSquares(int[] nums) {
int i = nums.length;
int left = 0;
int right = i-1;
int[] res = new int[i];
while(left <= right){
i--;
if(nums[left]+nums[right]<0){
res[i] = nums[left]*nums[left];
left++;
}else{
res[i] = nums[right]*nums[right];
right--;
}
}
return res;
}
参考
- 来源:力扣(LeetCode)