排序、数组——数组中重复的数字和first missing positive(桶排序)


题目:找到数组中不存在的第一个正整数。


For example,
Given[1,2,0]return3,
and[3,4,-1,1]return2.

要求O(N)时间复杂度,O(1)空间复杂度。


解法:

 若用桶排序则空间复杂度为O(N)。


关于桶排序

1,桶排序是稳定的(桶内使用插入排序)

2,桶排序时间复杂度可以达到O(N),

3,一般情况下,空间复杂度为O(N)。

桶排序要求:无序数组的成员隶属于固定(有限的)的区间,如范围为[0-9](考试分数为1-100等),以方便建桶。

基本思想:是将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
         简单来说,就是把数据分组,放在一个个的桶中,然后对每个桶里面的再进行排序。  

         桶排序理想的情况下各桶中的元素个数平均分布 ,实际应用中效果并没有这么好。如果所有的数字都落在同一个桶中,那就退化成一般的排序了。 


桶排序代码如下:

 public int firstMissingPositive(int[] A) {
        if(A == null||A.length == 0)
            return 1;
        
        int []bucket=new int[A.length];
        //当A中元素为1-A.length时为理想情况;
        for(int i=0;i<A.length;i++)
            {
            if(A[i]>0&&A[i]<=A.length)//只把满足条件的元素入桶,即1-A.length内的元素;
               {
                bucket[A[i]-1]=A[i];
            }
        }
        for(int i=0;i<bucket.length;i++)
            {
            if(bucket[i]!=i+1)
                {
                return i+1;
            }
        }
             return A.length+1;//当为理想情况时,返回A.length+1,即第一个missing的positive;  
    }

       *该题中利用bucketSort的思想,进行原地排序,即若 A[i] == x (x!=i+1)(并且前提x满足x>0&&x<=A.length),则将x放到它该在的位置,该数组下标为(x-1)的地方,即A[x-1]=x;再次遍历数组A时,找第一个A[i]!=i+1的数。*


public int firstMissingPositive(int[] A) {
        if(A == null||A.length == 0)
            return 1;
        
        for(int i=0;i<A.length;i++)
            {
          //将满足条件的值进行交换,注意:A[i]!=A[A[i]-1] 防止出现死循环!
           while(A[i]>=1&&A[i]<=A.length&&A[i]!=i+1&&A[i]!=A[A[i]-1])
                {
                swap(A,i,A[i]-1);
            }
        }
        for(int i=0;i<A.length;i++)
            {
            if(A[i]!=i+1)
                return i+1;
        }
        return A.length+1;//当为理想情况时,返回A.length+1,即第一个missing的positive;  
    }
    //swap例程
    public void swap(int[] data,int i,int j)
        {
        int temp=data[i];
        data[i]=data[j];
        data[j]=temp;
    }


题目描述:数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。

注意交换的写法,若写成

int temp=A[i];
A[i]=A[A[i]-1];
A[A[i]-1]=temp;

第三行中A[i]已不再是之前的值。

一:普通桶排序,构建一个大小为n的桶;

  public boolean duplicate(int numbers[],int length,int [] duplication) {
     if(numbers == null||numbers.length < 2)
         return false;
        int[]count=new int[length];
        for(int i=0;i<length;i++)
            {
            if(count[numbers[i]] == 1)
                {
                duplication[0]=numbers[i];
                return true;
            }else
                {
                count[numbers[i]]++;
            }
        }
        return false;
    }
二:原地排序
 public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers == null||numbers.length<2)
            return false;
        for(int i=0;i<length;i++)
            {
            while(numbers[i]!=i)
                {
                if(numbers[numbers[i]]!=numbers[i])
                    {
                    int temp=numbers[numbers[i]];
                    numbers[numbers[i]]=numbers[i];
                    numbers[i]=temp;
                }else
                    {
                    duplication[0]=numbers[i];
                    return true;
                }
            }
        }
        return false;
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值