荷兰国旗问题 即数组分区问题

222 阅读1分钟

颜色分类

题目

image.png

版本1 正确

    public static void sortColors(int[] nums) {

        // 荷兰国旗问题, 就是将数组分成三个区域
        // 第一个区域的值全部小于目标值
        // 第二各区域的值全部等于目标值
        // 第三个区域的值全部大于目标值

        // lessBound为第一个区域的右边界, 闭区间
        int lessBound = -1;
        // moreBound为第三个区域的左边界, 闭区间
        int moreBound = nums.length;

        // 遍历一遍数组 目标值是1
        // 需要注意的是, 这里不能不能用for循环, 因为交换完元素后, 当前位置的元素不一定符合要求
        // 需要再次判断, 因此不能让i自增
        int cur = 0;
        while (cur < moreBound) {
            if (nums[cur] > 1) {
                // 放入第三区域, 交换一次元素
                // 不移动cur指针
                // 这里不移动cur指针的原因是, 第三区域边界外边的元素可能小于目标值, 也可能大于等于目标值, 因此cur对应的元素还需要判断一次
                moreBound --;
                int temp = nums[moreBound];
                nums[moreBound] = nums[cur];
                nums[cur] = temp;
            } else if (nums[cur] < 1) {
                // 放入第一区域
                // 在第一区域必须移动cur指针, 不然cur指针就会一直停留在小于1的位置上
                // 这里能移动的原因就是lessBound以外的元素, 一定是大于等于目标值的, 是可以移动的
                lessBound ++;
                int temp = nums[lessBound];
                nums[lessBound] = nums[cur];
                nums[cur] = temp;
                cur ++;
            } else {
                // 如果相等, 移动cur指针
                cur++;
            }
        }

    }

正确的原因

非常棒的解析

(1) 利用两个指针, 定义两个区间的边界

(2) 注意什么情况下需要移动cur指针, 什么情况下不用移动