剑指Offer面试题8[旋转数组的最小数字]

1.题目描述:

  把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

2. 相关知识:

  查找和排序是是面试考察算法的重点,我们应该重点掌握二分查找、归并排序和快速排序,做到能随时正确、完整地写出它们的代码。

  • 查找算法:顺序查找、二分查找、哈希查找、二叉排序树查找。
  • 排序算法:插入排序、冒泡排序、归并排序、快速排序,面试者一定要能写出完整的代码,并对各种排序算法的特点烂熟于胸,能够从空间消耗、平均时间复杂度和最差时间复杂度等方面比较它们的优缺点。

  查找算法性能分析:为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望称为查找算法在查找成功时的用平均查找长度(Average Search Length, ASL)。
   设 n 为记录数,Pi为第 i 个记录的概率(ni=1Pi=1), Ci 为找到查找匹配时已查找次数。
  顺序查找的平均查找长度

ASL=i=1nPiCi=nP1+(n1)P2++2Pn1+Pn

等概率条件下 Pi=1/n ASL=(n+1)/2 。所以,顺序查找的算法复杂度为 O(n)
  折半查找可用判定树进行分析,二叉树长度 n 与深度h的关系 n=2h1 。等概率条件下 Pi=1/n ,且二叉树第 j 层有2j1个及结点。因而,折半查找的平均查找长度

ASLbs=i=1nPiCi=1nj=1hj2j1=1n(120+221++h2h1)=1n[(20+21++2h1)+(21++2h1)++(2h1)]=1n[(2h20)+(2h21)++(2h2h1)]=1n[h2h(20+21++2h1)]=1n[(h1)2h+1]=n+1nlog2(n+1)1

推导过程第四、六行均使用了等比数列求和公式,倒数第二行将 h=log2(n+1) 代入其中。当 n 较大时,ASLbslog2(n+1)1。所以,折半查找的算法复杂度为 O(log2(n))

  二叉排序树:左子树小于根结点,右子树大于根结点。查找过程中动态生成树的结构,因而其平均查找长度和树的形态有关。最坏情况是插入的关键字有序时,构成的二叉排序树退化为单支树,其平均查找长度为 (n+1)/2 ,与顺序查找相同;最好的情况是构成二叉树形态与折半查找判定树相同,平均查找长度与 log2(n) 成正比。
  为了使得二叉排序树的性能不退化为单支树,需要对树进行平衡化处理。平衡二叉树的所有左右子树的深度差的绝对值不超过1。平衡二叉树的构建需要对树进行“旋转”处理。

3. 解答思路:

  采用类似于二分法查找的算法,并且考虑特殊情况

4. 代码实现:

#include "stdafx.h"
int minInOrder(int* numbers, int index1, int index2)
{
    int result = numbers[index1];
    for (int i=index1;i<=index2; i++)
    {
        if (numbers[i]<result)      
            result = numbers[i];        
    }
    return result;
}

int getMin(int* numbers, int length)
{
    if(numbers == NULL || length <= 0)
        printf("error");
    int index1 = 0;
    int index2 = length - 1;
    int mid = index1;
    while(numbers[index1] >= numbers[index2])
    {
        if(index2 - index1 == 1)
        {
            mid = index2;
            break;
        }
        mid = (index1 + index2) / 2;
        if (numbers[index1] == numbers[index2] && numbers[mid] == numbers[index2])
        {
            return minInOrder(numbers, index1, index2);
        }
        if(numbers[mid] >= numbers[index1])
            index1 = mid;
        else if(numbers[mid] <= numbers[index2])
            index2 = mid;
    }
    return numbers[mid];
}

int _tmain(int argc, _TCHAR* argv[])
{
    //int testData[5] = {3, 4, 5, 1, 2};
    int testData[5] = {1, 0, 1, 1, 1};
    int min = getMin(testData, 5);
    printf("min is %d\n", min);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值