【Algorithm】二分法

来源:互联网 发布:美蓝漫画无法连接网络 编辑:程序博客网 时间:2024/06/05 17:27

题目:
有2个数组,原始数组和部分数据被删减后的数组
数组长度未知,仅可以通过get函数去取两个数组中的值
get的值为0时,表示超过数组长度
要求用最少的次数,找到被删减掉的全部数据

思路:
1)确定两个数组的长度
用二分法查找第一个不为0的数,那么这个数的位置就是数组的长度

int get_list_length(int file, int l, int r){    if(l>r) return l;    int mid = (l+r)/2;    if(get(file,mid)>0)         return get_list_length(file,mid+1,r);    else         return get_list_length(file,l,mid-1);}

2) 两个数组的长度确定后,那么就可以知道被删减的数据的长度,就是两个长度的差值

3)从左右两侧开始找第一个被删除的数和最后一个被删除的数,存入记录删除数据的数组中,这样二分查找的长度不断在减小

要知道左侧第一个被删的数据同样需要二分法,只有找到左侧第一个不相等的数据就可以了
难点在于找下一个,这里有一个差值offset,因为之前已经删了,两个坐标就不是一一对应,新数组的坐标应该减去offset

int get_the_first_delete_data(int l, int r, int offset){  if (l>r)return l;  int mid = (l+r)/2;  if(get(1,mid) != get(2, mid-offset))         return get_the_first_delete_data(file,mid+1,r);    else         return get_the_first_delete_data(file,l,mid-1);}

找右侧最后一个也是同样的原理,只不过条件是反的

int get_the_last_delete_data(int l, int r, int offset){  if (l>r)return l;  int mid = (l+r)/2;  if(get(1,mid) != get(2, mid-offset))         return get_the_last_delete_data(file,l,mid-1);    else         return get_the_last_delete_data(file,mid+1,r);}

左右两侧都找到之后,那整体长度就缩短了

4)有一个可以优化的地方就是get取过的数据一定要存下来,这样可以减少再去取数据的次数

int get_data()(    if(file_data[file-1][index]==0)        return get(file,index);    else        return file_data[file-1][index];)

这个方法算下来之后,次数大概在2700-2800左右,但是不能通过考试
我也不知道为啥。。。。

后来看了别人的思路,是这样的

1)二分法确定两个数组的长度
2)找到第二个数组中第一个元素,然后在原来的数组中从第一个元素查找,找到相等元素之前的那些元素都是删掉的,这个思路很好
3)同理 找到第二个数组中最后一个元素,然后在原来的数组中从最后一个元素查找,找到相等元素之前的那些元素都是删掉的
4)然后也是用二分法,找到一个位置,左右两边被删掉的元素相同,那么问题变成了2个子问题,不断递归,最后找到不断缩小两个元素所在区间,输出结果

/*调用部分*/cal(0,first_len, offset, delete_len);/*代码实现*/void cal(int start, int end, int offset, int del){    if(start+1 == end)    {    /*全找到了,打印结果*/    }    int mid = (start+end)/2;    int a = get_data(2,mid);    int foffset = 0;    int add = 0;    if(del%2) add =1;    if(del>1)    {        for(int i = 0;i<=del/2;i++)        {            int b = get_data(1,mid+del/2+i+add+offset);            if(a==b)            {                foffset=del/2+i+add;                break;            }            int c = get_data(1,mid+del/2-i+add+offset);            if(a==c)            {                foffset=del/2-i;                break;            }        }        if(foffset!=0)            cal(start,mid,offset,foffset);        if(foffset!=del)            cal(mid,end,offset+offset,del-foffset);    }    else    {        if(a==myget(1,mid+offset))            cal(mid,end,offset,1);        else            cal(start,mid,offset,1);    }}

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表。
这里虽然不是有序,但是也可以用来查找最后一个不为0的数来确定长度,因为这个0左右两次的数是不一样的,用来找两个数组的偏移也是一样

int bsearchWithoutRecursion(int array[],int low,int high,int target){    while(low<=high)        {            int mid=(low+high)/2;            if(array[mid]>target)                high=mid-1;            else if(array[mid]<target)            low=mid+1;            else                return mid;        }    return-1;}
原创粉丝点击