在旋转后的有序数组中查找元素,要求O(logn)的时间复杂度
2010-09-29 22:04
423 查看
题:比如说在A[] = {7, 8, 1, 2, 3, 4, 5, 6};查找元素。A是由{1, 2, 3, 4, 5, 6, 7, 8}左旋6位得到。
假定数组旋转前是有序递增的,且没有重复的元素。
方法:二分查找,再分情况讨论。在确定l, m, r后,旋转后的数组有图1所示的四种情况,且对应的元素有图2所示的关系。
由图中可以看出,根据A[l]与A[r]的大小关系可以区分出第4种情况。然后根据A[l]与A[m]的关系可以区分出第1中情况。
第2和第3中情况难以区分,但是如果
(1)m == r,肯定是第2种情况(或第4种情况,当然第4种情况右侧元素个数为0的话也退化成第2种情况)
(2)否则m < r,m+1在检查的范围之内,是有意义的
1)如果A[m] > A[m + 1]则是第2种情况
2)否则A[m] < A[m + 1]是第3种情况
对于第4和第2种情况,简单的调用通用的二分查找函数即可。
对于第1种情况,如果确定要查找的值在A[m+1:r]的范围内,可以调用简单的二分查找函数,否则对A[l:m+1]继续上面的情况分类。
对于第3种情况,讨论与第1种情况类似。
程序如下
假定数组旋转前是有序递增的,且没有重复的元素。
方法:二分查找,再分情况讨论。在确定l, m, r后,旋转后的数组有图1所示的四种情况,且对应的元素有图2所示的关系。
由图中可以看出,根据A[l]与A[r]的大小关系可以区分出第4种情况。然后根据A[l]与A[m]的关系可以区分出第1中情况。
第2和第3中情况难以区分,但是如果
(1)m == r,肯定是第2种情况(或第4种情况,当然第4种情况右侧元素个数为0的话也退化成第2种情况)
(2)否则m < r,m+1在检查的范围之内,是有意义的
1)如果A[m] > A[m + 1]则是第2种情况
2)否则A[m] < A[m + 1]是第3种情况
对于第4和第2种情况,简单的调用通用的二分查找函数即可。
对于第1种情况,如果确定要查找的值在A[m+1:r]的范围内,可以调用简单的二分查找函数,否则对A[l:m+1]继续上面的情况分类。
对于第3种情况,讨论与第1种情况类似。
程序如下
]#include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; static void left_rotate_1(int A[], const int N) { int tmp = A[0]; for (int i = 0; i < N - 1; i++){ A[i] = A[i + 1]; } A[N - 1] = tmp; } static int binary_search(const int A[], int l, int r, const int val) { int m; while (l <= r){ m = (l + r) >> 1; if (val == A[m]) return m; else if (val < A[m]) r = m - 1; else l = m + 1; } return -1; } static int rotated_search(const int A[], const int N, const int val) { int l, r, m; l = 0; r = N - 1; cout << "searching " << val << endl; while (l <= r){ m = (l + r) >> 1; if (A[l] < A[r]){ /*case 4*/ return binary_search(A, l, r, val); } if (val == A[m]) return m; else if (A[l] > A[m]){ /*case 1*/ if (val > A[m] && val <= A[r]) return binary_search(A, m + 1, r, val); else r = m - 1; }else{ /*case 2 and 3*/ if (m == r || A[m] > A[m + 1]){ /*case 2*/ l = binary_search(A, l, m - 1, val); if (-1 != l) return l; return binary_search(A, m + 1, r, val); }else{ /*case 3*/ if (val >= A[l] && val < A[m]){ return binary_search(A, l, m - 1, val); }else{ l = m + 1; } } } } return -1; } static inline void case_test(const int val) { cout << "get" << setw(5) << val << endl; } static void print_array(const int A[], const int N) { cout << "index:"; for (int i = 0; i < N; i++){ cout << setw(5) << i; } cout << endl; cout << "array:"; for (int i = 0; i < N; i++){ cout << setw(5) << A[i]; } cout << endl; } static int int_compare(const void *p1, const void *p2) { return (*(const int *)p1 - *(const int *)p2); } int main() { const int N = 8; int A = {4, 4, 5, 6, 7, 2, 3, 4};/* = {6, 1, 5, 5, 5, 3, 6, 4};*/ srandom((unsigned int)time(NULL)); print_array(A, N); case_test(rotated_search(A, N, 5)); for (int i = 0; i < N; i++) A[i] = random() % N; qsort(A, N, sizeof(int), int_compare); print_array(A, N); case_test(rotated_search(A, N, 3)); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); left_rotate_1(A, N); print_array(A, N); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); left_rotate_1(A, N); left_rotate_1(A, N); print_array(A, N); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); case_test(rotated_search(A, N, random() % N)); return 0; }
相关文章推荐
- 在旋转后的有序数组中查找元素,要求O(logn)的时间复杂度
- 面试题精选(75):经过旋转的有序数组中的元素查找(要求复杂度为O(lgn))
- 一个数组中除了两个数字之外,其余数字均出现了两次,如{1,2,3,4,5,3,2,1}.查找出这两个只出现一次的数字。要求时间复杂度为O(n),空间复杂度为O(1)。
- 11.3---旋转有序数组之后查找元素(CC150)
- 算法面试题——两个有序数组,将一个数组放入另一个空间很大的数组,要求合并之后依然有序,时间复杂度要求最小,不使用额外的数组。
- 查找无序数组中的一个元素下标,并分析时间和空间复杂度, 考虑效率(很重要)
- 试设计一个算法,将数组A(0..n-1)中的元素循环右移k位,并要求空间复杂度为O(1),时间复杂度为O(n)。
- 每天学习一算法系列(5)(已知两个数组,数组里的元素有正有负,但是都是按照从小到大已经排好序,要求用尽可能小的时间复杂度编写一算法求出两个数组的最大交集)
- 查找循环递增数组最小值,如3,4,5,1,2结果为1,要求时间复杂度尽量低
- 每天学习一算法系列(5)(已知两个数组,数组里的元素有正有负,但是都是按照从小到大已经排好序,要求用尽可能小的时间复杂度编写一算法求出两个数组的最大交集)
- 有序数组旋转后的元素值查找
- 给定一个经过一次旋转的有序数组,从中查找一个值,若存在返回它的索引,不存在返回-1,假定数组存在重复元素
- 字符串算法——查找有序数组旋转后的最小值(无重复元素)(Find Minimum in Rotated Sorted Array)
- 字符串算法——查找有序数组旋转后最小值(有重复元素)(Find Minimum in Rotated Sorted Array II)
- 在旋转有序数组中查找元素
- Java 旋转数组查找旋转点和任意元素(元素可重复)
- 循环有序数组/旋转数组的二分查找
- 插入元素到有序数组,二分搜索查找插入位置
- [练习题] 将数组中的负数全部移到非负数的前面,要求O(n)时间复杂度
- merge两个有序数组 & 查找一个有序数组中指定元素