1. 程式人生 > >[LeetCode] Count of Smaller Numbers After Self 計算後面較小數字的個數

[LeetCode] Count of Smaller Numbers After Self 計算後面較小數字的個數

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:

Given nums = [5, 2, 6, 1]

To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.

Return the array [2, 1, 1, 0].

這道題給定我們一個數組,讓我們計算每個數字右邊所有小於這個數字的個數,目測我們不能用brute force,OJ肯定不答應,那麼我們為了提高運算效率,首先可以使用用二分搜尋法,思路是將給定陣列從最後一個開始,用二分法插入到一個新的陣列,這樣新陣列就是有序的,那麼此時該數字在新陣列中的座標就是原陣列中其右邊所有較小數字的個數,參見程式碼如下:

解法一:

// Binary Search
class Solution {
public:
    vector<int> countSmaller(vector<int
>& nums) { vector<int> t, res(nums.size()); for (int i = nums.size() - 1; i >= 0; --i) { int left = 0, right = t.size(); while (left < right) { int mid = left + (right - left) / 2; if (t[mid] >= nums[i]) right = mid;
else left = mid + 1; } res[i] = right; t.insert(t.begin() + right, nums[i]); } return res; } };

上面使用二分搜尋法是一種插入排序的做法,我們還可以用C++中的STL的一些自帶的函式來幫助我們,比如求距離distance,或是求第一個不小於當前數字的函式lower_bound,這裡利用這兩個函式代替了上一種方法中的二分搜尋的部分,兩種方法的核心思想都是相同的,構造有序陣列,找出新加進來的陣列在有序陣列中對應的位置存入結果中即可,參見程式碼如下: 

解法二:

// Insert Sort
class Solution {
public:
    vector<int> countSmaller(vector<int>& nums) {
        vector<int> t, res(nums.size());
        for (int i = nums.size() - 1; i >= 0; --i) {
            int d = distance(t.begin(), lower_bound(t.begin(), t.end(), nums[i]));
            res[i] = d;
            t.insert(t.begin() + d, nums[i]);
        }
        return res;
    }
};
再來看一種利用二分搜尋樹來解的方法,我們來構造一棵二分搜尋樹,稍有不同的地方是我們需要加一個變數smaller來記錄比當前節點值小的所有節點的個數,我們每插入一個節點,會判斷其和根節點的大小,如果新的節點值小於根節點值,則其會插入到左子樹中,我們此時要增加根節點的smaller,並繼續遞迴呼叫左子節點的insert。如果節點值大於根節點值,則需要遞迴呼叫右子節點的insert並加上根節點的smaller,並加1,參見程式碼如下: 解法三:
// Binary Search Tree
class Solution {
public:
    struct Node {
        int val, smaller;
        Node *left, *right;
        Node(int v, int s) : val(v), smaller(s), left(NULL), right(NULL) {}
    };
    int insert(Node *&root, int v) {
        if (!root) return (root = new Node(v, 0)), 0;
        if (root->val > v) return root->smaller++, insert(root->left, v);
        else return insert(root->right, v) + root->smaller + (root->val < v ? 1 : 0);
    }
    vector<int> countSmaller(vector<int>& nums) {
        vector<int> res(nums.size());
        Node *root = NULL;
        for (int i = nums.size() - 1; i >= 0; --i) {
            res[i] = insert(root, nums[i]);
        }
        return res;
    }
};

參考資料: