【刷题】3-way-partition

概述

partition应该都很熟悉,是快排的核心,下面是是模板代码

public int partition(int[] arr, int left, int right) {
        int oldLeft = left; // 记录左边界
        int pivot = arr[left++];
        while(left <= right) {
            if(arr[left] <= pivot) {
                ++left;
            } else {
                swap(arr, left, right);
                --right;
            }
        }
        swap(arr, oldLeft, right);
        return right;
    }

对于数组中没有重复元素的数组,partition一定可以将数组按照pivot一分为二,pivot左边的值一定严格小于pivot,右边的值一定严格大于pivot,但是如果数组中元素重复出现比如下面的数据:

[5, 5, 3, 2, 6, 7, 8]

在运行partition之后会变成

[2, 5, 3, 5, 7, 8, 6]

选择的pivot是5(partiontion之后第二个5),pivot左侧出现了和其相等的值,原因是代码中,对于arr[left] <= pivot的情况不会做任何处理

这样对排序没有影响,但是如果我们希望partition进行更严格的划分,可以在每一轮partition之后,将nums分成三部分,如下所示
在这里插入图片描述
让nums所有和pivot相等的值都在中间部分,这样nums按照大小顺序就可以严格分成三部分,此时就需要使用到3-way-partition算法

思路

原版partition过程中,实际上遍历过程分为以下三种情况:

  • arr[left] < pivot:不操作(相当于放到pivot左边)
  • arr[left] == pivot:不操作(所以左边会出现和pivot相等的值,且可能与pivot不相邻)
  • arr[left] > pivot:将arr[left]这个较大的值换到右边去

为了实现之前所说的严格将nums划分为三部分,在arr[left] < pivot时不仅仅是将其放到pivot左边(即不操作),而是要将其放到最左边,使其尽量远离pivot,这样一轮划分下来,所有小于pivot的值都会集中在数组最左边,实现严格的划分,具体代码如下:

public int threeWayPartition(int[] arr, int left, int right) {
        int pivot = arr[left];
        int i = 0; // 记录左边小值应该放入的位置
        while(left < right) {
            if(arr[left] == pivot) {
                ++left;
            } else if(arr[left] > pivot) {
                swap(arr, left, right);
                --right;
            } else { // arr[left] < pivot
                swap(arr, i, left);
                ++i;
                ++left;
            }
        }
        return right;
    }

用i来记录可以放到的"最左边"的位置

[5, 5, 3, 2, 6, 7, 8]

划分之后

[3, 2, 5, 5, 7, 8, 6]

与pivot相等的值都会聚集到中间

例题

324. 摆动排序 II

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值