题目:找到一个乱序列表里面最小可分配的ID号,ID唯一且非负
解法一:
从0开始遍历,判断x是否是列表中的数,是的话换下一个数判断。如果不是,则是最小可分配ID.
int judege_num(int target, int arr[])
{
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
if (arr[i] == target) {
return false;
}
}
return true;
}
int find_num(int lst[])
{
int i=0;
while(1)
{
int flag=judge_num(i,lst);
if(flag)
{
return i;
}
i++;
}
}
解法二:
对于n个ID,如果存在小于n的可用ID,必然存在某个ID不在[0,n)这个范围内。否则这些ID⼀定是0到(n-1)的某个排列,这种情况下,最小的可用ID是n。
简单来说就是现在有十七个人(每个人有自己的编号&&随便坐),他要么坐满0~16号座位,要么有人坐到16号以后。
使用⼀个长度为n + 1的数组,来标记区间[0,n]内ID是否可用,长度为n+1是因为n-0+1。由于只有可用/不可用两种状态,可以用位标记状态。
初始化数组->小于n则标为1->遍历从0到 n 的所有数字,第一个未标记的数字就是最小的缺失非负整数,将其返回
#define N 1000000 // 1 million
#define WORD_LENGTH sizeof(int) * 8
void setbit(unsigned int* bits, unsigned int i) {
bits[i / WORD_LENGTH] |= 1<<(i % WORD_LENGTH);
}
int testbit(unsigned int* bits, unsigned int i) {
return bits[i/WORD_LENGTH] & (1<<(i % WORD_LENGTH));
}
unsigned int bits[N/WORD_LENGTH+1];
int min_free(int* xs, int n) {
int i, len = N/WORD_LENGTH+1;
for(i=0; i<len; ++i)
bits[i]=0;
for(i=0; i<n; ++i)
if(xs[i]<n)
setbit(bits, xs[i]);
for(i=0; i<=n; ++i)
if(!testbit(bits, i))
return i;
}
优化一般从时间和空间考虑,解法二使用数组,用空间换取了时间,数组很大的时候,空间带来的性能问题不得不考虑。
解法三:
将问题分解,ID值小于等于n/2(向下取整)的放序列1,其余放序列2.
还是用座位比喻,演唱会有分区,第一个区域坐满,第二区域(从n/2向下取整+1到n)肯定有空位置。
分而治之:http://t.csdnimg.cn/br7FF
用归并排序理解分而治之:将序列分组,组内排序后,合并排序,直至最后一次合并排序。
使用递归的方式,减小问题规模。函数入口参数增加上下界下标。
#include <stdio.h>
#include <limits.h>
int find_min_available_id(int arr[], int start, int end) {
if (start == end) {
return arr[start];
}
int mid = (start + end) / 2;
int left_min = find_min_available_id(arr, start, mid);
int right_min = find_min_available_id(arr, mid + 1, end);
return left_min < right_min ? left_min : right_min;
}
int main() {
int arr[] = {5, 3, 8, 1, 6};
int n = sizeof(arr) / sizeof(arr[0]);
int min_id = find_min_available_id(arr, 0, n - 1);
printf("The minimum available ID is: %d", min_id);
return 0;
}
解法四:
优化解法三的栈较大的问题,采用迭代的方式替代递归:
int min_free(int* xs, int n) {
int l=0;
int u=n-1;
while(n) {
int m = (l + u) / 2;
int right, left = 0;
for(right = 0; right < n; ++ right)
if(xs[right] <= m) {
swap(xs[left], xs[right]);
++left;
}
if(left == m - l + 1) {
xs = xs + left;
n = n - left;
l = m+1;
} else {
n = left;
u = m;
}
}
return l;
}