假如有一个排好序的整型数组,例如「1,2,3,4,5,6,7,8,9」, 从某处截断,后面一段整体移动到左边一段的左边,例如变成「5,6,7,8,9,1,2,3,4」,这样处理后的数组成为分截排序数组,给定一个分截排序数组,如何做二分搜索?
这道题理论上不难,曾经去携程面试的时候问到过,当时没怎么刷算法,答得有点慢,现在手头有几个offer了,索性总结一下:
思路如下,第一步还是找到中位,例如「5,6,7,8,9,1,2,3,4」的中位在9这个数字这里,这时,可能有两种情况,必属其一:第一,中位数处在“左段”,第二,中位数处在“右段”,所谓左段就是整体被从原始有序数组移到左边去的那一段,其余部分统称“右段”,那么如果中位数属于左段,则从开始位置到中位数都是完全排序好的,而从中位数到末尾位置又是一个子分截排序数组。理解清了这一点,就可以写递归了,废话不多说,上代码:
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Solution {
public int findIndex(int[] sectionOrder, int val){
return innerFindIndex(sectionOrder, 0, sectionOrder.length-1, val);
}
public int innerFindIndex(int[] arr, int start, int end, int val){
if(start>end){
return -1;
}else if(start==end){
if(val==arr[start]){
return start;
}else{
return -1;
}
}else{
int mid = (start+end)/2;
if(arr[mid]==val){
return mid;
}
if(arr[mid]>=arr[start]){
//mid in left section
if(val>=arr[start] && val<=arr[mid]){
//val in leftSection
return binarySearch(arr, start, mid, val);
}else{
return innerFindIndex(arr, mid, end, val);
}
}else if(arr[mid]<=arr[end]){
//mid in right section
if(val>=arr[mid] && val<=arr[end]){
return binarySearch(arr, mid, end, val);
}else{
return innerFindIndex(arr, start, mid, val);
}
}else{
return -1;
}
}
}
public int binarySearch(int[] arr, int start, int end, int val){
if(start>end){
return -1;
}else if(start==end){
if(val==arr[start]){
return start;
}else{
return -1;
}
}
int mid = (start+end)/2;
if(arr[mid]==val){
return mid;
}else if(val>arr[mid]){
return binarySearch(arr, mid+1, end, val);
}else{
return binarySearch(arr, start, mid-1, val);
}
}
public static void main(String[] args){
Solution sol = new Solution();
int[] bin = {1,3,5,7,9,13,17};
int[] arr={15,16,19,1,3,5,6,7,13};
System.out.println(sol.findIndex(arr, 3));
}
}