java查找数组arr中第k大的奇数

Question:

查找数组arr中第k大的奇数,如果不存在则返回0. (arr[i] > 0 (i>=0))
计算出时间复杂度(注意代码注释,不要使⽤库函数或脚本中已经实现好的排序算法和⼯具, 需要⾃⼰实现数据结构和所需要的算法)

当我阅读完毕题目时,第一个思路就是先进行排序 然后进行遍历查找第k的奇数

代码如下:

public static void BubbleSort(int []arr){
        int length=arr.length;
        for (int i = 0; i <length-1 ; i++) {
            for (int j = 0; j <length-1-i ; j++) {
                if(arr[j]>arr[j+1]){
                    int temp= arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
    }
    public static int findKth(int[] arr, int k){
        //冒泡排序(从小到大)
        BubbleSort(arr);
        //寻找第k大的奇数(要倒序遍历)
        int size =1;
        for (int i = arr.length-1; i >=0 ; i--) {
            if (arr[i]%2==1){   //奇数
                if (size==k){   //第k大
                    return  arr[i];
                }
                size++;
            }
        }
        return 0;
    }

由于题目要求不能使用库函数  ,so要自己编写排序算法,由此可以推断改算法的时间复杂度为O(N^2).

显然,这个时间复杂度有点大,能不能进一步优化一下呢?

经过查阅文档和java源码

想到了队列,我们知道队列是先进先出的,也不符合我们这个题的要求设计啊,但是队列有一个实现类  PriorityQueue,它可以根据优先级 优先处理优先级高的对象。

PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。

优先队列不允许空值,而且不支持non-comparable(不可比较)的对象,比如用户自定义的类。优先队列要求使用Java Comparable和Comparator接口给对象排序,并且在排序时会按照优先级处理其中的元素。

优先队列的头是基于自然排序或者Comparator排序的最小元素。如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个。当我们获取队列时,返回队列的头对象。

优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加!

PriorityQueue通过二叉小顶堆实现,可以用一棵完全二叉树表示(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。

由上图可以发现规律:

leftNo = parentNo*2+1

rightNo = parentNo*2+2

parentNo = (nodeNo-1)/2

通过上述三个公式,可以轻易计算出某个节点的父节点以及子节点的下标。这也就是为什么可以直接用数组来存储堆的原因。

有限队列具体的源代码后续文章会进行专题分析。

!!!优先队列的头是基于自然排序或者Comparator排序的最小元素。而且队列的大小会自动增加!!!

我们可以创建一容量大小为k的自然排序的priority队列来存放奇数,插入元素时。当队列满了时,poll()出最小的元素,再进行插入,如果未满,则继续插入,最后当队列满时我们peek()或者poll()的元素就是队列的头元素,也就是 我们想要的第k大的奇数,如果队列不满,即不存在第k大的 奇数。

代码如下:

public static int findKth2(int[] arr, int k) {
        PriorityQueue<Integer> q = new PriorityQueue<Integer>(k);
        for (int i = 0; i <arr.length ; i++) {
            if (arr[i]%2==1){   //奇数
                q.add(arr[i]);
            }
            if (q.size()>k){   //如果队列容量超过k了  就弹出最小元素
                q.poll();
            }
        }
        //判断队列长度是否为空或者根本不存在第k大的奇数
        if (q.size()!=k||q.size()==0){
            return 0;
        }else {
            return q.peek();
        }
    }

此时程序的时间复杂度为O(n)。

参考文章:

https://blog.csdn.net/huangwei18351/article/details/82183052

猜你喜欢

转载自blog.csdn.net/qq_37950333/article/details/103722287