【藍橋杯速成】| 10.回溯切割

前面兩篇內容我們都是在做有關回溯問題的組合應用

今天的題目主題是:回溯法在切割問題的應用

題目一:分割回文串

問題描述

131. 分割回文串 - 力扣(LeetCode)

給你一個字符串?s,請你將?s?分割成一些?子串,使每個子串都是?回文串?。返回?s?所有可能的分割方案。

示例 1:

輸入:s = "aab"
輸出:[["a","a","b"],["aa","b"]]

示例 2:

輸入:s = "a"
輸出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s?僅由小寫英文字母組成

解題步驟

在做這題之前我們需要明確回文串是什么東西👇

那么我們解決這個問題就可以分為分割字符串和判斷回文串兩個part

運用回溯法分割字符串其實和組合問題是類似的思路

我們需要按照字符串順序,在所有可能位置砍上一刀,形成不同的字符串碎片

那么為了不錯過任何一種可能,就需要按順序遍歷

下面就來嘗試使用回溯三部曲!

1.確定函數返回值及參數

依舊使用backtracking這個名字,沒有返回值的要求,參數呢傳入我們需要使用的字符串s以及一個開始索引startindex即可

這個開始索引是不斷變大的,意味著每次砍第一刀下去,第一個碎片的長度在慢慢變大,這也是我們有序分割的重要環節

void backtracking(string s,int startindex)

2.確定終止條件

按照最簡單的思路,和之前的組合問題一樣,我們會在葉子結點取到該過程的一個答案,再做個對應題目限制的判斷,合適就加入result中,?

那么我們的分割也是這樣,在葉子節點結束分割,把整個字符串剁碎了,

但需要注意的是,在葉子節點我們得到的不是碎片,而是雖然碎了但仍舊可以拼成完整s的組合體

就像你買了一只烤鴨,咔咔剁了幾刀,你拿到手的是所有鴨子碎片而不是只有一個鴨屁股

那么在這種情況下,加入判斷回文子串的代碼好像有點不方便

所以我們改為在單層遞歸的時候做判斷而不是在終止條件做判斷

這樣做同時也更省事了,如果你切了一刀發現這個不是回文串就沒必要再切下去了

就好比切到鴨屁股的話扔掉就好了,沒必要把鴨屁股也剁碎留著

還有一點需要明確的是分割完畢的表示方法,

在參數列表中我們不斷傳遞的startindex實際上就對應我們砍下去的那一刀,

那么只要這個索引大于等于回文串長度就是切完了

if(startindex>=s.size()){

? ? ? ? result.push_back(path);

? ? ? ? return;

}

?3.確定單層遍歷操作

還是同樣的邏輯,最外層確定第一刀位置

切下來以后加入path中,再遞歸切第二刀...

遞歸結束后需要pop加入值,做一個回溯

除了以上切割操作,我們還需要加入判斷回文串的代碼

這一個部分為使效率最大化可以加在把碎片加入path的代碼前

也就是說符合回文才加入path,否則直接return

判斷回文串我們可以另設函數所以單層遍歷操作應該如下:

for(int i=startindex;i<s.size();i++){

? ? ? ? if(isPalindrome(...){//這個函數等會再想!

? ? ? ? ? ? ? ? string str = s.substr(startindex,i-startindex+1);//當前碎片是【startindex,i】

? ? ? ? ? ? ? ? path.push_back(str);//是回文串!切下來放進path中!

? ? ? ? }else{

? ? ? ? ? ? ? ? continue;//不是就跳出!

? ? ? ? }

? ? ? ? backtracking(s,i+1);

? ? ? ? path.pop_back();

}? ? ? ?

補充:

s.substr(pos, len)

substr()是C++語言函數,主要功能是復制子字符串,要求從指定位置開始,并具有指定的長度。如果沒有指定長度_Count或_Count+_Off超出了源字符串的長度,則子字符串將延續到源字符串的結尾。?

?ok那么回溯算法的步驟我們已經完成了,還剩下判斷回文串的邏輯需要寫

4.判斷回文串

按照回文串的概念,我們只需要一個指針從頭開始,一個指針從尾開始

不斷同頻比較兩個字符是否相等就可以了

那么需要的參數就是這個字符串碎片

返回值設為bool類型

bool isPalindrome(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;

}

合并所有代碼,并在主函數中傳參調用即可!完整代碼看下面👇!?

code

class Solution {
public:vector<string> path;vector<vector<string>> result;bool isPalindrome(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;}void backtracking(string s,int startindex){if(startindex>=s.size()){result.push_back(path);return;}for(int i=startindex;i<s.size();i++){if(isPalindrome(s,startindex,i)){string str=s.substr(startindex,i-startindex+1);path.push_back(str);}else{continue;}backtracking(s,i+1);path.pop_back();}}vector<vector<string>> partition(string s) {backtracking(s,0);return result;}
};

題目二:復原IP地址

問題描述

93. 復原 IP 地址 - 力扣(LeetCode)

有效 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 地址。

給定一個只包含數字的字符串?s?,用以表示一個 IP 地址,返回所有可能的有效 IP 地址,這些地址可以通過在?s?中插入?'.'?來形成。你?不能?重新排序或刪除?s?中的任何數字。你可以按?任何?順序返回答案。

示例 1:

輸入:s = "25525511135"
輸出:["255.255.11.135","255.255.111.35"]

示例 2:

輸入:s = "0000"
輸出:["0.0.0.0"]

示例 3:

輸入:s = "101023"
輸出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 1 <= s.length <= 20
  • s?僅由數字組成

解題步驟

參照上一題,我一開始寫了以下代碼,

主要思路就是無情分割,直到最后,

在每一步分割中使用函數判斷是否符合要求

合理就加入path,逐漸組成IP地址

最后在葉子節點處加入正確的IP到result中

但是發現在單層遞歸中很難處理,

所以我們需要改變一下整個回溯的過程,按照這個題目的特點,給出量身定制的方案

class Solution {

public:

? ? string path;

? ? vector<string> result;

? ? bool isOK(string str){

? ? ? ? if(str.empty() || str.size()>3 || str[0]=='0'){

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? int num=stoi(str);

? ? ? ? return num>=0&&num<=255;

? ? }

? ? void backtracking(string s,int startindex){

? ? ? ? if(startindex>=s.size()){

? ? ? ? ? ? result.push_back(path);

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? for(int i=startindex;i<s.size();i++){

? ? ? ? ? ? string str=s.substr(startindex,i-startindex+1);

? ? ? ? ? ? if(isOK(str)){

? ? ? ? ? ? ? ? path+=str;

? ? ? ? ? ? ? ?//@#@¥¥#%#!@@¥#@%!@?????

? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? ? ? backtracking(s,i+1);

? ? ? ? ? ? path.pop_back();

? ? ? ? }

? ? }

? ? vector<string> restoreIpAddresses(string s) {

? ? ? ? if(s.size()<4 || s.size()>12){

? ? ? ? ? ? return result;

? ? ? ? }

? ? ? ? backtracking(s,0);

? ? ? ? return result;

? ? }

};

?再審審題!

IP地址是只能有4段的,每一段不超過3個數字,

所以這里我們需要把段數作為切割完成的標志,不能再用索引指到最后,

這樣就相當于做數學證明題有條件沒用上,那一般來說都是證不出來的!!!

那么和段數有關的還有IP地址中的 '.' (點),

為了一舉兩得(實現判斷段數和加點)我們可以用點數來代表段數,

點數為3意味著段數為4嘛!

重新走一邊回溯三部曲

1.確定函數返回值及參數

按照上面的思路,我們得加入段數作為參數,搭配startindex共同表示分割情況

startindex關乎下刀點,不能丟掉,把刀丟了還怎么切嘛!

void backtracking(string s,int startindex,int pointnum)

2.確定終止條件

上面已經捋清楚了:點數為3意味著段數為4

但是加入第三個點后我們還沒有判斷剩下部分,也就是第四段是否符合要求

所以這個最后一部分的合法性要放在這個終止條件中進行判斷

合法后再加入到result中

if(pointnum==3){

? ? ? ? if(isValid...){//判斷合法性等會再說!

? ? ? ? ????????result.push_back(s);

????????}

????????return;? ? ??

}

?3.確定單層遍歷操作

在單層遍歷中我們需要往s中加點(題目說了可以通過在?s?中插入?'.'?來形成),修改pointnum,遞歸,回溯

最外層遍歷依舊代表第一刀(或者說上一刀)的位置,

這樣才能確保第二🔪是從剩下的部分切的

切下來一段就需要判斷是否合法

如果合法,在s的這個位置后面加上點

再讓pointnum+1

遞歸backtracking函數

pointnum回溯,

s回溯

如果不合法,那么直接結束

for(int i=startindex;i<s.size();i++){

? ? ? ? if(isValid...){

? ? ? ? ? ? ? ? s.insert(s.begin()+i+1,'.');//加點

? ? ? ? ? ? ? ? pointnum++;

? ? ? ? ? ? ? ? backtracking(s,i+2,pointnum);//加入點后要再后挪一位!

? ? ? ? ? ? ? ? pointnum--;

? ? ? ? ? ? ? ? s.erase(s.begin()+i+1);

? ? ? ? }

? ? ? ? else

? ? ? ? ? ? ? ? break;

}

4.編寫判斷合法性函數

作為一個判斷類的函數,返回值肯定是bool類型,

參數是為了傳入待判斷的片段,所以依舊是s,start,end

在函數體中利用if?判斷IP地址一段的數字區間是否在[0,255],每一段開頭第一個是否為0,區間長度是否小于等于3,該片段是否為空

否就返回false,都沒有踩雷就返回true

bool isValid(string& s,int start,int end){? ?

????????if (start > end || end - start + 1 > 3) {

? ? ? ? ? ? return false; // 片段為空或長度超過3

? ? ? ? }

? ? ? ? if (s[start] == '0' && start != end) {

? ? ? ? ? ? return false; // 前導0不合法

? ? ? ? }

? ? ? ? string str = s.substr(start, end - start + 1);

? ? ? ? int num = stoi(str);

? ? ? ? return num >= 0 && num <= 255;

}????????

?最后整合代碼,傳入對應參數,在主函數中調用即可,

此外,在主函數中還可以加入一個剪枝,

如果字符串長度明顯不符合IP地址的長度就不用調用回溯算法了

if(s.size()<=0 || s.size()>12)

? ? ? ? return result;

完整代碼在下方!?

code?

class Solution {
public:vector<string> result;bool isValid(string& s,int start,int end){if (start > end || end - start + 1 > 3) {return false; // 片段為空或長度超過3}if (s[start] == '0' && start != end) {return false; // 前導0不合法}string str = s.substr(start, end - start + 1);int num = stoi(str);return num >= 0 && num <= 255;}?????void backtracking(string s,int startindex,int pointnum){if(pointnum==3){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)){s.insert(s.begin()+i+1,'.');//加點pointnum++;backtracking(s,i+2,pointnum);pointnum--;s.erase(s.begin()+i+1);}elsebreak;}}vector<string> restoreIpAddresses(string s) {if(s.size()<=0 || s.size()>12)return result;backtracking(s,0,0);return result;}
};

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

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

相關文章

【嵌入式硬件】三款DCDC調試筆記

關于開關電源芯片&#xff0c;重點關注輸入電源范圍、輸出電流、最低壓降。 1.MP9943: 以MP9943為例&#xff0c;輸入電壓范圍4-36V&#xff0c;輸出最大電流3A&#xff0c;最低壓降為0.3V 調整FB使正常輸出為5.06V 給定6V空載、5V空載、5V帶2A負載的情況&#xff1a; 6V帶2A…

2025年03月18日柯萊特(外包寧德)一面前端面試

目錄 自我介紹你怎么從0到1搭建項目的webpack 的構建流程手寫webpack插件你有什么想問我的嗎 2. 你怎么從 0 到 1 搭建項目的 在面試中回答從 0 到 1 搭建前端項目&#xff0c;可按以下詳細步驟闡述&#xff1a; 1. 項目前期準備 需求理解與分析 和產品經理、客戶等相關人…

在vitepress中使用vue組建,然后引入到markdown

在 VitePress 中&#xff0c;每個 Markdown 文件都被編譯成 HTML&#xff0c;而且將其作為 Vue 單文件組件處理。這意味著可以在 Markdown 中使用任何 Vue 功能&#xff0c;包括動態模板、使用 Vue 組件或通過添加 <script> 標簽為頁面的 Vue 組件添加邏輯。 值得注意的…

Jupyter Notebook 常用命令(自用)

最近有點忘記了一些常見命令&#xff0c;這里就記錄一下&#xff0c;懶得找了。 文章目錄 一、文件操作命令1. %cd 工作目錄2. %pwd 顯示路徑3. !ls 列出文件4. !cp 復制文件5. !mv 移動或重命名6. !rm 刪除 二、代碼調試1. %time 時間2. %timeit 平均時長3. %debug 調試4. %ru…

Java面試黃金寶典12

1. 什么是 Java 類加載機制 定義 Java 類加載機制是 Java 程序運行時的關鍵環節&#xff0c;其作用是把類的字節碼文件&#xff08;.class 文件&#xff09;加載到 Java 虛擬機&#xff08;JVM&#xff09;中&#xff0c;并且將字節碼文件轉化為 JVM 能夠識別的類對象。整個類…

第十四章:模板實例化_《C++ Templates》notes

模板實例化 核心知識點解析多選題設計題關鍵點總結 核心知識點解析 兩階段查找&#xff08;Two-Phase Lookup&#xff09; 原理&#xff1a; 模板在編譯時分兩個階段處理&#xff1a; 第一階段&#xff08;定義時&#xff09;&#xff1a;檢查模板語法和非依賴名稱&#xff0…

LSM-Tree(Log-Structured Merge-Tree)詳解

1. 什么是 LSM-Tree? LSM-Tree(Log-Structured Merge-Tree)是一種 針對寫優化的存儲結構,廣泛用于 NoSQL 數據庫(如 LevelDB、RocksDB、HBase、Cassandra)等系統。 它的核心思想是: 寫入時只追加寫(Append-Only),將數據先寫入內存緩沖區(MemTable)。內存數據滿后…

LangChain組件Tools/Toolkits詳解(6)——特殊類型注解Annotations

LangChain組件Tools/Toolkits詳解(6)——特殊類型注解Annotations 本篇摘要14. LangChain組件Tools/Toolkits詳解14.6 特殊類型注解Annotations14.6.1 特殊類型注解分類14.6.1 InjectedToolArg構建運行時綁定值工具14.6.3 查看并傳入參數14.6.4 在運行時注入參數14.6.5 其它特…

openharmony中hilog實證記錄說明(3.1和5.0版本)

每次用這個工具hilog都有一些小用法記不清&#xff0c;需要花一些時間去查去分析使用方法&#xff0c;為了給豐富多彩的生活留出更多的時間&#xff0c;所以匯總整理共享來了&#xff0c;它來了它來了~~~~~~~~~ 開始是想通過3.1來匯總的&#xff0c;但實際測試發現openharmony…

NVIDIA nvmath-python:高性能數學庫的Python接口

NVIDIA nvmath-python&#xff1a;高性能數學庫的Python接口 NVIDIA nvmath-python是一個高性能數學庫的Python綁定&#xff0c;它為Python開發者提供了訪問NVIDIA優化數學算法的能力。這個庫特別適合需要高性能計算的科學計算、機器學習和數據分析應用。 文章目錄 NVIDIA nv…

【euclid】20 2D包圍盒模塊(box2d.rs)

box2d.rs文件定義了一個二維軸對齊矩形&#xff08;Box2D&#xff09;&#xff0c;使用最小和最大坐標來表示。矩形在坐標類型&#xff08;T&#xff09;和單位&#xff08;U&#xff09;上是泛型的。代碼提供了多種方法來操作和查詢矩形&#xff0c;包括求交集、并集、平移、縮…

ChatTTS 開源文本轉語音模型本地部署 API 使用和搭建 WebUI 界面

ChatTTS&#xff08;Chat Text To Speech&#xff09;&#xff0c;專為對話場景設計的文本生成語音(TTS)模型&#xff0c;適用于大型語言模型(LLM)助手的對話任務&#xff0c;以及諸如對話式音頻和視頻介紹等應用。支持中文和英文&#xff0c;還可以穿插笑聲、說話間的停頓、以…

鏈表相關知識總結

1、數據結構 基本概念&#xff1a; 數據項&#xff1a;一個數據元素可以由若干個數據項組成數據對象&#xff1a;有相同性質的數據元素的集合&#xff0c;是數據的子集數據結構&#xff1a;是相互之間存在一種或多種特定關系的數據元素的集合 邏輯結構和物理結構&#xff1a…

藍橋杯備考-》單詞接龍

很明顯&#xff0c;這道題是可以用DFS來做的&#xff0c;我們直接暴力搜索&#xff0c;但是這里有很多點是我們需要注意的。 1.我們如何確定兩個單詞能接上&#xff1f; 比如touch和choose 應該合成為touchoose 就是這樣兩個單詞&#xff0c;我們讓一個指針指著第一個字符串…

C語言-訪問者模式詳解與實踐

C語言訪問者模式詳解與實踐 - 傳感器數據處理系統 1. 什么是訪問者模式&#xff1f; 在嵌入式系統中&#xff0c;我們經常需要對不同傳感器的數據進行多種處理&#xff0c;如數據校準、過濾、存儲等。訪問者模式允許我們在不修改傳感器代碼的情況下&#xff0c;添加新的數據處…

(UI自動化測試web端)第二篇:元素定位的方法_xpath路徑定位

1、第一種xpath路徑定位&#xff1a; 絕對路徑&#xff1a;表達式是以 /html開頭&#xff0c;元素的層級之間是以 / 分隔相同層級的元素可以使用下標&#xff0c;下標是從1開始的需要列出元素所經過的所有層級元素&#xff0c;工作當中一般不使用絕對路徑 例&#xff1a;/html/…

設置GeoJSONVectorTileLayer中的line填充圖片

設置GeoJSONVectorTileLayer中的line填充圖片 關鍵&#xff1a;linePatternFile const style [{filter: true,renderPlugin: {dataConfig: {type: "line",},type: "line",},symbol: {linePatternFile: "http://examples.maptalks.com/resources/pat…

electron框架(4.0)electron-builde和electron Forge的打包方式

----使用electron-builder打包&#xff08;需要魔法&#xff09; --安裝electron-builder: npm install electron-builder -D--package.json中進行相關配置&#xff1a; {"name": "video-tools","version": "1.0.0","main&quo…

讓 MGR 不從 Primary 的節點克隆數據?

問題 MGR 中&#xff0c;新節點在加入時&#xff0c;為了與組內其它節點的數據保持一致&#xff0c;它會首先經歷一個分布式恢復階段。在這個階段&#xff0c;新節點會隨機選擇組內一個節點&#xff08;Donor&#xff09;來同步差異數據。 在 MySQL 8.0.17 之前&#xff0c;同…

第三十二篇 深入解析Kimball維度建模:構建企業級數據倉庫的完整框架

目錄 一、維度建模設計原則深度剖析1.1 業務過程驅動設計1.2 星型模式VS雪花模式 二、維度建模五步法實戰&#xff08;附完整案例&#xff09;2.1 業務需求映射2.2 模型詳細設計2.3 緩慢變化維處理 三、高級建模技術解析3.1 漸變維度橋接表3.2 快照事實表設計 四、性能優化體系…