zoukankan      html  css  js  c++  java
  • [LeetCode] Triangle('Bottom-up' DP)

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

    For example, given the following triangle

    [
         [2],
        [3,4],
       [6,5,7],
      [4,1,8,3]
    ]
    

    The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

    Note: Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

    方法1:递归出现Time Limit Exceeded(答案正确)   对比方法3,方法1用的'top-down'方法,而且没有用DP。

    class Solution {
    public:
        vector<vector<int> > triangle;
        int len;
        int minimumTotal(vector<vector<int> > &triangle) {
            this->triangle = triangle;
            len = triangle.size();
            if(len<=0)
                return 0;
             
            return minPath(0,0);
            
        }
    private:
        int minPath(int row,int col){
           
           if(row>=len || col>row)
              return 0;
           else{
              int res1 = triangle[row][col]+minPath(row+1,col)  ;
              int res2 = triangle[row][col]+minPath(row+1,col+1) ;
              return res1>res2?res2:res1;
           }
           
        }//end minPath
    };

    方法2:跟上面思想一样,按bfs的思想,用queue实现如下 Memory Limit Exceeded(答案正确)

    class Solution {
    public:    
        int minimumTotal(vector<vector<int> > &triangle) {
            queue<vector<int>> q;
            int len = triangle.size();
            if(len<=0)
                return 0;
            
            vector<int> temp,temp1;
            temp.push_back(triangle[0][0]);
            q.push(temp);
            temp.clear();
            for(int row=1;row<len;row++)
                for(int col = 0;col<=row;col++){
                    if(col==0){
                        temp = q.front();
                        q.pop();
                        temp1.push_back(temp[0]+triangle[row][col]);
                        q.push(temp1);
                        temp1.clear();
                    }else if(col==row){
                       temp1.push_back(temp[0]+triangle[row][col]);
                       q.push(temp1);
                       temp1.clear();
                    
                    }else{
                        for(int i=0;i<temp.size();i++){
                         temp1.push_back(temp[i]+triangle[row][col]);
                        }
                        temp = q.front();
                        q.pop();
                        for(int i=0;i<temp.size();i++){
                         temp1.push_back(temp[i]+triangle[row][col]);
                        }
                        q.push(temp1);
                        temp1.clear();
                                  
                    }//end if            
                }//end for
                set<int> minTotal;
                while(!q.empty()){
                    temp = q.front();
                    q.pop();
                    for(int i=0;i<temp.size();i++)
                     minTotal.insert(temp[i]);
                    
                }
                set<int>::iterator iter = minTotal.begin();
                return *iter;        
        }    
    };

    方法3:好吧,LeetCode Discuss中的方法,the codes are  so cool!---------('Bottom-up' DP)

    class Solution {
    public:
    int minimumTotal(vector<vector<int> > &triangle) {
        int n = triangle.size();
        vector<int> minlen(triangle.back());
        for (int layer = n-2; layer >= 0; layer--) // For each layer
        {
            for (int i = 0; i <= layer; i++) // Check its every 'node'
            {
                // Find the lesser of its two children, and sum the current value in the triangle with it.
                minlen[i] = min(minlen[i], minlen[i+1]) + triangle[layer][i]; 
            }
        }
        return minlen[0];
     }
    };

    方法3作者的分析:(只是按照方法1的思路反向思考来编程,然后优化了空间复杂度)

    This problem is quite well-formed in my opinion. The triangle has a tree-like structure, which would lead people to think about traversal algorithms such as DFS. However, if you look closely, you would notice that the adjacent nodes always share a 'branch'. In other word, there are overlapping subproblems. Also, suppose x and y are 'children' of k. Once minimum paths from x and y to the bottom are known, the minimum path starting from k can be decided in O(1), that is optimal substructure. Therefore, dynamic programming would be the best solution to this problem in terms of time complexity.

    What I like about this problem even more is that the difference between 'top-down' and 'bottom-up' DP can be 'literally' pictured in the input triangle. For 'top-down' DP, starting from the node on the very top, we recursively find the minimum path sum of each node. When a path sum is calculated, we store it in an array (memoization); the next time we need to calculate the path sum of the same node, just retrieve it from the array. However, you will need a cache that is at least the same size as the input triangle itself to store the pathsum, which takes O(N^2) space. With some clever thinking, it might be possible to release some of the memory that will never be used after a particular point, but the order of the nodes being processed is not straightforwardly seen in a recursive solution, so deciding which part of the cache to discard can be a hard job.

    'Bottom-up' DP, on the other hand, is very straightforward: we start from the nodes on the bottom row; the min pathsums for these nodes are the values of the nodes themselves. From there, the min pathsum at the ith node on the kth row would be the lesser of the pathsums of its two children plus the value of itself, i.e.:

    minpath[k][i] = min( minpath[k+1][i], minpath[k+1][i+1]) + triangle[k][i];
    

    Or even better, since the row minpath[k+1] would be useless after minpath[k] is computed, we can simply set minpath as a 1D array, and iteratively update itself(优化了空间复杂度):

    For the kth level:
    minpath[i] = min( minpath[i], minpath[i+1]) + triangle[k][i]; 
    
  • 相关阅读:
    js压缩、混淆和加密 Alan
    与、或、异或运算 Alan
    Hello world Alan
    abstract class和interface有什么区别?
    接口是否可继承接口? 抽像类是否可实现(implements)接口? 抽像类是否可继承实体类(concrete class)?
    启动一个线程是用run()还是start()?
    数组有没有length()这个方法? String有没有length()这个方法?
    swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
    当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
    简要谈一下您对微软.NET 构架下remoting和webservice两项技术的理解以及实际中的应用。
  • 原文地址:https://www.cnblogs.com/Xylophone/p/3888822.html
Copyright © 2011-2022 走看看