1. 程式人生 > >LeetCode周練Contest-36程式碼解析(C++)

LeetCode周練Contest-36程式碼解析(C++)

寫在前面:

LeetCode這個網站相比不必多說了吧,凡是IT圈子的人應該都知道這個網站,最近開始準備找工作,當然也免不了上去刷刷題,做一做比較經典的程式設計題,剛好看到LeetCode有個周練,便報名參加。

進入正題:

概要: 總共4個題,一個半小時的時間安排。題目分級為,兩個easy,一個medium,一個hard。

第一題 617. Merge Two Binary Trees

題目描述

Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not.

You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of new tree.


其實就是一道開胃菜的題目而已,樹形結構,二叉樹的題目,就是合併兩棵二叉樹,合併規則為相加,使用遞迴的方法來做。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(t1 == NULL && t2 == NULL)    return NULL;
        TreeNode* new_node = new TreeNode(0);
        new_node->val = (t1==NULL?0:t1->val) + (t2==NULL?0:t2->val);
        new_node->left = mergeTrees(t1==NULL?NULL:t1->left, t2==NULL?NULL:t2->left);
        new_node->right = mergeTrees(t1==NULL?NULL:t1->right, t2==NULL?NULL:t2->right);
        return new_node;
    }
};

第二題 604. Design Compressed String Iterator

題目描述

None

這道題目後面再去看,需要prime才能開啟看了,不過根據程式碼回憶,這道題的要求是設計一個類,然後這個類負責將壓縮後的字串解壓縮,並且一定需要提供兩個成員函式,一個成員函式為next,負責輸出下一個迭代器的值;第二個成員函式為hasNext,負責輸出一個bool值,判斷是否還有下一個值可以輸出;

根據題意,可以設計一個建構函式,輸入為壓縮字串,在建構函式中,可以對壓縮字串進行解壓縮,需要注意的是,有可能會出現a1234567890這種數,如果單純的給a構造那麼多個重複的字元出來會造成MLE,所以可以考慮用一個二維陣列來儲存模擬解壓縮之後的狀態,每一維陣列有兩位,第一位表示字元,第二位表示有多少個字元,之後就可以完成順序去返回迭代器和是否能夠彈出有效字元的成員函式;

//MLE
class StringIterator {
private:
    string _ori;
    vector<vector<long long>> _table;

    void processString(string &s){
        string ret;
        int lens = s.size();
        for(int i=0;i<lens;){
            if(!(s[i]>='0'&&s[i]<='9')){
                int start = ++i;
                while(i<lens){
                    if(s[i]>='0'&&s[i]<='9')    ++i;
                    else    break;
                }
                int end = i;
                long long nums = stoi(s.substr(start, end-start));
                long long index = start - 1;
                _table.push_back({index, nums});
            }
        }
    }
public:
    StringIterator(string compressedString) {
        _ori = compressedString;
        processString(_ori);
    }
    
    char next() {
        for(int i=0;i<_table.size();i++){
            if(_table[i][1]>0){
                _table[i][1]--;
                return _ori[_table[i][0]];
            }
        }
        return ' ';
    }
    
    bool hasNext() {
        for(int i=0;i<_table.size();i++){
            if(_table[i][1]>0){
                return true;
            }
        }
        return false;
    }
};

/**
 * Your StringIterator object will be instantiated and called as such:
 * StringIterator obj = new StringIterator(compressedString);
 * char param_1 = obj.next();
 * bool param_2 = obj.hasNext();
 */

第三題 611. Valid Triangle Number

題目描述

Given an array consists of non-negative integers, your task is to count the number of triplets chosen from the array that can make triangles if we take them as side lengths of a triangle.


先解釋下題目,就是有一串數字,從中選擇三個數可以組成一個三角形,問總共有多少種組合方法;

LeetCode上有一類題,可以歸納為k-sum,比較經典,這個題可以藉助3-sum的思路來做,唯一不同的是,這裡選擇的三個數需要組成一個三角形,滿足的是三角形的三條邊的定律:a+b > c;所以可以先將一維陣列排序之後,使用夾逼的方法來做,這裡需要注意的是,在夾逼的時候,不能固定最前端的數,需要固定最後端的數;因為固定最後端的數以後,分別選擇未被固定的陣列中,第一位為a,最後一位為b,如果a+b大於c,那麼可以肯定的是從a到b之間的任何數都可以和b組合然後連上c組成三角形的三條邊,如果不行,那就需要b往左移動一步,然後再判斷;

如果固定的是陣列第一位,那麼未被固定的陣列中,當不滿足(最後一位 - 第一位 < 固定值),之後的第一位和最後一位,無論是第一位向右,還是最後一位向左,都是使得條件朝著滿足的方向進行,這樣做不能帶來比較妥善的處理方式,要想不漏掉任何一個可能的組合,會使得時間複雜度提升為平方,甚至於三次方;

程式碼如下:

//TLE
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int lens = nums.size();
        if(lens < 3)    return 0;
        sort(nums.begin(), nums.end());
        int ret = 0;
        for(int i=0;i<lens-2;i++){
            for(int j=i+1;j<lens-1;j++){
                for(int k=j+1;k<lens;k++){
                    ret += nums[i]+nums[j]>nums[k]?1:0;
                }
            }
        }
        return ret;
    }
};

//類似於k-sum那道題,夾逼來做
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int lens = nums.size();
        if(lens < 3)    return 0;
        sort(nums.begin(), nums.end());
        int ret = 0;
        //必須固定後面的,然後在前面夾逼
        for(int i=lens-1;i>=2;i--){
            int left = 0, right = i - 1;
            while(left < right){
                if(nums[right] + nums[left] > nums[i]){
                    ret += right - left;
                    --right;
                }
                else    ++left;
            }
        }
        return ret;
    }
};

第四題 616. Add Bold Tag in String

題目描述

None.

很抱歉,這道題後面再去看的時候也加入了prime套餐;根據程式碼來回憶吧;

題意為給定一個字串,一個字串陣列,陣列中的每一個字串為原始字串的子串,如果在原始字串中有出現,那就需要在選中的字串子串兩端加上HTML中的加粗標籤,即:<b></b>;如果有重複,那就保持重疊之後再加上標籤;

這道題其實雖然是medium的難度,但是很簡單,可以維護一個和原來字元串同樣大小的bool型陣列,然後遍歷每一個字串子串,如果在原始字串中有出現過,就將bool型陣列中相應位置置為true;最後根據bool型陣列輸出新增標籤的字串;該方法時間複雜度比較高,不過不失為一種快速完成程式的方法;

class Solution {
public:
    string addBoldTag(string s, vector<string>& dict) {
        int s_lens = s.size();
        vector<bool> marks(s_lens, false);
        int lens = dict.size();
        for(int i=0;i<lens;i++){
            int start = 0, pos = 0;
            while((pos = s.find(dict[i], start))!=string::npos){
                for(int j=pos;j<pos+dict[i].size();j++){
                    marks[j] = true;
                }
                start = pos + 1;
            }
        }
        string ret;
        //查詢一個字串的情況
        for(int i=0;i<s_lens;){
            if(marks[i]){
                ret += "<b>";
                while(i<s_lens){
                    if(marks[i])    ret.push_back(s[i++]);
                    else    break;
                }
                ret += "</b>";
            }
            else{
                ret.push_back(s[i++]);
            }
        }
        return ret;
    }
};

總結:

找工作路漫漫,但求不忘初心,回首對得起走過的路。