二分算法到红蓝染色

我的学习来源主要是灵神的力扣题解

下面是一个简单的二分查找的代码

复制代码
java 复制代码
public static int findPeakElement(int[] nums) {
        int left = 0;
        int right = nums.length - 2; // 初始右边界为倒数第二个元素
        
        while (left <= right) {
            int mid = left + (right - left) / 2; // 防止整数溢出的中间值计算
            
            // 比较中间元素和右侧元素
            if (nums[mid] < nums[mid + 1]) {
                left = mid + 1; // 峰值在右侧,调整左边界
            } else {
                right = mid - 1; // 峰值在左侧或当前元素为峰,调整右边界
            }
        }
        
        return left; // 最终left指向峰值位置
    }

这个代码很常见,每次去取mid然后比较就ok了,适用于有序数组。时间复杂度logn

之前做过一家大厂笔试题,其中有道题叫找出可能存在的二分序列有下面几个

10 20 30 40

40 10 20 30

20 30 40 10

40 20 10 30

正确的答案应该是第一个和第二个,二分序列就是每次的mid值

为什么呢

因为这个二分查找有一个隐藏性质和快速排序类似,就是每一次操作之后,左边小于mid,右边大于mid。

等于的情况得自己定义了

这个性质看似很简单,但是却延申出了用二分做算法题的一个常见方法

红蓝染色法

红蓝染色法

left指针掌管左边蓝色区域,蓝色表示 truej即所求值及其右侧,right指针掌管右边红色区域,红色表示false即所求值左侧,两者互不冲突,通过不断向目标区域靠近,扩大两个指针的掌管区域,直到两者掌管的区域接壤

使用闭区间时,L-1必定是红色即false,R+1必定是蓝色即true,这就是循环不变量

关键不在于区间里的元素具有什么性质,而是区间外面的元素具有什么性质,即将区间外染成红色与蓝色。

根据以上两点,在做题时关键即确定二分条件函数isBlue(),判断是否满足条件,满足条件则right 左移使右侧变蓝 ,不满足条件则left 右移使左侧变红

核心思想就是去查找一个数时,他的左右必然是不满足同一个法则的,有规律1的染红,有规律2的染蓝,交界处即为所求。

LeetCode162. 寻找峰值这道题

java 复制代码
public static int findPeakElement(int[] nums) {
        int left = 0;
        int right = nums.length - 2; // 初始右边界为倒数第二个元素
        
        while (left <= right) {
            int mid = left + (right - left) / 2; // 防止整数溢出的中间值计算
            
            // 比较中间元素和右侧元素
            if (nums[mid] < nums[mid + 1]) {
                left = mid + 1; // 峰值在右侧,调整左边界
            } else {
                right = mid - 1; // 峰值在左侧或当前元素为峰,调整右边界
            }
        }
        
        return left; // 最终left指向峰值位置
    }

这个时候红色的规则是什么

nums[mid] < nums[mid + 1]

蓝色的规则呢

nums[mid] > nums[mid + 1]

这道题还比较简单,下面再看一道,懂了应该就能明白这个办法了

LeetCode33. 搜索旋转排序数组

先找到旋转数组的最小值

即min的位置,然后比较目标值与E的大小

再使用正常的二分搜索

复制代码
java 复制代码
public class RotatedBinarySearch {

 
    public static int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 2; // 初始右边界为倒数第二个元素
        
        while (left <= right) {
            int mid = left + (right - left) / 2; // 防止溢出的中间值计算
            
            // 比较中间元素和最后一个元素
            if (nums[mid] < nums[nums.length - 1]) {
                right = mid - 1; // 最小值在左半区
            } else {
                left = mid + 1; // 最小值在右半区
            }
        }
        
        return left; // 返回最小值索引
    }

   
    public static int lowerBound(int[] nums, int left, int right, int target) {
        int r0 = right; // 保存初始右边界
        
        while (left <= right) {
            int mid = left + (right - left) / 2;
            
            if (nums[mid] < target) {
                left = mid + 1; // 目标在右半区
            } else {
                right = mid - 1; // 目标在左半区
            }
        }
        
        // 检查是否越界或未找到
        if (left == r0 + 1 || nums[left] != target) {
            return -1;
        }
        return left;
    }

    public static int search(int[] nums, int target) {
        int i = findMin(nums);
        
        // 根据目标值与末尾元素比较决定搜索区间
        if (target > nums[nums.length - 1]) {
            return lowerBound(nums, 0, i - 1, target); // 搜索左半区
        }
        return lowerBound(nums, i, nums.length - 1, target); // 搜索右半区
    }

这里主要说说找最小值的染色

红色:nums[mid] > nums[nums.length - 1]

蓝色:nums[mid] < nums[nums.length - 1]

相关推荐
yiqiqukanhaiba16 分钟前
Linux编程笔记2-控制&数组&指针&函数&动态内存&构造类型&Makefile
数据结构·算法·排序算法
PKNLP26 分钟前
逻辑回归(Logistic Regression)
算法·机器学习·逻辑回归
南方者31 分钟前
【JAVA】【BUG】经常出现的典型 bug 及解决办法
java·oracle·bug
可触的未来,发芽的智生1 小时前
新奇特:神经网络的自洁之道,学会出淤泥而不染
人工智能·python·神经网络·算法·架构
放羊郎1 小时前
SLAM算法分类对比
人工智能·算法·分类·数据挖掘·slam·视觉·激光
初圣魔门首席弟子2 小时前
c++嵌套类和局部类详细介绍
java·开发语言·c++
nice_lcj5202 小时前
Java 集合框架之 List 全面解析(从概念到实践)
java·windows·list
Juan_20122 小时前
P1447题解
c++·数学·算法·题解
ai智能获客_狐狐2 小时前
智能外呼产品架构组成
人工智能·算法·自然语言处理·架构·语音识别
高山上有一只小老虎2 小时前
输出单向链表中倒数第k个结点
java·数据结构·链表