主頁 > 軟體設計 > 最簡二分模板(秒殺Leetcode大部分二分題目)

最簡二分模板(秒殺Leetcode大部分二分題目)

2021-10-26 08:32:11 軟體設計

文章目錄

  • 二分模板
    • 整數二分
      • 模板一
      • 模板二
    • 浮點數二分
    • 寫出正確的二分
  • 704. 二分查找
  • 34.在排序陣列中查找元素的第一個和最后一個位置
  • 69.X的平方根
  • 33.搜索旋轉排序陣列
  • 81.搜索旋轉排序陣列II
  • 852.山脈陣列的峰頂索引
  • 278.第一個錯誤的版本

這里的二分模板來源于 《演算法競賽進階指南》和Acwing,這里只是對模板的用法及Leetcode的例題講解, 同時歡迎各位加入Acwing社區

所謂二分演算法,就是不斷的縮減區間的范圍去尋找目標值

二分模板

整數二分

模板一

  1. 會將區間劃分為[l,mid] 和[mid+1,r]兩個區間,最終結果會落在左半區間

  2. left指標和right指標最終都會落在相同的點上,可以通過兩個指標指向的值判斷是否是有解

int l = 0;
int r = nums.length-1;
while(l < r ){
    int mid = l+r>>1;
    if(check(mid)){
        r = mid;
    }else{
        l = mid+1;
    }
}

模板二

  1. 會將區間劃分為[l,mid-1] 和[mid,r]兩個區間,最終結果會落在右半區間

  2. left指標和right指標最終都會落在相同的點上,可以通過兩個指標指向的值判斷是否是有解

int l = 0;
int r = nums.length-1;
while(ll < r){
    int mid = l+r+1 >>1;
    if(check(mid)){
        l = mid;
    }else{
        r = mid-1;
    }
}

浮點數二分

這個用的比較少,這里的k指的是題目的精度

double find(int left,int right){
    double eps = le-k+2;
    while(right - left > eps){
        double mid = (right+left)/2;
        if(check(mid)){
            r = mid;
        }else{
            l = mid;
        }
    } 
    reutrn l;
}

寫出正確的二分

  1. 判斷題目是否可以使用二分,二分不僅僅適用于單調的序列,而且適用于有二段性的序列

  2. 通過判斷答案所落在的區間,以及mid 歸屬于那一半區間

  3. 寫出check函式,選用不同的模板

  4. 二分終止條件就是 l == r, 可以通過l或者是r指向的值是否是預期值,判斷有沒有解

704. 二分查找

題目描述

給定一個 n 個元素有序的(升序)整型陣列 nums 和一個目標值 target ,寫一個函式搜索 nums 中的 target,如果目標值存在回傳下標,否則回傳 -1

思路

這道題就是二分查找的模板題,

首先分析題目,這是一個有序的陣列,查找指定值,滿足二分的基本條件

這里是一個升序的陣列,如果說 num[mid] >= target,那么最終答案會落在左半區間,因為這又是一個升序的陣列,如果說mid指向的元素都比目標值大了,那么后面的只可能更大,

最終兩個指標都會指向同一個位置,可以通過判斷最后指向的位置是否為目標值,來判斷是否有解

class Solution {
    public int search(int[] nums, int target) {
        int l = 0;
        int r = nums.length-1;
        while(l < r){
            int mid  = l+r >>1;
            if(nums[mid]>= target){
                r = mid;
            }else{
                l  = mid+1;
            }
        }
        if(nums[l] == target){
            return l;
        }
        return -1;
    }

}

34.在排序陣列中查找元素的第一個和最后一個位置

題目描述

該題同樣是可以用暴力解的,但是這里就不給出解法

在排序陣列中查找元素的第一個和最后一個位置
給定一個按照升序排列的整數陣列 nums,和一個目標值 target,找出給定目標值在陣列中的開始位置和結束位置,

如果陣列中不存在目標值 target,回傳 [-1, -1],

思路

一般來說,看到有序的陣列,都要去想一想能不能用二分

  1. 如果說查找開始位置,在有解的情況之下,一定會落在候選區間的左半邊,所以說我們選擇r = mid的這個模板,那么check函式就順理成章的寫出來了,nums[mid]>=target,這樣答案就會落在左半區間,那么就得到的就是開始位置

  2. 如果說查找結束位置,與分析開始位置是一致的,在有解的情況之下,一定會落在候選區間的右半邊,所以說我們選擇l=mid的這個模板,那么check函式就是nums[mid]<=target,這樣答案就會落在右半區間,那么得到的就是結束位置

代碼

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ans  = new int[]{-1,-1};
        if(nums.length == 0){
            return new int[]{-1,-1};
        }
        // >= target 中最小的那一個
        int l = 0;
        int r = nums.length-1;
        while(l<r){
            int mid  = l+r>>1;
            if(nums[mid]>=target){
                r = mid;
            }else{
                l = mid+1;
            }
        }

        if(nums[l] != target){
            return ans;
        }
        // <= target 中最大的那一個
        ans[0] = l;
        l = 0;
        r = nums.length-1;
        while(l<r){
            int mid = l+r+1>>1;
            if(nums[mid]<=target){
                l=mid;
            }else{
                r =mid-1;
            }
        }
        if(nums[l]!=target){
            return ans;
        }
        ans[1] =l;
        return ans;

    }
}

69.X的平方根

題目描述

給你一個非負整數 x ,計算并回傳 x 的 算術平方根 ,

由于回傳型別是整數,結果只保留 整數部分 ,小數部分將被 舍去 ,

注意:不允許使用任何內置指數函式和算符,例如 pow(x, 0.5) 或者 x ** 0.5 ,

思路

二分模板題
和上述兩個題都是同樣的分析方法

代碼

class Solution {
    public int mySqrt(int x) {
        long l = 0;
        long r = x;
        while(l<r){
            long mid  = l+r+1l>>1;
            if(mid <= x/mid){
                l = mid;
            }else{
                r = mid-1;
            }
        }
        return (int)l;
    }
}

33.搜索旋轉排序陣列

題目描述

整數陣列 nums 按升序排列,陣列中的值 互不相同 ,

在傳遞給函式之前,nums 在預先未知的某個下標 k(0 <= k < nums.length)上進行了 旋轉,使陣列變為[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下標 從 0 開始 計數),例如, [0,1,2,4,5,6,7] 在下標 3 處經旋轉后可能變為 [4,5,6,7,0,1,2] ,

給你 旋轉后 的陣列 nums 和一個整數 target ,如果 nums 中存在這個目標值 target ,則回傳它的下標,否則回傳 -1 ,

示例 1:

輸入:nums = [4,5,6,7,0,1,2], target = 0
輸出:4

思路

從題目中進行分析,陣列中沒有重復元素,原來的陣列升序的,旋轉之
后,我們很容易發現,前半段都是大于新陣列的第一個數,后半段都是小于新陣列的第一個數,仍然具有二段性,可以使用二分,那么說現在就用兩個問題,首先,就是如何去尋找這個分界點,其次,就是分界點確定之后,如果去運用我們的二分模板去尋找答案

  1. 分界點獲取

    • 遍歷:分界點,后面的元素一定是比分界點出的元素小的
    • 二分:整個序列具有二段性,前半段具有大于num[0] 的性質,后半段具有小于num[0]的性質
  2. 找到分界點之后,如果說target比第一個元素大,那么答案區間一定在多半段,反之,一定在右半段,不管是那一段,都是單調的,合理分析,既可以得到答案

代碼

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length <= 0 ){
            return -1;
        }
        int l = 0 ;
        int r = nums.length-1;
        while(l <  r){
            int mid  = l+r+1>>1;
            if(nums[mid]>=nums[0]) l = mid;
            else  r = mid-1;          
        }
        if(target >= nums[0]) l = 0 ;
        else{
            l  =r+1;
            r = nums.length-1;
        }
        while(l < r){
            int mid  = l + r >> 1;
            if(nums[mid]>=target){
                r = mid;
            }else{
                l = mid +1;
            }
        }
        if(nums[r] == target ){
            return r;
        }
        return -1;
    }
}

81.搜索旋轉排序陣列II

題目描述

已知存在一個按非降序排列的整數陣列 nums ,陣列中的值不必互不相同,

在傳遞給函式之前,nums 在預先未知的某個下標 k(0 <= k < nums.length)上進行了 旋轉 ,使陣列變為 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下標 從 0 開始 計數),例如, [0,1,2,4,4,4,5,6,6,7] 在下標 5 處經旋轉后可能變為 [4,5,6,6,7,0,1,2,4,4] ,

給你 旋轉后 的陣列 nums 和一個整數 target ,請你撰寫一個函式來判斷給定的目標值是否存在于陣列中,如果 nums 中存在這個目標值 target ,則回傳 true ,否則回傳 false ,

示例 1:

輸入:nums = [2,5,6,0,0,1,2], target = 0
輸出:true

思路
相比于上題,陣列中有了重復元素,使得不具有二段性,而沒有二段性的原因就是旋轉之后,新陣列的頭和尾中有了重復元素,如果說取出了這些重復元素,陣列就重新具有了二段性,如果說陣列尾和陣列頭是一致的,就壓縮陣列的右邊界,然后就和上題一樣的做法,之后就不在贅述

代碼一

直接遍歷,時間復雜度 O(n)

class Solution {
    public boolean search(int[] nums, int target) {
        for(int i  = 0;i<nums.length;i++){
            if(nums[i] == target){
                return true;
            }
        }
        return false;
    }
}

代碼二

二分,最壞情況下是O(N),相比之下,更加推薦使用代碼一,代碼量更加短,時間復雜度一致

class Solution {
    public boolean search(int[] nums, int target) {
        if(nums.length == 0){
            return false;
        }
        int R  = nums.length - 1;
        while(R >= 0 && nums[R] == nums[0] ){
            R--;
        }
        if(R < 0) return nums[0] == target;
        
        int r = R;
        int l = 0;
        while(l < r){
            int mid  = l+r+1 >> 1;
            if(nums[mid] >= nums[0]) l = mid;
            else r = mid-1;
        }
        if(target >= nums[0]){
            r = l;
            l = 0;
        }else{
            l++;
            r = R;
        }
        while(l < r){
            int mid  = l+r>>1;
            if(nums[mid]>=target) r = mid;
            else l = mid+1;
        }
        if(nums[r] == target) return true;
        return false;
    }
}

852.山脈陣列的峰頂索引

題意描述

符合下列屬性的陣列 arr 稱為 山脈陣列 :
arr.length >= 3
存在 i(0 < i < arr.length - 1)使得:
arr[0] < arr[1] < ... arr[i-1] < arr[i] arr[i] > arr[i+1] > ... > arr[arr.length - 1].
給你由整陣列成的山脈陣列 arr ,回傳任何滿足arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1]的下標 i ,

思路

這個陣列實際上是具有二段性,前面一段是單調遞增的,后面一段是單調遞減的,我們需要找到分界點下標,如果說當前元素,比他的前一個元素要大的話,說明答案會在右半邊

代碼

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int n = arr.length;
        int l = 0;
        int r = n-2;
        while(l<r){
            int mid = l+r+1>>1;
            if(arr[mid]>arr[mid-1]){
                l = mid;
            }else{
                r = mid-1;
            }
        }
        return l;
    }
}

278.第一個錯誤的版本

題目描述

你是產品經理,目前正在帶領一個團隊開發新的產品,不幸的是,你的產品的最新版本沒有通過質量檢測,由于每個版本都是基于之前的版本開發的,所以錯誤的版本之后的所有版本都是錯的,

假設你有 n 個版本 [1, 2, …, n],你想找出導致之后所有版本出錯的第一個錯誤的版本,

你可以通過呼叫 bool isBadVersion(version) 介面來判斷版本號 version 是否在單元測驗中出錯,實作一個函式來查找第一個錯誤的版本,你應該盡量減少對呼叫 API 的次數

思路

  1. 從題意中分析,整個序列具有二段性,前面一段是沒有錯誤的版本,后面一段是錯誤的版本,所以可以用二分法去尋找中間的那個分割點
  2. 分析mid指標所指向的位置,如果說這個位置是錯誤的版本,那么答案最侄訓落至左半區間,選擇r = mid,的這個二分版本
  3. 只需要將題目中提供的函式作為check函式即可
  4. l == r 就是答案

代碼實作

時間復雜度 : O(logn)

空間復雜度 : O(l)

/* The isBadVersion API is defined in the parent class VersionControl.
      boolean isBadVersion(int version); */

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int l = 1;
        int r = n;
        while(l<r){
            long tem  =(long) l+r>>1;
            int mid = (int)tem;
            if(isBadVersion(mid)){
               r = mid; 
            }else{
                l = mid+1;
            }
        }
        return l;       
    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/336282.html

標籤:其他

上一篇:SpringBoot:Mybatis + Druid 資料訪問

下一篇:惹惱開源社區!微軟道歉:恢復 .NET SDK 熱多載功能

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more