LeetCode_03_BinarySearch筆記總結

摘要

今天的題涉及到一個二分的邊界問題的新套路,還處理一道經典的DP問題.

正文

1. LC274. H-Index


題目
Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher’s h-index.
According to the definition of h-index on Wikipedia: “A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each.”
For example, given citations = [3, 0, 6, 1, 5], which means the researcher has 5 papers in total and each of them had received 3, 0, 6, 1, 5 citations respectively. Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, his h-index is 3.
使用公司:
Google, Facebook, Bloomberg
難度:
中等


題目與思路分析:
這個題就是在說有一個數組, 其中的每個值代表着論文被引用的次數. 比如[3,0,6,1,5]就是表示總共有五篇論文,分別被引用了3次,0次,6次,1次和5次. 那到底什麼是h-index呢,就好比說有篇論文被引用5次,在他的這五篇中只有兩篇論文被引用次數達到5次和五次以上. 他
還有篇論文被引用6次,在他的五篇中只有一篇論文被引用次數達到6次和6次以上. 其中還有篇論文被引用3次,在五篇中,有三篇引用次數
大於等於3. 目前來說3就是最高索引了. 說白了就是找大於等於這個nums[i]的個數和i是不是相同,那麼i即是H-index.那麼這個思路是什麼呢?
首先就是將數組排序就一切簡單了.
這裏寫圖片描述
紅色字體是索引,藍字字體是大於等於nums[i]的論文篇數. 紅色=nums.length-藍色. 這樣就簡單了吧.
直接上代碼:

class Solution {
    public int hIndex(int[] citations) {
        if(citations == null || citations.length == 0){
            return 0;
        }
        Arrays.sort(citations);
        int result = 0;
        for(int i = 1; i < citations.length + 1; i++){
            if(citations[citations.length - i] >= i){
                result = i;
            }else{
                break;
            }
        }
        return result;
    }
}

2. LC275. H-Index II


題目
Follow up for H-Index: What if the citations array is sorted in ascending order? Could you optimize your algorithm?
使用公司:
Facebook
難度:
中等


題目與思路分析:
這個題就告訴你上一題是排序了的,問有沒有優化的方式解答同樣的問題.一旦排序,我們首先想到的就是二分法去優化.
與上面同樣的原理,紅色=nums.length-藍色. 找到mid,如果mid的值大於等於nums.length-mid,那麼就考慮左邊的情況.
直到找到大於等於的邊界值.注意這裏我們用之前while(left < right - 1)的套路的大好了,因爲這種逼近法最好讓他們重合起來
這樣的話left要麼就沒有動就在最後結果值上,要麼就是在結果值外一個單元,這樣left就永遠指向了最左面的值,我們
這道題需要的也是最左邊的值.接下的一道經典DP題能更深刻的理解這個.

class Solution {
    public int hIndex(int[] citations) { 
        if(citations == null || citations.length == 0){
            return 0;
        }
        int left = 0;
        int right = citations.length - 1;
        int len = citations.length;
        int result = 0;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(len - mid <= citations[mid]){
                right = mid - 1;
            }
            else{
                left = mid + 1;
            }
        }
        return len - left;
    }
}

3. LC34. Search for a Range

題目
Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].
使用公司:
Linkedln
難度:
中等


題目與思路分析:
這道題就是讓你在一個排序了的數組中找到給定的target的起始位置和終止位置的索引.時間複雜度只能是O(logn),
如果沒有對應就但會[-1, -1].思路:既然時間複雜度logn並且是排序數組,毫無疑問用二分. 怎麼分?找兩個端點,
那我就左面找左面的,右面找右面的點. 左面的點好找,我們上題的方式就能很輕鬆找到左點,但是右點怎麼找呢?
那就是即使找到相同的值也讓left右移動.反正這種二分方式都是要以左點做爲主角來獲得相應的左值和右值.
直接上代碼:

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = {-1,-1};
        if(nums.length == 0 || nums == null){
            return res;
        }
        int left_left = 0;
        int left_right = nums.length - 1;
        while(left_left <= left_right){

            int mid = left_left + (left_right - left_left) / 2;
            if(nums[mid] < target){
                left_left = mid + 1;
            }else{
                left_right = mid - 1;
            }
        }
        int right_left = 0;
        int right_right = nums.length - 1;
        while(right_left <= right_right){
            int mid = right_left + (right_right - right_left) / 2;
            if(nums[mid] <= target){
                right_left = mid + 1;
            }
            else{
                right_right = mid - 1;
            }
        }
        if(left_left <= right_right){
            res[0] = left_left;
            res[1] = right_right;
        }
        return res;
    }
}

4. LC300. Longest Increasing Subsequence

題目
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
使用公司:
Microsoft
難度:
中等


題目與思路分析:
題目就是讓你找到最長的增長序列長度,比如[10, 9, 2, 5, 3, 7, 101, 18], [2, 3, 7, 101]就是最長增長序列,注意並沒有說要連續.那麼這是一道
超級經典的DP問題.我們只需要維護一個額外的數組,記錄着每一個值它的前面有幾個連續增長的值,這樣的話當計算新的值的時候,只需要取前面最大的+1就行了.
這裏寫圖片描述
直接上代碼:

class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums.length == 0 || nums == null){
            return 0;
        }
        int[] dp = new int[nums.length];
        int res = 0;
        for(int i = 0; i < nums.length; i++){
            dp[i] = 1;

            for(int j = 0; j < i; j++){
                if(nums[j] < nums[i]){
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

5. LC278. First Bad Version

題目
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n versions [1, 2, …, n] and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
使用公司:
Facebook
難度:
容易


題目與思路分析:
這道題就是說現在有個有序序列,但是從某個位置開始就出現了問題,導致後面的都出現了問題,現在就是要找出這個出問題的位置.其中
提供了一個判斷是不是有問題的函數isBadVersion(version).思路:這個題很簡單,首先排序了,又是搜索,自然考慮到二分,那麼就找
中間值,左右值然後分別判斷是不是Bad就行.這個題可以用我們之前的left < right - 1,但是因爲要找邊界問題,所以還是left<=right最爲
方便.和前面的兩道題思路一樣.
直接上代碼:

public class Solution extends VersionControl {
    public int firstBadVersion(int n) { 
        if(n == 0){
            return 0;
        }
        int left = 0;
        int right = n - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(isBadVersion(mid + 1)){
                right = mid - 1;
            }
            else{
                left = mid + 1;
            }
        }
        return left + 1;
    }
}

6. LC50. Pow(x, n)

題目
Implement pow(x, n).
Example 1:
Input: 2.00000, 10
Output: 1024.00000
Example 2:
Input: 2.10000, 3
Output: 9.26100
使用公司:
Google, Facebook, Bloomberg, Linkedln
難度:
中等


題目與思路分析:
這道題就是說求n次方的.思路:題目很簡單,首先想到的問題是冪的正負問題,如果整數,處理正常,如果負數,我們需要用
1.0/正常處理的正數. 對於多次冪我們能進行遞歸分不斷的除以2到0.這裏就又涉及到一個問題,如果是偶次冪和如果是奇數
冪.其實奇數冪就是我們在偶次冪的基礎上再多乘個本身就行,因爲你/2的時候,其實是失了一個精度的, 因爲是取整.
直接上代碼:

class Solution {
    public double myPow(double x, int n) {  
        if(n == 0){
            return 1.0;
        }
        if(n < 0){
            return 1.0 / helper(x, -n);
        }
        return helper(x, n);
    }
    public double helper(double x, int n){
        if(n == 0){
            return 1.0;
        }
        Double res = helper(x, n / 2);
        if(n % 2 == 0){
            return res * res;
        }else{
            return res * res * x;
        }
    }
}

總結

今天的題學會了個新套路,就是二分求邊界值的問題,不能再用我們在01裏面用的模板了,需要變通一下,使用left<=right.並且主要就是靠left來進行決定的.如左面是left不說,右面也是通過控制條件使得左移動然後得到右值.然後還處理一道經典的DP問題.要學會利用前面的結果.再者就是善於總結題中的一些數組下標和數組的規律.


聯繫方式: [email protected]

發佈了19 篇原創文章 · 獲贊 2 · 訪問量 4152
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章