zoukankan      html  css  js  c++  java
  • [LeetCode#215] Kth Largest Element in an Array

    Problem:

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

    For example,
    Given [3,2,1,5,6,4] and k = 2, return 5.

    Note: 
    You may assume k is always valid, 1 ≤ k ≤ array's length.

    Analysis:

    This problem is great!
    It's a good time to make a good summary!
    We are always try to take advantage of a sorted array. 
    1. find duplicates
    2. missing number
    ...
    However, for any kind of sorting alogrithm, as long as you want to get an array completely sorted. You have to to use at least 
    O(logn) time for it. For some case you really don't need to get all elements sorted, since you may just want to find a qualified
    element meets certain characteristic.
    
    Quick sort is a weired algorithm compared with other other algorithm. Rather than take all other elements for each iteration, it finds the position of one element once a time. Then continue to find elements for other elements. 
    
    The sub-algorthm of Quick sort is to find an element's rank in the array. (which could be acheive at O(n)). To make things more
    beautiful, the average time of using quick find kth element is actually O(n) time. 
    
    The idea behind it is not hard, but it indeed take some minds to understand.
    Unit function: randomly pick an element (usually the first or last element of the valid range), find it is rank in the array. (please be noted the rank is start from 0)
    
    Basic idea: 
    pick an element, 
    we put all elements smaller than it before it, 
    and put all elements larger than it after it.
    
    1. To achieve this, we need to use two pointers, one starts from the low and the other starts from the end.
            int left = low;
            int right = high;
    
    2. Once the left pointer finds out an element larger than the pivot, and the right pointer finds out the element smaller than the pivot. We exchange them!
    
    while (true) {
        while (right > left && nums[right] > pivot)
            right--;
        while (left < right && nums[left] <= pivot)
            left++;
        if (left == right)
            break;
        swap(nums, left, right);
    }
    Note: During the process of finding right elements to exchange, the left and right pointer may meet with each other. In this case, we should jump out the process of finding elements to exchange.
    
    3. When the left and right pointer meets with each other. the meet up position is where we should put the pivot. 
    int pivot = nums[low];
    ...
    swap(nums, low, right);
    
    4. iff the pivot's rank (index of meet up position) is just the rank we want to find. we return it.
    (The most beautiful part of quick select method is that, we never need to update on k!!!)
    if (cur_pos == k - 1)
        return pivot;
    //note pivot's ranke is in realtive with base 0 index.
    
    5. iff the pivot's rank smaller than the rank we want to find, and are sure all elements before pivot actually with even smaller rank, we search the target at the part after pivot.
    if (cur_pos < k - 1) 
        return findKth(nums, k, cur_pos+1, high);
    
    6. iff the pivot's rank larger than the rank we ant to find, we search the target at the left part before pivot.
    if (cur_pos < k - 1) 
        return findKth(nums, k, low, cur_pos-1);
    
    
    The idea is so powerful and beautiful, right?
    But there are some pitfalls in the implementation, you should be very careful!!!
    Mistake 1:
    Try to start from the element after the pivot (nums[low]).
    int pivot = nums[low];
    ...
    int left = low+1;
    
    1st concern: what if there are only one element left????
    You may try to fix it through "if (low == hight) return nums[low]"
    Is that right?
    Nope!!! if the pivot's right index is low!!! the meet up position would not be it. (since we have left = low+1)
    
    Mistake 2:
    underestimate the order of moving two pointer:
    while (left < right && nums[left] <= pivot)
        left++;
    while (right > left && nums[right] > pivot)
        right--;
        
    The above code makes the same mistake in the mistake1. The logic
    if (nums[left] <= pivot)
        left++;
    Would skip the "low" index!!!If the real index for pivot is "low", we would get wrong answer.
    But if we put:
    while (right > left && nums[right] > pivot)
        right--;
    at the first. Since low is the smallest element in the range (it's real index is low), our right pointer would go straightly to meet it.

    Solution:

    public class Solution {
        public int findKthLargest(int[] nums, int k) {
            return findKth(nums, nums.length - k + 1, 0, nums.length - 1);
        }
        
        
        private int findKth(int[] nums, int k, int low, int high) {
            int pivot = nums[low];
            int left = low;
            int right = high;
            while (true) {
                while (right > left && nums[right] > pivot)
                    right--;
                while (left < right && nums[left] <= pivot)
                    left++;
                if (left == right)
                    break;
                swap(nums, left, right);
            }
            swap(nums, low, right);
            int cur_pos = right;
            if (cur_pos == k - 1) {
                return pivot;
            } else if (cur_pos < k - 1) {
                return findKth(nums, k, cur_pos+1, high);
            } else {
                return findKth(nums, k, low, cur_pos-1);
            }
        }
        
        
        private void swap(int[] nums, int low, int high) {
            int temp = nums[low];
            nums[low] = nums[high];
            nums[high] = temp;
        }
    }
  • 相关阅读:
    MacOS升级到10.15.5,打开Flutter项目,或者运行‘flutter doctor’的时候,提示:“ 无法打开“dart”,因为Apple无法检查其是否包含恶意软件。 ”
    Expected a key while parsing a block mapping.
    iOS 与 Swift 方法互相调用
    iOS SDWebImage知识点
    什么是书?什么是看书?
    读《黑客与画家》
    System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt".
    读《瞬间之美》
    拆掉你思维里的墙
    将两个列不同的DataTable合并成一个新的DataTable
  • 原文地址:https://www.cnblogs.com/airwindow/p/4850639.html
Copyright © 2011-2022 走看看