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问题.要学会利用前面的结果.再者就是善于总结题中的一些数组下标和数组的规律.


联系方式: reyren179@gmail.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值