查找和排序
查找喝排序都是在程序设计中经常用到的算法,查找相对而言较为简单,不外乎顺序查找,二分查找,哈希表查找和二叉树排序查找。在面试的时候,不管使用循环还是用递归,面试官都期待应聘者能够信手拈来写出完整正确的二分查找代码,否则可能连继续面试的兴趣都没有。
如果面试题是要求在排序的数组(或者部分排序的数组)中查找一个数字或者统计某个数字出现的次数,那么我们都可以尝试用二分查找算法。
哈希表和二叉排序树查找的重要在于考查对应的数据结构而不是算法。哈希表最主要的有点使我们利用它能够在o(1)的时间内查找某个元素,是效率最高的查找方式;但其缺点是需要额外的空间来实现哈希表。
排序比查找要复杂一些,面试官会经常要求应聘者比较插入排序、冒泡排序、归并排序、快速排序等不同算法的优劣。强烈建议应聘者能在准备面试的时候,一定对各种排序算法的特点熟烂于胸,能够从额外的空间消耗,平均时间复杂度和最差时间复杂度方面去比较它们的优缺点。
面试题 11 旋转数组的最小数字
这道题最直观的解法并不难,从头到尾遍历数组一次,我们就能找出最小的元素,这种思路的时间复杂度显然是n,但是这种思路没有利用输入的旋转数组的特性,肯定达不到面试官的要求。
我们注意到旋转之后的数组实际上可以划分成两个排序的子数组,而且前面子数组的元素都大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是两个子数组的分界线。在排序的数组中我门可以用二分查找法实现logn查找。本体给出的数组在一定程序上是排序的,因此我们可以试着用二分查找的思路来寻找这个最小的元素
和二分查找发一样,我们用两个指针分别指向数组的第一个元素和最后一个元素的(这其实不完全对,还有特例,后面再加以讨论)
接着我们可以找到数组总价你的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等与第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的第一指针仍然位于前面的递增子数组。
同样,如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。我们可以把第二个指针指向该中间元素,这样也可以缩小寻找的范围。移动之后的第二个指针仍然位于后面的递增子数组。
不管是移动第一个指针还是第二个指针,查找范围都会缩小到原来的一半。
package question11_find_min;
/**
* @Classname Solution1
* @Description TODO
* @Date 2020/3/8 16:32
* @Created by mmz
*/
public class Solution1 {
public static int findMin(int[] arr){
int max = arr.length-1;
int min = 0;
int mid = 0;
if(max == min){
return arr[max];
}
while(min<max &&(max-min) != 1){
mid = (max+min)/2;
if(arr[mid] >= arr[min]){
min = mid;
}else{
max = mid;
}
}
return arr[max];
}
public static void main(String[] args) {
int[] arr =new int[]{4};
System.out.println(findMin(arr));
}
}
if(arr[max] > arr[min]){
return arr[min];
}
如果这个数组是正常的数组那么就需要判断一下。
如果这个数组特殊情况
if(arr[max] == arr[min] &&arr[max]== arr[mid]){
Arrays.sort(arr);
return arr[0];
}
int[] arr =new int[]{1,0,1,1};
那么就需要重新排序再进行计算