1.基于二分查找的2扩展问题
1.1山脉数组的封顶索引
简单的方法
public static int peakIndexInMountainArray(int[] arr) {
int n = arr.length;
int ans = -1;
for (int i = 1; i < n - 1; ++i) {
if (arr[i] > arr[i + 1]) {
ans = i;
break;
}
}
return ans;
}
二分法
public int peakIndexInMountainArray(int[] arr){
if (arr.length==3){
return 1;
}
int left = 1,right = arr.length - 2;
while(left < right){
int mid = left + ((right - left)>>1);
if (arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1]){
return mid;
}
if (arr[mid] < arr[mid +1] && arr[mid] < arr[mid -1]){
left = mid + 1;
}
if (arr[mid]arr[mid 1]&arr[mid]arr[mid -1]){
right = mid - 1;
}
}
return left;
}
1.2旋转数字的最小数字
LeetCode153已知一个长度为n的数组,预先按照升序排列,经由1到n次旋转后,得到输入数组。例如
原数组ums=[0,1,2,4,5,6,7]在变化后可能得到:
·若旋转4次,则可以得到[4,5,6,7,0,1,2]
·若旋转7次,则可以得到[0,1,2,4,5,6,7]
注意,数组[a[0],a[1],a[2],,a[n-1]旋转一次的结果为数组[a[n-1],a[0],a[1,a[2],,a[n-2]。
示例1:
输入:num5=[4,4,4,5,1,2,3]
输出:1
解释:原数组为[1,2,3,4,5],旋转3次得到输入数组。
示例2:
输入:nums=[4,5,6,7,0,1,2]
输出:0
解释:原数组为[0,1,2,4,5,6,7],旋转4次得到输入数组。
我们考虑数组中的最后一个元素x:在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都严格小于X;而在最小值左侧的元素,它们的值一定都严格大于X。将中轴元素nums[pivot]与右边界元素nums[high]进行比较,可能会有以下的两种情况:
1.nums[pivot] > nums[high]:说明num[pivot]是最小值右侧元素,因此可以忽略二分查找的右半部分
2.nums[pivot] < nums[high]:说明num[pivot]是最小值左侧元素,因此可以忽略二分查找的左半部分
public static int findMin(int[] nums) {
int low = 0;
int high = nums.length - 1;
while (low < high) {
int pivot = low + ((high - low) >> 1);
if (nums[pivot] < nums[high]) {
high = pivot;
} else {
low = pivot + 1;
}
}
return nums[low];
}
1.3找缺失数字
剑指offr题目:一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~-1内的个数字中有且只有一个数字不在该数组中,请找出这个数字。
这个题很简单是不?从头到尾遍历一遍即可确定,但是这么简单肯定不是面试需要的。那这个题要考什么呢?就是二分查找。
对于有序的也可以用二分查找,这里的关键点是在缺失的数字之前,必然有ums的==,在缺失的数字之后,必然有nums[!=i。
因此,只需要二分找出第一个ums]!=i,此时下标i就是答案。若数组元素中没有找到此下标,那么缺失的就是n。代码如下:
public static int solve(int[] a) {
int left = 0;
int right = a.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (a[mid] == mid) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
1.4优化平方根
public static int sqrt (int x) {
int l=1,r=x;
while(l <= r){
int mid = l + ((r - l)>>1);
if(x/mid > mid){
l = mid + 1;
} else if(x / mid < mid){
r = mid - 1;
} else if(x/mid == mid){
return mid;
}
}
return r;
}
2.中序与搜索树原理
2.1二叉搜索树中搜索特定值
递归:
·如果根节点为空root==nul或者根节点的值等于搜索值val==root.val,返回根节点。
·如果val<root.val,进入根节点的左子树查找searchBST(root.left,val。
·如果val>root.val,进入根节点的右子树查找searchBST(root.right,,val)。
public static TreeNode searchBST(TreeNode root, int val) {
if (root == null || val == root.val) {
return root;
}
return val < root.val ? searchBST(root.left, val) : searchBST(root.right, val);
}
迭代:
。如果根节点不空root!=null且根节点不是目的节点va!=root.va:
。如果val<root.val,进入根节点的左子树查找root=root.left。
。如果val>root.val,进入根节点的右子树查找root=root.right。
public static TreeNode searchBST2(TreeNode root, int val) {
while (root != null && val != root.val) {
root = val < root.val ? root.left : root.right;
}
return root;
}
2.2验证二叉搜索树
有效二叉搜索树定义如下:
·节点的左子树只包含小于当前节点的数。
·节点的右子树只包含大于当前节点的数。
·所有左子对和右子树自身必须也是二叉搜索树。
递归:
public static boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
// 如果左子树下某个元素不满足要求,则退出
if (!isValidBST(root.left)) {
return false;
}
// 访问当前节点:如果当前节点小于等于中序遍历的前一个节点,说明不满足BST,返回 false;否则继续遍历。
if (root.val <= pre) {
return false;
}
pre = root.val;
// 访问右子树
return isValidBST(root.right);
}
迭代:
public static boolean isValidBST2(TreeNode root) {
Deque<TreeNode> stack = new LinkedList<TreeNode>();
double inorder = 0;
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
// 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
if (root.val <= inorder) {
return false;
}
inorder = root.val;
root = root.right;
}
return true;
}