数组中第K大的元素

数组中第K大的元素总结

        

解法1 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*logn + k)

解法2 如果k很小,比如第五个最大的数,而整个数组的长度非常的大,那么,还有一种方法就是,我做k遍找最大的数,每做一遍,就把最大的放在数组的最后面(遍历一次找出最大的数例如冒泡,选择排序都可以。),然后减少数组扫描的范围,就可以把第k大的数找出来,这样做的复杂度就是O(K*N),在K很小的情况下,还是不错的。

解法3 利用快速排序的思想,从数组S中随机找出一个元素X,把数组分为两部分SaSbSa中的元素大于等于XSb中元素小于X。第K大的元素在已排序数组中的下标应为index(第K大元素)=数组长度-1。记元素X的下标为index(x),当index(x)= index(第K大元素),表示找到结果,返回。

       这时有两种情况:

           1. index(x)> index(第K大元素),则继续在下标index(x)的左边找

           2. index(x)> index(第K大元素),则继续在下标index(x)的右边找

 解法4 二分[Smin,Smax]查找结果X,统计X在数组中出现,且整个数组中比X大的数目为k-1的数即为第k大数。时间复杂度平均情况为O(n*logn)

解法5:用O(4*n)的方法对原数组建最大堆,然后popk次即可。时间复杂度为O(4*n + k*logn)

解法6:维护一个k大小的最小堆,对于数组中的每一个元素判断与堆顶的大小,若堆顶较大,则不管,否则,弹出堆顶,将当前值插入到堆中。时间复杂度O(n * logk)

解法7利用计数排序的思想,,前面有k-1个数则为第k大数,平均情况下时间复杂度O(n)。

 像解法3和6应该是比较常见的解法:

    下面是解法3的java代码

package com.wj;

/**
 * Created by wangjia .
 * Date:2015/9/5 0005
 * Time:10:53
 */
public class MaxK {
   public int getIndexK(int[] nums, int left, int right, int k) {
    int i = left, j = right;
    while (i < j) {
        while (nums[j] >= nums[left] && i < j) {
            j--;
        }
        //所以交换结束后,需要为第一个基准元素找位置,这个位置就是现在i的位置.
        while (nums[i] < nums[left] && i < j) {
            i++;
        }
        if (i < j) {
            swap(nums, i, j);
        }
    }
    swap(nums, left, i);
    if (k == i) {
        return nums[i];
    } else if (k < i) {
        return getIndexK(nums, left, i - 1, k);
    } else {
        return getIndexK(nums, i + 1, right, k);
    }
}
//交换数组两个数的位置
private void swap(int[] nums, int i, int j) {
    int tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}

public int getK(int[] arr, int k) {
    return getIndexK(arr, 0, arr.length - 1, arr.length - k);
}
}
//时间复杂度:接近O(N)

测试代码:

package com;

import com.wj.MaxK;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/** 
 * MaxK Tester. 
 * Created by wangjia .
 * Date:09/05/2015
 * Time:$Time
 *
*/ 
public class MaxKTest { 
    private MaxK instance;
    @Before
    public void before() throws Exception { 
        instance=new MaxK();
    }
    @After
    public void after() throws Exception { 
        instance=null;
    }
    @Test
    public void testGetK() throws Exception { 
        int[] arr={4, 5, -1, 2, 3};
        Assert.assertEquals(-1,instance.getK(arr, 5));
        Assert.assertEquals(5,instance.getK(arr, 1));
        Assert.assertEquals(4,instance.getK(arr, 2));
        Assert.assertEquals(3,instance.getK(arr, 3));
        Assert.assertEquals(2,instance.getK(arr, 4));
        int[] arr2={-8,11,4,-2,44,56565,23,-232};

        Assert.assertEquals(56565,instance.getK(arr2, 1));
        Assert.assertEquals(44,instance.getK(arr2, 2));
        Assert.assertEquals(-232,instance.getK(arr2, 8));
    }
}

解法6下次再来。

另外给出一些其他的参考文章:http://blog.csdn.net/beiyeqingteng/article/details/6992290

http://job.xdnice.com/content/BiShiJingYan/2012-11/3971.htm

转载于:https://my.oschina.net/dadou/blog/501303

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值