代碼隨想錄學習摘抄day9(回溯1-11)

一個樸實無華的目錄

  • 定義:回溯法也可以叫做回溯搜索法,它是一種搜索的方式。
    • 應用場景:回溯法解決的問題都可以抽象為樹形結構
    • 代碼模板
  • 題型
    • 第77題. 組合
      • 思路:每次從集合中選取元素,可選擇的范圍隨著選擇的進行而收縮,調整可選擇的范圍。
    • 216.組合總和III
      • 思路:本題k相當于樹的深度,9(因為整個集合就是9個數)就是樹的寬度。
    • 17.電話號碼的字母組合
      • 思路:求不同集合之間的組合
    • 39. 組合總和
      • 思路:
    • 40.組合總和II
      • 思路:加一個bool型數組used,用來記錄同一樹枝上的元素是否使用過。實現去重
    • 131.分割回文串
      • 思路:
    • 93.復原IP地址
      • 思路:切割問題就可以使用回溯搜索法把所有可能性搜出來
    • 78.子集
      • 思路:子集問題是找樹的所有節點

定義:回溯法也可以叫做回溯搜索法,它是一種搜索的方式。

回溯是遞歸的副產品,只要有遞歸就會有回溯。

應用場景:回溯法解決的問題都可以抽象為樹形結構

集合的大小就構成了樹的寬度,遞歸的深度就構成了樹的深度。
組合問題:N個數里面按一定規則找出k個數的集合
切割問題:一個字符串按一定規則有幾種切割方式
子集問題:一個N個數的集合里有多少符合條件的子集
排列問題:N個數按一定規則全排列,有幾種排列方式
棋盤問題:N皇后,解數獨等等

代碼模板

void backtracking(參數) {if (終止條件) {存放結果;return;}for (選擇:本層集合中元素(樹中節點孩子的數量就是集合的大小)) {處理節點;backtracking(路徑,選擇列表); // 遞歸回溯,撤銷處理結果}
}

題型

第77題. 組合

給定兩個整數 n 和 k,返回 1 … n 中所有可能的 k 個數的組合。

示例: 輸入: n = 4, k = 2 輸出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

思路:每次從集合中選取元素,可選擇的范圍隨著選擇的進行而收縮,調整可選擇的范圍。

圖中可以發現n相當于樹的寬度,k相當于樹的深度。
圖中每次搜索到了葉子節點,我們就找到了一個結果。
把達到葉子節點的結果收集起來,就可以求得 n個數中k個數的組合集合。

class Solution {
private:vector<vector<int>> result; // 存放符合條件結果的集合vector<int> path; // 用來存放符合條件結果void backtracking(int n, int k, int startIndex) {if (path.size() == k) {result.push_back(path);return;}for (int i = startIndex; i <= n; i++) {path.push_back(i); // 處理節點backtracking(n, k, i + 1); // 遞歸path.pop_back(); // 回溯,撤銷處理的節點}}
public:vector<vector<int>> combine(int n, int k) {result.clear(); // 可以不寫path.clear();   // 可以不寫backtracking(n, k, 1);return result;}
};

216.組合總和III

找出所有相加之和為 n 的 k 個數的組合。組合中只允許含有 1 - 9 的正整數,并且每種組合中不存在重復的數字。

思路:本題k相當于樹的深度,9(因為整個集合就是9個數)就是樹的寬度。

一維數組path來存放符合條件的結果,二維數組result來存放結果集。

class Solution {
private:vector<vector<int>> result; // 存放結果集vector<int> path; // 符合條件的結果// targetSum:目標和,也就是題目中的n。// k:題目中要求k個數的集合。// sum:已經收集的元素的總和,也就是path里元素的總和。// startIndex:下一層for循環搜索的起始位置。void backtracking(int targetSum, int k, int sum, int startIndex) {if (path.size() == k) {if (sum == targetSum) result.push_back(path);return; // 如果path.size() == k 但sum != targetSum 直接返回}for (int i = startIndex; i <= 9; i++) {sum += i; // 處理path.push_back(i); // 處理backtracking(targetSum, k, sum, i + 1); // 注意i+1調整startIndexsum -= i; // 回溯path.pop_back(); // 回溯}}public:vector<vector<int>> combinationSum3(int k, int n) {result.clear(); // 可以不加path.clear();   // 可以不加backtracking(n, k, 0, 1);return result;}
};

17.電話號碼的字母組合

給定一個僅包含數字 2-9 的字符串,返回所有它能表示的字母組合。

給出數字到字母的映射如下(與電話按鍵相同)。注意 1 不對應任何字母。
在這里插入圖片描述

思路:求不同集合之間的組合

class Solution {
private:const string letterMap[10] = {"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9};
public:vector<string> result;string s;void backtracking(const string& digits, int index) {if (index == digits.size()) {result.push_back(s);return;}int digit = digits[index] - '0';        // 將index指向的數字轉為intstring letters = letterMap[digit];      // 取數字對應的字符集for (int i = 0; i < letters.size(); i++) {s.push_back(letters[i]);            // 處理backtracking(digits, index + 1);    // 遞歸,注意index+1,一下層要處理下一個數字了s.pop_back();                       // 回溯}}vector<string> letterCombinations(string digits) {s.clear();result.clear();if (digits.size() == 0) {return result;}backtracking(digits, 0);return result;}
};

39. 組合總和

給定一個無重復元素的數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和為 target 的組合。

candidates 中的數字可以無限制重復被選取。

說明:

所有數字(包括 target)都是正整數。
解集不能包含重復的組合。
示例 1:

輸入:candidates = [2,3,6,7], target = 7,
所求解集為: [ [7], [2,2,3] ]
示例 2:

輸入:candidates = [2,3,5], target = 8,
所求解集為: [ [2,2,2,2], [2,3,3], [3,5] ]

思路:

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if (sum > target) {return;}if (sum == target) {result.push_back(path);return;}for (int i = startIndex; i < candidates.size(); i++) {sum += candidates[i];path.push_back(candidates[i]);backtracking(candidates, target, sum, i); // 不用i+1了,表示可以重復讀取當前的數sum -= candidates[i];path.pop_back();}}
public:vector<vector<int>> combinationSum(vector<int>& candidates, int target) {result.clear();path.clear();backtracking(candidates, target, 0, 0);return result;}
};

40.組合總和II

給定一個數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和為 target 的組合。

candidates 中的每個數字在每個組合中只能使用一次。

說明: 所有數字(包括目標數)都是正整數。解集不能包含重復的組合。

思路:加一個bool型數組used,用來記錄同一樹枝上的元素是否使用過。實現去重

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& used) {if (sum == target) {result.push_back(path);return;}for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {// used[i - 1] == true,說明同一樹枝candidates[i - 1]使用過// used[i - 1] == false,說明同一樹層candidates[i - 1]使用過// 要對同一樹層使用過的元素進行跳過if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) {continue;}sum += candidates[i];path.push_back(candidates[i]);used[i] = true;backtracking(candidates, target, sum, i + 1, used); // 和39.組合總和的區別1,這里是i+1,每個數字在每個組合中只能使用一次used[i] = false;sum -= candidates[i];path.pop_back();}}public:vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<bool> used(candidates.size(), false);path.clear();result.clear();// 首先把給candidates排序,讓其相同的元素都挨在一起。sort(candidates.begin(), candidates.end());backtracking(candidates, target, 0, 0, used);return result;}
};

131.分割回文串

給定一個字符串 s,將 s 分割成一些子串,使每個子串都是回文串。

返回 s 所有可能的分割方案。

示例: 輸入: “aab” 輸出: [ [“aa”,“b”], [“a”,“a”,“b”] ]

思路:

class Solution {
private:vector<vector<string>> result;vector<string> path; // 放已經回文的子串void backtracking (const string& s, int startIndex) {// 如果起始位置已經大于s的大小,說明已經找到了一組分割方案了if (startIndex >= s.size()) {result.push_back(path);return;}for (int i = startIndex; i < s.size(); i++) {if (isPalindrome(s, startIndex, i)) {   // 是回文子串// 獲取[startIndex,i]在s中的子串string str = s.substr(startIndex, i - startIndex + 1);path.push_back(str);} else {                                // 不是回文,跳過continue;}backtracking(s, i + 1); // 尋找i+1為起始位置的子串path.pop_back(); // 回溯過程,彈出本次已經添加的子串}}bool isPalindrome(const string& s, int start, int end) {for (int i = start, j = end; i < j; i++, j--) {if (s[i] != s[j]) {return false;}}return true;}
public:vector<vector<string>> partition(string s) {result.clear();path.clear();backtracking(s, 0);return result;}
};

93.復原IP地址

給定一個只包含數字的字符串,復原它并返回所有可能的 IP 地址格式。

有效的 IP 地址 正好由四個整數(每個整數位于 0 到 255 之間組成,且不能含有前導 0),整數之間用 ‘.’ 分隔。

例如:“0.1.2.201” 和 “192.168.1.1” 是 有效的 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “192.168@1.1” 是 無效的 IP 地址。

思路:切割問題就可以使用回溯搜索法把所有可能性搜出來

在這里插入圖片描述
startIndex一定是需要的,因為不能重復分割,記錄下一層遞歸分割的起始位置。

本題我們還需要一個變量pointNum,記錄添加逗點的數量。

class Solution {
private:vector<string> result;// 記錄結果// startIndex: 搜索的起始位置,pointNum:添加逗點的數量void backtracking(string& s, int startIndex, int pointNum) {if (pointNum == 3) { // 逗點數量為3時,分隔結束// 判斷第四段子字符串是否合法,如果合法就放進result中if (isValid(s, startIndex, s.size() - 1)) {result.push_back(s);}return;}for (int i = startIndex; i < s.size(); i++) {if (isValid(s, startIndex, i)) { // 判斷 [startIndex,i] 這個區間的子串是否合法s.insert(s.begin() + i + 1 , '.');  // 在i的后面插入一個逗點pointNum++;backtracking(s, i + 2, pointNum);   // 插入逗點之后下一個子串的起始位置為i+2pointNum--;                         // 回溯s.erase(s.begin() + i + 1);         // 回溯刪掉逗點} else break; // 不合法,直接結束本層循環}}// 判斷字符串s在左閉右閉區間[start, end]所組成的數字是否合法bool isValid(const string& s, int start, int end) {if (start > end) {return false;}if (s[start] == '0' && start != end) { // 0開頭的數字不合法return false;}int num = 0;for (int i = start; i <= end; i++) {if (s[i] > '9' || s[i] < '0') { // 遇到非數字字符不合法return false;}num = num * 10 + (s[i] - '0');if (num > 255) { // 如果大于255了不合法return false;}}return true;}
public:vector<string> restoreIpAddresses(string s) {result.clear();if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了backtracking(s, 0, 0);return result;}
};

78.子集

給定一組不含重復元素的整數數組 nums,返回該數組所有可能的子集(冪集)。

說明:解集不能包含重復的子集。

思路:子集問題是找樹的所有節點

在這里插入圖片描述

遍歷這個樹的時候,把所有節點都記錄下來,就是要求的子集集合。

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {result.push_back(path); // 收集子集,要放在終止添加的上面,否則會漏掉自己if (startIndex >= nums.size()) { // 終止條件可以不加return;}for (int i = startIndex; i < nums.size(); i++) {path.push_back(nums[i]);backtracking(nums, i + 1);path.pop_back();}}
public:vector<vector<int>> subsets(vector<int>& nums) {result.clear();path.clear();backtracking(nums, 0);return result;}
};

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

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

相關文章

Altium Designer(AD24)打開工程文件的幾種方法

??《專欄目錄》 目錄 1,概述 2,源文件 2,菜單欄 4,工具欄 5,注意事項 1,概述 本文介紹幾種打開工程文件的方法。 2,源文件 找到工程的源文件存儲路徑,找到.PrjPcb的源工程文件,雙擊打開。 2,菜單欄 第1步:執行File→Open, 第2步:找到工程文件的存儲路徑,并選中…

Linux嵌入式自學筆記(基于野火EBF6ULL):2.點燈與ubuntu安裝

一、點燈登錄root&#xff1a;賬號&#xff1a;root ; 密碼&#xff1a;root點燈命令&#xff1a;echo 0 > /sys/class/leds/red/brightness #關閉red燈 echo 0 > /sys/class/leds/blue/brightness #關閉blue燈 echo 0 > /sys/class/leds/green/brightness …

【Java實戰?】Java實戰:MyBatis-Plus 開啟MySQL數據庫高效操作之旅

目錄 一、MyBatis-Plus 環境集成 1.1 項目依賴引入 1.2 數據庫配置 1.3 代碼生成器使用 二、核心 CRUD 操作實現 2.1 基礎查詢 2.2 數據新增與修改 2.3 復雜查詢場景 三、性能優化與高級特性 3.1 緩存配置 3.2 樂觀鎖實現 3.3 字段自動填充 四、實戰案例:用戶管理模塊開發 4.1…

開學季干貨——知識梳理與經驗分享

技術文章大綱&#xff1a;開學季干貨——知識梳理與經驗分享目標受眾分析明確文章面向的學生群體&#xff08;如大學生、高中生&#xff09; 分析不同群體的核心需求&#xff08;課程準備、時間管理、工具使用&#xff09; 結合技術場景&#xff08;如數字筆記、在線協作&#…

Linux《線程(上)》

通過之前的學習我們已經了解了操作系統當中的基本的概念包括進程、基礎IO、磁盤文件存儲等&#xff0c;但是到目前為止我們還未了解到線程相關的概念&#xff0c;這就使得當前我們對操作系統的認知還不是完整的&#xff0c;現在我們是還是無法理解一個進程當中是如何同時的執行…

為什么知識復用時缺乏場景化指導影響實用性

知識復用時因缺乏場景化指導而嚴重影響實用性&#xff0c;其根本原因在于知識的價值本質上根植于其應用情境。脫離了場景的“純知識”往往是抽象、片面且難以行動的。這導致了認知鴻溝的產生、隱性知識的流失、決策風險的增加、以及學習遷移效率的低下。當使用者面對一份缺乏“…

擁抱直覺與創造力:走進VibeCoding的新世界

引言 在傳統觀念里&#xff0c;編程是一項高度理性、邏輯嚴密的活動&#xff0c;開發者需要像建筑師一樣&#xff0c;用代碼一行行地精確構建數字世界。然而&#xff0c;隨著人工智能技術的飛速發展&#xff0c;一種全新的編程理念和體驗正在興起——它就是 VibeCoding&#xf…

HTTP的Web服務測試在Python中的實現

在Web開發領域&#xff0c;對HTTP Web服務進行測試是確保服務穩定性和可靠性的關鍵步驟。Python作為一種功能強大的編程語言&#xff0c;提供了多種工具和庫來簡化這一過程。本文將介紹如何在Python中實現HTTP的Web服務測試。首先&#xff0c;Python的requests庫是測試HTTP Web…

Android Studio 構建項目時 Gradle 下載失敗的解決方案

一、問題原因分析根據錯誤日志&#xff1a;下載地址 https://services.gradle.org/distributions/gradle-8.1-bin.zip 連接超時&#xff08;10秒&#xff09;。可能原因&#xff1a;網絡環境限制&#xff08;如公司防火墻、地區網絡屏蔽&#xff09;。代理配置未生效或配置錯誤…

mysql 與 MongoDB 的分片

MySQL 和 MongoDB 作為不同類型數據庫的代表(關系型 vs 文檔型),其分片機制在設計理念、實現方式和適用場景上存在顯著差異。兩者的分片核心目標一致——通過水平擴展(Scale Out)解決單節點存儲容量和性能瓶頸,但因數據模型、事務支持和分布式設計理念的不同,形成了截然…

Coze源碼分析-資源庫-創建知識庫-前端源碼-核心邏輯與接口

創建知識庫邏輯 1. 表單驗證系統 文件位置&#xff1a;frontend/packages/data/knowledge/knowledge-modal-base/src/create-knowledge-modal-v2/features/add-type-content/coze-knowledge/index.tsx 知識庫創建表單的驗證規則&#xff1a; // 知識庫名稱驗證規則 const nameV…

歐拉函數 | 定義 / 性質 / 應用

注&#xff1a;本文為 “歐拉函數” 相關合輯。 略作重排&#xff0c;未整理去重。 如有內容異常&#xff0c;請看原文。 歐拉函數最全總結 jiet07 已于 2024-10-22 10:00:54 修改 一、歐拉函數的引入 首先引入互質關系&#xff1a; 如果兩個正整數&#xff0c;除了 111 以…

ubuntu git push每次都要輸入密碼怎么解決只輸入一次密碼

在 Ubuntu 下使用 Git 時&#xff0c;如果每次 push 都需要重復輸入密碼&#xff0c;可以通過配置 Git 憑證存儲來解決。以下是幾種常用方法&#xff1a; &#x1f511; 方法一&#xff1a;使用 Git 憑證緩存&#xff08;推薦&#xff09; 設置憑證緩存&#xff08;默認 15 分鐘…

【機械故障】使用fir濾波器實現數據擬合

使用fir濾波器實現數據擬合 提示&#xff1a;學習筆記 使用fir濾波器實現數據擬合使用fir濾波器實現數據擬合一、問題建模二、 構建矩陣方程&#xff08;關鍵步驟&#xff09;三、最小二乘解四、重要注意事項4.1 濾波器長度 M4.2 數據的預處理4.3 延遲問題4.4 性能評估一、問題…

STC8H系列-高級PWM-兩相步進電機-細分驅動

兩相步進電機, STC8H系列 用高級PWM實現SPWM細分驅動 /************* 功能說明 ************** 用B組高級PWM細分驅動2相4線小型步進電機, 支持1、2、4、8、16、32、64細分, 比如1.8度的電機4細分到0.45度. 本程序用于演示SPWM多細分直接驅動2相4線小型步進電機…

內網環境下ubuntu 20.04搭建深度學習環境總結

2025年9月更新&#xff0c;隨著人工智能的發展&#xff0c;現在深度學習環境配置越來越簡單了&#xff0c;常用的pytorch、paddle&#xff08;3.x&#xff09;等深度學習庫安裝的時候自帶了cuda和cudnn的python包&#xff0c;不需要在操作系統層面自己安裝&#xff0c;配置環境…

深入 Linux 文件系統:從數據存儲到萬物皆文件

深入 Linux 文件系統&#xff1a;從數據存儲到萬物皆文件 Linux 文件系統是一個精妙而復雜的工程&#xff0c;它像一座圖書館&#xff0c;不僅存放著書籍&#xff08;數據&#xff09;&#xff0c;還有一套高效的卡片索引系統&#xff08;元數據&#xff09;來管理它們。本文將…

C++, ffmpeg, libavcodec-RTSP拉流,opencv實時預覽

文章目錄RTSPStreamPlayer.cppRTSPStreamPlayer.hmain.cpp編譯運行在ffmpeg_rtsp原有的rtsp拉流項目基礎上加入了udp連接rtsp&#xff0c;日志模塊&#xff0c;opencv實施預覽等功能。RTSPStreamPlayer.cpp #include "RTSPStreamPlayer.h" #include <iostream>…

MySQL在Ubuntu 20.04 環境下的卸載與安裝

目錄 前言&#xff1a;學習引入 1、安裝注意事項 2、學習建議 3、MySQL 和 MariaDB 核心概念一&#xff1a;它們是什么&#xff1f; 核心概念二&#xff1a;它們如何工作&#xff1f;&#xff08;“倉庫”比喻&#xff09; 核心概念三&#xff1a;為什么它們如此流行&…

BizDevOps 是什么?如何建設企業 BizDevOps 體系

在數字經濟加速滲透的今天&#xff0c;企業數字化轉型已從 “技術升級” 轉向 “價值重構”&#xff0c;單純的 IT 研發或業務優化已難以適應市場快速變化。業務研發運營一體化&#xff08;BizDevOps&#xff09;作為打通 “業務 - 技術 - 運維” 協同壁壘的核心模式&#xff0…