日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

leetcode阶段总结——拓扑排序

發(fā)布時(shí)間:2024/3/12 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 leetcode阶段总结——拓扑排序 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

leetcode階段總結(jié)——拓?fù)渑判?/strong>
?

leetcode中經(jīng)常出現(xiàn)的題型之一。其中,拓?fù)渑判虻母拍羁梢詤⒖歼@里,這里主要總結(jié)一下前300題中出現(xiàn)的幾個(gè)關(guān)于拓?fù)渑判虻念},以待之后復(fù)習(xí)的時(shí)候查找。

leetcode207 課程表

??? 現(xiàn)在你總共有 n 門課需要選,記為 0 到 n-1。
??? 在選修某些課程之前需要一些先修課程。 例如,想要學(xué)習(xí)課程 0 ,你需要先完成課程 1 ,我們用一個(gè)匹配來表示他們: [0,1]
??? 給定課程總量以及它們的先決條件,判斷是否可能完成所有課程的學(xué)習(xí)?

??? 示例 1:

??????? 輸入: 2, [[1,0]]
??????? 輸出: true
??????? 解釋: 總共有 2 門課程。學(xué)習(xí)課程 1 之前,你需要完成課程 0。所以這是可能的。

??? 示例 2:

??????? 輸入: 2, [[1,0],[0,1]]
??????? 輸出: false
??????? 解釋: 總共有 2 門課程。學(xué)習(xí)課程 1 之前,你需要先完成?課程 0;并且學(xué)習(xí)課程 0 之前,你還應(yīng)先完成課程 1。這是不可能的。

??? 說明:

??????? 輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請(qǐng)參見圖的表示法。
??????? 你可以假定輸入的先決條件中沒有重復(fù)的邊。

??? 提示:

??????? 這個(gè)問題相當(dāng)于查找一個(gè)循環(huán)是否存在于有向圖中。如果存在循環(huán),則不存在拓?fù)渑判?#xff0c;因此不可能選取所有課程進(jìn)行學(xué)習(xí)。
??????? 通過 DFS 進(jìn)行拓?fù)渑判?- 一個(gè)關(guān)于Coursera的精彩視頻教程(21分鐘),介紹拓?fù)渑判虻幕靖拍睢?br /> ??????? ?
??????

本題是一道經(jīng)典的「拓?fù)渑判颉箚栴}。

給定一個(gè)包含 nnn 個(gè)節(jié)點(diǎn)的有向圖 GGG,我們給出它的節(jié)點(diǎn)編號(hào)的一種排列,如果滿足:

??? 對(duì)于圖 GGG 中的任意一條有向邊 (u,v)(u, v)(u,v),uuu 在排列中都出現(xiàn)在 vvv 的前面。

那么稱該排列是圖 GGG 的「拓?fù)渑判颉?。根?jù)上述的定義,我們可以得出兩個(gè)結(jié)論:

??? 如果圖 GGG 中存在環(huán)(即圖 GGG 不是「有向無環(huán)圖」),那么圖 GGG 不存在拓?fù)渑判?。這是因?yàn)榧僭O(shè)圖中存在環(huán) x1,x2,? ,xn,x1x_1, x_2, \cdots, x_n, x_1x1?,x2?,?,xn?,x1?,那么 x1x_1x1? 在排列中必須出現(xiàn)在 xnx_nxn? 的前面,但 xnx_nxn? 同時(shí)也必須出現(xiàn)在 x1x_1x1? 的前面,因此不存在一個(gè)滿足要求的排列,也就不存在拓?fù)渑判?#xff1b;

??? 如果圖 GGG 是有向無環(huán)圖,那么它的拓?fù)渑判蚩赡懿恢挂环N。舉一個(gè)最極端的例子,如果圖 GGG 值包含 nnn 個(gè)節(jié)點(diǎn)卻沒有任何邊,那么任意一種編號(hào)的排列都可以作為拓?fù)渑判颉?/p>

有了上述的簡(jiǎn)單分析,我們就可以將本題建模成一個(gè)求拓?fù)渑判虻膯栴}了:

??? 我們將每一門課看成一個(gè)節(jié)點(diǎn);

??? 如果想要學(xué)習(xí)課程 AAA 之前必須完成課程 BBB,那么我們從 BBB 到 AAA 連接一條有向邊。這樣以來,在拓?fù)渑判蛑?#xff0c;BBB 一定出現(xiàn)在 AAA 的前面。

求出該圖是否存在拓?fù)渑判?#xff0c;就可以判斷是否有一種符合要求的課程學(xué)習(xí)順序。事實(shí)上,由于求出一種拓?fù)渑判蚍椒ǖ淖顑?yōu)時(shí)間復(fù)雜度為 O(n+m)O(n+m)O(n+m),其中 nnn 和 mmm 分別是有向圖 GGG 的節(jié)點(diǎn)數(shù)和邊數(shù),方法見 210. 課程表 II 的官方題解。而判斷圖 GGG 是否存在拓?fù)渑判?#xff0c;至少也要對(duì)其進(jìn)行一次完整的遍歷,時(shí)間復(fù)雜度也為 O(n+m)O(n+m)O(n+m)。因此不可能存在一種僅判斷圖是否存在拓?fù)渑判虻姆椒?#xff0c;它的時(shí)間復(fù)雜度在漸進(jìn)意義上嚴(yán)格優(yōu)于 O(n+m)O(n+m)O(n+m)。這樣一來,我們使用和 210. 課程表 II 完全相同的方法,但無需使用數(shù)據(jù)結(jié)構(gòu)記錄實(shí)際的拓?fù)渑判颉榱藬⑹龅耐暾?#xff0c;下面的兩種方法與 210. 課程表 II 的官方題解 完全相同,但在「算法」部分后的「優(yōu)化」部分說明了如何省去對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)。
方法一:深度優(yōu)先搜索

思路

我們可以將深度優(yōu)先搜索的流程與拓?fù)渑判虻那蠼饴?lián)系起來,用一個(gè)棧來存儲(chǔ)所有已經(jīng)搜索完成的節(jié)點(diǎn)。

??? 對(duì)于一個(gè)節(jié)點(diǎn) uuu,如果它的所有相鄰節(jié)點(diǎn)都已經(jīng)搜索完成,那么在搜索回溯到 uuu 的時(shí)候,uuu 本身也會(huì)變成一個(gè)已經(jīng)搜索完成的節(jié)點(diǎn)。這里的「相鄰節(jié)點(diǎn)」指的是從 uuu 出發(fā)通過一條有向邊可以到達(dá)的所有節(jié)點(diǎn)。

假設(shè)我們當(dāng)前搜索到了節(jié)點(diǎn) uuu,如果它的所有相鄰節(jié)點(diǎn)都已經(jīng)搜索完成,那么這些節(jié)點(diǎn)都已經(jīng)在棧中了,此時(shí)我們就可以把 uuu 入棧??梢园l(fā)現(xiàn),如果我們從棧頂往棧底的順序看,由于 uuu 處于棧頂?shù)奈恢?#xff0c;那么 uuu 出現(xiàn)在所有 uuu 的相鄰節(jié)點(diǎn)的前面。因此對(duì)于 uuu 這個(gè)節(jié)點(diǎn)而言,它是滿足拓?fù)渑判虻囊蟮摹?/p>

這樣以來,我們對(duì)圖進(jìn)行一遍深度優(yōu)先搜索。當(dāng)每個(gè)節(jié)點(diǎn)進(jìn)行回溯的時(shí)候,我們把該節(jié)點(diǎn)放入棧中。最終從棧頂?shù)綏5椎男蛄芯褪且环N拓?fù)渑判颉?/p>

算法

對(duì)于圖中的任意一個(gè)節(jié)點(diǎn),它在搜索的過程中有三種狀態(tài),即:

??? 「未搜索」:我們還沒有搜索到這個(gè)節(jié)點(diǎn);

??? 「搜索中」:我們搜索過這個(gè)節(jié)點(diǎn),但還沒有回溯到該節(jié)點(diǎn),即該節(jié)點(diǎn)還沒有入棧,還有相鄰的節(jié)點(diǎn)沒有搜索完成);

??? 「已完成」:我們搜索過并且回溯過這個(gè)節(jié)點(diǎn),即該節(jié)點(diǎn)已經(jīng)入棧,并且所有該節(jié)點(diǎn)的相鄰節(jié)點(diǎn)都出現(xiàn)在棧的更底部的位置,滿足拓?fù)渑判虻囊蟆?/p>

通過上述的三種狀態(tài),我們就可以給出使用深度優(yōu)先搜索得到拓?fù)渑判虻乃惴鞒?#xff0c;在每一輪的搜索搜索開始時(shí),我們?nèi)稳∫粋€(gè)「未搜索」的節(jié)點(diǎn)開始進(jìn)行深度優(yōu)先搜索。

??? 我們將當(dāng)前搜索的節(jié)點(diǎn) uuu 標(biāo)記為「搜索中」,遍歷該節(jié)點(diǎn)的每一個(gè)相鄰節(jié)點(diǎn) vvv:

??????? 如果 vvv 為「未搜索」,那么我們開始搜索 vvv,待搜索完成回溯到 uuu;

??????? 如果 vvv 為「搜索中」,那么我們就找到了圖中的一個(gè)環(huán),因此是不存在拓?fù)渑判虻?#xff1b;

??????? 如果 vvv 為「已完成」,那么說明 vvv 已經(jīng)在棧中了,而 uuu 還不在棧中,因此 uuu 無論何時(shí)入棧都不會(huì)影響到 (u,v)(u, v)(u,v) 之前的拓?fù)潢P(guān)系,以及不用進(jìn)行任何操作。

??? 當(dāng) uuu 的所有相鄰節(jié)點(diǎn)都為「已完成」時(shí),我們將 uuu 放入棧中,并將其標(biāo)記為「已完成」。

在整個(gè)深度優(yōu)先搜索的過程結(jié)束后,如果我們沒有找到圖中的環(huán),那么棧中存儲(chǔ)這所有的 nnn 個(gè)節(jié)點(diǎn),從棧頂?shù)綏5椎捻樞蚣礊橐环N拓?fù)渑判颉?/p> class Solution {static Map<Integer,List<Integer>> map;static int [] state;public boolean canFinish(int numCourses, int[][] p) {if(p==null){return true;}map=new HashMap<Integer,List<Integer>>();state=new int[numCourses];for(int i=0;i<p.length;i++){if(map.containsKey(p[i][0])){map.get(p[i][0]).add(p[i][1]);}else{List<Integer> list=new ArrayList<Integer>();list.add(p[i][1]);map.put(p[i][0], list);}}for(int i=0;i<p.length;i++){if(state[p[i][0]]==2){continue;}if(!dfs(p[i][0])){return false;}}return true;} public static boolean dfs(Integer i){if(state[i]==2) return true;if(state[i]==1) return false;state[i]=1;if(map.containsKey(i)){List<Integer> list=map.get(i);for(int j:list){if(!dfs(j)){return false;}}}state[i]=2;return true;} }

?

方法二入度表法:

???????

題意解釋

??? 一共有 n 門課要上,編號(hào)為 0 ~ n-1。
??? 先決條件[1, 0],意思是必須先上課 0,才能上課 1。
??? 給你 n 、和一個(gè)先決條件表,請(qǐng)你判斷能否完成所有課程。

再舉個(gè)生活的例子

??? 先穿內(nèi)褲再穿褲子,先穿打底再穿外套,先穿衣服再戴帽子,是約定俗成的。
??? 內(nèi)褲外穿、光著身子戴帽子等,都會(huì)有點(diǎn)奇怪。
??? 我們遵循穿衣的一條條先后規(guī)則,用一串順序行為,把衣服一件件穿上。
??? 我們遵循課程之間的先后規(guī)則,找到一種上課順序,把所有課一節(jié)節(jié)上完。

??? 示例:n = 6,先決條件表:[[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
??? 課 0, 1, 2 沒有先修課,可以直接選。其余的課,都有兩門先修課。
??? 我們用有向圖來展現(xiàn)這種依賴關(guān)系(做事情的先后關(guān)系):
???
??? 這種叫 有向無環(huán)圖,把一個(gè) 有向無環(huán)圖 轉(zhuǎn)成 線性的排序 就叫 拓?fù)渑判颉?br /> ??? 有向圖有 入度 和 出度 的概念:
??????? 如果存在一條有向邊 A --> B,則這條邊給 A 增加了 1 個(gè)出度,給 B 增加了 1 個(gè)入度。
??? 所以,頂點(diǎn) 0、1、2 的入度為 0。頂點(diǎn) 3、4、5 的入度為 2。

每次只能選你能上的課

??? 每次只能選入度為 0 的課,因?yàn)樗灰蕾噭e的課,是當(dāng)下你能上的課。
??? 假設(shè)選了 0,課 3 的先修課少了一門,入度由 2 變 1。
??? 接著選 1,導(dǎo)致課 3 的入度變 0,課 4 的入度由 2 變 1。
??? 接著選 2,導(dǎo)致課 4 的入度變 0。
??? 現(xiàn)在,課 3 和課 4 的入度為 0。繼續(xù)選入度為 0 的課……直到選不到入度為 0 的課。

這很像 BFS

??? 讓入度為 0 的課入列,它們是能直接選的課。
??? 然后逐個(gè)出列,出列代表著課被選,需要減小相關(guān)課的入度。
??? 如果相關(guān)課的入度新變?yōu)?0,安排它入列、再出列……直到?jīng)]有入度為 0 的課可入列。

BFS 前的準(zhǔn)備工作

??? 每門課的入度需要被記錄,我們關(guān)心入度值的變化。
??? 課程之間的依賴關(guān)系也要被記錄,我們關(guān)心選當(dāng)前課會(huì)減小哪些課的入度。
??? 因此我們需要選擇合適的數(shù)據(jù)結(jié)構(gòu),去存這些數(shù)據(jù):
??? 入度數(shù)組:課號(hào) 0 到 n - 1 作為索引,通過遍歷先決條件表求出對(duì)應(yīng)的初始入度。
??? 鄰接表:用哈希表記錄依賴關(guān)系(也可以用二維矩陣,但有點(diǎn)大)
??????? key:課號(hào)
??????? value:依賴這門課的后續(xù)課(數(shù)組)

怎么判斷能否修完所有課?

??? BFS 結(jié)束時(shí),如果仍有課的入度不為 0,無法被選,完成不了所有課。否則,能找到一種順序把所有課上完。
??? 或者:用一個(gè)變量 count 記錄入列的頂點(diǎn)個(gè)數(shù),最后判斷 count 是否等于總課程數(shù)。

代碼

public boolean canFinish(int numCourses, int[][]p ){if(p==null){return true;}int result=0; //記錄節(jié)點(diǎn)被哪些節(jié)點(diǎn)所依賴Map<Integer,List<Integer>> map=new HashMap<Integer,List<Integer>>();int [] indegree=new int[numCourses];for(int i=0;i<p.length;i++){if(map.containsKey(p[i][1])){map.get(p[i][1]).add(p[i][0]);}else{List<Integer> list=new ArrayList<Integer>();list.add(p[i][0]);map.put(p[i][1], list);}indegree[p[i][0]]++;}Queue<Integer> stack=new LinkedList<Integer>();for(int i=0;i<numCourses;i++){if(indegree[i]==0){stack.offer(i);}}while(!stack.isEmpty()){int numZero=stack.poll();result++;if(map.containsKey(numZero)){List<Integer> list=map.get(numZero);for(int num:list){indegree[num]--;if(indegree[num]==0){stack.offer(num);}}}}return result==numCourses;}

?

leetcode210 課程表2

??? 現(xiàn)在你總共有 n 門課需要選,記為 0 到 n-1。
??? 在選修某些課程之前需要一些先修課程。 例如,想要學(xué)習(xí)課程 0 ,你需要先完成課程 1 ,我們用一個(gè)匹配來表示他們: [0,1]
??? 給定課程總量以及它們的先決條件,返回你為了學(xué)完所有課程所安排的學(xué)習(xí)順序。
??? 可能會(huì)有多個(gè)正確的順序,你只要返回一種就可以了。如果不可能完成所有課程,返回一個(gè)空數(shù)組。

??? 示例 1:

??????? 輸入: 2, [[1,0]]
??????? 輸出: [0,1]
??????? 解釋: 總共有 2 門課程。要學(xué)習(xí)課程 1,你需要先完成課程 0。因此,正確的課程順序?yàn)?[0,1] 。

??? 示例 2:

??????? 輸入: 4, [[1,0],[2,0],[3,1],[3,2]]
??????? 輸出: [0,1,2,3] or [0,2,1,3]
??????? 解釋: 總共有 4 門課程。要學(xué)習(xí)課程 3,你應(yīng)該先完成課程 1 和課程 2。并且課程 1 和課程 2 都應(yīng)該排在課程 0 之后。
???????????? 因此,一個(gè)正確的課程順序是 [0,1,2,3] 。另一個(gè)正確的排序是 [0,2,1,3] 。

??? 說明:

??????? 輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請(qǐng)參見圖的表示法。
??????? 你可以假定輸入的先決條件中沒有重復(fù)的邊。

??? 提示:

??????? 這個(gè)問題相當(dāng)于查找一個(gè)循環(huán)是否存在于有向圖中。如果存在循環(huán),則不存在拓?fù)渑判?#xff0c;因此不可能選取所有課程進(jìn)行學(xué)習(xí)。
??????? 通過 DFS 進(jìn)行拓?fù)渑判?- 一個(gè)關(guān)于Coursera的精彩視頻教程(21分鐘),介紹拓?fù)渑判虻幕靖拍睢?br /> ??????? ?
??????? 拓?fù)渑判蛞部梢酝ㄟ^ BFS 完成。

如果我們要返回的不僅僅是排序的可能性,而是排序結(jié)果,應(yīng)該怎么辦?其實(shí)很容易想通,在入度表元素變?yōu)榱?某個(gè)元素的記憶化遞歸完成的時(shí)候,就說明這個(gè)元素已經(jīng)“無牽無掛”,沒有前向節(jié)點(diǎn)或前向節(jié)點(diǎn)已經(jīng)加入排序列表中,可以將這個(gè)元素加入列表中了。如果忘記了思路或是看不懂了,更詳細(xì)的解析也可以看這里,寫的非常清楚。

代碼和之前的基本相同。

入度表法

??? class Solution:
??????? def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
??????????? ##迭代方法
??????????? adjacent = [[] for i in range(numCourses)]
??????????? indegree = [0] * numCourses
??????????? result = []
??????????? for cur,pre in prerequisites:
??????????????? indegree[cur] += 1
??????????????? adjacent[pre].append(cur)
??????????? from collections import deque
??????????? queue = deque()
??????????? for i in range(numCourses):
??????????????? if not indegree[i]:
??????????????????? queue.append(i)
??????????????????? result.append(i)
??????????? while queue:
??????????????? #element = queue.popleft()
??????????????? element = queue.pop()
??????????????? numCourses -= 1
??????????????? for neighbor in adjacent[element]:
??????????????????? indegree[neighbor] -= 1
??????????????????? if not indegree[neighbor]:
??????????????????????? queue.append(neighbor)
??????????????????????? result.append(neighbor)
??????????? #print(result)
??????????? return result if numCourses == 0 else []

遞歸法

??? class Solution:
??????? def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
??????????? def dfs(i):
??????????????? if flag[i] == -1:
??????????????????? return True
??????????????? if flag[i] == 1:
??????????????????? return False
??????????????? flag[i] = 1
??????????????? for neighbor in adjacent[i]:
??????????????????? if not dfs(neighbor):
??????????????????????? return False
??????????????? flag[i] = -1
??????????????? result.append(i)
??????????????? return True
??? ?
??????????? adjacent = [[] for _ in range(numCourses)]
??????????? flag = [0] * numCourses
??????????? result = []
??????????? for cur,pre in prerequisites:
??????????????? adjacent[pre].append(cur)
??????????? for j in range(numCourses):
??????????????? if not dfs(j):
??????????????????? return []
??????????? return result[::-1]

leetcode269 火星詞典

??? 現(xiàn)有一種使用字母的全新語(yǔ)言,這門語(yǔ)言的字母順序與英語(yǔ)順序不同。
??? 假設(shè),您并不知道其中字母之間的先后順序。但是,會(huì)收到詞典中獲得一個(gè) 不為空的 單詞列表。因?yàn)槭菑脑~典中獲得的,所以該單詞列表內(nèi)的單詞已經(jīng) 按這門新語(yǔ)言的字母順序進(jìn)行了排序。
??? 您需要根據(jù)這個(gè)輸入的列表,還原出此語(yǔ)言中已知的字母順序。

??? 示例 1:

??????? 輸入:
??????? [
????????? "wrt",
????????? "wrf",
????????? "er",
????????? "ett",
????????? "rftt"
??????? ]
??????? ?
??????? 輸出: "wertf"

??? 示例 2:

??????? 輸入:
??????? [
????????? "z",
????????? "x"
??????? ]
??????? ?
??????? 輸出: "zx"
??????? ?
??????? 示例 3:

??? 輸入: [ "z", "x", "z" ]

??????? 輸出: ""
??????? ?
??????? 解釋: 此順序是非法的,因此返回 ""。

??? 注意:

??????? 你可以默認(rèn)輸入的全部都是小寫字母
??????? 假如,a 的字母排列順序優(yōu)先于 b,那么在給定的詞典當(dāng)中 a 定先出現(xiàn)在 b 前面
??????? 若給定的順序是不合法的,則返回空字符串即可
??????? 若存在多種可能的合法字母順序,請(qǐng)返回其中任意一種順序即可

從拓?fù)渑判虻慕嵌葋碚f,這個(gè)題其實(shí)不難,難點(diǎn)在于如何將詞典這一問題抽象成拓?fù)渑判?。?shí)際上,輸入所反映的字母的先后順序,也就是計(jì)算圖中節(jié)點(diǎn)的指向順序。

??? from collections import defaultdict, deque
??? class Solution:
??????? def alienOrder(self, words: List[str]) -> str:
??????????? ## 統(tǒng)計(jì)節(jié)點(diǎn)個(gè)數(shù)
??????????? nodes = set("".join(words))
??????????? ## 建立計(jì)算圖
??????????? adjacent = defaultdict(list)
??????????? indegree = dict(zip(list(nodes),[0] * len(nodes)))
??????????? for i in range(len(words) - 1):
??????????????? word1,word2 = words[i],words[i + 1]
??????????????? lenWord = min(len(word1),len(word2))
??????????????? for j in range(lenWord):
??????????????????? if word1[j] != word2[j]:
??????????????????????? adjacent[word1[j]].append(word2[j])
??????????????????????? indegree[word2[j]] += 1
??????????????????????? break
??????????? ## 拓?fù)渑判?br /> ??????????? result = []
??????????? queue = [i for i in indegree if indegree[i] == 0]
??????????? while queue:
??????????????? element = queue.pop()
??????????????? result.append(element)
??????????????? for neighbor in adjacent[element]:
??????????????????? indegree[neighbor] -= 1
??????????????????? if indegree[neighbor] == 0: queue.append(neighbor)
??? ?
??????????? return "".join(result) if len(result) == len(nodes) else ""

在結(jié)果是否有效的判定中,之前的判定條件是numCourses == 0,這里的判斷條件是len(result) == len(nodes),其實(shí)是一樣的,本質(zhì)都是判斷是否所有節(jié)點(diǎn)都被遍歷到。

leetcode261 以圖判樹

??? 給定從 0 到 n-1 標(biāo)號(hào)的 n 個(gè)結(jié)點(diǎn),和一個(gè)無向邊列表(每條邊以結(jié)點(diǎn)對(duì)來表示),請(qǐng)編寫一個(gè)函數(shù)用來判斷這些邊是否能夠形成一個(gè)合法有效的樹結(jié)構(gòu)。

??? 示例 1:

??????? 輸入: n = 5, 邊列表 edges = [[0,1], [0,2], [0,3], [1,4]]
??????? 輸出: true

??? 示例 2:

??????? 輸入: n = 5, 邊列表 edges = [[0,1], [1,2], [2,3], [1,3], [1,4]]
??????? 輸出: false

??? 注意: 你可以假定邊列表 edges 中不會(huì)出現(xiàn)重復(fù)的邊。由于所有的邊是無向邊,邊 [0,1] 和邊 [1,0] 是相同的,因此不會(huì)同時(shí)出現(xiàn)在邊列表 edges 中。

這個(gè)題和前面的問題有一個(gè)不同之處,就是前面的問題中,我們只需要考慮圖是否成環(huán)的問題,所有的點(diǎn)都必然是連通的。而這個(gè)問題中,我們還要考慮是否有不被其他點(diǎn)連通的點(diǎn)存在。

其他的思路幾乎相同,需要注意的就是判斷條件有兩個(gè):1.所有的點(diǎn)都聯(lián)通,這由所有的點(diǎn)都被遍歷過來判斷;2.沒有環(huán),這由邊的計(jì)數(shù)來判斷,和之前的numCourse對(duì)應(yīng)。

??? class Solution:
??????? def validTree(self, n: int, edges: List[List[int]]) -> bool:
??????????? adjacent = [[] for _ in range(n)]
??????????? for x,y in edges:
??????????????? adjacent[x].append(y)
??????????????? adjacent[y].append(x)
??????????? visited = set()
??? ?
??????????? def helper(prev,node):
??????????????? if node in visited: return False
??????????????? visited.add(node)
??????????????? for neighbor in adjacent[node]:
??????????????????? if neighbor == prev: continue
??????????????????? if not helper(node,neighbor): return False
??????????????? return True
??? ?
??????????? return helper(None,0) and len(visited) == n

另一種方法

??? class Solution:
??????? def validTree(self, n: int, edges: List[List[int]]) -> bool:
??????????? ##從一個(gè)點(diǎn)出發(fā),能遍歷所有的點(diǎn),保證的是連通性
??????????? ##無環(huán)性是這樣保證的:從一個(gè)點(diǎn)出發(fā),應(yīng)該只能到達(dá)另一個(gè)點(diǎn)一次
??????????? ##如果不重復(fù)路徑可以到達(dá)兩次,那就是有環(huán)
??????????? ##我們記錄下已經(jīng)遍歷過的點(diǎn),如果有環(huán),那么就會(huì)有已經(jīng)遍歷過的點(diǎn)再次出現(xiàn),也就是有一條邊沒有被從總數(shù)中減掉
??????????? ##那么就有l(wèi)enEdges != 0
??????????? ##這一套也可以改成遞歸,省個(gè)棧,改起來很容易
??????????? ##最后就是注意集合比列表快得多,如果不要求順序,還是優(yōu)先用這個(gè)
??????????? adjacent = [[] for _ in range(n)]
??????????? for x,y in edges:
??????????????? adjacent[x].append(y)
??????????????? adjacent[y].append(x)
??????????? visited = {0}
??????????? stack = [0]
??????????? lenEdges = len(edges)
??????????? while stack:
??????????????? element = stack.pop()
??????????????? for neighbor in adjacent[element]:
??????????????????? if not neighbor in visited:
??????????????????????? lenEdges -= 1
??????????????????????? visited.add(neighbor)
??????????????????????? stack.append(neighbor)
??????????? return len(visited) == n and lenEdges == 0?? ?
————————————————
版權(quán)聲明:本文為CSDN博主「菲菲小姐」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_39655021/article/details/103752005

總結(jié)

以上是生活随笔為你收集整理的leetcode阶段总结——拓扑排序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美性色黄大片手机版 | 寂寞d奶大胸少妇 | 久久综合一区二区三区 | 欧美一级夜夜爽 | 男人的天堂视频在线观看 | 高跟鞋av | 久久久久久久久久久电影 | 日韩av免费| 国产a不卡 | 一本一道精品欧美中文字幕 | 日本不卡一区二区三区在线观看 | 成人午夜免费观看 | 俺也去网站 | 黄色的网站免费观看 | 色综合久久久无码中文字幕波多 | 永久黄网站 | 九一亚洲精品 | 亚洲一区二区三区在线视频观看 | 激情久久网| 亚洲图片偷拍区 | 免费播放毛片 | xxxx视频在线观看 | 一区中文字幕 | 校园春色自拍偷拍 | 涩涩涩在线观看 | 亚洲男人的天堂在线视频 | 日韩av在线第一页 | 国产精品性色 | 免费操人视频 | 日韩在线视频在线 | 国产一级全黄 | 一边摸内裤一边吻胸 | 综合狠狠开心 | 中文字幕在线视频一区二区三区 | 欧美激情国产精品 | 欧美三级少妇高潮 | 高跟91娇喘 | 欧美精品首页 | 久久精品66 | 涩涩涩av | 青青草小视频 | 懂色av| 免费av福利 | 亚洲天堂热 | 亚洲一二三四五 | av中文字幕免费 | 人妻少妇精品无码专区 | 性猛交╳xxx乱大交 偷偷操不一样的久久 | 中文字幕一区三区 | jizz性欧美17 | 三度诱惑免费版电影在线观看 | 精品一区二区三区久久久 | 久久久久九九九九 | 强制憋尿play黄文尿奴 | 日韩91视频 | av资源免费 | 午夜电影一区 | 日本精品视频一区二区 | 在线视频观看 | 国产6区| 中出少妇 | 国模大尺度视频 | 亚洲一级黄色大片 | 色涩视频在线观看 | 中文字幕一区二区免费 | 风间ゆみ大战黑人 | 亚洲人 女学生 打屁股 得到 | 欧美日韩中出 | 在线观看成人av | 久久久久xxxx | 麻豆网站| 欧美 日韩 国产 成人 | 视频一区二区三区在线 | a毛片视频| 五月婷婷在线观看 | 69精品久久久久久久 | h片在线观看免费 | 污污的视频软件 | 日本三级影院 | 男人天堂最新网址 | 1024亚洲| 国产亚洲不卡 | 91日韩精品 | 午夜av剧场| 东京干手机福利视频 | 久久老女人 | 国产精品天天狠天天看 | 欧美啊v | 国产chinese男男gaygay视频 | 中文字幕在线一区二区三区 | 国产日韩欧美亚洲 | 进去里视频在线观看 | 中文一区二区在线 | 免费看日韩 | 五月婷婷丁香六月 | 美女黄色一级视频 | 泷泽萝拉在线播放 | 欧美激情成人在线 | 天天摸日日摸 |