一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
每日刷题 2021.04.28
- leetcode原题链接:leetcode-cn.com/problems/so…
- 难度:简单
- 方法:位运算、自定义排序
题目
- 给你一个整数数组
nums,将nums中的的所有偶数元素移动到数组的前面,后跟所有奇数元素。 - 返回满足此条件的 任一数组 作为答案。
示例
- 示例1
输入: nums = [3,1,2,4]
输出: [2,4,3,1]
解释: [4,2,3,1]、[2,4,1,3] 和 [4,2,1,3] 也会被视作正确答案。
- 示例2
输入: nums = [0]
输出: [0]
提示
1 <= nums.length <= 50000 <= nums[i] <= 5000
解题思路
- 分析题目:需要将
nums数组中的元素根据奇偶性进行排序,偶数放在数组的前半部分,奇数放在数组的后半部分。
二次遍历 + 位运算
- 思路:开辟一个额外的数组空间作为最终的答案数组,记为
ans;再开辟一个额外的数组空间存储nums数组中出现的奇数元素。- 第一次遍历遍历数组
nums,遇到偶数将其加入到ans数组中;遇到奇数将其加入到odd数组中。 - 第二次遍历:将
odd数组中的元素,加入到ans数组的尾部。
- 第一次遍历遍历数组
- 其中判断当前的数是偶数还是奇数的时候,可以给当前的数
&1,这样要比%2快很多,要多使用位运算。
sort自定义排序
- 回顾
sort函数,如果sort函数中的比较函数未声明,则按照字符串的形式进行比较。 - 如果声明了比较函数,分以下三种情况:
compare(a, b) < 0, a放在b之前compare(a, b) == 0,a与b的相对位置不变compare(a, b) > 0,b放在a的前面
- 那么结合本题,可知:
偶数&1 == 0, 奇数&1 == 1 - 想要将偶数放在前面,奇数放在后面,就需要将比较函数写成:
// 偶数放在前面,奇数放在后面,那么就需要偶数&1 - 奇数&1 是返回小于0的
// 刚好0 - 1 = -1;反之1 - 0 = 1
nums.sort((a, b) => a&1 - b&1);
一次遍历 + 位运算
- 优化:两次遍历的解题思路,是否能够通过一次遍历就实现呢?
- 思路:从
nums数组中的第一个数开始遍历,如果当前的数是偶数,那么就接着遍历下一个数;如果当前的数是奇数,那么就需要一个指针r从nums数组的末尾开始往前遍历,查找是否有偶数,找到第一个偶数,就将当前位的奇数与其交换。 - 循环重复上述过程,直到
nums数组中的所有元素都被处理完成。 - 注意⚠️:
r指针从数组尾部遍历的时候,要循环遍历到nums[r]等于偶数时,才能够停止,如果一直找不到,且已经小于了当前的i,就说明后面不存在可以交换的偶数,也就是说数组已经被排好序了。
AC代码
自定义sort()
var sortArrayByParity = function(A) {
// 位运算更快,取模可以通过位运算实现
return A.sort((a, b) => (a & 1) - (b & 1))
};
一次遍历+位运算
var sortArrayByParity = function(nums) {
let len = nums.length,ans = [],odd = [];
let r = len - 1;
for(let i = 0; i < len; i++) {
if((nums[i] & 1) == 1){
// console.log(nums[i])
// 奇数情况: 需要从后往前找偶数
while((nums[r] & 1) == 1 && r > i) {
r--;
}
if((nums[r] & 1) == 0){
// 找到偶数,位置互换
let tempt = nums[r];
nums[r] = nums[i];
nums[i] = tempt;
}
// 如果找到最后,都一直没有,那说明当前的数组已经排好了
}
if(r <= i) return nums;
}
};
总结
- 奇偶性的判断,使用位运算
num % 2的速度要远慢于num & 1.