Graph Valid Tree - Leetcode 261 - Python

  Рет қаралды 103,244

NeetCode

NeetCode

Күн бұрын

Пікірлер: 117
@NeetCode
@NeetCode 3 жыл бұрын
💡 GRAPH PLAYLIST: kzbin.info/www/bejne/e5isZqGLbsqnpLc
@lasbutious116
@lasbutious116 3 жыл бұрын
This was indirectly the best video explaining how to find a loop in an undirected graph
@symbol767
@symbol767 2 жыл бұрын
Wow, me just realizing that all this problem was is literally finding a loop in an undirected graph, damn.
@lavanya_m01
@lavanya_m01 Жыл бұрын
Not necessarily.. what if this is the case, edges are [0,1], [2,3], [3,4], [2,4].. Here the function returns False even though it has a loop (2,3,4).
@staiwow
@staiwow Жыл бұрын
if it has a loop, it should return false.
@ladydimitrescu1155
@ladydimitrescu1155 Жыл бұрын
@@lavanya_m01 it should return False if it has a loop
@tabassumkhan7498
@tabassumkhan7498 8 ай бұрын
​@@lavanya_m01Here the graph contains 2 islands and maybe your code is not handling the unconnected components. For a graph to be a tree, it should not contain any loops and all the nodes should be connected. Since you are not accounting the unconnected component, the program will never reach the 2nd island where it has a loop. The program will finish after traversing 0 and 1 and will return true. To get around this, check if the size of the visited nodes == N. If not, return false. In your case, size of visited nodes should be 2 and hence should return false.
@dpynsnyl
@dpynsnyl 2 жыл бұрын
Another use case of union find. In love with the algorithm!!
@yashsrivastava677
@yashsrivastava677 3 жыл бұрын
With your kind of explanation skills, I wish someday you create videos on System Design preparation videos.
@leetcoderafeeq2641
@leetcoderafeeq2641 Жыл бұрын
You must have future vision
@tarastsugrii4367
@tarastsugrii4367 3 жыл бұрын
It's possible to solve this problem using basic tree properties - it's connected and has |V|-1 edges, so doing a single traversal to check if graph is connected combined with check that len(edges) == n - 1 should suffice.
@BCS_AatirNadim
@BCS_AatirNadim 2 жыл бұрын
but its also possible that one node is isolated, that way one loop has to exist in the graph, and this would return true even though the graph had a loop in it.
@BCS_AatirNadim
@BCS_AatirNadim 2 жыл бұрын
we can keep a check of all the n-1 numbered nodes, whether they have been visited or not
@Nancy-gi9op
@Nancy-gi9op 2 жыл бұрын
@@BCS_AatirNadim I agree with Taras. The connected check ( if len(visited) == number_of_nodes) and edges check (len(edges) == number_of_nodes -1) should suffice. In the case that a node is isolated, the connected check would fail or if it is a single node with a self-loop, the edges check would fail.
@nanakwamekankam1281
@nanakwamekankam1281 2 жыл бұрын
I agree, but I think going through coding it out is good traversal practice. If anything, it helps the solver appreciate and understand this property of graphs more :)
@sachinwalunjakar8854
@sachinwalunjakar8854 2 жыл бұрын
yes it possible, with union-find algorithm to check cycle and use property tree E = (V - 1) to check connectivity of graph.
@danielsun716
@danielsun716 2 жыл бұрын
Since this problem is focusing on determine there is no cycle or not, so the first idea come up with me is using the Union find algorithm. Also, it can be solved with the normal DFS. Union-Find Solution: def valid_tree(self, n: int, edges: list): if n - 1 != len(edges): return False parent = [i for i in range(n)] rank = [1] * n def find(n): p = parent[n] while p != parent[p]: parent[p] = parent[parent[p]] p = parent[p] return p def union(n1, n2): p1, p2 = find(n1), find(n2) if p1 == p2: return 0 if rank[p1] > rank[p2]: parent[p2] = p1 rank[p1] += rank[p2] else: parent[p1] = p2 rank[p2] += rank[p1] return 1 res = n for n1, n2 in edges: res -= union(n1, n2) return res == 1
@snoopyuj
@snoopyuj 2 жыл бұрын
Can we just return false immediately when we meet the p1 == p2 condition?
@danielsun716
@danielsun716 2 жыл бұрын
@@snoopyuj No. cause the return value of the nested function is int, not Boolean.
@snoopyuj
@snoopyuj 2 жыл бұрын
@@danielsun716 hmm... Maybe I can cache preRes to check that from outside. Thank you :)
@danielsun716
@danielsun716 2 жыл бұрын
@@snoopyuj I do not think it can be broken into subproblems. But if you can do that, you could give a try.
@snoopyuj
@snoopyuj 2 жыл бұрын
@@AMKSD Good to know! Thanks!
@mahesh_kok
@mahesh_kok 2 жыл бұрын
i tried this problem on directed and my approach didnt worked for undirected and when saw your video my respect for you using prev went through sky ...hats off to you bro
@LavanVivekanandasarma
@LavanVivekanandasarma 9 ай бұрын
Really cool how the problem is a combo of Redundant Connection and Number of Connected Components In An Undirected Graph
@isseihyodou7111
@isseihyodou7111 8 ай бұрын
You can also, solve this by Union Find Algorithm Python: class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: par = [i for i in range(n)] rank = [1]*n conCom = n def find(n): p = par[n] while p != par[p]: par[p] = par[par[p]] p = par[p] return p def union(n1,n2): nonlocal conCom p1,p2 = find(n1),find(n2) if p1 == p2: return False if rank[p1] > rank[p2]: par[p2] = p1 rank[p1] += rank[p2] else: par[p1] = p2 rank[p2] += rank[p1] conCom -= 1 return True for n1,n2 in edges: if not union(n1,n2): return False if conCom != 1: return False return True
@servantofthelord8147
@servantofthelord8147 3 ай бұрын
Another toughie, but rewarding when you figure it out. Thanks!
@sadekjn
@sadekjn Жыл бұрын
could also run union-find to check for cycles and then return n - 1 == len(edges) to check for connectedness
@bchen1403
@bchen1403 2 жыл бұрын
For anyone that came from Redundant Connection, a little adjustment from that problem's solution can be applied here. if n == 1: return True if not edges or len(edges) < (n-1): return False With the above two lines added, you are good to go.
@hudsonriverrunner
@hudsonriverrunner 3 жыл бұрын
Wonderful DFS approach ! My solution is to use BFS without tracking prev. Observation: In BFS, there is NO way we can form a cycle without 2 nodes from the same level. Cycle can only be formed by connecting two nodes in the same level, OR visiting a node more than once in a level (it has >=2 parents from the previous level). Either way, it requires two nodes from the same level be connected directly (when we have odd number nodes in a cycle) or indirectly (through a common offspring, when we have even number), together with the root we started from, they form a cycle. Another BFS solution thought I first have is to revisit a node from a offspring two levels after. It can be accepted and has the same time complexity. But it is slower, because we have to go at least 2 more levels before realizing we are actually in a cycle, compared to the first solution. Correct me if I am wrong. Thx guys!
@leetcoderafeeq2641
@leetcoderafeeq2641 Жыл бұрын
Another person who made a YT account just for leetcode. Do you work at google yet?
@basic-2-advance
@basic-2-advance 5 ай бұрын
Additionally it is mentioned in the constrained n is greater than or equal to 1 so we can omit the n==0 check
@vipinamar8323
@vipinamar8323 2 жыл бұрын
nodes = set() no_of_edges = 0 for i in edges: no_of_edges +=1 nodes.add(i[0]) nodes.add(i[1]) if no_of_edges < len(nodes): return True return False
@subhashreebanik8131
@subhashreebanik8131 2 жыл бұрын
Hey there! Firstly, your videos are AMAZING. I love watching your videos whenever I'm stuck. I can't thank you enough for existing Neetcode. Recently, I've found out that I get stuck on recursive solutions. I don't have much knowledge on recursion. What reading material would you suggest so that I can become a pro on recursion?
@michellewww8036
@michellewww8036 2 жыл бұрын
very clear and I could learn DFS in a very logic way. Thanks!!!
@samuelrobert2927
@samuelrobert2927 2 күн бұрын
For a tree to be valid, number of nodes should be 1 above its edges. If it's not the case, then there exists disconnected components or cycles.
@avanishgvyas1992
@avanishgvyas1992 25 күн бұрын
You can skip the whole function if you add a below condition in the first line: if (edges.length != (n - 1)) return false; Basically, a graph with n nodes is a tree if it has exactly (n - 1) edges. So, if no. of edges is not equal to (n - 1), it can never form a tree.
@iambao1940
@iambao1940 8 ай бұрын
class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: if len(edges) != n - 1: return False if n == 1: return True nodes = set() for e in edges: nodes.add(e[0]) nodes.add(e[1]) return len(nodes) == n This code works
@davidlee588
@davidlee588 2 жыл бұрын
After solving all NeetCode Graph problems in JavaScript, I just found that JS is not responsive every time to the same technique in DFS. For example: the construction of visit = new Set(); sometimes you have to add value.toString() in order to work out sometimes don't; most of the times you cannot establish this visit array, you just use grid[r][c] to keep track of the visited value. The union find is also problematic, esp. the find() method (sometimes you write p = par[n], sometimes you write p = n in the beginning)and the way you use union(), all variates according to different problems. What a weird and frustrating experience! I found DP easier to implement.
@krishnasharma657
@krishnasharma657 Жыл бұрын
Can we do this by union join to Chek for loop and then checking if parent of each node is root to check for connected components??
@tylera3126
@tylera3126 Жыл бұрын
I was thinking the same thing
@sachinwalunjakar8854
@sachinwalunjakar8854 2 жыл бұрын
It is possible solve this problem with time complexity O(E) using union-find algorithm to check cycle and using property of tree E = (V - 1) to check connectivity of graph.
@AndroidNerd
@AndroidNerd 3 жыл бұрын
You deserve so many more views
@emmanuelromero2258
@emmanuelromero2258 Жыл бұрын
How about Union Find Algo? # Union Find Algorithm def Solution(): def graphValidTree(self, n, edges): parent = [i for i in range(n)] ranks = [i for i in range(n)] # Build Find def find(n1): p = parent[n1] while p != parent[p]: parent[p] = parent[parent[p]] # Path Compression p = parent[p] return p # Build Union def union(n1, n2): p1, p2 = find(n1), find(n2) if p1 == p2: return False if ranks[p1] > ranks[p2]: ranks[p1] += ranks[p2] parent[p2] = p1 else: ranks[p2] += ranks[p1] parent[p1] = p2 return True for n1, n2 in edges: if union(n1, n2): n -= 1 else: return False return n == 0
@aaronhanson1694
@aaronhanson1694 2 жыл бұрын
could we also do a union find algo? if number of components == 1 and no nodes share the same parent then were good?
@dr4gonbloodx
@dr4gonbloodx 2 жыл бұрын
Yes
@shan504
@shan504 3 жыл бұрын
why is the complexity O(e+v)?? if you visit each node once it should be O(v) right? going to an already visited node results in an immediate return of O(1)
@dorondavid4698
@dorondavid4698 3 жыл бұрын
He's using an Adjacency list, so for every V you have to visit all of its E (to get to the other V)
@BBRR442
@BBRR442 Жыл бұрын
great video thanks, better at 0.75
@johnscherian9925
@johnscherian9925 2 жыл бұрын
Not sure if this is the right place for this question. Interviewing for a Solutions Architect role. Have not coded fundamentals in a while. Wondering if given a position for the car how to get the associated string for example, If given the car is at position 25, what string sequence(s) would allow a car to achieve this position, the second part of the following question. I know from the problem statement/example, this would be achieved by AAAAARAAARA. However could other strings be obtained and how could i generate all this in code- what algo and ds should be considered, naive first and then optimized. Thanks! A (fictional) early version of self-driving car had some limitations: it could only travel in a straight line, and it was pre-programmed with a sequence of instructions from an instruction set of two. The two instructions are: [A]ccelerate: move in the current direction for one second, then double your speed. [R]everse: stop immediately, change direction, then reset your speed. The initial speed, and the speed after a Reverse instruction, is 1 unit per second So, for example, the sequence AAAAARAAARA moves the car (1+2+4+8+16)-(1+2+4)+(1) = 25. f(AAAAARAAARA) a) Take a sequence string and produce the final position def position(sequence): final_pos = 0 speed = 1 for command in range (len(sequence)): if sequence(command) == “A”: final_pos = final_pos + speed speed = speed * 2 else sequence(command) == “R”: speed = -1* speed/abs(speed) return final_pos b) Second part, given position get string Thanks for your feedback!
@roywastaken
@roywastaken 2 жыл бұрын
Doing God's work!
@timlee7492
@timlee7492 2 жыл бұрын
I have a dumb question . For example : in this example , when precessing node 1 and previous node is 0, then these two line of code' for j in adj[i] ; if j== previous' .That's mean prev node is 0, i=1, j=4. Are we comparing node 4 with node 0 instead of node 4 with node 1? Do I misunderstood anything there? Thanks! 🤔
@nikhilgoyal007
@nikhilgoyal007 5 ай бұрын
self notes - Prev used to detect a cycle because it is an undirected graph.
@shwethaks7994
@shwethaks7994 3 жыл бұрын
Your videos and explanations are just amazing. I was wondering if you can create some system design videos as well as it would be of great help to many people.
@asifchoudhuryca
@asifchoudhuryca 2 жыл бұрын
Thanks!
@dingus2332
@dingus2332 Жыл бұрын
Can we use union find to do this ?
@iknoorsingh7454
@iknoorsingh7454 3 жыл бұрын
I guess we do not need to check the previous node conditions if we save the nodes as directed edges in the adjacency matrix. @neetcode?
@dheepthaaanand3214
@dheepthaaanand3214 12 күн бұрын
I have the same question. Whichever type of direction we choose for the edge should not matter, because we'll somehow end up visiting a node again if it's in a cycle
@shadowsw8020
@shadowsw8020 8 ай бұрын
Love this one, great explanation
@romangirin772
@romangirin772 Жыл бұрын
this problem could be solved via DSU (disjoint set union)
@capooti
@capooti 3 жыл бұрын
excellent explanation as usual, thanks!
@pekarna
@pekarna 2 жыл бұрын
4:40 - wouldn't an array of booleans of size N be more efficient than a hashset? We are going to end up with all of them in the set anyway, so array would be less memory and also marginally quicker to access.
@axellbrendow1
@axellbrendow1 3 жыл бұрын
What happens if the root node is not node 0 ? This implementation assumes node 0 is not a leaf for example.
@petersiracusa5281
@petersiracusa5281 3 жыл бұрын
in a tree, any node can be treated a root. It will still be acyclic and connected. try redrawing any tree with some other node as root. Can always be done.
@axellbrendow1
@axellbrendow1 3 жыл бұрын
@@petersiracusa5281 I forgot that the question states the edges are undirected. If the edges were directed, my comment would make sense.
@niloofaryousefi1757
@niloofaryousefi1757 2 жыл бұрын
great explanation :) I was just wondering why this problem cannot be solved using UnionFind algorithm ? can anyone help, please!
@ianalexthompson
@ianalexthompson 2 жыл бұрын
Surely, It can be done that way. It's just one of possible solutions
@draugno7
@draugno7 Ай бұрын
Not hard after solving similar dfs problems, the only thing I wouldn't have figured out is false positives for loops
@lomoyang3034
@lomoyang3034 3 жыл бұрын
I'm not sure if this solution works. Think about A->B, B->C, C->A, in this case, A is C's neighbor, but not C's prev. but there is a loop, and it's not a tree. Please correct me if I'm wrong.
@jessepinkman2942
@jessepinkman2942 2 жыл бұрын
It would return false because A, and B would already be in the visited set when you visit C. So when you visit C's neighbor then you would encounter A (or B) and since it is already visited then a cycle has been detected.
@saitejanagam5748
@saitejanagam5748 3 жыл бұрын
Awesome explanation bro
@madhumithakolkar_
@madhumithakolkar_ Жыл бұрын
Which part of this takes care of the condition of having a node that isn't connected to the rest of the nodes ?
@chitii91
@chitii91 10 ай бұрын
return dfs(0, -1) and "len(visited) == n"
@johnj171
@johnj171 4 ай бұрын
heyyyy!!! your video come in priority when leetcode word is used. can you please update your SEO such that when a problem statement is given also your video pops up!!!!! without degrading current efficiency of you SEO
@gourishpisal2796
@gourishpisal2796 Жыл бұрын
what is the use of adj list?
@EduarteBDO
@EduarteBDO 11 ай бұрын
After all prev questions being union find I didn't even though of dfs and did union find solution: class Solution: def valid_tree(self, n: int, edges: List[List[int]]) -> bool: if len(edges) < n-1:return False par = [i for i in range(n)] rank = [1] * n def find(n): while n != par[n]: par[n] = par[par[n]] n = par[n] return n def union(n1:int, n2:int): r1, r2 = find(n1), find(n2) if r1 == r2:return False if rank[r1] > rank[r2]: par[r2] = r1 rank[r1] += rank[r2] else: par[r1] = r2 rank[r2] += rank[r1] return True for n1, n2 in edges: if not union(n1, n2): return False return True
@sushantrocks
@sushantrocks 3 жыл бұрын
Check connected and n=e+1?
@gokusaiyan1128
@gokusaiyan1128 2 жыл бұрын
union find would have been better/easier approach for this problem
@ameynaik2743
@ameynaik2743 3 жыл бұрын
Great video, is there any advantage of using dfs instead of bfs?
@NeetCode
@NeetCode 3 жыл бұрын
No, I think either one is fine. I'm more use to DFS but sometime BFS can make problems easier.
@annsway
@annsway 3 жыл бұрын
If possible, would you please explain line 25 - 26 in your code? I don't understand why dfs(j, i) should be in the if condition.
@yuemingpang3161
@yuemingpang3161 2 жыл бұрын
to check if there is a loop. If there is a loop then return false and it is not a tree. To be a tree, all the "if" loop detection guards need to be skipped during recursion and return true at the end.
@zorali8219
@zorali8219 3 жыл бұрын
謝謝!
@NeetCode
@NeetCode 3 жыл бұрын
Thank you so much, I really appreciate it! 😊
@jessanraj9086
@jessanraj9086 7 ай бұрын
thank you so much
@TomerBenDavid
@TomerBenDavid 3 жыл бұрын
Nice! Can you please tell which mic and drawing software you use? Affiliate links would be great way to support you on this thanks .
@NeetCode
@NeetCode 3 жыл бұрын
Sure, this is the mic I use: amzn.to/2RRrLQd And I just use Paint3D for the drawings with a mouse.
@TomerBenDavid
@TomerBenDavid 3 жыл бұрын
@@NeetCode thanks! I read a little bit about this mic I think this is really great choice from what I saw then this mic is comparable to blue yeti but has less base I think this only contributes to the clarity of voice! so it's better in that manner than blue yeti. I'm pretty surprised your are able to write letters pretty precisely with mouse. On top of all the explanations are brilliant (so even with the worst mouse/mic you would still rule the explanations) but somehow the clarity of this mic + drawing + the brilliant undoing of drawing while drawing to keep screen clear is a winning combination on top of the super clear brilliant explanations.
@gourishpisal2796
@gourishpisal2796 Жыл бұрын
why are we using it?
@kirillzlobin7135
@kirillzlobin7135 4 ай бұрын
Amazing
@leventoz9530
@leventoz9530 Жыл бұрын
I don't see where in the problem it says 0 is the root node.
@AndréNovaisBrito
@AndréNovaisBrito 7 ай бұрын
the is no root, the nodes are labeled from 0 to n-1
@AshishSarin1
@AshishSarin1 2 жыл бұрын
Great explanation. Really easy to understand. Thanks
@algorithmo134
@algorithmo134 3 жыл бұрын
Can you do binary tree cameras please Neetcode? 😭
@NeetCode
@NeetCode 3 жыл бұрын
I took a look at the problem, I havent solved it before but I will try to do it eventually, but maybe not soon.
@nikilragav
@nikilragav 3 ай бұрын
doesn't your solution inherently assume that 0 is the root node?
@ronsito4242
@ronsito4242 3 күн бұрын
if its a tree all vertices are in the same connected component so it doesn't matter where you start
@jonaskhanwald566
@jonaskhanwald566 3 жыл бұрын
how to code recursively.
@rishikaverma9846
@rishikaverma9846 Жыл бұрын
one testcase doesn't display the desired outcome
@tinymurky7329
@tinymurky7329 Жыл бұрын
I found out union find can work class Solution: """ @param n: An integer @param edges: a list of undirected edges @return: true if it's a valid tree, or false """ def valid_tree(self, n: int, edges: List[List[int]]) -> bool: # write your code here id = [i for i in range(n)] self.n = n def find(v): if v != id[v]: root = find(id[v]) id[v] = root return root else: return v def union(a, b): rootA = find(a) rootB = find(b) if rootA == rootB: return False else: id[rootA] = rootB self.n -= 1 return True for a, b in edges: if not union(a, b): return False if self.n != 1: return False return True
@FA513M
@FA513M 2 жыл бұрын
Anyone having problem with Lintcode login??
@eyeamkd
@eyeamkd Жыл бұрын
Takes 20.80MB to run..."eFfiCientLY"
@fishoil5310
@fishoil5310 3 жыл бұрын
I'm not sure why but it seems that I need to have both of these conditions to pass the test cases if n==1: return true if n>0 and len(edges)==0: return false
@quirkyquester
@quirkyquester 4 ай бұрын
you are not wrong, i think it was a mistake, that's a bug there.
@BBRR442
@BBRR442 Жыл бұрын
why does guy sound passively mad
@oliverduan1374
@oliverduan1374 2 жыл бұрын
LeetCode, LintCode and NeetCode, lol
@MaxFung
@MaxFung 8 ай бұрын
this mf always does dfs
@mushahidkhan7472
@mushahidkhan7472 7 ай бұрын
Dont take this the wrong way but you shouuld just state the complexities yhou should rather explain them. DOnt just say its O(E+V) rather explain why we are using E+V and why is it? I am thinking time complexity should just be O(E) where E is number of edges. It takes O(E) to make adjacency list and then it takes O(E) to visit all edges(in other words we do E number of recursion calls, i dont understand why the number of vertices matters here) and the space complexity is O(number of vertices * number of edges) because in worst case, we can have a fully connected graph input and so the dictionary has keys equal to number of vertices and for each vertex key in the dictionary, we have a list of edges.
@vatsalshah7557
@vatsalshah7557 Ай бұрын
``` if len(edges) != n - 1: return False # Build the adjacency list for the graph graph = defaultdict(list) for u, v in edges: graph[u].append(v) graph[v].append(u) # Set to keep track of visited nodes visited = set() # BFS def bfs(start): queue = deque([start]) visited.add(start) while queue: node = queue.popleft() for neighbor in graph[node]: if neighbor in visited: continue # If already visited, skip it visited.add(neighbor) queue.append(neighbor) # Start BFS from node 0 bfs(0) # Check if all nodes are visited (graph should be connected) return len(visited) == n ``` BFS solution is easier.
風船をキャッチしろ!🎈 Balloon catch Challenges
00:57
はじめしゃちょー(hajime)
Рет қаралды 90 МЛН
ТЮРЕМЩИК В БОКСЕ! #shorts
00:58
HARD_MMA
Рет қаралды 2,5 МЛН
Network Delay Time - Dijkstra's algorithm - Leetcode 743
19:48
Dynamic Programming isn't too hard. You just don't know what it is.
22:31
DecodingIntuition
Рет қаралды 196 М.
The hidden beauty of the A* algorithm
19:22
Polylog
Рет қаралды 897 М.
LeetCode: 261. Graph Valid Tree (Golang & Java)
19:39
Nandeshwar Sah
Рет қаралды 103
3 Types of Algorithms Every Programmer Needs to Know
13:12
ForrestKnight
Рет қаралды 499 М.
LeetCode was HARD until I Learned these 15 Patterns
13:00
Ashish Pratap Singh
Рет қаралды 576 М.
Top 7 Data Structures for Interviews Explained SIMPLY
13:02
Codebagel
Рет қаралды 226 М.
風船をキャッチしろ!🎈 Balloon catch Challenges
00:57
はじめしゃちょー(hajime)
Рет қаралды 90 МЛН