leetcode刷題筆錄-2


6.字梯游戲

  • 給定兩個單詞start和end,以及一本字典,找到由start到end的最短變換路徑,每一次變換只允許改變一個字母,且變換后的單詞必須出現在字典中。比如給出start為"hit"而end為"cog",字典為["hot","dot","dog","lot","log"],那么應當返回5,因為最短路徑是:"hit" -> "hot" -> "dot" -> "dog" -> "cog"
  • 思路:函數參數中unordered_set類型參數說明字典是用散列表維護的。題目就是圖論中最短路徑算法的簡單應用,同樣使用散列表為詞典中的每一個單詞維護一個域m_ladderLens,記錄與start頂點的距離(即變換的次數):具體的,對某個頂點,遍歷所有存在於字典中的變換(鄰接頂點),挑選出m_ladderLens值小於頂點自己的m_ladderLens值+1的,對這些頂點重復該過程。
  • 實現:
    class Solution {
    public:
        int ladderLength(string start, string end, unordered_set<string> &dict) {
            m_wordLen = start.length();
            for (unordered_set<string>::iterator i=dict.begin(); i!=dict.end(); i++){
                m_ladderLens[*i]=INT_MAX;
            }
            m_ladderLens[start]=1;        
    
            _ladderLength(start, end, dict);
    
            if (m_ladderLens[end] == INT_MAX){
                m_ladderLens[end] = 0;
            }
            return m_ladderLens[end];
        }
    private:
        void _ladderLength(string start, string end, unordered_set<string> &dict){
            for (int i=0; i<=m_wordLen-1; i++){
                for (int j=0; j<=26-1; j++){
                    string s = start;
                    s[i] = 'a'+j;
                    if (s!=start && 
                        dict.find(s)!=dict.end() && 
                        m_ladderLens[s]>m_ladderLens[start]+1)
                    {
                        m_ladderLens[s] = m_ladderLens[start]+1;
                        if (s != end){
                            _ladderLength(s, end, dict);
                        }
                    }
                }
            }
        }
        int m_wordLen;
        unordered_map<string, int> m_ladderLens;
    }; 

7.字梯游戲2

  • 給定兩個單詞start和end,以及一本字典,找到由start到end的最短變換路徑,每一次變換只允許改變一個字母,且變換后的單詞必須出現在字典中。但是需要輸出所有最短的路徑(即使有多條,也要一起輸出)。比如給出start為"hit"而end為"cog",字典為["hot","dot","dog","lot","log"],那么需要輸出:
    [
        ["hit","hot","dot","dog","cog"],
        ["hit","hot","lot","log","cog"]
    ]
  • 思路:與6幾乎一致,但是輸出不一樣,需要在迭代過程中添加一個量currentLadders,對某個頂點,記錄從start點到該點的最短路徑。(如果有多條最短的路徑,此時currentLadders中只有一條,它表示迭代到該函數的過程中產生的那一條。)
  • 實現:
    class Solution {
    public:
        vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
            m_ladders = vector<vector<string>>();
            m_wordLen = start.size();
            for (unordered_set<string>::iterator i=dict.begin(); i!=dict.end();i++){
                m_ladderLens[*i]=INT_MAX;
            }
            m_ladderLens[start] = 1;
    
            _ladderLength(start, end, dict);
            shortestLen = m_ladderLens[end]==INT_MAX ? 0 : m_ladderLens[end];
            _findLadders(start, end, vector<string>(), dict);
    
            return m_ladders;
        }
    
    private:
        void _findLadders(const string& start, const string& end, vector<string> currentLadders, unordered_set<string>& dict){
            currentLadders.push_back(start);
            if (start==end && currentLadders.size()==shortestLen){
                m_ladders.push_back(currentLadders);
                return;
            }
            for (int i=0; i<=m_wordLen-1; i++){
                for (int j=0; j<=26-1; j++){
                    string s = start;
                    s[i] = 'a'+j;
    
                    if (s!=start && dict.find(s)!=dict.end() && m_ladderLens[s]>=m_ladderLens[start]+1){
                        m_ladderLens[s]=m_ladderLens[start]+1;
                        _findLadders(s, end, currentLadders, dict);
                    }
                }
            }
        }
    
        void _ladderLength(string start, string end, unordered_set<string> &dict){
            for (int i=0; i<=m_wordLen-1; i++){
                for (int j=0; j<=26-1; j++){
                    string s = start;
                    s[i] = 'a'+j;
                    if (s!=start && 
                        dict.find(s)!=dict.end() && 
                        m_ladderLens[s]>m_ladderLens[start]+1){
                        m_ladderLens[s] = m_ladderLens[start]+1;
                        if (s != end){
                            _ladderLength(s, end, dict);
                        }
                    }
                }
            }
        }    
        int m_wordLen;
        unordered_map<string, int> m_ladderLens;
        int shortestLen;
        vector<vector<string>> m_ladders;    
    }; 

8.回文驗證

  • 給定一個字符串,判斷其是否是回文,只考慮數字和字母部分,標點符號略去。同樣,大小寫一致的字母也認為是一樣的。比如字符串"A man, a plan, a canal: Panama"就是回文,而
    "race a car"則不是回文。
  • 思路:很簡單。
  • 實現:
    class Solution {
    public:
        bool isPalindrome(string s){
            for (int i=0, j=s.size()-1; i<=j; ){
                if (!isAlphanumeric(s[i])){
                    i++;
                    continue;
                }
                if (!isAlphanumeric(s[j])){
                    j--;
                    continue;
                }
                if (tolower(s[i])==tolower(s[j])){
                    i++;
                    j--;
                    continue;
                }
                return false;
            }
            return true;
        }
    private:
        bool isAlphanumeric(char c){
            if (c>='a' && c<='z'){return true;}
            if (c>='A' && c<='Z'){return true;}
            if (c>='1' && c<='9'){return true;}
            if (c=='0'){return true;}
            return false;
        }
    }; 

 9.二叉樹最大路徑和

  • 給出一棵最大二叉樹,找到其“最大路徑和”。一條路徑,可以從二叉樹的任何一個節點開始,並到任何一個節點結束。路徑和就是這一條路徑上所有節點的值的和。需要考慮負數節點。比如,給出這樣一棵二叉樹:
           1
          / \
         2   3

     需要返回6,因為路徑2-3-1的路徑和為6(2+3+1)。

  • 思路:這個題的陷阱是,可能出現負數值的節點,我已開始就漏考慮了,而認為最大路徑至少有一個端點是葉子節點,另一個端點是根節點或葉子節點。可能有負數值的節點的情況下,這樣考慮:
    • 為每個節點考慮兩個屬性,最大路徑和(即要求的,記為S)和有一個端點為根節點的最大路徑和(記為P)。
    • 某個節點的S是以下這幾個值當中最大的:
      • 左節點的S(如果左節點存在的話)
      • 右節點的S(如果右節點存在的話)
      • 左節點的P(如果左節點存在且P>0,否則算0,就當沒取它,以根節點為一個端點)+右節點的P(同左節點,若兩者都不去,就是根節點一個端點組成的路徑)+節點自身的值
    • 某個節點的P是以下這幾個值中最大的:
      • 左節點的P(如果左節點存在且P>0,否則算0,就當沒取它,僅有根節點一個節點組成的路徑)+節點自身的值
      • 右節點的P(同上)+節點自身值
  • 實現:
    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int maxPathSum(TreeNode *root) {
            int sum = INT_MIN;
            if (root->left != NULL){
                int sum_left = maxPathSum(root->left);
                sum = max(sum, sum_left);
            }
            if (root->right != NULL){
                int sum_right = maxPathSum(root->right);
                sum = max(sum, sum_right);
            }
            int sum_root = (root->left==NULL?0:max(0,maxPathSumToRoot(root->left))) + 
                            root->val + 
                           (root->right==NULL?0:max(0,maxPathSumToRoot(root->right)));
            sum = max(sum, sum_root);
            return sum;        
        }
    private:
        int maxPathSumToRoot(TreeNode *root){        
            int sum = INT_MIN;
            if (root->left != NULL){
                int sum_left = root->val + max(0, maxPathSumToRoot(root->left));
                sum = max(sum, sum_left);
            }
            if (root->right != NULL){
                int sum_right = root->val + max(0, maxPathSumToRoot(root->right));
                sum = max(sum, sum_right);
            }
            sum = max(sum, root->val);
            return sum;
        }
    };

10.股價

  • 給定一個數組prices,表示第 i 天的股價,你總共只能買入並賣出1股,請確定買入和賣出的時機,使收益最大。
  • 思路:簡單,從前向后遍歷數組,維護一個域記錄已遍歷的天數中股價最低的那一天,然后用那一天的股價減去股價最低的那天的股價,獲得一個收益。取最大的收益。
  • 實現:
    class Solution {
    public:
        int maxProfit(vector<int> &prices) {
            int minIndex = 0;
            int maxProfitValue = 0;
            for (int i=0; i<=int(prices.size())-1; i++)
            {
                if (prices[i]<prices[minIndex])
                {
                    minIndex = i;
                }
                int profit = prices[i]-prices[minIndex];
                maxProfitValue = maxProfitValue<profit ? profit : maxProfitValue;
            }
            return maxProfitValue;
        }
    }; 

11.股價2

  • 給定一個數組prices,表示第 i 天的股價,你每天都可以進行一次交易(買入或賣出一股),請確定買入和賣出的時機,使收益最大。
  • 思路:簡單,直觀地看,如果第 i 天的股價低於第 i+1 天,那么就在第 i 天買進,第 i+1天賣出。
  • 實現:
    class Solution {
    public:
        int maxProfit(vector<int> &prices) {
            int maxProfitValue = 0;
            for (int i=0; i<=int(prices.size())-2; i++){
                if (prices[i]<prices[i+1]){
                    maxProfitValue+=prices[i+1]-prices[i];
                }
            }
            return maxProfitValue;
        }
    }; 

12.股價3

  • 給定一個數組prices,表示第 i 天的股價,你只能依次進行兩次交易(買入-賣出-買入-賣出),請確定買入和賣出的時機,使收益最大。
  • 思路:一開始的想法是,把10中的代碼拿過來稍作修改,然后將數組分割成[0...i]和[i...n-1]兩個部分,最大收益就是兩個部分最大收益之和(每個部分進行一次交易)。遍歷 i 找出最大的。但是這樣太耗時間了,后來看到uniEagle提供的思路,才恍然大悟。其實10中找出一段時間[i...j]內最大收益的過程就已經解決了[i...k]的子問題,只要維護兩個一維數組,一個記錄[0...i]的最大收益,一個記錄[i...n-1]的最大收益即可。這兩個數組都是可以在一次遍歷中得出的。然后再考慮兩個部分收益之和。
  • 實現:
    class Solution {
    public:
        int maxProfit(vector<int> &prices) {
            vector<int> profitToEnd(prices.size(), 0);
            {
                int minIndex = 0;
                int maxPft = 0;
                for (int i=0; i<prices.size(); i++){
                    int tmpPft = prices[i]-prices[minIndex];
                    if (tmpPft > maxPft){
                        maxPft = tmpPft;
                    }
                    if (prices[i]<prices[minIndex]){
                        minIndex = i;
                    }
                    profitToEnd[i]=maxPft;
                }
            }
            vector<int> profitFromStart(prices.size(), 0);
            {
                int maxIndex = prices.size()-1;
                int maxPft = 0;
                for(int i=prices.size()-1; i>=0; i--){
                    int tmpPft = prices[maxIndex]-prices[i];
                    if (tmpPft > maxPft){
                        maxPft = tmpPft;
                    }
                    if (prices[maxIndex] < prices[i]){
                        maxIndex = i;
                    }
                    profitFromStart[i]=maxPft;
                }
            }
            int maxPft = 0;
            for (int i=0; i<prices.size(); i++)
            {
                int tmpPft = profitFromStart[i]+profitToEnd[i];
                if (maxPft<tmpPft){
                    maxPft = tmpPft;
                }
            }
            return maxPft;
        }
    };


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM