【编程题目】一个数组是由一个递减数列左移若干位形成的,在这种数组中查找某一个数。☆

48.微软(运算):
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。

 

我的思路:

非常麻烦:先是用二分法找最大的数的位置,再定位要找的数在哪个递减区间里,最后用普通的二分查找法找到。代码如下:

/*
48.微软(运算):
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。
*/

#include <stdio.h>

int find(int * a, int len, int num)
{
    int begin = 0;
    int end = len - 1;
    int mid;
    int MaxNumLocation = -1;
    bool isfind = false;

    //首尾特殊处理
    if(a[0] == num)
        return 0;
    else if(a[len - 1] == num)
        return len - 1;
    else
    {
        //先用二分查找定位最大值位置
        while(end > begin + 1)
        {
            if(a[begin] > a[end])
            {
                MaxNumLocation = begin;
                break;
            }
            else
            {
                mid = begin + (end - begin) / 2;
                if(a[mid] > a[end])
                {
                    end = mid;
                }
                else
                {
                    begin = mid;
                }
            }
        }

        if(MaxNumLocation == -1)
        {
            MaxNumLocation = end;
        }

        //定位当前要找的数字所在的递减区间
        if(num > a[len - 1] && num < a[0]) //区间没有旋转过
        {
            begin = 0;
            end = len - 1;
        }
        else if(num > a[len - 1] && num > a[0]) //在旋转后的右半部分
        {
            begin = MaxNumLocation;
            end = len - 1;
        }
        else if(num < a[len - 1] && num < a[0])//在旋转后的左半部分
        {
            begin = 0;
            end = MaxNumLocation - 1;
        }
        else
        {
            printf("error!!!!");
        }

        //二分查找
        while(begin < end - 1)
        {
            mid = begin + (end - begin) / 2;
            if(a[mid] > num)
            {
                begin = mid;
            }
            else if(a[mid] < num)
            {
                end = mid;
            }
            else
            {
                return mid;
            }
        }

        if(a[begin] == num)
            return begin;
        else if(a[end] == num)
            return end;
        else
        {
            printf("error!");
            return -1;
        }


    }
}

int main()
{
    int a[6] = {6,4,2,0,10,8};
    int b = find(a, 6, 8);
    return 0;
}

 

在网上看答案,发现自己想得太复杂了

http://www.cnblogs.com/daniagger/archive/2012/06/11/2545533.html 里面介绍的挺好

A:任意将这个数组从中间分开,分成两个数组,则至少有一个数组单调递减,另一个数组则可以由递减数组左移若干位得到,所以我们在二分之后确定界限的时候必须考虑所有情况,即需要查找的数组在哪一个分区里。

首先我们需要判断哪一个分区是单调递减的分区,这可以通过比较arr[l]和arr[mid]来得到,如果是大于等于,则左分区是单调递减,否则是右分区;再通过判断要查找的值是否夹在递减分区中间来最终确定选择哪一个分区。

代码验证可行。

注意:其实自己也想过分类讨论,可是想得太多了,总是想找到数字所在的递减序列。其实不一定要界定出递减的序列边界,只要能一次排除一半的错误选项就可以实现二分查找了

#include <iostream>
using namespace std;

int FindData(int* arr,int value,int l,int r)
{
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(arr[mid]==value)
            return mid;
        else
        {
            if(arr[l]>=arr[mid])
            {
                if(value>arr[mid] && value<=arr[l])
                    r=mid-1;
                else
                    l=mid+1;
            }
            else
            {
                if(value<arr[mid] && value>=arr[r])
                    l=mid+1;
                else
                    r=mid-1;
            }
        }
    }
    return -1;
}

int main()
{
    int arr[]={6,4,2,0,10,8};
    int n;
    cin >>n;
    cout <<FindData(arr,n,0,5)<<endl;
    return 0;
}

 

posted @ 2014-10-01 18:14  匡子语  阅读(900)  评论(0编辑  收藏  举报