leetcode164-无序数组排序后的最大相邻差值

在这里插入图片描述
刷这道题是因为网上一篇文章《漫画算法:无序数组排序后的最大相邻差值》感兴趣,其中方法一先排序,遍历求解时间复杂度为N*log(N)过高不合适,方法二用计数法因为空间复杂度过高也不合适,方法三用到的同桶排序,看文章的时候觉得非常合理,现实刷题过程中发现文章有很多的细节问题,比如作者认为桶的个数为len+1,最大距离必定产生在一个空桶的左右,这些只有在刷题的过程中才会发现细节问题。本题最大的一个思路就是保证最大距离在桶间,而不是桶内,最小的值放第一个桶,最大的值放最后一个桶。笔者认为刷题还是自己动手写下代码才能感受到其中的细节和体会到里面的乐趣。本题的很多细节放在代码注释中,读者可以根据代码和注释慢慢理解、解决本题。

package no151_200;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class subject164 {
	/**
	 * 
	 * @author cehkongfu
	 * @time 2019.06.04 20:30~22:00
	 *
	 */
	class Solution {
		public int maximumGap(int[] nums) {
			int len = 0;
			//数据预处理:对数据进行去重
			HashMap<Integer, Integer> map = new HashMap<Integer,Integer>();
			for(int i=0; i<nums.length; i++) {
				if(!map.containsKey(nums[i])) {
					map.put(nums[i], 1);
					len++;
				}else {
					map.put(nums[i], map.get(nums[i])+1);
				}
			}
			int[] noRepeatNums = new int[len];
			int index=0;
			for(Integer key:map.keySet()) {
				noRepeatNums[index++] = key;
			}
			return maximumGap2(noRepeatNums);
		}
	    public int maximumGap2(int[] nums) {
	        int len = nums.length;
	        if(len<2) return 0;
	        int min=Integer.MAX_VALUE, max=Integer.MIN_VALUE;
	        //第一个循环找出最大、最小值
	        for(int i=0; i<len; i++) {
	        	if(nums[i]<min) {
	        		min = nums[i];
	        	}
	        	if(nums[i]>max) {
	        		max = nums[i];
	        	}
	        }
	        int gap = max - min ;
	        if(gap==1) return 1;
	        int bucketSize = (gap+1)/len;	//此处很奥妙,gap不加1会出现越界问题,最大的数会放到最后一个桶的后面的一个不存在的桶里面
	        int bucketLen = (int) Math.ceil((gap+1)*1.0/bucketSize);

	        List[] bucket = new List[bucketLen];
	        //第二个循环,把所有数据放入合适的桶中
	        //数组中元素个数是len,桶的个数是len或者len+1,这样能保证最小的数字和最大的数字分别在第一个桶和最后一个桶
	        //这样最大的桶间距就是所求的结果
	        for(int i=0; i<len; i++) {
	        	int index = (nums[i]-min)/bucketSize;
	        	
	        	if(bucket[index]==null) {
	        		ArrayList<Integer> list = new ArrayList<Integer>();
	        		list.add(nums[i]);//list.get(0)放最小数
	        		list.add(nums[i]);//list.get(1)放最大数
	        		list.add(nums[i]);
	        		bucket[index] = list;
	        	}else {
	        		ArrayList<Integer> list = (ArrayList<Integer>)bucket[index];
	        		if(nums[i]<list.get(0)) {
	        			list.set(0, nums[i]);
	        		} else if(nums[i]>list.get(1)) {
	        			list.set(1, nums[i]);
	        		}
	        		list.add(nums[i]);
	        	}
	        }
	        
	        //第三个循环,找出最大桶间距,注意:第一个桶和最后一个桶分别有最小数和最大数
	        int result = 0;
	        int leftMax = Integer.MIN_VALUE;
	        int rightMin = Integer.MAX_VALUE;
	        for(int i=1; i<bucket.length; i++) {//前面的桶取最小数,当前桶取最大数
	        	//前一个桶不为空,并且大左值没有求出来
	        	if(bucket[i-1]!=null&&leftMax==Integer.MIN_VALUE) {
					ArrayList<Integer> list = (ArrayList<Integer>)bucket[i-1];
					int tmp = list.get(1);
					if(tmp>leftMax) {
						leftMax = tmp;
					}
	        	}
	        	//当前桶不为空
	        	if(bucket[i]!=null) {
	        		ArrayList<Integer> list = (ArrayList<Integer>)bucket[i];
					int tmp = list.get(0);
					if(tmp<rightMin) {
						rightMin = tmp;
					}
	        	}
	        	
				if(leftMax!=Integer.MIN_VALUE&&rightMin!=Integer.MAX_VALUE) {
					int tmp = rightMin- leftMax ;
					if(tmp>result) {
						result = tmp;
						if(tmp==7) {
							System.out.println("test");
						}
					}
					//重置max,min
					leftMax = Integer.MIN_VALUE;
					rightMin = Integer.MAX_VALUE;
				}
	        }

	        
	        return result;
	    }
	}

	public static void main(String[] args) {
		subject164 subject = new subject164();
		Solution s = subject.new Solution();
		
		int[] nums = { 0,6,3,16,7,10,9,11,20,18 };
		//int[] nums = {1,1,2,1  };
		//int[] nums = {92,30851,24320,20449,7333,29396,10949,17319,9810,26639,20622,3359,14259,4050,21966,22269,24440,20895,2386,25837,628,12174,4901,29663,2720,18750,15281,29858,1891,2833,11814,21685,8976,23961,14880,18778,4529,26957,22660,20715,23811,17025,30634,24177,12737,4501,21186,25459,4645,2924,22640,11276,4525,19999,25786,16704,32283,30195,21028,17808,6591,32393,9753,32716,19192,17493,23693,2089,25849,14929,5857,19348,28105,10227,12807,22853,1421,860,2022,11926,21258,15314,24576,29974,6502,2160,21330,26329,23342,3868,10107,19731,11934,30650,25889,19685,10012,16287,11665,30327,30725,24905,5029,19015,13484,9293,31723,10433,20896,10640,18435,24591,19246,1978,20809,19506,5415,3048,30389,15698,14308,29346,16895,6226,16006,11532,26630,26024,23170,1632,10354,17004,24670,15771,20632,26542,437,26487,26015,15373,26753,11418,14817,9093,6042,14349,29076,393,13433,27119,15018,8530,7746,8811,15349,30838,30210,14567,32655,30652,31796,29566,23673,24111,26507,4785,9090,17009,6379,17753,4971,18002,20664,6368,22600,10401,18772,14769,6697,10563,23267,6125,24314,29569,3154,17504,17320,678,13719,6579,20614,13514,5946,1507,27886,32745,2836,2034,13867,32056,12887,13788,15766,16056,17614,24268,29184,8971,25958,7568,14416,7047,8174,28490,30573,6281,29723,8809,7007,4107,4559,12760,21425,21113,10906,24693,4377,8641,31874,10437,1627,16042,31231,21734,12394,24678,13130,21189,10704,19050,25815,6289,19793,29821,20256,11631,27595,30991,15269,10863,6497,15821,21297,18366,21976,2674,10590,18974,5185,480,8539,25748,26073,12655,4077,25184,19501,10885,16052,11570,30338,23143,13488,923,28275,5198,26628,29634,30684,446,15609,28248,10231,27923,30277,1486,30661,6749,31374,11717,21936,8813,4906,3782,31342,1072,2089,16947,1320,24636,15765,2685,8924,4777,13816,23448,17664,7970,7711,18348,11112,9019,17950,9230,17769,17157,11156,31342,11839,17377,31024,6738,18604,18833,8052,24259,15842,27029,27321,31813,25507,2228,14964,27405,19879,14041,15799,16751,3646,32032,22779,4758,27190,21041,6428,9591,1023,10445,22437,6151,16909,19622,29774,17068,29822,372,18371,28658,32253,6213,13223,15488,998,28436,29657,13130,27050,3742,5366,31240,7030,23153,13343,8678,27663,1862,27644,28797,2561,19344,4864,13570,20472,32341,12015,32189,29806,6205,16798,16829,23686,19177,21243,21195,5688,8837,23628,11164,15791,26017,30908,28235,20975,10044,32531,9990,15547,16162,26821,9991,4534,7289,10798,3013,18632,9878,24604,18028,30659,8213,30350,14219,20295,16424,11451,13069,24291,30255,6742,107,25724,2953,6673,11040,10995,6058,15712,14172,15362,31342,11647,3836,26983,20653,7606,15034,28997,5904,13020,15265,16839,28451,1050,6341,8198,15019,6385,30000,13869,313,2174,16927,19675,21503,7677,24943,13256,9187,9869,19538,7596,15826,19506,4678,29532,24919,8736,17480,25142,9580,17975,8260,10688,8080,15306,4305,27788,281,25508,21787,2143,7884,13645,25888,14737,5803,7561,26144,3511,2062,9762,17230,27008,4597,19175,16076,9693,2973,8181,3798,2149,11089,11573,23358,6903,3971,8998,12056,9889,24091,19677,12982,21952,28175,25418,16855,16745,12084,9660,12827,28168,17492,23463,23994,31559,896,9126,18038,2866,20647,13244,25806,9368,1640,28383,30581,5300,24869,29623,26370,5132,8281,2211,4585,12954,21035,2301,5290,20266,32067,14239,25160,7683,7388,6821,16637,713,8986,17525,32556,16802,30110,11773,29847,19352,6233,1596,9170,10815,31389,6916,4088,20119,6778,16126,6812,18227,29255,20718,32258,8603,25727,18488,14223,31472,6607,27300,30335,974,1388,3934,25302,31606,938,4929,20633,26157,18123,25172,13117,735,1556,14997,25952,17416,8999,3062,6327,20437,14732,6566,584,19334,19601,16529,5849,30230,1876,1834,27560,22046,17182,23144,3932,32503,18418,7182,28476,12574,31590,26160,7327,23005,29106,10227,1699,13864,5383,32660,31778,7366,22306,30124,2530,13233,8480,32178,2316,5310,30100,24513,29152,9600,30935,28571,18086,9834,21407,13551,10984,15669,9171,26839,31454,32385,28574,27813,30506,15039,20163,7647,22726,4686,15920,11144,24890,5348,20949,20641,15122,28720,14518,6128,16015,29118,18239,3328,28317,24602,31704,32361,16901,28472,12730,13649,3300,21523,30209,17971,7772,15253,13058,24288,26249,10423,9694,13763,14518,32233,21080,32360,32209,13748,26851,1856,27421,3742,21247,25758,4391,11854,22982,19718,22267,32752,6850,2727,13719,20955,16130,9766,18336,30321,10349,11933,340,27719,2390,17124,9408,20871,6736,16399,17971,9874,25155,14647,29938,9193,17599,7294,23597,10061,19089,10573,28722,31781,22676,7136,31713,801,18634,12805,8800,32029,6571,27936,10512,32072,10173,13683,7615,18053,9573,17052,11551,6161,17661,27999,15734,11622,18726,20134,8600,30048,28512,20422,30739,17567,26840,4100,2729,1836,21888,17240,16899,13663,30053,28273,419,4096,1086,9208,27,26540,29504,10009,28540,29562,30010,5952,2578,31455,4317,2336,22350,22223,11611,12538,15620,3621,19765,540,12503,4421,27469,26536,7665,22784,11843,31382,21239,27832,26110,22780,3131,5060,1929,653,28212,13845,6945,24160,1068,12314,20620,19956,5945,7650,11692,29040,29038,24961,2899,303,24914,26804,21593,24699,4497,30152,15084,19865,2290,28599,22568,21255,26249,32149,27111,24065,11822,28970,8923,7753,14638,17633,16602,4904,8000,12513,23928,27056,11194,7033,11483,4165,13060,26817,7883,9052,23629,28030,5641,6017,13182,2375,10722,17567,5996,11238,9731,13948,22610,18945,15503,26243,6782,1274,7791,17094,20810,2579,28138,9795,26190,27862,16245,9830,24788,180,7372,22992,8588,30188,15937,31831,1666,15790,28244,5198,2892,31104,19333,32006,14728,31202,23654,31380,32134,4141,10740,15061,13121,14273,21543,26544,32660,23135,21704,11931,18858,13268,25731,24929,26807,6360,13885,5154,23013,9525,31912,23707,4754,5420,28180,5799,17080,19988,14984,20998,7084,23108,10257,19806,28428,23603,18778,8831,14834,15582,637,2027,28782,6506,20505,19350,7476,13323,1189,27370,10641,27684,28675,27662,24996,432,9560,23656,2250,10208,21276,6241,4698,11013,24941,16488,21139,11697,19113,32569,15314,16665,25147,1375,31752,23742,32181,24055,3692,31053,13344,184,5485,21187,10127,17712,4331,5588,3323,6992,17574,31886,26186,11563,25335,7738,8881,19963,20414,30339,6460,23141,3995,26586,4523,28158,14177,15640,20352,4621,28615,28261,21334,18835,24929,11609,18036,7816,7375,31842,17570,5224,21301,21862,30780,9198,29419,9129,15492,9247,31861,5360,14908,17547,9141,1511,12917,31952,4447,3520,27554,5471,22702,27933,29936,11651,30037,25648,13274,25247,26041,13344,28663,31927,13661,20399,20759,17457,2973,32539,911,25821,4768,31553,30417,564,19080,17416,27200,24797,7403,13821,15426,18806,17543,9019,12182,2192,23857,29582,6888,12283,12303,4056,13986,32069,4103,7347,32006};
		int result = s.maximumGap(nums);
		System.out.println(result);

	}
}

在这里插入图片描述
以下代码是按照《漫画》算法中的思路写出来的,总体上来讲条理性更强一点,代码如下:

public class Solution {

    public int maximumGap(int[] array){
    	if(array.length < 2) return 0;
        //1.得到数列的最大值和最小值
        int max = array[0];
        int min = array[0];
        for(int i=1; i<array.length; i++) {
            if(array[i] > max) {
                max = array[i];
            }
            if(array[i] < min) {
                min = array[i];
            }
        }
        int d = max - min;
        //如果maxmin相等,说明数组所有元素都相等,返回0
        if(d == 0){
            return 0;
        }

        //2.初始化桶
        int bucketNum = array.length+1;
        Bucket[] buckets = new Bucket[bucketNum];
        for(int i = 0; i < bucketNum; i++){
            buckets[i] = new Bucket();
        }
        int index = 0;
        int bucketSize = (int)Math.ceil(d*1.0/ (bucketNum-1));
        //3.遍历原始数组,确定每个桶的最大最小值
        for(int i = 0; i < array.length; i++){
            //确定数组元素所归属的桶下标
            index = ((array[i] - min)  / bucketSize);
            System.out.println(array[i]+min+":"+":"+index+":"+":"+bucketSize+":"+d);
            if(buckets[index].min==null || buckets[index].min>array[i]){
                buckets[index].min = array[i];
            }
            if(buckets[index].max==null || buckets[index].max<array[i]){
                buckets[index].max = array[i];
            }
        }

        //4.遍历桶,找到最大差值
        int leftMax = buckets[0].max;
        int maxDistance = 0;
        for (int i=1; i<buckets.length; i++) {
            if (buckets[i].min == null) {
                continue;
            }
            if (buckets[i].min - leftMax > maxDistance) {
                maxDistance = buckets[i].min - leftMax;
            }
            leftMax = buckets[i].max;
        }

        return maxDistance;
    }

    /**
     **/
    private static class Bucket {
        Integer min;
        Integer max;
    }

    public static void main(String[] args) {
        int[] array = new int[] {601408776,63967816,431363697,242509930,15970592,60284088,228037800,147629558,220782926,55455864,456541040,106650540,17290078,52153098,103139530,294196042,16568100,426864152,61916064,657788565,166159446,1741650,101791800,28206276,6223796,524849590,125389882,84399672,153834912,164568204,1866165,283209696,560993994,16266096,219635658,9188983,485969304,782013650,120332636,44659356,444517408,36369045,47370708,18542592,98802990,137690000,124889895,56062800,265421676,309417680,4634176,801661539,510541206,258227892,398938089,47255754,152260962,409663140,102847688,45756553,377936600,269498,375738702,263761134,53797945,329493948,224442208,508336845,189507850,40944620,127879560,119629476,186894520,62409156,693721503,4289916,523899936,28955240,266488028,20356650,40769391,483694272,97988044,84102,67246047,310688630,41288643,58965588,42881432,152159462,94786355,174917835,119224652,525034376,261516,274800528,62643819,23613832,8397240,797832131,855155367,337066320,26341480,61932200,20661075,515542796,390337500,522552030,43538516,150800550,116747540,152989123,488640056,700610304,233604,344277340,21439176,9397864,16365822,73027584,453041413,197374275,157735188,15273822,187081152,379611084,865005504,223099767,80478651,377729400,186738219,34738263,16634072,112791343,99631856,119364960,477106486,583953920,624509809,188442472,294181256,213023715,146645884,149530380,497592753,132170327,72770643,126683010,405141255,590214306,26670714,95582385,162080790,231120099,8946432,204967980,592849110,54120698,375915096,602145859,5346440,226337825,425156369,653591624,578483360,572410800,32290700,381384563,149939976,183225375,155695620,38307636,457513760,97085778,75200576,8068176,221650296,556889418,252495726,895020231,19932465,156334887,191383314,348432526,368701264,14315598,148936587,279419435,237325542,252587218,322929504,26331343,355297676,600420786,652017765,51673622,159015675};
    	//int[] array = {1,1,1,1,5,5,5,5};
        System.out.println(new Solution().maximumGap(array));
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东心十

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值