public int[] sortedSquares(int[] A) {
int ri = findMinAbsNumIndex(A);
int li = ri - 1;
int i = 0;
int[] nums = new int[A.length];
while (i < A.length) {
if (ri >= A.length) {
nums[i++] = square(A[li--]);
continue;
}
if (li < 0) {
nums[i++] = square(A[ri++]);
continue;
}
int left = square(A[li]), right = square(A[ri]);
if (left < right) {
nums[i++] = left;
li--;
} else {
nums[i++] = right;
ri++;
}
}
return nums;
}
// 遍历数组查找第一个绝对值最小的元素索引 O(n/2)
public int findMinAbsNumIndex(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] >= 0) return i;
}
return nums.length;
}
public int square(int a) {
return a * a;
}
}
class Solution {
public int[] sortedSquares(int[] A) {
int mid = binarySearch(A);
int li = mid - 1, ri = mid;
int i = 0;
int[] nums = new int[A.length];
while (li >= 0 && ri < A.length) {
int left = square(A[li]), right = square(A[ri]);
if (left < right) {
nums[i++] = left;
li--;
} else {
nums[i++] = right;
ri++;
}
}
while (ri >= A.length && i < A.length) {
nums[i++] = square(A[li--]);
}
while (li < 0 && i < A.length) {
nums[i++] = square(A[ri++]);
}
return nums;
}
// 找到给定数组中第一个最接近非负数的索引
// 如果数组中元素全为负,则返回最后一个元素的索引
// 二分查找的变种
public int binarySearch(int[] nums) {
int li = 0, ri = nums.length - 1;
int mid = 0;
while (li <= ri) {
// 排除区域中符号一致的情况
if (nums[li] >= 0) return li;
if (nums[ri] <= 0) return ri;
mid = li + (ri - li) / 2;// 这样计算中点能防止大数溢出
if (nums[mid] == 0) return mid;
else if (nums[mid] < 0) {
li = mid + 1;
} else {
ri = mid;// 需要保留此正数元素的索引,不减小范围
}
}
return mid;
}
public int square(int a) {
return a * a;
}
}
977. 有序数组的平方
思路
从题干获取如下条件:
需要我们返回的结果:对输入的数组元素平方,且按照非递减排序
解题
考虑条件1以及输出要求,我们的输出数组(原数组共有
N
个元素):方法一:暴力实现
因此我们可以对元素组整个进行绝对值计算(A[i] = Math.abs(A[i])),然后再对
A'
数组中进行非递顺序排序。思路如上,实现略。
方法二:双指针
再进一步思考题干。如果建立目标输出数组和输入数组元素之间的对应关系,我们可以看出:
如果用两个索引(
li
和ri
)来分别表示中点左右索引,i
表示目标数组(T
)索引。方法三:在方法二基础上对于某些步骤进行优化
优化查找
由于方法二中我们是迭代查找,复杂度为
O(n^2/2)
,属于最能优化的地方。目标数组有序,因此可以使用二分查找,优化查找效率。根据方法二,我们需要查找的索引对应我们的右指针。
给定的数组元素有三种情况:
ri = A.length - 1
ri = 0
思路:二分查找
nums[ri] <= 0
代表符合上述情况1,返回当前右索引nums[li] >= 0
代表符合上述情况2,返回当前左索引mid = li + (ri - li) / 2
nums[mid]
的正负0
直接返回ri -= 1
,边界缩小)。代码