• 120. Triangle(中等)


    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],
        [2, 3],
       [1,-1,-3],
    ]
    

    结果应为 -1 + 2 + -1 = 0, 而不是 -1 + 2 + -3 = -2.

    idea来自 http://www.cnblogs.com/liujinhong/p/5551932.html 中的图片,感谢这位同学.
    本 code 属于 方法一: 自上而下,破坏原数组A. (O(n^2)) time, (O(1)) space
    另一种方法 方法二: 自下而上,不破坏数组A. 维护一个长度为 n 的 1-dim 数组. (O(n^2)) time, (O(n)) space.

    方法一的解题思路(请务必参照上面网址中的图片):

    从上至下,将值按照"路径"加到下一层
    除了A[0][0]这种情况外,还会遇到下列三种(注意判断条件)情况,共 4 cases:
    	case 1: left, right 上邻居都存在
    	case 2: left上不存在, right上存在
    	case 3: left上存在, right上不存在
    	case 4: A[0][0](它没left上 和 right上邻居), 我们 do nothing, 保留A[0][0]数值不变.
    

    下面的图可以让我们看清上面 4 cases 的判断条件:

    下面是元素索引:
    
    	[
    	     	  [0,0],
    	       [1,0],[1,1] ,          [row-1,col-1],[row-1,col],
    	    [2,0],[2,1],[2,2],                [row, col]
    	 [3,0],[3,1],[3,2],[3,3]
    	]
    
    

    人家想法,自个代码(方法一,破坏原数组):
    (O(n^2)) time, (O(1)) space

    // idea来自 http://www.cnblogs.com/liujinhong/p/5551932.html
    // 本 code 属于方法一:自上而下,破坏原数组A. $O(n^2)$ time, $O(1)$ space
    // 另一种方法方法二:自下而上,不破坏数组A. 维护一个长度为 n 的 1-dim 数组.
    //               $O(n^2)$ time, $O(n)$ space.
    int minimumTotal(vector<vector<int>>& A) {
    	const int n = A.size();
    	if (n == 0) return 0;
    
    	// 从上至下,将值按照"路径"加到下一层
    	// 除了A[0][0]这种情况外,还会遇到下列三种情况,共 4 cases.
    	for (int row = 0; row < n; row++) {
    		for (int col = 0; col <= row; col++) {
    			if ((row - 1 >= 0) && (col - 1 >= 0) && (col <= row - 1)) {
    				// case 1: left, right 上邻居都存在
    				int mi = min(A[row - 1][col - 1], A[row - 1][col]);
    				A[row][col] += mi;
    			} else if ((row - 1 >= 0) && (col - 1 < 0) && (col <= row - 1)) {
    				// case 2: left上不存在, right上存在
    				A[row][col] += A[row - 1][col];
    			} else if ((row - 1 >= 0) && (col - 1 >= 0) && (col > row - 1)) {
    				// case 3: left上存在, right上不存在
    				A[row][col] += A[row - 1][col - 1];
    			}
    			// case 4: A[0][0](它没left上 和 right上邻居)
    			// do nothing, 保留A[0][0]数值不变.
    		}
    	}
    
    	// 返回A中最下面的一行(A[n-1])最小元素
    	int res = INT_MAX;
    	for (int i = 0; i < A[n - 1].size(); i++) {
    		res = min(res, A[n - 1][i]);
    	}
    	return res;
    }
    

    方法二:
    自下而上,不破坏数组A.
    关键是找本层和上一层元素的关系,那就是 temp[j] = A[i,j] + min(temp[j], temp[j+1]).
    (O(n^2)) time, (O(n)) space.

    // 方法二:
    // 自下而上,不破坏数组A. 维护一个长度为 n 的 1-dim 数组.
    // $O(n^2)$ time, $O(n)$ space.
    int minimumTotal(vector<vector<int>>& A) {
    	const int n = A.size();
    	if (n == 0)
    		return 0;
    	if (n == 1)
    		return A[0][0];
    	vector<int> temp;
    	// A 最后一行存入temp
    	for (int j = 0; j < n; j++)
    		temp.push_back(A[n - 1][j]);
    
    	// 从倒数第二行到上按路径元素取min的,相加
    	// 对应关系:
    	//     A[2, 1]
    	// temp[1]  temp[1+1]
    
    	for (int i = n - 2; i >= 0; i--) {
    		for (int j = 0; j <= i; j++) {
    			int smal = min(temp[j], temp[j + 1]);
    			// 若当前使用temp[0], temp[1]
    			// temp[0] 被改, 但不影响下次使用temp[1], temp[2]
    			temp[j] = A[i][j] + smal;
    		}
    	}
    	return temp[0];
    }
    
  • 相关阅读:
    docker 应用-1(安装以及基础命令)
    网桥原理及使用
    【年终总结】个人的2019年年终总结
    【bat批处理】批量执行某个文件夹下的所有sql文件bat批处理
    【实用工具】.fbr格式免费播放器 FBR格式 Free FlashBack Player
    【SQL骚操作】SqlServer数据库表生成C# Model实体类SQL语句
    【算法基础】面试过程中遇到的一些算法题输出杨辉三角
    【sql基础】按照名字分组查询时间最早的一条记录
    【面试题】java面试题整理(有空再贴答案)
    【海驾资料】海淀驾校科目三考试资料
  • 原文地址:https://www.cnblogs.com/ZhongliangXiang/p/7450829.html
Copyright © 2020-2023  润新知