启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
该题是数组二分查找题型第五题。
题目来源
题目描述(简单)
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例1
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例2
输入: nums = [-7,-3,2,3,11]
输出: [4,9,9,49,121]
提示
nums已按 非递减顺序 排序
题目解析
直接排序
最简单的方法就是将数组元素平方后得到新数组,进行排序后返回最终数组。
代码
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
nums = nums.map((item) => {
return item * item
})
return nums.sort(function(left, right) {return left -right})
};
如图:
双指针
在直接排序中,我们没有用到原数组为升序数组这个条件。如果数组 nums 中的所有数都是非负数,那么将每个数平方后,数组仍然保持升序;如果数组中所有数都是负数,那么将每个数平方后,数组将为降序。
假设 num 为数组 nums 中负数和非负数的分界线。那么 nums[0] 到 nums[num] 均为负数, nums[num + 1] 到 nums[nums.length - 1] 均为非负数。当数组的元素平方后,那么 nums[0] 到 nums[num] 单调递减, nums[num + 1] 到 nums[nums.length - 1] 单调递增。此时以 num 为分界线,出现两个有序的区间,最后采用 归并排序 的方法即可。
代码
先找到原数组的最后一个负数的下标,在由左右指针依次遍历平方后的数组判断大小,将小的平方值放入新数组。
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
let left = 0, right = 0, res = [], length = nums.length
nums = nums.map((item, index) => {
if (item < 0) {
left = index
}
return item * item
})
right = left + 1
while (left >= 0 || right < length) {
if (left < 0) {
res.push(nums[right])
right++
}else if (right === length) {
res.push(nums[left])
left--
}else if (nums[left] < nums[right]) {
res.push(nums[left])
left--
}else{
res.push(nums[right])
right++
}
}
return res
};
执行用时和内存消耗仅供参考,大家可以多提交几次。如有更好的想法,欢迎大家提出。