Skip to content

Commit 66197ea

Browse files
committed
updates
1 parent cd26209 commit 66197ea

File tree

3 files changed

+92
-96
lines changed

3 files changed

+92
-96
lines changed

Python/Course_Schedule_II.py

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,43 @@
1-
def findOrder(numCourses, prerequisites):
2-
"""
3-
:type numCourses: int
4-
:type prerequisites: List[List[int]]
5-
:rtype: List[int]
6-
"""
7-
#Graph of courses directed to their prerequisites
8-
prereqs = {i:[] for i in range(numCourses)}
9-
#Graph of courses pointing from prerequisites to next courses
10-
dependants = {i:[] for i in range(numCourses)}
1+
# Question(#210): Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.
2+
# Difficulty: Medium
3+
# What do I learn from this question? How to implement a general topological sort with cycle checking
4+
5+
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
6+
7+
# Construct the graph by creating a map where each course maps to a list of its prereqs
8+
graph = {course: [] for course in range(numCourses)}
9+
for a, b in prerequisites: graph[a] += [b]
10+
11+
def depthFirst(course, visiting):
12+
nonlocal order, graph, visited
1113

12-
#Populate both graphs
13-
for x, y in prerequisites:
14-
prereqs[x] += [y]
15-
dependants[y] += [x]
14+
# If we've fully visited the course before we can skip it, if we were visiting it
15+
# and have come across it again then we know there was a cycle, so return False
16+
if course in visited: return True
17+
if course in visiting: return False
1618

17-
#Initialize a stack populated with courses without any prerequisites
18-
stack = [course for course in range(numCourses) if not prereqs[course]]
19-
order = []
20-
21-
#As long as the stack is not empty
22-
while stack:
23-
#Remove the last course from the stack
24-
topCourse = stack.pop()
25-
#Add the course to the order list as this course has no prerequisites
26-
order += [topCourse]
27-
#Now we can go through all of this courses dependants (ie courses which are available to take after this one)
28-
for dependantCourse in dependants[topCourse]:
29-
#Remove top course from the prerequisite of the dependant course as it's already been added to our ordering
30-
prereqs[dependantCourse].remove(topCourse)
31-
#If dependant course has no unvisited prerequisites then add it to the stack
32-
if not prereqs[dependantCourse]: stack += [dependantCourse]
33-
#Delete the topCourse rom the graph of prerequisites as all of its prerequisites must of been added to the stack now
34-
del prereqs[topCourse]
35-
#If the graph of prerequisites is not empty by now, then there is no order of courses that are possible to take
36-
return order if not prereqs else []
37-
38-
def main():
39-
print(findOrder(4, [[1,0],[2,0],[3,1],[3,2], [0, 3]]))
19+
# This is where the DFS starts, so we indicate we are now visiting the current node
20+
visiting.add(course)
21+
22+
# For every course in the prereq of the current course, we conduct a DFS again, returning
23+
# false if our DFS detects a cycle
24+
for prereq in graph[course]:
25+
if not depthFirst(prereq, visiting): return False
26+
27+
# We now add the current course to visited, indicating we've traversed all it's prereqs
28+
# We also add the current course to order, because the first time we reach here in our
29+
# recursion stack will be when we reach a course with no prerequisutes
30+
visited.add(course)
31+
order += [course]
32+
return True
33+
34+
visited, order = set(), []
35+
36+
# Run our DFS on every node in the graph, since our DFS actually returns a boolean
37+
# we can embed cycle checking in the DFS itself and based on that return an empty list
38+
# if a cycle exists in the graph
39+
for course in graph:
40+
if not (depthFirst(course, set())): return []
4041

41-
main()
42+
return order
43+

Python/Minimum_Window_Substring.py

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,46 @@
1-
def minWindow(s: str, t: str) -> str:
2-
3-
#Trivial base case
4-
if not s or not t: return ""
5-
6-
#Initialize a hashmap with the count of each character in t
7-
#This map denotes the characters we're looking for and their occurances
8-
lookingFor = {t[i]:t.count(t[i]) for i in range(len(t))}
9-
10-
#Declare minlen to be ∞
11-
minlen = float('inf')
12-
13-
#initialize letterCount, localLeft and globalLeft to 0
14-
letterCount = localLeft = globalLeft = 0
15-
16-
#For every letter in s
17-
for i, current in enumerate(s):
18-
19-
#If the letter is in the map, subtract 1 from it and increment letterCount if its count is >= 0
20-
#This way letterCount records the number of letter's we're looking for that have been found
21-
if current in lookingFor:
22-
lookingFor[current] -= 1
23-
if lookingFor[current] >= 0: letterCount += 1
24-
25-
#While our letterCount is the same as the len of t
26-
#Note this block of code will only execute when we've found a substring with all letters in t
27-
while letterCount == len(t):
28-
29-
#If our (current index - localLeft + 1) is less than minlen
30-
#In other words if the length of the substring we've localLeftust found is less than the minimum one we know, we'll update minlen and globalLeft
31-
#Note localLeft denotes the leftmost index of our candidate substring and minlen denotes the global leftmost index that results in the shortest substring
32-
if i - localLeft + 1 < minlen: globalLeft, minlen = localLeft, i - localLeft + 1
33-
34-
#If the leftmost item is in the map, add 1 to it and decrement letterCount if its still > 0
35-
#This essentially means we now need to look for this letter again since we're shifting an index that includes a letter we want
36-
#We decrement letter count if its value in the map is non-zero to signify we're missing a letter, since letterCount is no longer the same length as t, we also exit the while loop now
37-
if s[localLeft] in lookingFor:
38-
lookingFor[s[localLeft]] += 1
39-
if lookingFor[s[localLeft]] > 0: letterCount -= 1
40-
41-
#Keep shifting the localLeft pointer right to find smaller and smaller windows
42-
localLeft += 1
43-
44-
if minlen > len(s): return ""
1+
# Question: Given a string and a list of target letters, find the shortest continious string that has all those letters
2+
# Solution/Pattern: The intuition here is to try and find the first substring that contains all letters and then try shrinking
3+
# it's left boundary until we lose a character that was required. We contntinue to do this for all characters in
4+
# the string, hence creating a 'sliding window'
5+
# Difficulty: Hard
6+
457

46-
#Return the substring starting from the globalLeft pointer and ending at + minlen
47-
return s[globalLeft:globalLeft+minlen]
48-
49-
def main():
50-
print(minWindow('ADOBECODEBANC', 'ABC'))
8+
def minWindow(self, s: str, t: str) -> str:
9+
10+
# Initialize the starting point of our starting window
11+
start = 0
12+
shortest = len(s) + 1
13+
# We store the count of each letter needed in a hashmap
14+
lookingFor = collections.Counter(t)
15+
# We also store the total number of chars we have left to find
16+
charsNeeded = len(t)
17+
shortestString = ""
18+
19+
for end, v in enumerate(s):
20+
# If this char is one we were looking for (one that's present in our target) thenwe need
21+
# to decrement it's count by one indicating we've seen it.
22+
# After we've decremented the count we need to check if we've seen it enough times, if the the
23+
# count of the character is less than 0 that means that it's a extra char occuring more times than in t
24+
# However, if after decrementing we have a number greater than or equal to 0 then we can say this was one
25+
# of the targets we were lookingFor and decrement our chars needed count
26+
if v in lookingFor:
27+
lookingFor[v] -= 1
28+
if lookingFor[v] >= 0: charsNeeded -= 1
5129

52-
main()
30+
# Now, if charsNeeded == 0, we can start shrinking our window from the left
31+
# since we don't need any more chars, we know the current string we have from start to end contains
32+
# all the characters present in our target, so we can check if it's length is less than the the one we currently have
33+
# if it's length is less, we update the min length we've found so far and then update the shortest string we've found
34+
# Every time we shrink the window we have to check if we're removing a character we actually needed and then update charsNeeded
35+
# if we removed a character that was required. Finally we shrink the window from the left by incrementing start
36+
while not charsNeeded:
37+
if shortest > end - start + 1:
38+
shortest = end - start + 1
39+
shortestString = s[start:end + 1]
40+
41+
if s[start] in lookingFor:
42+
lookingFor[s[start]] += 1
43+
if lookingFor[s[start]] > 0:
44+
charsNeeded += 1
45+
start += 1
46+
return shortestString

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
| Longest Palindromic Substring| 5 | Medium | String | [Python](Python/Longest_Palindrome_Substring.py) |
4747
| Longest Substring Without Repeating Characters | 3 | Medium | String | [Python](Python/Longest_Substring_Without_Repeating_Characters.py) |
4848
| Text Justification | 68 | Hard | String, Scheduling | [Python](Python/Text_Justification.py) |
49-
| Minimum Window Substring | 76 | Hard | String | [Python](Python/Minimum_Window_Substring.py) |
49+
| Minimum Window Substring | [76](https://leetcode.com/problems/minimum-window-substring) | Hard | String | [Python](Python/Minimum_Window_Substring.py) |
5050

5151

5252
## 🌲 Trees
@@ -96,15 +96,15 @@
9696
## 📈 Graph
9797
| Title | Reccomended Order # | Leetcode # | Difficulty | Tags | Solution |
9898
| --- | --- | --- | --- | --- | --- |
99-
| Number Of Islands | 1 | 200 | Medium | Depth First Search | [Python](Python/Number_Of_Islands.py) / [C](C/Number_Of_Islands.c) |
100-
| Flood Fill | 733 | 2 | Easy | Depth First Search | [Python](Python/Flood_Fill.py) |
101-
| Graph Valid Tree | 3 | 261 | Easy | Graph | [Python](Python/Graph_Is_Tree.py) |
102-
| Number of Connected Components in an Undirected Graph | 4 | 323 | Medium | Depth First Search | [Python](Python/Connected_Components_In_Undirected_Graph.py) |
99+
| Number Of Islands | 1 | [200](https://leetcode.com/problems/number-of-islands/) | Medium | Depth First Search | [Python](Python/Number_Of_Islands.py) / [C](C/Number_Of_Islands.c) |
100+
| Flood Fill | 2 | [733](https://leetcode.com/problems/flood-fill/) | Easy | Depth First Search | [Python](Python/Flood_Fill.py) |
101+
| Graph Valid Tree | 3 | [261](https://leetcode.com/problems/graph-valid-tree/) | Easy | Graph | [Python](Python/Graph_Is_Tree.py) |
102+
| Number of Connected Components in an Undirected Graph | 4 | [323](https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/) | Medium | Depth First Search | [Python](Python/Connected_Components_In_Undirected_Graph.py) |
103103
| Topological Sort | 5 | - | Medium | Graph | [Python](Python/Topological_Sort.py) |
104104
| Validate DAG | 6 | - | Medium | Graph | [Python](Python/Validate_DAG.py) |
105-
| Redundant Connection | 7 | 684 | Medium | Graph | [Python](Python/Redundant_Connection.py) |
106-
| Course Schedule | 8 | 207 | Medium | Top Sort | [Python](Python/Course_Schedule.py) |
107-
| Course Schedule II | 9 | 210 | Medium | Top Sort | [Python](Python/Course_Schedule_II.py) |
105+
| Redundant Connection | 7 | [684](https://leetcode.com/problems/redundant-connection/) | Medium | Graph | [Python](Python/Redundant_Connection.py) |
106+
| Course Schedule | 8 | [207](https://leetcode.com/problems/course-schedule/) | Medium | Top Sort | [Python](Python/Course_Schedule.py) |
107+
| Course Schedule II | 9 | [210](https://leetcode.com/problems/course-schedule-ii/) | Medium | Top Sort | [Python](Python/Course_Schedule_II.py) |
108108

109109
## 🗃️ Sorting
110110
| Title | Leetcode # | Difficulty | Tags | Solution |

0 commit comments

Comments
 (0)