LeetCode:274. H-Index & 275. H-Index II

在这里插入图片描述

在这里插入图片描述

这一题算是第一次写桶排序,然后自己又没有看出来可以用二分法。
二分法真的很重要,只要可以用,基本就是最优的方法。符合之前总结的规律就可以用。大多数情况下不是一眼就能够看出来,所以需要时刻提醒一下自己,是不是可以用二分法来做。

首先是自己的做法:

class Solution {
public:
    int hIndex(vector<int>& citations) {
        sort(citations.begin(), citations.end());
        int sz = citations.size();
        if (sz == 0)
            return 0;
        int num = citations[sz-1];
        int cnt = 0;
        int i = sz-1;
        while (num > 0) {
            while (i >= 0 && citations[i] == num) {
                ++cnt;
                --i;
            }
            if (cnt >= num)
                return num;
            --num;
        }
        return num;
    }
};

从最大数开始往下降,统计比它大的数有多少个。时间O(nlogn),优点是不用额外空间。
然后是桶排序的方法:

class Solution {
public:
    int hIndex(vector<int>& citations) {
        int sz = citations.size();
        if (sz == 0)
            return 0;
        int maxNum = *max_element(citations.begin(), citations.end());
        vector<int> cnts(maxNum+1, 0);
        for (int num : citations)
            cnts[num]++;
        int cnt = 0;
        for (int i = cnts.size()-1; i >= 0; --i) {
            cnt += cnts[i];
            if (cnt >= i)
                return i;
        }
        return 0;
    }
};

缺点是需要额外空间。优点是时间O(n)。

然后二分法:
应该可以观察到:最终答案上界:数组最大值,下界:1。然后其中以某个数i为界,左边k(k <= i)都可以满足“比k大的数至少有k个“;右边不能够满足。所以这一题能够用二分法。
这是第二道的代码

class Solution {
public:
    int hIndex(vector<int>& citations) {
        int sz = citations.size();
        if (sz == 0)
            return 0;
        
        int lo = 1, hi = citations[sz-1];
        int mid;
        while (lo <= hi) {
            mid = lo + (hi - lo) / 2;
            int idx = binarySearch(citations, 0, sz-1, mid);
            int rightCnt = sz - idx;
            if (rightCnt >= mid)
                lo = mid + 1;
            else
                hi = mid - 1;
        }
        return hi;
    }
private:
    int binarySearch(vector<int>& nums, int lo, int hi, int target) {
        //如果有重复的,返回最左边的;如果找不到,返回该在位置的右边那个
        int i = lo, j = hi;
        int mid;
        while (i <= j) {
            mid = i + (j - i) / 2;
            if (target < nums[mid])
                j = mid - 1;
            else if (target > nums[mid])
                i = mid + 1;
            else {
                if (mid == lo || nums[mid-1] != target)
                    return mid;
                else 
                    j = mid - 1;
            }
        }
        return i;
    }
};
//啊啊啊又是一题可以用二分来做的,怎么又没有看出来???
//要有这样的直觉啊。

应该要有这样的直觉的。

posted @ 2019-09-16 16:52  于老师的父亲王老爷子  阅读(17)  评论(0编辑  收藏  举报