题4:最小可用ID

题目:

在非负数组(乱序)中找到最小可分配的id(从1开始编号),数据量1000000

思路:

第一种方法:暴力解法 时间复杂度O(n²)
从1开始探测每个自然数是否在数组中
第二种方法:先排序,再找第一个缺失数
时间复杂度O(NlgN)

第三种方法:开辟一个辅助空间
改进1
先建一个长度为n+1的数组helper,初始值全为0或false,扫描原数组中的数,小于n则将helper[a[i]]置为1或true
最后再扫描数组helper,返回值为0或false的小标

第四种方法:分区和递归
package 分治法;

import java.util.Arrays;

public class case05_最小可用ID {
    public static void main(String[] args) {
        int[] arr={1,2,3,4,5,7,8,9,11};
        System.out.println(solve3(arr));
        System.out.println(solve4(arr,0,8));
    }
    //第一种方法:暴力解法 时间复杂度O(n²)
    //从1开始探测每个自然数是否在数组中
    //static int solve1(int[] arr){
    //    int i=1;
    //    while(true){
    //        if(indexOf(arr,i)==-1){
    //            return i;
    //        }
    //        i++;
    //    }
    //}

    //第二种方法:先排序,再找第一个缺失数
    //时间复杂度O(NlgN)
    static int solve2(int[] arr){
        Arrays.sort(arr);
        int i=0;
        while(i<arr.length){
            if(i+1!=arr[i]){
                return i+1;
            }
            i++;
        }
        return i+1;
    }

    //第三种方法:开辟一个辅助空间
    /**改进1
     * 先建一个长度为n+1的数组helper,初始值全为0或false,扫描原数组中的数,小于n则将helper[a[i]]置为1或true
     *最后再扫描数组helper,返回值为0或false的小标
     */
    public static int solve3(int[] arr){
        int n=arr.length;
        int[] helper=new int[n+1];
        for(int i=0;i<n;i++){
            if(arr[i]<n+1) {
                helper[arr[i]] = 1;
            }
        }
        for(int i=1;i<=n;i++){
            if(helper[i]==0){
                return i;
            }
        }
        return n+1;
    }

    //第四种方法:分区、递归
    public static int solve4(int[] arr,int l,int r){
        if(l>r){
           return l+1;
        }
        int midIndex=l+((r-l)>>1);//中间下标
        int q=selectK(arr,l,r,midIndex-l+1);//返回中间下标实际对应的值
        int t=midIndex+1;//期望值
        if(q==t){//左侧紧密
            return solve4(arr,midIndex+1,r);
        }else{
            return solve4(arr,l,midIndex-1);
        }

    }
    public static int selectK(int[] A,int p,int r,int k){
        int q=partion(A,p,r);//主元下标
        int qk=q-p+1;//主元是第几个元素
        if(qk==k) {
            return A[q];
        }else if(qk>k){
            return selectK(A,p,q-1,k);
        }else{
            return selectK(A,q+1,r,k-qk);
        }


    }
    private static int partion(int[] A, int p, int r) {
        int pivot=A[p];
        int sp=p+1;//扫描指针
        int bigger=r;//右侧指针
        while(sp<=bigger){
            if(A[sp]<=pivot){
                sp++;//扫描元素小于主元指针右移
            }else{
                swap(A,sp,bigger);
                bigger--;//扫描元素大于主元,二指针所指元素交换,右侧指针左移
            }
        }
        swap(A,p,bigger);
        return bigger;
    }

    private static void swap(int[] A, int sp, int bigger) {
        int temp=A[sp];
        A[sp]=A[bigger];
        A[bigger]=temp;
    }


}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值