【知识积累】荷兰国旗问题2:给定一个数组arr,和一个整数num。请把小于num的数放在数组左边,等于num的数放在中间,大于num的数放在数组的右边。要求时间复杂度O(N),额外空间复杂度(1)

介绍一种能在O(N)时间复杂度及O(1)额外空间复杂度下,将数组按指定数值划分的方法。通过调整指针位置,实现数组中小于、等于、大于给定数值的元素分别位于数组左侧、中间和右侧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.example.demo.algorithm.D004;

/**
 * @Description :
 * 题目:
 * 给定一个数组arr,和一个整数num。请把小于num的数放在数组左边,等于num的数放在中间,大于num的数放在数组的右边。
 * 要求时间复杂度O(N),额外空间复杂度(1)
 *
 * partition流程:
 * 1)将整个数组左边划分为小于区域,下标初始值为-1,右边花费为大于区域,下标初始值为r+1
 * 2)当i位置的数小于num时,当前数arr[i]与小于区域下一个数交换,小于区右扩,i++
 * 3) 当i位置的数大于num时,当前数arr[i]与大于区域上一个数交换,大于区左扩,i原地不变(因为此时i位置的数没有看过)
 * 4)当i位置的数等于num时,i++
 *
 * [5,3,7,2,3,4,1] i=0 a=-1 b=7 num=3(a:左边界  b:右边界)
 *  0 1 2 3 4 5 6
 * 5 > 3  arr[0] swap arr[6] i=0 a=-1 b=6
 *
 * [1,3,7,2,3,4,5]
 *  0 1 2 3 4 5 6
 * 1 < 3 arr[0] swap arr[0] i=1 a=0 b=6
 *
 * [1,3,7,2,3,4,5]
 *  0 1 2 3 4 5 6
 *  3 = 3 i=2 a=0 b=6
 *
 * [1,3,7,2,3,4,5]
 *  0 1 2 3 4 5 6
 * 7 > 3 arr[2] swap arr[5] i=2, a=0, b=5
 *
 * [1,3,4,2,3,7,5]
 *  0 1 2 3 4 5 6
 * 4 > 3 arr[2] swap arr[4] i=2 a=0 b=4
 *
 * [1,3,3,2,4,7,5]
 *  0 1 2 3 4 5 6
 * 3 == 3 i=3 a=0 b=4
 *
 * [1,3,3,2,4,7,5]
 *  0 1 2 3 4 5 6
 *  2 < 3 arr[3] swap arr[1] i=4 a=1 b=4
 *
 * [1,2,3,3,4,7,5]
 *  0 1 2 3 4 5 6
 *    a     b
 * 小于3的在左边,等于3的在中间,大于3的在右边
 *
 * @Author : Darren
 * @Date : 2021 年 02 月 25 日 20:31:54
 * @since : 1.0
 */
public class J002_Partition {

    public static void main(String[] args) {
        int[] arr = {5,3,7,2,3,4,1};
        int[] partition = partition(arr, 0, arr.length - 1, 3);
        printArray(arr);
        printArray(partition);
    }

    /**
     * 给定一个数partition
     * @param arr
     * @param l
     * @param r
     * @param num
     * @return
     */
    public static int[] partition(int[] arr, int l, int r, int num){
        if (l > r){
            return new int[]{-1,-1};
        }
        if (l == r){
            return new int[]{l,r};
        }
        //左边界
        int lessEqual = l-1;
        //右边界
        int moreEqual = r+1;
        int index = l;
        while (index < moreEqual){
            // 当i位置的数小于num时,当前数arr[i]与小于区域下一个数交换,小于区右扩,i++
            // 当i位置的数大于num时,当前数arr[i]与大于区域上一个数交换,大于区左扩,i不变
            // 当i位置的数等于num时,i++
            if (arr[index] < num){
                swap(arr, index++, ++lessEqual);
            }else if(arr[index] > num){
                swap(arr, index, --moreEqual);
            }else{
                index++;
            }
        }
        return new int[]{lessEqual,moreEqual};
    }

    private static void swap(int[] arr, int i, int j) {
        /*arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];*/
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    /**
     * 生成一个随机数组
     * @param maxSize
     * @param maxValue
     * @return
     */
    public static int[] generateRandomArray(int maxSize, int maxValue){
        //Math.random() [0,1)
        //Math.random() * N [0,N)
        //(int)(Math.random() * N) [0,N-1]
        int[] arrays = new int[(int) ((maxSize+1) * Math.random())];
        for (int i = 0; i < arrays.length; i++) {
            arrays[i] = (int) ((maxValue+1) * Math.random()) - (int)(maxValue * Math.random());
        }
        return arrays;
    }

    /**
     * 打印数组
     * @param arrays
     */
    public static void printArray(int[] arrays){
        if (arrays == null){
            return;
        }
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i] + " ");
        }
        System.out.println();
    }

    /**
     * 复制数组
     */
    public static int[] copyArray(int[] arr){
        if (arr == null){
            return null;
        }
        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }

    /**
     * 判断两个数组是否相等
     * @param arr1
     * @param arr2
     * @return
     */
    public static boolean isArrayEqual(int[] arr1, int[] arr2){
        if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)){
            return false;
        }

        if (arr1 == null && arr2 == null){
            return true;
        }

        if (arr1.length != arr2.length){
            return false;
        }

        for (int i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]){
                return false;
            }
        }
        return true;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值