算法通关村第九关——二分查找与搜索树的高频算法题

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;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值