关于二分法在旋转数组中的应用
来源:互联网 发布:战舰世界藏王数据 编辑:程序博客网 时间:2024/06/10 18:05
关于旋转数组的问题在IT公司面试中是很常见的,而二分法因为其能达到O(logn)的效率而广受欢迎,网上也有不少相关的博文,本篇文章主要围绕下面两个议题讨论二分法在旋转数组中的应用。
旋转数组: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
1. 旋转数组中查找最小数
题目:
输入一个有序(增序)数组的一个旋转,输出旋转数组的最小元素。例如数组a {3,4,5,6,7,8,9,0,1,2} 为{0,1,2,3,4,5,6,7,8,9}的一个旋转,该数组的最小元素为0.
思路:
可以很容易观察到,旋转之后的数组实际上可以化为为两个排序的子数组{3,4,5,6,7,8,9}和{0,1,2},并且前面的子数组元素都大于或等于后面子数组的元素,最小的元素位于后面子数组的首位,刚好是两子数组的分界线。另外,如果数组旋转0位是不变的,它也是数组的一个旋转,那么最小元素实际上就是第一个元素。
因为数组在一定程度上是有序的,因此我们可以用二分法的思路来寻找最小的元素。用两个指针分别指向数组的第一个和最后一个元素,如果数组有实际的旋转(非0位),第一个元素必定是大于或等于最后一个元素的。接着我们取数组中间的元素,通过判断中间元素位于前后哪个子数组中来得出最小元素所在的子数组,如果中间元素的值大于或等于第一个元素,那么它位于前面的子数组,最小元素应该处于该中间元素的后面,此时我们可以移动第一个指针指向该中间元素,以此来缩小查找的范围。同样的,如果中间元素位于后面的子数组,则数组中最小元素应该位于该中间元素的前面或者就是中间元素,此时可以移动第二个指针指向该中间元素,缩小查找的范围。继续新一轮的查找并更新指针,最终两个指针会指向两相邻的元素,第一个指针指向前面子数组的最后一个元素,而个第二个指针会指向后面数组的第一个元素,即为最小的那个元素,循环结束。
有一种特殊的case需要注意,例如{1,1,0,1,1,1,1},两个子数组分别为{1,1},{0,1,1,1,1}, 中间元素和第一个、最后一个元素都相等,按照以上算法会有问题,因为中间元素和第一个元素相等,最小元素会被错判到缩小范围后的子数组{1,1,1,1}中。那么如果是这种case,我们只能顺序查找最小元素。
实现:
int minInOrder(int a[], int head, int tail){int res = a[head];for (int i = head + 1; i <= tail; i++){if (a[i] < res)res = a[i];}return res;}int minInRotateArray(int a[], int len){assert(len > 0);if (1 == len)return a[0];int head = 0;int tail = len-1; int mid = (head + tail)/2;if (a[head] == a[tail] && a[mid] == a[head]){return minInOrder(a, head, tail); // sequential search}while (a[head] >= a[tail]){if (1 == tail - head ){return a[tail];}if (a[mid] >= a[head])head = mid;else if (a[mid] <= a[tail])tail = mid;mid = (head + tail)/2;}return a[0];}
2. 旋转数组查找给定数
题目:
输入一个有序(增序)数组的一个旋转,查找并输出给定值为x的元素位置,若查找不到则输出-1。例如数组a {3,4,5,6,7,8,9,0,1,2} 为{0,1,2,3,4,5,6,7,8,9}的一个旋转,需要查找x=8的元素,输出为6.
思路:
实现:
int searchInOrder(int a[], int len, int x){int i = 0;for ( ; i < len; i++){return i + 1;}if (len == i)return -1;}int searchInRotateArray(int a[], int len, int x){assert(len > 0);int head = 0; int tail = len - 1;int mid = (head + tail)/2;if (a[head] == a[tail] && a[mid] == a[head])return searchInOrder(a, len, x);while((head <= tail)){ if (head == tail) return x == a[head] ? head + 1 : -1;int mid = (head + tail)/2;if (a[mid] >= a[head]){if (x == a[mid])return mid + 1;else if (x > a[mid])head = mid + 1;else{if (x >= a[head])tail = mid - 1;else head = mid + 1;}}else {if (x == a[mid])return mid + 1;else if (x < a[mid])tail = mid - 1;else {if (x > a[tail])tail = mid - 1;else head = mid + 1;}}mid = (head + tail)/2;}}
- 关于二分法在旋转数组中的应用
- 二分法在C#.net 中的应用
- 旋转数组的二分法查找
- 用php二分法查找一个值在数组中的位置
- 关于Android中的Rotate旋转动画应用
- Sorting&Searching 旋转数组二分法查找 @CareerCup
- php二分法在IP地址查询中的应用
- 寻找数字在旋转数组中的位置
- 二分法查找数组中的数
- java二分法实现在有序的数组中定位某数在数组中的位置
- 旋转数组中的最小值
- 旋转数组中的最小值
- 旋转数组求某个值:今日头条面试题--二分法
- [剑指Offer] 6.旋转数组的最小数字(二分法)
- 程序功能:用二分法查找数字在递增数组中的位置,并打印出来。
- 【求职之路】(1)利用二分法查找一个数字在数组中的位置
- PHP写一个二分法查找一个值在数组中的位置
- USACO 08 JAN 电话线Telephone Lines(二分法在图论题中的应用)
- Sciter笔记- 1
- python 使用memcache
- MyEclipse中变量变色的问题
- 机器翻译很搞笑
- 为View创建截图的优化方案
- 关于二分法在旋转数组中的应用
- 打造个人品牌
- SCiter笔记 - 2
- MyEclipse8.5破解方法
- 自定义Qt按钮
- HDU 1506 DP 最大完全子矩阵
- C++学习之路: 基本概念
- HDFS的写数据过程分析
- 提问的艺术