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

Leetcode 33 -- 二分查找 | 归约思想

题目描述

搜索旋转排序数组

二分的过程就是归约的过程

思路来源
一个重要的性质:源数组经过旋转之后,会划分为两个递增的数组,我们假设为 a a a b b b
一个清晰的思路:这道题和平常二分法查找的不同就在于,把一个有序递增的数组分成了,两个递增的数组,我们需要做的就是判断这个数在哪一个递增的数组中,然后再去用常规的二分法去解决。
一个假设:我们一般性的假设源数组被旋转为: [ b 1 , b 2 , . . b m , a 1 , a 2 , a 3 , . . . , a n ] [b1, b2, ..bm, a1, a2, a3 ,..., an] [b1,b2,..bm,a1,a2,a3,...,an]

如果我们从归约的角度去考虑二分问题,那么二分的过程就是不断归约的过程,而归约又与二叉树联系很密切。如果你仔细回想一下二分的过程,它不就是从一个起点和终点为 [ l , r ] [l,r] [l,r] 的数组逐渐划分,最终变成一个起点和终点相等的单个元素的过程吗。如果我们把初始时的 [ l , r ] [l,r] [l,r] 看作跟节点,那么叶子节点就是数组中的各个元素。这其实有点像线段数了。
总之,我想说的是,二分就是一个归约的过程(每次要么归约到 m i d mid mid 的左半部分,要么归约到 m i d mid mid 的右半部分),把这个归约的过程和二叉树结合起来更容易理解。
好了,明白了归约之后,再来看这道题。

思路1:一次二分

我们依据 m i d mid mid n u m s nums nums 划分为 [ l , m i d − 1 ] [l,mid-1] [l,mid1], [ m i d , r ] [mid,r] [mid,r] 两个区间,那么接下来我们就要依据 t a r g e t target target 在那个区间来进行规约,由于 n u m s nums nums 是一个旋转数组,导致 [ l , r ] [l,r] [l,r] 未必有序,也就是这两个子区间未必都有序,但必然至少有一个是有序的。因此我们可以先找出那个区间是有序的,然后判断 t a r g e t target target是 否在这个区间,若不在则 t a r g e t target target 就在另一个区间。

reference here

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0, r = nums.size() - 1;
        while(l < r) {
            int mid = l + r + 1 >> 1;
            // 根据mid将nums划分为两个区间:[l, mid - 1] [mid, r]
            // 接下来我们需要根据target在那个区间来进行归约
            // 由于两个区间只有一个有序,因此我们还需要先判断那个区间有序
            if(nums[mid] < nums[r]) { // 右区间有序
                if(nums[mid] <= target && target <= nums[r]) { // 在右区间
                    l = mid;
                }
                else { // 在左区间
                    r = mid - 1;
                }
            }
            else { // 左区间有序
                if(nums[l] <= target && target <= nums[mid - 1]) { // 在左区间
                    r = mid - 1;
                }
                else { // 在右区间
                    l = mid;
                }
            }
        }
        return nums[l] == target ? l : -1;
    }
};

思路2:两次二分

由于 n u m s nums nums 可能由两个有序区间构成,那么我们是否能找到这两个有序区间,然后分别在这两个区间上进行二分呢?答案是可行的!并且这种做法更为简单,直接!
那么怎么确定这两个有序区间呢?也很简单,直接找最值,通过最值来确定区间

class Solution {
public:
    int get_separate(vector<int> &nums) { // 找分隔点:e.g.最小值[l,pos(min)-1],[pos(min),r]
        int l = 0, r = nums.size() - 1;     // 如果找最大值就是 [l,pos(max)],[pos(max+1),r]
        while(l < r) {
            int mid = l + r >> 1;
            // [l, mid-1], [mid,r]
            if(nums[mid] < nums[r]) r = mid;
            else    l = mid + 1;
        }
        return l;
    }
    int binary_search(vector<int> &nums, int l, int r, int target) {
        while(l < r) {
            int mid = l + r + 1 >> 1;
            if(nums[mid] > target)  r = mid - 1;
            else    l = mid;
        }
        return nums[l] == target ? l : -1;
    }
    int search(vector<int>& nums, int target) {
        int s = get_separate(nums);
        cout << "sep: " << s << endl;
        // 找到两个有序区间:[0, s], [s+1, n-1]
        // 根据target在那个有序区间进行二分搜索
        if(s - 1 >= 0 && nums[0] <= target && target <= nums[s - 1])  
            return binary_search(nums, 0, s - 1, target);
        return binary_search(nums, s, nums.size() - 1, target);
    }
};
http://www.dtcms.com/a/111358.html

相关文章:

  • 【YOLO系列(V5-V12)通用数据集-交通红黄绿灯检测数据集】
  • SpringBoot集成swagger和jwt
  • Flask学习笔记 - 模板渲染
  • 深入探究 Hive 中的 MAP 类型:特点、创建与应用
  • 【Linux系统编程】进程概念,进程状态
  • 第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)
  • 游戏编程模式学习(编程质量提升之路)
  • 25.4.4错题分析
  • Linux: network: 两台直连的主机业务不通
  • 【移动编程技术】作业1 中国现代信息科技发展史、Android 系统概述与程序结构 作业解析
  • Leetcode——150. 逆波兰表达式求值
  • 【小沐杂货铺】基于Three.JS绘制三维数字地球Earth(GIS 、three.js、WebGL、vue、react)
  • 平台总线---深入分析
  • transforms-pytorch4
  • 要素的选择与转出
  • 阿里云服务器遭遇DDoS攻击有争议?
  • 在MacOS 10.15上使用MongoDB
  • 洛谷题单3-P4956 [COCI 2017 2018 #6] Davor-python-流程图重构
  • linux signal up/down/down_interruptiable\down_uninterruptiable使用
  • 机器视觉工程师的专业精度决定职业高度,而专注密度决定成长速度。低质量的合群,不如高质量独处
  • linux 命令 awk
  • 洛谷题单3-P1217 [USACO1.5] 回文质数 Prime Palindromes-python-流程图重构
  • eBay新规倒计时:您的店铺配送方案即将被系统默认修改
  • python如何快速删除文件夹中的大量文件
  • 内网(域)渗透测试流程和模拟测试day--5--Windows和Linux的提权
  • 通信数据记录仪-产品概念ID
  • IntelliJ IDEA 2020~2024 创建SpringBoot项目编辑报错: 程序包org.springframework.boot不存在
  • 人工智能时代人才培养的变革路径:模式创新、能力重塑与认证赋能
  • Hello Robot创新突破!Stretch3机器人搭载RUMs模型实现未知环境中“即插即用”
  • 【AI模型核心流程】(一)大语言模型输入处理机制详解与常见误解辨析