Java笔试题:移位有序数组二分查找
问题:
给定一个数组A及其大小n,同时给定需要查找的元素x,已知数组A是由一个排过序的数组向左移位了一定长度得到的,请返回x在现数组的位置(位置从0开始,(保证数组中元素互异)
输入:
{19,30,44,1,2,3,4,5,8,16},10,5 (表示输入10个数据,查找数据为5的元素位置)
答案:
7
这道题不知道leetCode上有木有,记录一下。
我的想法就是用递归实现二分查找。
先定义每次递归的Left(最左下标元素)、Mid((Left+Right)/2)、Right(最右下标元素),
这种情况下,单纯的二分查找是不行的,要分三种情况:
(1)Left到Mid有序,Mid到Right不完全有序
(2)Left到Mid不完全有序,Mid到Right有序
(3)Left到Mid有序,Mid到Right有序
同时还要想到普通二分查找中需要对Mid、Left、Right进行分析比较:
在(1)情况下,如果元素x介于Left到Mid中间,就递归调用Left到Mid,
如果元素x不介于Left到Mid中间,就递归调用Mid到Right
在(2)情况下,如果元素x介于Mid到Right中间,就递归调用Mid到Right,
如果元素x不介于Mid到Right中间,就递归调用Left到Mid
在(3)情况下,如果元素x介于Left到Mid中间,就递归调用Left到Mid
如果元素x介于Mid到Right中间,就递归调用Mid到Right
我从LeetCode上看到过一种(Left+Right)/2的写法,为了避免Left+Right可能存在溢出的情况:
int mid=left+(right-left)/2;
//而不是
int mid=(right+left)/2;
最终代码
{
//给定一个数组A及其大小n,同时给定需要查找的元素x,已知数组A是由一个排过序的
//数组向左移位了一定长度得到的,请返回x在现数组的位置(位置从0开始),
//保证数组中元素互异
public int findElement(int[] A, int n, int x) {
return div(A, n, x, 0, n - 1);
}
public int div(int[] A, int n, int x, int left, int right) {
if (left > right)
return -1;
int mid = left + (right - left) / 2;
if (A[mid] == x)
return mid;
if (A[mid] >= A[right] && A[left] <= A[mid])//情况1 Left到Mid有序,Mid到Right不完全有序
{
if (x < A[mid] && x >= A[left])
return div(A, n, x, left, mid - 1);
else
return div(A, n, x, mid + 1, right);
} else if (A[mid] <= A[right] && A[left] >= A[mid])//情况2 Left到Mid不完全有序,Mid到Right有序
{
if (x > A[mid] && x <= A[right])
return div(A, n, x, mid + 1, right);
else
return div(A, n, x, left, mid - 1);
} else if (A[mid] <= A[right] && A[left] <= A[mid])//情况3 Left到Mid有序,Mid到Right有序
{
if (x > A[mid])
return div(A, n, x, mid + 1, right);
else
return div(A, n, x, left, mid - 1);
}
return -1;
}
public static void main(String[] args) {
int[] A = {19, 30, 44, 1, 2, 3, 4, 5, 8, 16};
System.out.println(new Finder3().findElement(A, 10, 5));
}
}