目录
刷题日期: 20:5022 星期一2021年3月29日
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
难度简单103
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
提示:
0 <= nums.length <= 50000
1 <= nums[i] <= 10000
题目分析
根据提示可得数组长度和数据大小范围,int就够
需要判断字符是奇数还是偶数。
可以有很多种方法,主要是提高空间和时间效率。
得需要一个或两个辅助数组。
- 奇偶扫一遍分开存储,然后合并两个数组返回
- 一个辅助数组两个指针,扫到之后分别放到辅助数组的头和尾
初始解答:
自己实现了分析中的第二个方法,虽然效率比较低,但是调通后也一遍过了。
class Solution {
public int[] exchange(int[] nums) {
int size = nums.length; //数组长度
int[] List = new int[size]; //辅助数组
int x = 0;
int y = nums.length - 1; //辅助数组的位置标记
for (int i = 0; i < size; i++) {
if ((nums[i] % 2) == 1) {
List[x] = nums[i];
x++;
}
if ((nums[i] % 2) == 0) {
List[y] = nums[i];
y--;
}
}
return List;
}
}
执行结果:通过
显示详情
执行用时:3 ms, 在所有 Java 提交中击败了27.30%的用户
内存消耗:48.1 MB, 在所有 Java 提交中击败了5.67%的用户
参考书本,不用辅助数组直接交换:
class Solution {
public int[] exchange(int[] nums) {
int temp, i = 0, j = nums.length - 1;//两个指针
while (i < j) {
if ((nums[i] % 2) == 1) i++;
if ((nums[j] % 2) == 0) j--;
if ((nums[i] % 2) == 0 && (nums[j] % 2) == 1) {
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i++;
j--;
}
}
return nums;
}
}
执行结果:解答错误
显示详情
输入:
[11,9,3,7,16,4,2,0]
输出:
[11,9,3,16,7,4,2,0]
预期结果:
[11,9,3,7,16,4,2,0]
可以看到最中间的两个数并没有交换,分析原因是判断的顺序有误,改正后的代码
class Solution {
public int[] exchange(int[] nums) {
int temp, i = 0, j = nums.length - 1;//两个指针
while (i < j) {
if ((nums[i] % 2) == 1) i++;
if ((nums[i] % 2) == 0 && (nums[j] % 2) == 1) {
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i++;
j--;
}
if ((nums[j] % 2) == 0) j--;
}
return nums;
}
}
执行结果:通过
显示详情
执行用时:3 ms, 在所有 Java 提交中击败了27.30%的用户
内存消耗:46.5 MB, 在所有 Java 提交中击败了29.02%的用户
比之前的效果是好些了,评论区的算法基本都用了快速排序,学习后发现其实和自己的代码基本是一样的。
学习他人:
方法一:
…L1 2020-02-13
Java2ms一次快排
class Solution {
public int[] exchange(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
while (left < right && nums[left] % 2 != 0) {
left++;
}
while (left < right && nums[right] % 2 == 0) {
right--;
}
if (left < right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
return nums;
}
}
方法二:
K神:
复杂度分析:
时间复杂度 O(N)O(N) : NN 为数组 numsnums 长度,双指针 ii, jj 共同遍历整个数组。
空间复杂度 O(1)O(1) : 双指针 ii, jj 使用常数大小的额外空间。
代码:
x & 1x&1 位运算 等价于 x % 2x%2 取余运算,即皆可用于判断数字奇偶性。
作者:jyd
链接:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/solution/mian-shi-ti-21-diao-zheng-shu-zu-shun-xu-shi-qi-4/
来源:力扣(LeetCode)
class Solution {
public int[] exchange(int[] nums) {
int i = 0, j = nums.length - 1, tmp;
while(i < j) {
while(i < j && (nums[i] & 1) == 1) i++;
while(i < j && (nums[j] & 1) == 0) j--;
tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
return nums;
}
}
方法三:
kunxinL1 2020-03-08
两端不够优雅,可以考虑一端开始,龟兔赛跑
class Solution {
public int[] exchange(int[] nums) {
int slow = 0,fast = 0;
while(fast<nums.length){
if((nums[fast]&1)==1) swap(nums,slow++,fast);
fast++;
}
return nums;
}
public void swap(int[] nums,int a,int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] =temp;
return;
}
}
方法四:
解题思路:先遍历奇数放入数组,再遍历偶数放入数组,也就是我最一开始想到的那种。
作者:jovial-hugleufk
链接:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/solution/jian-dan-fang-fa-by-jovial-hugleufk-2cm0/
来源:力扣(LeetCode)
class Solution {
public int[] exchange(int[] nums) {
int[] arr = new int[nums.length];
int ans = 0;
for(int i = 0;i < arr.length;i++){
if(nums[i] % 2 != 0){
arr[ans++] = nums[i];
}
}
for(int i = 0;i < arr.length;i++){
if(nums[i] % 2 == 0){
arr[ans++] = nums[i];
}
}
return arr;
}
}
总结
以上就是本题的内容和学习过程了,双端快速排序想必会在很多地方用到,书里提的方法反而有些臃肿了,不过书中的方法实现了解耦,提高了代码的重用性,为功能扩展提供了便利。
欢迎讨论,共同进步。