• 215. 数组中的第K个最大元素_中等_数组


     暴力,排序取值

    class Solution {
    
        public int findKthLargest(int[] nums, int k) {
            Arrays.sort(nums);
            return nums[nums.length-k];
        }
    
    }

    优先队列

        //思路是创建一个大小为k的优先队列,对每一个元素判断和优先队列对头的元素(最小值,小顶堆)
        //进行比较,如果对头元素小,则移除加入新的元素,所以最终队列就是前k大,队头就是我们要的
        public int findKthLargest(int[] nums, int k) {
            PriorityQueue  queue = new PriorityQueue(k);
            for (int i = 0; i < nums.length; i++) {
    //            System.out.println(queue.size());
                if(queue.size()<k){
                    queue.add(nums[i]);
                }else{
                    if(nums[i]> (int)queue.peek()){
    //                    System.out.println(queue.peek());
                        queue.poll();
                        queue.add(nums[i]);
                    }
                }
            }
            return (int)queue.peek();
        }

    快排(每次确定一个指定大的数据,当为k时就可以返回)

    class Solution {
        //用一个全局变量来记录quickSelect的结果
        private int num;
    
        public int findKthLargest(int[] nums, int k) {
    //        quickSelect(nums,k,0,nums.length - 1);//快排选择
            int num = heapSelect(nums, k);//堆选择
            return num;
        }
    
        /**
         * 快排选择
         * @param nums 数组
         * @param k 第几大
         * @param left 左边界
         * @param right 右边界
         */
        public void quickSelect(int[] nums,int k,int left,int right){
            //递归终止条件
            if(left > right){
                return;
            }
    
            int pivot = nums[left];//基准值
            int leftIndex = left;//左指针
            int rightIndex = right;//右指针
            //用挖坑法逐步替换元素,使基准值归位
            while(leftIndex < rightIndex){
                //在右边寻找一个小于基准值的数,并与左指针所在位置交换
                while(leftIndex < rightIndex && nums[rightIndex] >= pivot){
                    rightIndex--;
                }
                if(leftIndex < rightIndex){
                    nums[leftIndex] = nums[rightIndex];
                }
                //在左边寻找一个大于基准值的数,并与右指针所在位置交换
                while(leftIndex < rightIndex && nums[leftIndex] < pivot){
                    leftIndex++;
                }
                if(leftIndex < rightIndex){
                    nums[rightIndex] = nums[leftIndex];
                }
            }
            nums[leftIndex] = pivot;//将基准值归位
            //以上都是快排的基本操作,接下来则是利用快排找出第k大的数
            //leftIndex是基准值的位置,以它为分界线,看第k大的位置在左边还是右边,进而对相应区域使用快排
            //如果第k大的数已经归位,则返回
            if(leftIndex == nums.length - k){
                num = nums[leftIndex];
                return;
            }else if(leftIndex > nums.length - k){
                quickSelect(nums,k,left,leftIndex - 1);
            }else if(leftIndex < nums.length - k){
                quickSelect(nums,k,leftIndex + 1,right);
            }
        }
    
        //交换数组中两个数的位置
        public void swap(int[] nums,int index1,int index2){
            int temp = nums[index1];
            nums[index1] = nums[index2];
            nums[index2] = temp;
        }
    
        /**
         * 调整堆
         * @param nums 数组
         * @param index 所要调整的元素下标
         * @param endIndex 此次调整的范围
         */
        public void adjustHeap(int[] nums,int index,int endIndex){
            //利用挖坑法调整,先保存nums[index],待找到其应在的位置时,再填充上去
            int temp = nums[index];
            //2 * index + 1是左子结点的下标,所谓调整,就是不断比较父结点与子结点的大小,从而将父结点调整到合适的位置
            for(int i = 2 * index + 1;i <= endIndex;i = 2 * i + 1){
                //先比较左右子结点哪个大,大的那个需要和父节点交换
                if(i + 1 <= endIndex && nums[i + 1] > nums[i]){
                    i = i + 1;
                }
                //如果大的那个子结点比父结点大,则交换
                if(nums[index] < nums[i]){
                    swap(nums,index,i);
                    index = i;//交换以后要记得调整下标
                }else{//如果父结点比两个子结点都大,则调整结束
                    break;
                }
            }
            nums[index] = temp;//将坑填上,也就是将父结点放到其应在的位置
        }
    
        //堆选择
        public int heapSelect(int[] nums,int k){
            int num = 0;//用来记录结果
            //首先建堆,建堆就是从最后一个非叶子结点开始,不断调整,直到根结点
            //最后一个非叶子结点的下标是(nums.length - 2)/2,这个是可以证明的,可以上网查一下
            for(int i = (nums.length - 2)/2;i >= 0;i--){
                adjustHeap(nums,i,nums.length - 1);
            }
            //所谓堆排序,就是不断将堆顶元素交换到堆尾
            //由于交换后破坏了堆,所以每次交换后都需要调整,以满足堆的要求
            //通过把堆顶元素交换到堆尾,并缩小堆尾范围,逐步使数组达到有序的状态
            for(int endIndex = nums.length - 1;endIndex >= 0;endIndex--){
                adjustHeap(nums,0,endIndex);//调整堆
                swap(nums,0,endIndex);//交换堆顶和堆尾
                //如果第k大元素已经归位,则返回
                if(endIndex == nums.length - k){
                    num = nums[endIndex];
                }
            }
            return num;
        }
    }
    作者:你的雷哥
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Android通讯录查询篇ContactsContract.Data
    startActivityForResult 用法
    Android 开发 – 使用菜单
    屏幕旋转 转
    动态更改屏幕方向LANDSCAPE与PORTRAIT 转
    .使用ContactsContract API
    主题:android之XmlResourceParser类使用实例 转
    Android使用AttributeSet自定义控件的方法 转
    EmbossMaskFilter BlurMaskFilter
    字典转换成实体列表
  • 原文地址:https://www.cnblogs.com/henuliulei/p/15349362.html
Copyright © 2020-2023  润新知