日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LeetCode——二分查找

發(fā)布時間:2024/2/28 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode——二分查找 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

二分查找


目錄

  • 二分查找法
  • 求開方
  • 大于給定元素的最小元素
  • 有序數(shù)組的 Single Element
  • 第一個錯誤的版本
  • 旋轉(zhuǎn)數(shù)組的最小數(shù)字
  • 查找區(qū)間

  • 1. 二分查找法

    正常實現(xiàn)

    public int binarySearch(int[] nums, int key) {int l = 0, h = nums.length - 1;while (l <= h) {int m = l + (h - l) / 2;if (nums[m] == key) {return m;} else if (nums[m] > key) {h = m - 1;} else {l = m + 1;}}return -1;}
    時間復(fù)雜度

    二分查找也稱為折半查找,每次都能將查找區(qū)間減半,這種折半特性的算法時間復(fù)雜度為 O(logN)。

    m 計算

    有兩種計算中值 m 的方式:

    • m = (l + h) / 2
    • m = l + (h - l) / 2l + h 可能出現(xiàn)加法溢出,也就是說加法的結(jié)果大于整型能夠表示的范圍。但是 l 和 h 都為正數(shù),因此 h - l 不會出現(xiàn)
      加法溢出問題。所以,最好使用第二種計算法方法。
    未成功查找的返回值

    循環(huán)退出時如果仍然沒有查找到 key,那么表示查找失敗。可以有兩種返回值:

    • -1:以一個錯誤碼表示沒有查找到 key
    • l:將 key 插入到 nums 中的正確位置
    變種

    二分查找可以有很多變種,變種實現(xiàn)要注意邊界值的判斷。例如在一個有重復(fù)元素的數(shù)組中查找 key 的最左位置的實現(xiàn)如下:

    public int binarySearch2(int[] nums, int key) {int l = 0, h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;if (nums[m] >= key) {h = m ;} else {l = m + 1;}}return l;}

    該實現(xiàn)和正常實現(xiàn)有以下不同:

    • h 的賦值表達(dá)式為 h = m
    • 循環(huán)條件為 l < h
    • 最后返回 l 而不是 -1

    在 nums[m] >= key 的情況下,可以推導(dǎo)出最左 key 位于 [l, m] 區(qū)間中,這是一個閉區(qū)間。h 的賦值表達(dá)式為 h =m,因為 m 位置也可能是解。

    在 h 的賦值表達(dá)式為 h = m 的情況下,如果循環(huán)條件為 l <= h,那么會出現(xiàn)循環(huán)無法退出的情況,因此循環(huán)條件只能是 l < h。以下演示了循環(huán)條件為 l <= h 時循環(huán)無法退出的情況

    當(dāng)循環(huán)體退出時,不表示沒有查找到 key,因此最后返回的結(jié)果不應(yīng)該為 -1。為了驗證有沒有查找到,需要在調(diào)用端判斷一下返回位置上的值和 key 是否相等。


    2. 求開方

    public int mySqrt(int x) {if (x <= 1) {return x;}int l = 1;int h = x;while (l <= h) {int mid = l + (h - l) / 2;int sqrt = x / mid;if (mid == sqrt) {return sqrt;} else if (mid > sqrt) {h = mid - 1;} else {l = mid + 1;}}return h;}

    3. 大于給定元素的最小元素


    題目描述:給定一個有序的字符數(shù)組 letters 和一個字符 target,要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 個字符。

    public char nextGreatestLetter(char[] letters, char target) {int n = letters.length;int l = 0, h = n - 1;while (l <= h) {int m = l + (h - l) / 2;if (letters[m] >= target) {h = m - 1;} else {l = m + 1;}}return l < n ? letters[l] : letters[0];}

    4. 有序數(shù)組的 Single Element


    題目描述:一個有序數(shù)組只有一個數(shù)不出現(xiàn)兩次,找出這個數(shù)。

    要求以 O(logN) 時間復(fù)雜度進(jìn)行求解,因此不能遍歷數(shù)組并進(jìn)行異或操作來求解,這么做的時間復(fù)雜度為 O(N)。

    令 index 為 Single Element 在數(shù)組中的位置。在 index 之后,數(shù)組中原來存在的成對狀態(tài)被改變。如果 m 為偶數(shù),并且 m + 1 < index,那么 nums[m] == nums[m + 1];m + 1 >= index,那么 nums[m] != nums[m + 1]。

    從上面的規(guī)律可以知道,如果 nums[m] == nums[m + 1],那么 index 所在的數(shù)組位置為 [m + 2, h],此時令 l = m +2;如果 nums[m] != nums[m + 1],那么 index 所在的數(shù)組位置為 [l, m],此時令 h = m。

    因為 h 的賦值表達(dá)式為 h = m,那么循環(huán)條件也就只能使用 l < h 這種形式

    public int singleNonDuplicate(int[] nums) {int l = 0;int h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;while (m % 2 == 1) {m--; // 保證 l/h/m 都在偶數(shù)位,使得查找區(qū)間大小一直都是奇數(shù)}if (nums[m] == nums[m + 1]) {l = m + 2;} else {h = m;}}return nums[l];}

    5. 第一個錯誤的版本

    題目描述:給定一個元素 n 代表有 [1, 2, …, n] 版本,在第 x 位置開始出現(xiàn)錯誤版本,導(dǎo)致后面的版本都錯誤。可以調(diào)用 isBadVersion(int x) 知道某個版本是否錯誤,要求找到第一個錯誤的版本。

    如果第 m 個版本出錯,則表示第一個錯誤的版本在 [l, m] 之間,令 h = m;否則第一個錯誤的版本在 [m + 1, h] 之間,令 l = m + 1。

    因為 h 的賦值表達(dá)式為 h = m,因此循環(huán)條件為 l < h。

    public int firstBadVersion(int n) {int l = 1, h = n;while (l < h) {int mid = l + (h - l) / 2;if (isBadVersion(mid)) {h = mid;} else {l = mid + 1;}}return l;}

    6. 旋轉(zhuǎn)數(shù)組的最小數(shù)字

    public int findMin(int[] nums) {int l = 0, h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;if (nums[m] <= nums[h]) {h = m;} else {l = m + 1;}}return nums[l];}

    7. 查找區(qū)間

    public int[] searchRange(int[] nums, int target) {int first = binarySearch(nums, target);int last = binarySearch(nums, target + 1) - 1;if (first == nums.length || nums[first] != target) {return new int[]{-1, -1};} else {return new int[]{first, Math.max(first, last)};}}private int binarySearch(int[] nums, int key) {int l = 0, h = nums.length - 1;while (l < h) {int m = l + (h - l) / 2;if (nums[m] >= key) {h = m;} else {l = m + 1;}}return l;}

    總結(jié)

    以上是生活随笔為你收集整理的LeetCode——二分查找的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。