LeetCode 调整顺序使奇数位于偶数前面/颜色问题

330 阅读3分钟

这是我参与更文挑战的第 10 天,活动详情查看: 更文挑战

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

题目描述

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

示例 1:

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

提示

  • 0 <= nums.length <= 50000
  • 1 <= nums[i] <= 10000

思路分析

我们可以使用双指针解法,左侧从 0 开始,右侧从数组尾部开始,不断将左侧的偶数值和右侧的奇数值进行交换,直到左侧指针等于右指针时,停止遍历。返回的数组就是我们想要的奇数在前,偶数在后的数组。

代码展示

解法一:时间复杂度是O(n){O(n)},空间复杂度是O(1){O(1)}

//剑指offer 21 调整数组顺序使得奇数位于偶数前面
    public int[] exchange(int[] nums) {  //1,2,4,3,6,5   //1,3,5,2,4,6
        int length = nums.length;
        int left = 0;
        int right = length - 1;
        while (left < right){
            if (nums[left] % 2 == 0){ //偶数
                if (nums[right] % 2 == 0){ //right 也是偶数
                    right--;
                } else { //right奇数
                    int temp = nums[right];
                    nums[right] = nums[left];
                    nums[left] = temp;
                    left++;
                    right--;
                }
            } else { //奇数
                left++;
            }
        }
        return nums;
    }

颜色分类(75)

题目描述

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 012 分别表示红色、白色和蓝色。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

示例 3:

输入:nums = [0]
输出:[0]

示例 4:

输入:nums = [1]
输出:[1]

提示

  • n == nums.length
  • 1 <= n <= 300
  • nums[i]012

进阶

  • 你可以不使用代码库中的排序函数来解决这道题吗?
  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

思路分析

不推荐使用官方的排序函数,而且仅仅使用常数空间,也就是说空间复杂度是O(1){O(1)},因为有三个颜色,所以我们可以先把前面两个颜色先归为一种,然后也是利用双指针解法,统一把 2 移到后面,在将 2 排序好之后在区分 0 和 1,也是利用双指针解法进行解答。

不过颜色问题还有一个注意点,在第二次判断时,也要过滤 nums[right] = 2 的情况,因为存在第一次遍历判断时不变的情况,所以这里还需要注意一下。我们可以用一些简单的案例,比如 {0,1},{1,2}等情况进行简单的代入。

代码展示

解法一:时间复杂度是O(n){O(n)},空间复杂度是O(1){O(1)}

public void sortColors(int[] nums) { //1,2
        int left = 0;
        int right = nums.length - 1;

        //先将0,1移到左侧,2移到右侧
        while (left < right){
            if (nums[left] == 2){
                if (nums[right] != 2){
                    nums[left++] = nums[right];
                    nums[right--] = 2;
                } else {
                    right--;
                }
            } else {
                left++;
            }
        }
        //0移到左侧,1移到右侧,2已经在最右侧了
        left = 0;
        while (left < right){
            if (nums[left] == 1){
                if (nums[right] != 1 && nums[right] != 2){  //需要特殊注意,这里也要判断不能为2,因为第一个while 可能被直接跳过比如: [1,2]
                    nums[left++] = nums[right];
                    nums[right--] = 1;
                } else {
                    right--;
                }
            } else {
                left++;
            }
        }
    }

总结

对于这类问题,我们可以将问题分解,然后利用双指针解法,直接在原地处理。