Graph Algorithms for Technical Interviews - Full Course

Graph Algorithms for Technical Interviews - Full Course


Graph Algorithms for Technical Interviews - Full Course

Learn how to implement graph algorithms and how to use them to solve coding challenges.

✏️ This course was developed by Alvin Zablan from Structy. Check out Alvin’s channel:    / alvintheprogrammer  

🔗 Learn data structures and algorithms: https://structy.net/

⭐️ Course Contents ⭐️
⌨️ (0:00:00) course introduction
⌨️ (0:02:23) graph basics
⌨️ (0:07:10) depth first and breadth first traversal
⌨️ (0:29:13) has path - https://structy.net/problems/has-path
⌨️ (0:42:11) undirected path - https://structy.net/problems/undirect
⌨️ (1:00:44) connected components count - https://structy.net/problems/connecte
⌨️ (1:13:29) largest component - https://structy.net/problems/largest-
⌨️ (1:24:03) shortest path - https://structy.net/problems/shortest
⌨️ (1:39:36) island count - https://structy.net/problems/island-c
⌨️ (1:58:52) minimum island - https://structy.net/problems/minimum-
⌨️ (2:12:05) outro

🎉 Thanks to our Champion and Sponsor supporters:
👾 Wong Voon jinq
👾 hexploitation
👾 Katia Moran
👾 BlckPhantom
👾 Nick Raker
👾 Otis Morgan
👾 DeezMaster
👾 Treehouse
👾 AppWrite



Learn to code for free and get a developer job: https://www.freecodecamp.org

Read hundreds of articles on programming: https://freecodecamp.org/news


Content

0.049 -> This course will help you learn what you need to implement graph algorithms and use them
5.1 -> to solve coding challenges. Alvin's dynamic programming course is one of the most popular
10.79 -> courses on our channel. And now he's back to teach you graph algorithms. Hey, programmers,
16.1 -> I'm Alvin from Structy. Welcome to our course on graphs. And in particular, this is going
19.939 -> to be about graphs for your technical interviews. Of course, graphs are a very common topic
24.199 -> when it comes to those technical interviews. And in particular, what I want to emphasize
27.949 -> throughout this course, is the handful of patterns that come up time and time again,
32.46 -> on those technical interviews. in just about two and a half hours, I'm going to give you
36.04 -> all the tools you need to basically cover I'd say about 80% of all graph problems. And
41.27 -> so what I have in store for this course, well, I think the key to victory for your data structures
44.91 -> and algorithms, and especially your graphs is to visualize things, right. So we're going
49.19 -> to do is trace through a lot of different algorithms, and be sure to understand them
53.1 -> at a high level. And that means going through different animations here, I think graphs
58.12 -> have a pretty bad rap for being a difficult topic. Because to a beginner, you can have
62.71 -> very, very different narratives around a problem, and not really understand. They're all really
67.09 -> based on a graph premise. So we're going to realize that a bunch of different things can
70.79 -> be understood as graphs. So when it comes to the prerequisites of this course, I'm going
75.11 -> to assume that you know nothing about graphs. But you do know how to code, right, so I'm
78.68 -> going to have the expectation that you understand some recursion. So as you work through the
83.09 -> course, and learn about different graph patterns, we're going to use those patterns to solve
86.39 -> some very classic interview problems about graphs, right. And I'm going to give you plenty
90.38 -> of opportunity to practice these patterns in different problems that we will be ready
93.79 -> whenever you have them on a technical interview. What I love about the topic of graphs is just
97.93 -> using a handful of different algorithms, you can cover the majority of graph problems,
102.95 -> right. For every graph problem that we cover, we're going to split it up into two sections,
106.45 -> section one is going to be about the approach for the video. So we're going to go over the
109.88 -> strategy and overall theory, and be sure to sketch out a nice meaningful picture. We're
113.84 -> also going to talk about the complexity of the algorithm in the approach video. Following
117.12 -> every approach, we're also going to implement the code of course, I'm going to be writing
120.23 -> all of my code in JavaScript, you'll be able to follow along in any language that you like.
124.41 -> So that means occasionally I'll be switching to my code editor where you of course can
127.55 -> follow along. We're also going to be sure provide links in description as well as links
132.06 -> on screen. That way you can formerly you read the prompts for every problem, as well as
135.96 -> look at the different test cases. Alright, I think that's enough introduction. For now,
139.37 -> let's hop right into the course. Alright, programmers. So let's jump right into the
142.85 -> course, I want to start by giving you some background about your graphs, we're going
145.9 -> to go over the graph basics that you need to start attacking problems in a technical
149.38 -> interview. So first off, what is a graph? A graph is really just a collection of nodes
154.43 -> and edges. So with respect to nodes, you can visualize them as typically just some circles
159.09 -> with some data inside of them. So I'll put some letter values in my nodes over here.
163.44 -> And when we refer to edges, that would be just any connections between nodes. So for
167.99 -> example, if there was a connection between A and C, it would look something like this,
171.63 -> right? What I can formally say is there's an edge between A and C, I can create many
175.84 -> edges between any nodes I want within this graph. Another word you might hear out in
180.48 -> the wild when it comes to describing nodes, as you might hear the word vertex being used,
184.17 -> right, they're really the same thing. In this course, I'll stick to the word node. And an
188.24 -> edge is just a connection between a pair of nodes. And that's really all a graph is at
192.19 -> a high level, where things get interesting is how we can use this graph framework to
196.17 -> actually solve a problem, right. So if you think of these nodes as just things and the
200.5 -> edges as relationships, a graph is grid describing the relationship between things. For example,
205.94 -> we can say that the nodes here are cities and edges would be roads connecting cities
210.41 -> are in a similar way, maybe our nodes here are courses, and then the edges represent
214.849 -> prerequisites. And so in the future, we're going to use graphs as a way to illustrate
218.92 -> and frame some narrative problem. Let's talk about this graph. In particular, here, I really
223.53 -> have drawn a directed graph. And that's because I have some arrowheads along the edges. That
229.099 -> would be a comparison to an undirected graph. So here, I have really the same structure,
233.819 -> except I don't have any arrowheads on the edges here. And that means that there is no
238.22 -> directionality to it right. If I look at the directed graph, let's say I was at the node
241.75 -> A, well, then I can travel to B or C, let's say I move to C. However, once I'm at C, I
247.36 -> cannot travel to a, I can only travel to E, right? That's because I have to obey the direction
252.551 -> of the arrow heads here. By take a look at my undirected graph, let's say I was currently
257.23 -> situated at the scene over here, that I do have the option of traveling to either a or
262 -> E, right? So if I traveled to a, that's all good, I can even travel back to C. So think
266.59 -> of as an undirected graph as a two way street. For now we'll just continue on with our directed
271.55 -> version. Let me also introduce some useful terminology we can use when talking about
275.46 -> the nodes in our graph. If I was currently situated at this a node, I can refer to B
280.379 -> and C as neighbor nodes. Alright, so a neighbor node is really any know that's accessible
285.749 -> through an edge, of course, obeying the direction of the edge. In other words, if I was currently
290.09 -> situated at the sea node, that I only have one neighbor of E, right, if I'm at the sea,
295.229 -> you know, then I won't consider a neighbor. Awesome. When you visualize graph algorithms,
301.22 -> you should really sketch a picture that looks just like this, right literally drop nodes
305.059 -> as circles and arrows as your edges here. However, when it comes to how we implement
309.669 -> this algorithm in some code, we're gonna have to represent it in a more programmatic way.
313.479 -> Right? So in my brain, I think of this image of like nodes and arrows between them. However,
318.55 -> in my program, I'm going to use typically an adjacency list, it's probably our preferred
323.12 -> way to represent and graph information, right. So depending on the programming language of
327.77 -> choice we're going to use typically, we would use some hash map data structure to represent
332.129 -> an adjacency list. Really, we're looking forward to using some constant time, I'll look up
336.83 -> data structure that has a key value pair mapping, right. So if you're in JavaScript, they'll
341.24 -> be an object, if you're in Python, they'll be a dictionary. If you're in a language like
344.779 -> Java, or C, you'll be using an unordered map. Looking at this hash map, I have drawn or
349.909 -> this adjacency list, the keys of this adjacency list are going to be every node in my graph,
355.58 -> right, so I just have all of the node values A through F laid out as the keys. However,
360.479 -> if you look at the corresponding values, the values are actually going to be an array,
364.33 -> right? So if I look at this very first entry, it says that I have a node of a and then in
371.139 -> the array of populated all of the neighbors have a that is a has two neighbors have BNC.
376.249 -> That's why I have this correspondence within my adjacency list. That holds true for every
381.8 -> entry within my adjacency lists. So for example, let's say look at the entry for e. So I go
387.54 -> to the spot and make j c list where the key is E, it only has a one outgoing edge to be.
393.11 -> That's why the array for he only has be inside of it. One thing to also note is even if a
398.669 -> node has no neighbors, it should still appear as a key within my adjacency list. For example,
403.36 -> if you look at the D, node D has no outgoing edges. That's why its neighbor array is empty.
408.02 -> However, it should still at least appear as a key within my adjacency lists, right, that
412.009 -> way, you can still know that the D node exists. So at the start of the course, will usually
417.33 -> be taking in adjacency list as the information to represent a graph, right. But as we sketch
422.569 -> through things on the whiteboard, we should be visualizing them using a nice picture like
426.38 -> this. Awesome. So let's actually jump into our first pair of algorithms. To me, the must
431.909 -> know algorithm for a graph is really going to be to do some sort of traversal on it.
436.36 -> Why don't we start by talking about a depth first traversal, something you may have heard
440.41 -> of before, right, now we're going to talk about the depth first traversal algorithm
443.79 -> that operates on a graph. So let's start by understanding at a high level what order a
449.099 -> depth first traversal would give you. So let's say I had some starting node, and I'm gonna
453.139 -> choose a as my starting node, right, so I'm gonna color it here in yellow. If I was following
457.599 -> a depth first traversal. Now that I've, you know, chosen as my starting point, I can either
462.039 -> hit B or C. Next, I'm just gonna commit to using B. So let's say I had the sequence so
466.809 -> far have a comma b. And at this point, if I was truly following a depth first traversal,
472.189 -> I must go deeper to the D node. In other words, I don't go to the C node yet. Cool, that would
478.87 -> be a true depth first traversal, right. At this point, now that I've bottomed out at
483.009 -> D, D is a dead end, right? I can't travel to F from D, because that would be disobeying
487.039 -> the arrowhead. And so now I can move to that other neighbor of C. And from here, the algorithm
492.679 -> would continue, right, I go from C to E, and then e to B. And technically, I would have
497.52 -> to double traverse some nodes like B and D over here. So overall, in this yellow coloring,
503.62 -> I have colored the full region that a depth first traversal would explore starting at
508.3 -> a notice that if you started at a it would be impossible to reach F. And that's kind
513.779 -> of normal, right? That's kind of why we use these traversal algorithms that can tell you
517.589 -> whether or not you can travel between some nodes. And we'll see that literal problem
521.919 -> later on. Right? So you're probably wondering, you know, exactly how do we implement this,
525.62 -> but for now, I just want to stay focused on the order that we got, right. So just regarding
529.99 -> our depth first traversal, we remember the first three iterations of the algorithm, we
535.13 -> hit the sequence of a B, D, right, that's indicative of a depth first traversal. Now
540.66 -> let's compare that to the breadth first Marion. So I'm going to lay down the same exact graph,
545.769 -> we're also going to start a traversal at the a node, but this time follow a breadth first
549.98 -> order. So I have a first and let's say, you know, I chose B as my next node when it comes
554.75 -> to breadth first traversal. It doesn't matter like which, you know, initial neighbor you
558.779 -> choose, so I'm just gonna choose B. But now that I've chosen B, if I was following a true
563.47 -> breadth first traversal, I must hit c next, right. And that's the main difference between
568.42 -> our depth first and breadth first reversals for the same graph, my depth first would start
572.81 -> a B, D, whereas my breadth first would start a, b, c. And so you're probably wondering,
578.5 -> is there any importance between this nuance right? When would I prefer depth first over
582.73 -> breadth first, or vice versa? Either a depth first or breadth first traversal would explore
588.25 -> the same exact nodes within a graph. However, it would explore them in a different order,
592.41 -> right? And this is more obvious to see when we have a larger graph with way more edges.
598.3 -> And so let's look at how he depth first traversal explores again, but this time on a much larger
602.089 -> graph, let's take a look at this one. So I'm going to choose some random node as a starting
606.519 -> point, let's say I chose this node in yellow, that was doing a depth first traversal, what
611.01 -> I'm going to do is, you know, pick a direction and travel in that same direction as far as
615 -> possible before switching directions. So let's say I move to the right, at this point, I
619.649 -> would have to continue moving toward the right, until I can't move to the right any longer,
624.06 -> at which point, I have to choose some new directions, let's say it was downward. I'll
628.19 -> keep doing that until I can't move downward anymore. And so I'd have to move to the left
632.079 -> now, now I'd keep chasing this single path in a very deep direction. So that's behavior
638.69 -> indicative of a depth first traversal, right, you're exploring one direction as far as possible
643.44 -> before switching directions. Let's compare that to a breadth first traversal. So let's
648.889 -> say start at the same node in pink, if I was following a breadth first traversal, it would
653.381 -> look something like this. From the starting point, I would explore all of the immediate
657.61 -> neighbors of this node, kind of in a circle like this. Now I just keep applying that behavior.
664.79 -> So as you notice about the breadth first traversal, is it'll tend to explore you know, all directions
673.029 -> evenly, right, instead of just favoring One Direction all the way through. That's really
678.04 -> the only difference between a depth first and breadth first traversal. Later on the
682.12 -> course, I'll bring up explicit problems where you might prefer one over the other. All right,
686.3 -> but for now, what I want to do is give you all the background you need. So you can actually
689.26 -> build this algorithm will kind of talk about things at a high level, consider this the
693.529 -> pseudocode, then, of course, we'll express it in some JavaScript code later on. So when
698.121 -> it comes to actually implementing in code, these two algorithms, the key is to understand
702.81 -> that a depth first traversal uses a stack, and a breadth first traversal uses a queue,
708 -> recall that a stack is something where you add to the top and remove from the top as
712.04 -> well, or is it Q is something where you add to the back and remove from the front, and
716.12 -> it gives you two very different orderings. That's really the only difference between
720.1 -> these two algorithms. So let's start by tracing through our depth first traversal, of course,
725.16 -> using a stack, so I'm going to use a slightly different graph. And to visualize my stack,
729.75 -> I'm going to use this bar to represent the bottom of my stack, obviously, for me, at
733.959 -> least I think of a stack as some vertical data structure. Cool. So let's say I just
738.589 -> arbitrarily chose a as my starting node to perform my depth first traversal, right, in
744.24 -> the long run, just want to print out all different node values within this graph. So what I'm
749.11 -> gonna do is I'm gonna take my starting node of a, and I'm just gonna immediately initialize
753.41 -> it onto my stack. So right now as the only thing on my stack, it's also at the top of
757.8 -> my stack. And now I can enter the flow of the main algorithm here, because I have a
762.18 -> stack, what I can only do is remove the top of my stack. So that means I pop off a from
767.05 -> the stack, and consider the a node, my current node being looked at, right? At this point,
772.639 -> let's say I print out a to my console. And from here, what I want to do is consider A's
777.329 -> neighbors, right. So if I look at the C node, what I should do is just push c to the stack,
782.589 -> then also push B to the stack, right. And it doesn't matter like in which order you
787.55 -> push these neighbors. If I want it to hit B first, then I'm going to push them second,
792.139 -> right? Awesome. That would end like my first iteration of this depth first traversal. Cool.
798.62 -> So at this point, I can look at my stack, and my stack still has some data on it. So
802.279 -> I should do is again, pop the top of my stack. So I'm going to pop and be off my stack. And
806.839 -> that becomes my current, I'm also going to print it out. At this point, I look at B's
811.579 -> neighbors, B has one neighbor of D and so I push d to the top of the stack. Notice that
816.689 -> because I have a stack D ends up on top of the C, right. And so now when I get to another
823.079 -> iteration, when I pop the top of my stack, I look at the D node as my current, right,
827.87 -> and I can print out D. And this feels good because so far, my print order would be a
833.389 -> BD, notice that I kind of pursued that single path deeply following a BD. But I have to
839.6 -> look at DS neighbors, I can take f and just push f to the top of my stack. next iteration,
845.329 -> my stack is still on empty. So I should do is pop the top F is now my current, I can
849.899 -> print out F, but f has no neighbors. So F isn't going to push anything else to the top
855.01 -> of the stack. Right? At this point, I get to this next pass, and I pop the top of my
860.31 -> stack. And that means C is now my current, I can print out CS value. And then I can look
865.47 -> at Sue's neighbors. And I just push e to the top of my stack. On this last iteration, I
871.37 -> popped up on my stack, he is now my current I print out he since he has no neighbors,
876.93 -> I don't push anything else to the top of my stack. And at this point, I've reached the
881.139 -> state where my stack is empty. And that means my algorithm is done right that means you
885.639 -> explored as far as possible within your graph. Notice that it might not necessarily be the
891.68 -> case that you're able to hit every node of the graph. And this particular example it
895.88 -> was possible though, awesome. So let's redo that trace using Our breadth first algorithm,
901.43 -> which means we just adjust things slightly. And we use a queue order. Remember that a
905.709 -> queue is a first in first out data structure, meaning things enter to the back, and then
910.189 -> they leave from the front. And so let's say I use this arrow to represent the directionality
915.149 -> of my queue, right. And I start the algorithm in the same way for my breadth first traversal.
920.17 -> Let's say I want it to begin at node A. So I just initialize my queue with a cool, so
925.98 -> I start by removing the front of my queue. So a becomes my current node, I can print
930.8 -> out a as well. And now I consider A's neighbors, right. So I consider B and C. If I wanted
937.129 -> to travel to B before C, then I should push B to my queue first, right, so I add B to
943.43 -> the back of my queue, right. And I should also add c to the back of my queue, right.
949.91 -> And that would actually end my first iteration. So now I look at my queue still has some stuff
955.509 -> on it. So I removed the front of my queue, that means B becomes my current. Of course,
960.759 -> I print out B. Now I consider B's neighbors. So I just look at the D node, and I push d
965.759 -> to the back of the queue, since D enters through the back and ends up behind the C, and that's
971.26 -> really important behavior. next iteration, I removed the front of my queue. So my current
976.959 -> is now see, right, I can print out see, and then look at sees neighbors of just E and
982.49 -> I add e to the back of the queue, which means that in the order of my queue, he ends up
986.99 -> behind the my next iteration, I removed D from the queue, and I print out the edits
993.5 -> neighbor of F to the back of my queue. next iteration, I removed e from the front of my
999.529 -> queue, print it out. Since he has no neighbors, he is not going to add anything else to the
1004.399 -> back of the queue. And of course, finally, f leaves the front of my queue, I print out
1009.35 -> F, F has no neighbors, at which point now my queue is totally empty. And since our queue
1014.24 -> is empty, that would be the end of our algorithm. Alright, and that's all there is to our depth
1018.57 -> first and breadth first algorithms, they're going to be the nice baseline code that we
1022.86 -> use to solve many different graph problems. I think that's enough theory. For now, what
1026.53 -> I want to do is now switch to my code editor, where you can actually implement these in
1030.27 -> JavaScript, hey, programmers, here I am in my editor, what I want to do is now show you
1034.57 -> how to implement those depth first and breadth first algorithms. So we'll start with the
1039.02 -> depth first. And my goal is really just to build a function that will print out all of
1042.88 -> my values in the graph, according to a depth first traversal, right, we're going to define
1047.64 -> this function depth first print, making an arrow function in JavaScript, it's going to
1052.56 -> take in the graph, which is going to be given as a nice adjacency list. And this is actually
1056.37 -> the same graph. Now last example we traced out, I'm also going to need to specify some
1060.9 -> starting node here, I'll call it a source node, we're going to begin the traversal.
1065.91 -> Starting at that node. Cool. And so we know inherent to a depth first traversal is going
1071.88 -> to be a stack. So I'll show you how to implement this iteratively, which means you need an
1076.01 -> explicit stack. For me in JavaScript, that's as simple as just using a JavaScript array,
1081.2 -> right? I'll make it empty at the start. And I can use this array as a stack, if I just
1085.99 -> commit to using operations that manipulate the same end of the array. In other words,
1090.62 -> if I just use push and pop, that will always manipulate the end of the array, right? removing
1096.05 -> and adding to the end of that array. What I want to actually be sure to do is I want
1100.271 -> to initialize the stack with my starting node, that is with my source node. Remember that
1105.05 -> like a node here is really just designated by some character. Cool. And when it comes
1110.6 -> to designing like the main loop for the algorithm here, do you want to keep running the algorithm
1114.45 -> while the stack is not empty? In other words, wall stack dot length is bigger than zero,
1119.97 -> that I have to keep running. That's very reminiscent to what we expressed on the whiteboard. So
1124.64 -> when it comes to performing like a single iteration of this depth first, what I want
1128.19 -> to do is remove the top of my stack. So if I do stack dot pop, that will remove the last
1133.48 -> item of an array, in this case like the top of my stack, and also return it to me. So
1137.46 -> I'm going to save that to a variable, I'll call it my current. And so this point would
1141.34 -> actually be a great opportunity to just print out that current. So I'll console dot log
1145.68 -> current, right? So looking at, you know, this example over here, since I initialize a stack
1152.01 -> to contain just the source note of a, on the very first iteration, this while loop, I would
1155.66 -> of course, pop out a, then I would print it out, right. And from that point, what I want
1160.39 -> to do is consider A's neighbors of B and C. So if I want to look at like the array associated
1165.8 -> with a, I can just key into my graph, right, cuz my graph is an object right now. So if
1171.06 -> I say graph, square bracket, current, right, if current is a, that means graph, square
1178.05 -> bracket current would give me back this array. I want to iterate through every node or every
1182.51 -> neighbor in that array. So I'm going to nest a loop here. And I say for let neighbor of
1188.11 -> that array. So if you're familiar in JavaScript, if you just use a for of loop, they'll iterate
1192.4 -> an order through an array. So now I'm hitting a neighbor as B and neighbors see. What I
1198.361 -> want to do with those neighbors is simply Push them to the top of my stack. So that
1202.72 -> will just be stacked up, push and push this neighbor. Awesome, I'm going to be sure to
1208.75 -> push every single neighbor that has. So sometimes I'll have two neighbors. Other times I'll
1213.12 -> have one neighbor, or even no neighbors. That's really all there is to implementing a nice
1217.8 -> baseline depth first print. Something that I do want to point out, my favorite way to
1222.83 -> implement this algorithm is to consider like processing your node, when it leaves the stack,
1227.59 -> not when it enters the stack. In other words, I usually write like my print statement, right
1231.93 -> after something is popped. And the thing that I pop is exactly what I print. Right. So let's
1237.12 -> go ahead and give this a run, see what we get. It looks like in my terminal, I got the
1243.2 -> order of AC e b df, which you'll notice is slightly different from what I expected from
1248.89 -> over here. However, this would be also a valid depth first traversal, we have to bear in
1254.97 -> mind is you know, depending on like the arbitrary order of values within the same neighbor's
1260.47 -> array, you could tend a different direction at first, right? Most important thing I look
1264.43 -> for when it comes to verifying a depth first is to make sure that I you know, chase the
1268.47 -> same direction before switching directions, right. So since I started out with a C, so
1273.26 -> I go a and then to a C over here, the next move would be going to E and that's exactly
1278.61 -> what happened in my code, right. And then once I hit E is actually a dead end. So then
1284.32 -> I can go on to my other lateral neighbor like B, right. And so I can contrive the same order
1291.66 -> expected here, if I just flipped this right. And so I put c followed by B. I'll give that
1297.37 -> around. They're both valid. depth first traversals. See what we got now. Cool, now I get the exact
1303.93 -> order of A, B, D, F, C. And really think about why that is, right. So let's say that I just
1310.34 -> popped out a from my stack. So I printed out a that's nothing fancy, right. And then from
1315.14 -> there, I start iterating through the array that's associated with a right, so on the
1319.89 -> first iteration, I iterate through C, right? If I push C on the stack, let's say this is
1324.59 -> the bottom my stack, by pushing on the stack, it's right here. Then followed by that I pushed
1329.39 -> B on the stack. Now B is on top. Since B is on top, I know like the next top level iteration,
1335.34 -> this while loop, I would remove B and that's going to be the next note I visit. And so
1339.01 -> they're really both depth for sure Russell's. Nice. So two things to note, you're definitely
1344.69 -> going to use a stack to implement depth reversal. And you can use the stack in a few different
1349.02 -> ways. Right? So here I'm using like an explicit like array as a stack. And I'm implementing
1353.08 -> this using some iterative code, right. So using a few loops, right, what you can also
1358.05 -> do is implement depth first recursively, because I know any recursion uses the underlying call
1363.54 -> stack. So let me show you how to implement that as well. And when it comes to, you know,
1368.65 -> having all these different tools in your arsenal, I would definitely practice both the iterative
1372.79 -> and recursive flavors. We'll see that later on in this course. So let's say I wanted to
1377.48 -> solve the same problem. But now recursively, it's actually going to be less code. So I'm
1382.87 -> going to have the same sort of arguments, I'm going to have the graph which is the adjacency
1386.71 -> list as well as a source node, consider like the source node as like your current location.
1392.32 -> So if I'm at some node, maybe the first thing I should do is just print out myself, right,
1396.66 -> print out this node, so I'll do is console dot log, this source node. And that feels
1401.79 -> good just from the get because when we actually do a top level call to this recursive function,
1407.01 -> they're passing in a as the source node. So I do want to begin a as a first note in my
1411.42 -> print, and then from there, I need to look at AES neighbors. Well, if you want to look
1415.44 -> at as neighbors like before, just key into the graph, adjacency list using that node,
1421.43 -> right, and this would give me an array of CNB. Now I just iterate through that array.
1425.9 -> So I'll say for let neighbor of that array. And at this point, what I want to do is now
1431.47 -> do the recursion, right, so I make a recursive call on each of these neighbors. So for me,
1436.52 -> that means just called depth first print, you give the same graph, right, the graph
1440.72 -> object doesn't change, but you should change like the source node. Now you want to pass
1445.4 -> in that neighbor as the source node. And you're going to make a recursive call for every neighbor
1451.5 -> in that array. And this would actually be all we need. Let's go ahead and just run this
1456.6 -> version. divider run over here. Looks like now we get the order AC E, B, D, F. And that's
1464.75 -> really again, another type of depth first print, right, not exactly this order, because
1468.79 -> this time we chased c first, right, we went a C, I want to get exactly this ordering and
1475.22 -> my recursion, then I would have to put in B first, really same sort of pattern. Now
1480.64 -> let's get that into the run. Good AB de FC. One thing I want to bring up about this recursive
1486.47 -> first is it has no explicit base case, meaning there's no obvious like, if statement that
1491.4 -> just like returns like you'd typically see in most recursion. That's because in this
1495.32 -> problem I have an implicit base case when a node like he is a dead end. All right, let's
1501.28 -> say my current source coming in is he, well, then when I iterate in this for loop, I'm
1505.99 -> iterating through this empty array, I mean to have zero iterations. If you have zero
1510.12 -> iterations, then you never make a recursive call. Right? That's the same thing as having
1513.89 -> a base case, right? A base case is really just a scenario where we don't have a recursive
1519.04 -> call. So that's how this code still works. Alright, so now you know how to implement
1522.91 -> depth first in two ways, right, iterated and recursively. And they both use definitely
1526.58 -> a stack. Let me now show you how to implement your breadth first, right as well comment
1531.3 -> out some of this code. Now we'll do a nice breath first, give myself some room over here.
1538.79 -> So for a breadth first, we want to solve the swan iteratively. And it's really only possible
1543.78 -> iteratively, right. So I know a breadth first traversal demands a queue, if you try to like
1548.51 -> implement a breadth first traversal using some recursion, and under the hood, there's
1552.51 -> some stack data structure, that's going to fight against the queue order that you want,
1556.06 -> right? So for breadth first traversal, you're always typically going to be writing some
1560.07 -> iterative code. So some loops, right? Let me define this, I'll say breadth first print,
1565.97 -> take in the full graph, adjacency list, as well as the source node, I want to initialize
1573.07 -> my queue. With that source note, again, the queue here is just going to be an array in
1577.75 -> JavaScript. So I'll say const q equals an array that begins with just the source node.
1583.24 -> Awesome. And I'm going to use this queue by just committing to two specific methods on
1588.22 -> my arrays in JavaScript. So if I use array dot shift that removes the first element of
1593.7 -> an array. If I do array dot push that adds to the last position of an Array. And using
1599.66 -> those two methods in combination would give me a nice cue, right, add to one end and remove
1604.16 -> from the other end. So like before, we're gonna have a while loop, we're gonna iterate
1607.36 -> while our queue is not empty. And so while queue dot length is bigger than zero, nice.
1613.15 -> And same thing as our iterative, you know, at first, you want to start by just removing
1616.83 -> the front of your queue. So I'll say q dot shift, that will remove the first element
1622.01 -> as well as return it to me. So I can save in a variable, I like to call it current,
1626.42 -> just like the whiteboard, right? And from there, maybe I'll print it out. So console
1629.4 -> dot log, this current node. And from here, just consider your neighbors, right. So if
1635.01 -> I key into my graph, using this current node, that gives me an array of its neighbors, I
1641.16 -> want to loop through each of those neighbors. So I can say four will say let neighbor of
1645.44 -> that array. And for that neighbor, I want to add them to the back of my queue. So for
1650.5 -> me, that would mean simply q dot push, I'm going to go ahead and push that neighbor.
1655.65 -> Awesome. So I remove from the front, and I add to the back. So that looks pretty good.
1661 -> Let's go ahead and give it a run. And actually, before I do that, I'm going to change the
1664.23 -> order of this, put the CNB. Again, doesn't really matter the relative order for neighbors,
1669.33 -> I just want this exact output, and we'll talk about why that is right. Give that a run.
1673.92 -> So I get ACB EDF just like I expected ACB EDF, right. So let's say you're on the first
1679.48 -> iteration of this breadth first print, I know that I would have just removed a because I
1683.54 -> initialized a on the queue, right? So my current is a and I print out a and then from there,
1688.24 -> I start iterating through this array, right. So on the first iteration, I have C, that
1692.57 -> means I put c into my queue, right? And then afterwards, I put B, if you put C and then
1699.95 -> B, that means C is at the front of the queue, which is why on the second iteration, I have
1704.45 -> C first, right? So that's how you can manipulate potentially the lateral order of a breadth
1709.29 -> first print. Awesome. That's all there is to this traversal algorithm, what I really
1713.5 -> want emphasizes, especially if you look at the apples to apples iterative code, you compare
1719.991 -> depth first or breadth first, it's almost identical code. You're really just changing
1724.28 -> how you access items in your array, right? You either pop or push or you shift and push
1731.47 -> harder than that the whole like structure of this code is identical, right? All right.
1735.77 -> So that's our introduction on depth first and breadth first for our graphs. In the next
1739.78 -> section, we're going to start to solve a problem, right, which will be really fun. I'm just
1743.46 -> utilizing this code as our baseline tool. And then that section also promised that start
1747.22 -> doing the analysis for bego of these algorithms. So let's jump back to that whiteboard. Hey,
1751.99 -> programmers, welcome back, right, and let's go over the approach for this has path problem.
1756.85 -> So in this problem, we're gonna take in an adjacency list representing a graph for this
1761.38 -> problem, and really all graph problems, you definitely want to visualize this one with
1764.2 -> a picture. And so what we'll do is we'll interpret each key of this adjacency list as representing
1769.13 -> a distinct node. And if I look at any particular list, I can see that this f node should point
1775.88 -> to G and I. And they do tell us in this problem that I have a directed graph. So I'm going
1780.23 -> to draw arrowheads on these edges here. So F points to G, as well as f points tie. And
1785.84 -> I'll create similar edges based on the information in the given graph. So we end up with an image
1790.72 -> like this, until they tell us that this is a directed graph that explains the arrowheads,
1794.59 -> but they also tell us that this graph is a cyclic. So if you're unfamiliar, a cyclic
1799.34 -> just means No cycles, that kind of begs the question, what is a cycle in a graph. So a
1804.84 -> cycle would be a some path through nodes, where I can end up where I want started. In
1810.15 -> other words, if I started at the a node over here that I can go to B, then from there,
1813.84 -> I can go to C, then back to a, and so on and so forth. So if I did a traversal, on the
1819.39 -> Sigma graph, I would get an infinite loop. And what they're saying is, our graph input
1823.57 -> is guaranteed to be directed. So it has arrowheads, but also a cyclic, so we don't have to consider
1828.57 -> any infinite cycles here. That being said, In this problem, we also want to take in not
1832.98 -> only the graph information, but also a source and destination node, we want to do is return
1839.06 -> true or false indicating whether or not we can travel from the source node to the destination
1844.04 -> node. In other words, is there a path that exists between those two nodes? For this problem,
1849.29 -> you can use either a depth first or breadth first search to actually solve the problem
1853.31 -> here, I'll trace through in this approach video, just the depth first search. But in
1857.45 -> the walkthrough, I'll be sure to code it up both ways. So let's say started at my source
1862.66 -> node, I know that if I was doing a depth first traversal, I can either choose the IRG, let's
1867.72 -> say happen to choose to G next. Now I have no choice, right? If I'm doing truly a depth
1872.27 -> first, I should go deeper to the H. So then I hit this H. And as I traverse through these
1876.83 -> different nodes, I need to ask myself if my current node is equal to my destination. So
1881.4 -> far, that hasn't been true. At this point, I bottomed out with my h node, I can't travel
1885.39 -> any deeper. So now I can move laterally to a node like I, at this point from I can either
1890.4 -> move to a K or a G, let's say by luck, I just happen to go to the G, this would actually
1895.12 -> bring me down a path I've explored previously, which we can optimize later on, but wouldn't
1899.62 -> be too much of a big deal. Eventually, if I continued this depth first search through
1903.86 -> the graph, I would end up at a node that matches my destination, at which point I can return
1909.27 -> true signifying that there must be some path from F to k, just doing a depth first search.
1915.6 -> And as we do this depth first search, it's really important that you obey the directions
1919.65 -> of your arrows. So I should never try to travel upstream. So that was a scenario where we
1924.55 -> were able to find a path from source of destination. That's why we return true. Let's reset and
1929.62 -> say that now, I should return false. Alright, so let's say my source was J. So I start at
1933.95 -> J. And I'm trying to get to my destination of F. If I start a depth first traversal,
1938.62 -> here, sorry, my j node traveled to the AI node. At this point, I can hit either the
1944.06 -> G, okay, let's say I happen to hit the k, this point of bottom now. So now I can move
1948.05 -> to the G. And then from there to the H. And at this point, there's actually nowhere else
1952.64 -> I can go, right. So if I finish my traversal through the graph, using either a depth first
1958.09 -> or breadth first and I never hit my destination, then I can just return false, right? It must
1962.75 -> be the case that there is no such path from my source to my destination. When it comes
1968.41 -> to implementing the depth first and breadth first reversals on this graph, it's going
1972.17 -> to be exactly what we're used to, you can either use a stack and solve it recursively.
1976.32 -> Or you can do it iteratively. And use a queue in which case you'd be doing the breadth first
1979.77 -> traversal. We talked about the complexity of this, let's say that n is the number of
1984.51 -> nodes of our graph, a common thing that you can also do with these graph problems is define
1989.49 -> e as the number of edges here and edges refers to a connection between two nodes, basically
1995.09 -> just the arrows. So if we use these two terms of number nodes and number edges, we would
1999.22 -> have a time complexity of our V o of the number of edges as because we would have to travel
2004.93 -> through every single edge of our graph. Here, the space complexity would be based on the
2009.51 -> number of nodes, right? If I solved it, recursively, or even iteratively, with some sort of a depth
2014.48 -> first stack, then the worst case, I would have to have every single node on the stack,
2019.57 -> right? Likewise, if I saw the eternity with a breadth first I would have every single
2023.5 -> node on the queue. So that's just one way we can define the terms for analyzing the
2028.68 -> time and space of this graph. Typically, for graph problems, another acceptable way to
2033.07 -> analyze the time and space of your algorithm is to just use a single variable and just
2037.27 -> define n as the number of nodes. That's because if you say n is the number of nodes, then
2043.19 -> we can also say that n squared would be the number of edges, or that big O. It's about
2048.47 -> the worst case. So let's imagine the worst case graph. Let's say I just had these nodes
2052.53 -> of ABC. Well, if I wanted to create as many edges as possible, how would I just create
2057.06 -> a single edge? Well, an edge is just a connection between two nodes. So you could just really
2062.88 -> draw an edge for every pair of nodes in your graph, something like this. And that's why
2066.93 -> we can say that n squared is the number of edges of any particular graph. And so if you
2072.44 -> just wanted to use n to define the complexity here, then you could say that your time is
2076.28 -> going to be O of n squared, and your space complexity would still be O of n. Do know
2081.56 -> that these are both two valid ways for defining the complexity for a very typical graph problems.
2087.89 -> That being said, I think this is pretty straightforward. Let's hop into the walkthrough video while
2091.649 -> we're actually implement both a depth first and breadth first solution for these. I'll
2096.28 -> see you there. Hey, programmers, Alvin here, right now. Let's go over Ah, JavaScript solution
2100.72 -> for this has path problem. And so we'll jump right in, we're gonna start by solving this
2104.44 -> one using a depth first traversal, which I know requires some underlying stack data structure,
2109.7 -> I'll just implement that using recursion. So I can leverage the call stack to get my
2113.79 -> ordering. And so I'm gonna solve this recursively, I'm gonna consider my source argument as like
2119.11 -> my current position during the traversal. And so I can have a base case in check. All
2123.48 -> right, if my source is equal to my destination, that I must have found the thing I'm looking
2128.2 -> for. So just return true. This base case signifies that I found my destination. So there must
2133.07 -> exist a path. And so I return true, always paying attention to the type that they want
2137.25 -> us to return for this function. Let's say it's not true, well, they need to keep looking.
2141.62 -> So what I should do is consider my current node, which is source, consider its neighbors.
2146.59 -> If I key into my adjacency list, I know that this is going to be an object. So I key into
2150.55 -> it using my source, that would give me an array of all of its neighbors. So for example,
2155.09 -> let's say it was staring at this one, if my current source was F, and I say graph square
2161.55 -> bracket, F, I would get back an array of gi. So now I want to look through the neighbors,
2166.67 -> right? So I can see over here is turned us into a loop and say for that neighbor of those
2174.42 -> neighbors, I want to traverse to them, which means I call recursively. Right call has path,
2180.77 -> keep your graph the same, but update your current position. Now I'm going to be situated
2185 -> at the neighbor. And the destination stays the same, right, always have the same goal
2189.42 -> to get to solving this one recursively. So think about what type of this is going to
2194.46 -> return, I know it's going to give back Boolean, right, it's going to tell me whether or not
2198.24 -> there is some path between my neighbor and the destination, right. So if there's some
2203.58 -> connecting point, or some connecting path between my neighbor and the destination, then
2207.68 -> I know that there must be some path from my source to the destination, because your source
2212.42 -> is definitely next to your neighbor, right. So there would be a path between all of us.
2217.07 -> And so what I'll do is, check if this recursive call returns true, I'll make it explicit here,
2223.42 -> maybe it's clear. And so if there is some path through my neighbor to the destination,
2229.52 -> then I can return true, just pass that true upward. Because once I find a path, you can
2234.901 -> just exit out and return that shoe all the way back to the top level of color. But let's
2239.87 -> say that this call returned false, that means that there is no path through my neighbor
2245.261 -> to the destination. But it couldn't be the case that some other neighbor is actually
2249.32 -> going to work out. And so what I don't want to do is just say like else return false,
2253.52 -> you should be able to immediately catch that code like this as suspect because there's
2257.15 -> no point of having a for loop then right? If in either case, you're always going to
2260.74 -> return, then you're never going to have a second iteration of this for loop, right?
2264.78 -> So if I don't find a path through my neighbor, so if this call returns false, then that's
2270.67 -> okay. Just continue on to the next iteration, and search through your other neighbor. that
2276.17 -> begs the question, Where should we return false, needs to be after the for loop? So
2279.88 -> only after I searched through all of my neighbors, and I never find a winning path? Should I
2284.25 -> return false, and that'd be our nice depth first traversal. Let's give that a test run.
2289.79 -> Awesome. There we have it. One thing to bear in mind here, we are leveraging the assumptions
2293.69 -> in the problem, right, they tell us straight up that the graph is going to be given is
2297.56 -> a sick like, so there are no cycles. So that's why in our code, we didn't really worry about
2301.62 -> getting trapped in an infinite loop. In our upcoming problems, we'll have harder grass
2305.48 -> to actually deal with that sick case. But for now, this is a good baseline solution.
2309.75 -> While we're here, let's also do a reference solution, which you know, by now should be
2316.81 -> iterated, right, there's no way to do like a breadth first recursively. And so I need
2321.28 -> to create my own queue. So I can create a queue, kind of in a pinch, I always just use
2326.59 -> an array in JavaScript, I'm gonna initialize that queue with my source on it. So I'm gonna
2331.97 -> refer to like source and destination, they're really nodes. But in the context of like our
2336.02 -> problem, they're really just given us strings, but they represent nodes, right? So think
2340.25 -> about the information they represent. I'm going to iterate while my queue is not empty.
2345.7 -> So while q dot length is bigger than zero, should be familiar code, very similar to our
2350.02 -> tree algorithms. And I start a single iteration of reference by removing the front of my queue.
2355.25 -> So I can say q dot shift some of the front, I can call that my current node that I'm traversing
2361.35 -> through. And now that something has left the queue, typically here is where I check, I
2366.11 -> can check. All right, if a thing I just visited, if that is my destination, then I can just
2372.44 -> return true, right, I found the thing I'm looking for. So there must be a path that
2376.31 -> connects my original source and my destination. Nice. But let's say this was not true. Well,
2383.03 -> then I need to consider its neighbors. So like before, look at the neighbors just key
2388.28 -> into your graph using the source like it's a graph, square bracket source. That gives
2392.22 -> me an array of all of the neighbors, all the neighbor nodes. That's what I want to do here
2397.35 -> is iterate through every neighbor Over there. And then I can just add them into my queue.
2404.78 -> So q dot push that single neighbor, and do be sure to implement your true breadth first.
2411.48 -> So you need to make things leave from one end of your queue, and you add to the other
2417.04 -> end. So this codes looking good. So you should realize how similar This is to our old like
2422.45 -> binary tree breadth first, except now we have to account for the fact that we could have
2426.03 -> like a dynamic amount of neighbors here, not just dot left and dot, right. So I'm just
2431.6 -> iterating through all those neighbors adding them, I need to wait to return false. And
2435.93 -> you guessed it, the move is after you finish this entire while loop, if your cube becomes
2440.5 -> empty, then you must have explored as far as you could. And if you never return true,
2445.49 -> and now you can return false, because it must be the case that there is no path between
2449.11 -> the original source and your target. So let's give this a test run will have a very similar
2456.24 -> time and space complexity. But this would be the code for all of my iterative fans.
2461.15 -> So here I'm getting a little error. Let's see what we did wrong here. So it looks like
2465.81 -> I timed out here. Let's see bug this one together, I had to guess that means I did something
2469.89 -> wrong getting trapped in an infinite loop. This condition looks okay, right q dot length
2474.75 -> greater than zero. And so here it is, must be the case that I'm not correctly iterating
2481.42 -> through the neighbors here, I just wrote source. Instead, I need to say current, because now
2486.47 -> I'm doing this iteratively, right. So whatever node has just left my queue, I consider that
2491.55 -> nodes neighbors and add them to be visited next through my queue. So let's give that
2497.29 -> a test run. honest mistake there. Cool. And there's our breadth first solution for this
2501.93 -> has path problem. So what I want you to do is practice both the depth first and the breadth
2506.19 -> first, like you expect, we're going to do a lot of graph problems coming up. And depending
2510.77 -> on you know what the problem is asking sometimes will prefer one type of algorithm over the
2515.27 -> other. So it's really important that you practice both of these algorithms. Now, all the problems
2519.69 -> are relatively easy. So practice this, give it a shot on your own. And I'll catch you
2523.421 -> in the next problem. See you there. Hey, programmers, Alvin here, right. Now let's go over the approach
2527.52 -> for this undirected path problem. So we'll jump right in. In this problem, we're going
2531.4 -> to be given an edge list for a undirected graph. So if I are familiar with the terminology
2536.48 -> here, really what we're saying is every pair and this edge list represents a connection
2540.76 -> between two nodes. For example, if I look at the first edge, and the list, I see i comma
2545.61 -> j, that means that there's a edge or connection between i and j. And since this is an undirected
2550.82 -> graph, not only can I directly travel from i to j, but I can of course, move from j to
2555.91 -> i. So it really represents a connection in both directions. And so as we start to attack,
2560.79 -> this problem we'll want to do is actually convert this edulis into a more favorable
2564.76 -> format, like an adjacency list. That's because typically, when we perform our traversal algorithms,
2569.78 -> they work best on an adjacency list form. So let's start by doing that conversion here.
2573.95 -> And I'll actually be pretty easy to code up. So I want to basically generate a graph where
2579.11 -> I have nodes as keys, I want them to point to a an array of their neighbors. For example,
2585.71 -> if I wanted to convert the first edge into an adjacency list form, what I can do is create
2590.54 -> keys for i and j. Now that I is a neighbor of J, and also j is a neighbor of I, so I'm
2596.28 -> going to populate those neighbors respectively. Now just follow this process for another edge.
2601.29 -> So if I look at the edge, k comma i, I need to create a new key for K. And I'm going to
2606.38 -> populate that with I and then for the existing key of I, I just add k into that collection.
2611.22 -> So do bear in mind, the most important thing about this conversion is because we know that
2615.32 -> the graph is going to be undirected, whenever you put a connection within your graph, make
2620.971 -> sure that you have the inverse connection. So if I have an edge from k to AI, they also
2626.09 -> need to have information for it. Okay. And this process would just continue for the entire
2631.99 -> list of edges. And by the end of this conversion, we'll end up with an adjacency list just like
2636.68 -> this. And now we're ready to perform our main algorithm. When we go through the code walkthrough
2640.96 -> for this, I'll show you in depth how you can actually create this adjacency list. And so
2645.86 -> when we want to actually come up with a traversal algorithm to solve a graph problem, it really
2650.27 -> helps if you actually visualize the shape of your graph. So actually want to visualize
2654.77 -> this in terms of nodes and edges. That means a bunch of circles and lines between them.
2659.29 -> If you drew out a nice picture for this graph information, you would end up with a diagram
2664.02 -> like so. And so we'll go through the rest of this approach video just referencing this
2668.48 -> diagram. Something important I want to bring up at this point is for this graph, a very
2673.98 -> common case we'll have to handle is what if your graph has a cycle. And that's especially
2678.63 -> true for your undirected graphs. And so just for the purposes of this approach video, I'm
2682.91 -> going to add an additional edge just so we can talk about an explicit cycle. So I'm going
2686.95 -> to add one new edge from k to J. Cool. The reason is now there's a nice big cycle of
2693.23 -> length three highlighting in red right now. And this cycle is important to watch out for
2698.22 -> because if we don't do any special handling Then we may get trapped in an infinite traversal.
2702.77 -> So imagine I started at this keynote, and next I moved to J, then I would move to i,
2707.33 -> and then back to k, and then back to J, and then I, and so on. So now it gives me a cycle,
2712.36 -> we'll have to guard against that. And so I can have a cycle of three nodes here, right,
2716.67 -> and you can really have a cycle of basically almost any size, as long as it's more than
2721.07 -> one. So for example, if I took a look down here, notice that my graph actually contains
2726.4 -> technically like two separate islands, but we would consider them as just one giant graph,
2730.99 -> right? So I've got the small island of O and N, they actually form a trivial cycle, right?
2735.97 -> If I started traversal, at o. From there, I can move to n. And because I know that the
2741.29 -> edge between o and n is bi directional writes an undirected graph, that means I can travel
2745.64 -> back to O, and then back to n. And this would give me cyclic behavior. So have to watch
2750.801 -> out for all types of cycles in this problem. So in the context of this problem, not only
2755.13 -> are we given a graph, we're also going to take in a two nodes. So let's step through
2759.59 -> an example where I want to return true or false, is there a path between I and L. So
2764.33 -> I'm going to mark those in my graph Israel. So I'm going to start at the notify. And to
2769.71 -> solve this one, you can use any type of traversal. So either depth first or breadth first, I'll
2774.57 -> step through explicitly the depth first traversal. Right. Now, in order to avoid any infinite
2778.56 -> traversals, I want to mark my nodes as visited as I travel through them. So not only do I
2783.56 -> situate myself at this source note of I, but I'm gonna mark it as visited. And you can
2788.51 -> implement this like marking a visited pattern. And a few different ways. When we code this
2792.72 -> up later on, we're probably going to use a set to represent what we have visited. But
2797.131 -> for now, I'll just check them off in my diagram. And so in my diagram, if you see a checkmark
2800.88 -> next to a node, that means that I already have visited it. So since I'm at this node
2804.681 -> of I want to move to its neighbors, so I'm gonna move to the neighbor of J. And I'll
2808.81 -> also be sure to check it off as visited. At this point, I can move to one of Jays neighbors,
2814.119 -> let's say I move to k. And I'm also going to mark it as visited. Now then Matt K, I
2818.86 -> can move to a few different neighbors, I could either move to I LRM. Let's say by chance
2823.96 -> I chose I, I once I get to this, I know, I'm immediately going to be able to see that,
2828.82 -> oh, I visited this node previously. So what I should do is not travel through it again.
2834.86 -> Instead, I should go back to the K, right, because this eye node is already visited.
2839.68 -> And that's where I actually avoid the infinite loop. So instead, I moved to some of Kay's
2844.14 -> other neighbors, let's say I chose the L. At this point, I would mark it as visited.
2848.44 -> If I do a quick check, I can see that this note I'm at L is also my destination node.
2853.82 -> So I must have just found a path between my source and the destination. So at this point,
2859.1 -> if I find my destination, I can just return true, which was a pattern we spoke about in
2863.87 -> a previous problem, the only additional criteria we need is to mark nodes as visited. That
2868.94 -> way, we don't get trapped in an infinite loop. And that's only going to be needed if we have
2873.1 -> cycles in our graph, which if they don't give us any assumptions we should always guard
2876.89 -> against. So let's take a look at another example. Let's say I had a source of K. And my destination
2882.1 -> was Oh, just looking visually in the graph, you can already see that there's no way to
2886.47 -> get from k to O, because they're disconnected, right, they're on separate islands both step
2891.13 -> through the algorithm regardless, so I'm going to start at K gonna mark it as visited, I'm
2894.98 -> going to visit some of Ks neighbors. So I can move to i, then I can move to J. And then
2900.54 -> at this point, I would move back to K and really make sure they don't explore any of
2904.64 -> Ks visited neighbors, so I don't move back to I right, instead, I should move to an unvisited
2910.4 -> neighbor, like l market is visited, then I only have one other node to visit, which would
2915.3 -> be this m node. And at this point, I've actually exhausted this full graph region, right, there's
2921.08 -> nowhere else I can go. And once I finished my traversal, if I never find my destination
2926.63 -> node, then I can just return false, right? It must be the case that there is no path
2931.48 -> that exists from my source node to the destination node. That's really all there is to this algorithm.
2938.03 -> Let's talk about the complexity. If we say that n is a number of nodes, let's also define
2942.85 -> that he is a number of edges. Like we said previously, this is something typically acceptable
2947.43 -> to do for our graph problems. I know that the time complexity is going to be roughly
2952.39 -> of the number of edges. And my space complexity is going to be O of n that is the number of
2957.08 -> nodes. I think it's worth stepping through, you know what this complexity actually means,
2961.7 -> you know, big O refers to the worst case. So let's think about a worst case graph that
2965.54 -> we can have. And there are a few different graphs that you can kind of design and think
2968.75 -> of, I'll just show you one example. So let's say I was given a graph like this, right?
2974.32 -> Notice that although z is kind of on its own island, all of these nodes that is a three
2979.2 -> as well as a C note. They're all members of the same graph. So let's say I wanted to figure
2984.57 -> out is there a path between A and z. So if I did my traversal algorithm from here, I'll
2991.49 -> start at a then I move to B, and then to C, and then to D, and then to E. At this point,
2997.48 -> I've covered all of the edges in the graph. Remember that the edges are the arrowheads
3002.33 -> here, because I have to travel through every edge of this graph. That's why we said the
3005.13 -> time complexity in the worst case is going to be o of E, right o of the number of edges.
3010.98 -> and here we can say the space complexity is O of n. Because if you're doing this with
3014.619 -> either a depth first stack, or a breadth first queue, in the worst case, you would have to
3019.83 -> add everything you visited, or that is all of the nodes onto your stack or queue. That's
3025.44 -> why we say for regular graph traversal algorithms, we have a time complexity of o v, and a space
3030.33 -> complexity of O of n. All right, I think we have the approach for this algorithm down
3033.83 -> pat. At this point, I want to join me in the walkthrough videos, where we can actually
3037.55 -> see how to implement these visited patterns in some code. I'll see you there. Hey, programmers,
3043.88 -> Alan here, right. Now let's go over a JavaScript solution for this undirected path problem.
3048.95 -> So we'll jump right in, just like we said, in the approach video, there's going to be
3052.09 -> a two parter. First, we're going to convert our edge list into an adjacency list. That
3056.95 -> way, it's easier to do a classic traversal through it. So I'm going to pretend I had
3061.37 -> a helper function here. That gives me back an adjacency list. I'll call it graph. And
3065.65 -> I'm going to call this helper function, we'll say build graph. And if I pass it, just all
3071.109 -> of my edges, I want it to do that conversion for me. So let's work on that helper function
3075.68 -> right now. And then we'll jump back to undirected path. So I'll create my build graph function,
3083.35 -> just going to take in the edges, right. And I know I want my adjacency list to be in the
3089.04 -> form of a plain old JavaScript object. So create that graph object here. And I'm going
3095.43 -> to return it by the end just like this. And what I want to do is fill up this graph with
3102.869 -> information from the edges. So I'm going to iterate through every edge. So for let edge
3106.859 -> of edges, so iterating, through every single edge, I know a single edge would be a pair.
3111.78 -> So I'm just gonna de structure out of that, maybe just my two node identifiers, we'll
3117.24 -> call them a and b, from the edge. Nice. What I want to do is now initialize these nodes
3124.3 -> as keys of this graph object. So a would be something like this, I note or this k node,
3131 -> right. So what I'll do is check if A is in my graph, I think really clean up this code,
3138.68 -> we better if I check if it's not in the graph. So if the a node is not in the graph, then
3144.6 -> what I can do is initialize it in the graph. So use it as a key and assign it to be an
3148.88 -> empty array. And I'll do the same for B over here. Right, so I'm initializing A and B in
3155.6 -> the graph if they don't exist, and once I do that, then I can safely just add neighbors
3161.13 -> into their their edges, right? So I can say, the graph square bracket a dot push B. So
3169.02 -> now I'm saying that right, B should be a neighbor of a, but I know that this is an undirected
3172.99 -> graph, right? So that should be symmetric. In other words, then make sure you push a
3179.29 -> into the neighbors of B. So it's really important that you notice that this is an undirected
3184.78 -> graph. So your adjacency list needs to be symmetric in that way. So if a is in B's neighbors,
3190.63 -> B should also be an A's neighbors. So that's looking pretty good. Let's go ahead and see
3195.8 -> how that graph looks just with a little little side test here. So I must steal maybe this
3203.02 -> snippet, get that full snippet here, I could just run it manually love to make sure I can
3210.45 -> test these little helper functions before I use them. So we'll give this a run, we should
3213.69 -> just see the adjacency list form of these edges here. See how it looks. So that looks
3222.07 -> pretty good. So I'm seeing that all right, I is connected to J and K. Right? And that
3228.491 -> looks correct based on these edges. Awesome. And I'm also want to make sure that it's symmetric,
3233.4 -> right. So if i and j are over here that I should have JNI over here as well, right,
3238.31 -> it should be a two way street. Alright, now let's work in our real algorithm here, which
3244.33 -> would be some sort of traversal. Now that you have a nice adjacency list, you can do
3249.9 -> either a breadth first or a depth first traversal. I'm going to implement I think, a depth first.
3255.15 -> Typically for me, it's just easier to raise push if I do it recursively. And so I'm going
3260.39 -> to pretend I had a function called has path, it's going to take in my graph now. And also
3266.79 -> a start node and an end node. So I want to find a path from node A to node B, of course,
3272.55 -> I'm going to assume that this function returns a Boolean. But of course, I have to write
3276.75 -> that function for myself. So stay organized in our code, we'll say has path. I'm going
3281.7 -> to take in the graph as well as node A and node B. And I think a better name for these
3288.38 -> arguments as I'm doing this recursively. Let's call this one source and this one destination.
3294.14 -> So over time, we're going to call recursively and update this source node. And that should
3297.89 -> be a familiar pattern to some other problems resolved. Recently. So think about my base
3302.48 -> case. All right, I know that I've has successfully found a path when my source is equal to my
3307.68 -> destination node, if that's the case in return true, because I just found a path. Otherwise,
3312.44 -> I have to keep looking. So I should be able to look through the neighbors of my source
3317.38 -> node. So I could say graph square brackets source, right? Remember that any point through
3321.41 -> this recursion source represents my current position. If I say graph, square bracket source,
3328.109 -> let's say source was I, I'd be accessing all of ies neighbors, right? So I want to do is
3333.14 -> really iterates for let neighbor and, or rather have graph of source. So if sources I on the
3342.891 -> first iteration neighbor would be j, second iteration neighbor might be K. And for each
3347.8 -> of my neighbors, I want to travel to them. So call has path, you can keep your graph
3352.87 -> argument the same needs to change your source though now you're situated at your neighbor,
3357.3 -> and your destination is fixed, or you're always trying to get to the same exact node. I'm
3361.51 -> gonna think about what type this returns I know this is going to tell me Boolean, right?
3364.869 -> True or false? Is there some path from my neighbor to the destination, I'm going to
3369.52 -> check. All right, if that call, returns true, I'll be explicit here, then I've just found
3376.03 -> a path. So just return that true, right, pass it all the way back up. And kind of the logic
3381.861 -> that we form here is, I know that by definition, source and neighbor are definitely connected.
3388.119 -> So there's definitely a path between them. They're connected by a direct edge. So if
3392.351 -> my neighbor has a path to the destination, then I know, then the source also has a path
3397.61 -> to the destination. Awesome. And so after this for loop is done running, let's say we
3403.78 -> never find that any of our neighbors make a winning path, then means I finished this
3410.3 -> for loop without ever returning true, which means that I can return false right must be
3414.98 -> the case that this source node does not have some path to destination. So I think we can
3422.03 -> go ahead and give this code a test run. If you watch the approach video, you'll notice
3426.241 -> that there's something important missing from this code. But we'll just run it and show
3430.28 -> you how to fish here. So here I'm getting an error edges is not defined what I do horribly
3436.15 -> wrong, line 34 months ago, line 34 over here. So got to take out this call, don't need that
3443.25 -> anymore. That's on me. Let's get that test run. So that was not the error I was expecting.
3450.53 -> I am expecting some sort of an infinite loop, though. Perfect, I'm getting maximum call
3456.26 -> stack size exceeded. So I got like an infinite recursion really. And that's going to occur
3461.1 -> because we didn't account for the case where we have cycles in our graph, right, we need
3465.451 -> to avoid that. Because if I have a cycle in my graph, I'm never going to hit any of these
3469.96 -> base cases, I'm just gonna keep traveling around in a circle. And if that's unclear,
3473.71 -> make sure you watch the approach video, right. And so like we said, the move here is to add
3478.46 -> some sort of data that shows where you've been previously. Typically, the way we do
3483.6 -> this for our graph problems is to track some visited set. So when I make my top level call
3490.22 -> to this house path, I know that that is the actual function that does that traversal,
3494.24 -> I'm going to pass along a new argument here. And I'll make it a new JavaScript set. So
3500.23 -> if you're unfamiliar with sets, and JavaScript, they're really just a collection of items.
3504.51 -> And what's really great about a set is in o of one time, I can add something into the
3509.06 -> set. And I can also check for something within the set is going to be very, very quick for
3514.57 -> our traversal. I don't want to use something slow like an array, because to do a lookup
3519.15 -> or a check within an array, that would actually be O of n time, or it's for a set, it's o
3523.721 -> of one. So I'm going to make a new argument here to receive a column visited. What I want
3530.33 -> to do is all right check if my source node is already in the visited set to do that in
3535.849 -> JavaScript I can check visited out has. So if the source node is inside of the visited
3541.96 -> set, then I could return false here, right, there's no reason to travel through this node
3547.44 -> anymore. Because if it's an visited then I must have traveled at previously. And this
3550.64 -> is how I can avoid an infinite recursion can also move this line downward if I wanted to.
3557.1 -> And let's say that I make it through this if statement. So that means that all right,
3561.88 -> this node source has not been visited. But I'm visiting it right now. So I need to do
3566.82 -> visit a dot add source. So this expression checks if source is in visited, and this expression
3574.23 -> adds source to the visited set. I want to change a few other details here. Make sure
3579.44 -> that you pass along the same visited set through all of your recursive calls over here. Because
3584.251 -> you want this visited set to be like global for the entire traversal right I need to know
3588.47 -> exactly where I've been in the past. And once we have that in place, that should be everything
3594.3 -> we need to prevent any any cycles from giving us infinite recursion here. Let's give it
3599.891 -> a test run. Awesome. There's a solution for our undirected path problem. So important
3606.98 -> things to take away here do consider this problem, a two parter right? phase one is
3611.4 -> really straightforward, just converting an edge list into an adjacency list, which is
3615.31 -> actually an important skill to practice. Because when it comes to, you know, some problems
3618.75 -> you'll face in the wild, they are all going to be basically graph problems. But sometimes
3623.54 -> they'll give you the graph and like a different format, and you can always convert into a
3626.87 -> format that you're comfortable with. And from there, we have a really core pattern of just
3631.29 -> doing a traversal through a graph, but also guarding against infinite loops, right. And
3636.19 -> to do that, we just use some sort of a visited set. Hey, programmers, welcome back right
3642.98 -> now want to go over the approach for this connected components count problem. So in
3647.11 -> this problem we want to do is take an adjacency list representing an undirected graph. As
3651.62 -> always, with any graph problem, you want to start by visualizing the actual graph. And
3655.05 -> so if you took a picture of this information, it would end up looking like a graph with
3658.96 -> this structure. The first thing we should notice about this visual graph is that a has
3663.31 -> multiple connected components. So for example, I can look at this component in pink spanning
3668.77 -> just the one and two nodes, I can look at another component spanning the four or 5678
3673.88 -> nodes. And finally, a third component just covering the three node. And that's why we
3678.74 -> say that your result for your function here should be three, right? Because there are
3683.2 -> three different connected components. So let's come up with an algorithm we can use to count
3687.57 -> the components, we know that a general counting algorithm is going to use some variable, and
3692.38 -> we'll initialize that count variable to zero. And the trick here is to use a combination
3697.359 -> of both some standard graph traversal code, maybe a depth first as well as some iterative
3702.43 -> code. So I'll do along the left hand side is just list out all of my different nodes.
3708.11 -> And what I'll do is start by iterating, through every node of this list. And what I'm going
3713.95 -> to do is when I'm currently at some note of this iterative list, I'm going to start a
3718.38 -> traversal at that node. So right now starting at the node of one, I begin, let's say a depth
3724.22 -> first traversal, you can really implement this pattern using either a depth first or
3727.78 -> breadth first. So let's say I start at the one node over here. What I should do now is
3732.4 -> continue this traversal as far as possible, that's the key to victory here. So from this
3738.01 -> one node, I can move to a neighbor of two. And of course, as I travel through these nodes,
3742.92 -> I want to make sure that I mark things as visited, so I can avoid loops. And marking
3747.599 -> things as visited will also ensure that we don't double count any components here. Once
3753.69 -> I hit that to note, I've actually completed this full component, there's nowhere else
3757.869 -> I can explore. So at this point, I should increment my count by one. So whenever I complete
3764.33 -> a new traversal on some region of the graph, I need to increment my count. At this point,
3770.3 -> I now fall back to my iterative code on the left hand side, and I iterate through the
3775 -> next node. So I now look at node number two. If I take a look at node number two, I see
3780.33 -> that I already have it marked as visited. So that means I don't need to start a traversal
3785.68 -> at that node. So effectively skip the two and keep the count the same. next iteration
3791.359 -> I have a three, three is unvisited right now. So I should begin a new traversal starting
3795.64 -> at this three node, which means I just mark it as visited. And since this three is a singleton
3800.54 -> node, right, it's not connected to anyone, I would actually complete their traversal,
3804.15 -> just on the three node. At this point, I've completed a traversal. So I increment my count
3808.95 -> by one. So now I have a total count of two, I fall back to my iterative code. So I moved
3814.07 -> from the three node to the four node. And I see that this four node is unvisited, which
3818.72 -> again means I must begin a traversal from this four node. And I'm going to expand this
3824.69 -> traversal. Starting at four as far as I can, before I go back to my iterative code, right,
3829.51 -> so I'm going to explore the six, explore this five, explore the seven, and finally explore
3835.31 -> this eight. At this point, I've completed a traversal. So I can increment my count up
3840.49 -> to three. And then I have to continue and fall back to my iterative code. So look at
3844.81 -> the five node, I see that the five note is already marked as visited, so I don't start
3848.5 -> traversal. And I see that the six node, same thing don't need to start traversal seven
3853.07 -> note already visited, eight nodes already visited. At this point, I would be done with
3857.98 -> the entire algorithm. And there's my final count of three. So a few interesting mechanics
3863.25 -> here, right, you're going to need to definitely implement some code or some function that
3867.53 -> does a traversal through some component as far as possible, then you also need some iterative
3873.44 -> code just to potentially begin a traversal at every single starting point. And what you
3879.091 -> want to do is be sure to mark nodes as visited as you traverse them, because only when you
3883.34 -> marked a new node as visited and complete that traversal should you increment your count.
3888.39 -> You're probably wondering the exact details of how we implement this in some code, but
3891.74 -> don't worry, you'll realize that it's really just a spin off of our previous graph algorithms
3895.67 -> in the walkthrough video, but for now, we see that n is a number of nodes And he has
3900.52 -> a number of edges like usual, we know that this is really just traversing through the
3904.381 -> entire graph. So we can say the time complexity is just o v, and the space complexity is O
3909.19 -> of n, right, depending on whether you do a breadth first or depth first, you're going
3912.88 -> to use that space, then in terms of your stack or cube. And we can also consider using the
3917.619 -> space within our set if you use a set to mark your nodes as visited, but overall, it still
3922.94 -> will lead to a linear time and linear space solution. Alright, I think I'm ready to code
3927.2 -> this one up. I'll see you in the walkthrough video. Hey, programmers, Alvin here, right,
3932.71 -> now let's go over a JavaScript solution for this connected components count problem. And
3937.12 -> so we'll implement exactly the strategy we spoke about in the approach video. So make
3940.421 -> sure you watch that first, we know that this is going to require really two different mechanisms
3945.59 -> are going to need our interactive code just to hop to different connected components.
3950.55 -> And we also need some traversal code to just explore some single component as far as possible.
3957.69 -> And so what I'll do here is let me start with the iterative code. So I need to begin a traversal
3964.44 -> at every potential node. So I can say for let node of my graph really say in my graph
3971.72 -> here, because for this problem we're given looks like JavaScript objects. So if I say
3976.849 -> for let node in graph that would give me each of these keys like 015, and so on. And so
3982.98 -> for every node of the graph, what I want to do is begin a traversal. So we're going to
3988.48 -> assume I have a function here, I'll call it explore. I'm gonna pass in, of course, the
3993.2 -> graph, as well as that node. And what I want that function to do is do like a, we'll say,
3998.31 -> a depth first traversal, from that node as far as possible, right, so probably going
4003.831 -> to need to add more logic into this main function. But for now, I think it's about time to actually
4008.36 -> flesh out explore. So I'll choose to do this explore method recursively. So we'll define
4015.18 -> explore, it's going to take in a graph, as well as my current node, I'll just call it
4020.17 -> current, right. And then from there, I want to solve this one, using a depth first. So
4027.63 -> recursion is fine. And not much to do here, but really go through my neighbors want to
4032.599 -> iterate through every neighbor of this node. So I can say like neighbor of graph of current,
4038.29 -> I recall that graph would be an adjacency list. So if current is spread this out. So
4046.13 -> if current was a node like eight, then on the first iteration neighbor would be zero,
4051.57 -> next iteration neighbor would be five. So here, I'm just going through all the neighbors
4055.66 -> of my current node, I just need to not traverse to them. So I can call explore, pass along
4061.2 -> the same graph, that doesn't change. But now my new current node would be that neighbor,
4068.349 -> just like that, and this will perform the baseline of just the kind of depth first traversal.
4073.89 -> But we need to also mark things as visited, like we said, in the approach video, that's
4077.43 -> a really important a part of the solution. And I want this like visited set to be global
4084.44 -> for my entire traversal. So I'm gonna have to create it, maybe my main function over
4089.28 -> here. So I can create my constant visited, make it a JavaScript set, because JavaScript
4094.839 -> sets off for me O of one lookup, and o of one addition, I can pass this visited set
4100.489 -> my reference until all of these calls over here. So I know I'm gonna receive visited
4104.94 -> over here now. Now I want to actually start using visited. So a few things to note, right,
4111.349 -> I definitely want to use visited to prevent cycles, right? That's one of the main reasons
4115.449 -> we always had visited to our graph traversals. So some familiar code here. If I've already
4120.719 -> visited this node, so if visited, has this current node, then nothing much to do here,
4126.889 -> maybe just return false. Later on, we'll see. The really cool trick we use here by returning
4133.42 -> false, right, actually serves two purposes. return false because this might be a cycle.
4139.839 -> And then I need to make sure that I pass as visited set along over here as well. Nice.
4144.859 -> And let's say that we have a current node that is not visited. So this statement is
4149.009 -> false. Well, then, it seems to be that we're visiting this node right now. So now we should
4153.159 -> add it into the visited set. Nice. And then beyond that, we need to make sure that our
4160.69 -> explorer function is consistent in its type, right? So I'm going to have my explorer function
4166.329 -> do is it's going to return true whenever it explores like a new node return true. So if
4172.969 -> you take a look at this code, for my function to hit this line 17 return true, then it must
4180.48 -> be the case that it has already finished exploring all of its neighbors, right, because I know
4184.71 -> that this for loop does the job of exploring all of the neighbors, right? So only after
4189.719 -> all of those neighbor calls returned. Will I return true? And that must mean that I've
4194.9 -> explored this component as far as possible. Right? And that seems good to go. And what
4202.239 -> I can do is now in my main function, when I call explore it, now it's going to give
4206.639 -> me boolean data, right? If it's exploring a new island, or a new component, it's going
4211.099 -> to return true. So I can check. All right, if explorer returns true, then that's a new
4217.61 -> component. So I can probably increment some count here, I should have created. So I'll
4221.84 -> say 11, counts equals zero, I'm going to increment that count, when I find a new component and
4228.659 -> plus equals one by the end, I should of course, return that counts. And what you'll notice
4234.65 -> is, for scenarios where we, let's say iterate into a node that we already explored, when
4241.989 -> I make this call, I know that that call is going to return false, because if something's
4246.48 -> already explored, it would have been added to visited. So that's why I'm using some Boolean
4251.83 -> return values for this recursive function. So that code is looking pretty good. I think
4259.77 -> at this point, we might be ready to test this one, let's give it a shot here. So some pretty
4264.92 -> tricky codes, not very long. And this is a really core pattern here. Looks like I'm getting
4270.219 -> an error, we have something wrong here. So looks like the answer should have been two,
4274.08 -> but I gave back seven. So I'm counting way too high. So what I'll do to debug This one
4278.849 -> is really just maybe print out my visited. So this is a very common mistake in JavaScript
4286.559 -> want to bring in, I think this example, I could test it manually. What I want to be
4291.97 -> sure to do is maybe at every iteration of, let's say this this for loop, I console dot
4300.199 -> log with visited associate visited changes every time. And I'll run this manually by
4306.97 -> just hitting run. And let's see what we get here. So a few things to note, it looks like
4316.19 -> some of our keys, or some of our items of the set are strings or the zeros a string.
4320.94 -> And other times they're actually numbers, notice that they're missing quotes, that has
4324.96 -> to do with, you know, kind of just JavaScript objects, technically, keys of a JavaScript
4329.249 -> object are going to be always converted as strings, although the data within these arrays
4335.26 -> over here is going to be number. And sets can actually store both types. And so if you
4340.179 -> have like two different types, it's not gonna be able to figure out like that those really
4344.209 -> represent the same node. For example, looking at this visited set over here, I have like
4349.32 -> the number one, as well as the string of one, which is no good. So let's just convert them
4355 -> all to maybe strings. So I'll check visited if it has the string version of my current
4362.01 -> node. So I'll just do the conversion for me. And likewise, I want to add the string version
4367.36 -> of the current node over here. That way, I have very consistent types. So let's run that
4374.429 -> manually, again, should just see all of our strings now. Awesome. And I think we can run
4380.6 -> all the test cases. So that's a really important thing to watch out for in JavaScript. And
4385.429 -> JavaScript is pretty unique in that regard. It just automatically converts all of your
4389.179 -> keys into strings. Awesome. All right, programmers, it's all I got for this connected components
4394.139 -> count problem, what you want to do is really practice this problem. It's actually a very,
4398.749 -> very common interview question. And there are many variations of this problem that we're
4403.17 -> going to do in the future. Hey, programmers, Alvin here, right? Now I want to go over an
4409.159 -> approach we can use for this largest component problem. So in this problem, we're going to
4413.01 -> take in a graph, just like we've been doing as of late. And the first thing you should
4416.429 -> probably do is think of this graph as a picture. So hopefully, you drew it out. So you can
4420.15 -> really understand what this is asking. Our graph information is already given as an adjacency
4424.429 -> list. So it's pretty easy to draw out. So since I have a graph like this, the first
4429.26 -> thing I should notice is it could contain multiple components, right. So here, I kind
4433.89 -> of see two separate islands, two separate components. And I want to consider the sizes
4438.449 -> of each respective component. So if I look at my first component, spanning the nodes,
4442.849 -> 015, and eight, I know that they have a size of four, they're the four represents the number
4447.909 -> of nodes within that component. So I'm really interested in a number of nodes have a component,
4453.099 -> not necessarily the number of edges. If I look at the other component that spans the
4457.61 -> nodes, two, three, and four, that definitely has a node group of three. And this problem
4463.039 -> really cares about the largest component, so I should just return four, because it's
4467.059 -> the largest component size. So when it comes to what this question is asking, you do have
4472.409 -> some familiar patterns if you've been following these problems in order and of course, I always
4475.989 -> recommend that you do these problems in order. So how can we go about solving this one? Well,
4480.13 -> I know I'm gonna need some sort of iterative code that way I can travel and hop to different
4485.099 -> components or different islands, I can probably do some depth first traversal variation that
4489.659 -> also finds the size of a connected component. So let's step through how this algorithm might
4494.929 -> run. On the side. I'm going to list out my nodes to represent how I'm going to do the
4498.949 -> iterations to be In a traversal at every node as my starting point, so I'm going to start
4502.699 -> at node zero. And since node zero is unvisited right, now, I'm going to begin a brand new
4509.03 -> traversal, starting at node zero. And I'm going to mark my nodes as visited as I go,
4514.3 -> because like usual for our undirected graphs, you want to watch out and prevent any cycles
4519.289 -> that you may get trapped in. And I know that this depth first traversal, is going to explore
4523.599 -> this full region as far as possible. And by the power of recursion, it'll be pretty easy
4528.73 -> to implement some pattern that can count every node as we traverse through it. So I'm going
4534.13 -> to treat each of these nodes as just being a single note, of course. And eventually,
4538.36 -> those ones are going to return to my top level call, in which case, I can add them all up,
4542.829 -> getting me a grand total of four. If this feels very hand wavy, and you're wondering,
4547.44 -> like how the heck are we going to code up that pattern, don't worry, it's actually a
4550.76 -> pattern we've seen before. And so I'll cover that in detail in the code. Just know for
4555.209 -> now, it's actually not a big deal to get the count of nodes, right. So now that I know
4559.9 -> that the size of this component is four, what I should do is I guess store it as my current
4564.409 -> largest island or component I've seen so far, because it's the first component that I've
4570.34 -> considered. At this point, I should fall back to my intuitive code. So I look at the node
4573.889 -> of one, what I should notice is this node one is already checked off, it's already visited.
4579.749 -> So there's no reason to start another traversal from this node, because if it's visited, that
4584.739 -> means I have already explored the component that node one is a member of, so I can basically
4590.159 -> skip it, go on to node two in my iteration, since node two is unvisited, I should begin
4594.82 -> a new traversal. Over here, I know that this depth first traversal is going to explore
4599.249 -> that component as far as possible, it's going to go ahead and count all of those nodes as
4603.59 -> one. And eventually some of those counts together, giving me a count of three. And so this next
4609.099 -> component has a size of three, I need to compare that three against my current largest four,
4614.349 -> obviously, the four is bigger, so the four gets to stay as the largest. When I fall back
4619.5 -> to my iterative code, I get to my note of three threes already visited, so no reason
4624.429 -> to start anew. traversal, four is already visited, so nothing to do, five is visited.
4629.409 -> And of course, eight is visited as well. At this point, we're done looking at every single
4633.699 -> node within our graph, and we must have explored every single component, so we can just return
4638.92 -> the final value that we have stored in that largest variable. Awesome. When it comes to
4644.3 -> the complexity of this algorithm, it's pretty straightforward. It's basically exactly all
4648.849 -> of the algorithms we've seen so far, we see that n is the number of nodes and e is a number
4652.969 -> of edges, we know that the time complexity is going to be roughly o of the number of
4657.749 -> edges really just exploring through the entire graph, we can also see that the space complexity
4663.55 -> is also going to be linear, really just O of n. Because through all of this, we're probably
4667.729 -> going to be storing all of our nodes in a set right to track visited. And depending
4671.869 -> on how you implement your traversal algorithm, whether you use depth first or breadth first,
4676.17 -> you're also going to use a linear amount of space through your stack or your queue. So
4681.05 -> overall, we're looking at a very efficient, linear solution. And so with that, I think
4685.729 -> I'm ready to code this one up. What I want you to do though, first is possibly give this
4689.349 -> one a shot on your own first cluster, really just utilizing some code that we've seen in
4693.56 -> the past. So give it a go on your own. If you get stuck, you can find me in the walkthrough
4697.25 -> video. I'll see you there. Hey, programmers, Alvin here, right now let's go over a JavaScript
4703.619 -> solution for this largest component problem. So this problem is going to be really just
4707.789 -> a spin off of our last problem. So we'll hop right into it. And as always, make sure you
4712.139 -> watch the approach video first. And we'll start by building our code that will help
4716.989 -> us start a traversal on disconnected islands here, right? This is connected components,
4721.929 -> we should say. And so I'll start my iterating through every node of the graph, that means
4727.67 -> I just iterate through the keys of my input object here. Because remember, we're given
4732.469 -> this graph as already an adjacency list. So I can say for let node in the graph. So I'll
4739.31 -> give me the nodes like 015, and so on. And what I'll do is I'm going to start a traversal
4747.039 -> here, right? So we're going to pretend I had a function, I'll call it explore size. And
4751.909 -> if I give it the graph information, as well as the node that I want to traverse through,
4756.749 -> hopefully, it actually does a traversal through that entire connected component, right. And
4762.25 -> what I'm going to assume is, let me assume that this function actually returns the size
4768.11 -> of that entire component. So that would be a number right, representing the number of
4772.039 -> nodes in that component. And so if I have that should receive it here, call it size.
4778.17 -> And I know I need some like max value logic for this entire for loop. So I'm going to
4783.139 -> create longest, initialize it to zero. And then from there, I can check. All right, if
4788.42 -> the size of the component I just found, if it's bigger than the longest, then I can replace
4794.53 -> the longest simply longest equals size, that after the for loop, I would just read Turn
4801.179 -> the longest course I need to write this explore size function. So I'll implement this as a
4808.03 -> type of depth first. So I'm going to make it recursive, as for size, taking the graph,
4812.929 -> as well as our current node. And a few things I should watch out for here, they tell us
4820.469 -> that we have an undirected graph. And so we need to make sure that we avoid any cycles.
4826.21 -> So we're also set up here is some classic structure, I'm going to use a visited set,
4831.929 -> we're going to use a set because it gives me O of one lookup and o of one insertion.
4836.86 -> So now that I have my visited set, I can pass it along, as I start the traversals. And now
4842.88 -> let's work on a base case, as well do to get going is check if I visited this node already.
4849.099 -> So if the visited set already has this current node that I need to return, basically avoid
4855.13 -> a recursive call. But I also want a consistent type here, right, so I'm assuming that this
4859.56 -> function gives back a number representing the size at some point in my traversal. If
4863.65 -> I get to a node that has already been visited, that means I counted it already. And so I'll
4868.15 -> treat it as zero right now, because I don't want to double count my nodes, right otherwise
4872.559 -> would be inaccurate here. And now beyond that, what I can do is maybe create a variable here,
4877.539 -> I'll call it size, I'm going to set that equal to one to represent the current node I'm on
4883.119 -> right now, right? If this condition is not true, then it's the first time I'm seeing
4886.929 -> this node, so I need to count it. And we'll also be sure to do is add it to visited that
4893.059 -> way I don't get into a cycle into the node later on. Nice. And at this point, I need
4899.479 -> to make my recursive call on the neighbors of this node. So like we usually do could
4902.86 -> say for let neighbor of graph of node. So remember your shape of data here. So if node
4910.489 -> was a key, like five, when I say, Neighbor of graph node, that would iterate through
4917.679 -> the neighbors a five, zero, and then eight, and so on. And so here, I make my recursive
4923.26 -> calls, I'm gonna call the same function explore sighs, pass along the same graph. But now
4928.15 -> you're situated at your neighbor, and you can provide the same visited set. And here's
4932.42 -> where I do my recursive leap of faith, right, I'm going to assume that this explore size
4936.699 -> function is working. So if it was working, what would it give back, it would give me
4939.619 -> back a number representing the size of that graph, right beginning at my neighbor. So
4946.09 -> whatever number I get back here, I just want to increment my size by that, right. And that
4952.179 -> would accumulate a basically a count of all of the nodes in this fully connected component.
4957.23 -> And after I'm done exploring my neighbors, I would have explored the entire component
4961.96 -> fully. So I can just return my final answer, which would just be the size over here, really
4967.89 -> important thing you need to do is make sure if you follow this kind of strategy, you start
4972.24 -> your size equal to one, and you add to it over time, because this one represents the
4976.789 -> current node that I'm at, I know that every call is going to count its own node. So over
4982.25 -> time, this will actually accumulate everything I need. So feels pretty good, have our nice
4987.32 -> visited logic. And we already wrote our main function here. Notice how we're splitting
4992.289 -> up this code in a nice little helper function here, I think it's the best way to express
4996.729 -> this, it's very similar to some previous problems that we've done. Right, I think at this point,
5002.42 -> let's go ahead and give this a shot. See, what we get, should be able to put it through
5006.38 -> a few different test cases. Nice. And there, we have the largest component to problem.
5012.07 -> So a few things, I want to draw your eye to remember that for your graph problems, or
5015.15 -> you have disconnected components, you're going to need not only your traversal code, but
5020.381 -> some just iterative mechanism, usually just a loop to make sure you can hop to different
5025.639 -> components, right? Because if you only had your regular like traversal function, by definition,
5031.82 -> there is no edge between separate components. So you would never be able to explore the
5036.63 -> full graph. Otherwise, alright, programmers practices, and I'll catch you in the next
5040.46 -> one. Hey, programmers, Alvin here, right. Now let's go over an approach we can use for
5044.639 -> the shortest path problem. So here we have another graph problem, and your graph is going
5048.55 -> to be given as an edge list. So the first thing we should probably do is, of course,
5052.51 -> visualize this graph. And in the context of your code, it probably would be best if you
5055.92 -> convert it into an adjacency list. Since we've seen that pattern a few times in some recent
5060.829 -> problems. I'll leave that part to you. But we're going to end up with a graph that looks
5064.699 -> like this. And in this problem, we're also going to be given a two nodes here, let's
5069.219 -> say W and z, what I want to do is return the smallest path between these two nodes. And
5076.929 -> here I have two obvious paths, right? One way I can get from W to z would be to go through
5081.179 -> x and y. And there I can see that that path length would be three. Do note here that we're
5086.369 -> going to consider the path link as the number of edges within the path. So not the number
5091.11 -> of nodes, right? So that means how do I calculate three here? What's really just three lines,
5096.199 -> right, three edges. That's one way to get from WC another obvious way to get from W
5101.119 -> to z would be to go through VI, which case, I would only need to use two edges. So that
5106.271 -> path line is of course two. And this problem, what I want to do is return the smallest possible
5111.52 -> path length. So I should return the final answer of two here. So we know that this problem
5116.17 -> is going to require us to do a graph pathfinding algorithm. The question is, which one should
5120.139 -> we take, we either can choose, of course, a depth first traversal, or a breadth first
5124.53 -> traversal, I'll cut to the chase here. And both of them would actually give you a strategy
5128.889 -> that works, meaning you can solve this with either a depth first or a breadth first strategy.
5133.499 -> But maybe one of these algorithms would be better than the other. So let's consider the
5137.949 -> possibilities. So let's say I had some large graph, well think abstractly right now. So
5142.54 -> kind of just looking at an abstract example. And let's say I was stepping through some
5146.32 -> depth first traversal. Let me say I have my starting node in yellow, and I'll have my
5151.07 -> target node in blue. So what I want to do is, again, figure out what's the minimum path
5156.36 -> distance between these two nodes, obviously, you know, just in the long run, you should
5161.249 -> get an answer like two here, right, because two is definitely the shortest path between
5165.269 -> these two nodes. If we did a depth first traversal, I know that depth first would force me to
5170.439 -> look in one direction as far as possible, until I have to switch directions, right.
5175.48 -> So for my starting on yellow, let's say we move to the right, that'd be one edge and
5178.769 -> move to the right again, two edges move to the right, again, three edges. At this point,
5182.37 -> I can't move right anymore. So let's say you move downward, so at 456 have to switch directions,
5188.209 -> again, seven, eight. And at this point, we kind of already see that this is going to
5192.019 -> end up possibly getting to the blue target node. But that wouldn't be the shortest path.
5198.34 -> Something unfortunate here is although my star and nodes are really close together,
5201.92 -> a depth first traversal could be unlucky in that it may search in a totally wrong direction,
5206.67 -> and snake all the way through the graph until it eventually finds my target node, at which
5211.239 -> point I definitely don't have the shortest path. So I think a breadth first traversal
5216.579 -> is going to be more useful here. So let's say start at my green node, still my same
5220.539 -> starting point. And if I did a breadth first traversal, I know that breadth first means
5224.749 -> I'm going to explore all the directions very evenly. So it would look like this. So I would
5231.862 -> explore all nodes one edge away from my starting point. And then from there, I would begin
5238.179 -> to explore all nodes two edges away from my starting point. And at some point, I'm going
5243.57 -> to hit my target node. And if it's the first time I'm seeing my target node, then by definition,
5249.039 -> I must have just found the shortest path, right, the shortest path would just be two.
5254.23 -> So that's my high level argument for why a breadth first search is going to be more useful,
5258.21 -> in my opinion, for this problem, let's step through this process a little more algorithmically.
5263.679 -> So let's say I had my original graph. And if I'm gonna do a breadth first traversal,
5268.309 -> I know that I have to use a queue right no matter what a queue is what gives you that
5272.239 -> breadth first order. And what I'll do is eyes the items of my queue, I'm going to store
5277.34 -> not only the nodes, but also the distance from my starting point, that means I'm going
5281.9 -> to initialize my starting note on the queue along with the distance of zero. And that
5287.019 -> represents the fact that all right, that note of W is zero edges away from the starting
5291.409 -> point, because it itself is the starting point. So at any point in time, the items of my queue
5297.01 -> are always going to be pairs, right of node comma distance. So now we're going to begin
5301.92 -> our general algorithm, I'm going to keep iterating. While my queue is not empty, a single iteration
5306.969 -> of breathless would remove the front end of my queue, and I'll label it as my current
5311.86 -> node. At this point, I should check Alright, is my current node of W, the thing I'm looking
5316.59 -> for? It's not, so I need to explore W's neighbors. So I can look at the x node. And I know I
5322.011 -> need to add it into my queue. But when I add it into my queue, I want to make sure I tag
5326.989 -> it with a distance. So if my current node has this zero, I know that a neighbor of this
5332.869 -> node would have distance one, so I just increment the current distance by one. So onto my queue,
5338.449 -> I put an item that says x comma one. And I have a similar scenario for this V node. It's
5343.619 -> also a neighbor of W. And so I put v comma one on my queue as well. At this point, I
5349.9 -> can go to my next iteration, or move the front of my queue. So I look at the x. And then
5354.699 -> I look at X's neighbors do bear in mind that because I have an undirected graph here, x
5359.77 -> really has two neighbors, right, it has w as a neighbor, as well as y. So something
5364.309 -> you should already know is I need to track visited. In other words, when x is going to
5369.08 -> consider its neighbors, it should really only care about the Y, right, I don't want X to
5374.269 -> put w back on the queue, because then I would get an infinite cycle. So I'm just gonna look
5379 -> at the Y over here. I'm going to add it to my queue. Because I know my current note of
5383.739 -> X has a distance of one y must have a distance of two always just incrementing the distance
5389.249 -> by one. Cool. And then I carry on with this algorithm. I removed the front of my queue
5394.59 -> now, which would be the V note. And at this point, I can consider V's neighbors, and I
5399.849 -> do See that one of its neighbors is actually the Xena, that's the only unvisited neighbor,
5404.369 -> I'm going to be sure to add z into my queue and tag it with a distance of two, right,
5409.3 -> because if my v has distance one, its neighbor would have a distance of one grader. At this
5415.05 -> point, you can already see how this algorithm is going to work out. Eventually, this z nodes
5419.67 -> going to leave the queue, and that would actually be my target node. So since I've added a node
5425.17 -> into the queue that matches my target, I know I have my final answer. The two here does
5429.969 -> represent the number of edges we took in that logical path. And I would, of course, just
5435.59 -> return that too. So for the most part, this algorithm just sounds like a classic breadth
5440.499 -> first traversal. Using a queue on a graph, the only interesting bit is now we're also
5444.719 -> going to track the current distance. You know, when it comes to counting the length of a
5448.84 -> path, you need some counting mechanism. And so if you begin your queue with your starting
5453.729 -> node with a distance of zero, every time something leaves a cube, and adds its neighbors, it
5458.381 -> should increment that distance by one. And like you already guessed, this algorithm is
5462.53 -> pretty efficient, because we don't have to traverse through the graph more than one.
5466.28 -> So we'll see that this has a linear complexity. Alright, I think I have everything I need
5470.699 -> to code up this one, I'm sure you're wondering about these implementation details. So what
5474.659 -> you want to do is possibly give this implementation a shot on your own. And if you need some help,
5479.119 -> you can find me in those walkthrough videos. See you there. Hey, programmers, Alan here,
5484.639 -> right. Now let's go over a JavaScript solution for the shortest path problem. So we'll jump
5489.28 -> right in, hopefully, you watch the approach video. And so we'll start by converting our
5493.139 -> edge list input into something more useful for our traversal like an adjacency list,
5497.489 -> we're going to write a very classic function. When I call it build graph, like you expect
5502.42 -> it takes in the edges. And I want it to return an adjacency list. For me, that means a JavaScript
5507.86 -> object, I'll call it graph, by the end of this function, this will help I'm going to
5512.57 -> return the graph and some common code, I'm going to iterate through every pair, right,
5518.789 -> basically every edge, I'll say, for left edge of edges. As I'm iterating, through every
5524.219 -> edge, when I want to do is unpack that edge into its component nodes, I'll call it a and
5532.01 -> b. And now I can start formatting my adjacency list. So I know I want the keys of this graph
5539.699 -> to be obviously the nodes, I want the values to be an array of the neighbors of that node.
5546.25 -> So what I'll do is, it's the first time encountering a node, I'll check. Alright, if this a node
5552.639 -> if it's not in the graph yet as a key, then I should create it for the first time. So
5559.41 -> use it as a key and initialize its value to an empty array, basically, at the start is
5564.579 -> going to have no neighbors. Likewise for B. And then, at this point, I know that A and
5571.739 -> B now definitely exist as keys within the graph. And so I just want to add those neighbors.
5577.439 -> So if I have an edge, like w comma x, I know x is a neighbor of w, and w is a neighbor
5582.849 -> of x. So simply put in say, graph a dot push B, and then just the inverse of that should
5591.369 -> be good to go. Cool. So that should give us our graph. Let's go ahead and use that in
5596.56 -> our main function now. So we'll just say graph equals build graph on the edges. And what
5602.849 -> we want to do now is actually work in our breadth first logic, like we said from the
5606.869 -> approach video. So a few things I'm going to do, I'm going to definitely set up my queue,
5612.229 -> we said that the key to victory here was to not only store the node in your queue, but
5617.791 -> for every like frame inside of your queue also store its distance from node A. So I'll
5623.459 -> just use like a pair of things. So the elements of my queue are going to be always a pair.
5628.059 -> And I'll throw on the initial node A, and also the number zero, because at the start,
5633.249 -> right, this node A is zero edges away from itself. So that's good to go. And over time,
5638.929 -> I'm going to be incrementing. This number, it seems nice. And so let's keep on keepin
5645.249 -> on here. All right, a while loop, classic condition would be all right, while your queue
5650.139 -> is not empty, then I shall remove something from the queue. So always remove from the
5657.619 -> front if you want to follow a true breadth first order. So I can do do dot shift. And
5662.869 -> that will give me back an array or give me back one of these sub arrays here. I know
5667.61 -> it's always going to be a pair so I can just unpack. And I'll just say alright, grab the
5672.409 -> current node as well as the distance. Nice. I'm going to check the node here that I just
5678.469 -> removed from the queue. If that node is node B, that I must have just found a path and
5685.249 -> I know the distance in that path, I can just return it. But if this condition is not true,
5690.709 -> then I need to keep searching through my graph. Since that means I need to add this nodes
5696.13 -> neighbors to the back of the queue. So I'm going to iterate remember that we have adjacency
5700.63 -> lists the entire time. So I'm going to say, for, let's say, Neighbor of graph of node.
5708.539 -> So get all the neighbors of this node. And what I'll do is just add those neighbors into
5715.13 -> my queue. So q dot push, neighbor, try to remember what the form of our graph is over
5721.889 -> here. Maybe as a quick little spot check, make sure on the same page, let me just console
5727.639 -> dot log, the adjacency lists, let's say we took this example manually, just paste it
5733.829 -> down below. And I'll just give it nice little manual runs, I'm not running the test cases
5739.869 -> quite yet. So we converted this edge list into this adjacency list, right. And when
5748.06 -> we say no to something like W, when we say graph, square bracket, no, that would give
5753.32 -> us this array, co authored sorters, iterating, through all the neighbors of this node and
5759.17 -> adding them to the queue, one thing we should watch out for is when we push things back
5763.949 -> onto the queue, we want to maintain the same format. So I actually still want to maintain
5769.11 -> pairs. So I'll make the first element of the pair, the neighboring node on the second element
5774.11 -> needs to be the distance. And since it's a neighbor, its distance would be plus one over
5780.719 -> here. So that's how I'm growing and counting the distance. So let's give this a test run.
5787.059 -> There are a few things we need to work on still, though. But we'll pass a few of these
5790.689 -> examples, at least until we timeout on a particular example. One thing this code is missing is
5796.949 -> any cycle prevention, right? I know that it's going to be a very common scenario, because
5802.4 -> I have an undirected graph, right. And so what I'll be sure to do is maintain a visited
5807.519 -> set, sort of pattern that you're used to, we're just gonna implemented for our iterative,
5811.559 -> breathless right now. So start out with a set. And when you do this iteratively, the
5817.84 -> move would be to make sure that if something is added to the queue, it should also be marked
5823.82 -> as visited. So if I initialize my queue with node A, then I also want to initialize my
5829.409 -> visited set with node A, just like so. So if you're unfamiliar with the set constructor
5836.479 -> in JavaScript, if you want to initialize it with some values, you actually have to pass
5840.499 -> in an array containing those values. So the values of my visited set are just going to
5844.889 -> be the nodes write the node IDs. Cool. And then I want to work that logic into my while
5852.039 -> loop. And so whenever I'm about to add something into the queue, that is, I'm going to add
5858.739 -> a neighbor into the queue, first check if that neighbor is not visited yet, so only
5863.28 -> if not visited has neighbor. Right, so only if this neighbor has not yet been visited,
5872.329 -> then I should add it to my queue. And if I'm about to add it to the queue, like we just
5876.479 -> said anything that interest, the queue should immediately be marked as visited. So here
5881.09 -> I'll say visited, add, the neighbor net should avoid adding any particular node more than
5886.619 -> once into the queue, avoiding any cycles. Awesome. So that feels pretty good. Let's
5893.309 -> give that a test run. Now. We hope to not timeout at least, all that same example, we're
5901.199 -> actually returning undefined where we expect negative one. So if you look at the actual
5906.059 -> prompt, they tell us that, alright, if you can't find a path between A and B, then you
5910.5 -> should return negative one. Let's look at an example or test 04. And you kind of drew
5916.849 -> it out, you would see that there would be no such path that connects B to G. The reason
5921.36 -> we're returning undefined right now is we're gonna finish our traversal mean, meaning our
5926.26 -> queue is going to empty out. And then we're just going to hit the end of this function.
5930.579 -> And if I don't hit a return line by default in JavaScript, I'm going to get undefined.
5935.13 -> So we know if we finish the while loop, and we never found node B, then we can just return
5941.099 -> negative one, that must mean that there is no such path that connects a to b. So let's
5946.65 -> give this a test run. Now. This should be our final version of our shortest path algorithm.
5951.9 -> Awesome. So be sure to practice this algorithm before you move on. And do make sure that
5956.559 -> you understand the choice of breadth first here over depth first, for most of your basic
5961.84 -> just graph problems that require you to calculate a shortest path path meaning just the number
5967.08 -> of edges. Typically, you'll find breadth first easiest way to calculate that hey programmers,
5973.04 -> Alvin here, right now let's go over to the approach for this island count problem. So
5978.119 -> in this problem, we're going to be given a 2d array representing a grid of land and waters
5982.8 -> here we have l characters representing land, and W characters representing water. Let's
5987.78 -> try to visualize this. In this problem we want to do is return a number representing
5992.86 -> the number of islands on the grid. We're going to consider an island as a vertical or horizontal
5998.16 -> connected region of land. So in this particular example, we should return four. Because there
6003.25 -> are four different islands, we can label them as such, this is going to be any type of problems
6007.849 -> for us. And we should really think about it as if we have a graph, I'm going to refer
6011.369 -> to these style problems as a grid graph. And so although we're not given any explicit like
6016.03 -> nodes and edges, I can still think about positions of this graph as nodes. So for example, let's
6022.019 -> consider the indices here. So I have my row indices along the left hand side, and my column
6026.829 -> indices along the top. And I can designate any position of this grid using a pair of
6032.719 -> row and column. So for example, if I looked at position three comma four, that would be
6037.459 -> this position over here. And what I should do is mentally think about a position as if
6042.739 -> it's a node. And if I met some node, I do have some potential neighbors. given any position
6049.13 -> of the spread, I have at most four neighbors in the up down left and right directions.
6055.4 -> given any position of the grid, it's really easy to determine what our potential neighbors
6058.919 -> are, it's really just a matter of adding or subtracting one from either the row or the
6063.34 -> column. Let's generalize this formula. So let's say I was at some position, we'll call
6067.82 -> it our see, if I want it to go upward, that would mean you decrement, the row by one,
6072.309 -> keep the column the same. If you went down, that would mean increasing the row by one,
6075.809 -> if you went to the right, that would be increasing the column by one. And if you want to go left,
6079.249 -> then you should just decrease the column by one, do bear in mind that the top left position
6085.179 -> of our grid is going to be 00. And that's why we have this type of arithmetic rule.
6089.67 -> So now that we're starting to frame this grid problem, as if it's a graph, we can use some
6093.23 -> common patterns, I know that this problem is really asked me to count the number of
6097.53 -> connected components or the number of islands on this grid. So I'm going to need some iterative
6102.84 -> code, probably some nested loops to just iterate through every potential Island and start some
6107.599 -> traversal at that island. So when it comes to our iterative code, we just want nested
6111.719 -> loops to iterate through every row column. That means the iterations should look something
6115.229 -> like this, just moving left to right. until we finish around which case we can go to the
6120.579 -> next row. Let's actually iron out the main logic that we need in our algorithm. So let's
6125.76 -> say we start or nested loops from the very beginning, what I do is check my current position,
6130.34 -> what I want to do is check if my current position is land right now it's water, so I can just
6134.869 -> continue. On the next iteration, I do have some land position. And since I'm on a piece
6139.659 -> of land, right now, what I want to do is explore this land region as far as possible, probably
6144.71 -> using some depth first traversal. And do bear in mind, like most of our undirected graph
6149.63 -> problems, we're going to need to be sure to mark things as visited, so we don't get trapped
6152.959 -> in any infinite cycles. So for example, if I started a traversal, at this position, I
6158.039 -> can go downward. But I can also go upward from here. And I can bounce back between the
6161.59 -> two going up and down, giving me an infinite cycle. So we know how to fix this using all
6166.42 -> of our graph mechanics, right, just use a visited set. So if I do a depth first traversal,
6171.199 -> starting at this position, I know I'm going to mark off all of these land pieces as visited.
6177.809 -> And what I also want to do is make sure that I increments accounts, representing the fact
6182.62 -> that I've just explored some new island fully. So right now, my count zero, since I just
6187.769 -> finished exploring something now my count is one. And at this point, I can fall back
6191.88 -> to my iterative code to scan for another island. So I move to the right, it's water. So continue,
6198.139 -> water continue. Now I have another island. And again, I just do some depth first traversal
6202.489 -> through it. And of course I increment my count. This pattern will follow right? Eventually,
6208.729 -> when I hit the new row, I could be at a land position. But I should also make sure that
6214.239 -> this land position is unexplored, right. So since I'm at position one, comma zero, and
6219.959 -> this land has already been explored, I don't need to begin a depth first traversal. And
6224.56 -> I also don't need to begin a traversal here. And this continues, avoiding starting a traversal.
6230.55 -> Wherever I have a visited piece of land, we know eventually, we're going to hit a new
6234.919 -> island like this one, where I have a piece of land that is unvisited. So at that point,
6240.179 -> that's my criteria for starting a new depth first traversal, I explore this region, increment
6246.08 -> my count, and continue business as usual until I hit this final island that is unvisited.
6251.3 -> And so I visit it and increment my count. And by the end of my iterations, I should
6255.619 -> have my final count of four. So that logic is actually pretty straightforward, just a
6260.45 -> variation of our classic connected component, counting logic, except now we're adjusting
6266.249 -> the criteria we use for looking at neighbors, right, our neighbors are actually going to
6270.719 -> just be either above downward to the left or to the right of our current position. We
6276.37 -> talked about the complexity of this algorithm, we should consider the size of the input and
6280.079 -> the fact that it has two dimensions, right? So if I say that R is a number of rows, and
6284.559 -> C is a number of columns, well and the iterative codes pretty straightforward, I know that's
6289.65 -> going to give me r times C iterations. And if I also consider any potential in depth
6295.729 -> first traversal I do starting at some land. In the worst case, I could have one Giant
6300.38 -> Island, which is also going to be our time to see. So the overall complexity, it's just
6305.15 -> going to be our time See, the space complexity for very similar reason is our time see, because
6310.079 -> imagine that we mark all of these positions as visited, that probably means we'd have
6314.209 -> to add them to some set. Right, so we have our time see different positions. And by the
6318.61 -> end, I could add each and every one of them into my set, the space complexity of our time.
6323.439 -> See also includes any traversal related data structures like stacks, or queues, depending
6328.499 -> on how you implement this one. So overall, this is going to be a very efficient solution
6332.46 -> to solve this one, what you should do is probably give it a shot on your own first, if you get
6335.979 -> stuck, you can find me in the walkthrough videos. I'll see you there. Hey, programmers,
6341.669 -> Alvin here, right now, let's go over a JavaScript walkthrough for this island count problem.
6345.669 -> So as always, make sure you watch the approach video first. And we'll jump right in. So we
6350.36 -> know that this is really just a spin off of our kind of graph connected components problems,
6355.76 -> except now we have a grid graph, right? I can still think about like this grid as if
6359.84 -> it's a graph, because if I think about any particular position of this grid, I know I
6364.881 -> have some neighboring positions that I can travel through mainly, my four neighbors Up,
6369.489 -> down, left and right for me, let me start my laying down some iterative code that can
6374.289 -> begin a traversal at every node or every position of this grid. That way, I can start considering
6379.989 -> different islands, right. So I'm going to use just a for loop for this, I'm going to
6384.34 -> iterate through every possible row column combinations every position. So I'll say R
6388.929 -> equals zero, iterate up to the length of the grid, so grid dot length to our plus equals
6395.909 -> one, and do something very similar for my columns nested inside, right? Watch out for
6401.26 -> some details here though, looking at the examples, we can't actually assume that we're always
6406.76 -> get a square shaped grid square meaning like as if the number of rows was the same as the
6411.499 -> number of columns, because sometimes I'll have like an asymmetric grid occasionally,
6416.119 -> right? If I look at this very first one, it looks like the width is going to be five here,
6422.079 -> but the height is six. So separately for the columns, I want to reference the column lines
6428.159 -> over here. So we're gonna say grid, zero length. Nice. And so at this point, I have some row
6434.75 -> composition, I want to begin a traversal, let's say a depth first traversal at that
6439.75 -> position. So here's where I invoke some like helper function, that will make it a little
6443.03 -> bit, I'll call it explore. And what's going to do is, of course, taking the grid information,
6449.079 -> as well as the row column I want to traverse through nice. And at this point, I think we'll
6454.53 -> actually hop to building this this helper function, then we probably need to fill out
6459.38 -> some more logic within our main driver function here. So let's bake this explore helper function.
6469.32 -> So taking the grid and your row column, and something I should also consider is because
6473.449 -> I know that this is really a type of graph problem, right? I want to prevent infinite
6477.73 -> cycles, right? So consider this, let's say I was somewhere in the middle of my traversal,
6482.13 -> let's say I was at this piece of land, I know that this piece of land is going to travel
6486.3 -> through its right neighbor. And it could be the case that this piece of land now travels
6490.409 -> its left neighbor, so I go left and then right and then left and right. Now it gives me an
6494.71 -> infinite loop, right. So whenever you have this notion of like undirected graph or undirected
6500.179 -> connections, then always guard with a visited set. We've seen this pattern before. So maybe
6506.09 -> up top globally, for the entire traversal, I'll create a visited set. So in JavaScript,
6512.119 -> just a new set, you're probably wondering, you know, what am I going to make the members
6517.079 -> of this set? Well, I need to designate positions, right? Think about it as if positions are
6522.11 -> like the nodes in this grid in this graph, right. And so what I'll do is pass along this
6529.86 -> visit set, so I can accept it as an org over here. And when it comes to using your visited
6535.719 -> set, what you want to do is make sure you combine your row and column because together
6540.469 -> they designate your actual position. I think this is actually worth going through specifically
6546.42 -> more of like a language thing in JavaScript, compared to other programming languages. So
6551.539 -> quick aside over here, let me get myself some more room might be a while. Because if you're
6557.8 -> unfamiliar with sets, and you don't kind of know, their nuances, might actually hit you
6564.219 -> in the butt later on. So let's say I had a set so I'll create an offset. So can you set
6571.88 -> and let's say I added I don't know, like an array containing a row column position. So
6576.34 -> I'm gonna say is, alright, maybe I had position, I don't know, one comma three. And I added
6581.619 -> that into my set. So I do s dot add that position. This is actually a common gotcha in JavaScript.
6587.739 -> If you put any like reference types, like an array or like an object into your set,
6593.519 -> it's actually going to check for reference equality when you check for existence later
6597.8 -> on. In other words, now I can't really do console dot log s dot has one three, because
6606.719 -> this array literal is technically a different array in memory. So I wish I could get like
6612.309 -> true back in this scenario, but I'm not going to get a true. So we'll just run that manually
6616.999 -> see what we get. So like, we say, we're gonna get a false here, which is not so good. So
6622.869 -> instead, your Fix would be to actually convert this into some string data. So instead, maybe
6628.289 -> write as if you had one comma three, because strings are primitive types, and I would actually
6633.38 -> be able to store that string. So whenever I say the string literal, this would actually
6638.03 -> give me a match now, so I should get a nice true here. Awesome. So we'll want to use that
6644.639 -> pattern to our advantage. And so maybe I'll start by creating some position variable,
6650.63 -> that's going to be like the string of FIDE a version of our position. So just take my
6654.61 -> row, maybe add a comma, and also put the column here. Nice. And the reason I want to comma
6662.63 -> separate is, I need to have different bounds for my row and column. In other words, imagine
6668.76 -> I had a row of let's say, 12. And I had a column of four. If I turn that into a key,
6677.13 -> or a position, that would give me position as looks like 12, comma for another scenario,
6683.349 -> let's say I had row one, and then column 24, that would give me a position of this right?
6692.329 -> one comma 24. Right, it's really important that you put a comma to separate your row
6696.94 -> and column positions, because imagine, I didn't put the comma, then it would have a collision
6702.36 -> here, I have two totally distinct positions, right? 12, four, and 124. And if I don't put
6707.639 -> a comma, they look like they have the same position key. So that's why I need to comma
6712.399 -> separate them. Common gotcha there. But now that I have this position, I can use it to
6718.13 -> my advantage in this visited set. So if I've already visited this position, so if my visited
6726.059 -> has this position, then I should exit, right, I need to return something. And I want this
6731.38 -> explorer function do something similar, like we've done in our old component problems,
6735.659 -> I want it to return a Boolean indicating whether or not this is a new island that I'm exploring.
6741.07 -> So if it's visited already, that's definitely not new, right. So just return false, meaning
6745.051 -> it's not a new island. If I make it past this if statement, in other words, if position
6749.559 -> is not in visited, that I need to mark it as visited right now, second, do visited,
6754.479 -> add this position. So now I have my core like cycle prevention logic. Beyond that, I have
6761.229 -> a few other scenarios, we know that in our traversal, we're going to look at our different
6765.489 -> like neighbors. And so what I want to do is make sure that I'm in bounds here. So I'm
6769.869 -> going to check, like to split this up into variables, I'll say, one, a boolean variable
6774.57 -> called row in bounds. And I'll do is just check if zero is less than or equal to the
6780.86 -> row. And that row is strictly less than will say, the length of my grid. So I'm just checking
6788.889 -> to see if my opposition is in bounds here, I do a quick check, I need to be inclusive
6795.08 -> with zero because zero is a totally valid index, right? I need to be exclusive with
6800.019 -> the length because imagine I had a grid with length five, it's last valid index is four.
6804.889 -> So I need to be strictly less than here. And I'll write a similar variable for my column
6810.11 -> in bounds, just like this. And at this point, I can write a nice semantic if statement check,
6818.9 -> all right, if your row is not in bounds, or your column is not in bounds, then exit, right?
6826.96 -> So return like before I can return false, right? Because I should not consider like
6831.899 -> an invalid position and a balanced position as an island, right? So that's looking good.
6838.849 -> Final base case I need though is, what if my current position is water, right? I only
6844.059 -> want to do my traversal through land. And so I'll add another statement for that. So
6850.06 -> up here, I can check. All right, if my grid at row column, if it's equal to water, then
6856.719 -> also return false. No reason to count it, it's really important that you put this in
6861.159 -> bounds check before you index into your grid, right? Because imagine that your row and column
6867.48 -> were out of bounds. If you write line 15 like this, immediately, you're going to get an
6872.07 -> out of bounds error. So start with your guard to check if you're in bounds if you want it
6876.889 -> to because most of these conditionals they all return false have the same consequence.
6881.929 -> You can probably or them together. Typically I like to keep them separate. That way I always
6885.809 -> remember to write them typically for like your grid graph problems. This is very canonical
6890.699 -> code. Alright, so if I make it past all of these base cases, and I have the recursive
6895.88 -> case, so I must be at an unvisited piece of land. And when I want to do is do my depth
6901.78 -> first traversal, right. So here's where I explore my neighbors and I have four neighbors.
6907.469 -> If I wanted to go above that I decrement, my row by one, keep the column the same, pass
6912.829 -> along the same visited, because remember, we have like the array indices here. So this
6917.789 -> is row zero, this is row one. So we'll lower row numbers mean upward, in the same way,
6923.869 -> lower column numbers mean to the left. So this is up, this is down by do just minus
6932.349 -> one over here, that would be to the left, then plus one on the column would be to the
6937.399 -> right. Cool, and I can keep this code very flat as it is something that I'm a huge proponent
6944.649 -> of when you write recursion, for the most part, I always try to make sure that I don't
6950.539 -> look before I leap. In other words, just from this logic alone, it couldn't be the case
6955.76 -> that row minus one is out of bounds. But that's okay. Because if it's out of bounds, when
6960.809 -> I evaluate this call, it's going to immediately be caught by this base case, right. And if
6967.179 -> I express my logic like this, if I don't look, before I leave, if I just leap and then catch
6971.169 -> myself with the base case, you don't have to write repetitive code. In other words,
6975.849 -> some people write code like this, where it's like, Alright, if row minus one inbounds kind
6981.34 -> of using pseudocode. Here, they would have to write row plus one inbounds. And you would
6986.28 -> have to write a guarding if statement around every recursive call, instead, just write
6991.28 -> one base case. And you can catch all of these different out of bounds, right. So that's
6997.449 -> why I prefer it this way. And so I know that by the time I return out of these recursive
7004.119 -> calls, I'm back at this segment of my code. And what I can do is return true because I
7010.169 -> must be finished with that traversal. And the reason I'm returning true is true symbolizes
7015.749 -> that I've just finished exploring a brand new island, so I need to count it. Nice. It's
7021.199 -> also consistent with the data type, I have Boolean for this explore function. So for
7026.939 -> the most part, this looks like really just a spin off of our previous like graph, depth
7031.48 -> first code. And now I want to use that boolean data in my main function here. So here's where
7036.949 -> I can actually count my islands. So guess I really need some logic here that says initialize
7042.3 -> some counts equal to zero. And whenever you find a new island, increment that count. So
7048.51 -> if I just have found a new island, we're going to get back true from this this call, right?
7053.219 -> Because remember that I'm beginning a traversal, starting at this row column position. So if
7058.409 -> it gives me back true, then I can totally increment my count by one. Notice that whenever
7065.449 -> I begin a traversal on a position I've seen before, it would have been added to visited
7070.8 -> before. So I would return via this if statement on line 21, I return false. If I return false,
7077.77 -> then I don't double count that island. So I do need a combination of both iterative
7084.949 -> code to potentially leap to different islands. But I can use a visited set to prevent myself
7090.229 -> from double counting any particular Island. So this is looking pretty good. Let's not
7095.8 -> forget to of course, return our counts at the end. Let's give this a run. This will
7103.079 -> probably be the first in a series of these like grid graph problems. Really try to understand
7109.11 -> how we can think about still a grid as if it's a graph, right? We just have different
7113.03 -> rules for how we look at our neighbors. Right? Now, a node is really a position and its neighbors
7118.219 -> are its four neighbors Up, down, left and right. Alright programmers, I want you to
7122.099 -> practice this pattern because we're going to see it in the next few problems. I'll leave
7125.8 -> it to you see in the next one. Hey, programmers outlane here, right now let's go over an approach
7132.459 -> for this minimum Island problem. So we're going to be given here a grid containing a
7137.519 -> water inland really just some characters inside of our grid. So of course, as always, let's
7142.3 -> visualize this. And what I want to do in this problem is return a number representing the
7146.34 -> minimum Island size, we're going to consider an island, a connected region of vertical
7151.69 -> or horizontally connected pieces of land. So for this particular input, our answer should
7157.169 -> be to looking at our grid, I have three separate islands. And they all have different sizes,
7161.439 -> right? sizes, a four, two and five, I just choose the smallest of the islands. So that
7166.399 -> would be the two over here. So how can I actually come up with a strategy for this one, you
7171.36 -> should already know that this is just a spin off of our previous a grid graph problem,
7175.77 -> where instead of doing just a count of the number of islands, now I want to find the
7181.169 -> sizes of islands. I know to actually look at different islands, I'm gonna need some
7186.11 -> nested code, but I'm also gonna need some depth first traversal code to explore a single
7191.209 -> Island. So overall, this should be a pretty classic strategy for us. So let's say we start
7196.489 -> attacking this we know we're going to begin our nested loops in the top left corner And
7201.439 -> if our current position is water, then we actually don't need to do anything. next iteration,
7205.84 -> I have some land. At this point, I could begin on my depth first traversal. And I know that
7210.739 -> I should be marking things as visited to avoid any infinite loops, right. So by the time
7216.219 -> this traversal completes, I'm going to mark all of these guys as visited. But I also wanted
7221.41 -> to determine the size of this entire island region. So every time I get a position that
7226.89 -> is land, I should treat it as one. And then when it comes to how I implement on my traversal,
7232.409 -> I can just gather up these ones, right, just add them all up. So that would look something
7236.71 -> like this. And for my top level call for that traversal, I should get an island size of
7244.389 -> four. And so if that kind of traversal algorithm, especially how we compute the size of the
7249.459 -> island, is pretty hand wavy, don't worry that when we actually go through the code walkthrough,
7253.429 -> it's just a matter of some recursion, and some recursion we've actually seen before
7257.399 -> in past problems of the course. But any case, now that I have this island size of four,
7262.119 -> it's actually the first island that I've seen. And so I'm going to consider it the mid size
7266.349 -> so far. But I need to keep looking in case something is smaller. So move to the right.
7271.01 -> So if it's water, I do nothing, water again, do nothing. Now I have another islands, I
7275.659 -> begin my traversal market these as visited. And when I find the size of this island, of
7280.32 -> course, it's going to give me two, I compare that to to my current mid size two is smaller,
7287.369 -> so I store two as the mid size so far. And we just continue business as usual. Note that
7292.649 -> when we get to a piece of land, we really want to make sure that it's land, but also
7297.349 -> a piece of unvisited land. So right now on that piece of land, but it's visited, so I
7301.8 -> should not wear I don't need to start traversal here. Likewise, for this position. Eventually,
7307.909 -> I'm going to hit some new unvisited land, in which case I should begin my traversal
7312.3 -> at Explorer, this region, and I want to count up all of these pieces of land. And I should
7318.149 -> realize that the final size of this island would be five, I can compare that five against
7324.26 -> my current min, five is bigger, so the size of two gets to stay. And I can just end up
7329.09 -> returning the minimum size by the end of this algorithm, basically representing this island
7333.989 -> of size two, the complexity of this algorithm is straightforward, we should say that the
7338.459 -> size of our input is r times C, because we have our rows and C columns, in which case
7344.489 -> a time complexity is simply our time C, right, we have to iterate through every row column
7349.84 -> within the grid. And even when we begin a traversal, in the worst case, we could have
7355.59 -> an island that spans the entire grid, in which case it would also be our C. Right. So overall,
7362.229 -> our full complexities are time c space complexities are time C as well. And do know that this
7367.719 -> is technically a linear solution in the size of the grid, right because the grid itself
7372.749 -> is exactly r times C positions. So with that, I think we're ready to code this one up and
7378.38 -> try it on your own first. And if you get stuck, I'll catch you in the walkthrough videos.
7382.01 -> See you there. Hey, programmers, Alvin here, right now let's go over a JavaScript walkthrough
7387.76 -> for this minimum Island problem. So we'll jump right in, make sure you watch the approach
7391.929 -> video. As always, this is just a nice spin off of our classic island hopping logic. But
7397.18 -> for a grid graph, right. And so let's start with the iterative code that can help us begin
7402.07 -> a traversal. Starting at every different position of our grids, that just means some nested
7407.309 -> loops. So start by iterating through all of the rows and columns. So r equals zero, go
7412.63 -> up to while r is less than length of the grid, also do our plus equals one and very similar
7420.019 -> loop for my column. But do make sure that you reference your inner column line because
7426.659 -> you could have like a rectangular shaped grid over here. And what I want to do now is begin
7432.679 -> a traversal starting at every row column. So I'm going to assume I have a helper function
7437.739 -> here that does that traversal, I'm going to call it explore size. That's because in the
7442.769 -> long run, I'm interested in the size of that island, right, so like a number representing
7446.5 -> how big or how many positions that island spans. So I'm going to pass along the grid
7451.689 -> information as well as the position. And I know when it comes to all of these like undirected
7457.849 -> graph, traversals should probably guard against your loops. And I have some foresight here.
7462.17 -> So I'm going to pass along a nice visited set, which I can maintain globally for the
7466.149 -> entire traversal because there's only a good reason to explore a position once right. So
7471.719 -> I'll create const visited gonna make it my neighs JavaScript set. And a few reasons for
7476.82 -> that. Well, for one JavaScript set, gives me O of one lookup, but also o of one insertion.
7482.349 -> So it's going to be a really quick data structure to use. And from there, we probably have to
7487.78 -> add some more logic over here to actually do something with the size but for now, I
7491.33 -> think I'm going to switch gears and actually take a look at building this helper function,
7496.53 -> right. So I think the best way to build this traversal is to use is a deaf purse, typically
7501.76 -> just my go to for problem like this, it's going to take in I know the grid, the row
7507.449 -> in the column and also visited, I need some a base case is very classic base cases, I'm
7512.71 -> going to start by checking if this row column position is inbounds. So my favorite pattern
7517.399 -> for that is to split up in some variables just makes it easier to read and debug. So
7521.43 -> I'm going to say is my row inbounds and just make that like a boolean variable. So I'll
7526.719 -> check if, let's say, zero is less than or equal to the row, I need to say and right,
7535.76 -> and that row should be strictly less than the grid length. So this Boolean would only
7543.51 -> be true if it's in bounds, right? And something very similar for my column bounds should be
7550.61 -> between zero and grid zero length. Nice just like this, I believe. And then I can write
7559.8 -> a nice if statement using both clauses. So I can say, all right, if let's say your row
7565.38 -> is not in balance, or your column is not in balance, then you're definitely at a bound.
7572.34 -> So you should probably use some base case here, right? So we're all choose to return
7576.28 -> here is zero, because I want to keep a consistent number, right consistent return type. That
7581.53 -> is, I know that this function has a kind of goal of returning the size of the explored
7586.079 -> islands sizes a number. So even in my base case, I need to make sure I return some type
7589.829 -> of number, returning zero to represent that, hey, if this is out of bounds, it's not going
7593.849 -> to contribute anything into the count of the size, right, which is good to go. I need some
7599.149 -> other base case here. What if my position is inbounds. But what if it's actually water,
7604.459 -> I don't want to count that as well. I only want to count islands. So land right. So quick
7609.369 -> fix, what I'll do is add a new base case, I can check if my grid at row column, if it's
7616.519 -> equal to the water character. So a capital W can also return zero. If you want it to,
7623.639 -> you can also maybe merge these into like a single if statement, just write a bunch of
7627.659 -> ORS, I kind of like them separate because it's just easy for me to remember what each
7632.169 -> of them does write a final conditional have here is alright, if I make it past both of
7637.869 -> these base cases, it might be the case that this position is land, but it's land I've
7643.619 -> already visited. So here's why I work in my visited logic, I'm going to represent a position,
7649.17 -> like we said in the last episode as really just a string. So I can put it as the members
7654.919 -> of my visited set. So I'm going to say position to have to be the row plus a comma plus the
7661.229 -> column. So just representing the position, that's because I can't add like an array into
7667.679 -> a visited set, and then look it up later. And so if visited has the position, then it's
7673.8 -> a duplicate position that I've explored. So return zero. Otherwise, it's not been visited
7679.19 -> yet. So I must be visiting it right now. So I can add it. Nice. So I have my base cases
7684.739 -> laid down. Now I'll need my actual recursive code. So I'll explore my four neighbors. By
7690.16 -> now you should be familiar with this pattern. So go upwards, a row minus one column pass
7694.889 -> on the same visited. So I'm going to explore my up down left right neighbors respectively.
7699.969 -> And I do my recursively buffet theory, right. So what type do I expect back from these calls,
7703.869 -> they're going to give me back a number representing the size of the island that my neighbor is
7708.849 -> a part of. But if my neighbor is part of some larger Island, then I am too because we're
7713.559 -> connected right to our neighbors. And so I want to create the grand total of all of these
7718.369 -> return values. So I'm going to create some size variable, let's say let size, I'm going
7722.949 -> to initialize it to one over here, it's going to be one and not zero, because the one represents
7728.039 -> my current position, my row column. And whatever these calls return, whatever number I'm just
7734.579 -> going to increment my size by that number, like so. Then finally, I can return our total
7740.879 -> size over here. So that will do my depth first traversal, because it's recursive, but we'll
7747.349 -> also tally up the size of this island region. Cool. So now that I have a working explore
7754.439 -> size helper, let's use it in our main function here. So I'm going to get back a number from
7759.929 -> this call. I'll call it my respective size. And what's great about this logic is if I
7767.09 -> have a Island or position I've already seen before, and I encounter it again in this this
7773.59 -> for loop, then I would just return early because I would hit this base case, right? If something
7777.791 -> has already been visited, just automatically return zero, because I've already considered
7781.4 -> it, no reason to consider it again. But now I need my minimization logic, right, I want
7786.28 -> the size of the smallest Island. And they tell us in the problem that we can totally
7789.84 -> assume that your grid contains at least one island. So I think a great default value here
7794.159 -> is to use positive infinity so I can set some will say min size variable To be positive
7800.699 -> infinity, JavaScript, if I make it positive infinity, I know when I encounter any like
7805.919 -> valid Island size, it's going to be less than infinity. And it should replace it. So now
7811.55 -> I can do some min logic here and check. All right, if the size of this island is less
7815.909 -> than the minimum size I have seen so far, then just replace that min size with that
7821.84 -> island. Then after I'm done with all of these traversals potential reversals, I'll return
7827.369 -> my mid size. So some classic patterns here. There's one nuance that we're not considering
7833.71 -> how to run the code, and we can debug it together. So it looks like we failed example. 00. So
7839.69 -> the very first example we expected to answer to, we accidentally gave back zero. If you
7844.999 -> look at that first example, it's pretty obvious that Yeah, the minimum size is two representing
7848.739 -> this island over here. The reason we're giving back zero is according to our code. Let's
7855.439 -> see we're on like the very first iteration, I'm going to respond it, I know that row is
7858.559 -> going to be zero column is going to be zero, that means my position would be this w over
7862.379 -> here. When I make the recursive call, and I pass along position 00, I know that it's
7868.65 -> going to immediately return zero because that position is water. And I'm going to check
7873.36 -> Alright, is that zero, less than infinity it is, so I'm going to replace min size with
7878.11 -> zero. But if I think about it, zero doesn't even represent a real Island. If an island
7883.3 -> has a size of zero, then it's not an island at all, it was a piece of water, right? And
7887.889 -> so I want to add some additional logic here to only actually look at nonzero quantities.
7893.199 -> So only do the comparison if that size is also valid. So size should be greater than
7899.159 -> zero, of course. And we'll want to add these together. So let's try that again. Just a
7907.849 -> little, little detail over there that we need. Awesome. And there we have a solution for
7911.719 -> this minimum Island problem. So we've seen this pattern a few times now, right or classic
7916.53 -> island hopping logic. So when you think about islands are like connected components of a
7920.749 -> graph, this should be your first kind of go to algorithm. Alright programmers. So that
7925.26 -> wraps up our course on graphs. I hope you learned a ton during the course. I definitely
7928.939 -> had a blast making it Be sure to head to Shruti dotnet, where you can continue to practice
7933.11 -> more graph problems, as well as explore any other data structure algorithm topics. I'll
7937.349 -> see you there.

Source: https://www.youtube.com/watch?v=tWVWeAqZ0WU