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;
        }
    };
posted @ 2013-03-27 16:51 一叶斋主人 阅读(...) 评论(...) 编辑 收藏