您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“C++實(shí)現(xiàn)求最小路徑和”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“C++實(shí)現(xiàn)求最小路徑和”吧!
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example:
Input:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.
這道題給了我們一個只有非負(fù)數(shù)的二維數(shù)組,讓找一條從左上到右下的路徑,使得路徑和最小,限定了每次只能向下或者向右移動。一個常見的錯誤解法就是每次走右邊或下邊數(shù)字中較小的那個,這樣的貪婪算法獲得的局部最優(yōu)解不一定是全局最優(yōu)解,因此是不行的。實(shí)際上這道題跟之前那道 Dungeon Game 沒有什么太大的區(qū)別,都需要用動態(tài)規(guī)劃 Dynamic Programming 來做,這應(yīng)該算是 DP 問題中比較簡單的一類,我們維護(hù)一個二維的 dp 數(shù)組,其中 dp[i][j] 表示到達(dá)當(dāng)前位置的最小路徑和。接下來找狀態(tài)轉(zhuǎn)移方程,因?yàn)榈竭_(dá)當(dāng)前位置 (i, j) 只有兩種情況,要么從上方 (i-1, j) 過來,要么從左邊 (i, j-1) 過來,我們選擇 dp 值較小的那個路徑,即比較 dp[i-1][j] 和 dp[i][j-1],將其中的較小值加上當(dāng)前的數(shù)字 grid[i][j],就是當(dāng)前位置的 dp 值了。但是有些特殊情況要提前賦值,比如起點(diǎn)位置,直接賦值為 grid[0][0],還有就是第一行和第一列,其中第一行的位置只能從左邊過來,第一列的位置從能從上面過來,所以這兩行要提前初始化好,然后再從 (1, 1) 的位置開始更新到右下角即可,反正難度不算大,代碼如下:
解法一:
class Solution { public: int minPathSum(vector<vector<int>>& grid) { if (grid.empty() || grid[0].empty()) return 0; int m = grid.size(), n = grid[0].size(); vector<vector<int>> dp(m, vector<int>(n)); dp[0][0] = grid[0][0]; for (int i = 1; i < m; ++i) dp[i][0] = grid[i][0] + dp[i - 1][0]; for (int j = 1; j < n; ++j) dp[0][j] = grid[0][j] + dp[0][j - 1]; for (int i = 1; i < m; ++i) { for (int j = 1; j < n; ++j) { dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]); } } return dp[m - 1][n - 1]; } };
我們可以優(yōu)化空間復(fù)雜度,可以使用一個一維的 dp 數(shù)組就可以了,初始化為整型最大值,但是 dp[0][0] 要初始化為0。之所以可以用一維數(shù)組代替之前的二維數(shù)組,是因?yàn)楫?dāng)前的 dp 值只跟左邊和上面的 dp 值有關(guān)。這里我們并不提前更新第一行或是第一列,而是在遍歷的時(shí)候判斷,若j等于0時(shí),說明是第一列,我們直接加上當(dāng)前的數(shù)字,否則就要比較是左邊的 dp[j-1] 小還是上面的 dp[j] 小,當(dāng)是第一行的時(shí)候,dp[j] 是整型最大值,所以肯定會取到 dp[j-1] 的值,然后再加上當(dāng)前位置的數(shù)字即可,參見代碼如下:
解法二:
class Solution { public: int minPathSum(vector<vector<int>>& grid) { if (grid.empty() || grid[0].empty()) return 0; int m = grid.size(), n = grid[0].size(); vector<int> dp(n, INT_MAX); dp[0] = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (j == 0) dp[j] += grid[i][j]; else dp[j] = grid[i][j] + min(dp[j], dp[j - 1]); } } return dp[n - 1]; } };
我們還可以進(jìn)一步的優(yōu)化空間,連一維數(shù)組都不用新建,而是直接使用原數(shù)組 grid 進(jìn)行累加,這里的累加方式跟解法一稍有不同,沒有提前對第一行和第一列進(jìn)行賦值,而是放在一起判斷了,當(dāng)i和j同時(shí)為0時(shí),直接跳過。否則當(dāng)i等于0時(shí),只加上左邊的值,當(dāng)j等于0時(shí),只加上面的值,否則就比較左邊和上面的值,加上較小的那個即可,參見代碼如下:
解法三:
class Solution { public: int minPathSum(vector<vector<int>>& grid) { if (grid.empty() || grid[0].empty()) return 0; for (int i = 0; i < grid.size(); ++i) { for (int j = 0; j < grid[i].size(); ++j) { if (i == 0 && j == 0) continue; if (i == 0) grid[0][j] += grid[0][j - 1]; else if (j == 0) grid[i][0] += grid[i - 1][0]; else grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]); } } return grid.back().back(); } };
下面這種寫法跟上面的基本相同,只不過用了 up 和 left 兩個變量來計(jì)算上面和左邊的值,看起來稍稍簡潔一點(diǎn),參見代碼如下:
解法四:
class Solution { public: int minPathSum(vector<vector<int>>& grid) { if (grid.empty() || grid[0].empty()) return 0; for (int i = 0; i < grid.size(); ++i) { for (int j = 0; j < grid[i].size(); ++j) { if (i == 0 && j == 0) continue; int up = (i == 0) ? INT_MAX : grid[i - 1][j]; int left = (j == 0) ? INT_MAX : grid[i][j - 1]; grid[i][j] += min(up, left); } } return grid.back().back(); } };
到此,相信大家對“C++實(shí)現(xiàn)求最小路徑和”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。