今天介绍用双指针来实现归并排序,先看题目:
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。例如:
输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100]
我们要知道,原数组里有正负数和0,这导致了它们平方后原来的数组就不再有序。
如果没接触过双指针,我们的第一想法就是先把数组里的数经过平方之后,再对数组进行排序,这也是一种方法,至少解决了问题。但当解决问题的方法不止一种的时候,我们就要考虑哪一种最合适,算法里用来衡量的就是时间复杂度和空间复杂度。
class Solution {
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];
}
//用Array工具类进行排序
Arrays.sort(ans);
return ans;
}
}
时间复杂度:O(n \log n)O(nlogn),其中 nn 是数组 \textit{nums}nums 的长度。
空间复杂度:O(\log n)O(logn)。除了存储答案的数组以外,我们需要 O(\log n)O(logn) 的栈空间进行排序。
这时我们会发现,这种方法与直接给我们一个无序的数组让我们操作是没有任何区别的,而我们没有利用好原来的数组是有序的这一条件。
说一下算法思想:观察原数组,不难发现元素的平方最大值一定产生在原数组的最左边或者最右边,我们可以用两个指针,一个指向最左边的数,一个指向最右边的数,将两个指针指向的数进行平方后再比较大小,把大的一个放到空数组的最后,然后再指针往里移动,循环这个步骤,最终两个指针指向同一个元素时就结束:
代码:
class Solution {
public int[] sortedSquares(int[] nums) {
//右指针指向最右边元素
int right = nums.length - 1;
//左指针指向最左边元素
int left = 0;
//定义一个空数组来存放排序后的元素
int[] result = new int[nums.length];
int index = result.length - 1;
//当两个指针还没有指向一处时,循环
while (left <= right) {
//若左>右,把左元素放到空数组最后,左指针往右移动一格
if (nums[left] * nums[left] > nums[right] * nums[right]) {
result[index--] = nums[left] * nums[left];
++left;
}
//若右>=左,把右元素放到空数组最后,右指针往左移动一格
else {
result[index--] = nums[right] * nums[right];
--right;
}
}
return result;
}
}
努力学习,不断进步!