【剑指Offer】个人学习笔记_21_调整数组顺序使奇数位于偶数前面

刷题日期: 20:5022 星期一2021年3月29日

个人刷题记录,代码收集,来源皆为leetcode

经过多方讨论和请教,现在打算往Java方向发力

主要答题语言为Java

题目:

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

难度简单103

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

示例:

输入:nums = [1,2,3,4]
输出:[1,3,2,4] 
注:[3,1,2,4] 也是正确的答案之一。

提示:

  1. 0 <= nums.length <= 50000
  2. 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;
    }
}

总结

以上就是本题的内容和学习过程了,双端快速排序想必会在很多地方用到,书里提的方法反而有些臃肿了,不过书中的方法实现了解耦,提高了代码的重用性,为功能扩展提供了便利。

欢迎讨论,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值