【LeetCode】triangle & pascals-triangle i&ii

题干

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 is11(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.

pascals-triangle i

Given numRows, generate the first numRows of Pascal’s triangle.

For example, given numRows = 5,
Return

[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]
pascals-triangle ii

Given an index k, return the *k*th row of the Pascal’s triangle.

For example, given k = 3,
Return[1,3,3,1].

Note:
Could you optimize your algorithm to use only O(k) extra space?

三个题都是跟三角形相关的。

问题一,类似于树的深度遍历,得到路径上和最小的路径值。

问题二,杨辉三角,得到固定行数的杨辉三角所有数据。

问题三,杨辉三角,得到第k行的杨辉三角,要求额外的空间开销为o(k)。

数据结构

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

解题思路

问题一

类似于树的深度遍历,得到每一条路径的和,找到最小的。但本体的数据结构不是树,没有左右子数的天然联系。于是采用动态规划,设任意结点到叶子节点路径的最小和为sum[i][j]=sum[i][j]+min((sum[i+1][j],sum[i+1][j+1])。于是从下面向上遍历就得到了最终根结点到叶子结点路径的最小和,为sum[0][0]。

问题二

所有数据的杨辉三角用每次上一个的数据进行计算得到即可。

两层循环,第一层i代表行数,第二层j为对每行每个值进行赋值,j=0或者j=i-1的值为triangle[i][0]=triangle[i][i-1]=1,其余triangle[i][j]=triangle[i-1][j-1]+triangle[i-1][j]。

问题三

要求得单一第k行的杨辉三角数据,每一行都是上一行的数据得到的,如果没有空间复杂度要求直接用迭代可解。本体直接用循环解,用一个存储v ectortmp上一层的杨辉三角数据,然后用tmp得到当前层的vecotrtriangle,与上题类似,第i行的第0个和第i-1个数据为1,其余用上一层数据triangle[j]=tmp[j-1]+tmp[j]得到。

参考代码

问题一:
class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        if (triangle.size()<=0)
            return 0;//无效输入
        vector<vector<int>> sum(triangle);//复制一份数据
        for(int i=sum.size()-2;i>=0;i--)//行数
        {
            for(int j=0;j<=i;j++)//每行每个数遍历
            {
                sum[i][j]=sum[i][j]+(sum[i+1][j]<sum[i+1][j+1])?sum[i+1][j]:sum[i+1][j+1]);//动态规划的表达式
            }
        }
        return sum[0][0];//最终结果
    }
};
问题二:
class Solution {
public:
    vector<vector<int> > generate(int numRows) {
        vector<vector<int>>triangle=*new vector<vector<int>>();
        for(int i=0;i<numRows;i++)
        {
            vector<int>tmp;
            for(int j=0;j<i+1;j++)
            {
                if (j==0||j==i)//第一个和最后一个数据为1
                    tmp.push_back(1);
                else
                    tmp.push_back(triangle[i-1][j-1]+triangle[i-1][j]);
            }
            triangle.push_back(tmp);
        }
        return triangle;
    }
};
问题三:
方法一:
    class Solution {
    public:
        vector<int> getRow(int rowIndex) {
            vector<int>triangle=*new vector<int>();//当前行数据
            vector<int>tmp=*new vector<int>();//存储上一行数据
            triangle.push_back(1);//初始化第一行
            for(int i=1;i<=rowIndex;++i)
            {
                for (int j=1; j<i; ++j)
                {
                    if (j==i)
                        triangle.push_back(1);
                    else
                        triangle[j]=tmp[j-1]+tmp[j];
                }
                triangle.push_back(1);
                tmp=triangle;//把当前行数据存储到tmp以便求下一行
            }
            return triangle;
        }
    };
方法二:
    class Solution {
    public:
    vector<int> getRow(int rowIndex) {
        vector<int> triangle(rowIndex+1, 0);
        triangle[0] = 1; //初始化第一个值
        for(int i=1; i<rowIndex+1; i++) 
            for(int j=i; j>=1; j--)//每行从后向前遍历
                triangle[j] += triangle[j-1]; 
                return triangle;
        }        
    };

方法讨论

三个题主要都是动态规划,写出每行之间的关系即可。

易错点

对于vector数据的输入

vector动态分配,没有分配值的vector元素是不可以用[][]的方式进行访问,也就是说,赋值的时候要用push_back()接口来进行赋值,而不能直接按照数组的赋值方式,因为未赋值,这样访问不合法。

数据覆盖问题

在问题三中,也可以不开辟储存上一行的空间。但注意数据不要覆盖掉。由于triangle[j]=triangle[j-1]+triangle[j],故从后往前遍历就会避免覆盖数据的情况。

边界条件

1.动态规划的边界条件,第一行或者第一个值要提前单独赋值,要不然无法迭代出后面的值。

2.对于杨辉三角每一行的第一个或者最后一个字符不在循环内。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值