一个数组的元素为1~n,在o(n)的时间内对数组排序

                                                                                                                                  点击此处返回总目录

 

一、长度为len的数组元素刚好为1-n,对数组进行排序。

【题目】

比如数组:[10,6,9,5,2,8,4,7,1,3] 

希望得到:[1,2,3,4,5,6,7,8,9,10]

 

【分析】

对于一般的数组,排序要花nlogn的时间。

但是,如果一个数组,长度为n。元素刚好是1~n。对这n个数排序,可以在o(n)时间内完成。

代码如下:

for(int i = 0 ;i<nums.length;i++){

     while(nums[i] != i+1){

           swap(nums[i], nums[nums[i]-1]);

     }

}

 

比如:

  [10,6,9,5,2,8,4,7,1,3 ]  //a[0]!=1。把10和3交换
  [3, 6,9,5,2,8,4,7,1,10]   //10已经归位。a[0]!=1。把3和9交换。
  [9, 6,3,5,2,8,4,7,1,10]   //3已经归位。a[0]!=1。把9和1交换。
  [1, 6,3,5,2,8,4,7,9,10]   //9已经归位。a[0]=1。1已经归位。a[1]!=2。把6,8交换。
  [1, 8,3,5,2,6,4,7,9,10]   //6已经归位。a[1]!=2。8和7交换。
  [1, 7,3,5,2,6,4,8,9,10]   //8已经归位。a[1]!=1。7和4交换。

  [14,3,5,2,6,7,8,9,10]   //7已经归位。a[1]!=1。4和5交换。

  [1, 5,3,4,2,6,7,8,9,10]   //4已经归位。a[1]!=2,5和2交换。

  [1, 2,3,4,5,6,7,8,9,10]   //5已经归位。顺次检查到最后,都不需要交换。

 

当第一个位置不是10的时候,就把10和应该放10的元素交换,这样10就放到应该放的位置了。

再看看第一位置是多少,不是1,就把这个元素放到应该放的位置。直到第一个元素是1。

接下来再看看第二个位置是不是2,不是就放到应该放的位置。

...

 

【代码】

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

【结果】

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

二、有重复数字的情况下,把数字排序。

【题目】

数组长度为n,元素为1-n。其中某些数字被其他的替换了。

希望没有被替换的数字放到本来的位置。

比如数组:[10,6,9,3,2,8,4,7,1,3 ]

希望得到:[1,2,3,4,3,6,7,8,9,10 ]

 

【分析】

比如,[10,6,9,3,2,8,4,7,1,3 ],其中5被3代替了。

按照前面思想,我们可以把数组的元素摆到应该存放的位置,我们想通过排序变为:[1,2,3,4,3,6,7,8,9,10]。除了这个3,其他的都归位。

 

但是上面的算法就不能直接用了。因为会导致无线循环。

  [10,6,9,3,2,8,4,7,1,3 ]   //a[0]!=1。把10和3交换
  [3, 6,9,3,2,8,4,7,1,10]   //10已经归位。a[0]!=1。把3和9交换。
  [9, 6,3,3,2,8,4,7,1,10]   //3已经归位。a[0]!=1。把9和1交换。
  [1, 6,3,3,2,8,4,7,9,10]   //9已经归位。a[0]=1。1已经归位。a[1]!=2。把6,8交换。
  [1, 8,3,3,2,6,4,7,9,10]   //6已经归位。a[1]!=2。8和7交换。
  [1, 7,3,3,2,6,4,8,9,10]   //8已经归位。a[1]!=1。7和4交换。

  [14,3,3,2,6,7,8,9,10]   //7已经归位。a[1]!=1。4和3交换。

  [1, 3,3,4,2,6,7,8,9,10]   //4已经归位。a[1]!=2,3和3交换。

  [1, 3,3,4,2,6,7,8,9,10]   //交换之后,a[1]还是3,不是2。继续交换。。。最后导致无限循环

 

导致无限循环的原因是,有相同的元素。当两个交换的元素相同时,交换之后不变。这样就会一直交换下去。

 

所以要在代码中加入一个判断,当交换的两个元素值相等时,就不交换了。

 

【代码】

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

【结果】

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

【其他情况一】

如果一个数字重复出现几次,也不影响。

比如,5和8都被3替换了,排序后除了5,8,其他也能归位。

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

【其他情况二】

如果被不止一个数字代替了,也不影响。

比如5,7,8被3和4代替了,其他数字也能归位。

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

 

 

 

三、只对符合要求的数字排序

我们进一步延伸一下,如果数组为:

[-3,2,5,6,-9,0,7,-3,8,10]

我们能不能得到:[?,2,?,?,5,6,7,8,?,10]

 

只要在while中写明条件即可。

 

【代码】

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

【结果】

一个数组的元素为1~n,在o(n)的时间内对数组排序

 

【延伸】

对于上面的数组,我只想让6,7,8归位。其他不管。

只要控制条件即可。

 

一个数组的元素为1~n,在o(n)的时间内对数组排序