B--2-基础算法(2)--二分查找扩展

摘要:
这个想法很简单。当魔鬼编写代码时,您应该设置搜索范围[L,R]或[L,R]。在不同的情况下,细节有所不同。R=阵列。size()/R=排列。size()-1;而(L˂R)/whileR=mid/R=mid+1;[L,R][L,R)R=array.size();R=arr.size()-1;whileR(L˂R),而R=mid;R=mid+1;主题1二进制搜索公共:intsearch{intl=0;intr=nums.size();while(L˂R){intmid=L+;ifreturnmid;if{R=midelseif{l=mid+1;}}返回-1;}};classSolution{public:intsearch{intl=0;intr=nums.size()-1;而{intmid=l+;ifreturnmid;if{r=mid-1;}elseif{l=mid+1;}}返回-1;}};主题2在有序数组中查找目标的左边界和右边界/查找目标的数量classSolution{public:intsearch{intl=find_Left;intr=find_Right;ifreturn0;returnr-l+1;}//查找目标[L,R]intfind_left的左边界{ifeturn-1;intans=-1;intL=0;//注意1intR=nums.size();//注意2while(L˂R){intmid=L+;if{//注意3R=mid;ans=mid否则{L=mid+1;}}返回者;}//查找目标intfind_right的右边界{ifreturn-1;intL=0;intR=nums.size();intans=-1;而(L˂R){intmid=L+;如果{L=mid+1;ans=mid;}否则{R=mid;}}返回者;}//查找目标intfind_left2{ifreturn-1;intans=-1;intL=0;intR=nums.size()-1;而{intmid=L+;如果{R=mid-1;ans=mid;}否则{L=mid+1;}}返回者;}//查找目标intfind_right2的右边界{ifreturn-1;intL=0;intR=nums.size()-1;intans=-1;而{intmid=L+;如果{L=mid+1;ans=mid;}否则{R=mid-1;}}返回者;}};};主题3旋转数组的最小值将数组的前几个元素移动到数组的末尾,这称为数组旋转。

二分查找及其扩展专题

题目
  1. 排序数组中查找数字是否存在
  2. 排序数组中查找某数左右边界
  3. 排序数组中查找某数出现的次数
  4. 局部极小值问题
  5. 旋转排序数组中最小值

二分查找的坑

真尼玛!!!思路很简单,细节是魔鬼

  1. 写代码的时候,要定好你的搜索区间, [L,R] 还是 [L,R),不同情况的细节也不一样
  2. R = array.size() / R = arr.size()-1 ;
  3. while(L < R) / while(L <= R)
  4. R = mid; / R= mid +1;
[L,R][L,R)
R = array.size();R = arr.size()-1 ;
while(L < R) while(L <= R)
R = mid;R= mid +1;
题目1 二分查找
public:
    int search(vector<int>& nums, int target) {
        int l = 0;
        int r = nums.size();
        while ( l <r )
        {
                int mid = l + ((r-l)>>1) ; 
                if (nums[mid] == target )
                        return mid;
                if (nums[mid] > target)
                {
                        r = mid  ;
                }else if (nums[mid] < target)
                {
                        l = mid + 1;
                }
        }
        return -1;
    }
};
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0;
        int r = nums.size()-1;
        while ( l <=r )
        {
                int mid = l + ((r-l)>>1) ; 
                if (nums[mid] == target )
                        return mid;
                if (nums[mid] > target)
                {
                        r = mid - 1 ;
                }else if ( nums[mid] < target )
                {
                        l = mid + 1;
                }
        }
        return -1;
    }
};
题目2 在有序数组中查找target的左右边界/求target的数量
class Solution {
public:
        int search(vector<int>& nums, int target) {
                int l = find_left(nums,target);
                int r = find_right(nums,target);
                if ( l < 0 || r < 0 || l > r )
                        return 0;
                return  r - l +1 ;
        }
        // 找到target的左边界[L,R]
        int find_left(vector<int>& nums ,int target)
        {
                if(nums.size()==0)
                        return  -1 ;
                int ans = -1 ;
                int L = 0 ;
                // 注意1 
                int R = nums.size();
                // 注意2
                while( L < R )
                {
                        int mid = L + (( R - L ) >>1);
                        if( nums[mid] >= target )
                        {
                                // 注意3 
                                R = mid;
                                ans = mid;
                                
                        }else{
                                L = mid + 1; 
                        }
                }
                return ans;
        }
        // 找到target的右边界
        int find_right(vector<int>& nums , int target)
        {
                if(nums.size() == 0 )
                        return -1;
                int L = 0;
                int R = nums.size() ;
                int ans = -1;
                while (L < R)
                {
                        int mid = L+ ( (R - L) >> 1) ;
                        if ( nums[mid] <= target )
                        {
                                L = mid + 1 ;
                                ans = mid; 
                        }else{
                                R = mid ;
                        } 
                }
                return ans;
        }
        
        // 找到target的左边界
        int find_left2(vector<int>& nums ,int target)
        {
                if(nums.size()==0)
                        return  -1 ;
                int ans = -1 ;
                int L = 0 ;
                int R = nums.size()-1;
                while( L <= R )
                {
                        int mid = L + (( R - L ) >>1);
                        if( nums[mid] >= target )
                        {
                                R = mid -1 ;
                                ans = mid;
                                
                        }else{
                                L = mid + 1; 
                        }
                }
                return ans;
        }
        // 找到target的右边界
        int find_right2(vector<int>& nums , int target)
        {
                if(nums.size() == 0 )
                        return -1;
                int L = 0;
                int R = nums.size()-1 ;
                int ans = -1;
                while (L <= R)
                {
                        int mid = L+ ( (R - L) >> 1) ;
                        if ( nums[mid] <= target )
                        {
                                L = mid + 1 ;
                                ans = mid; 
                        }else{
                                R = mid -1  ;
                        } 
                }
                return ans;
        }
};
};
题目3 旋转数组的最小值(二分法的扩展)

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素 。
例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1

class Solution {
public:
    int minArray(vector<int>& numbers) {
        // 原数组为空的情况
        if( numbers.empty() )
        {
            return -1;
        }
        // 原数组只有一个元素的情况
        if (numbers.size() == 1)
        {
            return numbers[0];
        }
        int l = 0 ;
        int r = numbers.size()-1;
        int mid = 0;
        // 原数组没有旋转的情况
        if ( numbers[l] < numbers[r] )
        {
            return numbers[l];
        }
        // 一般情况
        // l 和 r 分别在大数区域和小数区域
        // 小数区域的最大值是numbers[r]
        // 中位数比这个数大,就是在大于区域,中位数比这个数小,就是在小于区域
        // 中位数等于numbers[r] , 是没办法判断的. 就把 r 往前移动一位
        // 当l移动到大数区的最右边,r移动到小数区的最左边,返回numbers[r]就可以了
        while ( r > l+1 )
        {
            mid = l + ((r-l)>>1) ;
            // 根据三种情况 判断最小值的区域
            if ( numbers[mid] == numbers[r]){
                r--;
            }else if (numbers[mid] > numbers[r] ){
                l = mid;
            }else if (numbers[mid] < numbers[r]){
                r = mid;
            }
        }
        return numbers[r]; 
    }
};

免责声明:文章转载自《B--2-基础算法(2)--二分查找扩展》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇单调队列优化多重背包(学习笔记)linux网卡配置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Maven编译打包出错:找不到符号

项目中,使用的是maven管理,但是有几个jar不是通过maven引入的,是通过IDEA导入的,在使用maven插件编译的时候,会出现如下的一些错误: 解决方法: 在项目中创建一个目录lib,然后将jar复制到该文件夹下,最后在maven编译插件中配置如下 1 <plugin> 2...

用docker启动的oracle,重启后数据库访问失败

昨天更改了oracle数据库的最大连接数,然后手动重启了docker,以为数据库就直接启动了,没想到报错了 报错类似于一下文章 https://blog.csdn.net/h106140873/article/details/103251534 SQL>startup ORA-00821: Specified value of sga_target...

Android源码分析(一)-----如何快速掌握Android编译文件

一 : Android.mk文件概述 主要向编译系统指定相应的编译规则。会被解析一次或多次。因此尽量减少源码中声明变量,因为这些变量可能会被多次定义从而影响到后面的解析。这个文件的语法会把源代码组织成模块,每个模块属于下列类型之一: - APK程序:一般的Android程序,编译打包生成apk文件。 - JAVA库:java类库,编译打包生成jar包文件。...

Angular2中实现基于TypeScript的对象合并方法:extend()

TypeScript里面没有现成的合并对象的方法,这里借鉴jQuery里的$.extend()方法。写了一个TypeScript的对象合并方法,使用方法和jQuery一样。 部分代码和jQuery代码略有不同,主要是判断元素是否为数组和纯对象的部分。jQuery中有方法可直接判断元素是否为数组($.isArray())和对象($.isPlainObject...

Python脚本与Metasploit交互攻击

Metasploit是一款强大的漏洞扫描和利用工具,编写Python脚本与Metasploit进行交互,可以自动化的扫描和利用漏洞。 相关文章:Metasploit框架的使用 在脚本中,我们首选需要利用 nmap 模块扫描目标主机是否开放了445端口,我们写了一个 findTarget()函数,来扫描给定ip或者给定网段中开放了目标端口的主机,返回开放了4...

python 线程创建和传参(28)

在以前的文章中虽然我们没有介绍过线程这个概念,但是实际上前面所有代码都是线程,只不过是单线程,代码由上而下依次执行或者进入main函数执行,这样的单线程也称为主线程。 有了单线程的话,什么又是多线程?可以这么理解:一个线程执行一个代码块,多个线程可以同时执行多个代码,使用多线程能让程序效率更高。举个例子,你今天有两件事需要完成,分别是洗衣服和打扫房间,...