牛客网修炼之路3(桶排序和其中一个运用)

1、桶排序,桶排序的话,适用于一些已经知道确定边界的一些数的排序,时间复杂度,可以做到n,不过空间复杂度也是n。

这里举个例子。比如,对1,3,4,2,3,9 进行排序。这里最小是1,最大是9,所以可以声明一个10长度的数组temp。初始化为0,如下图:

下面的是下标,然后就可以通过遍历上面需要排的数,比如遍历到1,就直接temp[1]++,那么就会使得1的值变成了1,然后遍历

3,temp[3]++,遍历完后,就可以了。入下图:

然后打印就遍历temp,只要不为0,就打印下标,同时值减一。直到减到0

    @Test
	public void bucket() {
		int[] arrs = {1,3,4,2,3,9};
		int[] temp = new int[10];
		for(int i = 0; i< arrs.length; i++) {
			temp[arrs[i]]++;
		}
		
		//打印相应的排序值
		for(int i = 0; i< temp.length; i++) {
			while(temp[i] > 0){
				System.out.println(i);
				temp[i]--;
			}
		}
	}

下面介绍一个桶的运用。

在数组中(没有排序的),找出排好序后,相邻两个数差值最大的那个值。比如数组3,1,4,那么排好序的数组:1,3,4,则最大的差值maxDelta = 2

给出代码:

public static void main(String[] args) {
        int[] arrs = { 100, 100,101 };
        int bucket = bucket(arrs);
        System.out.println(bucket);
    }

    /**
     * 寻找排好序的数中,相邻两数差值最大的值。
     */
    public static int  bucket(int[] arrs) {
        int min = Integer.MAX_VALUE;// 最小值
        int max = Integer.MIN_VALUE;// 最大值
        for (int i = 0; i < arrs.length; i++) {
            min = Integer.min(arrs[i], min);
            max = Integer.max(arrs[i], max);
        }
        //所有的数相等,最大差值为0
        if(min == max) {
            return 0;
        }
        int lent = arrs.length;
        // 找到了最大值和最小值,然后进行分桶的操作,有lent+1个桶,lent+1个桶的原因是最大值和最小之间,肯定会有一个桶是空的
        // , 那么相邻两个数的差值,最大肯定不会出现在桶内部,因为一个空桶之间的最近非空桶,相邻两个数的差值,肯定大于桶内的,所以
        // 不考虑桶内的相邻差值,只考虑桶外,那么一个桶,就只需记录最大值和最小值就可以了。
        boolean[] bucketFlag = new boolean[lent + 1];
        int[] bucketMin = new int[lent + 1];
        int[] bucketMax = new int[lent + 1];
        // 这三个数组,分别是桶内的最大值和最小值和桶标记(桶是否进入过数)
        bucketMin[0] = min;
        bucketMax[lent] = max;
        
        for (int i = 0; i < arrs.length; i++) {
            //寻找数应该放入到哪个桶中。bucketId为桶标记
            int bucketId = findBucket(arrs[i], lent, min, max);
            //更新桶内的最大值和最小值,bucketFlag[bucketId]为false,说明没进过数,那么
            //桶的最大值和最小值都是arrs[i],否则进行比较
            bucketMin[bucketId] = bucketFlag[bucketId]?Integer.min(bucketMin[bucketId], arrs[i]): arrs[i];
            bucketMax[bucketId] = bucketFlag[bucketId]?Integer.max(bucketMax[bucketId], arrs[i]): arrs[i];
            //进入过数好,桶标记为true
            bucketFlag[bucketId] = true;
        }
        
        int lastMax = bucketMax[0];
        int maxDelta = 0;
        int index = 1;
        while(index < lent+1) {
            //为非空桶时才操作
            if(bucketFlag[index]) {
                //当前桶的最小值减去上一个桶的最大值。跟maxDelta比较,保留大的值
                maxDelta = maxDelta > (bucketMin[index] - lastMax) ? maxDelta : (bucketMin[index] - lastMax) ;
                //记录上一个桶的最大值
                lastMax  = bucketMax[index];
            }
            index++;
        }
       return maxDelta;
    }

    private static int findBucket(int num, int lent, int min, int max) {
        //(long)lent 这个是因为,值很大的时候,会超出Integer的最大值
        //这个好难扣,扣不出来,就网上找了下这个公式
        return (int) ((num - min) * (long)lent / (max - min));
    }

这个运用,左老师说经常考,个人感觉,除了扣某个数属于哪个桶比较难,其他代码写起来比较简单点。其实我现在还是不会扣它属于哪个桶,我只是验证了这条式子是对的而已,怎么得出来的,还是不会。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值