《剑指offer》NO40 最小的K个数 详解 <Java实现>

//题目描述:
//输入n个整数,找出其中最小的K的数.例如,输入4,5,1,6,2,7,3,8折8个数,
//则最小的4个数字是1,2,3,4.
public class Solution
{
     
    //解题思路:
    //要找出最小的K的数,首先考虑到排序,再选出前K个数.但是还不够快.这样的时间复杂度是O(nlogn).

    //借用快排的思想.只要先找出找出第K小的元素,再用快排,这样K左边就是比K 小的元素.时间复杂度为O(1).
    //但是要找出第K小的元素也是一个问题.所以直接循环判断整个数组,找出快排一次后左边的元素个数是K个,就找到了最小的K个元素.
    //这样的时间复杂度是O(n) + O(1).
    // 但是只有当允许修改数组元素时才可以使用

    public ArrayList<Integer> getKthNumber(int[] nums, int k)
    {
     
        ArrayList<Integer> res = new ArrayList<>();

        //初始判断
        if (nums.length == 0 || nums == null || k < 0 || k > nums.length)
        {
     
            return null;
        }
        int l = 0, h = nums.length - 1;
        //开始循环判断,有点类似二分法.
        while (l < h)
        {
     
            int j = quickSelect(nums, l, h);
            if (j > k)
            {
     
                h = j - 1;
            }
            else if (j < k)
            {
     
                l = j + 1;
            }
            else
            {
     
                break;
            }
        }
        //从index为0的到K-1的是最小一K个数.
        for (int i = 0; i < k; i++)
        {
     
            res.add(nums[i]);
        }
        return res;
    }

    //快排
    private int quickSelect(int[] nums, int l, int h)
    {
     
        int p = nums[l];
        int i = l, j = h + 1;
        while (i < j)
        {
     
            while (i < j && nums[++i] < p) ;
            while (i < j && nums[--j] > p) ;

            swap(nums, i, j);
        }
        swap(nums, l, j);
        return j;
    }

    private void swap(int[] nums, int i, int j)
    {
     
        int t = nums[i];
        nums[i] = nums[j];
        nums[j] = t;
    }
}

你可能感兴趣的:(java_算法,二分法,数据结构,算法,java,快速排序)