c语言中dfs用pos做参数,LeetCode算法练习——深度优先搜索 DFS(2)
更多干貨就在我的個(gè)人博客 BlackBlog.tech 歡迎關(guān)注!
也可以關(guān)注我的csdn博客:黑哥的博客
謝謝大家!
我們繼續(xù)LeetCode之旅.
做了一段時(shí)間的LeetCode,感覺(jué)還是不錯(cuò)的。算法很基礎(chǔ),沒(méi)有特別難的(至少我看在做的),很適合考試,面試,就業(yè)之前的訓(xùn)練。對(duì)提升基本功很有幫助,我覺(jué)得如果有時(shí)間的話,每天都做上幾道,日積月累,代碼能力必然有提高。
這一篇繼續(xù)進(jìn)行DFS的練習(xí),預(yù)計(jì)還會(huì)有十道題。
給個(gè)目錄:
LeetCode109 有序鏈表轉(zhuǎn)換二叉搜索樹(shù)
LeetCode332 重新安排行程
LeetCode337 打家劫舍 III
LeetCode394 字符串解碼
LeetCode417 太平洋大西洋水流問(wèn)題
LeetCode473 火柴拼正方形
LeetCode494 目標(biāo)和
LeetCode491 遞增子序列
LeetCode515 在每個(gè)樹(shù)行中找最大值
LeetCode513 找樹(shù)左下角的值
LeetCode109 有序鏈表轉(zhuǎn)換二叉搜索樹(shù)
題目
給定一個(gè)單鏈表,其中的元素按升序排序,將其轉(zhuǎn)換為高度平衡的二叉搜索樹(shù)。
本題中,一個(gè)高度平衡二叉樹(shù)是指一個(gè)二叉樹(shù)每個(gè)節(jié)點(diǎn) 的左右兩個(gè)子樹(shù)的高度差的絕對(duì)值不超過(guò) 1。
示例:
給定的有序鏈表: [-10, -3, 0, 5, 9],
一個(gè)可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面這個(gè)高度平衡二叉搜索樹(shù):
0
/ \
-3 9
/ /
-10 5
C++代碼
class Solution {
public:
bool isValidBST(TreeNode* root) {
return dfs(root,LONG_MAX,LONG_MIN);
}
bool dfs(TreeNode* root, long max,long min){
if(!root) return true;
if(root->val<=min || root->val>=max) return false;
else return (dfs(root->left,root->val,min) && dfs(root->right,max,root->val));
}
};
體會(huì)
這個(gè)題利用了二叉檢索樹(shù)自身的性質(zhì),左邊節(jié)點(diǎn)小于根節(jié)點(diǎn),右邊節(jié)點(diǎn)大于根節(jié)點(diǎn)。初始化時(shí)帶入系統(tǒng)最大值和最小值,在遞歸過(guò)程中換成它們自己的節(jié)點(diǎn)值,用long代替int就是為了包括int的邊界條件。
如果這棵樹(shù)遍歷到了葉節(jié)點(diǎn),則返回true。如果在遍歷的過(guò)程中出現(xiàn)了當(dāng)前節(jié)點(diǎn)大于等于父節(jié)點(diǎn)(左子樹(shù))或小于等于父節(jié)點(diǎn)(右子樹(shù))則返回false。對(duì)結(jié)果做&&運(yùn)算。返回最終的結(jié)果。
LeetCode332 重新安排行程
題目
給定一個(gè)機(jī)票的字符串二維數(shù)組 [from, to],子數(shù)組中的兩個(gè)成員分別表示飛機(jī)出發(fā)和降落的機(jī)場(chǎng)地點(diǎn),對(duì)該行程進(jìn)行重新規(guī)劃排序。所有這些機(jī)票都屬于一個(gè)從JFK(肯尼迪國(guó)際機(jī)場(chǎng))出發(fā)的先生,所以該行程必須從 JFK 出發(fā)。
說(shuō)明:
如果存在多種有效的行程,你可以按字符自然排序返回最小的行程組合。例如,行程 ["JFK", "LGA"] 與 ["JFK", "LGB"] 相比就更小,排序更靠前
所有的機(jī)場(chǎng)都用三個(gè)大寫(xiě)字母表示(機(jī)場(chǎng)代碼)。
假定所有機(jī)票至少存在一種合理的行程
示例 1:
tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
返回["JFK", "MUC", "LHR", "SFO", "SJC"]
示例 2:
tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
返回["JFK","ATL","JFK","SFO","ATL","SFO"]
另一種有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"]。但是它自然排序更大更靠后。
C++代碼
class Solution {
public:
unordered_map> hash; //用來(lái)存儲(chǔ)起點(diǎn)與終點(diǎn)的信息
vector res; //最終的路徑結(jié)果
vector findItinerary(vector> tickets) {
if(tickets.size()==0) return {}; //如果輸入為空 返回空
for (int i=0;i
hash[tickets[i].first].insert(tickets[i].second); //將ticket轉(zhuǎn)化為hash
}
dfs("JFK"); //dfs
reverse(res.begin(), res.end()); //因?yàn)樽罱K得到的結(jié)果是一個(gè)反序列的 我們要返回來(lái)
return res;
}
void dfs(string from){
while(hash[from].size()>0){ //如果當(dāng)前起點(diǎn)還有終點(diǎn)沒(méi)有去過(guò)的話
string tem = *hash[from].begin(); //記錄下當(dāng)前起點(diǎn)去往的第一個(gè)終點(diǎn)
hash[from].erase(hash[from].begin()); //將第一個(gè)終點(diǎn)從hash中刪除
dfs(tem); //繼續(xù)dfs
}
res.push_back(from); //將當(dāng)前的出發(fā)點(diǎn)加入res
}
};
體會(huì)
題目看起來(lái)并沒(méi)有什么難度。DFS+回溯,但我覺(jué)得有坑。。。
第一次寫(xiě),寫(xiě)的這個(gè)代碼,所有樣例測(cè)試完全正確。
class Solution {
private:
vector res;
public:
vector findItinerary(vector> tickets) {
vector path;
vector mark;
for(int i=0;i
mark.push_back(0);
path.push_back("JFK");
dfs(tickets,mark,path,"JFK");
tickets.clear();
path.clear();
mark.clear();
return res;
}
void dfs(vector> tickets, vector mark, vector path, string from){
int flag = true;
for(int i=0;i
if(mark[i]==0) flag=false;
}
if(flag == true){
res = path;
return;
}
for(int i=0;i
if(tickets[i].first==from && mark[i]==0){
path.push_back(tickets[i].second);
mark[i] = 1;
dfs(tickets,mark,path,tickets[i].second);
mark[i]=0;
path.pop_back();
}
}
return;
}
};
可是,每次提交都會(huì)報(bào)一個(gè)錯(cuò)誤,本地調(diào)試也沒(méi)有問(wèn)題。就很迷。
換了思路重新寫(xiě)。
各位有興趣麻煩幫我檢查一下代碼。
另外,此題少給出了一個(gè)條件。就是默認(rèn)輸出最長(zhǎng)的路徑,路徑長(zhǎng)度相同時(shí),再以字典序列輸出。
LeetCode337 打家劫舍 III
題目
小偷又發(fā)現(xiàn)一個(gè)新的可行竊的地點(diǎn)。 這個(gè)地區(qū)只有一個(gè)入口,稱為“根”。 除了根部之外,每棟房子有且只有一個(gè)父房子。 一番偵察之后,聰明的小偷意識(shí)到“這個(gè)地方的所有房屋形成了一棵二叉樹(shù)”。 如果兩個(gè)直接相連的房子在同一天晚上被打劫,房屋將自動(dòng)報(bào)警。
在不觸動(dòng)警報(bào)的情況下,計(jì)算小偷一晚能盜取的最高金額。
示例 1:
3
/ \
2 3
\ \
3 1
能盜取的最高金額 = 3 + 3 + 1 = 7.
示例 2:
3
/ \
4 5
/ \ \
1 3 1
能盜取的最高金額 = 4 + 5 = 9.
C++代碼
class Solution {
public:
//偷 對(duì)第一個(gè)根節(jié)點(diǎn) 采取偷與不偷的方式 最后求最大值
int rob(TreeNode* root) {
if(!root) return 0;
return std::max(robRoot(root),notRobRoot(root));
}
//偷根節(jié)點(diǎn)的情況 就不能偷兩個(gè)子節(jié)點(diǎn)
int robRoot(TreeNode *root){
if(!root) return 0;
return notRobRoot(root->left) +notRobRoot(root->right)+root->val;
}
//不偷根節(jié)點(diǎn)的情況 可以偷兩個(gè)子節(jié)點(diǎn) 但不一定就要偷
int notRobRoot(TreeNode *root){
if(!root) return 0;
return rob(root->left) + rob(root->right);
}
};
體會(huì)
這個(gè)題屬于思路很清晰就很簡(jiǎn)單的題。
首先我們來(lái)分析題目,題目中說(shuō)如果兩個(gè)節(jié)點(diǎn)連在一起,那么偷東西就會(huì)被發(fā)現(xiàn)。所有只要我們偷東西的節(jié)點(diǎn)不連在一起就沒(méi)有問(wèn)題。連在一起的情況只有根節(jié)點(diǎn)與子節(jié)點(diǎn)。
對(duì)于一個(gè)根節(jié)點(diǎn)分為偷與不偷兩種情況,如果偷的話,那么他的子節(jié)點(diǎn)就不能偷;如果不偷的話,可以偷他的子節(jié)點(diǎn),也可以不偷,根據(jù)偷到的金額去做判斷。對(duì)于每個(gè)根節(jié)點(diǎn),我們要把這兩周情況都考慮上,代碼如上。
LeetCode394 字符串解碼
題目
給定一個(gè)經(jīng)過(guò)編碼的字符串,返回它解碼后的字符串。
編碼規(guī)則為: k[encoded_string],表示其中方括號(hào)內(nèi)部的 encoded_string 正好重復(fù) k 次。注意 k 保證為正整數(shù)。
你可以認(rèn)為輸入字符串總是有效的;輸入字符串中沒(méi)有額外的空格,且輸入的方括號(hào)總是符合格式要求的。
此外,你可以認(rèn)為原始數(shù)據(jù)不包含數(shù)字,所有的數(shù)字只表示重復(fù)的次數(shù) k ,例如不會(huì)出現(xiàn)像 3a 或 2[4] 的輸入。
示例:
s = "3[a]2[bc]", 返回 "aaabcbc".
s = "3[a2[c]]", 返回 "accaccacc".
s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
C++代碼
class Solution {
public:
string decodeString(string s) {
dfs(s);
return s;
}
void dfs(string &s){
int l=0,r=0; //方括號(hào)的左起點(diǎn) 右起點(diǎn)
string num_s=""; //存儲(chǔ)數(shù)字的部分
int num_len =0; //數(shù)字的長(zhǎng)度
int num; //數(shù)字本身
//遍歷找方括號(hào)
for(int i=0;i
if(s[i]=='[') { //如果是左括號(hào)
l = i; //記錄位置
num = atoi(num_s.data()); //將之前存儲(chǔ)的num轉(zhuǎn)換為數(shù)字
num_len=num_s.size(); //得到數(shù)字的長(zhǎng)度 用于后面裁切字符串
num_s.clear(); //清空 方式影響后面內(nèi)容
}
else if(s[i]==']') {
r = i; //記錄右括號(hào)位置
break; //結(jié)束循環(huán)
}
else if(s[i]<='9' && s[i]>='0') num_s+=s[i]; //記錄每一位的數(shù)字
}
if(l>=r) return ; //結(jié)束條件
string newstr=""; //預(yù)備重復(fù)的部分字符串
for(int i=0;i
newstr+=s.substr(l+1,r-l-1); //重復(fù)字符串
s = s.substr(0,l-num_len)+newstr+s.substr(r+1,s.length()-r-1); //制作新的字符串
dfs(s);//遞歸調(diào)用
}
};
體會(huì)
算是一道完全的模擬題。
我用的思路比較簡(jiǎn)單,每次都只處理最里面的一個(gè)[],將其中的內(nèi)容重復(fù)。逐次遞歸調(diào)用,最后解析完所有的字符串。注意s = s.substr(0,l-num_len)+newstr+s.substr(r+1,s.length()-r-1);各個(gè)字符串的起始位置和裁切長(zhǎng)度。
LeetCode417 太平洋大西洋水流問(wèn)題
題目
給定一個(gè) m x n 的非負(fù)整數(shù)矩陣來(lái)表示一片大陸上各個(gè)單元格的高度。“太平洋”處于大陸的左邊界和上邊界,而“大西洋”處于大陸的右邊界和下邊界。
規(guī)定水流只能按照上、下、左、右四個(gè)方向流動(dòng),且只能從高到低或者在同等高度上流動(dòng)。
請(qǐng)找出那些水流既可以流動(dòng)到“太平洋”,又能流動(dòng)到“大西洋”的陸地單元的坐標(biāo)。
提示:
輸出坐標(biāo)的順序不重要
m 和 n 都小于150
示例:
給定下面的 5x5 矩陣:
太平洋 ~ ~ ~ ~ ~
~ 1 2 2 3 (5) *
~ 3 2 3 (4) (4) *
~ 2 4 (5) 3 1 *
~ (6) (7) 1 4 5 *
~ (5) 1 1 2 4 *
* * * * * 大西洋
返回:
[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上圖中帶括號(hào)的單元).
C++代碼
class Solution {
public:
vector> pacificAtlantic(vector>& matrix) {
if (matrix.empty() || matrix[0].empty()) return {};
int m = matrix.size(); //矩陣行數(shù)
int n = matrix[0].size(); //矩陣列數(shù)
vector> res; //最終結(jié)果
vector> pacific(m, vector(n, false)); //太平洋
vector> atlantic(m, vector(n, false)); //大西洋
//遍歷第一行,最底下一行
for(int i=0;i
dfs(matrix,pacific,i,0,matrix[i][0]);
dfs(matrix,atlantic,i,n-1,matrix[i][n-1]);
}
//遍歷第一列,最右邊一列
for(int i=0;i
dfs(matrix,pacific,0,i,matrix[0][i]);
dfs(matrix,atlantic,m-1,i,matrix[m-1][i]);
}
//將pacific與atlantic重合的部分 作為最終結(jié)果
for(int i=0;i
for(int j=0;j
if(atlantic[i][j] && pacific[i][j])
res.push_back(make_pair(i,j));
}
}
return res;
}
void dfs(vector>& matrix,vector> &visited,int x,int y,int val){
//越界 被訪問(wèn) 或者 當(dāng)前值小于上一個(gè)值的都直接返回
if (x<0 || x>matrix.size()-1 || y<0 || y>matrix[0].size()-1 || visited[x][y] || matrix[x][y] < val) return;
//將該坐標(biāo)設(shè)置為訪問(wèn)過(guò)
visited[x][y] = true;
dfs(matrix,visited,x+1,y,matrix[x][y]);
dfs(matrix,visited,x-1,y,matrix[x][y]);
dfs(matrix,visited,x,y+1,matrix[x][y]);
dfs(matrix,visited,x,y-1,matrix[x][y]);
}
};
體會(huì)
這個(gè)題第一眼看到覺(jué)得是一個(gè)很簡(jiǎn)單DFS搜索題。第一個(gè)想法肯定是對(duì)每一個(gè)點(diǎn)進(jìn)行dfs,看他是否能夠走到太平洋或者大西洋。顯然這樣,時(shí)間復(fù)雜度會(huì)很高。我們可以對(duì)其優(yōu)化,每一次得到一條路徑后,將路徑上的所有點(diǎn)都記錄下來(lái),這樣可以減少很多次dfs的過(guò)程,但優(yōu)化效果不明顯。
這個(gè)題,我們采用倒推法的思路。從大西洋、太平洋向內(nèi)搜索,每次找比當(dāng)前節(jié)點(diǎn)高的或者相同的節(jié)點(diǎn),將這些節(jié)點(diǎn)設(shè)置為T(mén)rue。最終將大西洋中為T(mén)rue的,太平洋中也為T(mén)rue的節(jié)點(diǎn)作為最終的答案。
LeetCode473 火柴拼正方形
題目
還記得童話《賣火柴的小女孩》嗎?現(xiàn)在,你知道小女孩有多少根火柴,請(qǐng)找出一種能使用所有火柴拼成一個(gè)正方形的方法。不能折斷火柴,可以把火柴連接起來(lái),并且每根火柴都要用到。
輸入為小女孩擁有火柴的數(shù)目,每根火柴用其長(zhǎng)度表示。輸出即為是否能用所有的火柴拼成正方形。
示例 1:
輸入: [1,1,2,2,2]
輸出: true
解釋: 能拼成一個(gè)邊長(zhǎng)為2的正方形,每邊兩根火柴。
示例 2:
輸入: [3,3,3,3,4]
輸出: false
解釋: 不能用所有火柴拼成一個(gè)正方形。
注意:
給定的火柴長(zhǎng)度和在 0 到 10^9之間。
火柴數(shù)組的長(zhǎng)度不超過(guò)15。
C++代碼
class Solution {
public:
bool makesquare(vector& nums) {
if(nums.size()<4 || nums.size()==0) return false; //如果數(shù)組的大小不滿足4 就直接返回0
int sum = accumulate(nums.begin(),nums.end(),0); //對(duì)整個(gè)數(shù)組進(jìn)行求和
int target = sum /4 ; //計(jì)算每一條邊需要的長(zhǎng)度
vector sums(4,0); //新建一個(gè)長(zhǎng)度為4的數(shù)組,用來(lái)記錄每一個(gè)邊當(dāng)前的長(zhǎng)度
sort(nums.rbegin(),nums.rend()); //對(duì)數(shù)組進(jìn)行排序,先計(jì)算大的,這樣可以優(yōu)化不少效率
bool res = dfs(nums,sums,0,target); // dfs
return res;
}
bool dfs(vector& nums,vector sums, int pos, int target){
if(pos>nums.size()-1){ //如果pos>nums.size()-1證明數(shù)組已經(jīng)被遍歷完,判斷當(dāng)前所有的邊是否都滿足要求
return sums[0]==target && sums[1]==target && sums[2]==target && sums[3]==target;
}
//對(duì)每一條邊進(jìn)行嘗試
for(int i=0;i<4;i++){
if(sums[i]+nums[pos]>target) continue; //如果i邊 放入一個(gè)數(shù)字后,超過(guò)target則不放入,進(jìn)入下一條邊
sums[i]+=nums[pos]; //i邊 長(zhǎng)度增加
if(dfs(nums,sums,pos+1,target)) return true; //pos+1 繼續(xù)dfs
sums[i]-=nums[pos]; //回溯
}
return false;
}
};
體會(huì)
這個(gè)題是一個(gè)比較標(biāo)準(zhǔn)DFS+回溯題。這問(wèn)題可以理解為,一個(gè)數(shù)組如何分為四個(gè)相同的數(shù)。我們創(chuàng)建一個(gè)數(shù)組,長(zhǎng)度為四,用來(lái)表明四條邊當(dāng)前的長(zhǎng)度,每次遍歷時(shí)將當(dāng)前的長(zhǎng)度與待放入長(zhǎng)度相加后target進(jìn)行比較。大于,則不放入,小于,則放入,不斷dfs,每次pos+1。當(dāng)pos超出范圍時(shí),證明所有的數(shù)字都被嘗試過(guò),返回當(dāng)前的狀態(tài)。
LeetCode494 目標(biāo)和
題目
給定一個(gè)非負(fù)整數(shù)數(shù)組,a1, a2, ..., an, 和一個(gè)目標(biāo)數(shù),S。現(xiàn)在你有兩個(gè)符號(hào) + 和 -。對(duì)于數(shù)組中的任意一個(gè)整數(shù),你都可以從 + 或 -中選擇一個(gè)符號(hào)添加在前面。
返回可以使最終數(shù)組和為目標(biāo)數(shù) S 的所有添加符號(hào)的方法數(shù)。
示例 1:
輸入: nums: [1, 1, 1, 1, 1], S: 3
輸出: 5
解釋:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
一共有5種方法讓最終目標(biāo)和為3。
注意:
數(shù)組的長(zhǎng)度不會(huì)超過(guò)20,并且數(shù)組中的值全為正數(shù)。
初始的數(shù)組的和不會(huì)超過(guò)1000。
保證返回的最終結(jié)果為32位整數(shù)。
C++代碼
class Solution {
public:
int solution =0; //方案數(shù)
int findTargetSumWays(vector& nums, int S) {
int sum = 0;
dfs(nums,S,0,sum);
return solution;
}
void dfs(vector& nums,int S,int pos,int sum){
//S表示最后結(jié)果,pos表示當(dāng)前位置,sum表示目前總和
if(pos>nums.size()-1) {
if(sum == S) solution+=1; //如果當(dāng)前sum==S 方案數(shù)+1
return ;
}
sum += nums[pos]; //先嘗試+
dfs(nums,S,pos+1,sum); //dfs
sum -= nums[pos]; //回溯
sum -= nums[pos]; //嘗試-
dfs(nums,S,pos+1,sum); //dfs
sum += nums[pos]; //回溯
return ;
}
};
體會(huì)
一道非常清晰的DFS+回溯題,我覺(jué)得都可以做標(biāo)準(zhǔn)模版了。S表示最后結(jié)果,pos表示當(dāng)前位置,sum表示目前總和,solution表示方案數(shù)。dfs中先嘗試+,回溯后,嘗試-。當(dāng)sum == S時(shí),方案數(shù)+1。最終返回方案數(shù)。
LeetCode491 遞增子序列
題目
給定一個(gè)整型數(shù)組, 你的任務(wù)是找到所有該數(shù)組的遞增子序列,遞增子序列的長(zhǎng)度至少是2。
示例:
輸入: [4, 6, 7, 7]
輸出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
說(shuō)明:
給定數(shù)組的長(zhǎng)度不會(huì)超過(guò)15。
數(shù)組中的整數(shù)范圍是 [-100,100]。
給定數(shù)組中可能包含重復(fù)數(shù)字,相等的數(shù)字應(yīng)該被視為遞增的一種情況。
C++代碼
class Solution {
public:
set> res; //使用set 實(shí)現(xiàn)去除重復(fù)的功能
vector> findSubsequences(vector& nums) {
vector> ans; //最終結(jié)果
vector path; //每一次遍歷的路徑
//對(duì)數(shù)組中的每一個(gè)元素都要dfs
for(int i=0;i
dfs(nums,path,i);
}
//將set中的數(shù)據(jù)轉(zhuǎn)換到vector
set>::iterator it; //迭代器
for(it=res.begin();it!=res.end();it++){
ans.push_back(*it);
}
return ans;
}
void dfs(vector nums,vector path,int pos){
//如果path的大小為0,則證明這是第一個(gè)數(shù)據(jù),直接放入
if(path.size()==0) path.push_back(nums[pos]);
//向后遍歷,逐個(gè)添加
for(int i=1;i
//如果待添加的值小于path的最后一個(gè)值 不添加,如果 當(dāng)前的位置大于數(shù)組長(zhǎng)度 證明 nums已經(jīng)遍歷完 此時(shí)continue其實(shí)就是return了
if(nums[pos+i]nums.size()-1)) continue;
path.push_back(nums[pos+i]);//path放入新數(shù)據(jù)
res.insert(path); //將path添加進(jìn)set
dfs(nums, path, pos + i); //對(duì)新的數(shù)據(jù)再進(jìn)行dfs
path.pop_back(); //回溯
}
}
};
體會(huì)
求一個(gè)序列中的所有遞增子序列。首先區(qū)分一下子序列與子串,子序列中的數(shù)字不需要是連續(xù)的,子串的數(shù)字是連續(xù)的。因?yàn)閿?shù)據(jù)中不能有重復(fù),我們使用set來(lái)達(dá)到這一效果。dfs內(nèi)部,path表示當(dāng)前的路徑,pos表示當(dāng)前的位置。思路很清晰,我們從當(dāng)前數(shù)據(jù)開(kāi)始,對(duì)其后面的每一個(gè)數(shù)據(jù)做插入操作后,繼續(xù)dfs,知道完成整個(gè)序列。注意回溯。
LeetCode515 在每個(gè)樹(shù)行中找最大值
題目
您需要在二叉樹(shù)的每一行中找到最大的值。
示例:
輸入:
1
/ \
3 2
/ \ \
5 3 9
輸出: [1, 3, 9]
C++代碼
class Solution {
public:
map> hash; //key為樹(shù)的深度 vector存放該層的數(shù)據(jù)
vector largestValues(TreeNode* root) {
dfs(root,0);
vector res;
for(auto key : hash){
res.push_back(*max_element(key.second.begin(),key.second.end())); //將每一行的最大值存在res中
}
return res;
}
void dfs(TreeNode* root,int depth){
if(!root) return;
hash[depth].push_back(root->val); //將當(dāng)前節(jié)點(diǎn)存在hash中對(duì)應(yīng)層的數(shù)組中
if(root->left) dfs(root->left,depth+1); //遍歷左孩子
if(root->right) dfs(root->right,depth+1); //遍歷右孩子
}
};
體會(huì)
思路很清晰,map的key表示第幾層,value表示對(duì)應(yīng)的節(jié)點(diǎn)。我們使用DFS的方法遍歷整個(gè)樹(shù)。遍歷的過(guò)程中,記錄下每一個(gè)節(jié)點(diǎn)的深度,將每一層的節(jié)點(diǎn)都存在map中對(duì)應(yīng)數(shù)組中。最后將每一層最大的數(shù)據(jù)存儲(chǔ)來(lái)即可。
LeetCode513 找樹(shù)左下角的值
題目
給定一個(gè)二叉樹(shù),在樹(shù)的最后一行找到最左邊的值。
示例 1:
輸入:
2
/ \
1 3
輸出:
1
示例 2:
輸入:
1
/ \
2 3
/ / \
4 5 6
/
7
輸出:
7
C++代碼
class Solution {
public:
map> hash;
int max_depth = INT_MIN; //初始化最大深度為一個(gè)極小值
int findBottomLeftValue(TreeNode* root) {
dfs(root,0); //從根節(jié)點(diǎn)開(kāi)始dfs
return hash[max_depth][0]; //將最底下一層最左邊的元素返回出來(lái)
}
void dfs(TreeNode* root,int depth){
if(!root) { // 如果是葉節(jié)點(diǎn)下面的節(jié)點(diǎn) 對(duì)最大深度作出修改
if(depth-1>max_depth) max_depth=depth-1;
return;
}
hash[depth].push_back(root->val); //將對(duì)應(yīng)層的節(jié)點(diǎn)依次放入
dfs(root->left,depth+1); //dfs左子樹(shù)
dfs(root->right,depth+1); //dfs右子樹(shù)
}
};
體會(huì)
這個(gè)題跟上一個(gè)題的思路完全一致,沒(méi)有任何區(qū)別。唯一的不同就在于我們這一次不需要將一行中的最大值求出來(lái),我們只需要返回最左邊的那個(gè)值就可以了。
總結(jié)
以上是生活随笔為你收集整理的c语言中dfs用pos做参数,LeetCode算法练习——深度优先搜索 DFS(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c语言sort函数排序二维数组,c++
- 下一篇: C语言循环结构素数判断,C语言实验之判断