一道简单的面试题:竟然有90%的程序员不能把这个算法完全写出来

本文深入探讨二分查找及其变种的实现,包括寻找第一个与key相等的元素、最后一个与key相等的元素等,旨在帮助程序员更好地掌握这一基本算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间,在论坛上看到有统计说有90%的程序员不能够写对简单的二分法。二分法不是很简单的吗? 这难道不是耸人听闻?

其实,二分法真的不那么简单,尤其是二分法的各个变种。 最最简单的二分法,就是从一个排好序的数组之查找一个key值。 如下面的程序。

/**
 * 二分查找,找到该值在数组中的下标,否则为-1
 */
static int binarySerach(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] == key) {
 return mid;
 }
 else if (array[mid] < key) {
 left = mid + 1;
 }
 else {
 right = mid - 1;
 }
 }
 return -1;
}

这个程序,相信只要是一个合格的程序员应该都会写。 稍微注意一点, 每次移动left和right指针的时候,需要在mid的基础上+1或者-1, 防止出现死循环, 程序也就能够正确的运行。

但如果条件稍微变化一下, 你还会写吗?如,数组之中的数据可能可以重复,要求返回匹配的数据的最小(或最大)的下标;更近一步, 需要找出数组中第一个大于key的元素(也就是最小的大于key的元素的)下标,等等。 这些,虽然只有一点点的变化,实现的时候确实要更加的细心。 下面列出了这些二分检索变种的实现。

1、找出第一个与key相等的元素

// 查找第一个相等的元素
static int findFirstEqual(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] >= key) {
 right = mid - 1;
 }
 else {
 left = mid + 1;
 }
 }
 if (left < array.length && array[left] == key) {
 return left;
 }

 return -1;
}

2、找出最后一个与key相等的元素

// 查找最后一个相等的元素
static int findLastEqual(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] <= key) {
 left = mid + 1;
 }
 else {
 right = mid - 1;
 }
 }
 if (right >= 0 && array[right] == key) {
 return right;
 }
 return -1;
}

3、查找第一个等于或者大于Key的元素

// 查找第一个等于或者大于key的元素
static int findFirstEqualLarger(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] >= key) {
 right = mid - 1;
 }
 else {
 left = mid + 1;
 }
 }
 return left;
}

4、查找第一个大于key的元素

// 查找第一个大于key的元素
static int findFirstLarger(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] > key) {
 right = mid - 1;
 }
 else {
 left = mid + 1;
 }
 }
 return left;
}

5、查找最后一个等于或者小于key的元素

// 查找最后一个等于或者小于key的元素
static int findLastEqualSmaller(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] > key) {
 right = mid - 1;
 }
 else {
 left = mid + 1;
 }
 }
 return right;
}

6、查找最后一个小于key的元素

// 查找最后一个小于key的元素
static int findLastSmaller(int[] array, int key) {
 int left = 0;
 int right = array.length - 1;
 // 这里必须是 <=
 while (left <= right) {
 int mid = (left + right) / 2;
 if (array[mid] >= key) {
 right = mid - 1;
 }
 else {
 left = mid + 1;
 }
 }
 return right;
}

接下来,大家可以对这四种变种算法进行相应的测试。

很多的时候,应用二分检索的地方都不是直接的查找和key相等的元素,而是使用上面提到的二分检索的各个变种,熟练掌握了这些变种,当你再次使用二分检索的检索的时候就会感觉的更加的得心应手了。

针对于上面的文章我总结出了互联网公司java程序员面试涉及到的绝大部分面试题及答案做成了文档和架构视频资料(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值