查找第index小的数

10 篇文章 0 订阅
package com.zzw.algorithm;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @program: sorttest
 * @description: 查找第n个小的数字
 * @author: zhaozhenwei
 * @create: 2021-03-30 19:42
 **/
public class FindMinKth {

    /**
     * 查找当前集合arr第n个小的数字时,使用当前集合的第一个数或者在当前集合随机找到一个数字A,将集合分为三部分
     *  第一部分是小于找到的数字A的集合,第二部分是等于数字A的集合,第三部分是大于数字A的集合
     *  判断要找的数字下标是在那一部分,如果是在第一、三部分,则对第一部分的集合进行上面动作的递归,如果是在第二部分,直接返回arr[index]
     */

    public static void main(String[] args) {
        int length = 20;
        Integer[] arr = {43, 44, 77, 91, 18, 5, 69, 83, 66, 35, 33, 13, 83, 61, 57, 8, 3, 86, 86, 15};

        System.out.println(process(arr, 0, arr.length - 1, 3));
        System.out.println(Arrays.toString(arr));

        System.out.println(process(arr, 0, arr.length - 1, 12));
        System.out.println(Arrays.toString(arr));

        System.out.println(process(arr, 0, arr.length - 1, 13));
        System.out.println(Arrays.toString(arr));

        System.out.println(process(arr, 0, arr.length - 1, 14));
        System.out.println(Arrays.toString(arr));


        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
        System.out.println(arr[3]+ " " + arr[12]+ " " + arr[13]+ " " + arr[14]+ " ");

    }

    /**
     * 通过递归查找第index小的数字的大小
     *      如果在分开集合的左侧,对左侧的数据进行递归处理
     *      如果在分开集合的右侧,对右侧的数据进行递归处理
     *      如果在分开集合的中间,直接通过arr[index]返回集合
     *          集合的左侧都是小于中间集合的数据,不用考虑数据的具体位置
     *          集合的右侧都是大于中间集合的数据,不用考虑数据的具体位置
     *          集合中间数据都是相等,因此也不用考虑数据的大小位置
     * @param arr
     * @param left
     * @param right
     * @param index
     * @return
     */
    public static int process(Integer[] arr, int left, int right, int index) {
        if (left == right) {
            // 当要处理的集合只有一位数字的时候,就是我们需要的数字,因为只有一位数字,也无法渠道第2+小的数字
            return arr[left];
        }
        // 找到一个值,将当前集合的left到right位划分成三部分
        int num = 0;
        num = arr[left];
        int[] partition = partition(arr, left, right, num);
        // 判断要查找的第index小的数为分开集合的哪一个部分
        if (index >= partition[0] && index <= partition[1]) {
            // 要查找的index为小的数字在中间位置,则可以直接返回对应下标位置的数字,因为中间位置数字都是相同的
            return arr[index];
        } else if (index < partition[0]) {
            return process(arr, left, partition[0] - 1, index);
        } else {
            return process(arr, partition[1] + 1, right, index);
        }
    }

    /**
     * 将数组arr中L、R之间的数据根据与数字num的大小进行分界
     *      返回的range数组是中间部分的起始和结尾
     * @param arr  进行数据分割的集合
     * @param l    集合的起始位置
     * @param r    集合的结束位置,包括该位置
     * @param num  用来将集合分开的数据
     */
    public static int[] partition(Integer[] arr, int l, int r, int num) {
        int[] range = new int[2];
        ArrayList<Integer> leftArr = new ArrayList<Integer>();
        ArrayList<Integer> centerArr = new ArrayList<Integer>();
        ArrayList<Integer> rightArr = new ArrayList<Integer>();

        for (int i = l; i <= r ; i++) {
            if (arr[i] > num) {
                rightArr.add(arr[i]);
            } else if(arr[i] == num) {
                centerArr.add(arr[i]);
            } else {
                leftArr.add(arr[i]);
            }
        }
        System.arraycopy(leftArr.toArray(), 0, arr, l, leftArr.size());
        System.arraycopy(centerArr.toArray(), 0, arr, l+leftArr.size(), centerArr.size());
        System.arraycopy(rightArr.toArray(), 0, arr, l+leftArr.size() + centerArr.size(), rightArr.size());

        range[0] = l + leftArr.size();
        range[1] = r - rightArr.size();
        return range;
    }


}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值