当前位置: 首页 > news >正文

二分查找与搜索树的高频问题(算法村第九关白银挑战)

基于二分查找的拓展问题

山峰数组的封顶索引

852. 山脉数组的峰顶索引 - 力扣(LeetCode)

给你由整数组成的山脉数组 arr ,返回满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i

你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。

提示:

  • 3 <= arr.length <= 105
  • 0 <= arr[i] <= 106
  • 题目数据保证 arr 是一个山脉数组
二分查找
public int peakIndexInMountainArray(int[] arr)
{int low = 1;    //mid - 1 >= 0int high = arr.length - 2;  // mid + 1 <= arr.length - 1while (low <= high){int mid = low + (high - low >> 1);//找到山峰if(arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1])return mid;//山峰左侧(递增)else if(arr[mid] > arr[mid - 1] && arr[mid] < arr[mid + 1])low = mid + 1;//山峰右侧(递减)elsehigh = mid - 1;}return -1;
}

旋转排序数组的最小值

无重复元素

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

已知一个长度为 n 的数组,预先按照升序排列,经由 1n旋转 后,得到输入数组。例如,原数组 nums = [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]]

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

二分查找

在这里插入图片描述

在这里插入图片描述

nums [pivot] >= nums [high] 时,移动 low

在这里插入图片描述

public int findMin(int[] nums){int left = 0;int right = nums.length - 1;while (left < right)  // left == right 时找到最低点(最小值){int mid = left + (right - left >> 1);if(nums[mid] < nums[right])right = mid; //让 right 去触碰最低点(因为无法确定mid是不是最低点下标,故不能跳过它。如果是比较数值,那可以直接跳过,即 right = mid + 1)elseleft = mid + 1;  // left 迫近最低点,与 right 汇合}return nums[left];   //left == right == mid}
有重复元素

154. 寻找旋转排序数组中的最小值 II - 力扣(LeetCode)

二分查找

重复元素要一个个排除

public int findMin(int[] nums){int left = 0;int right = nums.length - 1;while (left < right)  // left == right 时找到最低点(最小值){int mid = left + (right - left >> 1);if(nums[mid] < nums[right])right = mid; //让 right 去触碰最低点else if(nums[mid] > nums[right])left = mid + 1;  // left 迫近最低点,与 right 汇合elseright--; //处理重复元素要一步一步来}return nums[left];   //left == right == mid}

缺失的数字

剑指 offer :一个长度为 n - 1 的递增排序数组中的所有数字都是唯一的,每个数字的范围都是 [0,n-1] 。在范围 0~n-1 内的 n 个数字中有且只有一个数字不在该数组中,请找出这个数字。

LCR 173. 点名 - 力扣(LeetCode)

某班级 n 位同学的学号为 0 ~ n-1。点名结果记录于升序数组 records。假定仅有一位同学缺席,请返回他的学号。

示例 1:

输入: records = [0,1,2,3,5]
输出: 4

示例 2:

输入: records = [0, 1, 2, 3, 4, 5, 6, 8]
输出: 7

提示:

1 <= records.length <= 10000
二分查找
public static int missingNumber(int[] nums)
{int left = 0;int right = nums.length - 1;while (left <= right){int mid = left + (right - left >> 1);if (nums[mid] == mid)left = mid + 1; //让 left 去触碰缺失的元素,碰到后就不动了,交给 right 结束循环elseright = mid - 1;}return left;
}public static void main(String[] args)
{// n = 3 个数字, 数组长度(元素个数)为 n - 1 = 2, 元素范围 [0,2]int[] nums = {0, 1};System.out.println(missingNumber(nums)); // 输出 2// n = 7 个数字, 数组长度(元素个数)为 n - 1 = 6, 元素范围 [0,6]int[] nums2 = {0, 1, 2, 3, 5, 6};System.out.println(missingNumber(nums2)); // 输出 4
}

x 的平方根

LCR 072. x 的平方根 - 力扣(LeetCode)

给定一个非负整数 x ,计算并返回 x 的平方根,即实现 int sqrt(int x) 函数。

正数的平方根有两个,只输出其中的正数平方根。

如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去。

示例 1:

输入: x = 4
输出: 2

示例 2:

输入: x = 8
输出: 2
解释: 8 的平方根是 2.82842...,由于小数部分将被舍去,所以返回 2

提示:

  • 0 <= x <= 231 - 1
二分查找实现
public int mySqrt(int x)
{int left = 1;int right = x;int ans = 0;while (left <= right){int mid = left + (right - left >> 1);if(x / mid >= mid)  //x >= mid²{ans = mid;  //向下取整逼近答案left = mid + 1;}elseright = mid - 1;}return ans;
}

更多题目

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

875. 爱吃香蕉的珂珂 - 力扣(LeetCode)

29. 两数相除 - 力扣(LeetCode)

中序遍历与搜索树

简单来说,如果一棵二叉树是搜索树,则中序遍历序列是一个递增序列。

比较规范的定义是:

  • 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  • 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

它的左、右子树也分别为二叉排序树。

下面两棵树的中序序列分别是{3,6,9,10,14,16,19},{3,6,9,10},因此都是搜索树。

在这里插入图片描述

二叉搜索树中的搜索

700. 二叉搜索树中的搜索 - 力扣(LeetCode)

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null

示例 1:

img
输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

示例 2:

img
输入:root = [4,2,7,1,3], val = 5
输出:[]
递归
public TreeNode searchBST(TreeNode root, int val)
{if (root == null || root.val == val)return root;if (val < root.val) //进入左子树搜索return searchBST(root.left, val);else    //否则进入右子树搜索return searchBST(root.right, val);
}
迭代
public TreeNode searchBST(TreeNode root, int val)
{while (root != null){if (root.val == val)break;else if (val < root.val)root = root.left;elseroot = root.right;}return root;
}

验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode)

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

img
输入:root = [2,1,3]
输出:true

示例 2:

img
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4

提示:

  • 树中节点数目范围在[1, 104]
  • -231 <= Node.val <= 231 - 1
中序遍历+实时检查

二叉搜索树「中序遍历」序列是升序的,所以我们在中序遍历时,实时检查当前节点的值是否大于前一个节点的值即可。

long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root)
{if (root == null)return true;//检查左子树是否为二叉搜索树if(!isValidBST(root.left))  //等待左子树的返回结果。如果左子树下某个元素不满足要求,则退出所有递归return false;//检查当前节点是否大于等于前一个节点if (root.val <= pre)return false;pre = root.val;//检查右子树是否为二叉搜索树return isValidBST(root.right);  //等待右子树的返回结果
}
中序遍历+是否升序
public boolean isValidBST(TreeNode root)
{ArrayList<Integer> res = new ArrayList<>();inOrder(root,res);for (int i = 1; i < res.size(); i++)if (res.get(i - 1) >= res.get(i))return false;return true;
}public void inOrder(TreeNode root, ArrayList<Integer> res)
{if (root == null)return;inOrder(root.left, res);res.add(root.val);inOrder(root.right, res);
}

更多题目

530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

501. 二叉搜索树中的众数 - 力扣(LeetCode)

http://www.lryc.cn/news/281454.html

相关文章:

  • Python爬虫快速入门
  • 部署MinIO
  • RK3566环境搭建
  • 精确掌控并发:滑动时间窗口算法在分布式环境下并发流量控制的设计与实现
  • Python展示 RGB立方体的二维切面视图
  • 03 顺序表
  • 2023年全球软件开发大会(QCon北京站2023)9月:核心内容与学习收获(附大会核心PPT下载)
  • ChatGPT 和 文心一言 的优缺点及需求和使用场景
  • 架构师之超时未支付的订单进行取消操作的几种解决方案
  • 【容器固化】 OS技术之OpenStack容器固化的实现原理及操作
  • 设置 SSH 通过密钥登录
  • 1.6 面试经典150题 - 买卖股票的最佳时机
  • locust快速入门--使用分布式提高测试压力
  • K8s(三)Pod资源——pod亲和性与反亲和性,pod重启策略
  • 免费的域名要不要?
  • 高通sm7250与765G芯片是什么关系?(一百八十一)
  • [Python进阶] Python操作MySQL数据库:pymysql
  • Vue3实现带点击外部关闭对应弹出框(可共用一个变量)
  • 可视化试题(一)
  • RHCE 【在openEuler系统中搭建基本论坛(网站)】
  • 20240112让移远mini-PCIE接口的4G模块EC20在Firefly的AIO-3399J开发板的Android11下跑通【DTS部分】
  • 日志采集传输框架之 Flume,将监听端口数据发送至Kafka
  • 关于Vue前端接口对接的思考
  • 【设计模式之美】SOLID 原则之三:里式替换(LSP)跟多态有何区别?如何理解LSP中子类遵守父类的约定
  • 代码随想录第六十三天——被围绕的区域,太平洋大西洋水流问题,最大人工岛
  • Docker 项目如何使用 Dockerfile 构建镜像?
  • 实践学习PaddleScience飞桨科学工具包
  • Vue 中修改 Element 组件的 下拉菜单(Dropdown) 的样式
  • 达梦数据库主备集群
  • Spark Doris Connector 可以支持通过 Spark 读取 Doris 数据类型不兼容报错解决