代碼隨想錄算法訓練營第三十三天

LeetCode.62 不同路徑

題目鏈接?不同路徑

題解

class Solution {public int uniquePaths(int m, int n) {// dp表示到達ij有多少條路徑int[][] dp = new int[110][110];dp[1][1] = 1;for(int i = 0;i<m;i++){dp[i][0] = 1;}for(int j = 0;j<n;j++){dp[0][j] = 1;}for(int i = 1;i<m;i++){for(int j = 1;j<n;j++){dp[i][j] = dp[i-1][j] + dp[i][j-1];}}return dp[m-1][n-1];}
}

解題思路

這段代碼是用來解決不同路徑問題的動態規劃實現。下面我將詳細解析這段代碼的思路、實現細節以及可能的優化點。

一、問題背景:不同路徑問題

一個機器人位于一個?m x n?網格的左上角(起始點在下圖中標記為 “Start”)。機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為 “Finish”)。問總共有多少條不同的路徑?

例如,當?m=3,n=7?時,總共有 28 條不同路徑。

二、代碼思路解析

1. 動態規劃定義

  • dp[i][j]?表示:從左上角?(0,0)?出發,到達網格?(i,j)?時的不同路徑總數

2. 邊界條件

  • 當?i=0(第一行)時,機器人只能一直向右移動,所以到達?(0,j)?的路徑只有 1 條,即?dp[0][j] = 1
  • 當?j=0(第一列)時,機器人只能一直向下移動,所以到達?(i,0)?的路徑只有 1 條,即?dp[i][0] = 1
  • 代碼中初始化了?dp[1][1] = 1,但實際通過后續對第一行和第一列的初始化,這個值會被覆蓋(若?m?和?n?大于 1),可以忽略。

3. 狀態轉移方程

  • 對于網格中任意一點?(i,j)(非第一行、非第一列),機器人只能從上方?(i-1,j)?或左方?(i,j-1)?移動而來。
  • 因此,到達?(i,j)?的路徑數 = 到達?(i-1,j)?的路徑數 + 到達?(i,j-1)?的路徑數,即:
    dp[i][j] = dp[i-1][j] + dp[i][j-1]

4. 遍歷順序

  • 從?i=1?到?i=m-1(行遍歷),從?j=1?到?j=n-1(列遍歷),依次計算每個網格的路徑數,最終?dp[m-1][n-1]?即為答案。

三、代碼細節說明

  1. 數組初始化
    int[][] dp = new int[110][110];
    這里創建了一個?110x110?的二維數組,足夠覆蓋題目中常見的?m?和?n?范圍(通常題目約束?m,n <= 100)。

  2. for(int i = 0;i<m;i++){dp[i][0] = 1;  // 第一列全為1
    }
    for(int j = 0;j<n;j++){dp[0][j] = 1;  // 第一行全為1
    }
    
    ?

    這兩個循環正確初始化了邊界條件,確保第一行和第一列的路徑數均為 1。

  3. 狀態轉移計算

    for(int i = 1;i<m;i++){for(int j = 1;j<n;j++){dp[i][j] = dp[i-1][j] + dp[i][j-1];}
    }
    
    ?

    雙層循環遍歷網格的非邊界部分,通過上方和左方的路徑數累加得到當前網格的路徑數。

  4. 返回結果
    return dp[m-1][n-1];
    由于數組下標從 0 開始,右下角的坐標為?(m-1, n-1),直接返回該位置的路徑數即可。

四、測試案例驗證

以?m=3,n=7?為例:

  • 初始化第一行?dp[0][0..6] = [1,1,1,1,1,1,1],第一列?dp[0..2][0] = [1,1,1]
  • 計算?dp[1][1] = dp[0][1] + dp[1][0] = 1 + 1 = 2
  • 計算?dp[1][2] = dp[0][2] + dp[1][1] = 1 + 2 = 3
  • ... 依次類推,最終?dp[2][6] = 28,與預期結果一致。

LeetCode.63. 不同路徑 II

題目鏈接?不同路徑 II

題解

class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m = obstacleGrid.length;int n = obstacleGrid[0].length;int[][] dp = new int[110][110];for(int i = 0;i<m;i++){if(obstacleGrid[i][0] == 1) {break;}dp[i][0] = 1;}for(int j = 0;j<n;j++){if(obstacleGrid[0][j] == 1) {break;}dp[0][j] = 1;}for(int i = 1;i<m;i++){for(int j = 1;j<n;j++){dp[i][j] = dp[i-1][j] + dp[i][j-1];if(obstacleGrid[i][j] == 1) dp[i][j] = 0;}}return dp[m-1][n-1];}
}

解題思路

這段代碼是用來解決帶障礙物的不同路徑問題的動態規劃實現。相比基礎的不同路徑問題,這個問題增加了障礙物的限制,我們來詳細分析這段代碼的思路和實現細節。

一、問題背景:帶障礙物的不同路徑

一個機器人位于一個?m x n?網格的左上角(起始點)。機器人每次只能向下或者向右移動一步。網格中可能存在障礙物,機器人不能通過障礙物。求從左上角到右下角總共有多少條不同的路徑?

例如,對于下面的網格(1 表示障礙物):

[[0,0,0],[0,1,0],[0,0,0]
]

答案是 2,因為有兩條不同的路徑可以避開障礙物到達終點。

二、代碼思路解析

1. 動態規劃定義

  • dp[i][j]?表示:從左上角?(0,0)?出發,到達網格?(i,j)?時的不同路徑總數(若?(i,j)?是障礙物,則路徑數為 0)。

2. 邊界條件處理

  • 對于第一列(j=0):
    • 從?i=0?開始遍歷,如果遇到障礙物(obstacleGrid[i][0] == 1),則后續所有單元格都無法到達(直接?break)。
    • 否則,dp[i][0] = 1(只能從上方一直向下移動到達)。
  • 對于第一行(i=0):
    • 從?j=0?開始遍歷,如果遇到障礙物(obstacleGrid[0][j] == 1),則后續所有單元格都無法到達(直接?break)。
    • 否則,dp[0][j] = 1(只能從左方一直向右移動到達)。

3. 狀態轉移方程

  • 對于非邊界的單元格?(i,j)
    • 先計算正常情況下的路徑數:dp[i][j] = dp[i-1][j] + dp[i][j-1](從上方或左方到達)。
    • 如果當前單元格是障礙物(obstacleGrid[i][j] == 1),則路徑數為 0,即?dp[i][j] = 0

4. 最終結果

  • 返回?dp[m-1][n-1],即到達右下角的路徑總數。

三、代碼細節說明

  1. 初始化網格大小

    int m = obstacleGrid.length;
    int n = obstacleGrid[0].length;
    
    ?

    通過輸入的障礙物網格獲取行數?m?和列數?n

  2. DP 數組初始化

    int[][] dp = new int[110][110];
    
    ?

    創建一個?110x110?的二維數組,足夠覆蓋常見的網格大小約束。

  3. 第一列邊界處理

    for(int i = 0;i<m;i++){if(obstacleGrid[i][0] == 1) {break;  // 遇到障礙物,后續單元格都無法到達}dp[i][0] = 1;
    }
    
    ?

    從頂部開始向下遍歷第一列,一旦遇到障礙物,就終止循環,確保障礙物下方的單元格路徑數保持默認的 0。

  4. 第一行邊界處理

    for(int j = 0;j<n;j++){if(obstacleGrid[0][j] == 1) {break;  // 遇到障礙物,后續單元格都無法到達}dp[0][j] = 1;
    }
    
    ?

    從左側開始向右遍歷第一行,邏輯與第一列處理類似。

  5. 非邊界單元格計算

    for(int i = 1;i<m;i++){for(int j = 1;j<n;j++){dp[i][j] = dp[i-1][j] + dp[i][j-1];  // 先計算正常路徑數if(obstacleGrid[i][j] == 1) dp[i][j] = 0;  // 若有障礙物則路徑數為0}
    }
    
    ?

    雙層循環遍歷網格的非邊界部分,先按正常邏輯累加路徑數,再判斷當前位置是否為障礙物并修正路徑數。

四、測試案例驗證

以示例網格為例:

[[0,0,0],[0,1,0],[0,0,0]
]

  • 初始化第一列:dp[0][0]=1dp[1][0]=1dp[2][0]=1(無障礙物)。
  • 初始化第一行:dp[0][0]=1dp[0][1]=1dp[0][2]=1(無障礙物)。
  • 計算?dp[1][1]:先算?dp[0][1] + dp[1][0] = 2,但因?(1,1)?是障礙物,最終?dp[1][1] = 0
  • 計算?dp[1][2]dp[0][2] + dp[1][1] = 1 + 0 = 1(無障礙物,結果為 1)。
  • 計算?dp[2][1]dp[1][1] + dp[2][0] = 0 + 1 = 1(無障礙物,結果為 1)。
  • 計算?dp[2][2]dp[1][2] + dp[2][1] = 1 + 1 = 2(最終答案為 2)。

結果與預期一致,驗證了代碼的正確性。

LeetCode.96 不同的二叉搜索樹

題目鏈接?不同的二叉搜索樹

題解

class Solution {public int numTrees(int n) {int[] dp = new int[25];dp[0] = 1;for(int i = 1;i<=n;i++){for(int j = 1;j<=i;j++){dp[i] += dp[j-1] * dp[i-j]; }}return dp[n];}
}

解題思路

這段代碼實現了計算不同結構的二叉搜索樹數量的功能,使用的是動態規劃的思想。

代碼解析:

  1. 定義了一個numTrees方法,接收一個整數n作為參數,返回值是int類型,表示 n 個節點能組成的不同二叉搜索樹的數量。

  2. 創建了一個長度為 25 的數組dp,用于存儲中間計算結果。dp[i]表示 i 個節點能組成的不同二叉搜索樹的數量。

  3. 初始化dp[0] = 1,這是一個邊界條件,表示 0 個節點時只有 1 種情況(空樹)。

  4. 使用兩層循環計算dp數組:

    • 外層循環i從 1 到 n,表示計算 i 個節點的情況
    • 內層循環j從 1 到 i,表示以 j 為根節點的情況
    • 當以 j 為根節點時,左子樹有 j-1 個節點,右子樹有 i-j 個節點
    • 因此dp[i]等于所有可能的左子樹數量乘以右子樹數量的和
  5. 最后返回dp[n],即 n 個節點能組成的不同二叉搜索樹的數量

這個問題其實是一個經典的卡特蘭數(Catalan number)問題,代碼通過動態規劃的方式計算出了第 n 個卡特蘭數,也就是 n 個節點所能組成的不同二叉搜索樹的數量。

總結

以上三個問題均用動態規劃求解。62 題算 m×n 網格不同路徑數,dp [i][j] 為到 (i,j) 的路徑數,邊界為首行首列全 1,轉移方程為 dp [i][j] = 左 + 上。63 題加障礙物,遇障后首行 / 列后續為 0,當前有障則 dp 為 0。96 題算 n 個節點二叉搜索樹數,是卡特蘭數問題,dp [i] 為 i 個節點的樹數,轉移方程為左子樹數 × 右子樹數之和。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90994.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90994.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90994.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

銀行回單OCR識別技術原理

銀行回單OCR&#xff08;光學字符識別&#xff09;技術通過結合圖像處理、模式識別和自然語言處理&#xff08;NLP&#xff09;技術&#xff0c;將紙質或電子版銀行回單中的非結構化文本&#xff08;如賬號、金額、日期等&#xff09;轉化為結構化數據。以下是其核心原理和關鍵…

Day22-二叉樹的迭代遍歷

昨天學習了遞歸遍歷&#xff1a;遞歸就是一次次的把參數壓入棧中&#xff0c;然后返回的時候還是上一次遞歸保存的參數。今天學習迭代遍歷。迭代遍歷就是用棧去模擬保存二叉樹的節點&#xff0c;然后依次去遍歷&#xff0c;只不過要注意棧的后入先出的規則。前序遍歷&#xff1…

知識蒸餾 - 通過引入溫度參數T調整 Softmax 的輸出

知識蒸餾 - 通過引入溫度參數T調整 Softmax 的輸出 flyfish import torch import torch.nn.functional as F import matplotlib.pyplot as plt import numpy as np# 設置中文字體支持 plt.rcParams["font.family"] [AR PL UMing CN] # Linux plt.rcParams[axes.uni…

Java研學-RabbitMQ(三)

一 消息通信協議 1 AMQP AMQP 是一個開放的、跨語言、跨平臺的消息協議標準&#xff0c;用于在分布式系統中傳遞業務消息。它定義了消息隊列的二進制協議格式和交互模型&#xff08;如交換機、隊列、綁定等&#xff09;&#xff0c;確保不同語言&#xff08;Java、Python、C#等…

http.client 教程-如何使用 Python 標準庫發送 HTTP 請求

http.client 教程-如何使用 Python 標準庫發送 HTTP 請求以下是 http.client 模塊的詳細使用教程&#xff0c;幫助你理解如何使用 Python 標準庫發送 HTTP 請求&#xff1a;1. http.client 概述http.client 是 Python 內置的 HTTP 客戶端庫&#xff0c;提供了底層的 HTTP 協議實…

Android-三種持久化方式詳解

持久化技術分為3種&#xff0c;文件&#xff0c;sharedPreferences存儲&#xff0c;數據庫來存儲&#xff1b; 目錄 文件存儲&#xff1a; 利用SharedPreferences中讀取數據 SQLite創建數據庫 更新 添加 刪除 查找&#xff1a; 文件存儲&#xff1a; 文件存儲是 Andr…

并發安全之鎖機制一

鎖機制一 鎖機制是計算機系統中解決并發沖突的核心工具&#xff0c;其存在和應用場景源于一個根本問題&#xff1a;當多個執行單元&#xff08;線程、進程、分布式節點&#xff09;同時訪問或修改同一份共享資源時&#xff0c;如何保證數據的正確性、一致性和系統可靠性&#x…

結合項目闡述 設計模式:單例、工廠、觀察者、代理

原文鏈接&#xff1a;https://download.csdn.net/blog/column/12433305/133862792#_1613 1、工廠模式應用 C17及之后可編譯 /*日志落地模塊的實現1.抽象落地基類2.派生子類&#xff08;根據不同落地方向進行派生&#xff09;3.使用工廠模式進行創建與表示的分離 */#ifndef _…

uniapp 更新apk有緩存點不動,卸載安裝apk沒有問題。android

方式一。pages.json&#xff1a;"globalStyle" : {"navigationBarTextStyle" : "black","navigationBarTitleText" : "uni-app","navigationBarBackgroundColor" : "#F8F8F8","backgroundColor&qu…

HTML響應式SEO公司網站源碼

核心優勢 100%純HTML/CSS開發自動適配手機/平板/PC內置SEO優化結構0.5秒極速加載 包含頁面 ? 首頁&#xff08;關鍵詞布局優化版&#xff09; ? 服務項目展示頁 ? 客戶案例庫 ? 新聞資訊系統 ? 聯系方式&#xff08;帶地圖API&#xff09; 技術參數 兼容Chrome/Firefo…

Error: llama runner process has terminated: exit status 2

我是i7 12700h ,3080顯卡&#xff0c;在 Windows 11 上運行 ollama run deepseek-r1:1.5b 出現 Error: llama runner process has terminated: exit status 2 之前是好用的&#xff0c;后來不知為什么就不好用了。 原因&#xff1a; 檢查 Microsoft Visual C Redistributab…

Linux中ssh遠程登錄原理與配置

SSH連接的五個階段 1. 版本協商階段&#xff08;Protocol Version Negotiation&#xff09;目的&#xff1a;協商使用SSH-1或SSH-2協議&#xff08;現代系統默認SSH-2&#xff09;。流程&#xff1a;關鍵點&#xff1a;若版本不兼容&#xff08;如客戶端只支持SSH-1&#xff0c…

Kubernetes --存儲入門

一、Volume 的概念對于大多數的項目而言&#xff0c;數據文件的存儲是非常常見的需求&#xff0c;比如存儲用戶上傳的頭像、文件以及數據庫的數據。在 Kubernetes 中&#xff0c;由于應用的部署具有高度的可擴展性和編排能力&#xff08;不像傳統架構部署在固定的位置&#xff…

螞蟻 KAG 框架開源:知識圖譜 + RAG 雙引擎

引言&#xff1a;從RAG到KAG&#xff0c;專業領域知識服務的技術突破 在大語言模型&#xff08;LLM&#xff09;應用落地過程中&#xff0c;檢索增強生成&#xff08;RAG&#xff09; 技術通過引入外部知識庫有效緩解了模型幻覺問題&#xff0c;但在專業領域仍面臨三大核心挑戰…

V-Ray 7.00.08 for 3ds Max 2021-2026 安裝與配置教程(含語言補丁)

本文介紹 V-Ray 7.00.08 渲染器在 3ds Max 2021-2026 各版本中的安裝與使用配置步驟&#xff0c;適合需要進行可視化渲染工作的設計師、建筑師及相關從業者。附帶語言補丁配置方式&#xff0c;幫助用戶獲得更順暢的使用體驗。 &#x1f4c1; 一、安裝文件準備 軟件名稱&#xf…

Go-Elasticsearch Typed Client查詢請求的兩種寫法強類型 Request 與 Raw JSON

1 為什么需要兩種寫法&#xff1f; 在 Golang 項目中訪問 Elasticsearch&#xff0c;一般會遇到兩類需求&#xff1a;需求場景特點最佳寫法后臺服務 / 業務邏輯查詢固定、字段清晰&#xff0c;需要編譯期保障Request 結構體儀表盤 / 高級搜索 / 模板 DSL查詢片段由前端或腳本動…

Leaflet 綜合案例-聚類圖層控制

看過的知識不等于學會。唯有用心總結、系統記錄&#xff0c;并通過溫故知新反復實踐&#xff0c;才能真正掌握一二 作為一名摸爬滾打三年的前端開發&#xff0c;開源社區給了我飯碗&#xff0c;我也將所學的知識體系回饋給大家&#xff0c;助你少走彎路&#xff01; OpenLayers…

React組件中的this指向問題

在 React 組件中&#xff0c;函數定義方式影響this指向的核心原因是箭頭函數與普通函數的作用域綁定規則不同&#xff0c;具體差異如下&#xff1a;? 1. 普通函數&#xff08;function定義&#xff09;需要手動bind(this)的原因? 當用function在組件內定義方法時&#xff1…

Vue 項目中的組件引用如何實現,依賴組件間的數據功能交互及示例演示

在 Vue 項目中&#xff0c;組件間的引用與數據交互是核心功能之一。以下是組件引用和數據交互的詳細實現方式及示例&#xff1a;一、組件引用方式 1. 基本組件引用 局部注冊&#xff1a;在父組件中按需引入子組件并注冊。 // ParentComponent.vue import ChildComponent from .…

? 使用 Flask 實現頭像文件上傳與加載功能

文章目錄&#x1f9f1; 技術棧&#x1f5c2;? 項目結構與配置&#x1f510; 用戶身份校驗邏輯&#x1f4e4; 頭像上傳接口&#xff1a;/file/avatar/upload&#x1f4e5; 加載頭像接口&#xff1a;/file/avatar/load/<filename>&#x1f9ea; 示例請求&#xff08;使用 …