Build a Matrix With Conditions - Leetcode 2392 - Python

NeetCodeIO
20 Jul 202425:11

Summary

TLDRIn this coding tutorial, the presenter tackles the complex problem of building a matrix with specific row and column conditions. They start by explaining the problem and its constraints, then dive into the intuition behind the solution, drawing parallels to previous problems like the course schedule and alien dictionary. The core algorithm discussed is topological sorting, a concept integral to solving this problem, which is compared to depth-first search (DFS). The presenter outlines the steps for topological sort, including cycle detection, before demonstrating the solution in Python code. The video concludes with a walkthrough of the code, ensuring viewers understand the logic and implementation.

Takeaways

  • πŸ˜€ The video aims to solve a problem involving building a matrix with specific conditions.
  • πŸ” The problem description is lengthy and complex, involving a K by K square matrix filled with numbers 1 through K, with the remaining elements being zero.
  • πŸ”’ Two input arrays provide conditions for the placement of numbers in rows and columns, indicating which numbers must be above or to the left of others.
  • πŸ”„ The solution involves a topological sort, similar to the algorithm used in the 'course schedule' problem, which is a prerequisite for understanding the solution.
  • πŸ“ˆ The core idea is to transform the two-dimensional problem into a one-dimensional one by first focusing on the rows and then applying the same technique to the columns.
  • πŸ”Ž A graph is constructed based on the row and column conditions, which helps in visualizing the problem and applying the topological sort algorithm.
  • 🌐 The topological sort algorithm is used to determine a valid order for the elements in the matrix, ensuring that all prerequisites are met for each element.
  • πŸ” The process involves running a depth-first search (DFS) to detect cycles in the graph, which would make the matrix invalid.
  • πŸ“š The solution includes converting lists into hashmaps (dictionaries in Python) to efficiently look up the row and column positions for each number.
  • πŸ’» The final implementation involves coding the topological sort and DFS in Python, with careful attention to cycle detection and the correct ordering of elements.

Q & A

  • What is the main problem being discussed in the script?

    -The main problem discussed in the script is building a matrix with specific conditions based on two input arrays that dictate the placement of numbers within a K by K matrix.

  • What is the significance of the numbers 1 through K in the matrix?

    -The numbers 1 through K are the only values that will be populated in the matrix, with the remaining elements being zero. Each number must be placed according to the conditions given in the input arrays.

  • What does the term 'above' in the row conditions signify?

    -In the row conditions, 'above' means that one number must be placed in a row that is strictly above another number, and they cannot share the same row.

  • What is the core algorithm that needs to be understood to solve this problem?

    -The core algorithm needed to solve this problem is Depth-First Search (DFS), which is used in conjunction with topological sorting to order the elements in the matrix according to the given conditions.

  • Why is it important to know the topological sort algorithm for this problem?

    -Topological sort is important because it helps in ordering the elements in a way that respects the directed edges (or prerequisites) of a graph, which in this case is analogous to the conditions for the rows and columns of the matrix.

  • What is the role of the adjacency list in the script?

    -The adjacency list is used to represent the graph of conditions for both rows and columns, making it easier to perform DFS and topological sort to determine the order of elements.

  • How does the script simplify the two-dimensional problem into a one-dimensional one?

    -The script suggests focusing on the rows first, treating the problem as a one-dimensional ordering issue, and then applying the same technique to the columns after determining the row order.

  • What is the condition that would make the matrix invalid according to the script?

    -The matrix would be invalid if there is a contradiction in the conditions, such as a cycle in the graph, where a number is above another and that second number is above the first, creating a loop with no valid ordering.

  • How does the script handle the possibility of a disconnected graph?

    -The script handles disconnected graphs by running topological sort from every node and marking them visited as it goes, ensuring that all nodes are considered in the final matrix.

  • What is the time complexity of the solution provided in the script?

    -The time complexity of the solution is determined by the traversal of the graph, which in the worst case could be O(K^2), where K is the dimension of the matrix.

  • How does the script ensure that the final matrix satisfies the row and column conditions?

    -The script ensures this by using the results of the topological sort to create mappings for the row and column positions of each number, and then populating the matrix according to these mappings.

Outlines

00:00

πŸ˜€ Introduction to Matrix Construction Problem

The video begins with an introduction to a coding problem involving the construction of a matrix based on certain conditions. The presenter outlines a plan to quickly go through the problem description, which is lengthy and complex, and then compare the problem-solving intuition to a previous problem. The core algorithms needed for the solution are highlighted as complex, emphasizing the importance of understanding algorithms like DFS. The presenter also mentions that the problem will be tackled in Python and concludes with a note about taking a break due to a long week.

05:00

🧠 Understanding the Problem Through Topological Sorting

The presenter dives into the problem by explaining the conditions for filling a KxK matrix with numbers 1 through K, with the remaining elements being zero. The conditions involve certain numbers being placed above others in rows and to the left in columns. The analogy of a directed graph is used to simplify the problem, where numbers are prerequisites for others. The concept of topological sorting is introduced as a method to order the values in a way that respects the given conditions, drawing parallels to the problem of scheduling courses in a curriculum.

10:02

πŸ” Deep Dive into Topological Sorting and Cycle Detection

The video continues with a detailed explanation of how topological sorting can be applied to solve the matrix problem, both for rows and columns. The presenter discusses the process of converting the problem into a graph and using an adjacency list to represent it. The concept of detecting cycles in the graph is introduced as a critical step to ensure the matrix can be validly constructed. The presenter explains the use of two hash sets to track visited nodes and the current path to detect cycles, highlighting the importance of these steps in the algorithm.

15:04

πŸ’» Coding the Topological Sort and Handling Edge Cases

The presenter moves on to the coding part, explaining the implementation of topological sort and depth-first search (DFS). The code is structured to handle the row and column conditions separately, using helper functions for topological sort and DFS. The video discusses how to convert the list of edges into an adjacency list and how to use hash maps to quickly look up the row and column positions for each number. The presenter also addresses how to handle the case where the matrix might not be valid due to a cycle in the graph, returning an empty array in such cases.

20:04

πŸ”Ž Implementing DFS and Cycle Detection in Code

The video script details the implementation of DFS and cycle detection in code. The presenter explains the parameters passed to the DFS function, including the adjacency list, visit hash set, path hash set, and order array. The function is designed to detect cycles by checking if a node is already in the current path, indicating a cycle. The DFS function is used to traverse the graph, appending nodes to the order array once all their neighbors have been visited. The presenter also discusses the importance of reversing the order array to match the topological sort requirements.

25:06

🏁 Wrapping Up the Solution and Taking a Break

In the final part of the video script, the presenter wraps up the solution by summarizing the steps taken to solve the matrix construction problem. The focus is on the implementation of topological sort and DFS, and how they were used to populate the result matrix. The presenter acknowledges the complexity of the solution and congratulates the viewers for making it through the explanation. The video concludes with the presenter taking a break, thanking the viewers for watching, and promising to see them soon.

Mindmap

Keywords

πŸ’‘Matrix

A matrix is a rectangular array of numbers, symbols, or expressions, arranged in rows and columns. In the context of the video, the matrix is the primary structure the presenter is working with, aiming to build it according to specific conditions. The script mentions creating a 'K by K' square matrix, emphasizing the dimensions of the output matrix.

πŸ’‘Conditions

Conditions in this script refer to the rules that govern how elements are placed within the matrix. The video discusses 'row conditions' and 'column conditions' that dictate the relative positions of numbers within the matrix, such as one number needing to be 'above' another.

πŸ’‘Topological Sort

Topological sorting is an ordering algorithm used on directed graphs. It is a linear ordering of vertices such that for every directed edge from vertex u to vertex v, u comes before v in the ordering. The script describes using topological sort to solve the matrix-building problem by creating an order for the rows and columns based on the given conditions.

πŸ’‘DFS (Depth-First Search)

Depth-First Search is an algorithm for traversing or searching tree or graph data structures. The script mentions that topological sort is similar to DFS and that understanding DFS is crucial for implementing topological sort, as it is used to visit all the nodes in a graph in a manner that respects the edges' direction.

πŸ’‘Adjacency List

An adjacency list is a collection of unordered lists used to represent a finite graph. The script describes converting a list of edges into an adjacency list to facilitate the process of topological sorting, which is a way to prepare the graph for the algorithm to work on.

πŸ’‘Cycle Detection

Cycle detection is the process of identifying cycles in a graph. The script discusses the importance of detecting cycles in the row and column conditions because the presence of a cycle would invalidate the matrix, as it would create a contradiction in the placement of elements.

πŸ’‘Graph

In the context of the video, a graph is a structure that consists of nodes or vertices and edges that connect these nodes. The script uses the concept of a graph to represent the relationships between numbers in the matrix, with edges indicating that one number must come before another in the matrix.

πŸ’‘Hash Set

A hash set is a data structure that stores unique elements. In the script, hash sets are used to keep track of visited nodes during the DFS to avoid revisiting the same node, which would lead to infinite loops, and to detect cycles in the graph.

πŸ’‘Algorithm Complexity

Algorithm complexity refers to the amount of resources (such as time and space) that an algorithm consumes when it runs. The script briefly touches on the time complexity of the solution, suggesting that it is determined by the traversal of the graph, which could be as large as 'k^2' in the worst case.

πŸ’‘Disjointed Graph

A disjointed graph is a graph that is not connected; it has two or more separate subgraphs. The script mentions that topological sort works on a disjointed graph, meaning that even if the graph is not fully connected, the algorithm can still find a valid ordering for the nodes.

Highlights

Introduction to the problem of building a matrix with specific conditions.

Problem description involves creating a K by K matrix with conditions on row and column placement.

Only K elements will be populated in the matrix with the rest being zeros.

Row conditions specify that certain numbers must be placed above others.

Column conditions dictate that numbers must be placed to the left of others.

Observation that each element in the matrix will have its own unique row and column.

Simplification of the problem by considering rows first, ignoring columns initially.

Comparison of the problem to course scheduling and alien dictionary problems.

Introduction to topological sort as a method to solve the row ordering.

Explanation of how topological sort works in the context of directed edges and prerequisites.

Application of topological sort to columns, similar to rows.

Visual representation of how elements are placed in the matrix based on row and column orders.

Discussion on how to code the solution, emphasizing the need for a hashmap for efficient lookup.

Implementation of topological sort with considerations for detecting cycles in the graph.

Use of depth-first search (DFS) in the implementation of topological sort.

Explanation of how to detect cycles using a path hash set and a visit hash set.

Coding the solution in Python, detailing the process of converting lists to hashmaps for efficient access.

Final steps in the solution, including initializing the result matrix and populating it based on the determined orders.

Conclusion and encouragement for viewers who have followed through the complex solution.

Transcripts

play00:00

hey everyone welcome back and let's

play00:01

write some more neat code today so today

play00:03

let's solve the problem build a matrix

play00:05

with conditions okay so since we all got

play00:07

things to do in places to be I'm going

play00:09

to try to make this quick don't hold me

play00:11

to that though so the first thing I'm

play00:13

going to do is just go through the

play00:15

problem description because to be honest

play00:17

it's kind of long and pretty complicated

play00:19

second I'm going to show you that the

play00:21

intuition to solve this problem is

play00:22

actually very similar to yesterday's

play00:24

problem while at least trying to figure

play00:26

out the general idea third I'm going to

play00:28

explain the core algorithms you're going

play00:30

to need because even if you're a genius

play00:32

and you kind of know how to solve the

play00:33

problem the algorithms themselves are

play00:35

actually kind of complicated that's why

play00:37

I always say that you should know

play00:39

algorithms like DFS very very well

play00:41

because when you get to a problem like

play00:42

this DFS is only a small part of this

play00:45

problem finally we're going to code it

play00:47

up in Python lastly when I'm done with

play00:50

that I'm probably going to take a break

play00:51

because to be honest it's been a long

play00:53

week and I'm sure you might feel the

play00:54

same so let's get into it the idea is

play00:57

let's focus on the example we're given K

play00:59

so tells us the dimensions of the output

play01:02

Matrix that we want so it's going to be

play01:04

K by K it's going to be a square Matrix

play01:06

next we're given these two input arrays

play01:09

this is kind of the complexity of the

play01:10

problem what the first array is saying

play01:14

is that these two numbers are going to

play01:17

well first of all let me just say that

play01:19

the only values in this are going to be

play01:21

the numbers 1 through K the only values

play01:23

in column conditions are going to be the

play01:25

numbers 1 through K and we want to take

play01:28

the numbers 1 through k and put them in

play01:32

this Square Matrix now that might sound

play01:35

confusing because if we have a k byk

play01:37

Matrix how can we fill it with just K

play01:39

elements well the remaining elements are

play01:41

going to be zero so only K elements are

play01:44

going to be populated 1 through K

play01:47

obviously in this example K is three so

play01:49

what the first array row conditions

play01:51

tells us is that one will be in a row

play01:56

above the value two so theoretically we

play02:00

could have had one over here and two

play02:01

over here or we could have had one over

play02:03

here and two over here or we could have

play02:05

had one over here and two over here and

play02:07

that's what we ended up with now there's

play02:09

a second condition 32 so three has to be

play02:13

above two two could have been here or it

play02:16

could have been here or maybe three

play02:17

could have been here and then two could

play02:18

have been down there so it's a little

play02:20

bit ambiguous isn't it right now the

play02:22

ordering is three one 2 for the rows we

play02:26

could have I think had 1 3 2 because all

play02:29

we need is one to be above two and three

play02:32

to be above two and I think both of

play02:34

these satisfy that condition when they

play02:36

say above it needs to be strictly above

play02:38

so they can never share the same row the

play02:41

second array column conditions is pretty

play02:44

much the exact same thing except for

play02:46

column so if we have 2 one we say two

play02:48

has to be to the left of one it could

play02:50

have been like this or it could have

play02:52

been you know like this or it could have

play02:54

been like this now once you realize that

play02:58

these are saying it needs to be strictly

play03:00

different like it needs to be above or

play03:01

with the columns it needs to be to the

play03:03

left you kind of realize that every

play03:05

single element in the Matrix is going to

play03:08

have its own row and its own column

play03:11

that's kind of an important observation

play03:13

to make right like here you can see

play03:15

everything has its own row and own a

play03:18

column so this kind of makes the problem

play03:21

seem like it's not the end of the world

play03:23

doesn't mean it's easy but I'm about to

play03:25

show you how you can actually make it

play03:27

easy for yourself look I'm not going to

play03:29

lie to you I still don't know how to

play03:31

solve this problem so what can we do

play03:33

let's just try to simplify it for a

play03:34

second forget about the columns let's

play03:37

take this two-dimensional problem and

play03:39

turn it into a one-dimensional problem

play03:41

if we only had to deal with rows how

play03:44

would you solve the problem well I don't

play03:47

know about you but this is kind of

play03:48

giving me vibes from the problem course

play03:51

schedule if that's not enough maybe

play03:54

you've solved that crazy hard problem

play03:56

alien dictionary is it giving you

play03:58

similar Vibes because it is for me if we

play04:00

only have one array it's basically

play04:03

saying that one is a prerequisite of two

play04:07

like one is like a directed Edge kind of

play04:09

right like one is going to be above two

play04:12

and we're also saying three is going to

play04:14

be above two as well so if we were

play04:18

actually to draw it as an entire graph

play04:20

we'd have a graph that looks like this

play04:23

and this is only for the rows by the way

play04:26

so now it kind of becomes clear well it

play04:29

becomes clear if you've heard of the

play04:31

algorithm

play04:33

topological I I don't know how to spell

play04:35

today I'm really sorry topological sort

play04:37

if you don't know what this algorithm is

play04:39

I'll try to teach it to you because it's

play04:41

not super bad but at the very least I

play04:43

hope you do have a decent understanding

play04:44

of DFS if not I have plenty of other

play04:47

videos you can check out n cod. but

play04:49

definitely get a good understanding of

play04:51

DFS before attempting this because what

play04:53

topological sort says is what is a valid

play04:57

way that we could order the values in

play05:00

this graph so that they're actually

play05:01

visited in the order that the edges are

play05:04

represented such that basically for us

play05:06

to visit to we visit all of its

play05:09

prerequisites first so basically one

play05:12

valid ordering would be 1 3 and then two

play05:16

or 3 1 and then two so like those two

play05:21

orderings I said would work now we've

play05:24

kind of solved the problem in one

play05:25

Dimensions if we didn't have to worry

play05:27

about a matrix if we were just ordering

play05:30

the values on which like row each

play05:32

element is going to go in we've pretty

play05:34

much solved the problem haven't we okay

play05:37

but that's not enough because if we say

play05:40

okay we have 3 1 2 well we got to put

play05:43

these in different columns well can we

play05:45

just take the exact same technique and

play05:47

apply it to the columns why not I'm

play05:49

going to do exactly that and let's just

play05:51

try it and see what happens so down here

play05:53

I'm going to have the columns graph I'm

play05:55

going to take these edges build a graph

play05:59

in ter terms of code we generally use

play06:01

something called an adjacency list so

play06:04

that's what I would do but visually it's

play06:06

going to be looking something like this

play06:07

so two goes into one and three goes into

play06:13

two okay so this time it's actually very

play06:15

straightforward there is not a choice

play06:18

here it has to be in this order meaning

play06:21

the columns the First Column has to be

play06:24

three the second column has to be two

play06:27

and the First Column has to be one okay

play06:30

so that makes sense so far and we've

play06:32

pretty much solved the problem if you

play06:34

don't understand it let me kind of draw

play06:35

it out for you suppose I took one of

play06:37

those valid orderings from the row let's

play06:39

just represent it in terms of a list and

play06:42

I'll kind of do it consistent with this

play06:44

example so let's say we did three first

play06:46

and then one and then two these are the

play06:48

orderings of the rows and then same

play06:50

thing for this we got 3 2 1 this is the

play06:54

ordering of the columns now what does

play06:57

this tell us it might not seem obvious

play07:00

but if three is in the first position

play07:02

it's going to go in the first row

play07:04

meaning it's going to go in row zero one

play07:07

is in the second it's going to go in row

play07:08

one two is in the last position it's

play07:10

going to go in row two three is going to

play07:12

go in column zero this is going to go in

play07:15

column one this is going to go in column

play07:16

two so basically the index that each

play07:18

element shows up in is going to be the

play07:22

like coordinate it's going to be

play07:23

assigned so three you can see three is

play07:26

at row Zer and column Zer so it's going

play07:29

to go obviously at 0 0 one is at Row one

play07:34

and column 2 so it's going to go at Row

play07:37

one and column index two so right over

play07:41

there lastly two is at row two column

play07:44

one so it's going to go at row two

play07:46

column 1 and that's exactly it look we

play07:49

just did it conceptually it's not super

play07:52

crazy even this by the way like I drew

play07:55

this out like it's so simple but even

play07:56

this in terms of code how do you think

play07:58

you'd code this up because the way I

play08:00

filled this in was number by number so

play08:03

the way we're going to code this up is

play08:04

actually by converting this into a

play08:06

hashmap but that's a minor detail I

play08:08

think can be explained more easily in

play08:10

the code explanation we're actually not

play08:12

quite done with the drawing explanation

play08:14

yet there's a couple other things we

play08:16

have to cover one is going to be how

play08:18

does topological sort work how am I

play08:21

going to implement it it's very similar

play08:23

to DFS with a couple differences second

play08:26

there is an edge case that we do have to

play08:28

consider because it's Poss possible that

play08:29

the Matrix is not valid let me actually

play08:32

start with that can you think of what

play08:35

would have to happen for the Matrix to

play08:37

not be valid well we need a

play08:39

contradiction right so what if I said

play08:42

okay Row one is above row two this is a

play08:46

one Edge row two is above Row three and

play08:51

then I tell you well Row three is above

play08:53

Row one do you see the contradiction

play08:56

like if I put one here and then I put

play08:58

two down here and and then 2 is above

play09:01

three how can three be above 1 it's a

play09:04

contradiction so how would the graph for

play09:07

this look like let's say something like

play09:09

this 1 to 2 2 to 3 and then 3 to 1 now

play09:14

you might see we know it's invalid if

play09:18

either of the graphs either the row

play09:20

graph or the column graph has a cycle

play09:24

then it's invalid we'll get stuck in

play09:27

like an infinite Loop now how would you

play09:30

detect that there is a cycle because

play09:32

consider this for a second just consider

play09:34

like a random looking graph that looks

play09:36

something like this uh one maybe goes

play09:38

into two and three and then both of

play09:41

these go into something called four like

play09:43

imagine we have a graph that looks

play09:45

something like this this does not count

play09:48

as a cycle it doesn't count as a cycle

play09:51

because from one we can go to three and

play09:53

then we go to four that's it then we go

play09:55

back to three we go back to one and then

play09:57

from there we go to two and we get back

play09:59

to four yes we visited the same one

play10:01

twice but that doesn't mean there's a

play10:03

cycle a cycle would mean that you know

play10:06

along the same path we keep going and

play10:09

then we get back to a previously visited

play10:12

node this is not a cycle because we go

play10:14

here and then that's the dead end then

play10:16

we go all the way back and then we go

play10:18

down here and then we go all the way

play10:20

back I don't see the cycle here because

play10:22

there isn't a cycle in this graph so the

play10:25

way I'm going to detect Cycles is by

play10:27

having one hash set for visit did

play10:29

because we don't want to have repeated

play10:31

work we don't want to end up visiting

play10:32

the same node twice consider if this one

play10:34

had some descendants and we wouldn't

play10:36

want to have to Traverse them multiple

play10:38

times so that's going to be one hash set

play10:39

but the hash set that's going to detect

play10:41

Cycles I'm going to call it the path

play10:44

hash set and I'm always going to add

play10:46

every node that's along the current path

play10:48

in that hash set if we pop back I'm

play10:51

going to remove that node from the hash

play10:53

set but nothing is ever going to be

play10:55

removed from the visit hashset so that's

play10:57

the small distinction and that's pretty

play10:59

much the main distinction the only other

play11:02

point that you need to know in terms of

play11:04

like how I'm going to implement

play11:05

topological sort there are a couple ways

play11:07

to do it but I'll show you why I prefer

play11:09

doing it the way I'm going to show you

play11:11

consider pretty much the same graph

play11:13

actually and then uh maybe like we have

play11:16

some choices here like we have a five

play11:18

here and believe it or not topological

play11:20

sort works on a disjointed graph so you

play11:22

can see these are all connected but

play11:24

imagine I had six and it connects to

play11:26

seven and imagine I had like eight to

play11:28

nine so imagine a graph like this how is

play11:31

topological sort going to work well

play11:34

basically these ones are pretty

play11:36

straightforward the topological sword of

play11:37

this would just be 8 9 the topological

play11:40

sword of this would just be 67 the

play11:42

topological sword of this would be more

play11:45

interesting there'd be more choices here

play11:47

so we definitely have to start with one

play11:49

and then we have a choice of either

play11:52

three or two let's pick three we can't

play11:55

go to four yet because we haven't met

play11:57

the prerequisite so we have to also have

play11:59

two here now that we have one we have 3

play12:03

two we can either pick four or five the

play12:05

order of these doesn't really matter we

play12:07

could have it either way I'll just write

play12:08

it like this with topological sort it's

play12:11

non-deterministic there could be

play12:12

multiple correct Solutions well I don't

play12:14

know if non-deterministic is the best

play12:16

word to describe it but it could have

play12:18

multiple orderings so how would we

play12:20

actually arrive at this in terms of code

play12:23

well the way I prefer to do it and you

play12:25

might have a different opinion I run a

play12:28

dep first search I run the depth for

play12:30

search until we get to the base case so

play12:33

this is what I would do I would have my

play12:35

output array which is going to be the

play12:36

topological sort ordering I'm going to

play12:38

get to one I'm not going to add it yet I

play12:40

might add this to the visit hashset but

play12:42

I'm not going to add it to the output

play12:44

yet I'm going to do it in reverse order

play12:47

I'm going to get to one I'm going to get

play12:48

to two then I'm going to get to five

play12:50

okay five is the one that doesn't have

play12:53

any more descendants it's kind of the

play12:54

base case so I'm going to add it at the

play12:56

beginning I'm going to go back up to two

play13:00

I can't add two yet I'm not going to add

play13:02

two to the output yet I'm going to wait

play13:04

until I do all of its descendants so

play13:06

four is one of The Descendants now I'm

play13:08

going to add four to it and now that

play13:10

I've done both of its descendants now

play13:13

I'm going to add two to the topological

play13:15

sort output and then I'm going to pop

play13:18

back up to one and I haven't done all of

play13:20

one's descendants yet so now I'm going

play13:21

to go to three and then I'm going to do

play13:24

all of its descendants its descendants

play13:26

have already been visited so I'm going

play13:27

to go back now three all of its

play13:29

neighbors have been finished so I'm

play13:31

going to add three to the output

play13:32

ordering and then I'm going to pop back

play13:34

up to one everything's been finished so

play13:36

we can go ahead and add one to the

play13:38

output the only thing about this is It's

play13:41

not what we want but it's an easy thing

play13:43

for us to fix just take this and reverse

play13:47

it that's it because with topological

play13:49

sort what we're trying to do is visit

play13:51

each node before we do all of its

play13:54

descendants it seems like it might be

play13:56

easy to do but this example will show

play13:58

you it's not if I tried to do okay add

play14:00

one then add two then add five okay it

play14:04

seems like it's working so far then add

play14:07

four and then we go back up to one and

play14:09

then we add three well do you see the

play14:12

contradiction how did we have four

play14:14

before we added the three that's why

play14:16

it's easier to code up if you do it in

play14:18

reverse order you add these the nodes

play14:21

that don't have any more descendants you

play14:23

add them first and then you can just

play14:25

reverse the output so that's pretty much

play14:27

everything you need to know to solve

play14:29

this problem and in terms of a Time

play14:32

complexity I assume that there's not

play14:34

going to be any duplicates in here so

play14:36

it's basically going to be bottlenecked

play14:38

based on the traversal which we're going

play14:40

to run two times but that's a constant

play14:42

so it doesn't matter so how big could

play14:44

one of these graphs possibly be I guess

play14:46

in the worst case each value could be

play14:48

connected to every other value so I

play14:50

think in the worst case that's k^ squ so

play14:53

this is like the literal worst case I

play14:56

don't think it'll actually be that much

play14:58

so I guess

play14:59

um it's either k^ s or the maximum of

play15:04

either of these two it's going to be the

play15:06

minimum of those so I guess you know

play15:08

just take the length of either of these

play15:10

actually now that I think if we're going

play15:12

to be creating a matrix like this I

play15:13

think k^ squ is probably the most

play15:15

appropriate way to put it so I'll be

play15:17

leaving it at that so now let's code it

play15:19

up uh I don't know how helpful this is

play15:22

but this is the train of thought that I

play15:24

had um you can see it's going to be kind

play15:26

of a lot of code so I'll try to keep it

play15:27

relatively organized so the way this is

play15:30

going to work is we're going to run

play15:33

topological sort but remember the

play15:35

example I showed you where we had a

play15:37

disjointed graph where the graph isn't

play15:39

connected we can't just pick one random

play15:41

node in the graph and then run top

play15:44

logical sort on it we might have to run

play15:45

top logical sort from literally every

play15:47

node in the graph and we can mark them

play15:49

visited as we go so that's why we're

play15:52

actually going to split this up into two

play15:53

different helper functions I'm going to

play15:55

have one helper function for topological

play15:56

sort it's just going to take in the list

play15:59

of edges either this or this and we're

play16:01

also going to have a function for depth

play16:04

for search that's the one where kind of

play16:05

the bulk of the work is going to be done

play16:08

so let's just think about it abstracted

play16:10

for a second let's think about it from a

play16:12

high level the way I'm going to be

play16:14

calling topological sort is like this

play16:17

I'm going to call it twice passing in

play16:19

row conditions the first time and I'm

play16:21

going to be passing in column conditions

play16:24

the second time and what we expect this

play16:26

to return is pretty much what I had in

play16:29

the drawing this is going to return the

play16:31

row order of the numbers the order that

play16:33

the numbers should appear in in terms of

play16:35

the row the other one is of course going

play16:37

to do the column order so these are

play16:38

going to be arrays these are going to be

play16:40

lists the way I'm going to code up the

play16:42

topological store is if there's a cycle

play16:45

I'm going to detect that by returning an

play16:47

empty array so if either of these is an

play16:50

empty array if not row order or not

play16:54

column order then we're going to return

play16:57

an empty array because that's what they

play16:58

pretty much told us to do in the problem

play17:00

description if that's not the case

play17:02

assume that you already have these two

play17:05

maybe in your real interview you don't

play17:06

know the implementation details of

play17:08

either DFS or topological sort but you

play17:10

know that those are required to solve

play17:12

the problem I think it's better to

play17:13

actually start with this part of the

play17:14

code because then at least you know

play17:16

where you're going if you can Implement

play17:17

these you can solve the problem so here

play17:19

what I'm going to say is we have these

play17:22

but what we're trying to do is populate

play17:25

the result Matrix so I'm actually going

play17:27

to initialize that down here in pyth on

play17:29

it's pretty straightforward to do it's

play17:30

going to be K by K so something like

play17:32

this and now I want to go through every

play17:34

number from 1 to K num in range 1

play17:39

through K and I want to say that at some

play17:42

row column position I want to assign

play17:44

this numb but we don't know which row

play17:47

that this number belongs to or which

play17:48

column it belongs to but the fact that

play17:51

we have the column and row ordering we

play17:53

can get that with these data structures

play17:55

we wouldn't be able to get it in

play17:57

constant time so I'm going to convert

play17:58

convert these two lists into hashmaps or

play18:01

dictionaries in Python so I'm going to

play18:03

say before this over here I'm going to

play18:05

say value to row hashmap and you know

play18:10

you could probably code this part up

play18:12

like in your language of choice in

play18:14

Python I'm going to try to keep it

play18:15

concise because this is going to be a

play18:17

long enough solution as it is so I'm

play18:19

going to use something called dictionary

play18:21

comprehension right now I'm also going

play18:22

to enumerate I'm going to say for i n in

play18:26

enumerate row order so this will give us

play18:29

the index and the number in that array

play18:32

of course we want the number to be

play18:34

mapped to the index which tells us the

play18:37

row so I'm going to say n maps to I I'm

play18:41

going to copy this and just update it

play18:43

slightly by renaming this to Value to

play18:46

column and renaming this column order so

play18:49

it's going to do the exact same thing

play18:50

for column order so then down here I'm

play18:53

going to look up the row and column with

play18:56

these two data structures just just like

play18:59

that and assuming we do that we should

play19:02

have the result and we can guarantee

play19:05

that row order and column order if

play19:06

they're non-empty are going to include

play19:09

every number from 1 through K because

play19:12

even if the graph is not connected even

play19:14

if it's a disjointed graph we're going

play19:16

to visit every Edge and I'm going to

play19:17

show you that part right now I just

play19:19

happen to know it off the top of my head

play19:21

because I know how topological sort

play19:22

works at a pretty decent level this is

play19:24

like an advanced algorithm which is why

play19:26

I cover it in my Advanced algorithms

play19:27

course I don't expect you to like be an

play19:29

expert on this so if we're passing in

play19:33

the list of lists generally that's not

play19:35

how we want to run a DFS so the first

play19:37

thing we're actually going to do in here

play19:39

is convert it into an adjacency list so

play19:41

I'm going to call it adjacent default

play19:44

deck and I'm going to pass in list and

play19:46

so that will make it easy for us to do

play19:48

this for Source destination in edges

play19:52

because we know we're dealing with

play19:54

directed edges here so I'm going to say

play19:56

that for this Source node I'm going to

play19:58

append to its neighbors this destination

play20:00

note so that's just initializing the

play20:02

adjacency list the next thing we would

play20:04

want to do over here is go through every

play20:07

Source from one through K so I'm going

play20:11

to say 1 through k + 1 and then run a

play20:15

DFS on it now of course we're going to

play20:17

have to pass in the source node to run

play20:19

the DFS but there's a few other things

play20:20

we're going to have to pass in as well

play20:22

another thing will be the adjacency list

play20:24

obviously another thing is going to be

play20:26

the two hash sets that I talked about we

play20:28

want them Mark positions visited we

play20:30

don't want to get stuck in an infinite

play20:31

Loop and we also want to be able to

play20:33

detect a cycle so we're going to create

play20:35

two hash sets for those I'm going to

play20:38

just copy that right there there is one

play20:41

last parameter we're going to pass in

play20:43

it's going to actually be an array I'm

play20:45

going to call it order because remember

play20:47

ultimately what we're trying to do is

play20:49

collect the order so that's kind of what

play20:51

I showed in the drawing explanation when

play20:53

we reach the base case in DFS that's

play20:55

when we will append a node or not even a

play20:58

base case but once we visited all the

play20:59

neighbors of a given node so um here I

play21:02

will create an array for the order and

play21:05

then remember before you return the

play21:06

order you definitely want to make sure

play21:08

to reverse it in Python you can do that

play21:11

pretty easily like this and here I'm

play21:13

just going to make a comment that that's

play21:15

reversing it now what about cycle

play21:18

detection the way I'm going to detect a

play21:20

cycle is like this that's actually the

play21:22

first thing I'm going to do in the DFS

play21:24

other than I guess assign what

play21:26

parameters we're going to have for it so

play21:28

all these parameters so if source is in

play21:33

path and the other one is if source is

play21:36

in a visit I very specifically put this

play21:39

one first because if a source node is

play21:42

along the path that we're already on

play21:45

then we detected a cycle if that's true

play21:47

though this is also going to be true we

play21:49

want to know if this one is true more

play21:52

because this is the case where we've

play21:54

detected a cycle and that's when we're

play21:55

going to return false in the other case

play21:58

down here I'm going to return true this

play22:00

might make more sense when I finish the

play22:02

rest of the function because as you'll

play22:03

see when we get to a node we're going to

play22:06

mark it as visited immediately add this

play22:08

to visit so Source also I'm going to say

play22:12

add it to the path just like that and

play22:15

then I'm going to run my DFS somewhere

play22:16

over here and then when I'm done with

play22:18

that I'm going to say okay now path.

play22:20

remove this node but we're never going

play22:22

to remove a node from visit once a node

play22:25

is visited it should never be visited

play22:27

multiple times Okay so so now the actual

play22:30

DFS part it's not super crazy let's go

play22:32

through every neighbor of the current

play22:33

node that's exactly why we have the

play22:35

adjacency list so uh Source now we run

play22:38

DFS on the neighbor so passing in the

play22:41

same adjacency list same visit hashset

play22:44

same path hash set in same order array

play22:47

now what if we returned false from one

play22:50

of the base cases like what if we

play22:51

returned false from here what should we

play22:53

do in this case well probably return

play22:56

false immediately because once you

play22:57

detect a cycle there's no point in

play23:00

continuing so as soon as we see it if

play23:02

not this then just return false no need

play23:05

to visit the remaining neighbors if we

play23:08

never detect a cycle though down here

play23:10

let's just go ahead and return true

play23:12

there's only a couple things left first

play23:14

of all the order variable we haven't

play23:16

really used it anywhere and that's

play23:18

because we're saving it once we go

play23:20

through all the neighbors of a given

play23:22

node at the end after all that is when

play23:25

we append the current node so that's

play23:28

just the DFS portion okay I actually did

play23:31

have a typo so this is going to be

play23:32

Source sorry and I think we're actually

play23:35

nearly done I'm just going to quickly

play23:37

read through the rest of the code so I

play23:38

think the DFS looks good it's very easy

play23:41

to make a bug in a solution like this

play23:43

where there's so much code so that's

play23:45

another challenging part about this here

play23:47

if the DFS returns false so if not DFS

play23:51

here then we should return an empty

play23:54

array there's no need to continue

play23:55

running DFS and we definitely don't want

play23:56

to return the values that have already

play23:58

been added here at this point we return

play24:00

an empty array so that here we can

play24:02

detect that and then return an empty

play24:04

array now before you call DFS you could

play24:07

check if Source has already been visited

play24:09

but that's literally a base case in the

play24:12

DFS so it'll execute immediately anyway

play24:14

so I don't think it's necessary to have

play24:16

that line here um but here we're calling

play24:19

topological sort getting the output

play24:21

orderings um this is the case where we

play24:23

detected the cycle then we otherwise we

play24:25

convert it into the hashset down here we

play24:28

ize The Matrix we get the row and column

play24:31

here actually I think I messed this up

play24:33

these are hash Maps um we want to look

play24:35

up this number we want to map it to its

play24:38

row so I'm going to fix that and here we

play24:41

want to map that to its column so I'm

play24:43

going to do that as well now I think

play24:45

this is pretty much correct but it's

play24:47

hard to fit it all on one screen yeah I

play24:49

don't think it's possible to fit it all

play24:51

on one screen I'm really sorry I'm

play24:53

trying my best it's just really it's

play24:55

it's 40 lines of code we should be able

play24:57

to get it so that's a best I can do you

play24:59

might have to zoom in but I'm going to

play25:01

run it and it does look like it works

play25:04

and it's pretty efficient if you made it

play25:05

this far good job give yourself a pat on

play25:08

the back I'm going to go take a break

play25:09

thanks for watching and I'll see you

play25:10

soon

Rate This
β˜…
β˜…
β˜…
β˜…
β˜…

5.0 / 5 (0 votes)

Related Tags
Matrix BuildingTopological SortDepth First SearchAlgorithm TutorialCode ProblemGraph TheoryRow ConditionsColumn ConditionsCycle DetectionPython Coding