最小可用ID(4种方法,详细讲解)

28 篇文章 2 订阅
24 篇文章 1 订阅

最小可用ID:在非负数组(乱序)中找到最小的可分配的id(从1开始编号),数据量1000000
在这里插入图片描述
上面的数组的最小可用ID为1
在这里插入图片描述
这个数组的最小可用ID就为16
方法一:暴力解法------时间复杂度高O(n^2)

package smallid;

import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;

public class smallid {
	static class Util{
		static int indexOf(int[] arr,int i) {  //声明方法
			return i;
		}
	}
	//暴力解法O(n^2),从1开始依次探测每一个自然数是否在数组中
	static int find1(int[] arr){
		int i=1;   //i从1开始
		while(true) {
			if(Util.indexOf(arr,i) == -1){   //找到没有的那个数返回
				return i;
			}
			i++;  //若不是,继续循环
		}
	}
}

方法二:快速排序,让数组变得有序后找出缺少的数------时间复杂度O(nlogn)

package smallid;

public class Smallidk {
	static class Array{
	 static void sort(int[] arr) {  //声明方法
		return ;
	}
	int find2(int[] arr){
		Array.sort(arr);   //对数组进行排序
		int i=0;     //数组下标从0开始  ,i为数组下标
		while(i<arr.length) {
			if(i+1!=arr[i]) {    //当数组下标和对应的数不匹配时
				return i+1;  //返回对应缺少的数
			}
			i++;  //否则,继续循环
		}
		return i+1;
	}
}
}

方法三:利用辅助数组进行扫描-------时间复杂度O(n)
在这里插入图片描述
辅助空间的数组下标表示该下标元素出现的次数
伪代码

 helper=[A.length]
  for(i:0.....A.length-1)
  helper[A[i]-1=1;  //下标转为数字
  }
  for(i:0......A.length-1 //扫描辅助空间
  if(helper[i]==0)  //若help的下标没有系数为1
  return i+1;
  }
  return A.length+1;

代码

package smallid;

import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;

import sun.applet.Main;

public class Smallid2 {
    public static int find3(int[] arr) {
    	int n=arr.length;  //定义数组长度
    	int[] helper=new int [n+1];  //定义辅助空间
    	for(int i=0;i<n;i++) {  //构造辅助数组
    		helper[arr[i]]=1;  
    	}
    	for(int i=1;i<=n;i++) {  //扫描辅助数组
    		if(helper[i]==0) {   //如果辅助空间数组下标出现次数为0
    			return i;  //返回该元素
    		}
    	}
    	return n+1;  //若数组长度范围内度存在,则返回n+1
    }
    public static void main(String[] args) {
		int[] arr= {1,2,3,4,5,8,9,10,11,12};
		long now=System.currentTimeMillis();
		Object find2;
		Smallidk find2=new Smallidk();
		System.out.println(find2(arr));
		Util.duration(now);
		
		now=System.currentTimeMillis();
		System.out.println(find3(arr));
		Util.duration(now);
	}
}

方法四:区间分割法
在这里插入图片描述
假设一个长度为100的数组
分为以下三种情况;
1.中间值恰好为50时,表明数组左半区间数字元素紧凑,没有要找的缺少元素
2.中间值为大于50的值,表明数组左半区间有漏掉的元素

package smallid;
public class Smallidfenqu {
	public static int find4(int[] arr,int l,int r) {  //定义数组,左指针,右指针
		if(l>r)
			return l+1;
		int midIndx=l+((r-l)>>1);   //中间下标,用右指针减去左指针加1
		int q=selectk(arr,l,r,midIndex-l+1);  //实际中间位置的值
		int t=midIndex+1;  //t为要求的期望值
		if(q==t) {  //左侧紧密
			return find4(arr,midIndex+1,r);  //在右半区间查找
		}
		else {   //左侧稀疏
			return find4(arr,l,midIndex-1);  //在左半区间查找
		}
	}
  public static void main(String[] args) {
	int[] arr= {1,2,3,4,5,8,9,10,11,10000};
	arr=new int[1000*1000];
  }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值