• careercup-递归和动态规划 9.3


    9.3 在数组A[0...n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个有序整数数组,元素值给不相同,编写一个方法,在数组A中找出一个魔术索引,若存在的话。

    进阶:

    如果数组元素有重复值,又该如何处理。?

    解法一,选择蛮力法,我们可以直接迭代访问整个数组,找出符号条件的元素。

    int magicSlow(int arr[],int n)
    {
        if(n==0)
            return -1;
        int i;
        for(i=0;i<n;i++)
        {
            if(arr[i]==i)
                return i;
        }
        return -1;
    }

    解法二:既然给的数组是有序的,我们理应充分利用这个条件。

    你看你会发现这个问题与经典的二分查找问题非常相似。充分运用匹配法,就能找到适当的算法,我们又该怎样运用二分查找法呢?

    在二分查找中,要找出元素k,我们会先拿它跟数组中间的元素x比较,确定k位于x的左边还是右边。

    以此为基础,是否通过检查中间元素就能确定魔术索引的位置?

    通过比较A[mid]<mid,可以确定该魔术索引一定在mid的右边,因此left=mid+1;

    如果A[mid]>mid,可以取得该魔术索引一定在mid 的左边,因此right=mid-1;

    算法如下:

    int magicQuick(int arr[],int n)
    {
        if(n==0)
            return -1;
        int mid;
        int left=0;
        int right=n-1;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(mid==arr[mid])
                return mid;
            else if(mid<arr[mid])
                right=mid-1;
            else
                left=mid+1;
        }
        return -1;
    }

    进阶:

    如果存在重复元素,前面的算法就会失效。以下面的数组为例:

    -10 -5 2 2 2 3 4 7 9 12 13

      0   1  2 3 4 5 6 7 8 9 10 11

    看到A[mid]<mid时,我们无法判定魔术索引位于数组哪一边。它可能在数组右侧,跟前面一样。或者,也可能在左侧(在本例中的确在左侧)。

    它有没有可能在左侧的任意位置呢?不可能。由A[5]=3可知,A[4]不可能是魔术索引。A[4]必须等于4,其索引才能成为魔术索引,但数组是有序的,故A[4]必定小于A[5]。

    事实上,看到A[5]=3时按照前面的做法,我们需要递归搜索右半部分。不过,如搜索左半部分,我们可以跳过一些元素,值递归搜索A[0]到A[3]的元素。A[3]是第一个可能成为魔术索引的元素。

    综上:我们得到一种搜索模式,先比较midIndex和midValue是否相同。然后,若两者不同,则按如下方式递归搜索左半部分和右半部分。

    左半部分:搜索索引从start到min(midIndex-1,midValue)的元素。

    右半部分:搜索索引从max(midIndex+1,minValue)到end的元素。

    可以看做前面的基础上求左右两边的交集,例如A[mid]<mid,需要搜索mid左边的部分元素,即区间从start到min(midIndex-1,midValue)的元素和mid右边的全部元素。

    A[mid]>mid,需要搜索mid左边的全部元素和右边的部分元素,即区间从max(midIndex+1,minValue)到end,然后两者求交集,就得到上面的区间了。

    算法如下:

    int magicHelper(int arr[],int n,int l,int r)
    {
        if(l>r||l<0||r>=n)
            return -1;
        int mid=(l+r)/2;
        if(mid==arr[mid])
            return mid;
        int rightindex=min(mid-1,arr[mid]);
        int left=magicHelper(arr,n,l,rightindex);
        if(left>=0)
            return left;
        int leftindex=max(mid+1,arr[mid]);
        int right=magicHelper(arr,n,leftindex,r);
        return right;
    }
    //有重复元素
    int magicFast(int arr[],int n)
    {
        if(n==0)
            return -1;
        return magicHelper(arr,n,0,n-1);
    }

    完整代码:

    #include<iostream>
    using namespace std;
    
    int magicSlow(int arr[],int n)
    {
        if(n==0)
            return -1;
        int i;
        for(i=0;i<n;i++)
        {
            if(arr[i]==i)
                return i;
        }
        return -1;
    }
    
    int magicQuick(int arr[],int n)
    {
        if(n==0)
            return -1;
        int mid;
        int left=0;
        int right=n-1;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(mid==arr[mid])
                return mid;
            else if(mid<arr[mid])
                right=mid-1;
            else
                left=mid+1;
        }
        return -1;
    }
    
    int magicHelper(int arr[],int n,int l,int r)
    {
        if(l>r||l<0||r>=n)
            return -1;
        int mid=(l+r)/2;
        if(mid==arr[mid])
            return mid;
        int rightindex=min(mid-1,arr[mid]);
        int left=magicHelper(arr,n,l,rightindex);
        if(left>=0)
            return left;
        int leftindex=max(mid+1,arr[mid]);
        int right=magicHelper(arr,n,leftindex,r);
        return right;
    }
    //有重复元素
    int magicFast(int arr[],int n)
    {
        if(n==0)
            return -1;
        return magicHelper(arr,n,0,n-1);
    }
    
    int main()
    {
        int arr[10]={-1,0,1,2,3,4,5,6,7,9};
        cout<<magicSlow(arr,10)<<endl;
        cout<<magicQuick(arr,10)<<endl;
        cout<<magicFast(arr,10)<<endl;
    }
  • 相关阅读:
    使用animate()完成修改图片src切换图片的动画效果
    一键分享到各个SNS插件
    $data[$i++]+=2;不等于$data[$i++]=$data[$i++]+2;
    QQ在线客服的使用
    JQuery实时监控文本框字符变化
    迭代器的使用
    泛型的作用
    Eclipse的使用
    关于“类型”字段的处理
    java servlet+mysql全过程(原创)
  • 原文地址:https://www.cnblogs.com/wuchanming/p/4149788.html
Copyright © 2020-2023  润新知