算法通关村——二分法的具体应用

基于二分查找的拓展问题

山脉数组的峰顶索引

LeetCode852

此时 mid 的值三种情况

  1. mid 对应在山峰的左侧 对应的条件是 arr[mid] > arr[mid - 1] && arr[mid] < arr[mid + 1]
  2. mid 对应在山峰的右侧 arr[mid] < arr[mid - 1] && arr[mid] > arr[mid + 1]
  3. mid 就是在山峰位置上,就是在最大位置处,大于左侧和右侧的值,arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1]
class Solution {
    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;
    }
}

旋转数字的最小数字

这里仍然可以使用二分法,进行缩小范围,提高效率

图片来源 leetCode

这里使用 leetcode 的解释图片

  • 当我们的初始位置中间位置在最小值的左边时,当我们的 left 到达最小值时,我们的 left 指针就在最小值的位置,而且不会改变位置直到 right 指针和 left 指针回合,退出循环。
  • 当我们的初始位置的中间值在最小值在右边时,我们的的 left = pivot 那么我们的 中间值就会向左移动,直到我们的中间位置在最小值的左边时,就和上面的情况类似
class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int pivot = left + ((right - left) >> 1);
            // 这里存在一个前提条件就是 right 其实是最小值右边的最大值,最小值左边的最小值
            if (nums[pivot] < nums[right]) {
                right = pivot;
            } else {
                left = pivot + 1;
            }
        }
        return nums[left];
    }
}

找缺失数字

剑指 Offer 53 - II. 0~n-1中缺失的数字

正常情况下,不缺失的话会满足 nums[X] == X

使用二分法就会出现下面几种情况

  1. mid 与此时的值不相等,此时 nums[X] == X 这个条件将不满足,那么就需要把 right 之指针向移动,即 right = mid - 1
  2. mid 此时的位置出现确实,这种情况比较简单直接返回即可
class Solution {
    public int missingNumber(int[] nums) {
        int left = 0;
        int right = nums.length - 1;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == mid) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }    
        }
        return left;
    }
}

x 的平方根

x 的平方根

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

中序与搜索树原理

中序遍历与二叉搜索树之间有紧密的关联,二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树结构,其中每个节点都满足以下特征:

  1. 节点的左子树(如果存在)上的所有节点的值都小于节点的值。
  2. 节点的右子树(如果存在)上的所有节点的值都大于节点的值。
  3. 左子树和右子树都是二叉搜索树。

这个定义确保了在一个二叉搜索树中,通过中序遍历可以得到一个递增的有序序列。中序遍历是一种遍历二叉树的方法,其过程是先遍历左子树,然后访问当前节点,最后遍历右子树。

对于一个二叉搜索树,使用中序遍历可以按照从小到大的顺序访问所有的节点值,这是因为中序遍历首先会访问左子树中的所有节点,然后是当前节点,最后是右子树中的所有节点。

由于中序遍历的这种性质,二叉搜索树经常被用来进行查找、插入和删除操作,因为在二叉搜索树中,查找特定值的效率相对较高。但需要注意的是,如果二叉搜索树的平衡性被破坏,它的效率可能会下降,因此在实际应用中,通常会对二叉搜索树进行平衡操作,以保持树的平衡性。

二叉搜索树中搜索特定值

700. 二叉搜索树中的搜索

使用递归

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        // 剪枝
        // 边界条件是如果 root 是 null 就返回 true,如果 root 的值和 val 相等那么就直接返回 root 
        if (root == null || val == root.val) {
            return root;
        }
        TreeNode node = new TreeNode();
        if (root.val > val) {
            node = searchBST(root.left, val);
        } else {
            node = searchBST(root.right, val);
        }
        return node;
    }
}

二叉搜索树中搜索特定值

leetcode98

class Solution {
    long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        // 左中右,不要想太多
        if (!isValidBST(root.left)) {
            return false;
        }
        // 这里 root 一定不为 null 
        if (root.val > pre) {
            pre = root.val;
        } else {
            return false;
        }
        if (!isValidBST(root.right)) {
            return false;
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值