Skip to content

Commit

Permalink
feat(python): solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
hongbo-miao committed Jun 8, 2022
1 parent f15fe47 commit 07f6110
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Python/0236. Lowest Common Ancestor of a Binary Tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Solution:
def lowestCommonAncestor(
self, root: "TreeNode", p: "TreeNode", q: "TreeNode"
) -> "TreeNode":
if root is None:
if not root:
return None

if root == p or root == q:
Expand Down
63 changes: 63 additions & 0 deletions Python/0818. Race Car.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Your car starts at position 0 and speed +1 on an infinite number line. Your car can go into negative positions. Your car drives automatically according to a sequence of instructions 'A' (accelerate) and 'R' (reverse):
#
# - When you get an instruction 'A', your car does the following:
# - position += speed
# - speed *= 2
# - When you get an instruction 'R', your car does the following:
# - If your speed is positive then speed = -1
# - otherwise speed = 1
# Your position stays the same.
#
# For example, after commands "AAR", your car goes to positions 0 --> 1 --> 3 --> 3, and your speed goes to 1 --> 2 --> 4 --> -1.
# Given a target position target, return the length of the shortest sequence of instructions to get there.
#
# Example 1:
#
# Input: target = 3
# Output: 2
# Explanation:
# The shortest instruction sequence is "AA".
# Your position goes from 0 --> 1 --> 3.
#
# Example 2:
#
# Input: target = 6
# Output: 5
# Explanation:
# The shortest instruction sequence is "AAARA".
# Your position goes from 0 --> 1 --> 3 --> 7 --> 7 --> 6.
#
# Constraints:
#
# 1 <= target <= 10^4


# https://leetcode.com/problems/race-car/discuss/1512080/Greedy-Approach-oror-Normal-conditions-oror-94-faster-oror-Well-Coded
# Idea:
# The key point is move close to that point and then start reversing the gear based on conditions.
# If you are still before to the target and speed is reverse(i.e. deaccelerating) or if you are ahead of target and speed is positive (i.e. accelerating) then reverse the speed.
#
# There are two strategies to get to the target distance:
# 1. We go pass it, then come back.
# For example, the target is 2, we accelerate twice to 3, then reverse and come back (the new target is then 3 - 2 = 1.
# 2. We get super close to it, then reverse accelerate a few times, then reverse back to the target
# For example, the target is 2, we accelerate once to 1, then reverse to accelerate 0 times, and reverse again. The new target will be 1
class Solution:
def racecar(self, target: int) -> int:
q = []
q.append((0, 0, 1)) # (step, pos, speed)
while q:
step, pos, speed = q.pop(0)
if pos == target:
return step

q.append((step + 1, pos + speed, speed * 2))

# If you are back to the target and speed is reverse
# or if you are ahead of target and speed is positive then reverse the speed
if (pos + speed < target and speed < 0) or (
pos + speed > target and speed > 0
):
reversed_speed = -1 if speed > 0 else 1
q.append((step + 1, pos, reversed_speed))
return -1
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# You are given the root of a binary tree with n nodes. Each node is uniquely assigned a value from 1 to n. You are also given an integer startValue representing the value of the start node s, and a different integer destValue representing the value of the destination node t.
# Find the shortest path starting from node s and ending at node t. Generate step-by-step directions of such path as a string consisting of only the uppercase letters 'L', 'R', and 'U'. Each letter indicates a specific direction:
#
# 'L' means to go from a node to its left child node.
# 'R' means to go from a node to its right child node.
# 'U' means to go from a node to its parent node.
#
# Return the step-by-step directions of the shortest path from node s to node t.
#
# Example 1:
#
# Input: root = [5,1,2,3,null,6,4], startValue = 3, destValue = 6
# Output: "UURL"
# Explanation: The shortest path is: 3 → 1 → 5 → 2 → 6.
#
# Example 2:
#
# Input: root = [2,1], startValue = 2, destValue = 1
# Output: "L"
# Explanation: The shortest path is: 2 → 1.
#
# Constraints:
#
# The number of nodes in the tree is n.
# 2 <= n <= 10^5
# 1 <= Node.val <= n
# All the values in the tree are unique.
# 1 <= startValue, destValue <= n
# startValue != destValue


# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right


class Solution:
def getDirections(
self, root: Optional[TreeNode], startValue: int, destValue: int
) -> str:
# Return lowest common ancestor of start and dest nodes.
def lca(root):
if not root:
return None
if root.val == startValue or root.val == destValue:
return root

l = lca(root.left)
r = lca(root.right)

if l and r: # p and q are on different sides
return root
if l: # p and q are both on the left side
return l
if r: # p and q are both on the right side
return r

root = lca(root) # only this sub-tree matters

ps = pd = ""
st = [(root, "")]
while st:
node, path = st.pop()
if node.val == startValue:
ps = path
if node.val == destValue:
pd = path
if node.left:
st.append((node.left, path + "L"))
if node.right:
st.append((node.right, path + "R"))
return "U" * len(ps) + pd
81 changes: 81 additions & 0 deletions Python/2115. Find All Possible Recipes from Given Supplies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# You have information about n different recipes. You are given a string array recipes and a 2D string array ingredients. The ith recipe has the name recipes[i], and you can create it if you have all the needed ingredients from ingredients[i]. Ingredients to a recipe may need to be created from other recipes, i.e., ingredients[i] may contain a string that is in recipes.
# You are also given a string array supplies containing all the ingredients that you initially have, and you have an infinite supply of all of them.
# Return a list of all the recipes that you can create. You may return the answer in any order.
# Note that two recipes may contain each other in their ingredients.
#
# Example 1:
#
# Input: recipes = ["bread"], ingredients = [["yeast","flour"]], supplies = ["yeast","flour","corn"]
# Output: ["bread"]
# Explanation:
# We can create "bread" since we have the ingredients "yeast" and "flour".
#
# Example 2:
#
# Input: recipes = ["bread","sandwich"], ingredients = [["yeast","flour"],["bread","meat"]], supplies = ["yeast","flour","meat"]
# Output: ["bread","sandwich"]
# Explanation:
# We can create "bread" since we have the ingredients "yeast" and "flour".
# We can create "sandwich" since we have the ingredient "meat" and can create the ingredient "bread".
#
# Example 3:
#
# Input: recipes = ["bread","sandwich","burger"], ingredients = [["yeast","flour"],["bread","meat"],["sandwich","meat","bread"]], supplies = ["yeast","flour","meat"]
# Output: ["bread","sandwich","burger"]
# Explanation:
# We can create "bread" since we have the ingredients "yeast" and "flour".
# We can create "sandwich" since we have the ingredient "meat" and can create the ingredient "bread".
# We can create "burger" since we have the ingredient "meat" and can create the ingredients "bread" and "sandwich".
#
# Constraints:
#
# n == recipes.length == ingredients.length
# 1 <= n <= 100
# 1 <= ingredients[i].length, supplies.length <= 100
# 1 <= recipes[i].length, ingredients[i][j].length, supplies[k].length <= 10
# recipes[i], ingredients[i][j], and supplies[k] consist only of lowercase English letters.
# All the values of recipes and supplies combined are unique.
# Each ingredients[i] does not contain any duplicate values.


# Topological sort
#
# supplies -> recipes
# ingredients: the relationship of supplies -> recipes
#
# e.g.
# Input
# supplies = ["yeast","flour","meat"]
# ingredients = [["yeast","flour"],["bread","meat"]]
# recipes = ["bread","sandwich"]
#
# Output
# ["bread","sandwich"]
from collections import defaultdict, deque, Counter


class Solution:
def findAllRecipes(
self, recipes: List[str], ingredients: List[List[str]], supplies: List[str]
) -> List[str]:
in_degrees = Counter()
graph = defaultdict(list)
for recipe, ingredient in zip(recipes, ingredients):
in_degrees[recipe] = len(ingredient)
for supply in ingredient:
graph[supply].append(recipe)

recipes = set(recipes)
res = []
q = deque(supplies)
while q:
u = q.popleft()

if u in recipes:
res.append(u)

for v in graph[u]:
in_degrees[v] -= 1
if in_degrees[v] == 0:
q.append(v)
return res
47 changes: 47 additions & 0 deletions Python/2128. Remove All Ones With Row and Column Flips.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# You are given an m x n binary matrix grid.
# In one operation, you can choose any row or column and flip each value in that row or column (i.e., changing all 0's to 1's, and all 1's to 0's).
# Return true if it is possible to remove all 1's from grid using any number of operations or false otherwise.
#
# Example 1:
#
# Input: grid = [[0,1,0],[1,0,1],[0,1,0]]
# Output: true
# Explanation: One possible way to remove all 1's from grid is to:
# - Flip the middle row
# - Flip the middle column
#
# Example 2:
#
# Input: grid = [[1,1,0],[0,0,0],[0,0,0]]
# Output: false
# Explanation: It is impossible to remove all 1's from grid.
#
# Example 3:
#
# Input: grid = [[0]]
# Output: true
# Explanation: There are no 1's in grid.
#
# Constraints:
#
# m == grid.length
# n == grid[i].length
# 1 <= m, n <= 300
# grid[i][j] is either 0 or 1.


# https://leetcode.com/problems/remove-all-ones-with-row-and-column-flips/discuss/1695472/Python-3-or-Simple-Explanation
# 1. For each row or col, we only need to flip it once or do not flip.
# (Flip 2, 4, 6,.. times is same as not flip; flip 1, 3, 5, .. times is same as flip once);
# 2. The order of flipping does not matter.
# 3. If after some flips, we can get the all-zero matrix.
# Then for each pair of rows (or cols), they must be exactly same (every element is the same) or completely different (every element is different).
class Solution:
def removeOnes(self, grid: List[List[int]]) -> bool:
m, n = len(grid), len(grid[0])
row0 = grid[0]
row0_flip = [1 - x for x in grid[0]]
for row in range(1, m):
if grid[row] != row0 and grid[row] != row0_flip:
return False
return True

0 comments on commit 07f6110

Please sign in to comment.