美文网首页
Leetcode算法题215:数组中第k大元素

Leetcode算法题215:数组中第k大元素

作者: Persistence__ | 来源:发表于2020-05-12 21:31 被阅读0次

    在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
    示例 1:

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

    示例 2:

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

    思路1:快排思想
    快速排序是对冒泡的改进,降低冒泡的递归深度, 使时间复杂度降低到O(nlgn)。因为快排每次将数组划分为两组加一个基准元素,每一趟划分你只需要将k与基准元素的下标进行比较。
    如果比基准元素下标大就从右边的子数组中找,如果比基准元素下标小从左边的子数组中找,如果一样则就是基准元素,找到,
    如果需要从左边或者右边的子数组中再查找的话,只需要递归一边查找即可,无需像快排一样两边都需要递归,所以复杂度必然降低。

    - (int)findKthLargest:(NSMutableArray *)array k:(int)k {
        int i = 0;
        int j = (int)array.count - 1;
        while (true) {
            int temp = [self partition:array i:i j:j];//执行一遍后,把最大的放最前面,再比较temp和k的关系
            if (k == temp + 1) {
                return [array[temp] intValue];
            }else if(k < temp + 1)
            {
                j = temp-1;//这里每次要把基准元素去掉,否则会死循环
            }
            else
            {
                i = temp + 1;
            }
        }
    }
    
    - (int)partition:(NSMutableArray *)array i:(int)i j:(int)j {
        int pivot = [array[i] intValue];
        while (i != j) {
            while (i < j && [array[j] intValue] < pivot) {
                j--;
            }
            while (i < j && [array[i] intValue] > pivot) {
                i++;
            }
            if (i < j) {
                [array exchangeObjectAtIndex:i withObjectAtIndex:j];
            }
        }
        return i;
    }
    

    思路2:堆排序思想
    建立最小根堆,用数组的前k个数,建立最小根堆。然后从第k+1开始,和堆顶比较,如果比堆顶大,就交换,交换完重新维护成最小根堆,直到结束。这样堆里存放的就是数组中前k个最大的元素,而堆顶就是这里面最小的,也就是第k大的元素。

    - (int)findKthLargest:(NSMutableArray *)array k:(int)k {
        
        // 1.前k个数建立最小根堆,最小的数在堆顶
        NSMutableArray *newArr = [self buildHeap:[array subarrayWithRange:NSMakeRange(0, k)].mutableCopy n:k];
        // 2.从第k+1个开始,和堆顶比较
        for (NSInteger i = k; i < array.count; i++) {
            // 3.比堆顶大,则交换
            if ([array[i] intValue] > [newArr[0] intValue]) {
                newArr[0] = array[i];
                // 4.再对数组进行堆排序
                newArr = [self buildHeap:newArr n:k];
            }
        }
    
        return [newArr[0] intValue];
    }
    
    - (NSMutableArray *)buildHeap:(NSMutableArray *)array n:(NSInteger)n {
        NSInteger last = n - 1;
        NSInteger parent = (last - 1) / 2;
        for (NSInteger i = parent; i >= 0; i--) {
            [self heapify:array n:n i:i];
        }
        return array;
    }
    
    // heapify:小根堆思想,最小的放根位置
    - (void)heapify:(NSMutableArray *)array n:(NSInteger)n i:(NSInteger)i {
        if (i >= n) {
            return;//递归出口
        }
        
        // 完全二叉树,根节点位置为i
        // 左子节点
        NSInteger c1 = 2*i + 1;
        NSInteger c2 = 2*i + 2;
        NSInteger min = i;
        
        if (c1 < n && [array[c1] intValue] < [array[min] intValue]) {
            min = c1;
        }
        if (c2 < n && [array[c2] intValue] < [array[min] intValue]) {
            min = c2;
        }
        if (min != i) {
            [array exchangeObjectAtIndex:min withObjectAtIndex:i];
            [self heapify:array n:n i:min];
        }
    }
    

    思路3:java的优先队列PriorityQueue
    优先级队列,常用来代替堆,每次直接加入新数即可,自动维护大小顺序,最小的数在堆顶。数组中前k个元素加入到队列中,当k+1个进入后,最小的出队,这样数组遍历完后,队列中刚好剩下k个元素,返回堆顶元素就是第k大的元素

     public int findKthLargest(int[] nums, int k) {
         PriorityQueue<Integer> queue = new PriorityQueue<>();
         for (num:nums) {
             queue.offer(num);//入队
             if (queue.size() > k) {
                 queue.poll();//堆顶最小的元素出队
             }
         }
         return queue.peak();//返回堆顶最小的元素
     }
    

    相关文章

      网友评论

          本文标题:Leetcode算法题215:数组中第k大元素

          本文链接:https://www.haomeiwen.com/subject/qwninhtx.html