1. 程式人生 > >每天一道LeetCode-----找到給定陣列中第三大的值

每天一道LeetCode-----找到給定陣列中第三大的值

CLlgKg.png

要求找到給定陣列中第三大的數。其中第一大的數,第二大的數,第三大的數互不相同,即嚴格的小於關係。並且規定時間複雜度是O(n)。另外如果找不到第三大的數,則返回陣列中第一大的數

可以用三個變數first, second, third分別記錄第一大第二大以及第三大的數,初始化時是整數範圍的最小值,在隨後遍歷陣列的過程中進行比較(假設遍歷到的數用n表示)

  • 如果n大於first, 則將second賦值給third, first賦值給second,n賦值給first
  • 如果n大於second小於first,則將second賦值給thid,n賦值給second
  • 如果n大於third,則將n賦值給third

這樣實現有一些侷限性,如果輸入的陣列中包含整數的最小值(即first,second,third的初始值INT32_MIN),那麼就無法區分到底是找到了第三大的數(它的值是INT32_MIN)還是沒有找到(因為third的值沒有改變)

解決方法時將初始值設定的再小一點,即INT64_MIN,但是如果輸入的陣列包含的資料偏偏就是64位的就沒有辦法了

程式碼實現如下

class Solution {
public:
    int thirdMax(vector<int>& nums) {
        // 因為int的範圍小於long long int的範圍,所以這種方式可解
// 但是如果輸入的是vector<long long int> 就沒有辦法了 long long int first = INT64_MIN, second = INT64_MIN, third = INT64_MIN; for(auto& n : nums) { // 如果小於third或者和第一/二大的數相等,則不進行賦值 if(n <= third || n == second || n == first) { continue; } third = n; // 進行大小比較後交換資料
if(third > second) swap(second, third); if(second > first) swap(first, second); } return third == INT64_MIN ? first : third; } };

鑑於上述的侷限性,需要換一種思路解決,但是對於時間複雜度的要求就無法滿足了。

考慮到題目中要求的時間複雜度是O(n),而二叉搜尋樹插入刪除的時間複雜度是O(lgn),所以可以考慮用set實現,同時也可以受益於set的去重能力,總的時間複雜度是O(nlogn)

程式碼實現如下

class Solution {
public:
    int thirdMax(vector<int>& nums) {
        set<int> s;
        for(auto& n : nums) {
            s.emplace(n);
            if(s.size() > 3) {
                s.erase(s.begin());
            }
        }
        return s.size() == 3 ? *s.begin() : *s.rbegin();
    }
};