摘要
【面试必刷101】系列blog目的在于总结面试必刷101中有意思、可能在面试中会被考到的习题。总结通用性的解题方法,针对特殊的习题总结思路。既是写给自己复习使用,也希望与大家交流。
【面试必刷101】递归/回溯算法总结I(十分钟理解回溯算法)
【面试必刷101】递归/回溯算法总结II(十分钟刷爆回溯算法题)
【面试必刷101】链表
【面试必刷101】二叉树
1 基础知识
二分查找首先是要满足二分的性质,啥性质呢?target点左边全部满足一类条件,target点右边全部不满足一类条件,而且能够通过条件判别目标的target是在左区间还是右区间。
二分查找用的最多的是有序的数组。看下图中的题目:
查找target的上界和下界的差异在于:看这个数是出现在左区间还是出现在右区间。如果是查找下界,那么只可能出现在左区间,有点像夹逼准则,左边夹逼出最小值,右边夹逼出最大值。
然后就会涉及到两个模板,左区间的模板和右区间的模板。很容易记住,两者的差别就在于计算mid的时候是否加1,左区间不加,右区间加1。
1.1 查找值在左区间
区间[l, r]
被划分成 [l, mid]
和[mid + 1, r]
时使用:
// 首先是查找下界,是要在左边找
int l = 0, r = n - 1, mid = 0;
while (l < r) {
mid = l + ((r - l) >> 1);
if (arr[mid] >= x) {
r = mid;
} else {
l = mid + 1;
}
}
1.2 查找上界
区间[l, r]
被划分成[l, mid - 1]
和[mid, r]
时使用:
// 接下来查找上界,是要在右边找
l = 0; r = n - 1;
while (l < r) {
mid = l + ((r - l + 1) >> 1);
if (arr[mid] <= x) {
l = mid;
} else {
r = mid - 1;
}
}
2 面试必刷习题
2.1 二维数组中的查找
二维数组中的查找
谁能想到找个暑期实习这个题居然被考了两回,发现面试的题不一定难,但代码量一般会比较少,思路很重要。
public class Solution {
public boolean Find(int target, int [][] array) {
int row = array.length;
int col = array[0].length;
int i = 0, j = col - 1;
while (i < row && j > -1) {
if (array[i][j] == target) {
return true;
} else if (array[i][j] > target) {
j--;
} else {
i++;
}
}
return false;
}
}
2.2 旋转数组中的最小数字
这里非得和右边比,有点无奈。
import java.util.*;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int l = 0, r = array.length - 1;
while (l < r) {
int mid = l + ((r - l) >> 1);
if (array[mid] > array[r]) {
l = mid + 1;
} else if (array[mid] < array[r]) {
r = mid;
} else {
--r;
}
}
return array[l];
}
}
我非要和左边比
import java.util.*;
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
// 求数组中的最小值
int l = 0, r = array.length - 1;
while (l < r) {
if (array[r] > array[l]) return array[l];
int mid = l + ((r - l) >> 1);
if (array[mid] > array[l]) {
l = mid + 1;
} else if (array[mid] < array[l]) {
r = mid;
} else {
++l;
}
}
return array[l];
}
}
这个老哥就不同,直接理解为与第一个的比较。这种思路比较符合我的特点。这个思路非常非常good,这才是二分该有的思路。
图中水平的实线段表示相同元素。
我们发现除了最后水平的一段(黄色水平那段)之外,其余部分满足二分性质:
竖直虚线左边的数满足rotateArray[i]≥rotateArray[0]暨nums[i]≥nums[0];
而竖直虚线右边的数不满足这个条件。分界点就是整个数组的最小值。所以我们先将最后水平的一段删除即可。
另外,不要忘记处理数组完全单调的特殊情况:删除最后水平的一段之后,如果剩下的最后一个数大于等于第一个数,则说明数组完全单调。
import java.util.*;
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int l = 0, r = array.length - 1;
//while (l < array.length - 1 && array[l + 1] == array[l]) l++;
while (r > 0 && array[r] == array[0]) r--;
if (array[r] >= array[l]) return array[l];
while (l < r) {
int mid = l + ((r - l) >> 1);
if (array[mid] >= array[0]) {
l = mid + 1;
} else {
r = mid;
}
}
return array[l];
}
}
3 知识点总结
二分查找的边界处理还是很麻烦,所以建议记一下那两个模板,对于其他两道题就比较灵活了,需要抓住二分的特点,实在不行记一下吧。
4 总结
焦虑了就休息下。