ChatGPT,为啥写二分搜索容易死循环?

2023-03-30 23:38:02 浏览数 (1)

背景

这段时间ChatGPT在码农界,引起了不小轰动,最热的话题中有一个与程序员息息相关,它会写代码那程序员是不是会集体下岗? 刚好最近听说了这么一句话,“90%程序员都写不对二分搜索”,那就整个二分搜索最常见的问题考考ChatGPT


了不起: 为什么写二分搜索容易死循环?

ChatGPT: 一个常见的原因是在二分搜索中没有正确处理边界情况,例如:

1、非递归实现中,循环终止条件可能不正确,导致死循环;

2、递归实现中,递归条件可能不正确,导致无限递归。

此外,当待搜索的数组不是有序时,也可能导致搜索结果不正确或死循环。 如果你遇到了这个问题,可以仔细检查你的代码并尝试调试。可以使用打印语句或者调试器来寻找问题所在。同时,你也可以参考其他人的代码或者算法实现,再次检查你的思路是否正确。


了不起觉得,还算是一个中规中矩的答案,并没有十分惊艳,不过也讲到了关键所在就是条件处理。

随后让它给出一个二分搜索的代码,也与搜索引擎提供基本一致,没有系统的对二分问题做出分类,以下了不起总结的普通二分和不等式二分,几乎涵盖了所有的二分问题的方法论。

一、普通二分搜索

普通的二分搜索,就不再赘述,属于基本功了,现在的大多数算法面试也基本不再问。

1.1 编码实战
代码语言:javascript复制
public class _1_BinarySearch {
    public int basicBinarySearch(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left   right) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid   1;
            }
        }
        return -1;
    }
}
1.2 注意点

实数的二分就不用考虑所谓的mid 1和mid-1,因为index是整数是离散的,不是连续精确的,变更区间条件时出现死循环。

二、不等式二分搜索

2.1 三步走

1、写出二分的条件,需要满足的条件,包含mid的branch;

2、条件放到if,确定要求满足条件的mid的min(right = mid)或者max(left = mid);

3、else left = mid 1 或 right = mid - 1,后者需要在mid取值的时候补上 1。

2.2 注意点

mid取值补上1,是为了防止死循环,当left和right为5和6时,模拟想想。

前驱和后继和条件本身无关,与是否满足条件相关,如果是满足求min即是后继。

需要考虑如何表示无解?前驱left = -1,表示无解;后继right= n,表示无解。

2.3 编码实战

一段有序的数组但是有重复数组,搜索出目标数字的index区间。

代码语言:javascript复制
public class _1_BinarySearch {
    public int[] searchRange(int[] nums, int target) {
        int leftBound = leftBound(nums, target);
        int rightBound = rightBound(nums, target);
        if (leftBound > rightBound) {
            return new int[]{-1, -1};
        }
        return new int[]{leftBound, rightBound};
    }
    // 前驱型往前找
    int rightBound(int[] nums, int target) {
        int left = -1;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (left   right   1) / 2;
            if (nums[mid] <= target) {
                left = mid; // max 向右扩张
            } else {
                right = mid - 1;
            }
        }
        return left;
    }
    // 后继型往后找
    int leftBound(int[] nums, int target) {
        int left = 0;
        int right = nums.length;
        while (left < right) {
            int mid = (left   right) / 2;
            // 条件考虑了nums[mid],即func(mid)的递增递减关系,需要满足这个条件
            if (nums[mid] >= target) {
                right = mid; // min 向左收缩
            } else {
                left = mid   1;
            }
        }
        return left;
    }
}

小结

1、以上二分搜索,对于mid是否溢出均未处理,如果给了数据集接近int的max,那么可以这么取mid = left (right - left) / 2。

2、不等式二分搜索,属于常考的题目了,用于求取一些难解问题的最优值,这些难解的问题都有一个特点,问题可以转化成判定问题,这时候就可以二分的条件求值。

0 人点赞