【Leetcode】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, wheren is the total number of rows in the triangle.

思路一:遞歸,要求以某個數爲起點的最小和,可以先求出以跟它相鄰的下一層的兩個數爲起點的最小和,然後取兩者的更小者,最後與該數相加即可。基於此可以寫出下面的代碼:

class Solution {
public:
	int minimumTotal(vector<vector<int> > &triangle) 
	{
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		return minimumTotal(triangle,0,0);
	}

	int minimumTotal(vector<vector<int> > &triangle, int i, int j)
	{
		if(i == triangle.size()-1)
			return triangle[i][j];

		int sum0 = minimumTotal(triangle,i+1,j);
		int sum1 = minimumTotal(triangle,i+1,j+1);

		return min(sum0,sum1) + triangle[i][j];
	}
};
可以看到代碼簡潔易懂,不過在Judge large時超時,原因是重複計算了很多子問題,優化它的思路就是用DP,思想是把先把子問題計算好,供查詢使用。下面貼上優化的代碼:

class Solution 
{
public:
	int minimumTotal(vector<vector<int> > &triangle) 
	{
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		// 分配空間
		int numRow = triangle.size();
		vector<vector<int> > ibuffer;
		ibuffer.resize(numRow);
		for (int i=0; i<numRow; ++i)
			ibuffer[i].resize(numRow);

		// 從底到頂計算最小和
		for (int i=numRow-1; i>=0; --i)
		{
			vector<int> &row = triangle[i];

			for (int j=0; j<row.size(); ++j)
			{
				if(i==numRow-1)
					ibuffer[i][j] = row[j];
				else
					ibuffer[i][j] = min(row[j]+ibuffer[i+1][j], row[j]+ibuffer[i+1][j+1]);
			}
		}
		
		return ibuffer[0][0];
	}
};
上面的代碼可以通過Large judge。不過開了一個n*n大小的二維數組,因此空間複雜度爲O(n^2),n爲三角形的層數。進一步觀察發現,開二維數組沒有必要,因爲每次計算只會查詢下一層的計算結果,下下層及更後層的計算結果不會使用到,因此可以只開個大小爲n的一維數組就可以了。最終代碼如下:

class Solution 
{
public:
	int minimumTotal(vector<vector<int> > &triangle) 
	{
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		// 分配空間
		int numRow = triangle.size();
		vector<int> ibuffer;
		ibuffer.resize(numRow);

		// 從底到頂計算最小和
		for (int i=numRow-1; i>=0; --i)
		{
			vector<int> &row = triangle[i];

			for (int j=0; j<row.size(); ++j)
			{
				if(i==numRow-1)
					ibuffer[j] = row[j];
				else
					ibuffer[j] = min(row[j]+ibuffer[j], row[j]+ibuffer[j+1]);
			}
		}

		return ibuffer[0];
	}
};
空間複雜度爲O(n),n爲三角形的層數,時間複雜度爲O(K),K爲整個三角形中數字的個數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章