[LeetCode无序数组K小元素] | 刷题打卡

296 阅读2分钟

[LeetCode无序数组K小元素] | 刷题打卡

一直有刷题习惯,最近才看到掘金举办了刷题活动,特来参加!此题为第12题。不得不说掘金的主题就是漂亮呀!赞。

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

无序数组K小元素

描述 找到一个无序数组中第K小的数 样例

样例 1:

输入: [3, 4, 1, 2, 5], k = 3
输出: 3

样例 2:

输入: [1, 1, 1], k = 2
输出: 1

挑战
O(nlogn)的算法固然可行, 但如果你能 O(n) 解决, 那就非常棒了.

二、思路分析:

最简单的是直接排序,选择第k个位置的值,时间复杂度是O(nlog)O(nlog);这里使用推荐双指针+快速排序模板

方法
描述
时间复杂度
空间复杂度
双指针法(形似)只是用了两根指针,相向双指针,核心思想用的是快速排序O(n)O(n)(1)(1)

partition步骤:

  1. left = startright = endpivot = nums[left]
  2. nums[left] < pivot时,left指针向右移动。
  3. nums[right] > pivot时,right指针向左移动。
  4. 交换两个位置的值,right指针左移,left指针右移。
  5. 直到两指针相遇,否则回到第2步。

每次partition后根据pivot的位置,寻找下一个搜索的范围。

三、AC 代码:

public class Solution {
    /**
     * @param k: An integer
     * @param nums: An integer array
     * @return: kth smallest element
     */
    public int kthSmallest(int k, int[] nums) {
         return quickSelect(nums, 0, nums.length - 1, k - 1);
    }

    /**
     * 
     * @param nums
     * @param i
     * @param j
     * @param k
     * @return
     */
    private int quickSelect(int[] nums, int start, int end, int k) {
        if (start == end) {
            return nums[start];
        }
        int left = start;
        int right = end;
        int pivot = nums[(start + end) / 2];

        while (left <= right) {
            while (left <= right && nums[left] < pivot) {
                left++;
            }

            while (left <= right && nums[right] > pivot) {
                right--;
            }
            if (left <= right) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                left++;
                right--;
            }
        }

        // conditions
        if (right >= k && right >= start) {
            return quickSelect(nums, start, right, k);
        } else if (left <= k && left <= end) {
            return quickSelect(nums, left, end, k);
        }
        return nums[k];
    }
}

四、总结:

此题可以归为双指针算法类型的题目,也可以归为划分算法类的题目,可以配合第11题来食用更佳!

  • 形式上是双指针的变体,使用了leftrightpivot三根指针
  • 这题其实是快速排序算法的变体,通过快速排序算法的partition步骤,可以将小于pivot的值划分到pivot左边,大于pivot的值划分到pivot右边,所以可以直接得到pivot的范围。从而缩小范围继续找第k大的值。