(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指Offer:名企面试官精讲典型编程题》2012年”)

题目

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

算法设计思想

1. 暴力查找(Bruteforce Search):把旋转数组从前到后遍历一遍,其时间复杂度为 O(n)。很明显,这种思想非常直接粗暴,没有用到旋转数组的性质。

2. 二分查找(Binary Search):每次查找都把旋转数组平均分成两部分,通过比较当前旋转数组两端点中间点的值,判断最小值在数组的哪一部分,从而达到缩小搜索范围的目的。其中,两端点为当前的旋转数组索引最小索引最大的元素,中间点为这两部分子数组的连结元素,也可以看做为轴枢点(pivot point),这里取旋转数组的最小索引和最大索引的算术平均值(向下取整)作为索引,其对应的元素作为中间点。具体过程,如图 2.10 所示。

需要注意,当旋转数组的两端点的值都与中间点的值相等时,因为无法判断最小值在哪一部分,因此需要采用顺序查找方法,即暴力查找。其示例如图 2.11 所示。

C++ 实现

#include <stdio.h>
#include <exception>
#include <iostream> // Declare a parameter exception
class ParamException: public std::exception {
virtual const char* what() const throw()
{
return "Error: input parameters exception!";
}
}; // find minimum in data[staIndex..endIndex]
int findMinInRotatedArray(int data[], int staIndex, int endIndex)
{
if (staIndex > endIndex || data == NULL)
{
throw ParamException();
} int minimum = data[staIndex]; if (data[staIndex] >= data[endIndex] && staIndex < endIndex - ) // 易错点
{
// Use Binary Search
int midIndex = (staIndex + endIndex) / ; if (data[midIndex] > data[staIndex])
minimum = findMinInRotatedArray(data, midIndex, endIndex);
else if (data[midIndex] < data[endIndex])
minimum = findMinInRotatedArray(data, staIndex, midIndex);
else
{
// Find the minimum sequentially
for (int i = staIndex+; i <= endIndex; ++i)
if (minimum > data[i])
minimum = data[i];
}
}
else if (staIndex == (endIndex - ))
{
minimum = data[staIndex] > data[endIndex]? data[endIndex]:data[staIndex];
} return minimum;
} void unitest()
{
int arr1[] = {, , , , };
int arr2[] = {, , , , };
int arr3[] = {, , , , };
int arr4[] = {, , , , }; printf("The minimum of the rotated array {3, 4, 5, 1, 2} is %d.\n", findMinInRotatedArray(arr1, , ));
printf("The minimum of the rotated array {1, 0, 1, 1, 1} is %d.\n", findMinInRotatedArray(arr2, , ));
printf("The minimum of the rotated array {1, 1, 1, 0, 1} is %d.\n", findMinInRotatedArray(arr3, , ));
printf("The minimum of the rotated array {1, 2, 3, 4, 5} is %d.\n", findMinInRotatedArray(arr4, , )); // Test index parameter exception
try {
findMinInRotatedArray(arr3, , );
}
catch(std::exception& e) {
std::cout << e.what() << std::endl;
};
} int main(void)
{
unitest(); return ;
}

Python 实现

#!/usr/bin/python
# -*- coding: utf8 -*- # Define ParamError Exception
class ParamError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value) # Find the minimum in rotated array
def min_in_rotated_array(data, length):
if data is None or length <= 0:
raise ParamError("Error: input parameters exception!")
# Index initialization
sta, mid, end = 0, 0, length-1
# Ensure this requisite before binary search
while data[sta] >= data[end]:
if end - sta == 1:
mid = end
break
# Get the middle index
mid = (sta + end) / 2
# Find the minimum in order
if (data[sta] == data[mid]) and (data[mid] == data[end]):
minimum = data[sta]
for i in range(sta+1, end+1):
if minimum > data[i]:
minimum = data[i]
return minimum if data[sta] <= data[mid]:
sta = mid
elif data[end] >= data[mid]:
end = mid return data[mid] def unitest():
arr1 = [3, 4, 5, 1, 2]
arr2 = [1, 0, 1, 1, 1]
arr3 = [1, 1, 1, 0, 1]
arr4 = [1, 2, 3, 4, 5] print("The minimum of the rotated array [3, 4, 5, 1, 2] is %d." % min_in_rotated_array(arr1, 5));
print("The minimum of the rotated array [1, 0, 1, 1, 1] is %d." % min_in_rotated_array(arr2, 5));
print("The minimum of the rotated array [1, 1, 1, 0, 1] is %d." % min_in_rotated_array(arr3, 5));
print("The minimum of the rotated array [1, 2, 3, 4, 5] is %d." % min_in_rotated_array(arr4, 5)); try:
min_in_rotated_array(arr1, -2)
except Exception, e:
print "\nFunction call: min_in_rotated_array(arr1, -2)"
print e if __name__ == '__main__':
unitest()

参考代码

1. targetver.h

#pragma once

// The following macros define the minimum required platform.  The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified. // Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif

2. stdafx.h

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
// #pragma once #include "targetver.h" #include <stdio.h>
#include <tchar.h> // TODO: reference additional headers your program requires here

3. stdafx.cpp

// stdafx.cpp : source file that includes just the standard includes
// MinNumberInRotatedArray.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H
// and not in this file

4. MinNumberInRotatedArray.cpp

// MinNumberInRotatedArray.cpp : Defines the entry point for the console application.
// // 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛 #include "stdafx.h"
#include<exception> int MinInOrder(int* numbers, int index1, int index2); int Min(int* numbers, int length)
{
if(numbers == NULL || length <= )
throw new std::exception("Invalid parameters"); int index1 = ;
int index2 = length - ;
int indexMid = index1;
while(numbers[index1] >= numbers[index2])
{
// 如果index1和index2指向相邻的两个数,
// 则index1指向第一个递增子数组的最后一个数字,
// index2指向第二个子数组的第一个数字,也就是数组中的最小数字
if(index2 - index1 == )
{
indexMid = index2;
break;
} // 如果下标为index1、index2和indexMid指向的三个数字相等,
// 则只能顺序查找
indexMid = (index1 + index2) / ;
if(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])
return MinInOrder(numbers, index1, index2); // 缩小查找范围
if(numbers[indexMid] >= numbers[index1])
index1 = indexMid;
else if(numbers[indexMid] <= numbers[index2])
index2 = indexMid;
} return numbers[indexMid];
} int MinInOrder(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;
} // ====================测试代码====================
void Test(int* numbers, int length, int expected)
{
int result = ;
try
{
result = Min(numbers, length); for(int i = ; i < length; ++i)
printf("%d ", numbers[i]); if(result == expected)
printf("\tpassed\n");
else
printf("\tfailed\n");
}
catch (...)
{
if(numbers == NULL)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
} int _tmain(int argc, _TCHAR* argv[])
{
// 典型输入,单调升序的数组的一个旋转
int array1[] = {, , , , };
Test(array1, sizeof(array1) / sizeof(int), ); // 有重复数字,并且重复的数字刚好的最小的数字
int array2[] = {, , , , , };
Test(array2, sizeof(array2) / sizeof(int), ); // 有重复数字,但重复的数字不是第一个数字和最后一个数字
int array3[] = {, , , , , };
Test(array3, sizeof(array3) / sizeof(int), ); // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
int array4[] = {, , , , };
Test(array4, sizeof(array4) / sizeof(int), ); // 单调升序数组,旋转0个元素,也就是单调升序数组本身
int array5[] = {, , , , };
Test(array5, sizeof(array5) / sizeof(int), ); // 数组中只有一个数字
int array6[] = {};
Test(array6, sizeof(array6) / sizeof(int), ); // 输入NULL
Test(NULL, , ); return ;
}

7. 参考代码下载

项目 08_MinNumberInRotatedArray 下载: 百度网盘

何海涛《剑指Offer:名企面试官精讲典型编程题》 所有参考代码下载:百度网盘

参考资料

[1]  何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 63-71.

旋转数组的最小数字(C++ 和 Python 实现)的更多相关文章

  1. 剑指Offer面试题:7.旋转数组的最小数字

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

  2. 旋转数组的最小数字(JAVA)

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

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

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

  4. 剑指offer编程题Java实现——面试题8旋转数组的最小数字

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

  5. 【Java】 剑指offer(10) 旋转数组的最小数字

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. ...

  6. 《剑指offer》第十一题(旋转数组的最小数字)

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

  7. 《剑指offer》— JavaScript(6)旋转数组的最小数字

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

  8. 【C语言】求旋转数组的最小数字,输入一个递增排序的数组的一个旋转,输出其最小元素

    //求旋转数组的最小数字,输入一个递增排序的数组的一个旋转,输出其最小元素 #include <stdio.h> #include <string.h> int find_mi ...

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

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

  10. 剑指offer——面试题11:旋转数组的最小数字

    #include"iostream" using namespace std; int GetMinNumber(int *data,int len) { ,right=len-, ...

随机推荐

  1. 分分钟钟学会Python - 基础

    1.常见操作系统 1.windows xp/win7/win/10/window server 2.linux centos,图形化界面差 ubuntu,个人开发(图形化比较好) redhat,企业级 ...

  2. Xpath常用总结

    XPath常用定位节点元素语句总结 将一个XML或HTML文档转换成了DOM树结构后,如何才能定位到特定的节点?XPath实现了这样的功能,它通过DOM树中节点的路径和属性来导航,通过XPath路径表 ...

  3. 在Vue项目中使用html2canvas生成页面截图并上传

    使用方法 项目中引入 npm install html2canvas html代码 //html代码 <!-- 把需要生成截图的元素放在一个元素容器里,设置一个ref --> <di ...

  4. 【OpenCV-Python】-图像形态学转化

    原文为段立辉翻译,感谢Linux公社此文档为自学转述,如有侵权请联系本人. 目标: • 学习不同的形态学操作,例如腐蚀,膨胀,开运算,闭运算等 • 学习的函数有:cv2.erode(),cv2.dil ...

  5. 关于ASP.NET MVC+Repository+Service架构的一些思考

    看了一些ASP.NET MVC开源项目后的一些想法,关于ASP.NET MVC+Repository+Service架构的一些思考 最近在学习ASP.NET MVC 2.0的一些开源项目,发现这些项目 ...

  6. 如何获取用户的地理位置? && html5 地理位置

    推荐网站 https://html5demos.com/geo/ 我们有时候可能希望首先获得用户的地理位置,然后根据不同的地理位置(更具针对性地)推送不同的信息等等. 下面这段代码就可以在你有jQue ...

  7. Python"由于目标计算机积极拒绝,无法连接。"错误解决

    出现这种情况的原因是电脑使用了代理服务器,在设置中,将代理服务关闭就行 这时候通过GET访问界面就能成功了.测试代码: import requests r=requests.get('https:// ...

  8. Robot Framework自动化测试三(selenium API)

    Robot  Framework  Selenium  API 说明: 此文档只是将最常用的UI 操作列出.更多方法请查找selenium2Library 关键字库. 一.浏览器驱动 通过不同的浏览器 ...

  9. An internal error occurred during: "Initializing Java Tooling". Eclipse启动发生的错误

    An internal error occurred during: “Initializing Java Tooling” 错误经常是莫名其妙的出现这种总错误,解决办法: 1.eclipse -&g ...

  10. C 标准库 - string.h之strcat使用

    strcat Appends a copy of the source string to the destination string. The terminating null character ...