一、题目:旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

  这道题最直观的解法并不难,从头到尾遍历数组一次,我们就能找出最小的元素。这种思路的时间复杂度显然是O(n)。但是这个思路没有利用输入的旋转数组的特性,肯定达不到面试官的要求

  我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是这两个子数组的分界线。在排序的数组中我们可以用二分查找法实现O(logn)的查找

二、解题思路

  Step1.和二分查找法一样,我们用两个指针分别指向数组的第一个元素和最后一个元素。

  Step2.接着我们可以找到数组中间的元素:

  如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的第一个指针仍然位于前面的递增子数组之中。如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。

  Step3.接下来我们再用更新之后的两个指针,重复做新一轮的查找。

按照上述的思路,第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最终第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。

  以前面的数组{3,4,5,1,2}为例,下图展示了在该数组中查找最小值的过程:

三、解决问题

3.1 代码实现

    public static int GetMin(int[] numbers)
{
if (numbers == null || numbers.Length <= )
{
return int.MinValue;
} int index1 = ;
int index2 = numbers.Length - ;
// 把indexMid初始化为index1的原因:
// 一旦发现数组中第一个数字小于最后一个数字,表明该数组是排序的
// 就可以直接返回第一个数字了
int indexMid = index1; while (numbers[index1] >= numbers[index2])
{
// 如果index1和index2指向相邻的两个数,
// 则index1指向第一个递增子数组的最后一个数字,
// index2指向第二个子数组的第一个数字,也就是数组中的最小数字
if (index2 - index1 == )
{
indexMid = index2;
break;
}
indexMid = (index1 + index2) / ;
// 特殊情况:如果下标为index1、index2和indexMid指向的三个数字相等,则只能顺序查找
if (numbers[index1] == numbers[indexMid] && numbers[indexMid] == numbers[index2])
{
return GetMinInOrder(numbers, index1, index2);
}
// 缩小查找范围
if (numbers[indexMid] >= numbers[index1])
{
index1 = indexMid;
}
else if (numbers[indexMid] <= numbers[index2])
{
index2 = indexMid;
}
} return numbers[indexMid];
} public static int GetMinInOrder(int[] numbers, int index1, int index2)
{
int result = numbers[index1];
for (int i = index1 + ; i <= index2; ++i)
{
if (result > numbers[i])
{
result = numbers[i];
}
} return result;
}

  这里需要注意的是:

  (1)把indexMid初始化为index1的原因:一旦发现数组中第一个数字小于最后一个数字,表明该数组是排序的,就可以直接返回第一个数字了。

  (2)特殊情况的分析:如果下标为index1、index2和indexMid指向的三个数字相等,则只能顺序查找,因此这里定义了一个GetMinInOrder()方法。

3.2 单元测试

  (1)典型输入,单调升序的数组的一个旋转

    // 典型输入,单调升序的数组的一个旋转
[TestMethod]
public void GetMinNumTest1()
{
int[] array = {, , , , };
Assert.AreEqual(Program.GetMin(array),);
}

  (2)有重复数字,并且重复的数字刚好的最小的数字

    // 有重复数字,并且重复的数字刚好的最小的数字
[TestMethod]
public void GetMinNumTest2()
{
int[] array = { , , , , , };
Assert.AreEqual(Program.GetMin(array), );
}

  (3)有重复数字,但重复的数字不是第一个数字和最后一个数字

    // 有重复数字,但重复的数字不是第一个数字和最后一个数字
[TestMethod]
public void GetMinNumTest3()
{
int[] array = { , , , , , };
Assert.AreEqual(Program.GetMin(array), );
}

  (4)有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字

    // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
[TestMethod]
public void GetMinNumTest4()
{
int[] array = { , , , , };
Assert.AreEqual(Program.GetMin(array), );
}

  (5)单调升序数组,旋转0个元素,也就是单调升序数组本身

    // 单调升序数组,旋转0个元素,也就是单调升序数组本身
[TestMethod]
public void GetMinNumTest5()
{
int[] array = { , , , , };
Assert.AreEqual(Program.GetMin(array), );
}

  (6)数组中只有一个数字

    // 数组中只有一个数字
[TestMethod]
public void GetMinNumTest6()
{
int[] array = { };
Assert.AreEqual(Program.GetMin(array), );
}

  (7)鲁棒性测试:输入NULL

    // 鲁棒性测试:输入NULL
[TestMethod]
public void GetMinNumTest7()
{
Assert.AreEqual(Program.GetMin(null), int.MinValue);
}

  单元测试的结果如下图所示:

  对于GetMin方法编写的单元测试的代码覆盖率已达到了100%:

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

剑指Offer面试题:7.旋转数组的最小数字的更多相关文章

  1. 剑指Offer - 九度1386 - 旋转数组的最小数字

    剑指Offer - 九度1386 - 旋转数组的最小数字2013-11-24 01:57 题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转 ...

  2. 剑指offer【06】- 旋转数组的最小数字(java)

    题目:旋转数组的最小数字 考点:查找和排序 题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4, ...

  3. 《剑指Offer》算法题——“旋转数组”的最小数字

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减序列的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数 ...

  4. 剑指offer六之求旋转数组的最小数字

    一.题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个 ...

  5. 【剑指Offer】6、旋转数组的最小数字

      题目描述:   把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5 ...

  6. 剑指Offer:面试题8——旋转数组的最小值(java实现)

    题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入 一个递增排序的数组的一个旋转 输出 旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的 ...

  7. 剑指Offer:面试题33——把数组排成最小的数(java实现)(未完待续)

    问题描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 思路1: ...

  8. 【剑指offer】面试题 11. 旋转数组的最小数字

    面试题 11. 旋转数组的最小数字 题目描述 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4, ...

  9. Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)

    剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...

  10. 剑指Offer - 九度1504 - 把数组排成最小的数

    剑指Offer - 九度1504 - 把数组排成最小的数2014-02-06 00:19 题目描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输 ...

随机推荐

  1. C# DM5 32位加密

    using System.Security.Cryptography;using System.Text; public static string StringToMD5Hash(string in ...

  2. winform快速开发平台 -> 快速绑定ComboBox数据控件

    通常我们在处理编辑窗体时.往往会遇到数据绑定.例如combobox控件绑定数据字典可能是我们经常用到的.然而在我的winform快速开发平台中我是如何处理这个频繁的操作呢? 首先,我们要绑定combo ...

  3. 桥接模式/bridge模式/对象结构型

    意图 将抽象部分与它的实现部分分离,使它们都可以独立的变化. 动机 当一个抽象类有多个实现时,通常用继承来协调它们.但是继承机制将抽象和实现固定,难以对抽象部分和实现部分独立地进行修改.扩充和重用. ...

  4. (UWP开发)更为合理的一种ListView下拉刷新(PullToRefresh)实现方法

    最近在做的一个项目需要用到下拉刷新,但是参考了现在网络上比较普遍的方法,觉得都不太好,因为要在外部套上一个SrollViewer,容易出现滚动错误.于是刚开始的时候就把思路定到了ListView内部的 ...

  5. Design and Implementation of the Sun Network File System

    Introduction The network file system(NFS) is a client/service application that provides shared file ...

  6. python调用c\c++

    前言 python 这门语言,凭借着其极高的易学易用易读性和丰富的扩展带来的学习友好性和项目友好性,近年来迅速成为了越来越多的人们的首选.然而一旦拿python与传统的编程语言(C/C++)如来比较的 ...

  7. Codeforces Round #388 (Div. 2) - A

    题目链接:http://codeforces.com/contest/749/problem/A 题意:给定一个数n,求把n分解成尽量多的素数相加.输入素数个数和具体方案. 思路:因为要尽量多的素数, ...

  8. 【转】iOS学习之translucent属性

    原文地址:http://www.jianshu.com/p/930643270455 总所周知,苹果从iOS7开始采用扁平化的界面风格,颠覆了果粉们"迷恋"的拟物化风格.对于开发者 ...

  9. bzoj 4327: JSOI2012 玄武密码

    听说这题不公开.. 那就不贴题意了 一眼看上去还以为是exkmp的裸题.. 看了数据范围,呵呵.. 多串匹配嘛.. 就用AC自动机咯,而且每个点最多也就只有$4$个孩子 用原串在AC自动机上走,碰到的 ...

  10. [BZOJ1127][POI2008] KUP子矩阵

    Description 给一个n*n的地图,每个格子有一个价格,找一个矩形区域,使其价格总和位于[k,2k] Input 输入k n(n<2000)和一个n*n的地图 Output 输出矩形的左 ...