github_jakehoare_leetcode_4splits_75scale_with_difficulty
github_jakehoare_leetcode_4splits_75scale_with_difficulty
return [] # no sum # Find the middle element if sum of input list lengths is odd, or else the average of the middle pair.
# get_kth_smallest recusively removes k//2 elements from one list.
# Time - O(log(m+n)), half of the elements smaller than median are removed each recursive call.
# Space - O(log(m+n)) for the recursive call stack.
# python_1_to_1000/002_Add_Two_Numbers.py - m
class Solution(object):
_author_ = 'jake' def findMedianSortedArrays(self, A, B):
_project_ = 'leetcode' """
:type A: List[int]
# https://leetcode.com/problems/add-two-numbers/ :type B: List[int]
# You are given two linked lists representing two non-negative numbers. :rtype: float
# The digits are stored in reverse order and each of their nodes contain a single digit. """
# Add the two numbers and return it as a linked list. def get_kth_smallest(a_start, b_start, k):
# Iterate over lists. Add to result a node with the the sum of input nodes plus carry, mod 10. if k <= 0 or k > len(A) - a_start + len(B) - b_start:
# Time - O(max(m,n)) where m and n are input list lengths. raise ValueError('k is out of the bounds of the input lists')
# Space - O(max(m,n)), output will be at most one digit more than longest input.
# base cases
# Definition for singly-linked list. if a_start >= len(A):
class ListNode(object): return B[b_start + k - 1]
def __init__(self, x): if b_start >= len(B):
self.val = x return A[a_start + k - 1]
self.next = None if k == 1:
return min(A[a_start], B[b_start])
class Solution(object):
def addTwoNumbers(self, l1, l2): # remove k//2 elements from one list
""" # find the smallest of the k//2 - 1th element from both lists and recurse having reduced that list.
:type l1: ListNode # k//2 - 1th element must exist in at least 1 list
:type l2: ListNode mid_A, mid_B = float('inf'), float('inf')
:rtype: ListNode if k // 2 - 1 < len(A) - a_start:
""" mid_A = A[a_start + k // 2 - 1]
prev = result = ListNode(None) # dummy head if k // 2 - 1 < len(B) - b_start:
carry = 0 mid_B = B[b_start + k // 2 - 1]
return result.next
# python_1_to_1000/005_Longest_Palindromic_Substring.py - m
# python_1_to_1000/003_Longest_Substring_Without_Repeating_Characters.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/longest-palindromic-substring/
# https://leetcode.com/problems/longest-substring-without-repeating-characters/ # Given a string S, find the longest palindromic substring in S.
# Given a string, find the length of the longest substring without repeating characters. # You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
# Maintain a sliding window, updating the start whenever we see a character repeated. # For each centre point of a character or between 2 characters,
# Time - O(n) # expand the palindrome if the end characters are the same.
# Space - O(1), dictionary is limited by fixed size alphabet # Return early by starting with the middle centre and ruling out later centres that could not have longer
# substring than the palindrome already found.
# Time - O(n^2), 2n centres, each expanded upto n times # Example2: x = -123, return -321
# Space - O(n) to store the result
# Repeatedly multiply previous result by 10 and add last digit.
# Note that Manacher's algorithm provides a O(n) time solution. # Time - O(n) where n is the number of digits.
# Space - O(n), same number of digits in output as input.
class Solution(object):
def longestPalindrome(self, s): class Solution(object):
""" def reverse(self, x):
:type s: str """
:rtype: str :type x: int
""" :rtype: int
longest = "" """
negative = x < 0 # record if negative and change to positive
# create list of 2n-1 possible centres, each letter and between each pair x = abs(x)
# even indices represent letters, odd represent between letters reversed = 0
# start with middle index that potentially creates longest palindrome
centres = [len(s) - 1] while x != 0:
for diff in range(1, len(s)): # build list of indices from long to short reversed = reversed * 10 + x % 10
centres.append(centres[0] + diff) x //= 10
centres.append(centres[0] - diff)
if reversed > 2**31 - 1: # required to pass leetcode test cases, not applicable for python
for centre in centres: return 0
return reversed if not negative else -reversed
if (min(centre + 1, 2 * len(s) - 1 - centre) <= len(longest)):
break # return if cannot make a longer palindrome
if centre % 2 == 0:
left, right = (centre // 2) - 1, (centre // 2) + 1
else: # python_1_to_1000/008_String_to_Integer_(atoi).py - m
left, right = centre // 2, (centre // 2) + 1
_author_ = 'jake'
while left >= 0 and right < len(s) and s[left] == s[right]: _project_ = 'leetcode'
left -= 1
right += 1 # https://leetcode.com/problems/string-to-integer-atoi/
# left and right are now beyond the ends of the substring # Implement atoi to convert a string to an integer.
# Notes: It is intended for this problem to be specified vaguely (ie, no given input specs).
if right - left - 1 > len(longest): # You are responsible to gather all the input requirements up front.
longest = s[left + 1:right]
# Return the integer upto any non-digit.
return longest # Time - O(n)
# Space - O(n), new str created by strip()
while left < right: # Repeatedly take of as many copies of each numeral as possible until num is less than
if s[left] != s[right]: # the value of that numeral.
return False # Time - O(n) where n = len(str(num)), the longest roman equivalent is 8 where one digit maps to 4 chars
left += 1 # Space - O(n)
right -=1
class Solution(object):
return True def intToRoman(self, num):
"""
:type num: int
# python_1_to_1000/010_Regular_Expression_Matching.py - h :rtype: str
"""
_author_ = 'jake' mapping = [(1000, 'M'),
_project_ = 'leetcode' (900, 'CM'),
(500, 'D'),
# https://leetcode.com/problems/regular-expression-matching/ (400, 'CD'),
# Implement regular expression matching with support for '.' and '*'. (100, 'C'),
# '.' Matches any single character. (90, 'XC'),
# '*' Matches zero or more of the preceding element. (50, 'L'),
# The matching should cover the entire input string (not partial). (40, 'XL'),
(10, 'X'),
# Dynamic programming calculation of matrix of whether any prefix of s patches any prefix of p. (9, 'IX'),
# Time - O(m*n) when m = len(p) and n = len(s) (5, 'V'),
# Space - O(m*n) (4, 'IV'),
(1, 'I'),]
class Solution(object):
def isMatch(self, s, p): roman = []
for i, numeral in mapping:
# matched[i][j] is True if the first i chars of s (i.e. s[:i]) matches the first j chars of p (i.e. p[:j]) while num >= i:
matched = [[False for _ in range(len(p)+1)] for _ in range(len(s)+1)] num -= i
matched[0][0] = True # no pattern (j=0) matches no string and not any non-zero string roman.append(numeral)
# Start with the widest separation of lines. To form a greater area, any lesser separation must have a greater integer = 0
# minimum boundary height. i = 0
# Time - O(n) while i < len(s):
# Space - O(1) if i < len(s) - 1 and s[i:i + 2] in doubles:
integer += doubles[s[i:i + 2]]
class Solution(object): i += 2
def maxArea(self, height): else:
""" integer += singles[s[i]]
:type height: List[int] i += 1
:rtype: int
""" return integer
left = 0
right = len(height)-1
max_area = (right - left) * min(height[right], height[left])
# python_1_to_1000/014_Longest_Common_Prefix.py
while left < right:
if height[left] < height[right]: # By moving in the lower boundary we have the possibility _author_ = 'jake'
left += 1 # of finding a larger area. _project_ = 'leetcode'
else:
right -= 1 # https://leetcode.com/problems/longest-common-prefix/
max_area = max(max_area, (right - left) * min(height[right], height[left])) # Write a function to find the longest common prefix string amongst an array of strings.
return max_area # Sort strings and find longest prefix of first and last, which are the most different.
# Alternatively all strings could be inserted into a trie and we find the first node
# with more than one child.
# python_1_to_1000/012_Integer_to_Roman.py - m # Time - O(k*n logn) where k is the length of the longest string and n is number of strings.
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def longestCommonPrefix(self, strs):
# https://leetcode.com/problems/integer-to-roman/ """
# Given an integer, convert it to a roman numeral. :type strs: List[str]
# Sort the array. For each index i perform a bidirectional search on the higher values in the array.
# Skip over duplicates. Increment i to the next new minimum number. # python_1_to_1000/017_Letter_Combinations_of_a_Phone_Number.py - m
# Time - O(n**2), for each i at least one of j and k moves every iteration.
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def threeSum(self, nums): # https://leetcode.com/problems/letter-combinations-of-a-phone-number/
""" # Given a digit string, return all possible letter combinations that the number could represent.
:type nums: List[int]
:rtype: List[List[int]] # For each digit add all possible letter mappings to each of the previous results.
""" # Alternatively can be solved recursively.
results = [] # Time - O(n * 4^n)
nums.sort() # Space - O(n * 4^n), max 4 possible chars per digit so O(4^n) strings each of length n
i = 0 class Solution(object):
while i < len(nums): def letterCombinations(self, digits):
j = i + 1 """
k = len(nums) - 1 :type digits: str
:rtype: List[str]
while j < k: """
if not digits or '0' in digits or '1' in digits:
triple_sum = nums[i] + nums[j] + nums[k] return []
if triple_sum == 0: # record result and move both j and k to next new numbers results = [[]]
results.append([nums[i], nums[j], nums[k]]) mapping = {'2' : ['a', 'b', 'c'],
k -= 1 '3' : ['d', 'e', 'f'],
while k > j and nums[k] == nums[k + 1]: '4' : ['g', 'h', 'i'],
k -= 1 '5' : ['j', 'k', 'l'],
j += 1 '6' : ['m', 'n', 'o'],
while j < k and nums[j] == nums[j - 1]: '7' : ['p', 'q', 'r', 's'],
j += 1 '8' : ['t', 'u', 'v'],
'9' : ['w', 'x', 'y' , 'z']}
elif triple_sum > 0: # decrement k to next new number
k -= 1 for digit in digits:
while k > j and nums[k] == nums[k + 1]: temp = []
k -= 1 for result in results:
else: # increment j to next new number for letter in mapping[digit]:
j += 1 temp.append(result + [letter])
while j < k and nums[j] == nums[j - 1]: results = temp
j += 1
# convert lists of chars to strings
i += 1 # increment i to next new number return ["".join(result) for result in results]
while i < len(nums) - 2 and nums[i] == nums[i - 1]:
i += 1
# python_1_to_1000/018_4Sum.py - m
return results
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/4sum/
# python_1_to_1000/016_3Sum_Closest.py - m # Given an array nums of n integers, are there elements a, b, c, and d in nums such that a + b + c + d = target?
# Find all unique quadruplets in the array which gives the sum of target.
_author_ = 'jake' # Note: The solution set must not contain duplicate quadruplets.
_project_ = 'leetcode'
# Recursively reduce to 2sum problem.
# https://leetcode.com/problems/3sum-closest/ # Time - O(n^3), for each pair perform linear search on the rest of the array
# Given an array nums of n integers, find three integers in nums such that the sum is closest to a given number, target.
# Return the sum of the three integers. You may assume that each input would have exactly one solution. class Solution(object):
ELEMENTS = 4 # parametrise the number of elements being summed
# Sort the array. For each staring index bidirectional search in the rest of the array.
# Time - O(n**2) def fourSum(self, nums, target):
# Space - O(1) """
:type nums: List[int]
class Solution(object): :type target: int
def threeSumClosest(self, nums, target): :rtype: List[List[int]]
""" """
:type nums: List[int] results = []
self.n_sum(sorted(nums), target, [], self.ELEMENTS, results) for c in s:
return results if c in match:
stack.append(c)
else:
def n_sum(self, nums, target, partial, n, results): # generalise for n-sum if not stack or match[stack.pop()] != c:
return False
if len(nums) < n or target > nums[-1]*n or target < nums[0]*n: # early return if impossible
return return not stack
class Solution(object):
# python_1_to_1000/019_Remove_Nth_Node_From_End_of_List.py - m def mergeTwoLists(self, l1, l2):
_author_ = 'jake' prev = dummy = ListNode(None) # new dummy head for the merged list
_project_ = 'leetcode'
while l1 and l2: # link prev to the lowest node
# https://leetcode.com/problems/remove-nth-node-from-end-of-list/
# Given a linked list, remove the nth node from the end of list and return its head. if l1.val < l2.val:
prev.next = l1
# Advance first pointer n steps then advance both pointers at same rate. l1 = l1.next
# Time - O(n) else:
# Space - O(1) prev.next = l2
l2 = l2.next
# Definition for singly-linked list.
# class ListNode(object): prev = prev.next
# def __init__(self, x):
# self.val = x prev.next = l1 or l2 # link prev to the list with remaining nodes
# self.next = None return dummy.next
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode # python_1_to_1000/022_Generate_Parentheses.py - m
:type n: int
:rtype: ListNode _author_ = 'jake'
""" _project_ = 'leetcode'
first, second = head, head
# https://leetcode.com/problems/generate-parentheses/
for i in range(n): # move first n steps forwards # Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
first = first.next
if not first: # Recursively add an opening left bracket if any remain, and a closing right bracket if more left brackets have been
return head.next used.
# Time - O(2^n), each recursion can generate 2 recursive calls althougn in practive this is an upper bound
while first.next: # move both pointers until first is at end # Space - O(2^n)
first = first.next
second = second.next class Solution(object):
second.next = second.next.next # nth from end is second.next def generateParenthesis(self, n):
return head """
:type n: int
:rtype: List[str]
# python_1_to_1000/020_Valid_Parentheses.py """
result = []
_author_ = 'jake' self.generate([], n, n, result)
_project_ = 'leetcode' return result
# https://leetcode.com/problems/valid-parentheses/ # Generates all parentheses given a starting prefix and remaining left and right brackets.
# Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. def generate(self, prefix, left, right, result):
# The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not. if left == 0 and right == 0:
result.append("".join(prefix))
# Maintain a stack of opening brackets. For each closing bracket pop the head of the stack and check it matches. if left != 0:
# Time - O(n) self.generate(prefix + ['('], left-1, right, result)
# Space - O(n) if right > left:
self.generate(prefix + [')'], left, right-1, result)
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool # python_1_to_1000/023_Merge_k_Sorted_Lists.py - h
"""
stack = [] _author_ = 'jake'
match = {'(' : ')', '[' : ']', '{' : '}'} _project_ = 'leetcode'
# https://leetcode.com/problems/merge-k-sorted-lists/ # You may not alter the values in the nodes, only nodes itself may be changed.
# Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. # Only constant memory is allowed.
# Maintain a min heap of tuples of (val, list index) for the next node in each list. # If there are at least k nodes, recursively reverse remainder and append reversed group to reversed remainder.
# Also maintain a list of the next node to be merged for each list index. # Time - O(n)
# Time - O(n log k) for n total nodes, each of which is pushed and popped from heap in log k time. # Space - O(1)
# Space - O(k) for heap of k nodes
class Solution(object):
# Definition for singly-linked list. def reverseKGroup(self, head, k):
class ListNode(object): """
def __init__(self, x): :type head: ListNode
self.val = x :type k: int
self.next = None :rtype: ListNode
"""
import heapq if k < 2:
return head
class Solution(object):
def mergeKLists(self, lists): node = head
""" for _ in range(k):
:type lists: List[ListNode] if not node:
:rtype: ListNode return head # return head if there are not at least k nodes
""" node = node.next
prev = dummy = ListNode(None) # else node is now head of second group
next_nodes, heap = [], []
# reverse remainder after this group
for i, node in enumerate(lists): prev = self.reverseKGroup(node, k)
next_nodes.append(node) # next_nodes[i] is the next node to be merged from lists[i]
if node: for _ in range(k): # reverse this group, adding in front of prev
heap.append((node.val, i)) temp = head.next
heapq.heapify(heap) head.next = prev
prev = head
while heap: head = temp
value, i = heapq.heappop(heap)
node = next_nodes[i] return prev
prev.next = node # add node to merged list
prev = prev.next
if node.next: # python_1_to_1000/026_Remove_Duplicates_from_Sorted_Array.py
next_nodes[i] = node.next
heapq.heappush(heap, (node.next.val, i)) _author_ = 'jake'
_project_ = 'leetcode'
return dummy.next
# https://leetcode.com/problems/remove-duplicates-from-sorted-array/
# Given a sorted array, remove the duplicates in place such that each element appear only once and return the new
length.
# python_1_to_1000/024_Swap_Nodes_in_Pairs.py - m # Do not allocate extra space for another array, you must do this in place with constant memory.
_author_ = 'jake' # Maintain a pointer to the next index to be filled with a new number. Check every number against the previous num
_project_ = 'leetcode' # (if any) and if different, move to the next_new index.
# Time - O(n)
# https://leetcode.com/problems/swap-nodes-in-pairs/ # Space - O(1)
# Given a linked list, swap every two adjacent nodes and return its head.
# E.g. given 1->2->3->4, you should return the list as 2->1->4->3. class Solution(object):
# Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be def removeDuplicates(self, nums):
changed. """
:type nums: List[int]
# Store the previous node, swap and append in pairs. :rtype: int
# Time - O(n) """
# Space - O(1) next_new = 0 # index where the next unique number is to be moved to
while dividend >= (max_divisor << 1): # find divisor * 2^i where divisor * 2^(i+1) > dividend class Solution(object):
max_divisor <<= 1 def nextPermutation(self, nums):
shift_count <<= 1 """
:type nums: List[int]
while shift_count >= 1: :rtype: void Do not return anything, modify nums in-place instead.
if dividend >= max_divisor: # subtract max_divisor whenever possible """
dividend -= max_divisor if not nums or len(nums) == 1:
result += shift_count return
shift_count >>= 1
max_divisor >>= 1 i = len(nums)-2 # starting at back, find the first decrease - increasing it will increment the permutation
while i >= 0 and nums[i] >= nums[i+1]:
if diff_sign: i -= 1
result = -result
return max(min(result, 2**31-1), -2**31) # required for leetcode if i != -1: # if any decrease then find the smallest larger number to swap with
j = i+1
while j < len(nums) and nums[j] > nums[i]:
j += 1
# python_1_to_1000/030_Substring_with_Concatenation_of_All_Words.py - h j -= 1
nums[i], nums[j] = nums[j], nums[i]
_author_ = 'jake'
_project_ = 'leetcode' # reverse all from i+1 onwards since they were decreasing and increasing minimises permutation
left = i+1
# https://leetcode.com/problems/substring-with-concatenation-of-all-words/ right = len(nums)-1
# You are given a string, s, and a list of words, words, that are all of the same length. while left < right:
# Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once nums[left], nums[right] = nums[right], nums[left]
# and without any intervening characters. left += 1
right -= 1
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/032_Longest_Valid_Parentheses.py - h # https://leetcode.com/problems/search-for-a-range
# Given a sorted array of integers, find the starting and ending position of a given target value.
_author_ = 'jake' # Your algorithm's runtime complexity must be in the order of O(log n).
_project_ = 'leetcode' # If the target is not found in the array, return [-1, -1].
# https://leetcode.com/problems/longest-valid-parentheses/ # Search for target +/- 0.5 (not integer so not found) and return the index above this.
# Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) # If same index is returned for + and - 0.5 then target not found.
parentheses substring. # Binary search could be implemented iteratively or use the bisect module.
# For example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4. # Time - O(log n)
# Space - O(1)
# Maintain a stack of indices in s of unmatched brackets. Pop an opening bracket when matched with a closing bracket.
# Push unmatched closing brackets and all opening brackets. Then find the longest gap between indices on the stack. class Solution(object):
# Time - O(n) def searchRange(self, nums, target):
# Space - O(n) """
:type nums: List[int]
class Solution(object): :type target: int
def longestValidParentheses(self, s): :rtype: List[int]
""" """
:type s: str def binary(target, left, right):
:rtype: int
""" if left > right:
stack = [] # indices of brackets that are not matched return left
stack.append(len(s)) # last unmatched index after end of s return binary(target, left, right)
max_length = stack[0] # first unmatched index before start of s
lower = binary(target - 0.5, 0, len(nums) - 1)
for index in range(1, len(stack)): # find max gap between remaining unmatched indices upper = binary(target + 0.5, 0, len(nums) - 1)
max_length = max(max_length, stack[index] - stack[index-1] - 1) return [-1, -1] if lower == upper else [lower, upper - 1]
return max_length
# python_1_to_1000/035_Search_Insert_Position.py
_author_ = 'jake'
# python_1_to_1000/033_Search_in_Rotated_Sorted_Array.py - m _project_ = 'leetcode'
class Solution(object):
# python_1_to_1000/034_Search_for_a_Range.py - m def isValidSudoku(self, board):
"""
:type board: List[List[str]] for r in range(self.size):
:rtype: bool for c in range(self.size):
"""
size = 9 if len(self.board[r][c]) == 1:
digits = {str(i) for i in range(1,10)} continue
rows = [set() for _ in range(size)] for digit in self.board[r][c]: # loop over possible digits
cols = [set() for _ in range(size)] if self.is_valid(r, c, digit): # will always be valid on first recursion
boxes = [set() for _ in range(size)] save_set = self.board[r][c]
self.board[r][c] = digit
for r in range(size): if self.solve_recursive():
for c in range(size): return True
self.board[r][c] = save_set # revert back
digit = board[r][c] return False
if digit == '.': return True
continue
if digit not in digits: def is_valid(self, row, col, digit): # checks whether board is valid after adding digit in row, col
return False for i in range(self.size): # row and column
if self.board[row][i] == digit or self.board[i][col] == digit:
box = (size//3) * (r // (size//3)) + (c // (size//3)) return False
if digit in rows[r] or digit in cols[c] or digit in boxes[box]:
return False n = self.size // 3
rows[r].add(digit) for r in range(n*(row//n), n + n*(row//n)): # box
cols[c].add(digit) for c in range(n*(col//n), n + n*(col//n)):
boxes[box].add(digit) if self.board[r][c] == digit:
return False
return True return True
# python_1_to_1000/037_Sudoku_Solver.py - h
# python_1_to_1000/038_Count_and_Say.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/sudoku-solver/
# Write a program to solve a Sudoku puzzle by filling the empty cells. # https://leetcode.com/problems/count-and-say/
# Empty cells are indicated by the character '.'. # The count-and-say sequence is the sequence of integers beginning as follows:
# You may assume that there will be only one unique solution. # 1, 11, 21, 1211, 111221, ...
# 21 is read off as "one 2, then one 1" or 1211.
# Convert unknown cells to a set of possible digits, initially {1..9}. # Given an integer n, generate the nth sequence.
# Repeatedly use known cells to eliminate possibilities in unknown cells. Which creates new known cells etc.
# If this does not result in a solution, recursively guess each cell from its range of possibilities. # Iterate through the previous sequence. When we see a different number, append [1, num] to the new sequence.
# When we see the same number increment its count.
class Solution(object): # Time - O(2^n), the sequence at worst doubles each step
def solveSudoku(self, board): # Space - O(2^n)
"""
:type board: List[List[str]] class Solution(object):
:rtype: void Do not return anything, modify board in-place instead. def countAndSay(self, n):
""" """
self.size = 9 :type n: int
self.board = board :rtype: str
self.new_digits = [] # new digits at start or digits found by reducing to 1 possibility """
sequence = [1]
for r in range(self.size): for _ in range(n-1):
self.board[r] = [digit for digit in self.board[r]] # convert from string to list of digits next = []
for c in range(self.size): for num in sequence:
if self.board[r][c] == '.': if not next or next[-1] != num:
self.board[r][c] = {str(i) for i in range(1, 10)} # convert dot to set of possible digits next += [1, num]
else: else:
self.new_digits.append((r, c)) next[-2] += 1
sequence = next
while self.new_digits:
for r, c in self.new_digits: return "".join(map(str, sequence))
self.eliminate(r, c) # given a new digit in (r,c), eliminate that digit from row, col and box
self.new_digits = []
self.find_new() # identify cells with only one possible digit
self.solve_recursive() # python_1_to_1000/039_Combination_Sum.py - m
_author_ = 'jake'
def eliminate(self, row, col): _project_ = 'leetcode'
for i in range(self.size):
# https://leetcode.com/problems/combination-sum/
if isinstance(self.board[i][col], set): # Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate
self.board[i][col].discard(self.board[row][col]) # discard does not cause error if element not present numbers sums to T.
if isinstance(self.board[row][i], set): # The same repeated number may be chosen from C unlimited number of times.
self.board[row][i].discard(self.board[row][col]) # All numbers (including target) will be positive integers.
# The solution set must not contain duplicate combinations.
for box_row in range(3*(row//3), 3 + 3*(row//3)):
for box_col in range(3*(col//3), 3 + 3*(col//3)): # Subtract each candidate from target as many times as possible whilst remainder is non-negative. Recurse
if isinstance(self.board[box_row][box_col], set): # each time, moving on to the next candidate.
self.board[box_row][box_col].discard(self.board[row][col]) # Time - approx f^n where f is target/average_candidate and n is the number of candidates with this nb recursions
return result # Your algorithm should run in O(n) time and uses constant space
def helper(self, nums, next, target, partial, result): # If an element of nums is a positive integer that could appear in nums (1 to len(nums) inclusive) and is not in
if target == 0: # correct place (nums[i] = i+1) then swap.
result.append(partial) # Time - O(n)
return # Space - O(1)
if next == len(nums):
return class Solution(object):
def firstMissingPositive(self, nums):
i = 0 """
while target - i * nums[next] >= 0: :type nums: List[int]
self.helper(nums, next + 1, target - i * nums[next], partial + [nums[next]] * i, result) :rtype: int
i += 1 """
i = 0
while i < len(nums):
# python_1_to_1000/040_Combination_Sum_II.py - m while nums[i] > 0 and nums[i] <= len(nums) and nums[nums[i]-1] != nums[i]:
temp = nums[nums[i]-1]
_author_ = 'jake' nums[nums[i]-1] = nums[i]
_project_ = 'leetcode' nums[i] = temp
# https://leetcode.com/problems/combination-sum-ii/ i += 1
# Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the
candidate numbers sums to T. for i, num in enumerate(nums):
# Each number in C may only be used once in the combination. if nums[i] != i+1:
# All numbers (including target) will be positive integers. return i+1
# The solution set must not contain duplicate combinations. return len(nums)+1
# Count the frequency of each number in candidates. For each number subtract all possible numbers of copies up to
# the count and without exceeding target and recurse for the next number. Alternative iterative version below.
# Time - O((f+1)^n) where f is the max frequency of any number and n is the number of distinct numbers # python_1_to_1000/042_Trapping_Rain_Water.py - h
new_partials = [] # https://leetcode.com/problems/multiply-strings/
for partial in partials: # Given two numbers represented as strings, return multiplication of the numbers as a string.
# The numbers can be arbitrarily large and are non-negative.
partial_sum = sum(partial) # Converting the input string to integer is NOT allowed.
for i in range(count + 1): # You should NOT use internal library such as BigInteger.
if partial_sum + candidate*i < target:
new_partials.append(partial + [candidate]*i) # Create a list of each digit in the result, starting wiht the least significant digit.
elif partial_sum + candidate*i == target: # Reverse input digit order. nums1[i] * nums2[j] is added to result[i+j+1] and result[i+j]
results.append(partial + [candidate]*i) # Alternatively: return str(int(num1) * int(num2))
if partial_sum + candidate*i >= target: # Time - O(m * n) where inputs are of lengths m and n
break # Space - O(max(m,n))
# https://leetcode.com/problems/first-missing-positive/
# Given an unsorted integer array, find the first missing positive integer. for i in range(len(num1)):
# e.g. given [1,2,0] return 3, and [3,4,-1,1] return 2.
int1 = ord(num1[i]) - ord('0') class Solution(object):
def jump(self, nums):
for j in range(len(num2)): """
:type nums: List[int]
int2 = ord(num2[j]) - ord('0') :rtype: int
"""
tens, units = divmod(int1 * int2, 10) if len(nums) == 1:
return 0
result[i + j] += units # add units and handle carry of units
if result[i + j] > 9: start, end = 0, 0 # indices in nums of current range
result[i + j + 1] += result[i + j] // 10 max_index = 0
result[i + j] %= 10 steps = 1
result[i + j + 1] += tens # add tens and handle carry of tens while True: # will always terminate since last index is accessible
if result[i + j + 1] > 9: for i in range(start, end+1):
result[i + j + 2] += result[i + j + 1] // 10 max_index = max(max_index, i + nums[i])
result[i + j + 1] %= 10 if max_index >= len(nums)-1:
return steps
while len(result) > 1 and result[-1] == 0: # remove trailing zeros steps += 1
result.pop() start, end = end + 1, max_index
return "".join(map(str, result[::-1])) # reverse and convert to string
# python_1_to_1000/046_Permutations.py - m
# python_1_to_1000/044_Wildcard_Matching.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/permutations/
# https://leetcode.com/problems/wildcard-matching/ # Given a collection of distinct numbers, return all possible permutations.
# Implement wildcard pattern matching with support for '?' and '*'.
# '?' Matches any single character. # For each number, insert it at all possible places in all existing permutations.
# '*' Matches any sequence of characters (including the empty sequence). # Alternatively recursively swap every index with every greater index (and itself).
# The matching should cover the entire input string (not partial). # Time - O(n^2 * n!). n! results, each of with has n elements added, each addition taking O(n) time for list slicing
# Space - O(n *n!)
# Record index in p of star and index in s at that time. Try to match without star, if fails back up and use *
# to match one more character from s. class Solution(object):
# Time - O(m * n), * at beginning of p could match many chars in s before failing and repeatedly backtrack def permute(self, nums):
# Space - O(1) """
:type nums: List[int]
class Solution(object): :rtype: List[List[int]]
def isMatch(self, s, p): """
permutations = [[]]
i, j = 0, 0 # next indices to be matched in s and p
star = -1 # last index in p of * for num in nums:
new_permutations = []
while i < len(s): for perm in permutations:
for i in range(len(perm) + 1):
# if beyond end of pattern or pattern is unmatched letter new_permutations.append(perm[:i] + [num] + perm[i:])
if j >= len(p) or (p[j] not in {'*' , '?'} and p[j] != s[i]): permutations = new_permutations
if star == -1: # no flexibility if no star
return False return permutations
j = star + 1 # reset p to character after star
star_i += 1 # reset s to charcater after star_i, i.e. use * to match one char from s
i = star_i class Solution2(object):
def permute(self, nums):
elif p[j] == '*': # record * index in p and next index to be matched in s """
star = j :type nums: List[int]
star_i = i :rtype: List[List[int]]
j += 1 """
return self.permute_helper(nums, 0)
else: # chars match or ?, increment both
i += 1 def permute_helper(self, nums, index):
j += 1
permutations = []
while j < len(p): # any remaining characters in p can only be *
if p[j] != '*': if index >= len(nums):
return False permutations.append(nums[:]) # make a new copy to freeze nums
j += 1
return True for i in range(index, len(nums)):
nums[i], nums[index] = nums[index], nums[i] # swap with all indices >= index
permutations += self.permute_helper(nums, index + 1)
nums[i], nums[index] = nums[index], nums[i] # swap back
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/jump-game-ii/
# Given an array of non-negative integers, you are initially positioned at the first index of the array.
# Each element in the array represents your maximum jump length at that position.
# Your goal is to reach the last index in the minimum number of jumps. # python_1_to_1000/047_Permutations_II.py - m
# The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last
index.) _author_ = 'jake'
# You can assume that you can always reach the last index. _project_ = 'leetcode'
# For each index in currently accessible range, update the max_index that can be reached in one more step. # https://leetcode.com/problems/permutations-ii/
# Iterate to next range, from end of previous range to max_index. # Given a collection of numbers that might contain duplicates, return all possible unique permutations.
# Time - O(n)
# Space - O(1) # Count occurences of each unique number. Recursively append each number if still has a positive count.
# Time - O(n^2 * n!), as 046_Permutations if all numbers are unique
class Solution(object):
# python_1_to_1000/054_Spiral_Matrix.py - m def merge(self, intervals):
"""
_author_ = 'jake' :type intervals: List[Interval]
_project_ = 'leetcode' :rtype: List[Interval]
"""
# https://leetcode.com/problems/spiral-matrix/ intervals.sort(key=lambda x : x[0])
# Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. merged = []
# Use row_leg and col_leg to traxk the max number of moves before turning. Decrease row_leg and col_leg then turning. for interval in intervals:
# Time - O(m * n) if not merged or merged[-1][1] < interval[0]:
# Space - O(1) merged.append(interval)
else:
class Solution(object): merged[-1][1] = max(merged[-1][1], interval[1])
def spiralOrder(self, matrix): return merged
"""
:type matrix: List[List[int]]
:rtype: List[int]
""" # python_1_to_1000/057_Insert_Intervals.py - m
if not matrix or not matrix[0]:
return [] _author_ = 'jake'
_project_ = 'leetcode'
spiral = []
row, col = 0, -1 # https://leetcode.com/problems/insert-interval/
d_row, d_col = 0, 1 # movement direction # Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
row_leg, col_leg = len(matrix[0]), len(matrix)-1 # steps before change of direction # You may assume that the intervals were initially sorted according to their start times.
row += d_r
# Find all intervals strictly to the left and to the right of new interval. If any intervals in between they col += d_c
# overlap with newInterval. If any overlap, update start of newInterval with start of first overlap and
# update end with end of last overlap. return spiral
# Time - O(n)
# Space - O(1)
while right >= 0 and intervals[right][0] > newInterval[1]: # Find each digit according to the ratio between k and the total number of possible permutations.
right -= 1 # Time - O(n**2) since each iteration adds one digit and O9n) for del from list
# Space - O(n) to store chars list
if left <= right:
newInterval[0] = min(newInterval[0], intervals[left][0]) from math import factorial
newInterval[1] = max(newInterval[1], intervals[right][1])
class Solution(object):
return intervals[:left] + [newInterval] + intervals[right + 1:] def getPermutation(self, n, k):
"""
:type n: int
:type k: int
# python_1_to_1000/058_Length_of_Last_Word.py :rtype: str
"""
_author_ = 'jake' chars = [str(i) for i in range(1, n+1)] # the symbols that will be permuted
_project_ = 'leetcode' permutations = factorial(n) # total number of permutations for this n
k -= 1 # change indexing to 0
# https://leetcode.com/problems/length-of-last-word/ result = []
# Given a string s consists of upper/lower-case alphabets and empty space characters ' ',
# return the length of last word in the string. while chars:
# If the last word does not exist, return 0. digit = n * k // permutations # get the first digit (range is 0 to n-1)
# Note: A word is defined as a character sequence consists of non-space characters only. result.append(chars[digit]) # map from digit to a symbol
del chars[digit] # remove that symbol
# Start at last character and decrement i. permutations //= n # repeat for next digit with decreased permutations, n and k
# Set variable end when non-blank is seen. k -= digit * permutations
# Return at next non-blank. n -= 1
# Time - O(n)
# Space - O(1) return "".join(result)
class Solution(object):
def lengthOfLastWord(self, s):
""" # python_1_to_1000/061_Rotate_List.py - m
:type s: str
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
i = len(s) - 1
end = -1 # https://leetcode.com/problems/rotate-list/
# Given a list, rotate the list to the right by k places, where k is non-negative.
while i >= 0:
if s[i] == ' ' and end != -1: # Count length of list, reset k to k % length (avoids repeated cycles). Connect tail of list with head and then
return end - i # break k%length steps before the old tail.
if s[i] != ' ' and end == -1: # Time - O(n), n is length of list
end = i # Space - O(1)
i -= 1
return end + 1 if end != -1 else 0 # Definition for singly-linked list.
class ListNode(object):
def __init__(self, x):
self.val = x
# python_1_to_1000/059_Spiral_Matrix_II.py - m self.next = None
# python_1_to_1000/062_Unique_Paths.py - m # Dynamic programming, min path to a cell = cell value + min(min paths to cells above and left)
# Time - O(m * n)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/unique-paths/ def minPathSum(self, grid):
# A robot is located at the top-left corner of a m x n grid. """
# The robot can only move either down or right at any point in time. :type grid: List[List[int]]
# The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). :rtype: int
# How many possible unique paths are there? """
m = len(grid)
# Dynamic programming, nb paths = paths from above cell + paths from right cell n = len(grid[0])
# Alternatively, catalan number.
# Time - O(m * n) min_path = [float('inf') for _ in range(n + 1)]
# Space - O(n), just keep last row instead of entire grid min_path[1] = 0
# Dynamic programming. Nb paths is 0 if obstacle, else paths from above + paths from left. def is_int(self, s, signed):
# Time - O(m * n) if len(s) == 0:
# Space - O(n) return False
if s[0] == '-' and signed:
class Solution(object): s = s[1:]
def uniquePathsWithObstacles(self, obstacleGrid): elif s[0] == '+' and signed:
""" s = s[1:]
:type obstacleGrid: List[List[int]] if len(s) == 0:
:rtype: int return False
"""
m = len(obstacleGrid) for c in s:
n = len(obstacleGrid[0]) if c not in self.digits:
return False
if not m or not n: return True
return 0
if obstacleGrid[0][0] or obstacleGrid[-1][-1]:
return 0 def is_float(self, s):
try:
row_paths = [0 for _ in range(n+1)] dot = s.index('.')
row_paths[1] = 1 before = s[:dot]
after = s[dot+1:]
for row in range(1, m+1):
new_row_paths = [0] if before and before[0] in '+-':
for col in range(1, n+1): before = before[1:]
if obstacleGrid[row-1][col-1]: if before and not self.is_int(before, False):
new_row_paths.append(0) return False
else: if after and not self.is_int(after, False):
new_row_paths.append(new_row_paths[-1] + row_paths[col]) return False
row_paths = new_row_paths return before or after
except:
return row_paths[-1] return False
# python_1_to_1000/067_Add_Binary.py justified.append("".join(line))
class Solution(object):
def addBinary(self, a, b): # python_1_to_1000/069_Sqrt(x).py
"""
:type a: str _author_ = 'jake'
:type b: str _project_ = 'leetcode'
:rtype: str
""" # https://leetcode.com/problems/sqrtx/
result = [] # Implement int sqrt(int x).
carry = 0 # Compute and return the square root of x.
i = len(a)-1
j = len(b)-1 # Newton method. Initial guess of x. Iteratively update guess to be average of previous guess and x // guess.
# Since guess is too high, x // guess is too low.
while carry or i >= 0 or j >= 0: # Terminate when guess^2 <= x.
# Time - O((log x)^3) - log x from nb iterations, log x from multiple and log x from divide
total = carry # Space - O(1)
if i >= 0:
total += int(a[i]) class Solution(object):
i -= 1 def mySqrt(self, x):
if j >= 0: """
total += int(b[j]) :type x: int
j -= 1 :rtype: int
result.append(str(total % 2)) """
carry = total // 2 guess = x
while guess * guess > x:
return "".join(result[::-1]) guess = (guess + x // guess) // 2
return guess
# python_1_to_1000/068_Text_Justification.py - h
class Solution(object):
# python_1_to_1000/071_Simplify_Path.py - m def setZeroes(self, matrix):
"""
_author_ = 'jake' :type matrix: List[List[int]]
_project_ = 'leetcode' :rtype: void Do not return anything, modify matrix in-place instead.
"""
# https://leetcode.com/problems/simplify-path/ if not matrix or not matrix[0]:
# Given an absolute path for a file (Unix-style), simplify it. return 0
# Create result stack. Go up a level if '..'. Stay at same level if '.'. rows = len(matrix)
# Time - O(n) cols = len(matrix[0])
# Space - O(n)
first_row_zero = any([True for c in range(cols) if matrix[0][c] == 0])
class Solution(object): first_col_zero = any([True for r in range(rows) if matrix[r][0] == 0])
def simplifyPath(self, path):
""" for r in range(1, rows):
:type path: str for c in range(1, cols):
:rtype: str if matrix[r][c] == 0:
""" matrix[r][0] = 0
path_list = path.split('/') # does not treat consecutive delimiters as one if delimiter specified matrix[0][c] = 0
result = []
for r in range(1, rows):
for item in path_list: if matrix[r][0] == 0:
if item == '..': # go up one level if possible for c in range(1, cols):
if result: matrix[r][c] = 0
result.pop()
elif item and item != '.': # add item to path for c in range(1, cols):
result.append(item) if matrix[0][c] == 0:
# else ignore '.' and '' for r in range(1, rows):
matrix[r][c] = 0
return '/' + '/'.join(result)
if first_row_zero:
matrix[0] = [0] * cols
# python_1_to_1000/072_Edit_Distance.py - m if first_col_zero:
for r in range(rows):
_author_ = 'jake' matrix[r][0] = 0
_project_ = 'leetcode'
# https://leetcode.com/problems/edit-distance/
# Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. # python_1_to_1000/074_Search_a_2D_Matrix.py - m
# You have the following 3 operations permitted on a word (each 1 step):
# a) Insert a character _author_ = 'jake'
# b) Delete a character _project_ = 'leetcode'
# c) Replace a character
# https://leetcode.com/problems/search-a-2d-matrix/
# Dynamic programming. Base case if either string is empty, return unmatched length of other string. # Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
# If last characters matched then same cost as matching other characters. Else best case of insert, delete or replace. # Integers in each row are sorted from left to right.
# Time - O(m * n) # The first integer of each row is greater than the last integer of the previous row.
# Space - O(m * n)
# Treat the 2-d matrix as a 1-d list of length rows * cols. Binary search indices from 0 to rows * cols - 1.
class Solution(object): # Time - O(log m + log n)
def minDistance(self, word1, word2): # Space - O(1)
"""
:type word1: str class Solution(object):
:type word2: str def searchMatrix(self, matrix, target):
:rtype: int """
""" :type matrix: List[List[int]]
:type target: int
def edit_distance(i, j): :rtype: bool
if i < 0 or j < 0: """
return i + 1 + j + 1 if not matrix or not matrix[0]:
return False
if (i, j) in memo:
return memo[(i, j)] rows, cols = len(matrix), len(matrix[0])
low, high = 0, rows * cols - 1
if word1[i] == word2[j]:
result = edit_distance(i - 1, j - 1) while high >= low:
else:
result = 1 + min(edit_distance(i - 1, j), mid = (high + low) // 2
edit_distance(i, j - 1), value = matrix[mid // cols][mid % cols] # convert mid to a row and column
edit_distance(i - 1, j - 1))
if target == value:
memo[(i, j)] = result return True
return result if target > value:
low = mid + 1
memo = {} else:
# python_1_to_1000/075_Sort_Colors.py - m # python_1_to_1000/077_Combinations.py - m
# https://leetcode.com/problems/sort-colors/ # https://leetcode.com/problems/combinations/
# Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, # Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
# with the colors in the order red, white and blue.
# Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. # Recursively ignore the last number and choose k form n-1, or use the last number and combine with k-1 from n-1.
# Time - O(k * n! / (k! * (n-k)!)), nCk combinations each of length k
# Overwrite each index with blue. If index was red or white, add a new white and increment white pointer. If index # Space - O(k * n! / (k! * (n-k)!))
# was red, add a new red and increment red pointer.
# Time - O(n) class Solution(object):
# Space - O(1) def combine(self, n, k):
"""
class Solution(object): :type n: int
def sortColors(self, nums): :type k: int
""" :rtype: List[List[int]]
:type nums: List[int] """
:rtype: void Do not return anything, modify nums in-place instead. if k == 0: # or if k == 1 return [[i] for i in range(1,n+1)]
""" return [[]]
next_red, next_white = 0, 0 if n < k: # or if k == n return [[i for i in range(1,n+1)]]
return []
for i in range(len(nums)):
without_last = self.combine(n-1, k)
colour = nums[i]
nums[i] = 2 with_last = [[n] + combo for combo in self.combine(n-1, k-1)]
if colour == 0:
nums[next_red] = 0 # python_1_to_1000/078_Subsets.py - m
next_red += 1
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/076_Maximum_Window_Substring.py - h # https://leetcode.com/problems/subsets/
# Given a set of distinct integers, nums, return all possible subsets.
_author_ = 'jake' # The solution set must not contain duplicate subsets.
_project_ = 'leetcode'
# Each bit of binary number form 0 to 2**n - 1 represents whether or not an entry in nums is in that set.
# https://leetcode.com/problems/minimum-window-substring/ # Alternatively, copy partial subsets both with and without each item.
# Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity # Time - O(n * 2**n), 2**n subsets each of length n.
O(n). # Space - O(n * 2**n)
# If there is no such window in S that covers all characters in T, return the empty string "".
# If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S. class Solution(object):
def subsets(self, nums):
# Slide end of window forwards when not all letters in t are matched with window. Slide start of window when all """
# letters are matched. Maintain the required count of each letter (can be negative if excess) and overall to_match. :type nums: List[int]
# Time - O(n) :rtype: List[List[int]]
# Space - O(1) """
nb_subsets = 2**len(nums)
from collections import Counter all_subsets = []
while end < len(s)-1 or to_match == 0: # can extend end or all matched so will increase start
if i >= len(word): # nothing more of word to find if nums[mid] < nums[right]: # RHS is sorted
return True if target > nums[mid] and target <= nums[right]: # check target in range of both ends
if r < 0 or r >= len(board) or c < 0 or c >= len(board[0]): # outside board return self.binary(nums, mid+1, right, target) # target cannot be on LHS
return False return self.binary(nums, left, mid-1, target) # target cannot be on RHS
if word[i] != board[r][c]: # no match letter
return False if nums[left] == nums[mid] and nums[mid] != nums[right]: # LHS is flat and does not include target
return self.binary(nums, mid+1, right, target) # so check RHS
board[r][c] = '*' # set this position so cannot be used again if nums[right] == nums[mid] and nums[mid] != nums[left]: # RHS is flat and does not include target
return self.binary(nums, left, mid-1, target) # so check LHS
if (self.can_find(word, i+1, board, r+1, c) or self.can_find(word, i+1, board, r-1, c) or
self.can_find(word, i+1, board, r, c+1) or self.can_find(word, i+1, board, r, c-1)): if self.binary(nums, left, mid-1, target): # both sides flat, if not fount on one side check the other
return True return True
return self.binary(nums, mid+1, right, target)
board[r][c] = word[i] # if False, reset position to letter
return False
# python_1_to_1000/082_Remove_Duplicates_from_Sorted_List_II.py - m
# python_1_to_1000/080_Remove_Duplicates_from_Sorted_Array_II.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
# https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/ # Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the
# Follow up for "Remove Duplicates": original list.
# What if duplicates are allowed at most twice?
# For example, given sorted array nums = [1,1,1,2,2,3], # If node is duplicated, move past all nodes of same value. Else add node to final list.
# Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. # Time - O(n)
# Space - O(1)
# Maintain a pointer to the next index to contain a result. If a new number does not have 2 copies already
# in result then add it. # Definition for singly-linked list.
# Time - O(2) class ListNode(object):
# Space - O(1) def __init__(self, x):
self.val = x
class Solution(object): self.next = None
def removeDuplicates(self, nums):
""" class Solution(object):
:type nums: List[int] def deleteDuplicates(self, head):
:rtype: int """
""" :type head: ListNode
next = 2 # next index to be filled with result :rtype: ListNode
"""
for index in range(2, len(nums)): pseudo = prev = ListNode(None)
pseudo.next = head
if nums[index] != nums[next-2]: # result does not contain 2 copies of this num node = head
nums[next] = nums[index]
next += 1 while node:
return min(next, len(nums)) if node.next and node.val == node.next.val: # node begins a sequence of duplicates
duplicate_value = node.val
node = node.next
# python_1_to_1000/081_Search_in_Rotated_Sorted_Array_II.py - m while node and node.val == duplicate_value: # skip over all duplicates
node = node.next
_author_ = 'jake' prev.next = None # list ends until non-duplicate found
_project_ = 'leetcode'
else: # node is not duplicated
# https://leetcode.com/problems/search-in-rotated-sorted-array-ii/ prev.next = node # add to resulting list
# Follow up for "Search in Rotated Sorted Array": prev = node
# What if duplicates are allowed? node = node.next
# Would this affect the run-time complexity? How and why?
# Write a function to determine if a given target is in the array. return pseudo.next
# When splitting the array at mid, one side contains the rotation point. The other side must be increasing or flat.
# Rotation point side cannot be increasing, only flat or decreasing.
# Therefor if we find an increasing side we know whether to recurse on that side or the other. # python_1_to_1000/083_Remove_Duplicates_from_Sorted_List.py
# Then if either side is not flat we know it is not sorted adn the other side is, so recurse there.
# If both sides are flat we must check them both. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/remove-duplicates-from-sorted-list/
class Solution(object): # Given a sorted linked list, delete all duplicates such that each element appear only once.
def search(self, nums, target):
""" # If next node is same as node, link node to node.next.next. Else move to next node.
:type nums: List[int] # Time - O(n)
return head
# python_1_to_1000/086_Partition_List.py - m
_author_ = 'jake'
# python_1_to_1000/084_Largest_Rectangle_in_Histogram.py - h _project_ = 'leetcode'
# python_1_to_1000/085_Maximal_Rectangle.py - h
# python_1_to_1000/087_Scramble_String.py - h
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/maximal-rectangle/
# Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. # https://leetcode.com/problems/scramble-string/
# Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
# For each row build a 'histogram' of the number of 1s above and including each column. Then proceed as for problem 084 # To scramble the string, we may choose any non-leaf node and swap its two children.
# and pop a column off the stack whenever its 2 boundaries are lower. # Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.
# Time - O(m*n)
# Space - O(n) # Base cases of strings containing different characters or same string. Else for all partition points, lest and right
# sides are scrambled versions, before or after swapping.
class Solution(object): # Time - exponential since 4n recursive calls for string of length n.
def maximalRectangle(self, matrix):
""" from collections import Counter
:type matrix: List[List[str]]
:rtype: int class Solution(object):
""" def isScramble(self, s1, s2):
if not matrix or not matrix[0]: """
return 0 :type s1: str
:type s2: str
rows = len(matrix) :rtype: bool
cols = len(matrix[0]) """
count1 = Counter(s1)
max_area = 0 for c in s2:
if c not in count1: return gray
return False
count1[c] -= 1
if count1[c] < 0:
return False
# python_1_to_1000/090_Subsets_II.py - m
if s1 == s2:
return True _author_ = 'jake'
_project_ = 'leetcode'
for partition in range(1, len(s1)):
# https://leetcode.com/problems/subsets-ii/
s1_l = s1[:partition] # partition number of chars from left # Given a collection of integers that might contain duplicates, nums, return all possible subsets.
s1_r = s1[partition:] # last (len(s1) - partition) chars # Note: The solution set must not contain duplicate subsets.
s2_l = s2[:partition]
s2_r = s2[partition:] # Count the frequency of times each num in nums. Starting with the empty subset, for each num append it to all
s2_l_swap = s2[:-partition] # (len(s2) - partition) chars from left # subsets every possible number of times (between 0 and its frequency in nums, inclusive).
s2_r_swap = s2[-partition:] # last partition chars # Time - O(n * 2**n), worst case when nums are all ujnique
# Space - O(n * 2**n)
if (self.isScramble(s1_l, s2_l) and self.isScramble(s1_r, s2_r)) or \
(self.isScramble(s1_l, s2_r_swap) and self.isScramble(s1_r, s2_l_swap)): from collections import Counter
return True
class Solution(object):
return False def subsetsWithDup(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
# python_1_to_1000/088_Merge_Sorted_Array.py """
num_count = Counter(nums)
_author_ = 'jake' results = [[]]
_project_ = 'leetcode'
for num in num_count:
# https://leetcode.com/problems/merge-sorted-array/ results += [partial+[num]*i for i in range(1,num_count[num]+1) for partial in results]
# Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
# You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from return results
nums2.
# The number of elements initialized in nums1 and nums2 are m and n respectively.
# Start from end of nums1. Move largest elements from each array.
# Time - O(m + n) # python_1_to_1000/091_Decode_Ways.py - m
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def merge(self, nums1, m, nums2, n):
""" # https://leetcode.com/problems/decode-ways/
:type nums1: List[int] # A message containing letters from A-Z is being encoded to numbers using the following mapping:
:type m: int # 'A' -> 1, 'B' -> 2, ..., 'Z' -> 26
:type nums2: List[int] # Given an encoded message containing digits, determine the total number of ways to decode it.
:type n: int
:rtype: void Do not return anything, modify nums1 in-place instead. # Dynamic programming. Calc ways for prefix of length i from prefixes of lengths i-1 and i-2.
""" # Time - O(n)
i, j, k = m - 1, n - 1, m + n - 1 # Space - O(n), could be O(1) by keeping only last 2 values of nb_ways
if i < 0: # Nothing to move if only nums1 remain, else move rest of nums2 nb_ways = [0] * (len(s)+1) # nb_ways[i] is number of ways to decode prefix of length i
nums1[:k+1] = nums2[:j+1] nb_ways[0] = 1 # required else '10' will be 0
if s[0] != '0':
nb_ways[1] = 1
# python_1_to_1000/089_Gray_Code.py - m
for i in range(1, len(s)):
_author_ = 'jake'
_project_ = 'leetcode' if s[i] != '0': # last char is not '0'
nb_ways[i+1] += nb_ways[i] # use all ways to decode without this char
# https://leetcode.com/problems/gray-code/ if 10 <= int(s[i-1:i+1]) <= 26: # last 2 form int between 10 and 26
# The gray code is a binary numeral system where two successive values differ in only one bit. nb_ways[i+1] += nb_ways[i-1] # use all ways to decode without last 2 chars
# Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code.
# A gray code sequence must begin with 0. For example, given n = 2, return [0,1,3,2]. Its gray code sequence is: return nb_ways[-1]
# 00 - 0, 01 - 1, 11 - 3, 10 - 2
# Grey sequence of n + 1 is formed starting with sequence for n, then appending the reverse of that sequence with
# the extra bit set. # python_1_to_1000/092_Reverse_Linked_List_II.py - m
# GC(0) = [0], GC(1) = [0,1], GC(2) = [0,1,3,2], GC(3) = [0,1,3,2,6,7,5,4]
# Time - O(2**n) _author_ = 'jake'
# Space - O(2**n) _project_ = 'leetcode'
self.val = x # Given a binary tree, return the inorder traversal of its nodes' values.
self.next = None # Note: Recursive solution is trivial, could you do it iteratively?
class Solution(object): # From root, go as far left as possible pushing all nodes onto stack. While nodes on stack, pop a node and add it to
def reverseBetween(self, head, m, n): # the result. Its left child (if any) has already been visited because it was added to the stack later so popped
""" # earlier. If the node has a right child, add that child and all its left branch to the stack.
:type head: ListNode # Time - O(n)
:type m: int # Space - O(n)
:type n: int
:rtype: ListNode # Definition for a binary tree node.
""" # class TreeNode(object):
pseudo = ListNode(None) # create a new pseudo head # def __init__(self, x):
pseudo.next = head # self.val = x
node = pseudo # self.left = None
n -= m # n = nb nodes to be reversed - 1 # self.right = None
while m > 1: # find the tail of the first non-reversed section class Solution(object):
node = node.next def inorderTraversal(self, root):
m -= 1 """
:type root: TreeNode
reversed_head = None :rtype: List[int]
next_reverse = node.next """
stack, result = [], []
while n >= 0: # add next_reverse in front of reversed_head
tail = next_reverse.next while root: # make top of stack the smallest value
next_reverse.next = reversed_head stack.append(root)
reversed_head = next_reverse root = root.left
next_reverse = tail
n -= 1 while stack:
node.next.next = tail # link tail of reversed section to second non-reversed section node = stack.pop()
node.next = reversed_head # link tail of the first non-reversed section to reversed section result.append(node.val)
# https://leetcode.com/problems/restore-ip-addresses/
# Given a string containing only digits, restore it by returning all possible valid IP address combinations. # python_1_to_1000/095_Unique_Binary_Search_Trees_II.py - m
# E.g. given "25525511135", return ["255.255.11.135", "255.255.111.35"]. (Order does not matter)
_author_ = 'jake'
# For each of the 4 sections of an IP address, use 3 chars if between 100 and 255, 2 if > 10 and always use 1 char - _project_ = 'leetcode'
# provided that the remaining chars are not too few or too many to make an IP address.
# an IP address # https://leetcode.com/problems/unique-binary-search-trees-ii/
# Time - O(1), max of 4**3 possibilities for any s # Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n.
# Space - O(1)
# Any number i from 1 to n is the root. Numbers less than i form the left subtree, numbers greater from the right.
class Solution(object): # Time - O(n**2 * Catalan(n)) where Catalan(n) = 2n! / (n+1)!n!
def restoreIpAddresses(self, s): # Space - O(n * Catalan(n))
"""
:type s: str # Definition for a binary tree node.
:rtype: List[str] class TreeNode(object):
""" def __init__(self, x):
NB_SECTIONS = 4 self.val = x
if 3 * NB_SECTIONS < len(s) < NB_SECTIONS: # cannot make any IPs self.left = None
return [] self.right = None
# https://leetcode.com/problems/binary-tree-inorder-traversal/ # python_1_to_1000/096_Unique_Binary_Search_Trees.py - m
_author_ = 'jake' # https://leetcode.com/problems/validate-binary-search-tree/
_project_ = 'leetcode' # Given a binary tree, determine if it is a valid binary search tree (BST).
# Assume a BST is defined as follows:
# https://leetcode.com/problems/unique-binary-search-trees/ # The left subtree of a node contains only nodes with keys less than the node's key.
# Given an integer n, count all structurally unique BST's (binary search trees) that store values 1...n. # The right subtree of a node contains only nodes with keys greater than the node's key.
# Both the left and right subtrees must also be binary search trees.
# Dynamic programming. Base case of 1 for n = 0 or 1. For each of n possible root nodes, multiply the
# possible left subtrees with the right subtrees. # Perform an inorder traversal and check that each node is greater than the previous. Does not work if equal nodes
# Time - O(n**2) # are allowed.
# Space - O(n) # Alternatively track the upper and lower bounds possible for each node, depending on parents.
# Time - O(n)
# Definition for a binary tree node. # Space - O(n), or log n if balanced
class TreeNode(object):
def __init__(self, x): # Definition for a binary tree node.
self.val = x class TreeNode(object):
self.left = None def __init__(self, x):
self.right = None self.val = x
self.left = None
class Solution(object): self.right = None
def numTrees(self, n):
""" class Solution(object):
:type n: int def isValidBST(self, root):
:rtype: int """
""" :type root: TreeNode
memo = [-1] * (n+1) # memo[i] is number of ways for i nodes :rtype: bool
return self.helper(n, memo) """
self.correct = True
def helper(self, n, memo): self.prev = float('-inf')
if n <= 1: self.inorder(root)
return 1 # 1 tree for n==0 (empty tree) and 1 tree for n==1 return self.correct
self.inorder(node.right)
# python_1_to_1000/097_Interleaving_String.py - m
class Solution2(object):
_author_ = 'jake' def isValidBST(self, root):
_project_ = 'leetcode' return self.valid(root, float('-inf'), float('inf'))
# https://leetcode.com/problems/interleaving-string/ def valid(self, node, lower, upper): # node.val must be above lower and below upper
# Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. if not node:
return True
# If the next char of s1 or s2 matches s3, recurse on the remainder. if node.val <= lower or node.val >= upper: # can be amended if equal values are allowed
# Time - O(m * n), every prefix of s1 * every prefix of s2 return False
# Space - O(m * n) return self.valid(node.left, lower, node.val) and self.valid(node.right, node.val, upper)
class Solution(object):
def isInterleave(self, s1, s2, s3):
""" # python_1_to_1000/099_Recover_Binary_Search_Tree.py - m
:type s1: str
:type s2: str _author_ = 'jake'
:type s3: str _project_ = 'leetcode'
:rtype: bool
""" # https://leetcode.com/problems/recover-binary-search-tree/
if len(s1) + len(s2) != len(s3): # early return # The values of 2 nodes of a binary search tree (BST) are swapped by mistake.
return False # Recover the tree without changing its structure.
return self.helper(s1, s2, s3, 0, 0, {})
# Perform an inorder traversal tracking the previous node. The first time a non-increasing node value is found,
# store the previous node. The second time a non-increasing node value is found, store the node.
def helper(self, s1, s2, s3, i, j, memo): # i, j are indices of next char to be matched in s1, s2 # E.g. for 1,2,3,8,5,6,7,4,9 we store 8 and 4.
# Time - O(n)
if i >= len(s1) or j >= len(s2): # base case, one string already matched # Space - O(n), recursion depth worst case, log n if balanced
return s1[i:] + s2[j:] == s3[i+j:]
# Definition for a binary tree node.
if (i, j) in memo: class TreeNode(object):
return memo[(i, j)] def __init__(self, x):
self.val = x
result = False self.left = None
if s1[i] == s3[i+j] and self.helper(s1, s2, s3, i+1, j, memo): self.right = None
result = True
elif s2[j] == s3[i+j] and self.helper(s1, s2, s3, i, j+1, memo): class Solution(object):
result = True def recoverTree(self, root):
"""
memo[(i, j)] = result :type root: TreeNode
return result :rtype: void Do not return anything, modify root in-place instead.
"""
self.swapped1 = None
self.swapped2 = None
# python_1_to_1000/098_Validate_Binary_Search_Tree.py - m self.prev = TreeNode(float('-inf'))
self.inorder(root)
_author_ = 'jake' self.swapped1.val, self.swapped2.val = self.swapped2.val, self.swapped1.val
_project_ = 'leetcode'
# python_1_to_1000/100_Same_Tree.py # Create a list of all non-null nodes from the nodes in the level above.
# Time - O(n)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
# Definition for a binary tree node.
# https://leetcode.com/problems/same-tree/ # class TreeNode(object):
# Given two binary trees, write a function to check if they are equal or not. # def __init__(self, x):
# Two binary trees are considered equal if they are structurally identical and the nodes have the same value. # self.val = x
# self.left = None
# Traverse both trees, checking nodes exist in same places and values are same. Could preorder, inorder or postorder. # self.right = None
# Time - O(min(m, n))
# Space - O(min(m, n)), or log is balanced class Solution(object):
def levelOrder(self, root):
# Definition for a binary tree node. """
class TreeNode(object): :type root: TreeNode
def __init__(self, x): :rtype: List[List[int]]
self.val = x """
self.left = None result = []
self.right = None if not root:
return result
class Solution(object):
def isSameTree(self, p, q): level_nodes = [root]
"""
:type p: TreeNode while level_nodes:
:type q: TreeNode
:rtype: bool new_level_nodes = []
""" result.append([])
if not p and not q:
return True for node in level_nodes:
if not p or not q: result[-1].append(node.val)
return False if node.left:
new_level_nodes.append(node.left)
if p.val != q.val: if node.right:
return False new_level_nodes.append(node.right)
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
level_nodes = new_level_nodes
return result
# python_1_to_1000/101_Symmetric_Tree.py
# python_1_to_1000/103_Binary_Tree_Zigzag_Level_Order_Traversal.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/symmetric-tree/
# Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). # https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/
# Given a binary tree, return the zigzag level order traversal of its nodes' values.
# Check if left and right subtrees are both present or not, then if root values are equal. Then recurse on their # (ie, from left to right, then right to left for the next level and alternate between).
# subtrees being mirrors - left/left of right/right and left/right of right/left
# Time - O(n) # Alternately append new nodes from left to right and right to left.
# Space - O(n) # Time - O(n)
# Space - O(n)
# Definition for a binary tree node.
# class TreeNode(object): # Definition for a binary tree node.
# def __init__(self, x): # class TreeNode(object):
# self.val = x # def __init__(self, x):
# self.left = None # self.val = x
# self.right = None # self.left = None
# self.right = None
class Solution(object):
def isSymmetric(self, root): class Solution(object):
""" def zigzagLevelOrder(self, root):
:type root: TreeNode """
:rtype: bool :type root: TreeNode
""" :rtype: List[List[int]]
if not root: """
return True if not root:
return self.is_mirror(root.left, root.right) return []
traversal = []
def is_mirror(self, left_node, right_node):
level = [root]
if not left_node and not right_node: forward = True
return True
while level:
return root
new_level = []
if forward: preorder.reverse() # reverse so we can pop in O(1) time
traversal.append([n.val for n in level]) inorder.reverse()
else: return build(None)
traversal.append([n.val for n in level[::-1]])
return traversal # Construct in postorder. Last element of postorder is root. Partition preorder about this element.
# Build the right subtree first until postorder[0] is not in inorder.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/105_Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.py - m # https://leetcode.com/problems/binary-tree-level-order-traversal-ii/
# Given a binary tree, return the bottom-up level order traversal of its nodes' values.
_author_ = 'jake' # I.e. from left to right, level by level from leaf to root.
_project_ = 'leetcode'
# Perform an inorder traversal, tracking depth and appending node values to corresponding sub-list. Reverse
# https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ # result before returning.
# Given preorder and inorder traversal of a tree, construct the binary tree. # Time - O(n)
# You may assume that duplicates do not exist in the tree. # Space - O(n)
# Build until we reach stop value, initially None. Take first preorder as root then recurse left until inorder is # Definition for a binary tree node.
# root value. Then discard inorder and recurse right until final stop. class TreeNode(object):
# Time - O(n) def __init__(self, x):
# Space - O(n) self.val = x
self.left = None
from collections import deque self.right = None
root.left = left_subtree
node_as_list[0] = node_as_list[0].next # update entry to next node of linked-list
# https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/
# Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
# python_1_to_1000/110_Balanced_Binary_Tree.py
# Mid element is root, recursively form left and right subtrees.
# Time - O(n) _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'
# Count the length of the list. Form left subtree from nodes before mid. Mid node forms root, then right subtree
# from nodes after mid. When a new tree node is made, advance the linked list pointer. Bottom-up approach.
# Time - O(n)
# Space - O(n) # python_1_to_1000/111_Minimum_Depth_of_Binary_Tree.py
def list_to_bst(self, node_as_list, start, end): # convert linked-list nodes from start to end (inclusive) l = self.minDepth(root.left)
r = self.minDepth(root.right)
if start > end:
return None if not l or not r:
return 1 + l + r
mid = (start + end) // 2
return 1 + min(l, r)
left_subtree = self.list_to_bst(node_as_list, start, mid - 1) # will update contents of node_as_list to
# become the mid node of linked list
root = TreeNode(node_as_list[0].val)
# python_1_to_1000/112_Path_Sum.py # Each node only has a right child. Left subtree is flattened before right.
_author_ = 'jake' # Records the root of the previous subtree flattened as an instance field.
_project_ = 'leetcode' # Flattens right subtree, after which self.prev is the root of the right subtree.
# Then connects the flattened left subtree to the flattened right subtree.
# https://leetcode.com/problems/path-sum/ # Then removes the link from the root to the old left subtree, and sets the
# Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up # root.right to the root of the left subtree (now flattened).
# all the values along the path equals the given sum. # Time - O(n)
# Space - O(n)
# Base cases of False if no node and True if leaf node with correct sum. Else subtract node value and check if
# True in either subtree. # Definition for a binary tree node.
# Time - O(n) class TreeNode(object):
# Space - O(n) def __init__(self, x):
self.val = x
# Definition for a binary tree node. self.left = None
class TreeNode(object): self.right = None
def __init__(self, x):
self.val = x class Solution(object):
self.left = None
self.right = None def __init__(self): # instance field self.prev to track previous node
self.prev = None
class Solution(object):
def hasPathSum(self, root, sum): def flatten(self, root):
""" """
:type root: TreeNode :type root: TreeNode
:type sum: int :rtype: None Do not return anything, modify root in-place instead.
:rtype: bool """
""" if not root:
if not root: return
return False
self.flatten(root.right)
sum -= root.val self.flatten(root.left)
if sum == 0 and not root.left and not root.right: # leaf node
return True root.left = None
root.right = self.prev
return self.hasPathSum(root.left, sum) or self.hasPathSum(root.right, sum) self.prev = root
# python_1_to_1000/113_Path_Sum_II.py - m # python_1_to_1000/115_Distinct_Subsequences.py - h
# https://leetcode.com/problems/path-sum-ii/ # https://leetcode.com/problems/distinct-subsequences/
# Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. # Given a string S and a string T, count the number of distinct subsequences of T in S.
# A subsequence of a string is a new string which is formed from the original string by deleting some (can be none)
# Maintain a partial path, appending latest node and decrementing target. When path has been explored, pop node off # of the characters without disturbing the relative positions of the remaining characters.
# partial path. Base cases are no node and leaf with remaining target of zero.
# Time - O(n log n), balanced tree has n/2 leaves and height log n # Dynamic programming. For all prefixes of S and T calculate the number of sequences. Base case is that the prefix
# Space - O(n log n), every path of balanced tree has correct sum # of T is the empty string, which is one subsequence of every prefix of S.
# The number of times T[:r] is a subsequence of S[:c] is the number of times T[:r] is a subsequence of S[:c - 1], plus
# Definition for a binary tree node. # if the last chars of T[:r] and S[:c] match then every T[:r - 1] subsequence of S[:c] can also be extended.
class TreeNode(object): # empty string is a subsequence of any string.
def __init__(self, x): # Time - O(m * n) where m = len(S) and n = len(T)
self.val = x # Space - O(m)
self.left = None
self.right = None
class Solution(object):
class Solution(object): def numDistinct(self, s, t):
def pathSum(self, root, sum): """
""" :type s: str
:type root: TreeNode :type t: str
:type sum: int :rtype: int
:rtype: List[List[int]] """
""" prev_subsequences = [1 for _ in range(len(s) + 1)] # empty string is always one subsequence of any string
paths = []
self.preorder(root, sum, [], paths) for r in range(1, len(t) + 1): # first r characters of T, i.e. T[:r]
return paths
subsequences = [0 for _ in range(len(s) + 1)]
def preorder(self, node, target, partial, paths):
for c in range(r, len(s) + 1): # first c chars of S. If c < r then no possibilities
if not node:
return subsequences[c] = subsequences[c - 1] # all T[:r] subsequences of S[:c - 1] are also
# subsequences of S[:c]
target -= node.val if s[c - 1] == t[r - 1]: # last chars match, add T[:r-1] subsequences of S[:c-1]
partial.append(node.val) subsequences[c] += prev_subsequences[c - 1]
if target == 0 and not node.left and not node.right:
paths.append(partial[:]) prev_subsequences = subsequences
partial.pop()
# python_1_to_1000/116_Populating_Next_Right_Pointers_in_Each_Node.py - m
# python_1_to_1000/114_Flatten_Binary_Tree_to_Linked_List.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/populating-next-right-pointers-in-each-node/
# https://leetcode.com/problems/flatten-binary-tree-to-linked-list/ # Given a binary tree, populate each next pointer to point to its next right node.
# Given a binary tree, flatten it to a linked list in-place. # If there is no next right node, the next pointer should be set to NULL.
# You may only use constant extra space. # Given numRows, generate the first numRows of Pascal's triangle.
# You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two
children). # Next row is sum of consecutive pairs of items from previous row.
# Time - O(n**2)
# Breadth first search by level. # Space - O(n**2)
# Time - O(n)
# Space - O(n) class Solution(object):
def generate(self, numRows):
# Definition for binary tree with next pointer. """
class TreeLinkNode(object): :type numRows: int
def __init__(self, x): :rtype: List[List[int]]
self.val = x """
self.left = None if numRows == 0:
self.right = None return []
self.next = None
pascal = [[1]]
class Solution(object):
def connect(self, root): for i in range(1, numRows):
"""
:type root: TreeLinkNode pascal.append([1])
:rtype: nothing for num1, num2 in zip(pascal[-2][:-1], pascal[-2][1:]):
""" pascal[-1].append(num1 + num2)
level = [root] pascal[-1].append(1)
while level and level[0]: # if first item is None then all are None because perfect, so terminate return pascal
next_level = []
prev = None
# python_1_to_1000/119_Pascal's_Triangle_II.py
for node in level: # set next right pointer
if prev: _author_ = 'jake'
prev.next = node _project_ = 'leetcode'
prev = node
# https://leetcode.com/problems/pascals-triangle-ii/
next_level.append(node.left) # add nodes to next level list, do not check if None # Given an index k, return the kth row of the Pascal's triangle.
next_level.append(node.right)
# Next row is sum of consecutive pairs of previous row.
level = next_level # Time - O(n**2)
# Space - O(n)
class Solution(object): # Bottom-ip dynamic programming. Min path is value of that element + min of the 2 paths to elements below.
def connect(self, root): # Time - O(n**2) for triangle height n since all elements visited
""" # Space - O(1), modifies input data
:type root: TreeLinkNode
:rtype: nothing class Solution(object):
""" def minimumTotal(self, triangle):
if not root: """
return :type triangle: List[List[int]]
level = [root] :rtype: int
"""
while level: for row in range(len(triangle)-2, -1, -1):
next_level = []
prev = None for col in range(len(triangle[row])):
for node in level: triangle[row][col] += min(triangle[row+1][col], triangle[row+1][col+1])
if prev:
prev.next = node return triangle[0][0]
prev = node
if node.left:
next_level.append(node.left) # python_1_to_1000/121_Best_Time_to_Buy_and_Sell_Stock.py
if node.right:
next_level.append(node.right) _author_ = 'jake'
_project_ = 'leetcode'
level = next_level
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
# Say you have an array for which the ith element is the price of a given stock on day i.
# If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock),
# python_1_to_1000/118_Pascal's_Triangle.py # design an algorithm to find the maximum profit.
_author_ = 'jake' # Record the max cash after buying stock at any point previously (which is negative), and the max cash after selling
_project_ = 'leetcode' # as the cash after boying + sale proceeds.
# Time - O(n)
# https://leetcode.com/problems/pascals-triangle/ # Space - O(1)
# def __init__(self, x):
class Solution(object): # self.val = x
def maxProfit(self, prices): # self.left = None
""" # self.right = None
:type prices: List[int]
:rtype: int class Solution(object):
""" def maxPathSum(self, root):
buy = float('-inf') # maximum cash balance after buying a stock """
sell = 0 # maximum cash balance after buying and selling a stock :type root: TreeNode
:rtype: int
for price in prices: """
buy = max(-price, buy) # max of buying earlier or now return self.helper(root)[0]
sell = max(price + buy, sell) # max of selling earlier or now
def helper(self, node): # returns tuple of (via, down) where via is max path sum via (and including) this node
return sell # or via any node below, down is max path sum downwards from this node
if not node:
return float('-inf'), 0 # -inf for via if no node since path must have at least one node
"""
:type beginWord: str new_front = set()
:type endWord: str for word in front:
:type wordList: List[str]
:rtype: List[List[str]] visited.add(word) # add word to set of those already removed from frontiers
"""
if endWord not in wordList: for i in range(len(word)): # add reachable words to frontier
return [] next_words = graph[word[:i] + '_' + word[i + 1:]]
next_words -= visited # apart from if already removed from a frontier
wordList = set(wordList) # convert to set for O(1) lookup new_front |= next_words
left, right = {beginWord}, {endWord} # frontiers at both ends
left_parents, right_parents = defaultdict(set), defaultdict(set) # map word to its parent length += 1
swapped = False # have the frontiers been swapped? front = new_front
while left and right and not (left & right): # while both frontiers and no intersection if len(back) < len(front): # expand the smaller frontier next
front, back = back, front
if len(right) < len(left): # swap to expand smaller frontier
left, right = right, left return 0
left_parents, right_parents = right_parents, left_parents
swapped = not swapped
next_left = defaultdict(set)
for word in left: # python_1_to_1000/128_Longest_Consecutive_Sequence.py - m
for char in string.ascii_lowercase:
for i in range(len(beginWord)): _author_ = 'jake'
n = word[:i] + char + word[i + 1:] # replace every position with every char _project_ = 'leetcode'
if n in wordList and n not in left_parents: # valid word not been used
next_left[n].add(word) # https://leetcode.com/problems/longest-consecutive-sequence/
# Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
left_parents.update(next_left)
left = set(next_left.keys()) # Test if each number starts a new sequence, if it does then count that sequence.
# Time - O(n), visits each number at most twice
if swapped: # swap back # Space - O(n)
left, right = right, left
left_parents, right_parents = right_parents, left_parents class Solution(object):
def longestConsecutive(self, nums):
ladders = [[word] for word in left & right] # start from central intersection """
while ladders and ladders[0][0] not in beginWord: # extend ladders left to start :type nums: List[int]
ladders = [[p] + l for l in ladders for p in left_parents[l[0]]] :rtype: int
while ladders and ladders[0][-1] != endWord: # extend ladders right to end """
ladders = [l + [p] for l in ladders for p in right_parents[l[-1]]] numset = set(nums) # no ordering, O(1) lookup
longest = 0
return ladders
for num in numset:
if front & back: # intersection between frontiers if not node: # no path to leaves
return length return 0
partial = 10 * partial + node.val # incorporate this node.val _author_ = 'jake'
_project_ = 'leetcode'
if not node.left and not node.right: # base case, leaf
return partial # https://leetcode.com/problems/palindrome-partitioning-ii/
# Given a string s, partition s such that every substring of the partition is a palindrome.
return self.helper(node.left, partial) + self.helper(node.right, partial) # Return the minimum cuts needed for a palindrome partitioning of s.
# Initialise worst case for each prefix as length of prefix - 1. For each character expand outwards both odd and even
# python_1_to_1000/130_Surrounded_Regions.py - m # length palindromes. Whenever a palindrome is found, update min_cuts for that palindrome plus the left prefix.
# Time - O(n**2)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/surrounded-regions/ def minCut(self, s):
# Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. """
# A region is captured by flipping all 'O's into 'X's in that surrounded region. :type s: str
:rtype: int
# All edge cells containing 'O' and their adjoining 'O' cannot be surrounded. Temporarily flag these cells, by depth- """
# first search. Then convert all unflagged 'O' (that can be surrounded) to 'X'. min_cuts = [i-1 for i in range(len(s)+1)] # min_cuts[i] is min cuts for prefix s[:i] of length i
# Time - O(m * n)
# Space - O(m * n) for i in range(len(s)): # for each character as centre of palindrome
while to_expand: # if cell contains 'O', change to temporary 'T' and add neighbours to stack _author_ = 'jake'
row, col = to_expand.pop() _project_ = 'leetcode'
if 0 <= row < rows and 0 <= col < cols and board[row][col] == 'O':
board[row][col] = 'T' # https://leetcode.com/problems/clone-graph/
for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]: # Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors
to_expand.append((row + dr, col + dc))
# When a new node is discovered it is copied, added to mapping and to_clone. Main while loop makes directed edges
for row in range(rows): # change all 'T' back to 'O' and all 'O' to 'X' # to neighbors.
for col in range(cols): # Time - O(m + n), edges + nodes
if board[row][col] == 'O': # Space - O(m + n)
board[row][col] = 'X'
elif board[row][col] == 'T': # Definition for a undirected graph node
board[row][col] = 'O' class UndirectedGraphNode(object):
def __init__(self, x):
self.label = x
# python_1_to_1000/131_Palindrome_Partitioning.py - m self.neighbors = []
# python_1_to_1000/134_Gas_Station.py - m
_author_ = 'jake'
# python_1_to_1000/132_Palindrome_Partitioning_II.py - h _project_ = 'leetcode'
return xor
# https://leetcode.com/problems/gas-station/
# There are N gas stations along a circular route, where the amount of gas at station i is gas[i].
# You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next # python_1_to_1000/137_Single_Number_II.py - m
# station (i+1). You begin the journey with an empty tank at one of the gas stations.
# Return the starting gas station's index if you can travel around the circuit once, otherwise return -1. _author_ = 'jake'
_project_ = 'leetcode'
# If total gas >= total cost then a circuit is possible.
# Iterate round the circuit, updating current tank balance and total. If current tank is negative, cannot start at # https://leetcode.com/problems/single-number-ii/
# that station so update start to next possible station. # Given an array of integers, every element appears three times except for one. Find that single one.
# Time - O(n)
# Space - O(1) # If a bit is set in num, but not set in ones or twos then that bit is then set in ones.
# If a bit is set in num, set in ones but not in twos then that bit is then set in twos and not ones.
class Solution(object): # If a bit is set in num, but not set in ones or twos then that bit is then set in ones.
def canCompleteCircuit(self, gas, cost): # Time - O(n)
""" # Space - O(1)
:type gas: List[int]
:type cost: List[int] class Solution(object):
:rtype: int def singleNumber(self, nums):
""" """
start, tank, total = 0, 0, 0 :type nums: List[int]
:rtype: int
for station in range(len(gas)): """
balance = gas[station] - cost[station] ones, twos = 0, 0
tank += balance
total += balance for num in nums:
if tank < 0: ones = (ones ^ num) & ~twos # xor of all nums that have appeared once only
start = station + 1 twos = (twos ^ num) & ~ones # xor of all nums that have appeared twice only
tank = 0
return ones
return -1 if total < 0 else start
# python_1_to_1000/135_Candy.py - h # python_1_to_1000/138_Copy_List_with_Random_Pointer.py
# https://leetcode.com/problems/candy/ # https://leetcode.com/problems/copy-list-with-random-pointer/
# There are N children standing in a line. Each child is assigned a rating value. # A linked list is given such that each node contains an additional random pointer which could point to any node in the
# You are giving candies to these children subjected to the following requirements: list or null.
# Each child must have at least one candy. # Return a deep copy of the list.
# Children with a higher rating get more candies than their neighbors.
# What is the minimum candies you must give? # Duplicate every node and insert copy in list after original node. Link copied nodes to random pointers, which
# follow random pointers of original nodes. Separate out original and copied lists.
# Find how many candies are required due to children on left and then on right. # Time - O(n)
# Result for each child is the higher of those values. # Space - O(1)
# Time - O(n)
# Space - O(n) # Definition for singly-linked list with a random pointer.
class RandomListNode(object):
class Solution(object): def __init__(self, x):
def candy(self, ratings): self.label = x
""" self.next = None
:type ratings: List[int] self.random = None
:rtype: int
""" class Solution(object):
left = [1 for _ in range(len(ratings))] # default to 1 per child def copyRandomList(self, head):
right = [1 for _ in range(len(ratings))] """
:type head: RandomListNode
for i in range(1, len(ratings)): # increase above previous child if greater rating :rtype: RandomListNode
if ratings[i] > ratings[i-1]: """
left[i] = left[i-1] + 1 node = head
while node:
candies = left[-1] # rightmost child not included in loop below next = node.next
for i in range(len(ratings)-2, -1, -1): copy = RandomListNode(node.label)
if ratings[i] > ratings[i+1]: # increase if greater rating node.next = copy
right[i] = right[i+1] + 1 copy.next = next
candies += max(left[i], right[i]) # child gets higher of candies due to left and right node = next
# Dynamic programming. A prefix can be made from words in dictionary if it can be split into a shorter prefix # Increment fast pointer by 2 nodes and slow pointer by 1 node per time step. If loop, fast will catch up with slow
# that can be made and another word in dictionary. # else fast will reach end.
# Time - O(n**3), there are O(n**2) substrings s[j:i], each taking O(n) to create # Time - O(n)
# Space - O(n) # Space - O(1)
# python_1_to_1000/140_Word_Break_II.py - h
# Test if word can be broken as per problem 139. For all prefixes of s in the dictionary, recurse on the suffix. # If there are k nodes before a cycle of c nodes, when slow reaches start of loop, fast is k % c into loop.
# Time - O(n**3 * 2**(n-1)) # When fast reaches slow, both are c - k % c into the loop. Restart fast at head and move both 1 step at a time.
# Space - O(n * 2**(n-1)), 2**(n-1) possible partitions of string of length n (every combination of gaps between words) # After k steps, both are at start of loop.
# each partiton is of length n. Memo for shorter suffixes does not impact big O. # Time - O(n)
# Space - O(1)
class Solution(object):
# Definition for singly-linked list.
def canBreak(self, s, wordDict): class ListNode(object):
can_make = [False] * (len(s)+1) # can_make[i] is True if can make prefix of length i def __init__(self, x):
can_make[0] = True self.val = x
for i in range(1, len(s)+1): # prefix length self.next = None
for j in range(i-1, -1, -1): # j is existing prefix, start with longest + shortest new word
if can_make[j] and s[j:i] in wordDict: class Solution(object):
can_make[i] = True def detectCycle(self, head):
break """
return can_make[-1] :type head: ListNode
:rtype: ListNode
"""
def wordBreak(self, s, wordDict): fast, slow = head, head
""" while fast and fast.next:
:type s: str fast = fast.next.next
:type wordDict: Set[str] slow = slow.next
:rtype: List[str] if fast == slow:
"""
if not self.canBreak(s, wordDict): fast = head
return [] while fast != slow:
result_lists = self.break_word(s, 0, wordDict, {}) fast = fast.next
return [" ".join(result) for result in result_lists] # convert back to strings slow = slow.next
return slow
def break_word(self, s, left, wordDict, memo): # break from s[left] onwards return None
# set slow to mid for odd length lists, first of second half for even # Definition for a binary tree node.
fast, slow = head, head class TreeNode(object):
while fast and fast.next: def __init__(self, x):
fast = fast.next.next self.val = x
slow = slow.next self.left = None
self.right = None
# reverse nodes after slow (slow has pointers from both sides)
prev, node = None, slow from collections import deque
while node:
prev, node.next, node = node, prev, node.next class Solution(object):
def postorderTraversal(self, root):
first, second = head, prev # heads of the normal and reversed lists """
while second.next: :type root: TreeNode
first.next, first = second, first.next # insert second after first :rtype: List[int]
second.next, second = first, second.next # insert first after second """
if not root:
return []
preorder = [] # python_1_to_1000/146_LRU_Cache.py - m
stack = [root]
_author_ = 'jake'
while stack: _project_ = 'leetcode'
node = stack.pop()
preorder.append(node.val) # https://leetcode.com/problems/lru-cache/
if node.right: # Design and implement a data structure for Least Recently Used cache. It should support the following operations:
stack.append(node.right) # push right first so left is popped first # get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
if node.left: # set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity,
stack.append(node.left) # it should invalidate the least recently used item before inserting a new item.
return preorder # Dictionary stores keys with values of nodes. Nodes form double linked list containing key, value pairs. DLL is in
# order of use with least recent at head and most recent at tail.
# Time - O(1) to set and get
class Solution2(object): # Space - O(n)
def preorderTraversal(self, root):
result = [] class Node:
self.preorder(root, result) def __init__(self, key, val):
return result self.key = key
self.val = val
def preorder(self, node, result): self.prev = None
if not node: self.next = None
return
result.append(node.val) class DLL:
self.preorder(node.left, result) def __init__(self):
self.preorder(node.right, result) self.head = Node(None, None) # least recently used, remove at head
self.tail = Node(None, None) # most recently used, add and update at tail
self.head.next = self.tail
self.tail.prev = self.head
# python_1_to_1000/145_Binary_Tree_Postorder_Traversal.py
def insert(self, node):
_author_ = 'jake' node.prev, self.tail.prev.next = self.tail.prev, node
_project_ = 'leetcode' node.next, self.tail.prev = self.tail, node
class LRUCache(object):
# Base case is empty list or single node. Else recursively split list in half, sort halves and merge.
def get(self, key): # Time - O(n log n)
""" # Space - O(n)
:rtype: int
""" # Definition for singly-linked list.
if key not in self.mapping: class ListNode(object):
return -1 def __init__(self, x):
node = self.mapping[key] self.val = x
self.queue.update(node) self.next = None
return node.val
class Solution(object):
def sortList(self, head):
def set(self, key, value): """
""" :type head: ListNode
:type key: int :rtype: ListNode
:type value: int """
:rtype: nothing if not head or not head.next:
""" return head
if key in self.mapping: # update value and move node to tail
node = self.mapping[key] fast, slow, prev = head, head, None
node.val = value while fast and fast.next:
self.queue.update(node) prev, slow, fast = slow, slow.next, fast.next.next
return
prev.next = None
node = Node(key, value) # else new key one = self.sortList(head)
self.mapping[key] = node two = self.sortList(slow)
self.queue.insert(node)
return self.merge(one, two)
if self.capacity == 0: # cache is full, eject oldest
removed_key = self.queue.remove_at_head()
del self.mapping[removed_key] def merge(self, one, two):
else: # decrement capacity
self.capacity -= 1 dummy = merged = ListNode(None)
# Maintain a sorted part of the list. For each next node, find its correct location by iterating along sorted section. merged.next = one or two # add remaining list
# Time - O(n**2)
# Space - O(1) return dummy.next
:rtype: str
class Solution(object): """
def maxPoints(self, points): words = s.split()
""" return " ".join(words[::-1])
:type points: List[Point]
:rtype: int
""" # python_1_to_1000/152_Maximum_Product_Subarray.py - m
if len(points) <= 2:
return len(points) _author_ = 'jake'
_project_ = 'leetcode'
overall_max = 2
# https://leetcode.com/problems/maximum-product-subarray/
for i, point in enumerate(points): # for each point # Find the contiguous subarray within an array (containing at least one number) which has the largest product.
gradients = defaultdict(int) # key is gradient, value is nb lines involving point with this gradient # Calculate the most positive and most negative subarray products ending at each element.
max_points = 1 # point is on every line # Either the element alone or multiplied by previous most positive or most negative.
# Time - O(n)
for point_2 in points[i+1:]: # check all # Space - O(1)
# python_1_to_1000/153_Find_Minimum_in_Rotated_Sorted_Array.py - m
# Push numbers onto stack. Apply operators to top 2 members of stack and push back result. # If right element is less than mid element, min mist be to right of mid. Else min mist be mid or left.
# Faster but less concise without using eval(). # Time - O(log n)
# Time - O(n) # Space - O(1)
# Space - O(n)
class Solution(object):
class Solution(object): def findMin(self, nums):
def evalRPN(self, tokens): """
""" :type nums: List[int]
:type tokens: List[str] :rtype: int
:rtype: int """
""" left = 0
ops = {'+', '-', '/', '*'} right = len(nums)-1
stack = []
while left < right:
for token in tokens:
if nums[left] <= nums[right]: # not rotated, left is min
if token in ops: break
right = stack.pop()
left = stack.pop() mid = (left + right) // 2
if token == '/': if nums[right] < nums[mid]: # min must be on right of mid
stack.append(int(left / float(right))) # round down left = mid + 1
else: else: # nums[right] > nums[mid]
stack.append((eval(str(left) + token + str(right)))) right = mid # min must be mid or on left
else: # nums[right] != nums[mid] because loop terminated if left == right and if right == left + 1 then
stack.append(int(token)) # mid == left and since nums are unique num[left] != nums[right]
# python_1_to_1000/154_Find_Minimum_in_Rotated_Sorted_Array_II.py - h
# python_1_to_1000/151_Reverse_Words_in_a_String.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/
# https://leetcode.com/problems/reverse-words-in-a-string/ # Follow up for "153 Find Minimum in Rotated Sorted Array": What if duplicates are allowed?
# Given an input string, reverse the string word by word.
# As per problem 153 except if nums[left] == nums[right] == nums[mid] must search both left and right.
# Parse int a list of words by spaces, reverse word list and recombine with spaces. # Time - O(n)
# Time - O(n) # Space - O(1)
# Space - O(n)
class Solution(object):
class Solution(object): def findMin(self, nums):
def reverseWords(self, s): """
""" :type nums: List[int]
:type s: str :rtype: int
""" # class TreeNode(object):
left, right = 0, len(nums)-1 # def __init__(self, x):
# self.val = x
while left < right: # self.left = None
# self.right = None
if nums[left] < nums[right]: # already sorted
break class Solution(object):
def upsideDownBinaryTree(self, root):
mid = (left + right) // 2 """
:type root: TreeNode
if nums[right] < nums[mid]: :rtype: TreeNode
left = mid + 1 # discontinuity on RHS of mid """
elif nums[right] > nums[mid] or nums[left] > nums[mid]: if not root or not root.left: # if no left then no right, leaf
right = mid # discontinuity is mid or LHS return root
else: # nums[right] == nums[mid] == nums[left]
left += 1 new_root = self.upsideDownBinaryTree(root.left) # recurse left
right -= 1 node = new_root
while node.right: # traverse as far right as possible
return nums[left] node = node.right
node.left = root.right
# python_1_to_1000/155_Min_Stack.py - m node.right = root
root.left = None
_author_ = 'jake' root.right = None
_project_ = 'leetcode'
return new_root
# https://leetcode.com/problems/min-stack/
# Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
# push(x) -- Push element x onto stack. # python_1_to_1000/157_Read_N_Characters_Given_Read4.py
# pop() -- Removes the element on top of the stack.
# top() -- Get the top element. _author_ = 'jake'
# getMin() -- Retrieve the minimum element in the stack. _project_ = 'leetcode'
# Main stack has all items, mins stack has items less than or equal to previous min. # https://leetcode.com/problems/read-n-characters-given-read4/
# Note : no error handling for empty stack required # The API: int read4(char *buf) reads 4 characters at a time from a file.
# Time - O(1) # The return value is the actual number of characters read. Eg, it returns 3 if only 3 characters are left in the file.
# Space - O(n) # By using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file.
class MinStack(object): # Read up to 4 chars into buf4 and copy to buf (which is modified in-place).
# Time - O(n)
def __init__(self): # Space - O(n)
"""
initialize your data structure here. # The read4 API is already defined for you.
""" # @param buf, a list of characters
self.main = [] # @return an integer
self.mins = [] def read4(buf):
pass
def push(self, x):
""" class Solution:
:type x: int def read(self, buf, n):
:rtype: void
""" total_chars, last_chars = 0, 4
self.main.append(x)
if not self.mins or x <= self.mins[-1]: while last_chars == 4 and total_chars < n:
self.mins.append(x)
buf4 = [""] * 4 # temporary buffer
def pop(self): last_chars = min(read4(buf4), n - total_chars)
""" buf[total_chars:total_chars+last_chars] = buf4
:rtype: void total_chars += last_chars
"""
item = self.main.pop() return total_chars
if item == self.mins[-1]:
self.mins.pop()
# python_1_to_1000/158_Read_N_Characters_Given_Read4_II_-_Call_multiple_times.py - h
def top(self):
""" _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
return self.main[-1] # https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/
# The API: int read4(char *buf) reads 4 characters at a time from a file.
def getMin(self): # The return value is the actual number of characters read.
""" # By using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file.
:rtype: int # The read function may be called multiple times.
"""
return self.mins[-1] # Use a double-linked list to store any characters read by read4 but not required. Use those characters first
# on the next call of read().
# Time - O(n)
# python_1_to_1000/156_Binary_Tree_Upside_Down.py - m # Space - O(n)
# Base case for recursion is a leaf node or None. Recursively process left subtree, find rightmost path, add previous class Solution(object):
# right on left and previous root on right. def __init__(self):
# Time - O(n) self.leftover = deque() # store chars read by read4 but not added previous buf
# Space - O(1)
def read(self, buf, n):
# Definition for a binary tree node. """
# https://leetcode.com/problems/one-edit-distance/
# Given two strings s and t, determine if they are both one edit distance apart.
# python_1_to_1000/160_Intersection_of_Two_Linked_Lists.py # If same lengths find the one different char (replacement edit) and test all else are same.
# If length diff of 1, find the extra char in longer and check all else is the same.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)
# python_1_to_1000/163_Missing_Ranges.py # python_1_to_1000/165_Compare_Version_Numbers.py - m
# https://leetcode.com/problems/missing-ranges/ # https://leetcode.com/problems/compare-version-numbers/
# Given a sorted integer array where elements are in the inclusive range [lower, upper], return its missing ranges. # Compare two version numbers version1 and version2.
# For example, given [0, 1, 3, 50, 75], lower = 0 and upper = 99, return ["2", "4->49", "51->74", "76->99"]. # If version1 > version2 return 1, if version1 < version2 return -1, otherwise return 0.
# You may assume that the version strings are non-empty and contain only digits and the . character.
# Track the last number seen. If num == last_seen+2 then last_seen+1 is the start and end of a missing range. # The . character does not represent a decimal point and is used to separate number sequences.
# If num > last_seen+2 then inclusive range last_seen+1 to num-1 is missing. Update last_seen. Do nothing if
# num is last_seen or last_seen+1 since nothing is missing. # Split by '.' and pad shorter list with [0]. Then compare each section.
# Time - O(n) # Time - O(n)
# Space - O(n) # Space - O(n)
for num in nums: for i1, i2 in itertools.zip_longest(v1, v2, fillvalue=0): # pad shorter with zeros
if num == last_seen + 2: if i1 > i2:
missing.append(str(last_seen+1)) return 1
elif num > last_seen + 2: if i1 < i2:
missing.append(str(last_seen+1) + '->' + str(num-1)) return -1
last_seen = num
return 0 # all version components are same
return missing
# python_1_to_1000/166_Fraction_to_Recurring_Decimal.py - m
# Find the initial integer part then repeatedly multiply by 10, divide by denominator and calculate remainder. If column = deque() # faster than list for appendleft()
# same remainder repeats there is a cycle. while n > 0:
n, output = divmod(n-1, 26)
class Solution(object): column.appendleft(output)
def fractionToDecimal(self, numerator, denominator):
""" return "".join([chr(i+ord('A')) for i in column])
:type numerator: int
:type denominator: int
:rtype: str
"""
if denominator == 0: # python_1_to_1000/169_Majority_Element.py
return None
decimal = [] # store result as a list _author_ = 'jake'
if numerator * denominator < 0: # negative sign _project_ = 'leetcode'
decimal.append('-')
# https://leetcode.com/problems/majority-element/
output, remainder = divmod(abs(numerator), abs(denominator)) # divide and modulo combined # Given an array of size n, find the majority element. The majority element appears more than [n/2] times.
decimal.append(str(output)) # You may assume that the array is non-empty and the majority element always exist in the array.
if remainder == 0:
return "".join(decimal) # When the count is zero, the next element becomes the candidate. When an element is the same as the candidate,
# increment the count, else decrement the count.
decimal.append('.') # Time - O(n)
seen = {} # key is remainder, value is index in decimal # Space - O(1)
if count == 0:
candidate = num
# python_1_to_1000/167_Two_Sum_II_-_Input_array_is_sorted.py - m
if candidate == num:
_author_ = 'jake' count += 1
_project_ = 'leetcode' else:
count -= 1
# https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/
# Given an array of integers that is already sorted in ascending order, find an ordered pair of indices of two numbers return candidate
# such that they add up to a specific target number.
# Please note that your returned answers (both index1 and index2) are not zero-based.
# You may assume that each input would have exactly one solution. # python_1_to_1000/170_Two_Sum_III_-_Data_structure_design.py
# Start pointers at both ends of array. Increment left if sum is too low or decrement right if sum is too high. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(1)
# https://leetcode.com/problems/two-sum-iii-data-structure-design/
class Solution(object): # Design and implement a TwoSum class. It should support the following operations: add and find.
def twoSum(self, numbers, target): # add - Add the number to an internal data structure.
""" # find - Find if there exists any pair of numbers which sum is equal to the value.
:type numbers: List[int]
:type target: int # Use a dictionary to store each number and whether it has been added multiple times. To find, for each num in
:rtype: List[int] # dictionary look for the difference between target value and that num, or for the num to be duplicated if it
""" # is half of the target value.
left, right = 0, len(numbers)-1 # Time - O(1) to add, O(n) to find
# Space - O(n)
while True:
class TwoSum(object):
pair_sum = numbers[left] + numbers[right]
if pair_sum == target: def __init__(self):
return [left+1, right+1] """
initialize your data structure here
if pair_sum < target: """
left += 1 self.nums = {} # key is num, value is True if num is duplicated else False
else:
right -= 1 def add(self, number):
"""
Add the number to an internal data structure.
# python_1_to_1000/168_Excel_Sheet_Column_Title.py :rtype: nothing
"""
_author_ = 'jake' self.nums[number] = number in self.nums # False for first occurence, True for multiple occurrences
_project_ = 'leetcode'
def find(self, value):
# https://leetcode.com/problems/excel-sheet-column-title/ """
# Given a positive integer, return its corresponding column title as appear in an Excel sheet. Find if there exists any pair of numbers which sum is equal to the value.
# For example:, 1 -> A, 2 -> B, 3 -> C, ..., 26 -> Z, 27 -> AA :type value: int
:rtype: bool
# Generate characters starting with least significant by calculating remainder of division by 26. """
# Time - O(log n) for num in self.nums:
# Space - O(log n) if value == 2 * num: # need num to be duplicated
if self.nums[num]:
from collections import deque return True
else: # look for difference
class Solution(object): if value - num in self.nums:
def convertToTitle(self, n): return True
""" return False
:type n: int
:rtype: str
"""
# python_1_to_1000/171_Excel_Sheet_Column_Number.py def next(self):
"""
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
node = self.stack.pop()
# https://leetcode.com/problems/excel-sheet-column-number/ result = node.val
# Given a column title as appear in an Excel sheet, return its corresponding column number. if node.right:
node = node.right
# For each char, multiply previous result by 26 and add value of char while node:
# Time - O(n) self.stack.append(node)
# Space - O(n) node = node.left
return result
class Solution(object):
def titleToNumber(self, s):
""" # python_1_to_1000/174_Dungeon_Game.py - h
:type s: str
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
result = 0
for c in s: # https://leetcode.com/problems/dungeon-game/
result = result*26 + ord(c) - ord('A') + 1 # The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon.
return result # The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the
# top-left room and must fight his way through the dungeon to rescue the princess.
# The knight has an initial health point represented by a positive integer. If at any point his health point drops
# python_1_to_1000/172_Factorial_Trailing_Zeros.py - m # to 0 or below, he dies immediately.
# Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms;
_author_ = 'jake' # other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers).
_project_ = 'leetcode' # In order to reach the princess as quickly as possible, the knight moves only rightward or downward in each step.
# Write a function to determine the knight's minimum initial health so that he is able to rescue the princess.
# https://leetcode.com/problems/factorial-trailing-zeroes/
# Given an integer n, return the number of trailing zeroes in n!. # Dynamic programming. Min health to reach end from any room is health lost/gained in that room + min required
# after moving down or right, floored at 1 since health cannot be zero.
# Every trailing zero is created by a factor of 5 (since there are many more factors of 2 that together make # Time - O(n * m)
# trailing zeroes). Count the numbers in 1..n that are divisible by 5, then those divisible by 25 which have a # Space - O(n + m)
# second factor of 5, then 125 etc ...
# Time - O(log n) class Solution(object):
# Space - O(1) def calculateMinimumHP(self, dungeon):
"""
class Solution(object): :type dungeon: List[List[int]]
def trailingZeroes(self, n): :rtype: int
""" """
:type n: int rows, cols = len(dungeon), len(dungeon[0])
:rtype: int
""" for r in range(rows - 1): # add new final column and row of infinity
zeroes = 0 dungeon[r].append(float('inf'))
power_of_5 = 5 dungeon.append([float('inf') for _ in range(cols + 1)])
while power_of_5 <= n: dungeon[rows - 1].append(1) # final room requires min health of 1
zeroes += n // power_of_5
power_of_5 *= 5 for r in range(rows - 1, -1, -1):
for c in range(cols - 1, -1, -1):
return zeroes dungeon[r][c] = max(1, -dungeon[r][c] + min(dungeon[r+1][c], dungeon[r][c+1]))
return dungeon[0][0]
# python_1_to_1000/173_Binary_Search_Tree_Iterator.py - m
# Time - O(n * k)
_author_ = 'jake' # Space - O(n * k)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/reverse-words-in-a-string-ii/ def maxProfit(self, k, prices):
# Given an input string, reverse the string word by word. A word is defined as a sequence of non-space characters. """
# The input string does not contain leading or trailing spaces and the words are always separated by a single space. :type k: int
:type prices: List[int]
# Revese entire string then reverse each word individually. :rtype: int
# Alternatively use built-in reverse() and reversed() functions. """
# Time - O(n) if k >= len(prices) // 2: # can transact as often as required to get max profit
# Space - O(1) return sum([max(0, prices[i] - prices[i-1]) for i in range(1, len(prices))])
class Solution: # buys[i] is the max profit after i-1 buy/sell transactions and another buy
# @param s, a list of 1 length strings, e.g., s = ['h','e','l','l','o'] # sells[i] is the max profit after i buy/sell transactions
# @return nothing buys, sells = [float('-inf') for _ in range(k + 1)], [0 for _ in range(k + 1)]
def reverseWords(self, s):
for price in prices:
self.reverse(s, 0, len(s)-1) for i in range(1, len(buys)):
s.append(' ') # temporary space to signify end of last word buys[i] = max(buys[i], sells[i-1] - price) # add -price to previous best after i-1 transactions
start = 0 if buys[i] == buys[i-1]: # additional transaction has not increased profit
for i in range(len(s)): break
if s[i] == ' ': sells[i] = max(sells[i], buys[i] + price) # add +price to max after i-1 transactions and another buy
self.reverse(s, start, i-1) # reverse word from start to i-1
start = i+1 # start of next word return max(sells)
s.pop()
# https://leetcode.com/problems/rotate-array/
class Solution2: # Rotate an array of n elements to the right by k steps.
def reverseWords(self, s):
s.reverse() # Reverse entire array, then reverse left k elements and right n-k elements.
s.append(' ') # Alternatively, split after n-k elements and swap slices.
start = 0 # Time - O(n)
for i in range(len(s)): # Space - O(1)
if s[i] == ' ':
s[start:i] = reversed(s[start:i]) class Solution(object):
start = i+1 def rotate(self, nums, k):
s.pop() """
:type nums: List[int]
:type k: int
# python_1_to_1000/187_Repeated_DNA_Sequences.py - m :rtype: void Do not return anything, modify nums in-place instead.
"""
_author_ = 'jake' k %= len(nums)
_project_ = 'leetcode' nums.reverse()
nums[:k] = reversed(nums[:k])
# https://leetcode.com/problems/repeated-dna-sequences/ nums[k:] = reversed(nums[k:])
# All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG".
# When studying DNA, it is sometimes useful to identify repeated sequences within the DNA. class Solution2(object):
# Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule. def rotate(self, nums, k):
n = len(nums)
# Store all substrings of length 10 in a set, if substring is duplicated add to result set. k %= n
# Time - O(n) nums[:] = nums[n-k:] + nums[:n-k]
# Space - O(n)
# Dynamic programming. Max profit after i buys = cost + max after i-1 transactions. reversed, bit = 0, 31
# Max profit after i sells = sale price + max after i-1 transactions and additional buy.
while n != 0: right_view = []
if n % 2 == 1: # last bit is set layer = [root]
reversed += 2**bit
bit -= 1 while layer:
n //= 2
right_view.append(layer[-1].val)
return reversed next_layer = []
# BFS layer by layer. Add to result last value found in a layer. def set_island(self, row, col, grid):
# Alternatively, recursively pre-order traverse tracking depth and updating result for each node. if row < 0 or row >= len(grid) or col < 0 or col >= len(grid[0]):
# Time - O(n) return
# Space - O(n) if grid[row][col] != '1':
return
# Definition for a binary tree node. grid[row][col] = '0'
class TreeNode(object): self.set_island(row+1, col, grid)
def __init__(self, x): self.set_island(row-1, col, grid)
self.val = x self.set_island(row, col+1, grid)
self.left = None self.set_island(row, col-1, grid)
self.right = None
class Solution(object):
def rightSideView(self, root): # python_1_to_1000/201_Bitiwse_AND_of_Numbers_Range.py - m
"""
:type root: TreeNode _author_ = 'jake'
:rtype: List[int] _project_ = 'leetcode'
"""
if not root: # https://leetcode.com/problems/bitwise-and-of-numbers-range/
return [] # Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
# Starting from the most significant bit that is set in n, compare each bit in n to the equivalent bit in m. # Definition for singly-linked list.
# If both bits are the same, set the same bit in the result to its value in m and n. class ListNode(object):
# Stop when a bit is set differently in m and n. def __init__(self, x):
# When any bit is different, all less significant bits must take on both values of 0 and 1 in the range. self.val = x
# Time - O(log n) self.next = None
# Space - O(1)
class Solution(object):
from math import log def removeElements(self, head, val):
"""
class Solution(object): :type head: ListNode
def rangeBitwiseAnd(self, m, n): :type val: int
""" :rtype: ListNode
:type m: int """
:type n: int dummy = prev = ListNode(None) # dummy in case head is deleted
:rtype: int dummy.next = head
"""
if m == 0: while head:
return 0
result = 0 if head.val == val:
prev.next, head.next, head = head.next, None, head.next
bit = int(log(n, 2)) # highest bit that is set in n else:
prev, head = head, head.next
while bit >= 0 and ((m & (1 << bit)) == (n & (1 << bit))):
if (m & (1 << bit)): # if this bit is set return dummy.next
result += 2**bit
bit -= 1
# python_1_to_1000/204_Count_Primes.py - m
return result
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/202_Happy_Number.py
# https://leetcode.com/problems/count-primes/
_author_ = 'jake' # Count the number of prime numbers less than a non-negative number, n.
_project_ = 'leetcode'
# Sieve numbers. Assume all are prime and eliminate those with factors.
# https://leetcode.com/problems/happy-number/ # Time - O(n***3/2)
# Write an algorithm to determine if a number is "happy". # Space - O(n)
# A happy number is a number defined by the following process: Starting with any positive integer,
# replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 class Solution(object):
# (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this def countPrimes(self, n):
# process ends in 1 are happy numbers. """
:type n: int
# Fast and slow pointers increment to the next sum of square digits. If in a cycle pointers will converge at :rtype: int
# a value other than 1, if no cycle pointers will both be 1. """
# Alternatively, if n == 4 then we are in a cycle. See https://en.wikipedia.org/wiki/Happy_number sieve = [False, False] + [True for _ in range(n-2)] # 0 and 1 are not prime
# Time - O(log n)
# Space - O(1) for i in range(2, int(n**0.5) + 1): # end at sqrt since any j not prime must have a factor <= sqrt(j)
class Solution2(object): # Store a mapping from chars of s to chars of t. If a char in s is already in mapping then check that the char in t
def isHappy(self, n): # is same as previously observed. Check also that a new mapping of char in s is not to a char in t already mapped.
""" # Time - O(n)
:type n: int # Space - O(n)
:rtype: bool
""" class Solution(object):
while True: def isIsomorphic(self, s, t):
if n == 1: """
return True :type s: str
if n == 4: :type t: str
return False :rtype: bool
n = sum([int(c)*int(c) for c in str(n)]) """
if len(s) != len(t):
return False
# python_1_to_1000/203_Remove_Linked_List_Elements.py s_to_t = {}
t_mapped = set()
_author_ = 'jake'
_project_ = 'leetcode' for cs, ct in zip(s, t):
# https://leetcode.com/problems/remove-linked-list-elements/ if cs in s_to_t:
# Remove all elements from a linked list of integers that have value val. if s_to_t[cs] != ct:
return False
# Iterate along list, cutting out nodes with val. elif ct in t_mapped:
# Time - O(n) return False
# Space - O(1) s_to_t[cs] = ct
t_mapped.add(ct)
return True # Node stores dictionary mapping letters to child nodes. Array would use fixed space regardless of actual nb children.
# Note that node does not explicitly store letter.
# Time - O(n) to create where n is total length of all words, O(k) to search where k is length of word.
# Space - O(n)
# python_1_to_1000/206_Reverse_Linked_List.py
class TrieNode(object):
_author_ = 'jake' def __init__(self):
_project_ = 'leetcode' """
Initialize your data structure here.
# https://leetcode.com/problems/reverse-linked-list/ """
# Reverse a singly linked list. self.children = {} # mapping from letter to child TrieNodes
self.terminal = False # flag indicates whole word
# Iterative resvers. Alternatively, use recursion.
# Time - O(n) class Trie(object):
# Space - O(1)
def __init__(self):
# Definition for singly-linked list. self.root = TrieNode()
class ListNode(object): self.root.terminal = True # empty string is a whole word
def __init__(self, x):
self.val = x def insert(self, word):
self.next = None """
Inserts a word into the trie.
class Solution(object): :type word: str
def reverseList(self, head): :rtype: void
""" """
:type head: ListNode node = self.root
:rtype: ListNode for c in word:
""" if c not in node.children: # create a node if it does not exist
reversed = None node.children[c] = TrieNode()
while head: node = node.children[c]
next = head.next node.terminal = True # set to True at end of word
head.next = reversed
reversed = head def search(self, word):
head = next """
return reversed Returns if the word is in the trie.
:type word: str
:rtype: bool
# python_1_to_1000/207_Course_Schedule.py - m """
node = self.root
_author_ = 'jake' for c in word:
_project_ = 'leetcode' if c in node.children:
node = node.children[c]
# https://leetcode.com/problems/course-schedule/ else:
# There are a total of n courses you have to take, labeled from 0 to n - 1. return False
# Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed return node.terminal # only True if terminal
as a pair: [0,1]
# Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses? def startsWith(self, prefix):
"""
# Topological sort. Find nodes with no dependencies. Remove outgoing edges from each such node. Repeat until Returns if there is any word in the trie
# no node has no dependencies. that starts with the given prefix.
# Time - O(m + n), edges + nodes :type prefix: str
# Space - O(m + n) :rtype: bool
"""
from collections import defaultdict node = self.root
for c in prefix:
class Solution(object): if c in node.children:
def canFinish(self, numCourses, prerequisites): node = node.children[c]
""" else:
:type numCourses: int return False
:type prerequisites: List[List[int]] return True
:rtype: bool
"""
nb_prerequisites = defaultdict(int) # key is course, value is number of prerequisite courses # python_1_to_1000/209_Minimum_Size_Subarray_Sum.py - m
prereq_list = defaultdict(list) # key is a course, value is list of courses that depend on course
_author_ = 'jake'
for after, before in prerequisites: _project_ = 'leetcode'
nb_prerequisites[after] += 1
prereq_list[before].append(after) # https://leetcode.com/problems/minimum-size-subarray-sum/
# Given an array of n positive integers and a positive integer s, find the minimal length of a
can_take = set(i for i in range(numCourses)) - set(nb_prerequisites.keys()) # subarray of which the sum ≥ s. If there isn't one, return 0 instead.
while can_take: # Maintain a sliding window and increase the end by 1 element at every step. Whenever the subarray sum is >= s then
# update min_length and increment the starting index until the subarray sum < s.
course = can_take.pop() # take any course with no prerequisites # Time - O(n)
numCourses -= 1 # decrement count of remaining courses to be taken # Space - O(1)
for dependent in prereq_list[course]:
nb_prerequisites[dependent] -= 1 # decrement count of dependencies class Solution(object):
if nb_prerequisites[dependent] == 0: # no more prerequisites def minSubArrayLen(self, s, nums):
can_take.add(dependent) """
:type s: int
return numCourses == 0 :type nums: List[int]
:rtype: int
"""
subarray_sum, min_length, start = 0, len(nums) + 1, 0 # min_length len(nums)+1 indicates no subarray sum >= s
# python_1_to_1000/208_Implement_Trie_(Prefix_Tree).py - m
for i in range(len(nums)):
_author_ = 'jake'
_project_ = 'leetcode' subarray_sum += nums[i] # add this element to window
# https://leetcode.com/problems/course-schedule-ii/
# There are a total of n courses you have to take, labeled from 0 to n - 1. # python_1_to_1000/212_Word_Search_II.py - h
# Some courses may have prerequisites, for example to take course 0 you have to first take course 1,
# which is expressed as a pair: [0,1]. Given the total number of courses and a list of prerequisite pairs, _author_ = 'jake'
# return the ordering of courses you should take to finish all courses. There may be multiple correct orders, _project_ = 'leetcode'
# you just need to return one of them. If it is impossible to finish all courses, return an empty array.
# https://leetcode.com/problems/word-search-ii/
# As per problem 207, find courses with no prerequisites and remove dependencies on such courses. # Given a 2D board and a list of words from the dictionary, find all words in the board.
# Time - O(m + n) # Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those
# Space - O(m + n) # horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
from collections import defaultdict # Build a trie of the words to be found. For each starting cell of the board, if cell contains same letter as a child
# of the trie node then update node to child and recurse on 4 surrounding cells. Add complete words to found list.
class Solution(object): # Overwrite letters used in each dfs with '*' char (not used in words) during recursion then replace before return.
def findOrder(self, numCourses, prerequisites): # Time - O(m * n * t) where board is m by n and t is total number of chars in all words
""" # Space - O(t) for trie
:type numCourses: int
:type prerequisites: List[List[int]] class Node:
:rtype: List[int] def __init__(self):
""" self.children = {} # map letter to child node
order = [] self.word = None
nb_prerequisites = defaultdict(int) # key is course, value is number of prerequisite courses
prereq_list = defaultdict(list) # key is a course, value is list of courses that depend on course class Solution(object):
def findWords(self, board, words):
for after, before in prerequisites: """
nb_prerequisites[after] += 1 :type board: List[List[str]]
prereq_list[before].append(after) :type words: List[str]
:rtype: List[str]
can_take = set(i for i in range(numCourses)) - set(nb_prerequisites.keys()) """
root = Node()
while can_take: for word in words: # build a trie
node = root
course = can_take.pop() # take any course with no prerequisites for c in word:
order.append(course) if c not in node.children:
for dependent in prereq_list[course]: node.children[c] = Node()
nb_prerequisites[dependent] -= 1 # decrement count of dependencies node = node.children[c]
if nb_prerequisites[dependent] == 0: # no more prerequisites node.word = word # node is end of complete word
can_take.add(dependent)
found = []
return order if len(order) == numCourses else [] for r in range(len(board)):
for c in range(len(board[0])):
self.search(board, root, r, c, found)
# python_1_to_1000/211_Add_and_Search_Word_-_Data_structure_design.py - m return found
_author_ = 'jake' def search(self, board, node, r, c, found): # depth first search of board
_project_ = 'leetcode'
if r < 0 or r >= len(board) or c < 0 or c >= len(board[0]):
# https://leetcode.com/problems/add-and-search-word-data-structure-design/ return
# Design a data structure that supports the following two operations:
# void addWord(word) letter = board[r][c]
# bool search(word) if letter not in node.children:
# search(word) can search a literal word or a regular expression string containing only letters a-z or '.' (one letter). return
# Store of a list of words by length. Check search word against list of words of same length by checking each char node = node.children[letter]
# and ignoring '.'. if node.word:
# Alternatively use a trie to store words and when search char is '.' then search all children. found.append(node.word)
# Time - O(1) to addWord, O(n * k_ search where there are n strings of length k node.word = None # avoid duplication of results
# Space - O(t), total number of chars in all strings
board[r][c] = '*' # temporarily flag this cell as being used
from collections import defaultdict self.search(board, node, r+1, c, found)
self.search(board, node, r-1, c, found)
class WordDictionary(object): self.search(board, node, r, c+1, found)
def __init__(self): self.search(board, node, r, c-1, found)
""" board[r][c] = letter # replace cell contents
initialize your data structure here.
"""
self.words = defaultdict(list)
# python_1_to_1000/213_House_Robber_II.py - m
def addWord(self, word):
""" _author_ = 'jake'
Adds a word into the data structure. _project_ = 'leetcode'
:type word: str
:rtype: void # https://leetcode.com/problems/house-robber-ii/
""" # This is an extension of 198 House Robber.
self.words[len(word)].append(word) # After robbing those houses on that street, the thief has found himself a new place for his thievery so that he
# will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first
def search(self, word): # house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for
""" # those in the previous street.
Returns if the word is in the data structure. A word could # Given a list of non-negative integers representing the amount of money of each house, determine the maximum
contain the dot character '.' to represent any one letter. # amount of money you can rob tonight without alerting the police.
:type word: str
:rtype: bool # As per 198 except consider the greater of 2 cases - allow robbing the first house but no the last, allow robbing the
""" # last house but not the first.
# Time - O(n) while True:
# Space - O(1) index = self.partition(nums, left, right) # all entries < index are <= nums[index]
if index == k:
class Solution(object): return nums[index]
def rob(self, nums): if index > k:
""" right = index-1
:type nums: List[int] else:
:rtype: int left = index+1
"""
if len(nums) < 2:
return sum(nums) # 1 house has no neighbours def partition(self, nums, left, right):
nums[-1] = 0 # do not rob last house next_lower = left # the next index there an entry <= rand_entry will be stored
loot2, prev = 0, 0 for i in range(left, right):
for num in nums: if nums[i] <= rand_entry: # no action if > rand_entry
loot2, prev = max(num + prev, loot2), loot2 nums[next_lower], nums[i] = nums[i], nums[next_lower]
next_lower += 1
return max(loot, loot2)
nums[next_lower], nums[right] = nums[right], nums[next_lower] # swap rand_entry back to be next_lower
return next_lower
# python_1_to_1000/214_Shortest_Palindrome.py - h
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/216_Combination_Sum_III.py - m
# https://leetcode.com/problems/kth-largest-element-in-an-array/ # If every number is unique then the set length is the same as the list length. If this is not true, then there is
# Find the kth largest element in an unsorted array. Note that it is the kth largest element in # some duplicate.
# the sorted order, not the kth distinct element. # Time - O(n)
# Space - O(n)
# Quick select. Partition array about random element. Narrow search region to one side of partition.
# Time - O(n), recurse on half (random) of array class Solution(object):
# Space - O(1) def containsDuplicate(self, nums):
"""
import random :type nums: List[int]
:rtype: bool
class Solution(object): """
def findKthLargest(self, nums, k): return len(set(nums)) != len(nums)
"""
:type nums: List[int]
:type k: int # python_1_to_1000/218_The_Skyline_Problem.py - h
:rtype: int
""" _author_ = 'jake'
k = len(nums) - k # find index k when sorted ascendingly _project_ = 'leetcode'
left, right = 0, len(nums)-1
# https://leetcode.com/problems/the-skyline-problem/
# A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from class Solution(object):
# a distance. Now suppose you are given the locations and height of all the buildings as a cityscape photo. def containsNearbyAlmostDuplicate(self, nums, k, t):
# Write a program to output the skyline formed by these buildings collectively. """
# The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], where Li and Ri :type nums: List[int]
# are the x coordinates of the left and right edge of the ith building, respectively, and Hi is its height. :type k: int
# It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are :type t: int
# perfect rectangles grounded on an absolutely flat surface at height 0. :rtype: bool
"""
# Iterate over a sorted list of all left and right edges. Heap stores (-building height, right edge) whenever we if k <= 0 or t < 0: # cannot have distinct integers if no index separation
# see a left edge. For each edge, pop of all the buildings to the left, if it's a left edge then add the right return False # numerical separation must be positive
# edge to the heap, record the highest building. Heap top has the highest 'alive' building after each edge. buckets = {} # map from a bucket to num in that bucket
# Time - O(n * logn), each building is inserted and removed from heap
# Space - O(n) for i, num in enumerate(nums):
bucket = num // (t + 1) # bucket width t+1, collision implies difference <= t. handles t == 0
import heapq if bucket in buckets:
return True
class Solution(object): if bucket+1 in buckets and abs(num - buckets[bucket+1]) <= t: # neighbouring buckets
def getSkyline(self, buildings): return True
""" if bucket-1 in buckets and abs(num - buckets[bucket-1]) <= t:
:type buildings: List[List[int]] return True
:rtype: List[List[int]]
""" buckets[bucket] = num # add to bucket
skyline = [(0, 0)] # resulting list of points, dummy first point if i - k >= 0: # remove from start of window
current = [(0, float('inf'))] # heap of 'alive' buildings by height, then by right edge old_bucket = nums[i - k] // (t + 1)
del buckets[old_bucket]
edges = [(l, -h, r) for l, r, h in buildings] # left edges
edges += [(r, 0, None) for _, r, _ in buildings] # right edges return False
edges.sort()
while current[0][1] <= x: # discard right edges that are left or equal to new edge _author_ = 'jake'
heapq.heappop(current) # dummy right edge at infinity ensures heap will never be empty _project_ = 'leetcode'
if neg_h != 0: # implies left edge (since h will not be zero), push right edge # https://leetcode.com/problems/maximal-square/
heapq.heappush(current, (neg_h, r)) # Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.
if skyline[-1][1] != -current[0][0]: # previous skyline different from highest alive building # For each cell find the largest square with that cell at the bottom right by dynamic programming.
skyline.append([x, -current[0][0]]) # add point (x, highest 'alive' bldg) to result # If cell == '1' then it extends the squares with bottom right cells to the left, above and above-left. Take the min
# of these 3 squares that are extended.
return skyline[1:] # Time - O(m * n)
# Space - O(n)
class Solution(object):
def maximalSquare(self, matrix):
# python_1_to_1000/219_Contains_Duplicate_II.py """
:type matrix: List[List[str]]
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
if not matrix or not matrix[0]:
# https://leetcode.com/problems/contains-duplicate-ii/ return 0
# Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array
# such that nums[i] = nums[j] and the absolute difference between i and j is at most k. rows, cols = len(matrix), len(matrix[0])
max_side = 0
# Create a set of nums in a sliding window of length k. Iterate over nums, removing the num at the back of the window, square_sides = [0] * cols # largest square side with cell in each col as bottom right
# checking if the new num is already in the window, or else adding it.
# Time - O(n) for r in range(rows):
# Space - O(k)
new_square_sides = [int(matrix[r][0])] + [0 for _ in range(cols-1)]
class Solution(object):
def containsNearbyDuplicate(self, nums, k): for c in range(1, cols):
""" if matrix[r][c] == '1':
:type nums: List[int] new_square_sides[c] = 1 + min(new_square_sides[c-1], square_sides[c], square_sides[c-1])
:type k: int
:rtype: bool max_side = max(max_side, max(new_square_sides))
""" square_sides = new_square_sides
window = set() # elements in window must be unique or else solution already found
return max_side**2
for i, num in enumerate(nums):
if i > k:
window.remove(nums[i - k - 1]) # python_1_to_1000/222_Count_Complete_Tree_Nodes.py
if num in window:
return True _author_ = 'jake'
window.add(num) _project_ = 'leetcode'
if left_subtree == right_subtree: def evaluate(self, expression, i): # evaluate from index i onwards to closing bracket
return 2**left_subtree + self.countNodes(root.right) # 1 (root) + 2**left_subtree - 1 (left subtree)
else: calc, operator = 0, '+'
return 2**right_subtree + self.countNodes(root.left) while expression[i] != ')':
atom = expression[i]
def left_depth(self, node): if atom == '+' or atom == '-': # store the operator
depth = 0 operator = atom
while node: else: # open bracket or integer
node = node.left if isinstance(atom, int):
depth += 1 num = atom
return depth else: # recurse on bracketed expression
num, i = self.evaluate(expression, i+1)
# Calculate the left and right edges of horizontal overlap. Take the difference to get the x_overlap and similar for # python_1_to_1000/225_Implement_Stack_Using_Queues.py
# y_overlap. Subtract the overlap area from the sum of the areas of the two rectangles.
# Time - O(1) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'
if c.isdigit(): # build num # check if candidates are more than 1/3 of list length
num = num*10 + int(c) return [n for n in (cand1, cand2) if nums.count(n) > len(nums) // 3]
# https://leetcode.com/problems/number-of-digit-one/
# python_1_to_1000/231_Power_of_Two.py # Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
_author_ = 'jake' # Calculate the number of 1s in each position, starting with units and moving forwards.
_project_ = 'leetcode' # In each position we consider the n+1 numbers from 0 to n inclusive.
# block_size is the cycle length before the pattern of 1s repeats.
# https://leetcode.com/problems/power-of-two/ # Count the number of complete blocks in n+1, each such block having 1/10th of its size of 1s.
# Given an integer, write a function to determine if it is a power of two. # Then add the partial blocks.
# n must be positive. Powers of 2 have their most significant bit set and no other bits, so there are no set bits # Time - O(log n)
# in common between n and n - 1. # Space - O(1)
# Time - O(1)
# Space - O(1) class Solution(object):
def countDigitOne(self, n):
class Solution: """
def isPowerOfTwo(self, n): :type n: int
""" :rtype: int
:type n: int """
:rtype: bool if n <= 0:
""" return 0
return n > 0 and not n & (n - 1) ones = 0
block_size = 10
# python_1_to_1000/232_Implement_Queue_using_Stacks.py for _ in range(len(str(n))):
# One stack contains the iteams as they are added. Another stack is used to reverse the order during the pop operation. # python_1_to_1000/234_Palindrome_Linked_List.py
# The top of the stack is recorded for O(1) peek.
# Time - O(1) for init, push, peek and empty. O(n) for pop. _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'
# https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ # python_1_to_1000/238_Product_of_Array_Except_Self.py - m
# Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
# According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as _author_ = 'jake'
# the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).” _project_ = 'leetcode'
# If both p and q are more than the node value then the common ancestor must be on the right. Similarly on the left if # https://leetcode.com/problems/product-of-array-except-self/
# p and q are lower. Else this is the common ancestor. Could also be iterative instead of recursive. # Given an array of n integers where n > 1, nums, return an array output such that output[i] is equal to the
# Time - O(n) # product of all the elements of nums except nums[i].
# Space - O(1)
# Iterate from left to right, calculating the product of all numbers to the left.
class Solution(object): # The iterate from right to left, multiplying each result by the product of all numbers to the right.
def lowestCommonAncestor(self, root, p, q): # If any one value is zero then result is all zeros apart from that entry.
""" # Time - O(n)
:type root: TreeNode # Space - O(1)
:type p: TreeNode
:type q: TreeNode class Solution(object):
:rtype: TreeNode def productExceptSelf(self, nums):
""" """
if p.val > root.val and q.val > root.val: :type nums: List[int]
return self.lowestCommonAncestor(root.right, p, q) :rtype: List[int]
if p.val < root.val and q.val < root.val: """
return self.lowestCommonAncestor(root.left, p, q) products = [1] # product of all to left of nums[0] is set to 1
return root for i in range(1, len(nums)):
products.append(nums[i-1] * products[-1])
# python_1_to_1000/236_Lowest_Common_Ancestor_of_a_Binary_Tree.py - m right_product = 1
for i in range(len(nums)-1, -1, -1):
_author_ = 'jake' products[i] *= right_product
_project_ = 'leetcode' right_product *= nums[i]
# Recursive function return p or q if only one of those nodes is present, None if neither. _author_ = 'jake'
# Find LCA of p and q in and right subtrees. If both return a value then p and q are in opposite subtrees and _project_ = 'leetcode'
# root is LCA. Else return LCA of p and q in the subtree containing both of them.
# Time - O(n) # https://leetcode.com/problems/sliding-window-maximum/
# Space - O(1) # Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the
# very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.
# Definition for a binary tree node. # Return a list of the max number in each window of the sliding window.
class TreeNode(object):
def __init__(self, x): # Keep indices in double ended queue. New indices are added at head of queue (RHS) so oldest are at tail (LHS).
self.val = x # Before adding a new index, pop from tail all indexes whose numbers are less than the new num since they can
self.left = None # never be the window max. Pop from head if that index is now outside the window. Head has largest in window.
self.right = None # Time - O(n)
# Space - O(k)
class Solution(object):
def lowestCommonAncestor(self, root, p, q): from collections import deque
"""
:type root: TreeNode class Solution(object):
:type p: TreeNode def maxSlidingWindow(self, nums, k):
:type q: TreeNode """
:rtype: TreeNode :type nums: List[int]
:type k: int
:rtype: List[int]
""" def diff_ways(self, s, left, right, memo):
q = deque()
max_window = [] if left == right: # case case of single integer
return [s[left]]
for i, num in enumerate(nums): if (left, right) in memo:
return memo[(left, right)]
while q and nums[q[-1]] < num: # pop smaller numbers from RHS
q.pop() ways = []
for i in range(left+1, right, 2): # partiton by each operator
q.append(i) # append this number at RHS
left_results = self.diff_ways(s, left, i-1, memo)
if q[0] <= i - k: # if LHS is outside window, remove it right_results = self.diff_ways(s, i+1, right, memo)
q.popleft()
for l in left_results:
if i >= k - 1: # if window is at least k, add LHS to result for r in right_results:
max_window.append(nums[q[0]]) if s[i] == '+':
ways.append(l+r)
return max_window elif s[i] == '-':
ways.append(l-r)
elif s[i] == '*':
# python_1_to_1000/240_Search_a_2D_Matrix_II.py - m ways.append(l*r)
# https://leetcode.com/problems/search-a-2d-matrix-ii/
# Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
# Integers in each row are sorted in ascending from left to right. # python_1_to_1000/242_Valid_Anagram.py
# Integers in each column are sorted in ascending from top to bottom.
_author_ = 'jake'
# Start at the top-right. If target is greater than this value then it cannot be in this row so increment row. _project_ = 'leetcode'
# If target is less than this value then it cannot be in this column so decrement column.
# Time - O(m + n) # https://leetcode.com/problems/valid-anagram/
# Space - O(1) # Given two strings s and t, write a function to determine if t is an anagram of s.
# You may assume the string contains only lowercase alphabets.
class Solution(object):
def searchMatrix(self, matrix, target): # Strings s and t must contain the same number of each character.
""" # Time - O(m + n)
:type matrix: List[List[int]] # Space - O(1)
:type target: int
:rtype: bool from collections import Counter
"""
if not matrix or not matrix[0]: class Solution(object):
return False def isAnagram(self, s, t):
"""
rows, cols = len(matrix), len(matrix[0]) :type s: str
r, c = 0, cols-1 :type t: str
:rtype: bool
while r < rows and c >= 0: """
return Counter(s) == Counter(t)
if matrix[r][c] == target:
return True
# python_1_to_1000/243_Shortest_Word_Distance.py
if target > matrix[r][c]:
r += 1 _author_ = 'jake'
else: _project_ = 'leetcode'
c -= 1
# https://leetcode.com/problems/shortest-word-distance/
return False # Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list.
# For example,
# Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
# python_1_to_1000/241_Different_Ways_to_Add_Parentheses.py - m # Given word1 = “coding”, word2 = “practice”, return 3.
# Given word1 = "makes", word2 = "coding", return 1.
_author_ = 'jake' # You may assume that word1 does not equal to word2, and word1 and word2 are both in the list.
_project_ = 'leetcode'
# Iterate over list, updating the last seen indices whenever word matches word1 or word2. Also update the shortest
# https://leetcode.com/problems/different-ways-to-add-parentheses/ # distance.
# Given a string of numbers and operators, return all possible results from computing all the different # Time - O(n)
# possible ways to group numbers and operators. The valid operators are +, - and *. # Space - O(1)
# Preprocess the string into a list of integers and string operators. Split the string by each operators and class Solution(object):
# recurse on the left and the right expressions. Combine the left and the right results in all possible ways. def shortestDistance(self, words, word1, word2):
# Memoize the results to save duplication. """
:type words: List[str]
class Solution(object): :type word1: str
def diffWaysToCompute(self, input): :type word2: str
""" :rtype: int
:type input: str """
:rtype: List[int] shortest = len(words)
""" i_1, i_2 = float("-inf"), float("-inf") # last seen indices of word1 and word2
start = 0 # start index of current integer
parsed = [] for i, word in enumerate(words):
# python_1_to_1000/246_Strobogrammatic_Number.py
# python_1_to_1000/244_Shortest_Word_Distance_II.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/strobogrammatic-number/
# https://leetcode.com/problems/shortest-word-distance-ii/ # A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).
# Design a class which receives a list of words in the constructor, and implements a method that takes two words word1 # Write a function to determine if a number is strobogrammatic. The number is represented as a string.
# and word2 and return the shortest distance between these two words in the list. Distance is the difference between # For example, the numbers "69", "88", and "818" are all strobogrammatic.
# the indices of the words in the list.
# Your method will be called repeatedly many times with different parameters. # Iterate over nums, matching digits at the front with rotated digits at the back.
# Time - O(n)
# Dictionary stores and ordered list of the indices of each word in words. # Space - O(1)
# Iterate along the lists of indices of each word together, moving forwards the pointer to the lower index.
# Time - O(n) class Solution(object):
# Space - O(n) def isStrobogrammatic(self, num):
"""
from collections import defaultdict :type num: str
:rtype: bool
class WordDistance(object): """
def __init__(self, words): strob = {'0':'0', '1':'1', '8':'8', '6':'9', '9':'6'} # map digit to its rotation
"""
initialize your data structure here. for left in range((len(num) + 1) // 2): # include middle digit if odd length
:type words: List[str]
""" right = len(num) - 1 - left
self.word_indices = defaultdict(list) if num[left] not in strob or strob[num[left]] != num[right]:
for i, word in enumerate(words): return False
self.word_indices[word].append(i)
return True
def shortest(self, word1, word2):
"""
Adds a word into the data structure. # python_1_to_1000/247_Strobogrammatic_Number_II.py - m
:type word1: str
:type word2: str _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
i1 = self.word_indices[word1] # list of indices of word1 # https://leetcode.com/problems/strobogrammatic-number-ii/
i2 = self.word_indices[word2] # list of indices of word2 # A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).
distance = float('inf') # Find all strobogrammatic numbers that are of length = n.
p1, p2 = 0, 0 # pointers to indices in the lists
# Base case of single strobogrammatic digits for odd n, empty string for even n.
while p1 < len(i1) and p2 < len(i2): # break when either pointer exceeds its list # Create numbers of length i by adding pairs of strobogrammatic digits before and after all numbers of length i-2.
# Remove results with leading zero unless single digit.
distance = min(distance, abs(i1[p1] - i2[p2])) # Time - O(5**(n//2)), each number of length n-2 is wrapped by 5 pairs to produce numbers of length n
if i1[p1] < i2[p2]: # index of word1 is less than index of word2 # Space - O(5**(n//2))
p1 += 1
else: import time
p2 += 1
class Solution(object):
return distance def findStrobogrammatic(self, n):
"""
:type n: int
:rtype: List[str]
# python_1_to_1000/245_Shortest_Word_Distance_III.py - m """
if n <= 0:
_author_ = 'jake' return ['']
_project_ = 'leetcode'
if n % 2 == 1:
# https://leetcode.com/problems/shortest-word-distance-iii/ results = ['0', '1', '8']
# Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list. else:
# word1 and word2 may be the same and they represent two individual words in the list. results = ['']
# As per problem 243 except if word1 == word2 treat indices as queue of length 2. strobo = {'0' : '0', '1' : '1', '8': '8', '6' : '9', '9' : '6'}
# Time - O(n) for i in range(n//2):
# Space - O(1) results = [c + r + strobo[c] for r in results for c in strobo]
class Solution(object): return [result for result in results if (result[0] != '0' or n == 1)]
def shortestWordDistance(self, words, word1, word2):
"""
:type words: List[str]
:type word1: str # python_1_to_1000/248_Strobogrammatic_Number_III.py - h
:type word2: str
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
last1, last2 = -1, -1 # last indices in words of word1 and word2
same = word1 == word2 # only test once # https://leetcode.com/problems/strobogrammatic-number-iii/
distance = len(words) # A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).
# Write a function to count the total strobogrammatic numbers that exist in the range of low <= num <= high.
for i, word in enumerate(words): # Because the range might be a large number, the low and high numbers are represented as string.
if word == word1:
if same: # Build lists of numbers upto the length of high. Wrap pairs of strobogrammatic digits around previous numbers.
last1, last2 = last2, i # shift last2 to last1 and update last2 to i
else: class Solution(object):
last1 = i def strobogrammaticInRange(self, low, high):
elif word == word2: """
last2 = i :type low: str
:type high: str
if last1 != -1 and last2 != -1: :rtype: int
distance = min(distance, abs(last1 - last2)) """
max_len, min_len = len(high), len(low)
return distance low, high = int(low), int(high)
live_list = [''] # base case for even length numbers def is_univariate(self, root):
other_list = ['0', '1', '8'] # bas case for odd length numbers
strobo_count = 0 if not root:
strobo = {'0' : '0', '1' : '1', '8': '8', '6' : '9', '9' : '6'} return True
live_list, other_list = other_list, live_list # swap even and odd lists class Solution2(object):
def countUnivalSubtrees(self, root):
return strobo_count self.univariates = 0
self.preorder(root)
return self.univariates
class Solution(object):
def groupStrings(self, strings):
""" # python_1_to_1000/251_Flatten_2D_Vector.py - m
:type strings: List[str]
:rtype: List[List[str]] _author_ = 'jake'
""" _project_ = 'leetcode'
shifted = defaultdict(list)
# https://leetcode.com/problems/flatten-2d-vector/
for s in strings: # Implement an iterator to flatten a 2d vector.
shift = ord(s[0]) - ord('a') # assumes s is not empty # Store pointer to the next valid sublist and item. To initialise and after every iteration move pointers to the next
s_shifted = "".join([chr((ord(c) - ord('a') - shift) % 26 + ord('a')) for c in s]) # valid item or beyond final sublist.
shifted[s_shifted].append(s) # Time - O(1) for hasNext. init() and next() are O(m) where m is number of sublists
# Space - O(n), total length of all sublists
return shifted.values()
class Vector2D(object):
class Solution(object):
def countUnivalSubtrees(self, root): def hasNext(self):
""" """
:type root: TreeNode :rtype: bool
:rtype: int """
""" return self.list_nb < len(self.vec2d) # list_nb pointer beyond end of vec2d
self.univariates = 0
self.is_univariate(root)
return self.univariates
# python_1_to_1000/252_Meeting_Rooms.py
# returns True if tree from root is univariate and increments count for all univariate subtrees
_author_ = 'jake' # Numbers can be regarded as product of its factors. For example,
_project_ = 'leetcode' # Write a function that takes an integer n and return all possible combinations of its factors.
# https://leetcode.com/problems/meeting-rooms/ # Recursive helper function returns all combinations of factors of n starting from trial factor, where partial is the
# Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), # list of existing factors. Whenever trial is a factor add a new result and recurse without this factor.
# determine if a person could attend all meetings. # Alternatively, iterative version same except stack replaces recursive calls.
# Siort by increasing start time, then check for any meeting starting before previous meeting finishes. import time
# Time - O(n log n)
# Space - O(1) class Solution(object):
def getFactors(self, n):
class Solution(object): """
def canAttendMeetings(self, intervals): :type n: int
""" :rtype: List[List[int]]
:type intervals: List[Interval] """
:rtype: bool return self.factorise(n, 2, [], [])
"""
intervals.sort(key=lambda x: x.start) def factorise(self, n, trial, partial, factors):
for i, interval in enumerate(intervals[1:], 1): # skip first interval while trial * trial <= n: # if trial**2 > n then have already found all factors
return factors
# python_1_to_1000/253_Meeting_Rooms_II.py - m
import heapq
# python_1_to_1000/254_Factor_Combinations.py - m
# python_1_to_1000/256_Paint_House.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/factor-combinations/
# https://leetcode.com/problems/paint-house/ # Given an array of n integers nums and a target, find the number of index triplets i, j, k
# There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. # with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target
# The cost of painting each house with a certain color is different. You have to paint all the houses such that no
# two adjacent houses have the same color. # Sort the array. For each index i search nums[i+1, len(nums)]. Whenever a triple sums to less than target we
# The cost of painting each house with a certain color is represented by a n x 3 cost matrix. # increment the count by right - left since for that value of the left pointer all values to the left of nums[right]
# Find the minimum cost to paint all houses. All costs are positive integers. # also form a triplet less than the target.
# Time - O(n**2)
# Min cost of painting a house any colour is the cost of painting that house that colour + min of painting the previous # Space - O(1)
# house a different colour.
# Time - O(n) class Solution(object):
# Space - O(1) def threeSumSmaller(self, nums, target):
"""
class Solution(object): :type nums: List[int]
def minCost(self, costs): :type target: int
""" :rtype: int
:type costs: List[List[int]] """
:rtype: int count = 0
""" nums.sort()
if not costs:
return 0 for i in range(len(nums)-2):
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/260_Single_number_III.py - m
# Recursive dfs. If leaf, add path to result. Else add node value to partial and recurse. # https://leetcode.com/problems/single-number-iii/
# Time - O(n**2) # Given an array of numbers nums, in which exactly two elements appear only once and all the other elements
# Space - O(n) # appear exactly twice. Find the two elements that appear only once.
class Solution(object): # Xor all the numbers to create the xor of the 2 singles. If a bit is set in this xor, it is set in one of the
def binaryTreePaths(self, root): # singles and not the other. Find the first bit that is set, then find the xor of all nums with that bit set
""" # and the xor of all nums without that bit set.
:type root: TreeNode # Time - O(n)
:rtype: List[str] # Space - O(1)
"""
class Solution(object):
def helper(node, partial): # partial is exiting path from root def singleNumber(self, nums):
if not node: """
return :type nums: List[int]
partial.append(str(node.val)) :rtype: List[int]
if not node.left and not node.right: """
paths.append("->".join(partial)) xor = 0
return for num in nums:
helper(node.left, partial[:]) xor = xor ^ num
helper(node.right, partial)
bit = 0
paths = [] while not (1 << bit) & xor:
helper(root, []) bit += 1
return paths
bit_set_xor, bit_not_set_xor = 0, 0
for num in nums:
if (1 << bit) & num:
# python_1_to_1000/258_Add_Digits.py bit_set_xor = bit_set_xor ^ num
else:
_author_ = 'jake' bit_not_set_xor = bit_not_set_xor ^ num
_project_ = 'leetcode'
return [bit_set_xor, bit_not_set_xor]
# https://leetcode.com/problems/add-digits/
# Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.
# python_1_to_1000/261_Graph_Valid_Tree.py - m
# Repeatedly sum digitss until < 10.
# Time - O(log n) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'
adjacency = {i: [] for i in range(n)} # list of neighbours for each node class Solution(object):
for a, b in edges: def nthUglyNumber(self, n):
adjacency[a].append(b) """
adjacency[b].append(a) :type n: int
:rtype: int
dfs(0) """
return not adjacency ugly = [1]
i_2, i_3, i_5 = 0, 0, 0 # last index in ugly of any not already be multiplied by 2, 3 and 5
# Reject if <= 0. Remove all factors of 2, 3, and 5 then check if remainder is 1. for i in range(1, len(costs)):
# Time - O(log n)
# Space - O(1) min_colours = [0, 1] # colours of previous house that give min and second min costs
if costs[i-1][0] > costs[i-1][1]:
class Solution(object): min_colours = [1, 0]
def isUgly(self, num):
""" for colour in range(2, len(costs[0])):
:type num: int if costs[i-1][colour] <= costs[i-1][min_colours[0]]: # new min cost
:rtype: bool min_colours[1], min_colours[0] = min_colours[0], colour
""" elif costs[i-1][colour] < costs[i-1][min_colours[1]]: # new second min cost
if num <= 0: min_colours[1] = colour
return False
for colour in range(len(costs[0])): # colour == min_colours[0] is 1 if colour is the min_colours[0]
while num % 2 == 0: costs[i][colour] += costs[i-1][min_colours[colour == min_colours[0]]]
num //= 2
while num % 3 == 0: return min(costs[-1])
num //= 3
while num % 5 == 0:
num //= 5
return num == 1
# python_1_to_1000/266_Palindrome_Permutation.py
_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/missing-number/
# Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.
# https://leetcode.com/problems/palindrome-permutation/
# Given a string, determine if a permutation of the string could form a palindrome. # Subtract the sum from n*(n-1)/2
# Time - O(n)
# There can be at most one character with an odd count in a palindrome. # Space - O(1)
# Time - O(n)
# Space - O(1) class Solution(object):
def missingNumber(self, nums):
from collections import Counter """
:type nums: List[int]
class Solution(object): :rtype: int
def canPermutePalindrome(self, s): """
""" return (((len(nums) + 1) * len(nums)) // 2) - sum(nums)
:type s: str
:rtype: bool
"""
freq = Counter(s)
odd = False # no odd has been seen # python_1_to_1000/269_Alien_Dictionary.py - h
# For each character, count the number of chars that appear before it and create a set of chars that appear after it.
# python_1_to_1000/267_Palindrome_Permutation_II.py - m # The first difference in chars at the same position for consecutive words in the dictionary gives an ordered pair
# of chars. Find a topologial ordering of the resulting directed graph by repeatedly removing chars that have no
_author_ = 'jake' # earlier chars remaining.
_project_ = 'leetcode' # Time - O(n), total number of chars in all words
# Space - O(m**2), nb chars in alphabet - order can be set of all chars for each char
# https://leetcode.com/problems/palindrome-permutation-ii/
# Given a string s, return all the palindromic permutations (without duplicates) of it. from collections import defaultdict
# Return an empty list if no palindromic permutation could be formed.
class Solution(object):
# Firstly find the only char with an odd count, if there is any. If more than 1 odd count char then return []. def alienOrder(self, words):
# Remove one instance of this from the count so all chars now have even counts. """
# Build all possible permutations of the remaining chars recursively by adding one instance of any char with a :type words: List[str]
# non-zero count to partial list and decrementing the count of this char by 2. Track the number of remaining :rtype: str
# chars to add such that when this is zero we have a resulting half-palindrome. Finally build full palindromes from """
# half and odd_char. after = defaultdict(int) # key is char, value is nb times char depends on a previous char
# Time - O(n * n!), n! permutations of length n order = defaultdict(set) # key is char, value is set of chars appearing after char
# Space - O(n * n!) seen = set(words[0]) # all chars found so far
if remaining == 0: letters = []
palindromes.append(partial[:]) # copy of partial while frontier:
b = frontier.pop() # add char from frontier to result
for c in char_counts.keys(): del after[b]
if char_counts[c] == 0: # skip if count is zero letters.append(b)
continue for a in order[b]: # decrement dependency count of those appearing after b
after[a] -= 1
char_counts[c] -= 2 # decrement count and add c to partial list if after[a] == 0:
partial.append(c) frontier.add(a)
self.build_palindromes(palindromes, partial, char_counts, remaining-1)
partial.pop() # revert count and partial list if after:
char_counts[c] += 2 return ""
return "".join(letters)
# python_1_to_1000/268_Missing_Number.py
# Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.
_author_ = 'jake' # You may assume k is always valid, that is: k ≤ total nodes.
_project_ = 'leetcode' # You are guaranteed to have only one unique set of k values in the BST that are closest to the target.
# https://leetcode.com/problems/closest-binary-search-tree-value/ # Heap stores k closest values as tuples (- abs node diff from target, node value). Top of heap is furthest from
# Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. # target. If a node.val is closer than the furthest value in the heap then add it to the heap and check left and
# Given target value is a floating point. # right subtrees. If a node.val is further than the furthest value in the heap then the nodes of one subtree are all
# You are guaranteed to have only one unique value in the BST that is closest to the target. # also further away.
# Alternatively, preorder traverse tree to create a sorted list. Find the pair of values surrounding target and
# If target is node val then return. Update closest if node val is closer. If target is more than root val then # expand outwards always taking the closest to target. O(n + k) but always visits ever node.
# no value in left subtree can be closer than node.val so move to right subtree. Vica versa for left subtree. # Time - O(n log k)
# Time - O(n) # Space - O(k)
# Space - O(1)
# Definition for a binary tree node.
class Solution(object): class TreeNode(object):
def closestValue(self, root, target): def __init__(self, x):
""" self.val = x
:type root: TreeNode self.left = None
:type target: float self.right = None
:rtype: int
""" import heapq
closest = root.val
class Solution(object):
while root: def closestKValues(self, root, target, k):
"""
if root.val == target: # early return since cannot improve :type root: TreeNode
return root.val :type target: float
:type k: int
if abs(root.val - target) < abs(closest - target): :rtype: List[int]
closest = root.val """
closest = [(float('-inf'), 0)] # add one item to avoid checking for empty heap
if target < root.val: self.find_closest(root, target, k, closest)
root = root.left return [val for _, val in closest]
else:
root = root.right def find_closest(self, node, target, k, closest):
if not node:
return closest return
if abs(node.val - target) < -closest[0][0]: # node.val is closer to target than furthest in heap
heapq.heappush(closest, (-abs(node.val - target), node.val))
# python_1_to_1000/271_Encode_and_Decode_Strings.py - m if len(closest) > k: # heap is over capacity
heapq.heappop(closest)
_author_ = 'jake' self.find_closest(node.left, target, k, closest)
_project_ = 'leetcode' self.find_closest(node.right, target, k, closest)
# https://leetcode.com/problems/encode-and-decode-strings/ elif target > node.val: # LHS nodes cannot be closer than node.val, which is itself not in k closest
# Design an algorithm to encode a list of strings to a string. self.find_closest(node.right, target, k, closest)
# The encoded string is then sent over the network and is decoded back to the original list of strings. else:
self.find_closest(node.left, target, k, closest)
# Prepend each string with its lenght and a special char '*'. To decode, find the first '*', text before this is the
# length of the substring. find() will always locate '*' after the length, never within a substring.
# Alternatively, prepend each string by its length as a string, padding string length with zeros to be a fixed number # python_1_to_1000/273_Integer_to_English_Words.py - h
# of characters.
# Alternatively, separate strings by a rare character surrounded by spaces eg ' # '. Whenever '#' appears in a string _author_ = 'jake'
# duplicate it such that all even numbers of consecutive "#" are from original strings. _project_ = 'leetcode'
# Time - O(n)
# Space - O(n) # https://leetcode.com/problems/integer-to-english-words/
# Convert a non-negative integer to its english words representation.
class Codec: # Given input is guaranteed to be less than 2**31 - 1.
def encode(self, strs):
"""Encodes a list of strings to a single string. # Build the words from left to right in blocks of 3 digits.
:type strs: List[str] # Time - O(log n)
:rtype: str # Space - O(log n)
"""
encoding = [] from collections import deque
for s in strs:
len_s = str(len(s)) class Solution(object):
encoding.append(len_s) # length as string def numberToWords(self, num):
encoding.append('*') # delimiter '*' """
encoding.append(s) :type num: int
return "".join(encoding) :rtype: str
"""
def decode(self, s): int_to_word = {1 : 'One', 2 : 'Two', 3 : 'Three', 4 : 'Four', 5 : 'Five',
"""Decodes a single string to a list of strings. 6 : 'Six', 7 : 'Seven', 8 : 'Eight', 9 : 'Nine', 10 : 'Ten',
:type s: str 11 : 'Eleven', 12 : 'Twelve', 13 : 'Thirteen', 14 : 'Fourteen',
:rtype: List[str] 15 : 'Fifteen', 16 : 'Sixteen', 17 : 'Seventeen', 18 : 'Eighteen',
""" 19: 'Nineteen', 20 : 'Twenty', 30 : 'Thirty', 40 : 'Forty',
decoding = [] 50 : 'Fifty', 60 : 'Sixty', 70 : 'Seventy', 80 : 'Eighty', 90 : 'Ninety'}
i = 0
while i < len(s): digits_to_word = {3 : 'Thousand', 6 : 'Million', 9 : 'Billion', 12 : 'Trillion',
j = s.find('*', i) # '*' must be present if any remaining test 15 : 'Quadrillion', 18 : 'Quintillion', 21 : 'Sextillion', 24 : 'Septillion',
len_substring = int(s[i:j]) 27 : 'Octillion', 30 : 'Nonillion'}
decoding.append(s[j+1:j+1+len_substring])
i = j+1+len_substring english = deque()
return decoding digits = 0
if num == 0:
return "Zero"
# python_1_to_1000/272_Closest_Binary_Search_Tree_Value_II.py - h
while num:
_author_ = 'jake'
_project_ = 'leetcode' num, section = divmod(num, 1000) # section is the block of 3 digits
hundreds, tens = divmod(section, 100)
# https://leetcode.com/problems/closest-binary-search-tree-value-ii/
if section and digits > 0: # Return the total number of ways you can paint the fence.
english.appendleft(digits_to_word[digits]) # n and k are non-negative integers.
digits += 3
# Base cases of zero or one post are 0 or k respectively. For more than 1 post, track the number of ways when the last
if tens >= 20: # 2 posts are same and when they are different. Update same as previous different, since we add the next post as the
if tens%10: # same colour as previous. Update different as (k - 1) * (same + different) since any previous way of either same or
english.appendleft(int_to_word[tens%10]) # different can add a post that is not the same colour as the last post.
english.appendleft(int_to_word[10*(tens//10)]) # Time - O(n)
elif tens: # Space - O(1)
english.appendleft(int_to_word[tens])
class Solution(object):
if hundreds: def numWays(self, n, k):
english.appendleft("Hundred") """
english.appendleft(int_to_word[hundreds]) :type n: int
:type k: int
return " ".join(english) :rtype: int
"""
if n == 0:
# python_1_to_1000/274_H-Index.py - m return 0
if n == 1:
_author_ = 'jake' return k
_project_ = 'leetcode'
same, different = 0, k
# https://leetcode.com/problems/h-index/
# Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute for _ in range(n - 1):
# the researcher's h-index. According to the definition of h-index on Wikipedia: "A scientist has index h if h of same, different = different, (same + different) * (k - 1)
# his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each."
# If there are several possible values for h, the maximum one is taken as the h-index. return same + different
# Bucket sort the papers by number of citations, using one bucket for all papers with len(citations) citations or
# more. Starting from the bucket with the papers with the most citations, add those papers to the cumulative sum # python_1_to_1000/277_Find_the_Celebrity.py - m
# and until there are at least as many papers as citations.
# Time - O(n) _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'
"""
class Solution(object): Initialize your data structure here.
def firstBadVersion(self, n): :type v1: List[int]
""" :type v2: List[int]
:type n: int """
:rtype: int self.vectors = [v for v in (v1, v2) if v] # list of non-empty vectors
""" self.q = deque((i, 0) for i in range(len(self.vectors))) # queue of (index in vectors, index in vector)
left, right = 1, n # left, right are the lowest and highest possible first bad versions
def next(self):
while left < right: """
:rtype: int
mid = (left + right) // 2 """
if isBadVersion(mid): # first bad version must be mid or before vector, index = self.q.popleft()
right = mid if index < len(self.vectors[vector])-1:
else: # first bad version must be after mid self.q.append((vector, index+1)) # rejoin queue if not last item of vector
left = mid + 1 return self.vectors[vector][index]
# https://leetcode.com/problems/perfect-squares/
# Given a positive integer n, find the least number of perfect square numbers (e.g., 1, 4, 9, 16, ...) which sum to n. # python_1_to_1000/282_Expression_Add_Operators.py - h
# Dynamic programming. memo[i] is the minimum nb squares that sum to i. While n is not already in memo, extend memo _author_ = 'jake'
# to be 1 + min of all previous memo results that are a perfect square number of indices away. _project_ = 'leetcode'
# Time - O(n**1.5)
# Space - O(n) # https://leetcode.com/problems/expression-add-operators/
# Given a string that contains only digits 0-9 and a target value, return all possibilities to insert binary operators
class Solution(object): # +, -, or * between the digits so they evaluate to the target value.
memo = [0, 1] # memo is persistent so that calls to numSquares() build on previous results # Insert an operator (except before first digit) then for each partition of the remaining digits treat the first part
# as the next integer. Track the evaluation of the current expression and the result of appending '*1' to the
def numSquares(self, n): # expression and so multiplying the last part by 1.
""" # Time - O(4**(n-1)), choice of 3 operators or none at each partition point.
:type n: int # Space - O(n * 4**(n-1)), worst case input of all zeros
:rtype: int
""" class Solution(object):
while len(self.memo) <= n: def addOperators(self, num, target):
self.memo.append(1 + min(self.memo[-i*i] for i in range(1, int(len(self.memo)**0.5)+1))) """
:type num: str
return self.memo[n] :type target: int
:rtype: List[str]
"""
if not num:
return []
# python_1_to_1000/280_Wiggle_Sort.py - m
self.num, self.target, self.expressions = num, target, []
_author_ = 'jake' self.helper("", 0, 0, 0)
_project_ = 'leetcode' return self.expressions
# https://leetcode.com/problems/wiggle-sort/
# Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]... def helper(self, path, index, eval, multed):
# If index is odd and not greater than or equal to previous, then swap with previous. if index == len(self.num) and self.target == eval:
# If index is even and greater than or equal to previous, then swap with previous (if equal, swap has no effect). self.expressions.append(path)
# Time - O(n)
# Space - O(1) for i in range(index, len(self.num)): # use num[index:i+1] as next integer
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/283_Move_Zeros.py
# Maintain a queue of tuples (next vector, index in next vector) containing the next valid index and vector. After # https://leetcode.com/problems/move-zeroes/
# iterating, add vector to back of queue if any more items remain. # Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the
# Time - O(k) (nb of vectors) to initialise vectors and q, O91) for next() and hasNext() # non-zero elements. For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be
# Space - O(n), total number of items in all vectors # [1, 3, 12, 0, 0].
# You must do this in-place without making a copy of the array.
from collections import deque
# Track the next index where a non-zero entry can be placed, initially zero. Iterate over nums, when a non-zero entry
class ZigzagIterator(object): # is seen, copy it to nums[i] and increment i. No action if num == 0. After iteration, replace all entries from i
# onwards with zero.
def __init__(self, v1, v2): # Time - O(n)
# Space - O(n) :type root: TreeNode
:type p: TreeNode
class Solution(object): :rtype: TreeNode
def moveZeroes(self, nums): """
""" succ = None
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead. while root:
""" if p.val >= root.val:
i = 0 # next index to move a non-zero entry to root = root.right
else:
for num in nums: succ = root
if num != 0: root = root.left
nums[i] = num
i += 1 return succ
# Store the next iterator result and return it when peeking. # python_1_to_1000/286_Walls_and_Gates.py - m
# Time - O(1)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class PeekingIterator(object):
def __init__(self, iterator): # https://leetcode.com/problems/walls-and-gates/
""" # You are given a m x n 2D grid initialized with these three possible values.
Initialize your data structure here. # -1 - A wall or an obstacle.
:type iterator: Iterator # 0 - A gate.
""" # INF - Infinity means an empty room. We use the value 2**31 - 1 = 2147483647 to represent INF.
self.front = None # Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled
self.it = iterator with INF.
if self.it.hasNext():
self.front = self.it.next() # Multidirectional BFS. Frontier initially contains all gates. For each room in frontier update any surrounding
# rooms with infinite distance and add them to frontier. Expands in concentric circles around gates.
def peek(self): # DFS or BFS from each gate in turn can result in repeatedly updating rooms and greater time complexity.
""" # Time - O(m * n), each cell visited once
Returns the next element in the iteration without advancing the iterator. # Space - O(m * n) for queue
:rtype: int
""" from collections import deque
return self.front # None if not iterator.hasNext()
class Solution(object):
def next(self): def wallsAndGates(self, rooms):
""" """
:rtype: int :type rooms: List[List[int]]
""" :rtype: void Do not return anything, modify rooms in-place instead.
temp = self.front """
self.front = None if not rooms or not rooms[0]:
if self.it.hasNext(): # replace front return
self.front = self.it.next()
return temp INF = 2 ** 31 - 1
rows, cols = len(rooms), len(rooms[0])
def hasNext(self): frontier = deque([(r, c) for r in range(rows) for c in range(cols) if rooms[r][c] == 0])
"""
:rtype: bool while frontier:
""" row, col = frontier.popleft()
return bool(self.front) for i, j in [(row + 1, col), (row - 1, col), (row, col + 1), (row, col - 1)]:
if i >= 0 and i < rows and j >= 0 and j < cols:
if rooms[i][j] == INF:
rooms[i][j] = rooms[row][col] + 1
# python_1_to_1000/285_Inorder_Successor_in_BST.py - m frontier.append((i, j))
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/287_Find_the_Duplicate_Number.py - m
count = 0
for row_offset in range(-1, 2):
for col_offset in range(-1, 2):
# python_1_to_1000/288_Unique_Word_Abbreviation.py - m
if row_offset == col_offset == 0:
_author_ = 'jake' continue
_project_ = 'leetcode' if 0 <= r+row_offset < len(board) and 0 <= c+col_offset < len(board[0]):
count += board[r+row_offset][c+col_offset] % 2 # 1st bit defines current status
# https://leetcode.com/problems/unique-word-abbreviation/
# An abbreviation of a word follows the form <first letter><number><last letter>. return count
# Assume you have a dictionary and given a word, find whether its abbreviation is unique in the dictionary.
# A word's abbreviation is unique if no other word from the dictionary has the same abbreviation.
# Create a set of words form dictionary to eliminate duplicates so the same word is not double counted. For each # python_1_to_1000/290_Word_Pattern.py
# unique word, create a mapping from its abbreviation to the count of words with the same abbreviation. A word is
# unique if it is in the dictionary and no other word has the same abbreviation, or no other word has same abbreviation. _author_ = 'jake'
# Time - O(n) for init() where n is the total number of letters in all words in the dictionary. O(k) for isUnique() _project_ = 'leetcode'
# where k is the length of the word to be tested for uniqueness.
# Space - O(n) # https://leetcode.com/problems/word-pattern/
# Given a pattern and a string str, find if str follows the same pattern.
from collections import defaultdict # Here follow means a full match, so that there is a bijection between a letter in pattern and a non-empty word in str.
# You may assume pattern contains only lowercase letters and str contains lowercase letters separated by a single space.
class ValidWordAbbr(object):
# Iterate over pairs of pattern chars and words, creating 2 mappings from pattern char to word and word to pattern
def __init__(self, dictionary): # char. If a word or pattern char has been mapped differently already then return False.
""" # Time - O(m + n)
:type dictionary: List[str] # Space - O(m + n)
"""
self.dictionary = set(dictionary) class Solution(object):
self.freq = defaultdict(int) def wordPattern(self, pattern, str):
for word in self.dictionary: """
self.freq[self.abbreviate(word)] += 1 :type pattern: str
:type str: str
def isUnique(self, word): :rtype: bool
""" """
:type word: str str = str.split()
:rtype: bool if len(str) != len(pattern): # early return if lengths do not match
""" return False
abbr = self.abbreviate(word)
if word in self.dictionary: p_to_s, s_to_p = {}, {}
return self.freq[abbr] == 1
else: for w, c in zip(str, pattern):
return abbr not in self.freq
if c in p_to_s and p_to_s[c] != w:
def abbreviate(self, word): return False
n = len(word) p_to_s[c] = w
if n < 3:
return word if w in s_to_p and s_to_p[w] != c:
return word[0] + str(n - 2) + word[-1] return False
s_to_p[w] = c
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/291_Word_Pattern_II.py - m
# python_1_to_1000/292_Nim_Game.py memo = {}
return helper(s)
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/nim-game/
# You are playing the following Nim Game with your friend: There is a heap of stones on the table, each time one of # python_1_to_1000/295_Find_Median_from_Data_Stream.py - h
# you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner.
# You will take the first turn to remove the stones. _author_ = 'jake'
# Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can _project_ = 'leetcode'
# win the game given the number of stones in the heap.
# https://leetcode.com/problems/find-median-from-data-stream/
# Can win if n is not divisible by 4, since then I can make it so n is divisible by 4 for my opponent. On each # Design a data structure that supports the following two operations:
# subsequent turn I will always make it so n is divisible by 4 or take the last 1, 2 or 3 stones. # void addNum(int num) - Add a integer number from the data stream to the data structure.
# Time - O(1) # double findMedian() - Return the median of all elements so far.
# Space - O(1) # If the size of the list is even, median is the mean of the two middle values.
class Solution(object): # Partition the numbers into 2 heaps containing half the numbers below (or equal to) median and half the numbers above
def canWinNim(self, n): # (or equal to) median. If the count of numners is odd, spare number is added to lower heap. New numbers are
""" # added to lower heap if less than or equal to its max value, else to higher heap. Then heaps are rebalanced to
:type n: int # maintain the lower being at most 1 greater than higher.
:rtype: bool # Time - O(log n) to addNum(), O(1) to findMedian()
""" # Space - O(n)
return n % 4 != 0
import heapq
# Create sorted lists of row and column indices of people. Because dimensions are independent for Manhattan distance, node = node_list.popleft()
# rows and cols can be optimised separately. Optimal meet is median of sorted indices (or anywhere between median pair if node == "null":
# if even number). To reach a meet between a pair of points takes distance of points separation if meet is between return None
# points, else greater distance if meet is not between points. Hence optimal meet is between the most pairs of
# points, which is the median. node = TreeNode(node)
# Time - O((m*n) + nlogn) node.left = rebuild()
# Space - O(m * n) if all cells contain people node.right = rebuild()
return node
class Solution(object):
def minTotalDistance(self, grid): return rebuild()
"""
:type grid: List[List[int]]
:rtype: int # python_1_to_1000/298_Binary_Tree_Longest_Consecutive_Sequence.py - m
"""
rows, cols = [], [] _author_ = 'jake'
_project_ = 'leetcode'
for r in range(len(grid)): # collect rows in sorted order
for c in range(len(grid[0])): # https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/
if grid[r][c] == 1: # Given a binary tree, find the length of the longest consecutive sequence path. The path refers to any sequence
rows.append(r) # of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive
cols.append(c) # path must be from parent to child (cannot be the reverse).
cols.sort() # potentially better to collect cols in separate loop O(m*n) rather than sort in O(n log n) # Preorder traversal. If a node is 1 + previous value then increment sequence length, else start a new sequence.
dist = 0 # Time - O(n)
# Space - O(1)
left, right = 0, len(rows)-1 # increment distance by separation of outer pair of rows
while left < right: # Definition for a binary tree node.
dist += (rows[right] - rows[left]) class TreeNode(object):
left += 1 def __init__(self, x):
right -= 1 self.val = x
self.left = None
left, right = 0, len(cols)-1 # increment distance by separation of outer pair of cols self.right = None
while left < right:
dist += (cols[right] - cols[left]) class Solution(object):
left += 1 def longestConsecutive(self, root):
right -= 1 """
:type root: TreeNode
return dist :rtype: int
"""
self.longest = 0
# python_1_to_1000/297_Serialize_and_Deserialize_Binary_Tree.py - h self.consecutive(root, float('inf'), 0)
return self.longest
_author_ = 'jake'
_project_ = 'leetcode' def consecutive(self, node, parent_val, sequence):
if not node:
# https://leetcode.com/problems/serialize-and-deserialize-binary-tree return
# Serialization is the process of converting a data structure or object into a sequence of bits so that it can be
# stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the if node.val == 1 + parent_val:
# same or another computer environment. sequence += 1
# Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your else:
# serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized sequence = 1
# to a string and this string can be deserialized to the original tree structure. self.longest = max(self.longest, sequence)
# Perform a preorder traversal, appending all visited nodes to a list and special sentinel "null" For None. Recursing self.consecutive(node.left, node.val, sequence)
# whenever we see a non-null node. Rebuild by creating a queue and taking the front value. self.consecutive(node.right, node.val, sequence)
# Ignore if null, else rebuild the root with value, recurse right then left.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/299_Bulls_and_Cows.py - m
from collections import deque
_author_ = 'jake'
class Codec: _project_ = 'leetcode'
# python_1_to_1000/300_Longest_Increasing_Subsequence.py - m # python_1_to_1000/302_Smallest_Rectangle_Enclosing_Black_Pixels.py - h
# https://leetcode.com/problems/longest-increasing-subsequence/ # https://leetcode.com/problems/smallest-rectangle-enclosing-black-pixels/
# Given an unsorted array of integers, find the length of longest increasing subsequence. # An image is represented by a binary matrix with 0 as a white pixel and 1 as a black pixel. The black pixels are
# connected, i.e., there is only one black region. Pixels are connected horizontally and vertically. Given the
# Maintain a list of the smallest final memeber of longest increasing subsequence of each length. Binary search this # location (x, y) of one of the black pixels, return the area of the smallest (axis-aligned) rectangle that encloses
# list to find the sequence that each num can extend. This either creates a new longest sequence, improves some other # all black pixels.
# existing length sequence, or does nothing.
# Time - O(nlogn) # If the black pixels are connected then every column and row in the enclosing rectangle contains a black pixel. We
# Space - O(n) # search in each dimension separately for the first row/col with a black pixel and the first row/col after the (x,y)
# pixel without a black pixel.
class Solution(object): # Time - O(mlogn + nlogm), binary search cols checking every row and vica versa
def lengthOfLIS(self, nums): # Space - O(1)
"""
:type nums: List[int] class Solution(object):
:rtype: int def minArea(self, image, x, y):
""" """
LIS = [] # LIS[i] is the smallest number at the end of an increasing subsequence of length i+1 :type image: List[List[str]]
:type x: int
for num in nums: :type y: int
list_nb = self.binary_search(num, LIS) :rtype: int
if list_nb == len(LIS)-1: # num extends longest list """
LIS.append(num) if not image or not image[0] or image[x][y] != '1':
else: # num extends LIS[list_nb] return 0
LIS[list_nb+1] = min(num, LIS[list_nb+1])
# find lowest index of a row with any black cells
return len(LIS) top_edge = self.find_edge(0, x, True, True, image)
mid = (left + right) // 2 # find lowest index of a col with any white cells
if num <= LIS[mid]: # if num equals or is less than LIS[mid] then it cannot extend mid sequence right_edge = self.find_edge(y+1, len(image[0]), False, False, image)
right = mid-1 # so look at all shorter sequences
else: return (right_edge - left_edge) * (bottom_edge - top_edge)
left = mid+1
class Solution(object):
def removeInvalidParentheses(self, s):
""" # python_1_to_1000/303_Range_Sum_Query_-_Immutable.py
:type s: str
:rtype: List[str] _author_ = 'jake'
""" _project_ = 'leetcode'
valid = []
self.remove(s, valid, 0, 0, ('(', ')')) # https://leetcode.com/problems/range-sum-query-immutable/
# Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. # Time - O(k log* k) where log* is iterated logarithm amd k is number of positions
# Space - O(k)
# Store cumulative sums.
# Time - O(n) for __init__(), O(1) for sumRange() class Solution(object):
# Space - O(n) def numIslands2(self, m, n, positions):
"""
class NumArray(object): :type m: int
:type n: int
def __init__(self, nums): :type positions: List[List[int]]
""" :rtype: List[int]
:type nums: List[int] """
""" island_count = [0]
self.cumul = [0] parent = {} # key is (r,c), value is parent (r,c)
for num in nums:
self.cumul.append(self.cumul[-1] + num) for r, c in positions:
# https://leetcode.com/problems/range-sum-query-2d-mutable/ # python_1_to_1000/310_Minimum_Height_Trees.py - m
# Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner
# (row1, col1) and lower right corner (row2, col2). _author_ = 'jake'
# You may assume the number of calls to update and sumRegion function is distributed evenly. _project_ = 'leetcode'
# You may assume that row1 ≤ row2 and col1 ≤ col2.
# https://leetcode.com/problems/minimum-height-trees/
# Store the cumulative sums for each row. To sumRegion, sum the difference between the sum to the last and first col # For a undirected graph with tree characteristics, we can choose any node as the root.
# over each row. To update, add the difference to the cumulative sum of that row for each later column. # The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called
# Time - O(mn) to initialise, O(n) to update, O(m) to sumRegion # minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of
# Space - O(1), modified im place # their root labels.
# The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of
class NumMatrix(object): # undirected edges (each edge is a pair of labels). You can assume that no duplicate edges will appear in edges.
def __init__(self, matrix):
""" # In each iteration of the while loop, remove all leaves (nodes with 1 neighbour). This prunes the tree from the
:type matrix: List[List[int]] # outwards resulting in either 1 or 2 nodes that are the maximum distance from any leaf.
""" # Time - O(n)
if not matrix or not matrix[0]: # Space - O(n)
return
rows, self.cols = len(matrix), len(matrix[0]) from collections import defaultdict
class Solution(object):
def findMinHeightTrees(self, n, edges): for length in range(1, n + 1):
"""
:type n: int for left in range(1, n + 2 - length): # consider subarrays from left to right inclusive
:type edges: List[List[int]] right = left + length - 1
:rtype: List[int]
""" for last in range(left, right + 1):
if n == 1: this_coins = nums[left - 1] * nums[last] * nums[right + 1] # last balloon and neighbours
return [0] max_coins[length][left] = max(max_coins[length][left],
connections = defaultdict(set) # key is node, value is set of neighbouring nodes this_coins + max_coins[last - left][left] + max_coins[right - last][last + 1])
return C # https://leetcode.com/problems/binary-tree-vertical-order-traversal/
# Given a binary tree, return the vertical order traversal of its nodes' values. (from top to bottom, column by column).
# If two nodes are in the same row and column, the order should be from left to right.
# python_1_to_1000/312_Burst _Balloons.py - h
# Breadth first search tracking column number in a dictionary (since the range of columns is unknown).
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(n)
# For each house explore all of the grid that is reachable by previous houses with BFS. Add the distance from the
# house to a copy of the grid. BFS is pruned by only considering cells reached by earlier houses.
# Time - O(m * n * h) where h is the number of houses
# Space - O(m * n)
return indices # reachable are those distances of cells reached by all houses
reachable = [distances[r][c] for r in range(rows) for c in range(cols) if grid[r][c] == -house]
return -1 if not reachable else min(reachable)
smaller = [0 for _ in range(len(nums))]
helper([i for i in range(len(smaller))])
return smaller
# python_1_to_1000/318_Maximum_Product_of_Word_Lengths.py - m
_author_ = 'jake'
# python_1_to_1000/316_Remove_Duplicate_Letters.py - m _project_ = 'leetcode'
# python_1_to_1000/317_Shortest_Distance_from_All_Buildings.py - h
# python_1_to_1000/319_Bulb_Switcher.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/shortest-distance-from-all-buildings/
# You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. # https://leetcode.com/problems/bulb-switcher/
# There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. max_number = max(max_number, int("".join(map(str, merged))))
# On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the ith return [int(c) for c in str(max_number)]
# round, you toggle every i bulb. For the nth round, you only toggle the last bulb.
# Find how many bulbs are on after n rounds.
def max_single(self, nums, k):
# The ith bulb is toggled twice by every pair a, b where a*b == i. Thus every prime is toggled twice only, most stack, n = [], len(nums)
# bulbs are toggled an even number of times. Only if i is a square then it has an odd number of divisors and is on. for i, num in enumerate(nums):
# Time - O(1) # stack not empty and num is more than top of stack and stack + remaining nums are more than k
# Space - O(1) while stack and num > stack[-1] and (len(stack) + (n - i) > k):
stack.pop()
class Solution(object): if len(stack) < k:
def bulbSwitch(self, n): stack.append(num)
""" return stack
:type n: int
:rtype: int
""" def merge(self, nums1, nums2):
return int(n**0.5) i, j = 0, 0
merged = []
# abbreviate c
if len(abbr) > 0 and isinstance(abbr[-1], int):
new_abbreviations.append(abbr[:-1] + [abbr[-1] + 1])
else: # python_1_to_1000/322_Coin_Change.py - m
new_abbreviations.append(abbr + [1])
_author_ = 'jake'
# do not abbreviate c _project_ = 'leetcode'
new_abbreviations.append(abbr + [c])
# https://leetcode.com/problems/coin-change/
abbreviations = new_abbreviations # You are given coins of different denominations and a total amount of money amount. Write a function to compute the
# fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any
return ["".join(map(str, a)) for a in abbreviations] # combination of the coins, return -1.
# Depth first search of the tree of coin combinations. Explore first branch by removing as many of largest coin until
# python_1_to_1000/321_Create_Maximum_Number.py - h # zero balance (result) or then try removing next smallest coins. Back up to decrement number of largest coin.
# Prune branches that cannot lead to an improved result.
_author_ = 'jake' # Time - O(c**d) where branching factor c is number of coins and d is depth of tree (amount / smallest coin)
_project_ = 'leetcode' # Space - O(c**d)
for a, b, in edges:
# python_1_to_1000/326_Power_of_Three.py
a_parent = update_parent(a)
b_parent = update_parent(b) _author_ = 'jake'
_project_ = 'leetcode'
if a_parent != b_parent:
parents[a_parent] = b_parent
components -= 1 # https://leetcode.com/problems/power-of-three/
# Given an integer, write a function to determine if it is a power of three.
return components
# Find the maximum power of 3 within a 4 byte signed integer. When divided by a power of 3, this number will have no
# remainder.
# python_1_to_1000/324_Wiggle_Sort_II.py - m # Time - O(1)
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' import math
# < left are > median, >= left and < i are == median, > right are < median # Create an array of the cumulative prefix sums. Mergesort this array, counting the number of range sums purely
# >= i and <= right are unsorted # within LHS and RHS. Then given that both sides are sorted, for each prefix_sum in LHS find the indices i and j
left, i, right = 0, 0, len(nums) - 1 # that define the ranges summing to between lower and upper. Perform the merge using python sorted().
# Time - O(n log n)
while i <= right: # Space - O(n)
if nums[mapping(i)] > median:
nums[mapping(i)], nums[mapping(left)] = nums[mapping(left)], nums[mapping(i)] class Solution(object):
left += 1 def countRangeSum(self, nums, lower, upper):
i += 1 """
elif nums[mapping(i)] < median: :type nums: List[int]
nums[mapping(i)], nums[mapping(right)] = nums[mapping(right)], nums[mapping(i)] :type lower: int
right -= 1 :type upper: int
else: :rtype: int
i += 1 """
cumul = [0]
for num in nums:
# python_1_to_1000/325_Maximum_Size_Subarray_Sum_Equals_k.py - m cumul.append(num + cumul[-1])
# https://leetcode.com/problems/patching-array/
# Given a sorted positive integer array nums and an integer n, add/patch elements to the array such that any number
# in range [1, n] inclusive can be formed by the sum of some elements in the array.
# python_1_to_1000/328_Odd_Even_Linked_List.py - m # Return the minimum number of patches required.
_author_ = 'jake' # At each stage we add the lowest missing number to the sequence. If the next num is <= next_missing then it can
_project_ = 'leetcode' # be used to extend the sequence without a patch. Or else we patch with next_missing, which extends the sequence
# as far as possible.
# https://leetcode.com/problems/odd-even-linked-list/ # Time - O(m + log n) where m = len(nums)
# Given a singly linked list, group all odd nodes together followed by the even nodes. # Space - O(1)
# Please note here we are talking about the node number and not the value in the nodes.
# The relative order inside both the even and odd groups should remain as it was in the input. class Solution(object):
# The first node is considered odd, the second node even and so on ... def minPatches(self, nums, n):
"""
# Create 2 new dummy heads for odd and even index nodes. Connect each pair of nodes to the odd and even lists :type nums: List[int]
# respectively. Break if no even node or next odd node. Connect the odd and even lists. :type n: int
# Time - O(n) :rtype: int
# Space - O(1) """
next_missing = 1
# Definition for singly-linked list. patches = 0
class ListNode(object): i = 0
def __init__(self, x):
self.val = x while next_missing <= n:
self.next = None if i < len(nums) and nums[i] <= next_missing:
next_missing += nums[i]
class Solution(object): i += 1
def oddEvenList(self, head): else:
""" next_missing += next_missing
:type head: ListNode patches += 1
:rtype: ListNode
""" return patches
even_head = even = ListNode(None)
odd_head = odd = ListNode(None)
# Sort the tickets so that for for each starting location the destinations are in reverse alphabetical order. Create if left_bst[2] != -1 and right_bst[2] != -1: # both sides are BSTs
# a mapping from each start airport to a list of end airports in reverse alphabetical order. DFS the graph, always if left_bst[0] < node.val < right_bst[1]: # node.val within bounds set by subtrees
# taking the lexicographically first next airport. When we reach an end, this airport has an odd number of edges size = 1 + left_bst[2] + right_bst[2] # update largest
# and must be the ultimate end of the itinerary so add it to the result. Backtrack, adding airports to the result self.largest = max(self.largest, size)
# when there is no other choice, or else exploring. return max(right_bst[0], node.val), min(left_bst[1], node.val), size
# Alternatively, iteratively.
# Time - O(n), number of tickets return 0, 0, -1
# Space - O(n)
is_bst(root) # ignore return value
from collections import defaultdict return self.largest
class Solution(object):
def findItinerary(self, tickets):
"""
:type tickets: List[List[str]] # python_1_to_1000/334_Increasing_Triplet_Subsequence.py - m
:rtype: List[str]
""" _author_ = 'jake'
tickets.sort(reverse = True) # reverse start destination, then ties broken by reverse end _project_ = 'leetcode'
flights = defaultdict(list)
for start, end in tickets: # key is start, value is list of ends (lowest alphabetical is last) # https://leetcode.com/problems/increasing-triplet-subsequence/
flights[start].append(end) # Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array.
journey = []
# Track the smallest num seen so far and the next_smallest. If we see a num larger than next_smallest, return True.
def visit(airport): # Time - O(n)
while flights[airport]: # Space - O(1)
visit(flights[airport].pop())
journey.append(airport) class Solution(object):
def increasingTriplet(self, nums):
visit("JFK") """
return journey[::-1] :type nums: List[int]
:rtype: bool
"""
class Solution2(object): smallest, next_smallest = float("inf"), float("inf")
def findItinerary(self, tickets):
""" for num in nums:
:type tickets: List[List[str]] smallest = min(smallest, num)
:rtype: List[str] if num > smallest:
""" next_smallest = min(next_smallest, num)
flights = defaultdict(list) if num > next_smallest:
tickets.sort(reverse = True) return True
# There are 3 scenarios for a crossing (described from the perspective of the first move m0 being vertically up),
# 1) After 4 moves. Down move m2 <= up move m0 and left move m3 >= right move m1.
# python_1_to_1000/333_Largest_BST_Subtree.py - m # 2) After 5 moves. Left move m1 == right move m3 and final up move m4 >= distance to start m2 - m0.
# 3) After 6 moves. Final up move m4 <= previous down move m2 and also >= distance to start m2 - m0. Final right move
_author_ = 'jake' # m5 >= previous left move m3 and also left move m3 > right move m1 and final right move m5 >= distance to
_project_ = 'leetcode' # start m3 - m1.
# Time - O(n)
# https://leetcode.com/problems/largest-bst-subtree/ # Space - O(1)
# Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree
# with largest number of nodes in it. class Solution(object):
def isSelfCrossing(self, x):
# Bottom-up recursively determine whether a subtree is a BST if its children and BSTs and he root node value is """
# between the highest in left subtree and smallest in right subtree. :type x: List[int]
# Time - O(n) :rtype: bool
# Space - O(1) """
for i in range(len(x)):
# Definition for a binary tree node. # assume staring with verical move up
class TreeNode(object): if i >= 3:
def __init__(self, x): # move down <= move up and move left >= move right
self.val = x if x[i - 1] <= x[i - 3] and x[i] >= x[i - 2]:
self.left = None return True
self.right = None if i >= 4:
# move right equal to move left and last move up >= vertical distance from start
class Solution(object): if x[i - 1] == x[i - 3] and x[i] >= x[i - 2] - x[i - 4]:
def largestBSTSubtree(self, root): return True
""" if i >= 5:
:type root: TreeNode # final move right >= horizontal distance to start and left move > first right move and
:rtype: int # final vertical move >= vertical distance to start but also <= down move
""" if x[i] >= x[i - 2] - x[i - 4] and x[i - 2] > x[i - 4] and x[i - 3] - x[i - 5] <= x[i - 1] <= x[i - 3]:
self.largest = 0 return True
def is_bst(node): # return largest in subtree, smallest in subtree, subtree count return False
# subtree count = -1 if not a BST
if not node:
# python_1_to_1000/338_Counting_Bits.py
# python_1_to_1000/336_Palindrome_Pairs.py - h
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/counting-bits/
# https://leetcode.com/problems/palindrome-pairs/ # Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's
# Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that the concatenation # in their binary representation and return them as an array.
# of the two words, i.e. words[i] + words[j] is a palindrome.
# Dynamic programming. Number of set bits is 1 + the number of set bits in the number after removing the lowest
# Build a mapping from each word to its index in words. Partition each word at ever possible point. If left is a # set bit.
# palindrome and reverse right is a word (but not the word itself), then add rev_right + word to the result. # Time - O(n)
# Repeat for right being a palindrome and rev_left a word. Remove duplicates from words and their reverses by # Space - O(n)
# requiring left not to be empty.
# Time - O(n * k**2) where k is the max length of a word class Solution(object):
# Space - O(n * k) def countBits(self, num):
"""
class Solution(object): :type num: int
def palindromePairs(self, words): :rtype: List[int]
""" """
:type words: List[str] ones = [0]
:rtype: List[List[int]] for i in range(1, num + 1):
""" ones.append(1 + ones[i & (i - 1)]) # i & (i-1) removes the lowest set bit
palindromes = [] return ones
word_to_index = {}
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/flatten-nested-list-iterator/ # python_1_to_1000/343_Integer_Break.py - m
# Given a nested list of integers, implement an iterator to flatten it.
# Each element is either an integer, or a list -- whose elements may also be integers or other lists. _author_ = 'jake'
_project_ = 'leetcode'
# Recursively flatten the list. If isInteger() then append that integer to the list, else depth first search.
# Time - O(n) to initialise, O(1) for next() and hasNext() # https://leetcode.com/problems/integer-break/
# Space - O(n) # Given a positive integer n, break it into the sum of at least two positive integers and maximize the product
# of those integers. Return the maximum product you can get.
# """
# This is the interface that allows for creating nested lists. # For numbers > 4, subtract as many 3s as possible since any larger number should itself be broken and 3*3 > 2*2*2 so
# You should not implement it, or speculate about its implementation # subtracting 3s is better than 2s.
# """ # Alternatively, dynamic programming to try all splits.
# class NestedInteger(object): # Time - O(1)
# def isInteger(self): # Space - O(1)
# """
# @return True if this NestedInteger holds a single integer, rather than a nested list. class Solution(object):
# :rtype bool def integerBreak(self, n):
# """ """
# :type n: int
# def getInteger(self): :rtype: int
# """ """
# @return the single integer that this NestedInteger holds, if it holds a single integer if n <= 3:
# Return None if this NestedInteger holds a nested list return n - 1
# :rtype int
# """ threes, remainder = divmod(n - 4, 3)
# product = 3**threes
# def getList(self): remainder += 4
# """
# @return the nested list that this NestedInteger holds, if it holds a nested list if remainder == 4:
# Return None if this NestedInteger holds a single integer return product * 2 * 2
# :rtype List[NestedInteger] if remainder == 5:
# """ return product * 3 * 2
return product * 3 * 3
class NestedIterator(object):
s = [c for c in s] # https://leetcode.com/problems/design-tic-tac-toe/
for j in range(n_vowel // 2): # Design a Tic-tac-toe game that is played between two players on a n x n grid.
s[vowel_i[j]], s[vowel_i[n_vowel - j - 1]] = s[vowel_i[n_vowel - j - 1]], s[vowel_i[j]] # A move is guaranteed to be valid and is placed on an empty block.
# Once a winning condition is reached, no more moves is allowed.
return "".join(s) # A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game.
# Arrays store the sums of each row and column, integers store the sums of the diagonals. Convert player to +/-1 and
# python_1_to_1000/346_Moving_Average_from_Data_Stream.py # increment sum of row, col and potentially diagonals. Check if any of row, col or diagonal has absolute sum of n.
# Time - O(n) for constructor and to O(1) for move()
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class TicTacToe(object):
# https://leetcode.com/problems/moving-average-from-data-stream/
# Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window. def __init__(self, n):
"""
# Circular array. Replace array at index i with next val, update total and increment i. When i reaches end of array, Initialize your data structure here.
# reset i to start of array. :type n: int
# Time - O(n) where n == size for __init__(). O(1) for next(). """
# Space - O(n) self.rows, self.cols = [0 for _ in range(n)], [0 for _ in range(n)]
self.d_up, self.d_down = 0, 0
class MovingAverage(object):
def move(self, row, col, player):
def __init__(self, size): """
""" Player {player} makes a move at ({row}, {col}).
Initialize your data structure here. @param row The row of the board.
:type size: int @param col The column of the board.
""" @param player The player, can be either 1 or 2.
self.array = [None for _ in range(size)] # sliding window contents @return The current winning condition, can be either:
self.i = 0 # next index of array to be updated 0: No one wins.
self.total = 0 # sum of array 1: Player 1 wins.
2: Player 2 wins.
def next(self, val): :type row: int
""" :type col: int
:type val: int :type player: int
:rtype: float :rtype: int
""" """
if self.array[self.i] is not None: # subtract entry leaving window from total n = len(self.rows)
self.total -= self.array[self.i] score = (2 * player) - 3 # convert player to -1 or +1
self.total += val
self.array[self.i] = val self.rows[row] += score
self.cols[col] += score
self.i = (self.i + 1) % len(self.array) if abs(self.rows[row]) == n or abs(self.cols[col]) == n:
return player
count = len(self.array) # find number of entries
if self.array[-1] is None: if row == col:
count = self.i self.d_up += score
if abs(self.d_up) == n:
return self.total / float(count) return player
if row + col == n - 1:
self.d_down += score
# python_1_to_1000/347_Top_K_Frequent_Elements.py - m if abs(self.d_down) == n:
return player
_author_ = 'jake'
_project_ = 'leetcode' return 0
# https://leetcode.com/problems/top-k-frequent-elements/
# Given a non-empty array of integers, return the k most frequent elements.
# python_1_to_1000/349_Intersection_of_Two_Arrays.py
# Count the frequency of each element. Bucket sort the elements by frequency since the highest frequency cannot be
# more than the length of nums. Take the most frequent buckets, ties are split randomly. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/intersection-of-two-arrays/
from collections import Counter # Given two arrays, write a function to compute their intersection.
class Solution(object): # Convert to sets, find intersection and convert back to list.
def topKFrequent(self, nums, k): # Time - O(n + m)
""" # Space - O(n + m)
:type nums: List[int]
:type k: int class Solution(object):
:rtype: List[int] def intersection(self, nums1, nums2):
""" new_visited.add(extension)
:type nums1: List[int] new_paths.append([new_visited, extension])
:type nums2: List[int]
:rtype: List[int] paths = new_paths
"""
return list(set(nums1) & set(nums2)) if length >= m:
patterns += len(paths)
class Solution(object):
def intersect(self, nums1, nums2): # python_1_to_1000/352_Data_Stream_as_Disjoint_Intervals.py - h
"""
:type nums1: List[int] _author_ = 'jake'
:type nums2: List[int] _project_ = 'leetcode'
:rtype: List[int]
""" # https://leetcode.com/problems/data-stream-as-disjoint-intervals/
freq1 = Counter(nums1) # Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen so far as a
# list of disjoint intervals in order of interval starting value.
result = []
for i, num in enumerate(nums2): # Create a wrapper class for interval that adds a parent attribute. For each number map it to an IntervalNode which
if num in freq1 and freq1[num] > 0: # may itself be mapped to further IntervalNodes in a tree. Separately track all ultimate intervals in a set.
freq1[num] -= 1 # When a new value is added, check for integers above and below for their ultimate parent intervals. Collapsing the
result.append(num) # tree in a union-find structure. If only one is found, update that interval with the new value.
# If both are found, update the lower interval to merge them, remove the upper interval and update the parent of the
return result # upper IntervalNode to the lower IntervalNode.
# Alternatively store intervals as an sorted list with O(n) to insert then sort then O(1) to getIntervals().
# Alternatively store vals as an unsorted list then sort the list and merge to form intervals in getIntervals().
# python_1_to_1000/351_Android_Unlock_Patterns.py - m # Alternatively, use BST.
# Time - O(log*n) to find parent, O(n log n) to sort intervals
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
# Definition for an interval.
# https://leetcode.com/problems/android-unlock-patterns/ # class Interval(object):
# Given an Android 3x3 key lock screen and two integers m and n, where 1 ≤ m ≤ n ≤ 9, count the total number of # def __init__(self, s=0, e=0):
# unlock patterns of the Android lock screen, which consist of minimum of m keys and maximum n keys. # self.start = s
# - Each pattern must connect at least m keys and at most n keys. # self.end = e
# - All the keys must be distinct.
# - If the line connecting two consecutive keys in the pattern passes through any other keys, the other keys must class IntervalNode(object):
# have previously selected in the pattern. No jumps through non selected key is allowed. def __init__(self, interval):
# - The order of keys used matters. self.inner = interval
self.parent = self
# BFS. For each of 3 starting positions (corner, middle edge, centre) extend all paths by all possible new digits.
# An extension is possible if the new digit has not been used before and any required intervening digits have been class SummaryRanges(object):
# used. Alternatively, DFS uses less memory.
# Alternatively, having worked out the result for each digit, store the results and perform a simple sum. def __init__(self):
# Time - O(n!) """
# Space - O(n!) Initialize your data structure here.
"""
class Solution(object): self.parents = {} # mapping from val to its IntervalNode
def numberOfPatterns(self, m, n): self.intervals = set() # all intervals that have not been joined
"""
:type m: int def get_parent(self, v):
:type n: int if v not in self.parents:
:rtype: int return None
""" interval_node = self.parents[v]
skips = [(1, 7, 4), (1, 9, 5), (1, 3, 2), (2, 8, 5), while interval_node != interval_node.parent:
(3, 7, 5), (3, 9, 6), (4, 6, 5), (7, 9, 8)] interval_node.parent = interval_node.parent.parent
jumps = {} interval_node = interval_node.parent
for start, end, skip in skips: return interval_node
jumps[(start, end)] = skip # to extend from start to end requires going via skip
jumps[(end, start)] = skip def addNum(self, val):
"""
def count_patterns(start): :type val: int
:rtype: void
paths = [[{start}, start]] """
patterns = 1 if m == 1 else 0 if val in self.parents: # already seen val, ignore
for length in range(2, n + 1): return
for extension in range(1, 10): if lower and upper: # update lower, remove upper
if extension in visited: # cannot extend is already visited digit lower.inner.end = upper.inner.end
continue self.parents[val] = lower
if (last, extension) in jumps and jumps[(last, extension)] not in visited: upper.parent = lower
continue # cannot extend if have not visited any intervening digit self.intervals.remove(upper.inner)
new_visited = set(visited)
elif lower:
lower.inner.end += 1
self.parents[val] = lower
# python_1_to_1000/354_Russian_Doll_Envelopes.py - h
elif upper:
upper.inner.start -= 1 _author_ = 'jake'
self.parents[val] = upper _project_ = 'leetcode'
else: # https://leetcode.com/problems/russian-doll-envelopes/
new_inner = Interval(val, val) # You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envelope can fit
self.parents[val] = IntervalNode(new_inner) # into another if and only if both the width and height of one envelope is greater than the width and height of the
self.intervals.add(new_inner) # other envelope. What is the maximum number of envelopes can you Russian doll? (put one inside other)
# Create nested envelopes by wrapping larger ones around smaller. Sort by increasing width, with ties broken by
def getIntervals(self): # decreasing height. If widths are unique then when envelopes are considered in order we can always wrap the
""" # next envelope around any previous in the width dimension. If widths are same then largest height first ensures we
:rtype: List[Interval] # do not put same width envelopes inside each other.
""" # Maintain a list of the smallest outer envelope height for each number of nested envelopes. For each envelope find the
result = list(self.intervals) # longest nested list that can be extended. Update the best extended list with the new envelope if it has smaller
result.sort(key = lambda x : x.start) # height, or make a new longest list.
return result # Time - O(n log n)
# Space - O(n)
return feed for digits in range(2, min(n, 10) + 1): # no increase after used all digits
can_expand *= (11 - digits)
def follow(self, followerId, followeeId): uniques += can_expand
"""
Follower follows a followee. If the operation is invalid, it should be a no-op. return uniques
:type followerId: int
:type followeeId: int
:rtype: void
"""
self.followers[followerId].add(followeeId) # python_1_to_1000/358_Rearrange_String_k_Distance_Apart.py - h
# https://leetcode.com/problems/bomb-enemy/
# python_1_to_1000/359_Logger_Rate_Limiter.py # Given a 2D grid, each cell is either a wall 'W', an enemy 'E' or empty '0' (the number zero), return the maximum
# enemies you can kill using one bomb. The bomb kills all the enemies in the same row and column from the planted
_author_ = 'jake' # point until it hits the wall since the wall is too strong to be destroyed.
_project_ = 'leetcode' # Note that you can only put the bomb at an empty cell.
# https://leetcode.com/problems/logger-rate-limiter/ # Whenever there is a wall to the left or above we have the start of a new clear row/col. Run along the row/col until
# Design a logger system that receive stream of messages along with its timestamps, each message should be printed # either end or next wall counting enemies. At every clear space, add the current row and col enemies.
# if and only if it is not printed in the last 10 seconds. # Time - O(m * n)
# Given a message and a timestamp (in seconds granularity), return true if the message should be printed in the # Space - O(n)
# given timestamp, otherwise returns false.
# It is possible that several messages arrive roughly at the same time. class Solution(object):
def maxKilledEnemies(self, grid):
# Dictionary maps messages to last print time. If message not sen before or not seen for 10 seconds then update last """
# print time and return true. Else return false. :type grid: List[List[str]]
# Time - O(1) :rtype: int
# Space - O(n) """
if not grid or not grid[0]:
class Logger(object): return 0
rows, cols = len(grid), len(grid[0])
def __init__(self): max_kill_enemies, row_kill, col_kill = 0, 0, [0 for _ in range(cols)]
"""
Initialize your data structure here. for r in range(rows):
""" for c in range(cols):
self.last = {}
if c == 0 or grid[r][c - 1] == "W": # wall on left
def shouldPrintMessage(self, timestamp, message): row_kill, i = 0, c
""" while i < cols and grid[r][i] != "W": # go right until end or wall
Returns true if the message should be printed in the given timestamp, otherwise returns false. row_kill += grid[r][i] == "E" # count enemies
If this method returns false, the message will not be printed. i += 1
The timestamp is in seconds granularity.
:type timestamp: int if r == 0 or grid[r - 1][c] == "W": # wall above
:type message: str col_kill[c], i = 0, r
:rtype: bool while i < rows and grid[i][c] != "W": # go down until end or wall
""" col_kill[c] += grid[i][c] == "E" # count enemies
if message not in self.last or timestamp - self.last[message] >= 10: i += 1
self.last[message] = timestamp
return True if grid[r][c] == "0":
max_kill_enemies = max(max_kill_enemies, row_kill + col_kill[c])
return False
return max_kill_enemies
# python_1_to_1000/360_Sort_Transformed_Array.py - m
class Solution(object):
class HitCounter2(object): def depthSumInverse(self, nestedList):
"""
def __init__(self): :type nestedList: List[NestedInteger]
self.time_diff = 300 :rtype: int
self.q = deque() """
self.count = 0 depth_sums = [] # depth_sums[i] is the sum of integers at depth i
for nested in nestedList:
def hit(self, timestamp): self.dfs(nested, 0, depth_sums)
if self.q and self.q[len(self.q) - 1][0] == timestamp:
self.q[len(self.q) - 1][1] += 1 total = 0
else: max_depth = len(depth_sums)
self.q.append([timestamp, 1]) for i, depth_sum in enumerate(depth_sums):
self.count += 1 total += (max_depth - i) * depth_sum
return total
def getHits(self, timestamp):
while self.q and timestamp - self.q[0][0] >= self.time_diff:
_, num = self.q.popleft() def dfs(self, nested, depth, depth_sums):
self.count -= num if len(depth_sums) <= depth: # new depth, extend list
return self.count depth_sums.append(0)
# DFS to calculate the sum of integers at each depth, starting with the shallowest. When max_depth is known,
# weight each depth sum by its number of layers above max_depth. # python_1_to_1000/366_Find_Leaves_of_Binary_Tree.py - m
# Alternatively, BFS calculating the cumulative unweighted sum and repeatedly adding it at each depth.
# Bottom-up preorder traversal to find height of each node (1 + max height of children). num_set = set() # the set that has num as its largest value
# Time - O(n) for max_in_s, s in max_to_set.items():
# Space - O(n) if num % max_in_s == 0 and len(s) > len(num_set):
num_set = s
# Definition for a binary tree node.
# class TreeNode(object): max_to_set[num] = num_set | {num} # include num in the set
# def __init__(self, x):
# self.val = x return list(max(max_to_set.values(), key = len)) # max set by length
# self.left = None
# self.right = None
# python_1_to_1000/369_Plus_One_Linked_List.py - m
class Solution(object):
def findLeaves(self, root): _author_ = 'jake'
""" _project_ = 'leetcode'
:type root: TreeNode
:rtype: List[List[int]] # https://leetcode.com/problems/plus-one-linked-list/
""" # Given a non-negative integer represented as non-empty a singly linked list of digits, plus one to the integer.
leaves = [] # leaves[i] is ordered list of nodes with height i # You may assume the integer do not contain any leading zero, except the number 0 itself.
self.height(root, leaves) # The digits are stored such that the most significant digit is at the head of the list.
return leaves
# Add zero to the front then find the digit before the first 9. Increment that digit and set all digits after to zero.
def height(self, node, leaves): # remove leading zero if not incremented.
if not node: # Time - O(n)
return -1 # Space - O(1)
h = 1 + max(self.height(node.left, leaves), self.height(node.right, leaves))
if h >= len(leaves): # increase list size # Definition for singly-linked list.
leaves.append([]) class ListNode(object):
leaves[h].append(node.val) def __init__(self, x):
return h self.val = x
self.next = None
if square == num:
return True # python_1_to_1000/370_Range_Addition.py - m
# python_1_to_1000/371_Sum_of_Two_Integers.py - m smallest = []
frontier = [(nums1[0] + nums2[0], 0, 0)]
_author_ = 'jake'
_project_ = 'leetcode' while frontier and len(smallest) < k:
_, i, j = heapq.heappop(frontier)
# https://leetcode.com/problems/sum-of-two-integers/ smallest.append([nums1[i], nums2[j]])
# Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -. if len(frontier) >= k: # limit heap size
continue
# Use mask to isolate 32 bits. Sum of 2 bits is the XOR. If both bits are set, carry to next bit. Repeat until no if i < len(nums1) - 1: # not the last element of nums1
# more carry. Ir result is more than MAX_INT, subtract 2**32. heapq.heappush(frontier, (nums1[i + 1] + nums2[j], i + 1, j))
# Time - O(log n) if i == 0 and j < len(nums2) - 1: # first element of nums 1 and not the last element of nums2
# Space - O(1) heapq.heappush(frontier, (nums1[i] + nums2[j + 1], i, j + 1))
# Base case is 1 (since a cannot be zero). For each digit of b starting with first, iteratively raise to the power 10 if g == -1: # search lower region
# and multiply by a**digit, all modulo 1337 high = mid - 1
# Time - O(log b) elif g == 1: # search higher region
# Space - O(1) low = mid + 1
else:
class Solution(object): return mid
def superPow(self, a, b):
"""
:type a: int
:type b: List[int] # python_1_to_1000/375_Guess_Number_Higher_or_Lower_II.py - m
:rtype: int
""" _author_ = 'jake'
result = 1 _project_ = 'leetcode'
# python_1_to_1000/373_Find_K_Pairs_With_Smallest_Sums.py - m # Dynamic programming. Min money for any range is the minimum cost after all possible next guesses. Min cost of
# a particular guess is the guess + worst case of having to recurse on the range either above or below the guess.
_author_ = 'jake' # Best guess is never in LHS of range since then the RHS is longer and has greater numbers so we always want LHS to be
_project_ = 'leetcode' # longer.
# Alternatively, top-down recursive.
# https://leetcode.com/problems/find-k-pairs-with-smallest-sums/ # Time - O(n**3)
# You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. # Space - O(n**2)
# Define a pair (u,v) which consists of one element from the first array and one element from the second array.
# Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums. class Solution(object):
def getMoneyAmount(self, n):
# Maintain a heap from which the smallest sums are removed. Add the sum of elements at index 0 in both arrays to heap. """
# Pop smallest from heap, add to heap the pair with incremented index from nums1 unless at end of nums1. Add to heap :type n: int
# the pair :rtype: int
# Time - O(k log k) """
# Space - O(k) # min_money[i][j] is min money to guarantee win if search range length is i+1 starting from j+1
# if length == 1, min_money = 0 since no guess required
import heapq # if length == 2, min_money = lower value of range
min_money = [[0 for _ in range(n)], [i for i in range(1, n)]]
class Solution(object):
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/378_Kth_Smallest_Element_in_a_Sorted_Matrix.py - m
# https://leetcode.com/problems/wiggle-subsequence/
# A sequence of numbers is called a wiggle sequence if the differences between successive numbers strictly alternate _author_ = 'jake'
# between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence _project_ = 'leetcode'
# with fewer than two elements is trivially a wiggle sequence.
# Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A subsequence # https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/
# is obtained by deleting some number of elements (potentially zero) from the original sequence, leaving the remaining # Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest
# elements in their original order. # element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element.
# If next move is in opposite direction to previous move then increase max_length. If not then update previous so # Maintain a heap of frontier numbers to be checked. Remove smallest and add next smallest column (if not end) and
# the last element of the increasing/decreasing/same subsequence is used. # if first column also add next smallest row (if any) to heap.
# Time - O(n) # If k if is more than half the size of the matrix, look for m * n - k + 1th largest.
# Space - O(1) # Time - O(m * n)
# Space - O(m + n)
class Solution(object):
def wiggleMaxLength(self, nums): import heapq
"""
:type nums: List[int] class Solution(object):
:rtype: int def kthSmallest(self, matrix, k):
""" """
if not nums: :type matrix: List[List[int]]
return 0 :type k: int
:rtype: int
max_length = 1 """
prev = nums[0] # start at opposite corner if more than half
direction = 0 # last move undetermined, +1 = up, -1 = down rows, cols = len(matrix), len(matrix[0])
def helper(self, nums, target, memo): # Store the set of all unused numbers. Storing the used numbers does not allow finding a new number in O(1) time.
if target < 0: # Time - O(n) to initialise, O(1) all other operations
return 0 # Space - O(n)
if target == 0:
return 1 class PhoneDirectory(object):
if target in memo:
return memo[target] def __init__(self, maxNumbers):
"""
combos = 0 Initialize your data structure here
for num in nums: @param maxNumbers - The maximum numbers that can be stored in the phone directory.
:type maxNumbers: int # assumes self.items is not empty
""" return self.items[random.randint(0, len(self.items) - 1)]
# need to find new numbers that are free, not numbers that are used
# so only store the free set
self.free = set(range(maxNumbers)) # python_1_to_1000/381_Insert_Delete_GetRandom_O(1)_Duplicates_Allowed.py - h
class Solution(object):
def firstUniqChar(self, s): # python_1_to_1000/390_Elimination_Game.py - m
"""
:type s: str _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
counts = [0 for _ in range(26)] # https://leetcode.com/problems/elimination-game/
# There is a list of sorted integers from 1 to n. Starting from left to right, remove the first number and every other
for c in s: # number afterward until you reach the end of the list. Repeat the previous step again, but this time from right to
counts[ord(c) - ord("a")] += 1 # left, remove the right most number and every other number from the remaining numbers.
# We keep repeating the steps again, alternating left to right and right to left, until a single number remains.
for i, c in enumerate(s): # Find the last number that remains starting with a list of length n.
if counts[ord(c) - ord("a")] == 1:
return i # Track the first remaining number until only 1 number is left. On left to right passes, head moves by step. On right
# to left passes, head moves by step only if an odd number remain else head stays. Step doubles and remaining halves
return -1 # every pass.
# Time - O(log n), half remaining each pass
# Space - O(1)
# python_1_to_1000/388_Longest_Absolute_File_Path.py - m
class Solution(object):
_author_ = 'jake' def lastRemaining(self, n):
_project_ = 'leetcode' """
:type n: int
# https://leetcode.com/problems/longest-absolute-file-path/ :rtype: int
# Suppose we abstract our file system by a string in the following manner: """
# The string "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext" represents the directory dir contains an empty sub-directory head = 1 # first remaining number
# subdir1 and a sub-directory subdir2 containing a file file.ext. l_to_r = True # direction of next movement
# Given a string representing the file system in the above format, return the length of the longest absolute path to step = 1 # numbers jumped over in each move
# file in the abstracted file system. If there is no file in the system, return 0.
while n > 1: # remaining live numbers
# For each line, depth is number of prefix tabs. If line cointains "." update longest with stripped line length +
# depth (for intervening "/") + depths[depth] (for directories). Else if not a file, update the next directory if l_to_r:
# length as directory length at this depth + new directory length. head += step
# Time - O(n) else: # head only moves if odd number remaining
# Space - O(n) if n % 2 != 0:
head += step
class Solution(object):
def lengthLongestPath(self, input): step *= 2
""" n //= 2 # reduce by half, +1 if n is odd
:type input: str l_to_r = not l_to_r
:rtype: int
""" return head
longest = 0
depths = [0] # depths[i] is the cumulative length of all directory strings preceeding file at depth i.
corners[(r1, c1)] += 1 i += 1
corners[(r2, c2)] += 1 while bytes:
corners[(r1, c2)] += 1 if i >= len(data) or data[i] & (128 + 64) != 128:
corners[(r2, c1)] += 1 return False
bytes -= 1
rows = max_r - min_r i += 1
cols = max_c - min_c
if area != rows * cols: return True
return False
for r, c in corners:
if r in {min_r, max_r} and c in {min_c, max_c}: # python_1_to_1000/394_Decode_String.py - m
if corners[(r, c)] != 1:
return False _author_ = 'jake'
elif corners[(r, c)] % 2 != 0: _project_ = 'leetcode'
return False
# https://leetcode.com/problems/decode-string/
return True # Given an encoded string, return it's decoded string.
# The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated
# exactly k times. Note that k is guaranteed to be a positive integer.
# python_1_to_1000/392_Is_Subsequence.py # You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.
_author_ = 'jake' # Build stack of chars of result. Iterate over input, pushing chars to stack.
_project_ = 'leetcode' # Parse digits to an integer until opening bracket, then push integer to stack and reset.
# If closing bracket, pop chars until integer is found then push back char sequence multiplied by integer.
# https://leetcode.com/problems/is-subsequence/ # Alternatively, recursively.
# Given a string s and a string t, check if s is subsequence of t. # Time - O(2**n), integer creates sequence of length 2**n
# You may assume that there is only lower case English letters in both s and t. t is potentially a very long # Space - O(2**n)
# (length ~= 500,000) string, and s is a short string (<=100).
class Solution(object):
# Iterate over t looking for first char of s. When found continue iteration over t looking for next char of s. def decodeString(self, s):
# Alternatively if many different s, create lists if indices of each char in t then binary search list for each char of """
# s to find index in t after previous index in t. :type s: str
# Time - O(n) when len(t) = n :rtype: str
# Space - O(1) """
stack = []
class Solution(object): repeats = 0
def isSubsequence(self, s, t): digits = set("0123456789")
"""
:type s: str for c in s:
:type t: str
:rtype: bool if c == "]":
""" item = stack.pop()
if not s: current = []
return True while not isinstance(item, int):
current.append(item)
i = 0 # next char to match in s item = stack.pop()
for c in t: stack += (current[::-1] * item)
if c == s[i]:
i += 1 elif c in digits:
if i == len(s): repeats = repeats * 10 + int(c)
return True
return False elif c == "[": # must have preceeding integer
stack.append(repeats)
repeats = 0
# python_1_to_1000/393_UTF-8_Validation.py - m
else:
_author_ = 'jake' stack.append(c)
_project_ = 'leetcode'
return "".join(stack)
# https://leetcode.com/problems/utf-8-validation/
# A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules:
# For 1-byte character, the first bit is a 0, followed by its unicode code. class Solution2(object):
# For n-bytes character, the first n-bits are all one's, the n+1 bit is 0, followed by n-1 bytes with most def decodeString(self, s):
# significant 2 bits being 10. """
# Given an array of integers representing the data, return whether it is a valid utf-8 encoding. :type s: str
:rtype: str
# If first bit set then count number of leading 1s, not 1 or more than 4, check following bytes start with 10 """
# Time - O(n) self.i = 0 # next index in s to be decoded
# Space - O(1) return "".join(self.decode(s))
# Calculate the initial rotated_value and sum of all elements. To rotate, every element is incremented and last element :type nums: List[int]
# is reduced from n-1 to zero times. :type numsSize: int
# Time - O(n) """
# Space - O(n) self.nums = nums
# https://leetcode.com/problems/evaluate-division/
# python_1_to_1000/397_Integer_Replacement.py - m # Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real
# number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.
_author_ = 'jake'
_project_ = 'leetcode' # Create a graph with nodes as variables and directed edge A->B weighted by the ratio A/B. Floyd-Warshall calculates
# weights of paths between all pairs of nodes by iteratively adding paths between 2 nodes (j and k) that can be reached
# https://leetcode.com/problems/integer-replacement/ # from node i.
# Given a positive integer n and you can do operations as follow: # Time - O(n**3) where n is number of variables
# If n is even, replace n with n/2. # Space - O(n**2)
# If n is odd, you can replace n with either n + 1 or n - 1.
# What is the minimum number of replacements needed for n to become 1? from collections import defaultdict
mins = str(mins)
# python_1_to_1000/400_Nth_Digit.py - m if len(mins) == 1: # pad with leading zero
mins = "0" + mins
_author_ = 'jake' result.append(str(hours) + ":" + mins)
_project_ = 'leetcode'
return result
# https://leetcode.com/problems/nth-digit/
# Find the nth digit of the infinite integer sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...
# python_1_to_1000/402_Remove_K_Digits.py - m
# There are 9 digits of length 1, 2 * 90 of length 2, 3 * 900 of length 3 ... Find the length of the number containing
# the nth digit by subtracting all shorter length digits. Then divide n - 1 by length to get the number. Remainder is _author_ = 'jake'
# the required digit. _project_ = 'leetcode'
# Time - O(log n)
# Space - O(1) # https://leetcode.com/problems/remove-k-digits/
# Given a non-negative integer num represented as a string, remove k digits from the number so that the new number
class Solution(object): # is the smallest possible.
def findNthDigit(self, n):
""" # Iterate over num. If previous digit > current digit then preferable to remove previous digit provided k is +ve.
:type n: int # This creates result in non-descending order. Add all digits to result.
:rtype: int # If any k remain, remove least significant digits. Remove leading zeros.
""" # Time - O(n)
length = 1 # Space - O(n)
digits = 9
class Solution(object):
while n > digits: def removeKdigits(self, num, k):
n -= digits """
digits = (length + 1) * 9 * (10 ** length) :type num: str
length += 1 :type k: int
:rtype: str
start = 10 ** (length - 1) # first number of this length """
num, digit = divmod(n - 1, length) result = []
num += start
for c in num:
return int(str(num)[digit])
while k and result and result[-1] > c:
result.pop()
# python_1_to_1000/401_Binary_Watch.py k -= 1
# Enumerate the possible arrangements of setting num bits. Set bits one at a time, initially the first bit can be in _author_ = 'jake'
# any position that allows enough space for the remaining bits. Then for each setting add the next bit in all positions _project_ = 'leetcode'
# that allow space for the remaining bits.
# https://leetcode.com/problems/frog-jump/
# For each setting, convert the first 4 bits to the hour and the last 6 to minutes. Reject if impossible. Format as # A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone.
# time with zero padding for single-digit minutes. # The frog can jump on a stone, but it must not jump into the water.
# Time - O(n * 10! / n!(10 - n)!) 10 choose n possibilities, each of length n # Given a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the
# Space - O(n * 10! / n!(10 - n)!) # river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1
unit.
class Solution(object): # If the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units.
def readBinaryWatch(self, num): # Note that the frog can only jump in the forward direction.
"""
:type num: int # For each stone, create a set of previous jump distances that can reach that stone.
:rtype: List[str] # For each jump size that can reach each stone, for each of the 3 jump sizes, if this reaches another stone add it
# to the set of jumps that can reach that next stone. # python_1_to_1000/406_Queue_Reconstruction_by_Height.py - m
# Time - O(n**2)
# Space - O(n**2) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def canCross(self, stones): # https://leetcode.com/problems/queue-reconstruction-by-height/
""" # Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k),
:type stones: List[int] # where h is the height of the person and k is the number of people in front of this person who have a
:rtype: bool # height greater than or equal to h. Write an algorithm to reconstruct the queue.
"""
jumps = {} # key is stone position, value is set of jump sizes that can reach that stone # Group people by height. Sort heights descending from tallest. For each group of people of the same height, sort
for stone in stones: # from least to most in front and insert into queue. if_front is correct insertion position because there are no
jumps[stone] = set() # shorter people already in queue.
jumps[0].add(0) # Time - O(n**2), each person inserted into list.
# Space - O(n)
for stone in stones:
for jump in jumps[stone]: from collections import defaultdict
for shift in [-1, 0, 1]:
if jump + shift > 0 and stone + jump + shift in jumps: class Solution(object):
jumps[stone + jump + shift].add(jump + shift) def reconstructQueue(self, people):
"""
return bool(jumps[stones[-1]]) :type people: List[List[int]]
:rtype: List[List[int]]
"""
# python_1_to_1000/404_Sum_of_Left_Leaves.py queue = []
height_groups = defaultdict(list)
_author_ = 'jake'
_project_ = 'leetcode' for height, in_front in people:
height_groups[height].append(in_front)
# https://leetcode.com/problems/sum-of-left-leaves/
# Find the sum of all left leaves in a given binary tree. all_heights = list(height_groups.keys())
all_heights.sort(reverse = True)
# If node has a left child with no children then return the left child val + recurse right. Else recurse left and right.
# Time - O(n) for height in all_heights:
# Space - O(1) height_groups[height].sort()
for in_front in height_groups[height]:
class Solution(object): queue.insert(in_front, [height, in_front])
def sumOfLeftLeaves(self, root):
""" return queue
:type root: TreeNode
:rtype: int
""" # python_1_to_1000/407_Trapping_Rain_Water_II.py - h
if not root:
return 0 _author_ = 'jake'
_project_ = 'leetcode'
if root.left and not root.left.left and not root.left.right:
return root.left.val + self.sumOfLeftLeaves(root.right) # https://leetcode.com/problems/trapping-rain-water-ii/
# Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map,
return self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right) # compute the volume of water it is able to trap after raining.
# Simulate raising the water level from the outside of the map. Add to a heap all cells on the outer perimeter.
# python_1_to_1000/405_Convert_a_Number_to_Hexadecimal.py # Pop the lowest cell and for each neighbour not previously visited, add water to the height of the original cell
# and add neighbour to the heap.
_author_ = 'jake' # Time - O(mn log mn)
_project_ = 'leetcode' # Space - O(mn)
# Binary search must make progress each iteration. Since mid can equal left then next iteration brings right down to
# python_1_to_1000/408_Valid_Word_Abbreviation.py # mid instead of left up (which may result in no change). right = mid-1 and left=mid may not make progress.
# Time - O(n log sum(n))
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/valid-word-abbreviation/ def splitArray(self, nums, m):
# Given a non-empty string s and an abbreviation abbr, return whether the string matches with the given abbreviation. """
# Assume s contains only lowercase letters and abbr contains only lowercase letters and digits. :type nums: List[int]
:type m: int
# Iterate over abbreviation. If char then check if matches words and increment both pointer. If digit, parse the :rtype: int
# number and move forward the pointer in word. Return false if pointers do not reach the end of word and abbr """
# simultaneously. left, right = max(nums), sum(nums) # search range
# Time - O(n) length of abbr
# Space - O(1) while left < right: # if left == right then return
mid = (left + right) // 2
class Solution(object): if self.can_split(nums, m, mid): # recurse on LHS (smaller max subarray sums) including mid
def validWordAbbreviation(self, word, abbr): right = mid # mid < right so always make progress
""" else:
:type word: str left = mid + 1
:type abbr: str
:rtype: bool return left
"""
i, j = 0, 0 def can_split(self, nums, m, max_subarray): # can nums be split into m subarrays each sum <= max_subarray ?
else: # letter
if i >= len(word) or abbr[j] != word[i]:
return False # python_1_to_1000/411_Minimum_Unique_Word_Abbreviation.py - h
i += 1
j += 1 _author_ = 'jake'
_project_ = 'leetcode'
return i == len(word) # must use all of word
# https://leetcode.com/problems/minimum-unique-word-abbreviation/
# A string such as "word" contains the following abbreviations:
# ["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2", "2r1", "3d", "w3", "4"]
# Given a target string and a set of strings in a dictionary, find an abbreviation of this target string with the
# python_1_to_1000/409_Longest_Palindrome.py # smallest possible length such that it does not conflict with abbreviations of the strings in the dictionary.
# Each number or letter in the abbreviation is considered length = 1. For example, the abbreviation "a32bc" has length =
_author_ = 'jake' 4.
_project_ = 'leetcode' # In the case of multiple answers, you may return any one of them.
# https://leetcode.com/problems/longest-palindrome/ # Encode each word in dictionary with same length as target, setting bits where word char != target char.
# Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that # For each possible pattern of chars in target to to retain, check if target differs from each word by at least one
# can be built with those letters. This is case sensitive, for example "Aa" is not considered a palindrome here. # char. If so convert bitwise encoded trget to string and compare with shortest.
# Time - O(n * k * 2**n) where len(target) = n and len(dictionary) = k
# Iterate over s maintaining a set of letters seen. If a letter is seen again, add 2 to length of palindrome and # Space - O(kn)
# delete from set. If a letter is not in set, add it. Add 1 for a single letter in the middle of the palindrome if
# there are any single letters after iteration. class Solution(object):
# Time - O(n) """
# Space - O(1) :type target: str
:type dictionary: List[str]
class Solution(object): :rtype: str
def longestPalindrome(self, s): """
""" def minAbbreviation(self, target, dictionary):
:type s: str def abbr(target, num):
:rtype: int word, count = [], 0 # count of char sequence that can be abbreviated
""" for w in target:
max_length = 0 if num & 1 == 1: # char in target must remain
letters = set() if count:
word += str(count)
for c in s: count = 0
if c in letters: word.append(w)
max_length += 2 else: # char in target can be abbreviated
letters.remove(c) count += 1
else: num >>= 1 # right shift, divide by 2
letters.add(c)
if count:
return max_length + bool(letters) word.append(str(count))
return "".join(word)
# python_1_to_1000/410_Split_Array_Largest_Sum.py - h m = len(target)
diffs = [] # representation of each word in terms of which chars are different from target
_author_ = 'jake'
_project_ = 'leetcode' for word in dictionary:
if len(word) != m:
# https://leetcode.com/problems/split-array-largest-sum/ continue
# Given an array which consists of non-negative integers and an integer m, you can split the array into m non-empty bits = 0
# continuous subarrays. Write an algorithm to minimize the largest sum among these m subarrays. for i, char in enumerate(word):
if char != target[i]: # set bits when chars are different
# Binary search the range of possible smallest max subarray sums. If x is valid, search range x and below else search bits += 2 ** i
# above x. diffs.append(bits)
_project_ = 'leetcode'
if not diffs:
return str(m) # https://leetcode.com/problems/third-maximum-number/
# Given a non-empty array of integers, return the third maximum number in this array. If it does not exist, return
min_abbr = target # the maximum number. The time complexity must be in O(n).
for i in range(2 ** m): # i represents which chars remain in target
if all(d & i for d in diffs): # i has at least has one char different from every word in dictionary # Iterate over nums. If a number is already one of the top 3 largest unique numbers then ignore it. If larger than
abbr_i = abbr(target, i) # the largest, update largest and demote the first and second largest to second and third. Else if more than the
if len(abbr_i) < len(min_abbr): # second largest, replace second largest and demote previous second to third. Else if more than third, replace third.
min_abbr = abbr_i # Time - O(n)
# Space - O(1)
return min_abbr
class Solution(object):
def thirdMax(self, nums):
# python_1_to_1000/412_Fizz_Buzz.py """
:type nums: List[int]
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
maxima = [float("-inf")] * 3 # maxima[0] is largest unique number seen, maxima[1] is second
# https://leetcode.com/problems/fizz-buzz/
# Write a program that outputs the string representation of numbers from 1 to n. for num in nums:
# But for multiples of three it should output “Fizz” instead of the number and for the multiples of five output “Buzz”.
# For numbers which are multiples of both three and five output “FizzBuzz”. if num in maxima:
continue
# Test if divisible by 15 or 5 or 3 or none of these.
# Time - O(n) if num > maxima[0]:
# Space - O(n) maxima = [num] + maxima[:2]
elif num > maxima[1]:
class Solution(object): maxima[1:] = [num, maxima[1]]
def fizzBuzz(self, n): elif num > maxima[2]:
""" maxima[2] = num
:type n: int
:rtype: List[str] return maxima[2] if maxima[2] != float("-inf") else maxima[0]
"""
result = []
class Solution(object):
# python_1_to_1000/413_Arithmetic_Slices.py - m def addStrings(self, num1, num2):
"""
_author_ = 'jake' :type num1: str
_project_ = 'leetcode' :type num2: str
:rtype: str
# https://leetcode.com/problems/arithmetic-slices/ """
# A sequence of number is called arithmetic if it consists of at least three elements and if the difference between num1, num2 = num1[::-1], num2[::-1]
# any two consecutive elements is the same.
# Return the number of arithmetic slices in the array. length_diff = len(num1) - len(num2)
if length_diff < 0:
# If the current diff is the same as the previous, add to result all slices ending here. Else reset progression start. num1 += "0" * -length_diff
# Time - O(n) else:
# Space - O(1) num2 += "0" * length_diff
class Solution2(object): # Preprocess to find the number of complete sentences and the index of next starting word, for a row starting
def canPartition(self, nums): # with each word. Fill row with complete sentences, then fill word by word. For each row find number of
nums_sum = sum(nums) # sentences and next starting word.
if nums_sum % 2 == 1: # Time - O(nc + r) where n is number of words, c is cols, r is rows.
return False # Space - O(n)
while row_length + sentence_len <= cols: # can fit next sentence in row
row_length += sentence_len
sentences += 1
# python_1_to_1000/417_Pacific_Atlantic_Water_Flow.py - m
while row_length + len(sentence[word_index]) <= cols: # can fit next word in row
_author_ = 'jake' row_length += len(sentence[word_index]) + 1 # extend row_length by word and space
_project_ = 'leetcode' word_index += 1 # move to next word
if word_index == len(sentence): # fitted last word of sentence
# https://leetcode.com/problems/pacific-atlantic-water-flow/ sentences += 1
# Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, word_index = 0
# the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic ocean" touches the right and
# bottom edges. Water can only flow in four directions (up, down, left, or right) from a cell to another one with line_fits.append((sentences, word_index))
# height equal or lower. Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.
fits, word_index = 0, 0
# Maintain a frontier of all cells that flow to each ocean, initially edges of matrix. Expand the frontier by adding for r in range(rows):
# all higher neighbours. sentences, next_word_index = line_fits[word_index]
# Time - O(mn) fits += sentences
# Space - O(mn) word_index = next_word_index
# For difficult case of length > 20. Use required deletions to reduce the number of substitutions required.
# Time - O(n) # python_1_to_1000/422_Valid_Word_Square.py
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def strongPasswordChecker(self, s):
""" # https://leetcode.com/problems/valid-word-square/
:type s: str # Given a sequence of words, check whether it forms a valid word square.
:rtype: int # A sequence of words forms a valid word square if the kth row and column read the exact same string,
""" # where 0 ≤ k < max(numRows, numColumns).
upper, lower, digit = False, False, False
subs, i = 0, 0 # nb subs to remove sequences, index counter # Make a square of same length sides by padding words with spaces. If any word is longer than the first word then
singles, doubles = 0, 0 # nb single and double deletions # it is longer than the corresponding column so not a valid square. Check each row against each column.
# Time - O(n**2)
while i < len(s): # Space - O(n**2)
if len(s) < 6:
return max(types_missing, 6 - len(s)) # python_1_to_1000/423_Reconstruct_Original_Digits_from_English.py - m
if len(s) <= 20:
return max(types_missing, subs) _author_ = 'jake'
_project_ = 'leetcode'
deletions = len(s) - 20
# https://leetcode.com/problems/reconstruct-original-digits-from-english/
subs -= min(deletions, singles) # Given a non-empty string containing an out-of-order English representation of digits 0-9, output the digits in
subs -= min(max(deletions - singles, 0), doubles * 2) / 2 # ascending order.
subs -= max(deletions - singles - 2 * doubles, 0) / 3 # Input contains only lowercase English letters.
# Input is guaranteed to be valid and can be transformed to its original digits.
return deletions + max(types_missing, subs)
# Count the occurrences of letters that uniquely identify thier words (0, 2, 4, 6, 8). For other digits, count the
# occurences of a letter and subtract letters from digits already counted.
# Time - O(n)
# python_1_to_1000/421_Maximum_XOR_of_Two_Numbers_in_an_Array.py - m # Space - O(1)
from collections import Counter for i in range(1, len(word)): # create all non-empty prefixes (excluding full word)
prefixes[word[:i]].append(word)
class Solution(object):
def originalDigits(self, s): squares = []
""" for word in words:
:type s: str self.build_square([word], prefixes, squares) # try all words in first row
:rtype: str return squares
"""
digit_freq = [0] * 10
letter_freq = Counter(s) def build_square(self, partial, prefixes, squares):
#(letter to be counted, words already counted with this letter, digit)
words = [("z", [], 0), ("w", [], 2), ("u", [], 4), ("x", [], 6), ("g", [], 8), if len(partial) == len(partial[0]): # complete square
("o", [0, 2, 4], 1), ("r", [0, 4], 3), ("f", [4], 5), ("v", [5], 7), ("i", [5, 6, 8], 9)] squares.append(list(partial)) # copy partial
return
for letter, other_digits, digit in words:
word_count = letter_freq[letter] prefix = []
for other_digit in other_digits: col = len(partial)
word_count -= digit_freq[other_digit] for row in range(len(partial)):
digit_freq[digit] = word_count prefix.append(partial[row][col])
next_words = prefixes["".join(prefix)]
result = []
for digit, count in enumerate(digit_freq): for next_word in next_words:
result += [str(digit)] * count partial.append(next_word)
return "".join(result) self.build_square(partial, prefixes, squares)
partial.pop() # remove next_word
# python_1_to_1000/424_Longest_Repeating_Character_Replacement.py - m # python_1_to_1000/426_Convert_Binary_Search_Tree_to_Sorted_Doubly_Linked_List.py - m
# https://leetcode.com/problems/longest-repeating-character-replacement/ # https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/
# Given a string that consists of only uppercase English letters, you can replace any letter in the string with another # Convert a BST to a sorted circular doubly-linked list in-place.
# letter at most k times. Find the length of a longest substring containing all repeating letters you can get after # Think of the left and right pointers as synonymous to the previous and next pointers in a doubly-linked list.
# performing the above operations. # Each node in a doubly linked list has a predecessor and successor.
# For a circular doubly linked list, the predecessor of the first element is the last element,
# Maintain a sliding window, moving end forwards every iteration. Move start forwards so that there are at most k chars # and the successor of the last element is the first element.
# in the window that are not the most frequent.
# Time - O(n) # Recursively convert left and right subtrees to circular linked lists. Link tail of left subtree to root and head of
# Space - O(1) # right subtree to root. Complete the circle by linking head and tail.
# Time - O(n)
from collections import defaultdict # Space - O(n)
# Build a mapping of each prefix to all words that have that prefix. For each starting word, find all words with _author_ = 'jake'
# appropriate prefixes to build next row of square. _project_ = 'leetcode'
# Time - O((nk)**k) where k = len(word). For each of n words, calculate prefix of max length k, then recurse n times.
# Space - O(nk) # https://leetcode.com/problems/construct-quad-tree/
# We want to use quad trees to store an N x N boolean grid. Each cell in the grid can only be true or false.
from collections import defaultdict # The root node represents the whole grid. For each node, it will be subdivided into four children nodes until the
# values in the region it represents are all the same.
class Solution(object): # Each node has another two boolean attributes : isLeaf and val. isLeaf is true if and only if the node is a leaf node.
def wordSquares(self, words): # The val attribute for a leaf node contains the value of the region it represents.
""" # Your task is to use a quad tree to represent a given grid.
:type words: List[str] # For the non-leaf nodes, val is True if any of the child node vals are True.
:rtype: List[List[str]] # N is less than 1000 and guaranteed to be a power of 2.
"""
prefixes = defaultdict(list) # Bottom-up recursion. Base case of a single cell. For any grid, recurse for each of the 4 quadrants. If all are
for word in words: # leaves with the same value, the root representing the grid is also a leaf. Else the root is a node with children of
# the 4 quadrant nodes. return
# Time - O(n**2)
# Space - O(n**2) while tokens[0] != "#": # add child nodes with subtrees
value = tokens.popleft()
class Solution(object): child = Node(int(value), [])
def construct(self, grid): node.children.append(child)
""" helper(child)
:type grid: List[List[int]]
:rtype: Node tokens.popleft() # discard the "#"
"""
def helper(r, c, side): # construct quad tree for grid from cell (r, c) with side length of side helper(root)
return root
if side == 1: # base case of single cell
return Node(bool(grid[r][c]), True, None, None, None, None)
# python_1_to_1000/429_N-ary_Tree_Level_Order_Traversal.py - m
top_left = helper(r, c, side // 2)
top_right = helper(r, c + side // 2, side // 2) _author_ = 'jake'
bottom_left = helper(r + side // 2, c, side // 2) _project_ = 'leetcode'
bottom_right = helper(r + side // 2, c + side // 2, side // 2)
# https://leetcode.com/problems/n-ary-tree-level-order-traversal/
if top_left.isLeaf and top_right.isLeaf and bottom_left.isLeaf and bottom_right.isLeaf: # Given an n-ary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
if top_left.val == top_right.val == bottom_left.val == bottom_right.val:
return Node(top_left.val, True, None, None, None, None) # Breadth-first search. For each level, add all child nodes to new_level and append list of node vals to result.
# Time - O(n)
node_val = any((top_left.val, top_right.val, bottom_left.val, bottom_right.val)) # Space - O(n)
return Node(node_val, False, top_left, top_right, bottom_left, bottom_right)
class Solution(object):
if not grid: def levelOrder(self, root):
return None """
return helper(0, 0, len(grid)) :type root: Node
:rtype: List[List[int]]
"""
# python_1_to_1000/428_Serialize_and_Deserialize_N-ary_Tree.py - h if not root:
return []
_author_ = 'jake'
_project_ = 'leetcode' result = []
level = [root] # list of nodes in current level
# https://leetcode.com/problems/serialize-and-deserialize-n-ary-tree/
# Serialization is the process of converting a data structure or object into a sequence of bits so that it can be while level:
# stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the
# same or another computer environment. new_level = []
# Design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a rooted tree in which each node for node in level:
# has no more than N children. There is no restriction on how your serialization/deserialization algorithm should work. new_level += node.children
# Ensure that an N-ary tree can be serialized to a string and this string can be deserialized to the tree structure. result.append([node.val for node in level])
level = new_level
# Serialize with preorder traversal where sentinel "#" indicates the final child of a node has been processed, so the
# function returns to its parent call. return result
# Deserialize by creating a deque (could also use an iterator with next() instead of popleft()). While the next item is
# not "#", create a child with the item, add the child to the list of children and recurse to create its subtree.
# Repeat until there are no more children, then ignore the "#".
# Time - O(n) # python_1_to_1000/430_Flatten_a_Multilevel_Doubly_Linked_List.py - m
# Space - O(n)
_author_ = 'jake'
from collections import deque _project_ = 'leetcode'
def deserialize(self, data): old_next = node.next # save the next so we can link the tail of the flattened child list
"""Decodes your encoded data to tree. node.next = self.flatten(node.child) # insert the flattened child list
:type data: str node.next.prev = node # link child list back to node
:rtype: Node node.child = None # remove the child since it is now flattened
"""
if not data: while node.next:
return None node = node.next # find tail of child list
node.next = old_next # link tail to old_next
tokens = deque(data.split()) if old_next: # link in other direction
root = Node(int(tokens.popleft()), []) old_next.prev = node
new_block.after = old_after
old_after.before = new_block
# python_1_to_1000/431_Encode_N-ary_Tree_to_Binary_Tree.py - h
class Solution(object):
# python_1_to_1000/434_Number_of_Segments_in_a_String.py def findRightInterval(self, intervals):
"""
_author_ = 'jake' :type intervals: List[Interval]
_project_ = 'leetcode' :rtype: List[int]
"""
# https://leetcode.com/problems/number-of-segments-in-a-string/ intervals = [[intervals[i], i] for i in range(len(intervals))]
# Count the number of segments in a string, where a segment is defined to be a contiguous sequence of intervals.sort(key=lambda x: x[0].start)
# non-space characters.
result = [-1] * len(intervals) # default to no right interval
# Split by spaces.
# Time - O(n) for interval, i in intervals:
# Space - O(1)
left, right = 0, len(intervals) # right = len(intervals) indicates no right interval
class Solution(object):
def countSegments(self, s): while left < right:
"""
:type s: str mid = (left + right) // 2
:rtype: int if intervals[mid][0].start < interval.end:
""" left = mid + 1
return len(s.split()) else:
right = mid
if left == len(intervals):
# python_1_to_1000/435_Non-overlppaping_Intervals.py - m continue
result[i] = intervals[left][1]
_author_ = 'jake'
_project_ = 'leetcode' return result
# https://leetcode.com/problems/non-overlapping-intervals/
# Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the
# intervals non-overlapping. # python_1_to_1000/437_Path_Sum_III.py - m
else:
# python_1_to_1000/438_Find_All_Anagrams_in_a_String.py - m stack.append(c)
# https://leetcode.com/problems/find-all-anagrams-in-a-string/ # python_1_to_1000/440_K-th_Smallest_in_Lexicographical_Order.py - h
# Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
# Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than _author_ = 'jake'
20,100. _project_ = 'leetcode'
# The order of output does not matter.
# https://leetcode.com/problems/k-th-smallest-in-lexicographical-order/
# Maintain a count of each letter in a sliding window in s, minus the counts of letters in p. Populate the dictionary # Given integers n and k, find the lexicographically k-th smallest integer in the range from 1 to n.
# with the intial counts, then slide along removing chars at the back and adding chars at the front. Add to result if
# dictionary is empty (all values zero). # Search integers beginning with 1, if not found increment first digit to 2, 3, ... etc.
# Time - O(n) len(s) # Given a beginning digit kth, repeatedly multiply the start and end of search range by 10 until the range includes n.
# Space - O(m) len(p) # If range does not include solution, increment beginning digit kth. Else use kth and multiply range start by 10.
# k complete rows contain the sum form 1 to k coins = k(k + 1) / 2. Solve this quadratic polynomial for k and round down char_start = i
# to nearest integer.
# Time - O(1) return result_length
# Space - O(1)
import math
_author_ = 'jake' # Note org is permutation hence no duplicates. Create set of all consecutive pair in org and mapping from each num in
_project_ = 'leetcode' # org to its index. For each seq remove any consecutive pair from pairs and check numbers appear in increasing index
# order in org. Consecutive pairs in some seq ensures there is no choise condition
# https://leetcode.com/problems/find-all-duplicates-in-an-array/ # Time - O(s + n), total length of all seqs + org
# Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once. # Space - O(n)
# Find all the elements that appear twice in this array.
class Solution(object):
# Indicate that nums[i] has been seen by setting the i-1th entry to be negative. def sequenceReconstruction(self, org, seqs):
# Time - O(n) """
# Space - O(1) :type org: List[int]
:type seqs: List[List[int]]
class Solution(object): :rtype: bool
def findDuplicates(self, nums): """
""" extended = [None] + org # prepend with None to catch len(org) == 1
:type nums: List[int] pairs = set((n1, n2) for n1, n2 in zip(extended, org))
:rtype: List[int] num_to_index = {num: i for i, num in enumerate(extended)}
"""
result = [] for seq in seqs:
num = abs(nums[i]) # nums[i] may be negative because we have seen i + 1, which is irrelevant here if n2 not in num_to_index or num_to_index[n2] <= num_to_index[n1]:
return False
if nums[num - 1] < 0: # already seen num last_index = num_to_index[n2]
result.append(num)
continue pairs.discard((n1, n2))
nums[num - 1] = -nums[num - 1] # flag num as having been seen return not pairs
return result
# python_1_to_1000/445_Add_Two_Numbers_II.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/443_String_Compression.py - m
# https://leetcode.com/problems/add-two-numbers-ii/
_author_ = 'jake' # You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes
_project_ = 'leetcode' # first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
# You may assume the two numbers do not contain any leading zero, except the number 0 itself.
# https://leetcode.com/problems/string-compression/
# Given an array of characters, compress it in-place. # Iterate over lists to calculate the integers they represent and sum them. Build resulting list from the least
# The length after compression must always be smaller than or equal to the original array. # significant digit by repeatedly dividing by 10.
# Every element of the array should be a character (not int) of length 1. # Time - O(m + n)
# After you are done modifying the input array in-place, return the new length of the array. # Space - O(max(m, n))
# Iterate over chars, finding when a sequence ends. Add the char to result and if the sequence is longer than 1 char # Definition for singly-linked list.
# then we compress and add the digits of the number of chars to the result. class ListNode(object):
# Time - O(n) def __init__(self, x):
# Space - O(1) self.val = x
self.next = None
class Solution(object):
def compress(self, chars): class Solution(object):
""" def addTwoNumbers(self, l1, l2):
:type chars: List[str] """
:rtype: int :type l1: ListNode
""" :type l2: ListNode
chars += " " # append with ASCII value 32, will not appear in chars :rtype: ListNode
char_start = 0 # start index of sequence of current char """
result_length = 0 # next index for result to be updated num1, num2 = 0, 0
# https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/
# python_1_to_1000/446_Arithmetic_Slices_II-Subsequence.py - h # Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
# Find all the elements of [1, n] inclusive that do not appear in this array.
_author_ = 'jake'
_project_ = 'leetcode' # Iterate over the list. For every number seen, set the number with index of num - 1 to be negative.
# Iterate again over the list, finding all indices that are still positive and so have not been seen.
# https://leetcode.com/problems/arithmetic-slices-ii-subsequence/ # Time - O(n)
# A sequence of numbers is called arithmetic if it consists of at least three elements and if the difference between # Space - O(1)
# any two consecutive elements is the same.
# A zero-indexed array A consisting of N numbers is given. A subsequence slice of that array is any sequence of class Solution(object):
# integers (P0, P1, ..., Pk) such that 0 ≤ P0 < P1 < ... < Pk < N. def findDisappearedNumbers(self, nums):
# A subsequence slice (P0, P1, ..., Pk) of array A is called arithmetic if the sequence A[P0], A[P1], ..., """
# A[Pk-1], A[Pk] is arithmetic. In particular, this means that k ≥ 2. :type nums: List[int]
# The function should return the number of arithmetic subsequence slices in the array A. :rtype: List[int]
"""
# For each num, create a dictionary mapping arithmetic progression differences to the count of APs of length >= 2 and for num in nums:
# ending at num. For each num find the diff from all previous nums. All APs of length >= 2 ending at previous num num = abs(num) # may be negative so take absolute value
# with that diff can be extended to make a valid subsequence slice. All APs form new APs ending at num plus the new nums[num - 1] = -abs(nums[num - 1]) # set nums[num - 1] to indicate num - 1 seen
# AP from A[i] to A[j].
# Time - O(n**2) return [i + 1 for i, num in enumerate(nums) if num > 0]
# Space - O(n**2)
serial(root)
class Solution(object): return " ".join(serial_list)
def numberOfBoomerangs(self, points):
""" def deserialize(self, data):
:type points: List[List[int]] """Decodes your encoded data to tree.
:rtype: int :type data: str
""" :rtype: TreeNode
"""
def dist_squared(p1, p2): preorder = deque(int(val) for val in data.split()) # convert to integers
return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2
# if first preorder is between low and high, create tree of all vals in that range with first preorder as root # python_1_to_1000/452_Minimum_Number_of_Arrows_to_Burst_Balloons.py - m
def deserial(low, high):
if preorder and low < preorder[0] < high: _author_ = 'jake'
val = preorder.popleft() _project_ = 'leetcode'
node = TreeNode(val)
node.left = deserial(low, val) # https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/
node.right = deserial(val, high) # There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the
return node # start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter and hence
# the x-coordinates of start and end of the diameter suffice. Start is always smaller than end.
return deserial(float("-inf"), float("inf")) # An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend
# bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot.
# An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be
# python_1_to_1000/450_Delete_Node_in_a_BST.py - m # shot to burst all balloons.
_author_ = 'jake' # Sort by ending edge. Greedily shoot first ending edge, which bursts all balloons that start before or after that edge.
_project_ = 'leetcode' # Time - O(n)
# Space - O(1)
# https://leetcode.com/problems/delete-node-in-a-bst/
# Given a root node reference of a BST and a key, delete the node with the given key in the BST. class Solution(object):
# Return the root node reference (possibly updated) of the BST. def findMinArrowShots(self, points):
"""
# Recursively test if key is root value. If not recurse left or right and update subtree. If root has key, replace root :type points: List[List[int]]
# value with next largest value and recurse to update root right subtree having deleted node with next largest value. :rtype: int
# Time - O(n), height of tree """
# Space - O(1) arrows, last_arrow = 0, float("-inf")
points.sort(key = lambda x: x[1])
# Definition for a binary tree node.
class TreeNode(object): for start, end in points:
def __init__(self, x):
self.val = x if start > last_arrow:
self.left = None arrows += 1
self.right = None last_arrow = end
# python_1_to_1000/454_4Sum_II.py - m
# python_1_to_1000/451_Sort_Characters_by_Frquency.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/4sum-ii/
# https://leetcode.com/problems/sort-characters-by-frequency/ # Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that
# Given a string, sort it in decreasing order based on the frequency of characters. # A[i] + B[j] + C[k] + D[l] is zero. All A, B, C, D have same length.
# Count frequency of chars and sort tuples of (-count, char) into frequency order. # Count all sums of pairs in lists A and B. For each pair in C and D, increment total by count of -(c + d) from AB.
# Time - O(n log n) # Time - O(n**2)
# Space - O(n) # Space - O(n**2)
class Solution(object):
class Solution(object): def fourSumCount(self, A, B, C, D):
def frequencySort(self, s): """
""" :type A: List[int]
:type s: str :type B: List[int]
:rtype: str :type C: List[int]
""" :type D: List[int]
freq = Counter(s) :rtype: int
pairs = [(count, c) for c, count in freq.items()] """
pairs.sort(reverse = True) AB = defaultdict(int)
count = 0
result = []
for count, c in pairs: for a in A:
result += [c] * count for b in B:
AB[a + b] += 1
return "".join(result)
for c in C:
for d in D:
if -(c + d) in AB: # Assume the first element of the array is forward next to the last element, and the last element is backward next to
count += AB[-(c + d)] # the first element. Determine if there is a loop in this array.
# A loop starts and ends at a particular index with more than 1 element along the loop.
return count # The loop must be "forward" or "backward'.
# Example 1: Given the array [2, -1, 1, 2, 2], there is a loop, from index 0 -> 2 -> 3 -> 0.
# Example 2: Given the array [-1, 2], there is no loop.
# python_1_to_1000/455_Assign_Cookies.py # Note: The given array is guaranteed to contain no element "0".
_author_ = 'jake' # For each starting num, attempt to find a sequence of n steps, which implies there must be a loop. A loop is not found
_project_ = 'leetcode' # if any step returns to the same index or moves in the opposite direction.
# Time - O(n)
# https://leetcode.com/problems/assign-cookies/ # Space - O(1)
# Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at
# most one cookie. Each child i has a greed factor gi, which is the minimum size of a cookie that the child will be class Solution(object):
# content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, and the def circularArrayLoop(self, nums):
# child i will be content. Your goal is to maximize the number of your content children and output the maximum number. """
:type nums: List[int]
# Sort both lists in ascending order. For each cookie, offer it to the next child. If it is accepted, increment the :rtype: bool
# number of satisfied children and move to the next child. If it is not accepted, discard the cookie and test the """
# next cookie on the same child. n = len(nums)
# Time - O(n)
# Space - O(1) for i, num in enumerate(nums):
while stack and stack[-1] < nums[i]: return int(ceil(log(buckets) / log(rounds + 1)))
two = stack.pop()
stack.append(nums[i]) # python_1_to_1000/459_Repeated_Substring_Pattern.py
# python_1_to_1000/457_Circular_Array_Loop.py - m # https://leetcode.com/problems/repeated-substring-pattern/
# Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of
_author_ = 'jake' # the substring together. You may assume the given string consists of lowercase English letters only.
_project_ = 'leetcode'
# If a string consists of 2 copies of a substring, then appending the string to itself and removing the first and last
# https://leetcode.com/problems/circular-array-loop/ # letters will still contain 2 copies of the substring. The same is true if there are more than 2 copies.
# You are given an array of positive and negative integers. If a number n at an index is positive, then move forward # Conversely, if the string is not a repeated substring then it cannot be built this way from 2 copies.
# n steps. Conversely, if it's negative (-n), move backward n steps. # Time - O(n)
# Space - O(n) self.map[key] = value
class Solution(object):
def repeatedSubstringPattern(self, s):
""" # python_1_to_1000/461_Hamming_Distance.py
:type s: str
:rtype: bool _author_ = 'jake'
""" _project_ = 'leetcode'
return s in (s[1:] + s[:-1])
# https://leetcode.com/problems/hamming-distance/
# The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
# python_1_to_1000/460_LFU_Cache.py - h # Given two integers x and y, calculate the Hamming distance.
_author_ = 'jake' # Iterate over the bits of z and y together. If least significant bits are different, increment result. Right shift
_project_ = 'leetcode' # to move to next bit until both integers are zero.
# Time - O(log n)
# https://leetcode.com/problems/lfu-cache/ # Space - O(1)
# Design and implement a data structure for Least Frequently Used (LFU) cache.
# It should support the following operations: get and put. class Solution(object):
# get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. def hammingDistance(self, x, y):
# put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it """
# should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when :type x: int
# there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted. :type y: int
:rtype: int
# Maintain dict form key to value, dict from key to (freq, time), priority queue and set of keys to update in queue. """
# For get and put existing key, do not update queue but add key to update set. For put when cache is full, update queue hamming = 0
# until top item does not need updating.
# Time - O(1) for get, O(k log k) for put while x or y:
# Space - O(k) hamming += (x & 1) != (y & 1)
x >>= 1
import heapq y >>= 1
def get(self, key): # Sort and remove front and back in pairs. The difference between each pair has to be closed to equal the pair, but the
""" # meeting point can be anywhere in the gap. Result is that median (or anywhere between 2 medians) is optimal.
:type key: int # Time - O(n log n)
:rtype: int # Space - O(1)
"""
self.time += 1 class Solution(object):
def minMoves2(self, nums):
if key in self.map: """
freq, _ = self.freq_time[key] :type nums: List[int]
self.freq_time[key] = (freq + 1, self.time) :rtype: int
self.update.add(key) """
return self.map[key] nums.sort()
front, back = 0, len(nums) - 1
return -1 moves = 0
while front < back:
def put(self, key, value): moves += nums[back] - nums[front]
""" front += 1
:type key: int back -= 1
:type value: int
:rtype: void return moves
"""
if self.capacity <= 0:
return # python_1_to_1000/463_Island_Perimeter.py
if len(self.map) >= self.capacity: # must remove least frequent from cache # https://leetcode.com/problems/island-perimeter/
# You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water.
while self.priority_queue and self.priority_queue[0][2] in self.update: # Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water,
# whilst (least frequent, oldest) needs to be updated, update it and add back to heap # and there is exactly one island (i.e., one or more connected land cells). The island doesn't have "lakes" (water
_, _, k = heapq.heappop(self.priority_queue) # inside that isn't connected to the water around the island). One cell is a square with side length 1. The grid
f, t = self.freq_time[k] # is rectangular, width and height don't exceed 100. Determine the perimeter of the island.
heapq.heappush(self.priority_queue, (f, t, k))
self.update.remove(k) # Iterate over grid. If a cell is land, add 4 to perimeter assuming cell is surrounded by water. Then for each of lower
# and right cells that are land, decrement the perimeter by 2 (both sides of the internal edge).
# remove (least frequent, oldest) # Time - O(mn)
_, _, k = heapq.heappop(self.priority_queue) # Space - O(mn)
self.map.pop(k)
self.freq_time.pop(k) class Solution(object):
def islandPerimeter(self, grid):
self.freq_time[key] = (0, self.time) """
heapq.heappush(self.priority_queue, (0, self.time, key)) :type grid: List[List[int]]
:rtype: int
else: """
freq, _ = self.freq_time[key] rows, cols = len(grid), len(grid[0])
self.freq_time[key] = (freq + 1, self.time) for row in grid: # pad with water
self.update.add(key) row.append(0)
grid.append([0] * (cols + 1))
# Keep unused numbers in an ordered list (not a set, so can be converted to stable tuple for memo, largest can be
# identified). If for any number, opposition cannot win then can win. Memoise lists as tuples. # python_1_to_1000/466_Count_The_Repetition.py - h
# Time - O(n * n!), n = maxChoosableInteger. n choices initially, n-1, n-2. Each choice takes O(n) to construct list.
# Space - O(n * n!) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def canIWin(self, maxChoosableInteger, desiredTotal): # https://leetcode.com/problems/count-the-repetitions/
""" # Define S = [s,n] as the string S which consists of n connected strings s. For example, ["abc", 3] ="abcabcabc".
:type maxChoosableInteger: int # On the other hand, we define that string s1 can be obtained from string s2 if we can remove some characters from s2
:type desiredTotal: int # such that it becomes s1. For example, “abc” can be obtained from “abdbec” based on our definition, but it can not
:rtype: bool # be obtained from “acbbe”.
""" # You are given two non-empty strings s1 and s2 and two integers n1 and n2. Now consider the strings S1 and S2,
if maxChoosableInteger * (maxChoosableInteger + 1) // 2 < desiredTotal: # where S1=[s1,n1] and S2=[s2,n2]. Find the maximum integer M such that [S2,M] can be obtained from S1.
return False # all numbers cannot reduce desiredTotal to zero
# Step through s1, incrementing also in s2 if chars match. Go back to the beginning and increment reps at the end of
return self.next_player_win(desiredTotal, list(range(1, maxChoosableInteger + 1)), {}) # either string. At end of s1, record position in s2 and reps. If position seen before then break because loop found.
# Find number of possible loops after initial stub. Add s2_reps for final stub.
# Time - O(m * n), iterate over s1 until have seen all ending positions in s2
def next_player_win(self, target, unused, memo): # Space - O(m * n)
if s1[i] == s2[j]:
# python_1_to_1000/465_Optimal_Account_Balancing.py - h j += 1 # increment j if chars match
i += 1
_author_ = 'jake'
_project_ = 'leetcode' if j == len(s2):
j = 0
# https://leetcode.com/problems/optimal-account-balancing/ s2_reps += 1
# A group of friends went on holiday and sometimes lent each other money. For example, Alice paid for Bill's lunch for
# $10. Then later Chris gave Alice $5 for a taxi ride. We can model each transaction as a tuple (x, y, z) which means if i == len(s1):
# person x gave person y $z. Assuming Alice, Bill, and Chris are person 0, 1, and 2 respectively (0, 1, 2 are the i = 0
# person's ID), the transactions can be represented as [[0, 1, 10], [2, 0, 5]]. s1_reps += 1
# Given a list of transactions between a group of people, return the minimum number of transactions to settle the debt. if j in s2_index_to_reps: # same position in s2 as before, in a loop
break
# Calculate the net balance owed to or from each person. For any sequence of net balances, calculate the number of s2_index_to_reps[j] = (s1_reps, s2_reps) # record reps at this position in s2
# transfers recursively. Take the net balance of the first person. If any other person has the opposite balance then
# net them off (one transfer) and calculate the transfers to settle the remaining balances. Else find the minimum if s1_reps == n1: # no loop found
# transfers from netting with each other person. return s2_reps // n2
# Time - O(m + (n - 1)!) where m = len(transactions) and n is the number of people, since t(n) = (n-1) * t(n-1)
# Space - O(n**2) initial_s1_reps, initial_s2_reps = s2_index_to_reps[j]
loop_s1_reps = s1_reps - initial_s1_reps
from collections import defaultdict loop_s2_reps = s2_reps - initial_s2_reps
loops = (n1 - initial_s1_reps) // loop_s1_reps # number of loops possible after initial_s1_reps
class Solution(object):
def minTransfers(self, transactions): s1_reps = initial_s1_reps + loops * loop_s1_reps
""" s2_reps = initial_s2_reps + loops * loop_s2_reps
:type transactions: List[List[int]]
:rtype: int while s1_reps < n1: # until n1 copies of s1 used
"""
balances = defaultdict(int) # map person to net balance if s1[i] == s2[j]:
j += 1 n = int(group, 16)
i += 1 if n < 0 or n > int("FFFF", 16) or len(group) > 4 or group[0] == "-": # eliminate "00000" and "-0"
return "Neither"
if i == len(s1):
i = 0 return "IPv6"
s1_reps += 1
if j == len(s2): # python_1_to_1000/469_Convex_Polygon.py - m
j = 0
s2_reps += 1 _author_ = 'jake'
_project_ = 'leetcode'
return s2_reps // n2
# https://leetcode.com/problems/convex-polygon/
# Given a list of points that form a polygon when joined sequentially, find if this polygon is convex.
# There are at least 3 and at most 10,000 points.
# python_1_to_1000/467_Unique_Substrings_in_Wraparound_String.py - m # Coordinates are in the range -10,000 to 10,000.
# You may assume the polygon formed by given points is always a simple polygon (Simple polygon definition). In other
_author_ = 'jake' # words, we ensure that exactly two edges intersect at each vertex, and that edges otherwise don't intersect each other.
_project_ = 'leetcode'
# For each edge, calculate cross product with previous edge. All cross products must have same sign to be convex.
# https://leetcode.com/problems/unique-substrings-in-wraparound-string/ # Time - O(n)
# Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz", so s will look like # Space - O(1)
# this: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....".
# Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. class Solution(object):
# In particular, your input is the string p and you need to output the number of different non-empty substrings of p def isConvex(self, points):
# in the string s. p consists of only lowercase English letters. """
:type points: List[List[int]]
# Record the longest substring ending with each of the 26 letters. Iterate over p, incrementing the substring length :rtype: bool
# if letter incerements previous. Update max substring ending with current letter. Result is sum of all substrings for """
# all letters. points.append(points[0]) # close the polygon by appending first edge to end
# Time - O(n) points.append(points[1]) # ditto
# Space - O(1) previous = [points[1][0] - points[0][0], points[1][1] - points[0][1]]
previous_cross = 0
class Solution(object):
def findSubstringInWraproundString(self, p): for i in range(2, len(points)):
"""
:type p: str vector = [points[i][0] - points[i - 1][0], points[i][1] - points[i - 1][1]]
:rtype: int cross_product = vector[0] * previous[1] - vector[1] * previous[0]
"""
substring_ending = [0] * 26 # length of longest substring ending with char if cross_product != 0:
length = 0 if previous_cross * cross_product < 0:
return False
for i, c in enumerate(p): previous_cross = cross_product
if i != 0 and (ord(c) == ord(p[i - 1]) + 1 or ord(c) == ord(p[i - 1]) - 25): previous = vector
length += 1
else: return True
length = 1
# https://leetcode.com/problems/implement-rand10-using-rand7/
# python_1_to_1000/468_Validate_IP_Address.py - m # Given a function rand7 which generates a uniform random integer in the range 1 to 7, write a function rand10 which
# generates a uniform random integer in the range 1 to 10.
_author_ = 'jake'
_project_ = 'leetcode' # Create a 2 digit number in base 7, of which there are 49. Use only the first 40, where the units in base 10 have
# an equal probability of being each digit.
# https://leetcode.com/problems/validate-ip-address/ # Time - O(infinity), expected is sum of arithmetico–geometric sequence
# Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither. # Space - O(1)
# IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each
# ranging from 0 to 255, separated by dots ("."). leading zeros in IPv4 are invalid. class Solution(object):
# IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The def rand10(self):
# groups are separated by colons (":"). Leading zeros are optional. Upper or lower case letters are allowed. """
# However, we don't replace a consecutive group of zero value with a single empty group using two consecutive colons :rtype: int
# (::) to pursue simplicity. """
# You may assume there is no extra space or special characters in the input string. units = rand7() - 1
sevens = rand7() - 1
# Split by "." to check if IPv4. All group members must be integers >= 0 and <= 255. Split by ":" to check IPv6. num = 7 * sevens + units # between 0 and 48 inclusive
# Time - O(n)
# Space - O(n) if num >= 40: # use on 0 to 39 inclusive
return self.rand10()
class Solution(object):
def validIPAddress(self, IP): return (num % 10) + 1 # take units digit
"""
:type IP: str
:rtype: str # python_1_to_1000/471_Encode_String_With_Shortest_Length.py - h
"""
ip_list = IP.split(".") _author_ = 'jake'
if len(ip_list) == 4: _project_ = 'leetcode'
for group in ip_list:
n = int(group) # https://leetcode.com/problems/encode-string-with-shortest-length/
if n < 0 or n > 255 or len(str(n)) != len(group): # len checks for leading zeros or minus zero # Given a non-empty string, encode the string such that its encoded length is the shortest.
return "Neither" # The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being
return "IPv4" # repeated exactly k times.
# k will be a positive integer and encoded string will not be empty or have extra space.
ip_list = IP.split(":") # You may assume that the input string contains only lowercase English letters.
if len(ip_list) != 8: # If an encoding process does not make the string shorter, then do not encode it.
return "Neither" # If there are several solutions, return any of them is fine.
for group in ip_list: # Take the minumum length of 3 possible encoding types:
# 1) If s consists entirely of a repeated substring, encode as that substring with recursion. def dfs(index):
# 2) For all breakpoints in s, recursively encode LHS and RHS
# 3) s without encoding if index == len(nums): # all sides are full
# Memoise results. return True
# Time - O(n**3) every one of O(n**2) substring is encoded, taking O(n) time to construct each. for side in range(4):
# Space - O(n**3) if sides[side] + nums[index] > target or sides[side] in sides[side + 1:]: # match too long or
continue # skip if replicated side length to avoid duplicate recusrsion
class Solution(object): sides[side] += nums[index] # add match to side
def encode(self, s, memo = {}): # amend signature to add memo, empty by default if dfs(index + 1):
""" return True
:type s: str sides[side] -= nums[index] # remove match if cannot fill all sides
:rtype: str return False # match cannot fit on any side
"""
if s in memo: perimeter = sum(nums)
return memo[s] target, remainder = divmod(perimeter, 4)
if not perimeter or remainder: # no matches or not divisible by 4
encodings = [s] # list of possible encodings return False
i = (s + s).find(s, 1) # repeated substring problem
if i != -1 and i != len(s): # s consists of a repeated substring (which is not s itself) nums.sort(reverse = True) # fail early, e.g 5 matches are > target/2
encodings.append(str(len(s) / i) + "[" + self.encode(s[:i], memo) + "]") # recurse if nums[0] > target: # longest is greater than side length
return False
for i in range(1, len(s)): # all possible break points
encodings.append(self.encode(s[:i], memo) + self.encode(s[i:], memo)) sides = [0] * 4 # total length of matches on each side
i = 0
result = min(encodings, key = len) # minimum length of all encodings while i < 4 and nums[i] == target: # prefill any side with matches of exact length
memo[s] = result sides[i] = target
return result i += 1
return dfs(i)
# python_1_to_1000/472_Concatenated_Words.py - h
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/474_Ones_and_Zeros.py - m
class Solution(object): # Dynamic programming. max_form[i][j] is the max number of strings that can be formed form i zeros and j ones.
def findAllConcatenatedWordsInADict(self, words): # For each string, if i or j are insufficient cannot form string so keep max_form unchanged. If can form string, take
""" # max of incremented max_form and using s_zeros, s_ones, or same max_form and not using any zeros or ones.
:type words: List[str] # Time - O(mnk), where k = len(strs)
:rtype: List[str] # Space - O(mn)
"""
class Solution(object):
def is_concat(word): def findMaxForm(self, strs, m, n):
if not word or word in word_set: # word will not be empty on first call """
return True :type strs: List[str]
:type m: int
for i in range(1, len(word) + 1): # check to end of word :type n: int
if word[:i] in word_set and is_concat(word[i:]): :rtype: int
return True """
max_form = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
return False for s in strs:
# python_1_to_1000/473_Matchsticks_to_Square.py - m
class Solution(object): # Sort heaters and houses. Add sentinel heaters at + and - infinity. For each house, move along the heaters until the
def makesquare(self, nums): # current heater is on the left of the house and the next heater is at or on the right of the house. One of these
""" # heaters is the closest to the house. Update the radius to be the max of the current radius and the closest heater.
:type nums: List[int] # Time - O(m log m + n log n)
:rtype: bool # Space - O(m) where m = len(heaters)
"""
class Solution(object):
def findRadius(self, houses, heaters): # Given the radius and x-y positions of the center of a circle, write a function randPoint which generates a uniform
""" # random point in the circle.
:type houses: List[int] # Note:
:type heaters: List[int] # input and output values are in floating-point.
:rtype: int # radius and x-y position of the center of the circle is passed into the class constructor.
""" # a point on the circumference of the circle is considered to be in the circle.
heaters.sort() # randPoint returns a size 2 array containing x-position and y-position of the random point, in that order.
houses.sort()
heaters = [float("-inf")] + heaters + [float("inf")] # Rejection sampling from the square containing the circle. Choos a random point inside the square with x and y
# between -1 and 1. This has probability of pi / 4 of being in the circle of radius 1. Else repeat until random point
i = 0 # is in the circle.
radius = -1 # Alternatively use polar coordinates with a random distance and angle. Square root of distance is required to
# normalise the density of points, or else the probability decreases with radius.
for house in houses: # Time - O(1) expected 4 / pi
# Space - O(1)
while heaters[i + 1] < house:
i += 1 import random
left_distance = house - heaters[i]
right_distance = heaters[i + 1] - house # could be zero class Solution(object):
closest = min(left_distance, right_distance)
radius = max(radius, closest) def __init__(self, radius, x_center, y_center):
"""
return radius :type radius: float
:type x_center: float
:type y_center: float
"""
# python_1_to_1000/476_Number_Complement.py self.radius = radius
self.x_center = x_center
_author_ = 'jake' self.y_center = y_center
_project_ = 'leetcode'
def randPoint(self):
# https://leetcode.com/problems/number-complement/ """
# Given a positive integer, output its complement number. The complement strategy is to flip the bits of its :rtype: List[float]
# binary representation. """
x, y = 2 * random.random() - 1, 2 * random.random() - 1 # x and y between -1 and 1
# Find the number with all 1s that is the same length as num. Then take the XOR to flip the bits. if x * x + y * y > 1: # outside circle, repeat
# Time - O(log n) return self.randPoint()
# Space - O(1) return [x * self.radius + self.x_center, y * self.radius + self.y_center] # translate from unit circle
# python_1_to_1000/477_Total_Hamming_Diatance.py - m # Build palindromes with 2 * n digits, starting from the largest palindrome and check if they can be factorised.
# Define palindrome as upper * 10**n + lower.
_author_ = 'jake' # The two factors are M = 10**n - i and L = 10**n - j where i and j are small.
_project_ = 'leetcode' # Hence palindrome = (10**n - i) * (10**n - j) = 10**n * (10**n - (i + j)) + i * j = upper * 10**n + lower.
# So upper = 10**n - (i + j) and lower = i * j.
# https://leetcode.com/problems/total-hamming-distance/ # Define a = i + j. This means that a = 10**n - upper.
# The Hamming distance between two integers is the number of positions at which the corresponding bits are different. # Substituting for j = a - i, the equation for lower can be rewritten as lower = a * i - i * i.
# Now your job is to find the total Hamming distance between all pairs of the given numbers. # Solving for i, in order for i to be an integer sqrt(a**2 - 4 * lower) must be an integer.
# Time - O(n * 10**n) for the for loop
# For each of the 32 bits, count how many nums have that bit set. Add to total hamming distance count of pairs from # Space - O(1)
# nums where one num has bit set and one num soes not have bit set.
# Time - O(n) class Solution(object):
# Space - O(1) def largestPalindrome(self, n):
"""
class Solution(object): :type n: int
def totalHammingDistance(self, nums): :rtype: int
""" """
:type nums: List[int] if n == 1:
:rtype: int return 9
"""
n = len(nums) for a in range(1, 9 * 10 ** (n - 1)):
hamming = 0
hi = (10 ** n) - a # most significant digits of palindrome
for bit in range(32): lo = int(str(hi)[::-1]) # least significant digits of palindrome
set_bits = 0 # count of nums with this bit set
for num in nums: if a ** 2 - 4 * lo < 0:
set_bits += (num >> bit) & 1 continue
hamming += (n - set_bits) * set_bits if (a ** 2 - 4 * lo) ** .5 == int((a ** 2 - 4 * lo) ** .5): # sqrt(a**2 - 4*lo) is an integer
return (lo + 10 ** n * (10 ** n - a)) % 1337
return hamming
# python_1_to_1000/478_Generate_Random_Point_in_a_Circle.py - m # python_1_to_1000/480_Sliding_Window_Median.py - h
# https://leetcode.com/problems/generate-random-point-in-a-circle/ # https://leetcode.com/problems/sliding-window-median/
# Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the
# very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. # For each s[i], append to s i copies of a different digit from that currently at the end of s.
# Your job is to output the median array for each window in the original array. # Time - O(n)
# Space - O(n)
# Maintain 2 heaps, upperr with values >= median and lower with values <= median. If window is odd length, upper
# contains the odd value. Fill heaps with initial window then iterate over remaining nums. At star of each iteration class Solution(object):
# balance = 0. Add median to result, add start of old window to junk and add end of window to new heap, both times def magicalString(self, n):
# updating balance. If imbalance then shift a num from one heap to the other. Remove junk from top of heaps. """
# Time - O(n log k) :type n: int
# Space - O(n) :rtype: int
"""
from collections import defaultdict if n == 0:
import heapq return 0
for i in range(k, len(nums)): if len(s) > n and s[-1] == 1: # added too many ones
ones -= 1
if k % 2 == 1: return ones
medians.append(float(upper[0]))
else:
medians.append((upper[0] - lower[0]) / 2.0)
# python_1_to_1000/482_License_Key_Formatting.py
balance = 0 # +ve implies surplus in upper, -ve is surplus in lower
_author_ = 'jake'
if nums[i - k] >= upper[0]: _project_ = 'leetcode'
balance -= 1
else: # https://leetcode.com/problems/license-key-formatting/
balance += 1 # You are given a string S, which represents a software license key which we would like to format. The string S is
junk[nums[i - k]] += 1 # composed of alphanumerical characters and dashes. The dashes split the alphanumerical characters within the string
# into groups. (i.e. if there are M dashes, the string is split into M+1 groups). The dashes in the given string are
if nums[i] >= upper[0]: # possibly misplaced.
balance += 1 # We want each group of characters to be of length K (except for possibly the first group, which could be shorter, but
heapq.heappush(upper, nums[i]) # still must contain at least one character). To satisfy this requirement, we will reinsert dashes. Additionally, all
else: # the lower case letters in the string must be converted to upper case.
balance -= 1 # You are given a non-empty string S, representing a license key to format, and an integer K. And you need to
heapq.heappush(lower, -nums[i]) # return the license key formatted according to the description above.
# balance == +/-2 or 0 # Replace "-" by "" and convert to upper case. Append complete blocks of length K to result working from back of string.
# if either heap has a surplus, it's top value cannot be junk # If any stub append that, reverse blocks and join.
if balance > 0: # Time - O(n)
heapq.heappush(lower, -heapq.heappop(upper)) # Space - O(n)
elif balance < 0:
heapq.heappush(upper, -heapq.heappop(lower)) class Solution(object):
def licenseKeyFormatting(self, S, K):
while upper and upper[0] in junk: """
removed = heapq.heappop(upper) :type S: str
junk[removed] -= 1 :type K: int
if junk[removed] == 0: :rtype: str
del junk[removed] """
while lower and -lower[0] in junk: key = S.replace("-", "").upper()
removed = -heapq.heappop(lower) formatted = []
junk[removed] -= 1
if junk[removed] == 0: i = len(key) - K
del junk[removed] while i >= 0:
formatted.append(key[i:i + K])
if k % 2 == 1: i -= K
medians.append(float(upper[0]))
else: if i != -K:
medians.append((upper[0] - lower[0]) / 2.0) formatted.append(key[:i + K])
return medians return "-".join(formatted[::-1])
return "-".join(formatted)
# python_1_to_1000/481_Magical_String.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/483_Smallest_Good_Base.py - h
# https://leetcode.com/problems/magical_string/
# A magical string S consists of only '1' and '2' and obeys the following rules: _author_ = 'jake'
# The string S is magical because concatenating the number of contiguous occurrences of characters '1' and '2' generates _project_ = 'leetcode'
the string S itself.
# The first few elements of string S is the following: S = "1221121221221121122……" # https://leetcode.com/problems/smallest-good-base/
# If we group the consecutive '1's and '2's in S, it will be: 1 22 11 2 1 22 1 22 11 2 11 22 ...... # For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1.
# and the occurrences of '1's or '2's in each group are: 1 2 2 1 1 2 1 2 2 1 2 2 ...... # Given a string representing n, you should return the smallest good base of n in string format.
# You can see that the occurrence sequence above is the S itself.
# Given an integer N as input, return the number of '1's in the first N number in the magical string S. # For base b, n = b**k + b**(k-1) + .. n + 1 for some b and max_power k.
# Try max powers from largest (base 2 = binary representation) down to 2. Since n > base**max_power and consecutive += 1
# n < (base+1)**max_power, base must be int(n**(1/max_power). Test if true. Fallback to base n-1.
# Time - O(log n) return max(max_consecutive, consecutive) # check final sequence
# Space - O(1)
import math
# python_1_to_1000/486_Predict_the_Winner.py - m
class Solution(object):
def smallestGoodBase(self, n): _author_ = 'jake'
""" _project_ = 'leetcode'
:type n: str
:rtype: str # https://leetcode.com/problems/predict-the-winner/
""" # Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the
n = int(n) # array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not
# be available for the next player. This continues until all the scores have been chosen.
for max_power in range(int(math.log(n, 2)), 1, -1): # largest max_power implies smallest base # The player with the maximum score wins. If the scores of both players are equal, then player 1 is still the winner.
# Given an array of scores, predict whether player 1 is the winner. You can assume each player maximizes his score.
base = int(n ** max_power ** -1) # find the only possible base for this max_power
if n == ((base ** (max_power + 1)) - 1) // (base - 1): # sum of geometric series # Recursively remove left and right. For each case, find score after worst case next opponent move. Take best score of
return str(base) # each case. Memoize.
# Time - O(n**2)
return str(n - 1) # fallback to base n-1, represents any n as "11" # Space - O(n**2)
class Solution(object):
def PredictTheWinner(self, nums):
# python_1_to_1000/484_Find_Permutation.py - m """
:type nums: List[int]
_author_ = 'jake' :rtype: bool
_project_ = 'leetcode' """
stack.append(len(s) + 1) # https://leetcode.com/problems/max-consecutive-ones-ii/
while stack: # Given a binary array, find the maximum number of consecutive 1s in this array if you can flip at most one 0.
permutation.append(stack.pop())
# Record the start of the current sequence and the start of the previous sequence (flipping a zero).
return permutation # Iterate over array, incrementing sequence end. If two zeros, reset prev_start to current. If single zero, update max
# and prev_start to start.
# Time - O(n)
# python_1_to_1000/485_Max_Consecutive_Ones.py # Space - O(1)
# Depth-first search. Each state is a location and direction. Clean the location and add to visited set.
# For each of the 4 neighbouring cells, if neighbour has not been visited and can be moved to, recurse to visit
# python_1_to_1000/488_Zuma_Game.py - h # neighbour, then move back to original cell and turn left.
# Time - O(mn)
_author_ = 'jake' # Space - O(mn)
_project_ = 'leetcode'
class Solution:
# https://leetcode.com/problems/zuma-game/ def cleanRoom(self, robot):
# You have a row of balls on the table, colored red(R), yellow(Y), blue(B), green(G), and white(W). You also have """
# several balls in your hand. :type robot: Robot
# Each time, you may choose a ball in your hand, and insert it into the row (including the leftmost place and :rtype: None
# rightmost place). Then, if there is a group of 3 or more balls in the same color touching, remove these balls. Keep """
# doing this until no more balls can be removed. Find the minimal balls you have to insert to remove all the balls visited = set()
# on the table. If you cannot remove all the balls, output -1.
def dfs(x, y, dx, dy):
# Iterate over board. When a sequence ends, if enough of same colour in hand to make a run of 3, add those balls
# from hand and recurse. robot.clean()
# Time - T(n) for board of length n = n**2 * T(n-3) since n recursions, each taking n time to remove_sequences visited.add((x, y))
# then solving sub-problem of length n-3.
for _ in range(4):
from collections import Counter
if ((x + dx, y + dy)) not in visited and robot.move():
class Solution(object): dfs(x + dx, y + dy, dx, dy)
def findMinStep(self, board, hand): robot.turnLeft() # revert to original position and direction
""" robot.turnLeft()
:type board: str robot.move()
:type hand: str robot.turnLeft()
:rtype: int robot.turnLeft()
"""
def remove_sequences(board): # recursively remove any sequences of length 3 or more robot.turnLeft()
start, end = 0, 0 dx, dy = -dy, dx
while end < len(board):
if board[start] == board[end]: dfs(0, 0, 0, 1)
end += 1
elif end - start >= 3:
return remove_sequences(board[:start] + board[end:])
else: # python_1_to_1000/490_The_Maze.py - m
start = end
if end - start >= 3: _author_ = 'jake'
board = board[:start] _project_ = 'leetcode'
return board
# https://leetcode.com/problems/the-maze/
def helper(board): # There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up, down,
if not board: # left or right, but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next
return 0 direction.
if not hand: # Given the ball's start position, the destination and the maze, determine whether the ball can stop at the destination.
return -1 # The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. You may assume that the
# borders of the maze are all walls. The start and destination coordinates are represented by row and column indexes.
min_balls = 6 # since len(hand) <= 5
start, end = 0, 0 # DFS. Maintain queue of stopping points. For the next point, move in all 4 directions to find next stopping points.
# Store visisted points to avoid repetition.
while end < len(board) + 1: # Time - O(m * n)
# Space - O(m * n)
if end == len(board) or board[start] != board[end]:
need = 3 - (end - start) # number needed in hand to make a sequence of 3 class Solution(object):
colour = board[start] def hasPath(self, maze, start, destination):
if hand[colour] >= need: """
:type maze: List[List[int]]
hand[colour] -= need :type start: List[int]
next_board = remove_sequences(board[:start] + board[end:]) :type destination: List[int]
min_end = helper(next_board) :rtype: bool
if min_end != -1: """
min_balls = min(need + min_end, min_balls) queue = [start]
hand[colour] += need # put balls back dirns = ((1, 0), (-1, 0), (0, 1), (0, -1))
visited = set()
start = end
while queue:
end += 1 start_r, start_c = queue.pop()
visited.add((start_r, start_c))
return -1 if min_balls == 6 else min_balls
for dr, dc in dirns:
hand = Counter(hand) r, c = start_r, start_c # move as far as possible
return helper(board) while 0 <= r + dr < len(maze) and 0 <= c + dc < len(maze[0]) and maze[r + dr][c + dc] == 0:
r += dr
c += dc
subsequences |= new_subsequences
return [s for s in subsequences if len(s) > 1] # convert to list and filter out if too short # python_1_to_1000/494_Target_Sum.py - m
_author_ = 'jake'
# python_1_to_1000/492_Construct_the_Rectangle.py _project_ = 'leetcode'
# Find the largest integer less than or equal to the square root of the area that divides the area. Try the integer
# less than or equal to the square root and if it does not divide area, decrement until it does. class Solution(object):
# Time - O(area**0.5) def findTargetSumWays(self, nums, S):
# Space - O(1) """
:type nums: List[int]
class Solution(object): :type S: int
def constructRectangle(self, area): :rtype: int
""" """
:type area: int sums = defaultdict(int)
:rtype: List[int] sums[0] = 1
""" running = nums[:] # calc remaining sum from each index
side = int(area ** 0.5)
for i in range(len(nums) - 2, -1, -1):
while area % side != 0: # decrement to find shorter side, faster than increment to find longer side running[i] += running[i + 1]
side -= 1
for i, num in enumerate(nums):
return [area // side, side]
new_sums = defaultdict(int)
for old_sum in sums:
if S <= old_sum + running[i]: # add to neew_sums if not too large
# python_1_to_1000/493_Reverse_Pairs.py - h new_sums[old_sum + num] += sums[old_sum]
if S >= old_sum - running[i]:
_author_ = 'jake' new_sums[old_sum - num] += sums[old_sum]
_project_ = 'leetcode' sums = new_sums
# Mergesort. Before merge, count reversed pairs in sorted left and right lists.
# Time - O(n log n) # python_1_to_1000/495_Teemo_Attacking.py
# Space - O(n log n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def reversePairs(self, nums):
""" # https://leetcode.com/problems/teemo-attacking/
:type nums: List[int] # In LOL world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned condition.
:rtype: int # Now, given the Teemo's attacking ascending time series towards Ashe and the poisoning time duration per Teemo's
""" # attacking, you need to output the total time that Ashe is in poisoned condition.
self.pairs = 0 # You may assume that Teemo attacks at the very beginning of a specific time point, and makes Ashe be in poisoned
condition immediately.
def mergesort(nums):
if len(nums) < 2: # For each time step, add min of the step and duration.
return nums # Time - O(n)
# Space - O(1)
mid = len(nums) // 2
left = mergesort(nums[:mid]) class Solution(object):
right = mergesort(nums[mid:]) def findPoisonedDuration(self, timeSeries, duration):
return merge(left, right) """
:type timeSeries: List[int]
def merge(left, right): :type duration: int
j = 0 :rtype: int
for num in left: """
while j < len(right) and num > 2 * right[j]: poisoned = 0
def vertical(dirn): # Inorder traversal visiting each node in sorted order. If a node value is the same as the previous node value then
return dirn in {"d", "u"} # extend the current sequence. Else start a new sequence. If a sequence has the same count as the previous mode then
# add the value to the mode list. If a sequence has a greater count than the previous mode then value is the only mode.
def perpendicular(dirn): # Time - O(n)
return ["r", "l"] if vertical(dirn) else ["u", "d"] # reverse lexicographical order # Space - O(n) if all values are unique.
# move in same direction as previous if possible if node.val == self.prev: # extend sequence of same value
elif nm == 0: self.count += 1
queue.append((r + dr, c + dc, moves)) # add to back of queue else:
self.prev = node.val # start new sequence
# else move in a perpendicular direction if possible and not at start self.count = 1
elif [r, c] != ball:
trial_dirns = perpendicular(moves[-1]) if self.count == self.mode_count:
for trial_dirn in trial_dirns: modes.append(node.val) # another mode with same count as existing mode(s)
queue.appendleft((r, c, moves + [trial_dirn])) # add to front of queue elif self.count > self.mode_count:
self.mode_count = self.count # new unique mode
return "impossible" modes.clear() # Python 3.3+, else pop until empty or use instance variable
modes.append(node.val)
inorder(node.right)
# python_1_to_1000/500_Keyboard_Row.py inorder(root)
return modes
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/keyboard-row/ # python_1_to_1000/502_IPO.py - h
# Given a List of words, return the words that can be typed using letters of alphabet on only one row of a keyboard.
_author_ = 'jake'
# Map each of the 26 keys to its row. Iterate over word, setting the row of the first char and checking that the rows _project_ = 'leetcode'
# of all other characters are the same as the first.
# Time - O(n) total number of characters in words. # https://leetcode.com/problems/ipo/
# Space - O(1) excluding result. # Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Capital, LeetCode
# would like to work on some projects to increase its capital before the IPO. Since it has limited resources, it can
class Solution(object): # only finish at most k distinct projects before the IPO. Help LeetCode design the best way to maximize its total
def findWords(self, words): # capital after finishing at most k distinct projects.
""" # You are given several projects. For each project i, it has a pure profit Pi and a minimum capital of Ci is needed to
:type words: List[str] # start the corresponding project. Initially, you have W capital. When you finish a project, you will obtain its pure
:rtype: List[str] # profit and the profit will be added to your total capital.
""" # To sum up, pick a list of at most k distinct projects from given projects to maximize your final capital, and output
keyboard = {} # your final maximized capital.
rows = ["qwertyuiop", "asdfghjkl", "zxcvbnm"]
for i, row in enumerate(rows): # Sort projects in increasing order of capital required. Add all projects available with current capital to heap. Pop
for c in row: # from heap project with most profit.
keyboard[c] = i # Time - O(n log n)
# Space - O(n)
result = []
import heapq
for word in words:
row = -1 class Solution(object):
def findMaximizedCapital(self, k, W, Profits, Capital):
for c in word: """
if row == -1: # set the row of first char :type k: int
row = keyboard[c.lower()] :type W: int
elif keyboard[c.lower()] != row: # compare to previous rows :type Profits: List[int]
break :type Capital: List[int]
else: :rtype: int
result.append(word) """
projects = sorted(zip(Capital, Profits))
return result
i = 0
available = [] # profits of projects requiring at most current capital W
# Given the ball's start position, the destination and the maze, find the shortest distance for the ball to stop at the
while i < len(projects) and projects[i][0] <= W: # destination. The distance is defined by the number of empty spaces traveled by the ball from the start position
heapq.heappush(available, -projects[i][1]) # (excluded) to the destination (included). If the ball cannot stop at the destination, return -1.
i += 1 # The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. You may assume that the
# borders of the maze are all walls. The start and destination coordinates are represented by row and column indexes.
if not available: # cannot do any projects
return W # BFS. If can move in same direction, add to new_queue. Else check if solution, move perpendicular. Memoize visited
best_profit = heapq.heappop(available) # locations and directions.
# Time - O(mn)
W -= best_profit # Space - O(mn)
k -= 1
class Solution(object):
return W def shortestDistance(self, maze, start, destination):
"""
:type maze: List[List[int]]
# python_1_to_1000/503_Next_Greater_Element_II.py - m :type start: List[int]
:type destination: List[int]
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
rows, cols = len(maze), len(maze[0])
# https://leetcode.com/problems/next-greater-element-ii/ distance = 0
# Given a circular array (the next element of the last element is the first element of the array), print the Next visited = set()
# Greater Number for every element. The Next Greater Number of a number x is the first greater number to its dirns = {"u": (-1, 0), "d": (1, 0), "l": (0, -1), "r": (0, 1)}
# traversing-order next in the array, which means you could search circularly to find its next greater number. perps = {"u": ("l", "r"), "d": ("l", "r"), "l": ("u", "d"), "r": ("u", "d")}
# If it doesn't exist, output -1 for this number. queue = [(start[0], start[1], d) for d in dirns]
# Stack holds indices of numbers without greater element, hence decreasing order. Pop of all numbers lower than while queue:
# current and set their next_greater to current. Repeat iteration over nums to account for circularity.
# Time - O(n) new_queue = []
# Space - O(n)
while queue:
class Solution(object):
def nextGreaterElements(self, nums): r, c, dirn = queue.pop()
""" if ((r, c, dirn)) in visited:
:type nums: List[int] continue
:rtype: List[int] visited.add((r, c, dirn))
"""
n = len(nums) dr, dc = dirns[dirn]
stack = [] # indices whose nums form decreasing sequence if 0 <= r + dr < rows and 0 <= c + dc < cols and maze[r + dr][c + dc] == 0:
next_greater = [-1] * n # default -1 if no greater new_queue.append((r + dr, c + dc, dirn))
else:
for i in range(2 * n): if [r, c] == destination:
num = nums[i % n] # wrap around return distance
while stack and num > nums[stack[-1]]: perp = perps[dirn]
next_greater[stack.pop()] = num for new_dirn in perp:
if i < n: queue.append((r, c, new_dirn))
stack.append(i)
distance += 1
return next_greater queue = new_queue
return -1
# python_1_to_1000/504_Base_7.py
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/506_Relative_Ranks.py
# Record if num is negative and convert to positive. Repeatedly divide by 7 and add digit to result. Result is in # https://leetcode.com/problems/relative-ranks/
# reverse order with least significant digit first. Add leading minus sign is negative, reverse list and join. # Given scores of N athletes, find their relative ranks and the people with the top three highest scores, who will be
# Time - O(log n) # awarded medals: "Gold Medal", "Silver Medal" and "Bronze Medal".
# Space - O(log n)
# Create a list of tuples of num and its index in nums. Sort descending by num. Iterate over list, setting result
class Solution(object): # with medals for the first 3 then rank as a string for others.
def convertToBase7(self, num): # Time - O(n log n)
""" # Space - O(n)
:type num: int
:rtype: str class Solution(object):
""" def findRelativeRanks(self, nums):
negative = num < 0 # flag for negative num """
num = abs(num) :type nums: List[int]
base_7 = [] :rtype: List[str]
"""
while num: num_i = [(num, i) for i, num in enumerate(nums)]
num, digit = divmod(num, 7) num_i.sort(reverse=True)
base_7.append(str(digit))
result = [None for _ in range(len(nums))]
if negative: medals = ["Gold", "Silver", "Bronze"]
base_7.append("-")
for rank, (_, i) in enumerate(num_i):
return "".join(base_7[::-1]) or "0" # base_7 is empty if num == 0 if rank < 3: # best ranked 3 get medals
result[i] = medals[rank] + " Medal"
else:
# python_1_to_1000/505_The_Maze_II.py - m result[i] = str(rank + 1) # add 1 since enumeration is from zero
# https://leetcode.com/problems/the-maze-ii/
# There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up, down, # python_1_to_1000/507_Perfect_Number.py
# left or right, but it won't stop rolling until hitting a wall. When the ball stops, it can choose the next direction.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)
def count_sums(node):
if not node: # python_1_to_1000/513_Find_Bottom_Left_Tree_Value.py - m
return 0
_author_ = 'jake'
total_sum = node.val + count_sums(node.left) + count_sums(node.right) _project_ = 'leetcode'
tree_sums[total_sum] += 1
# https://leetcode.com/problems/find-bottom-left-tree-value/
return total_sum # Given a binary tree, find the leftmost value in the last row of the tree.
if not root: # BFS from right to left so final node is left most.
return [] # Time - O(n)
tree_sums = defaultdict(int) # Space - O(n)
count_sums(root)
from collections import deque
max_sum = max(tree_sums.values())
result = [] class Solution(object):
for key, val in tree_sums.items(): def findBottomLeftValue(self, root):
if val == max_sum: """
result.append(key) :type root: TreeNode
return result :rtype: int
"""
queue = deque([root])
# python_1_to_1000/509_Fibonacci_Number.py
while queue:
_author_ = 'jake' node = queue.popleft()
_project_ = 'leetcode' if node.right:
queue.append(node.right)
# https://leetcode.com/problems/fibonacci-number/ if node.left:
# The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such that each number queue.append(node.left)
# is the sum of the two preceding ones, starting from 0 and 1. That is,
# F(0) = 0, F(1) = 1 return node.val
# F(N) = F(N - 1) + F(N - 2), for N > 1.
# Given N, calculate F(N).
# python_1_to_1000/514_Freedom_Trail.py - h
# Iterate N times, storing anf updating the last 2 numbers of the sequence.
char_to_ring = defaultdict(list) # key is char, values is list of indices in ring of that char if s[i] == s[i + length - 1]:
for i, c in enumerate(ring): subsequence.append(2 + subsequence_2[i + 1])
char_to_ring[c].append(i) else:
subsequence.append(max(subsequence_1[i], subsequence_1[i + 1]))
i_to_steps = {0: 0} # key is index in ring, value is to min steps to reach char at that index
for k in key: subsequence_2 = subsequence_1
subsequence_1 = subsequence
new_i_to_steps = {}
new_indices = char_to_ring[k] # indices in ring with next required character of key return subsequence[0]
for new_i in new_indices:
min_steps = float("inf")
for i in i_to_steps: # python_1_to_1000/517_Super_Washing_Machines.py - h
min_steps = min(min_steps, i_to_steps[i] + dist(i, new_i))
new_i_to_steps[new_i] = min_steps _author_ = 'jake'
_project_ = 'leetcode'
i_to_steps = new_i_to_steps
# https://leetcode.com/problems/super-washing-machines/
return min(i_to_steps.values()) + len(key) # add button press step for each char # You have n super washing machines on a line. Initially, each washing machine has some dresses or is empty.
# For each move, you could choose any m (1 ? m ? n) washing machines, and pass one dress of each washing machine to one
# of its adjacent washing machines at the same time .
# Given an integer array representing the number of dresses in each washing machine from left to right on the line,
# python_1_to_1000/515_Find_Largest_Value_in_Each_Tree_Row.py - m # you should find the minimum number of moves to make all the washing machines have the same number of dresses.
# If it is not possible to do it, return -1.
_author_ = 'jake'
_project_ = 'leetcode' # Max of max positive balance on any machine, and max imbalance from any machine to the next (since dresses must flow
# to correct that imbalance).
# https://leetcode.com/problems/find-largest-value-in-each-tree-row/ # Time - O(n)
# You need to find the largest value in each row of a binary tree. # Space - O(1)
# BFS. Queue of all nodes by row. Iterate over queue, updating row max and generating next row. class Solution(object):
# Time - O(n) def findMinMoves(self, machines):
# Space - O(n) """
:type machines: List[int]
class Solution(object): :rtype: int
def largestValues(self, root): """
""" dresses = sum(machines)
:type root: TreeNode if dresses % len(machines) != 0: # early return if not possible
:rtype: List[int] return -1
"""
result = [] target = dresses // len(machines)
if not root: moves, running = 0, 0
return [] machines = [m - target for m in machines]
queue = [root]
for machine in machines:
while queue: running += machine
new_queue = [] # max of the net imbalance for any split point and the positive balance on the current machine
max_val = float("-inf") moves = max(moves, abs(running), machine)
for node in queue:
max_val = max(max_val, node.val) return moves
if node.left:
new_queue.append(node.left)
if node.right: # python_1_to_1000/518_Coin_Change_2.py - m
new_queue.append(node.right)
_author_ = 'jake'
_project_ = 'leetcode'
# For the first and second letter, the only disallowed combination is lower case then upper case. All letter after
# https://leetcode.com/problems/coin-change-2/ # the second character must be the same case as the second character.
# You are given coins of different denominations and a total amount of money. # Time - O(n)
# Write a function to compute the number of combinations that make up that amount. # Space - O(1)
# You may assume that you have infinite number of each kind of coin.
class Solution(object):
# Dynamic programming. List stores the number of ways to make each amount. Use each coin in turn. def detectCapitalUse(self, word):
# For each amount >= the coin value, increment the number of ways to make that amount with the number of ways to """
# make the amount - coin value. :type word: str
# Time - O(mn) where m is the amount and n nis the number of coins :rtype: bool
# Space - O(m) """
if len(word) <= 1: # empty string or single letter
class Solution(object): return True
def change(self, amount, coins):
""" first = word[0] <= "Z"
:type amount: int second = word[1] <= "Z"
:type coins: List[int] if not first and second: # first is not capital but second is
:rtype: int return False
"""
dp = [0 for _ in range(amount + 1)] # dp[i] nb ways to make i using no coins for c in word[2:]:
dp[0] = 1 # one way to make amount of zero if (c <= "Z") != second:
return False
for coin in coins:
return True
for i in range(coin, amount + 1):
dp[i] += dp[i - coin]
# python_1_to_1000/521_Longest_Uncommon_Subsequence_I.py - m
return dp[-1]
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/519_Random_Flip_Matrix.py - m
# https://leetcode.com/problems/longest-uncommon-subsequence-i/
_author_ = 'jake' # Given a group of two strings, you need to find the longest uncommon subsequence of this group of two strings.
_project_ = 'leetcode' # The longest uncommon subsequence is defined as the longest subsequence of one of these strings and this subsequence
# should not be any subsequence of the other strings.
# https://leetcode.com/problems/random-flip-matrix/ # A subsequence is a sequence that can be derived from one sequence by deleting some characters without changing the
# You are given the number of rows n_rows and number of columns n_cols of a 2D binary matrix where all values are # order of the remaining elements. Trivially, any string is a subsequence of itself and an empty string is a
# initially 0. Write a function flip which chooses a 0 value uniformly at random, changes it to 1, # subsequence of any string.
# and then returns the position [row.id, col.id] of that value. # The input will be two strings, and the output needs to be the length of the longest uncommon subsequence.
# Also, write a function reset which sets all values back to 0. # If the longest uncommon subsequence doesn't exist, return -1.
# Try to minimize the number of calls to system's Math.random() and optimize the time and space complexity.
# If the strings are identical then there is no uncommon subsequence. Else the longer string cannot be a subsequence of
# Reduce 2D matrix to a 1D list of length rows * cols. For every random choice, increment the start index in the list # the shorter. If strings are same length but not identical they are uncommon subsequences of each other.
# and map the used number to an unused number that is now outside the [start, end] range. If random choice has been # Time - O(m + n)
# used already, get its mapping instead. # Space - O(1)
# If x has been chosen before use it
# Time - O(1) class Solution(object):
# Space - O(k) number of calls to flip() def findLUSlength(self, a, b):
"""
import random :type a: str
:type b: str
class Solution(object): :rtype: int
"""
def __init__(self, n_rows, n_cols): if a == b:
""" return -1
:type n_rows: int return max(len(a), len(b))
:type n_cols: int
"""
self.start, self.end = 0, n_rows * n_cols - 1
self.used_to_free = {} # map chosen random ints to an unchosen ints outside [start, end] # python_1_to_1000/522_Longest_Uncommon_Subsequence_II.py - m
self.cols = n_cols
_author_ = 'jake'
def flip(self): _project_ = 'leetcode'
"""
:rtype: List[int] # https://leetcode.com/problems/longest-uncommon-subsequence-ii/
""" # Given a list of strings, you need to find the longest uncommon subsequence among them. The longest uncommon
x = random.randint(self.start, self.end) # subsequence is defined as the longest subsequence of one of these strings and this subsequence should not be any
index = self.used_to_free.get(x, x) # returned index is x if not used, else mapping of x # subsequence of the other strings.
self.used_to_free[x] = self.used_to_free.get(self.start, self.start) # map x to start or mapping of start # A subsequence is a sequence that can be derived from one sequence by deleting some characters without changing the
self.start += 1 # order of the remaining elements. Trivially, any string is a subsequence of itself and an empty string is a
return list(divmod(index, self.cols)) # convert index to 2d coordinates # subsequence of any string.
# The input will be a list of strings, and the output needs to be the length of the longest uncommon subsequence.
def reset(self): # If the longest uncommon subsequence doesn't exist, return -1.
"""
:rtype: void # COunrt freq of each string. Sort list of keys by decreasing length. If key is not unique, add to seen set. Else if
""" # not a subsequence of any string already seen, return its length.
self.start = 0 # Time - O(s * n**2) where s is max length of string and n is number of strings
self.used_to_free = {} # Space - O(sn)
j += 1
if i == len(s): for word in d:
return True if is_subsequence(word, s):
return False return word
for i, n in enumerate(nums):
prefix_sum += n # python_1_to_1000/526_Beautiful_Arrangement.py - m
if k != 0: # if k == 0 then look for prefix sum difference of zero
prefix_sum = prefix_sum % k _author_ = 'jake'
_project_ = 'leetcode'
if prefix_sum in prefix_sums:
if i - prefix_sums[prefix_sum] > 1: # check length >= 2 # https://leetcode.com/problems/beautiful-arrangement/
return True # Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these
else: # N numbers successfully if one of the following is true for the ith position (1 <= i <= N) in this array:
prefix_sums[prefix_sum] = i # do not overwrite if key present already # The number at the ith position is divisible by i.
# i is divisible by the number at the ith position.
return False # Given N, how many beautiful arrangements can you construct?
# For each position from final index working forwards, insert all valid numbers and recurse. Backwards ensures less
# python_1_to_1000/524_Longest_Word_in_Dictionary_through_Deleting.py - m # branching resulting in failures.
# Time - O(n!)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/ def countArrangement(self, N):
# Given a string and a string dictionary, find the longest string in the dictionary that can be formed by deleting """
# some characters of the given string. If there are more than one possible results, return the longest word with the :type N: int
# smallest lexicographical order. If there is no possible result, return the empty string. :rtype: int
"""
# Sort by length then by lexicogrphic order. For each string from longest, test if is a subsequence of s. used = [False for _ in range(N + 1)]
# Time - O(mn + knlogn) where knlogn is time taken to sort for n strings and s is of length m self.count = 0
# Space - O(1)
def helper(i): # i is position to be filled
class Solution(object): if i == 0: # solution found
def findLongestWord(self, s, d): self.count += 1
""" return
:type s: str
:type d: List[str] for num in range(1, N + 1):
:rtype: str if not used[num] and (num % i == 0 or i % num == 0):
""" used[num] = True
helper(i - 1)
def is_subsequence(s, t): # return True if s is a subsequence of t used[num] = False
i, j = 0, 0
while i < len(s) and (len(t) - j) >= (len(s) - i): # nb chars remaining in t >= nb chars remaining in s helper(N)
if s[i] == t[j]: return self.count
i += 1
j += 1
if i == len(s): # python_1_to_1000/527_Word_Abbreviation.py - h
return True
return False _author_ = 'jake'
_project_ = 'leetcode'
d.sort(key=lambda x: (-len(x), x)) # primary and secondary keys
# https://leetcode.com/problems/word-abbreviation/ # python_1_to_1000/529_Minesweeper.py - m
# Given an array of n distinct non-empty strings, you need to generate minimal possible abbreviations for every word
# following rules below. _author_ = 'jake'
# Begin with the first character and then the number of characters abbreviated, which followed by the last character. _project_ = 'leetcode'
# If there are any conflict, that is more than one words share the same abbreviation, a longer prefix is used instead
# of only the first character until making the map from word to abbreviation become unique. In other words, a final # https://leetcode.com/problems/minesweeper/
# abbreviation cannot map to more than one original words. # Let's play the minesweeper game (Wikipedia, online game)!
# If the abbreviation doesn't make the word shorter, then keep it as original. # You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an
# unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and
# Create abbreviation for each word ignoring conflicts. Group words by abbreviation. If single word in group, retain # all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and
# abbreviation. Else recurse on group, creating new groups by next char until group lengths are 1 (which will always # finally 'X' represents a revealed mine.
# happen since words are unique). # Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the
# Time - O(nk) for n words of max length k # board after revealing this position according to the following rules:
# Space - O(nk) # If a mine ('M') is revealed, then the game is over - change it to 'X'.
# If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its
from collections import defaultdict # adjacent unrevealed squares should be revealed recursively.
# If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8')
class Solution(object): # representing the number of adjacent mines.
def wordsAbbreviation(self, dictionary): # Return the board when no more squares will be revealed.
"""
:type dict: List[str] # BFS. If mine, update and return. If blank count adjacent mines. If zero then recurse, else return count.
:rtype: List[str] # Time - O(mn)
""" # Space - O(mn)
if not node:
return pairs += 1
col_counts = [0 for _ in range(cols)] # black pixels per column col_counts = [0 for _ in range(cols)] # black pixels per column
row_pixels = [[] for _ in range(rows)] # black pixels indices by row row_strings = defaultdict(int) # string representation of row mapped to its frequency
return pixels
# python_1_to_1000/532_K-diff_Pairs_in_an_Array.py - m
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/538_Convert_BST_to_Greater_Tree.py - m
def next_num(): # returns a TreeNode containing the integer at the prefix of s, also increments self.i inorder(node.left)
num, neg = 0, False
if s[self.i] == "-": inorder(root)
neg = True return root
self.i += 1
while self.i < len(s) and s[self.i] not in {"(", ")"}:
num = num * 10 + int(s[self.i]) # python_1_to_1000/539_Minimum_Time_Difference.py - m
self.i += 1
return TreeNode(-num) if neg else TreeNode(num) _author_ = 'jake'
_project_ = 'leetcode'
def helper():
if self.i >= len(s): # https://leetcode.com/problems/minimum-time-difference/
return None # Given a list of 24-hour clock time points in "Hour:Minutes" format, find the minimum minutes difference between any
root = next_num() # two time points in the list.
if self.i < len(s) and s[self.i] == "(":
self.i += 1 # opening bracket # Convert times to minutes, append first time + 24hrs so neighboring pairs list all differences are listed and find min
root.left = helper() # Time - O(n log n)
self.i += 1 # closing bracket # Space - O(n)
if self.i < len(s) and s[self.i] == "(":
self.i += 1 # opening bracket class Solution(object):
root.right = helper() def findMinDifference(self, timePoints):
self.i += 1 # closing bracket """
:type timePoints: List[str]
return root :rtype: int
"""
return helper() minutes = []
for time in timePoints:
hrs, mins = time.split(":")
minutes.append(int(hrs) * 60 + int(mins))
# python_1_to_1000/537_Complex_Number_Multiplication.py - m
minutes.sort()
_author_ = 'jake' minutes.append(minutes[0] + 24 * 60) # len(minutes) guaranteed to be >= 2
_project_ = 'leetcode'
min_diff = 24 * 60
# https://leetcode.com/problems/complex-number-multiplication/ for i in range(1, len(minutes)):
# Given two strings representing two complex numbers. min_diff = min(min_diff, minutes[i] - minutes[i - 1])
# You need to return a string representing their multiplication. Note i2 = -1 according to the definition.
return min_diff
# Split by "+" into real and imaginary.
# Time - O(max(m, n))
# Space - O(max(m , n)) # python_1_to_1000/540_Single_Element_in_a_Sorted_Array.py - m
for r in range(rows):
for c in range(cols):
# python_1_to_1000/541_Reverse_String_II.py if matrix[r][c] == 1:
unknown.add((r, c))
_author_ = 'jake'
_project_ = 'leetcode' while unknown:
new_unknown = set()
# https://leetcode.com/problems/reverse-string-ii/ for r, c in unknown:
# Given a string and an integer k, you need to reverse the first k characters for every 2k characters counting from for dr, dc in deltas:
# the start of the string. If there are less than k characters left, reverse all of them. If there are less than 2k if 0 <= r + dr < rows and 0 <= c + dc < cols and (r + dr, c + dc) not in unknown:
# but greater than or equal to k characters, then reverse the first k characters and left the other as original. matrix[r][c] = matrix[r + dr][c + dc] + 1
break
# Iterate over s in steps of k. else: # no known neighbours
# Time - O(n) new_unknown.add((r, c))
# Space - O(n)
unknown = new_unknown
class Solution(object):
def reverseStr(self, s, k): return matrix
"""
:type s: str
:type k: int # python_1_to_1000/543_Diameter_of_Binary_Tree.py
:rtype: str
""" _author_ = 'jake'
reverse = True _project_ = 'leetcode'
result = []
# https://leetcode.com/problems/diameter-of-binary-tree/
for i in range(0, len(s), k): # Given a binary tree, you need to compute the length of the diameter of the tree.
block = s[i:i + k] # The diameter of a binary tree is the length of the longest path between any two nodes in a tree.
if reverse: # This path may or may not pass through the root.
result.append(block[::-1])
else: # Bottom up recursion.
result.append(block) # The longest path passing with a node as root is the longest downwards left path + longest downwards right path.
reverse = not reverse # If there is no child on right or left then the longest path on that side is zero.
# Else longest path is 1 + longest of left and right paths down from child.
return "".join(result) # Time - O(n)
# Space - O(1)
def helper(left, right, same): # same is number of boxes to right of boxes[right] that are same colour
# python_1_to_1000/545_Boundary_of_Binary_Tree.py - m
if left > right:
_author_ = 'jake' return 0
_project_ = 'leetcode'
if (left, right, same) in memo:
# https://leetcode.com/problems/boundary-of-binary-tree/ return memo[(left, right, same)]
# Given a binary tree, return the values of its boundary in anti-clockwise direction starting from root. Boundary
# includes left boundary, leaves, and right boundary in order without duplicate nodes. # extend same to left of boxes[right] as far as possible
# Left boundary is defined as the path from root to the left-most node. Right boundary is defined as the path from while right > left and boxes[right] == boxes[right - 1]:
# root to the right-most node. If the root doesn't have left subtree or right subtree, then the root itself is left right -= 1
# boundary or right boundary. Note this definition only applies to the input binary tree, and not applies to any same += 1
subtrees.
# The left-most node is defined as a leaf node you could reach when you always firstly travel to the left subtree result = helper(left, right - 1, 0) + (same + 1) ** 2 # remove boxes[right] and same
# if exists. If not, travel to the right subtree. Repeat until you reach a leaf node.
# The right-most node is also defined by the same way with left and right exchanged. for i in range(left, right): # if anx box i from left to right-1 is same as same then
# remove boxes between i and right, then remove left to i with extended same
# Find left edge until leaf. Inorder traversal to append all leaves. Find right edge and reverse. if boxes[i] == boxes[right]:
# Time - O(n) result = max(result, helper(i + 1, right - 1, 0) + helper(left, i, same + 1))
# Space - O(n)
memo[(left, right, same)] = result
class Solution(object): return result
def boundaryOfBinaryTree(self, root):
""" memo = {}
:type root: TreeNode return helper(0, len(boxes) - 1, 0)
:rtype: List[int]
"""
# python_1_to_1000/547_Friend_Circles.py - m
def left_side(node):
if not node or (not node.left and not node.right): _author_ = 'jake'
return _project_ = 'leetcode'
boundary.append(node.val)
if node.left: # https://leetcode.com/problems/friend-circles/
left_side(node.left) # There are N students in a class. Some of them are friends, while some are not.
else: # Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C,
left_side(node.right) # then A is an indirect friend of C.
# We define a friend circle is a group of students who are direct or indirect friends.
def right_side(node): # Given a N*N matrix M representing the friend relationship between students in the class, if M[i][j] = 1, then the
if not node or (not node.left and not node.right): # ith and jth students are direct friends with each other, otherwise not.
return # You have to output the total number of friend circles among all the students.
right_edge.append(node.val)
if node.right: # Union find structure. Initially each friend is in their own group. Iterate over the matrix, only using the lower
right_side(node.right) # triangle because of the symmetry. For each friend relationship, union the groups by setting the group exemplar (an
else: # arbitrary member of the gorup) of one friend to the group exemplar of the other.
right_side(node.left) # Result is the final number of unique group exemplars.
# Alternatively, dfs for each friend marking already explored friends.
def inorder(node): # Time - O(n**2 log* n)
if not node: # Space - O(n)
return
inorder(node.left) class Solution(object):
if not node.left and not node.right: def findCircleNum(self, M):
boundary.append(node.val) """
inorder(node.right) :type M: List[List[int]]
:rtype: int
if not root: """
return [] n = len(M)
group = [i for i in range(n)] # map from firend index to group exemplar
boundary, right_edge = [root.val], []
def get_group(x): # get the group exemplar for x
# ignore root while group[x] != x:
left_side(root.left) group[x] = group[group[x]] # collapse parent to grandparent
inorder(root.left) x = group[x]
inorder(root.right) return x
right_side(root.right)
for i in range(1, n):
if node.right:
# python_1_to_1000/548_Split_Array_with_Equal_Sum.py - h if node.right.val == node.val + 1:
incr = max(incr, 1 + r_i) # update best increasing
_author_ = 'jake' elif node.right.val == node.val - 1:
_project_ = 'leetcode' decr = max(decr, 1 + r_d) # update best decreasing
# For each possible middle index j, try all possible values of first index i and is this creates 2 equal subarrays then
# then add their sum to the candidates set. Then with the same value fo j, try all possible values of k. If the RHS # python_1_to_1000/551_Student_Attendance_Record_I.py
# subarrays have the same sum and that sum is in candidates the return True.
# Time - O(n**2) _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'
cumul = [nums[0]] # array of cumulative sums for easy lookup of subarray sums # Find the count of 'A' and whether 'LLL' appears in s.
for num in nums[1:]: # Time - O(n)
cumul.append(num + cumul[-1]) # Space - O(1)
# Moving from right to left, find the first pair where n[left] < n[right]. Then moving right again, find the smallest
# python_1_to_1000/554_Brick_Wall.py - m # digit that is more than n[left] and swap. Put all digits to the right of n[left] in increasing order.
# Time - O(log n), number of digits in n
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/brick-wall/ def nextGreaterElement(self, n):
# There is a brick wall in front of you. The wall is rectangular and has several rows of bricks. The bricks have the """
# same height but different width. You want to draw a vertical line from the top to the bottom and cross the least :type n: int
# bricks. :rtype: int
# The brick wall is represented by a list of rows. Each row is a list of integers representing the width of each """
# brick in this row from left to right. num = [c for c in str(n)] # convert to list of chars
# If your line go through the edge of a brick, then the brick is not considered as crossed.
# You need to find out how to draw the line to cross the least bricks and return the number of crossed bricks. i = len(num) - 1 # find num[i-1] < num[i], so swapping increases value
# You cannot draw a line just along one of the two vertical edges of the wall. while i > 0 and num[i - 1] >= num[i]:
i -= 1
# Count number of bricks in wall with right edges at every position. Choose the position with the most edges.
# Time - O(n), number of bricks if i == 0: # no increase possible
# Space - O(n) return -1
from collections import defaultdict j = i # find lowest nums[j] that is > nums[i-1]
while j + 1 < len(num) and num[j + 1] > num[i - 1]:
class Solution(object): j += 1
def leastBricks(self, wall):
""" num[j], num[i - 1] = num[i - 1], num[j] # swap i-1 and j
:type wall: List[List[int]]
:rtype: int result = int("".join(num[:i] + sorted(num[i:]))) # sort after i
""" # 2**31 - 1 is the largest signed 32 bit number
edges = defaultdict(int) # mapping from x-position of an edge to count of number of edges return -1 if result >= 2 ** 31 else result
return 0
# python_1_to_1000/557_Reverse_Words_in_a_String_III.py if not root.children: # required to avoid taking max of empty sequence
return 1
_author_ = 'jake'
_project_ = 'leetcode' return 1 + max(self.maxDepth(child) for child in root.children)
# https://leetcode.com/problems/reverse-words-in-a-string-iii/
# Given a string, you need to reverse the order of characters in each word within a sentence while still preserving # python_1_to_1000/560_Subarray_Sum_Equals_K.py - m
# whitespace and initial word order.
_author_ = 'jake'
# Split string by space into a list of words. Reverse each word. Join reversed words by spaces. _project_ = 'leetcode'
# Time - O(n)
# Space - O(n) # https://leetcode.com/problems/subarray-sum-equals-k/
# Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose
class Solution(object): # sum equals to k.
def reverseWords(self, s):
""" # Store counts of prefix sums in dictionary. Iterate over array, updating running_sum and incrementing result if
:type s: str # running_sum == k. Lookup prefix value that makes a subararry of sum k.
:rtype: str # Time - O(n)
""" # Space - O(n)
return " ".join([w[::-1] for w in s.split(" ")])
from collections import defaultdict
# Information required but not in problem description: the val attribute for a non-leaf node is False. if running_sum == k:
# Combine two leaves according the logical OR of their values. If one node is a leaf then return it if is True, else total += 1
# return the other node. If neither are leaves, intersect each of the 4 subtree children and return a leaf if they are if running_sum - k in sums:
# all leaves with the same value, or else return a non-leaf with value of False. total += sums[running_sum - k]
# Time - O(n)
# Space - O(n) sums[running_sum] += 1
topLeft = self.intersect(quadTree1.topLeft, quadTree2.topLeft) # Sort nums. The smallest num must be paired with some other num that will not form part of the sum. In order to
topRight = self.intersect(quadTree1.topRight, quadTree2.topRight) # maximise the sum, the smallest number should be paired with the next smallest. Pair each number with the next larger
bottomLeft = self.intersect(quadTree1.bottomLeft, quadTree2.bottomLeft) # number, hence numbers of even indices form the resulting sum.
bottomRight = self.intersect(quadTree1.bottomRight, quadTree2.bottomRight) # Time - O(n log n)
# Space - O(n) for the sorted list
children = [topLeft, topRight, bottomLeft, bottomRight]
values = [child.val for child in children] class Solution(object):
leaves = [child.isLeaf for child in children] def arrayPairSum(self, nums):
"""
if all(leaves) and (sum(values) == 0 or sum(values) == 4): :type nums: List[int]
return Node(topLeft.val, True, None, None, None, None) :rtype: int
"""
# non-leaf must have False val return sum(sorted(nums)[::2]) # iterate with step of 2 to select even indices
return Node(False, False, topLeft, topRight, bottomLeft, bottomRight)
# python_1_to_1000/562_Longest_Line_of_Consecutive_One_in_Matrix.py - m
# python_1_to_1000/559_Maximum_Depth_of_N-ary_Tree.py
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/longest-line-of-consecutive-one-in-matrix/
# https://leetcode.com/problems/maximum-depth-of-n-ary-tree/ # Given a 01 matrix M, find the longest line of consecutive one in the matrix.
# Given a n-ary tree, find its maximum depth. # The line could be horizontal, vertical, diagonal or anti-diagonal.
# The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
# Dynamic programming. Iterate over matrix, if cell == 1 update longest line in each of 4 directions based on
# Recursive function. Base cases of no node or leaf node. Else add 1 to the max depth of any child. # longest lines to cells on left and in previous row.
# Time - O(n) # Time - O(mn)
# Space - O(n) # Space - O(n), number of columns
if M[r][c] == 0: # cannot extend any lines mid = len(n) // 2 # middle index if odd length, or first of RHS if even
row_dp.append([0 for _ in range(4)]) left = n[:mid]
continue
if len(n) % 2 == 1:
row_dp.append([1 for _ in range(4)]) # default line length of this cell centre_count = 1 # odd, so single middle index
centre = n[mid]
if c != 0: right = left[::-1]
row_dp[-1][0] += row_dp[-2][0] # horizontal else:
row_dp[-1][1] += previous_dp[c][1] # vertical centre_count = 2 # even, so pair of middle indices
if c != 0: # descending diagonal centre = left[-1]
row_dp[-1][2] += previous_dp[c - 1][2] left = left[:-1]
if c != cols - 1: # ascending diagonal right = left[::-1]
row_dp[-1][3] += previous_dp[c + 1][3]
candidates.add(int(left + centre * centre_count + right))
max_len = max(max_len, max(row_dp[-1])) if centre != "9":
new_centre = str(int(centre) + 1)
previous_dp = row_dp candidates.add(int(left + new_centre * centre_count + right))
if centre != "0":
return max_len new_centre = str(int(centre) - 1)
candidates.add(int(left + new_centre * centre_count + right))
n_int = int(n)
# python_1_to_1000/563_Binary_Tree_Tilt.py candidates.discard(n_int)
candidates = list(candidates)
_author_ = 'jake' candidates.sort(key=lambda x: (abs(x - n_int), x)) # sort by (abs difference from n, value)
_project_ = 'leetcode' return str(candidates[0])
# https://leetcode.com/problems/binary-tree-tilt/
# Given a binary tree, return the tilt of the whole tree. # python_1_to_1000/565_Array_Nesting.py - m
# The tilt of a tree node is defined as the absolute difference between the sum of all left subtree node values and
# the sum of all right subtree node values. Null node has tilt 0. _author_ = 'jake'
# The tilt of the whole tree is defined as the sum of all nodes' tilt. _project_ = 'leetcode'
# Recursive helper function returns the sum of the values in a tree. Tilt is the absolute difference between the # https://leetcode.com/problems/array-nesting/
# left and right subtree sums. # A zero-indexed array A of length N contains all integers from 0 to N-1. Find and return the longest length of set S,
# Time - O(n) # where S[i] = {A[i], A[A[i]], A[A[A[i]]], ... } subjected to the rule below.
# Space - O(1) # Suppose the first element in S starts with the selection of element A[i] of index = i, the next element in S should
# be A[A[i]], and then A[A[A[i]]]… By that analogy, we stop adding right before a duplicate element occurs in S.
class Solution(object):
def findTilt(self, root): # Each set forms an independent cycle of nums. For each num, follow the cycle until a num repeats. Update the longest
""" # and add all nus in the cycle to the seen set. Iterate over nums finding the cycle for each num, ignoring any num
:type root: TreeNode # already known to be part of a cycle.
:rtype: int # Time - O(n)
""" # Space - O(n)
self.tilt = 0 # instance variable collects sum
class Solution(object):
def helper(node): def arrayNesting(self, nums):
"""
if not node: # base case :type nums: List[int]
return 0 :rtype: int
"""
left, right = helper(node.left), helper(node.right) visited = set() # nums visited
self.tilt += abs(left - right) # update total tilt longest = 0 # biggest set
return node.val + left + right # return sum of all values in tree
for i, num in enumerate(nums):
helper(root)
return self.tilt if num in visited:
continue
if len(reshaped[-1]) == c: # end of column, start new column for week in range(weeks - 1, -1, -1):
reshaped.append([]) this_week_max_days = [0 for _ in range(cities)]
reshaped[-1].append(nums[i][j])
for start in range(cities):
return reshaped max_vacation = days[start][week] + prev_week_max_days[start] # stay in same city
class Solution(object): if r == 0:
def minDistance(self, height, width, tree, squirrel, nuts): paths += dp[r][c]
""" if r == m - 1:
:type height: int paths += dp[r][c]
:type width: int if c == 0:
:type tree: List[int] paths += dp[r][c]
:type squirrel: List[int] if c == n - 1:
:type nuts: List[List[int]] paths += dp[r][c]
:rtype: int paths %= 10 ** 9 + 7
"""
if not nuts: for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
return 0 if 0 <= r + dr < m and 0 <= c + dc < n:
new_dp[r + dr][c + dc] += dp[r][c]
nuts_to_tree = 0 # sum of all distances from nut to tree new_dp[r][c] %= 10 ** 9 + 7
best_gain = height * width # best change in total distance
dp = new_dp
def distance(a, b):
return abs(a[0] - b[0]) + abs(a[1] - b[1]) return paths
# Sisted get len(candies) // 2 candies. If there are this number or more of different candies, then sister can have memo[(r, c, steps)] = paths
# all different candies. If there are fewer different kinds, then sister can have one of each kind. return paths
# Time - O(n)
# Space - O(1) memo = {}
return helper(i, j, N)
class Solution(object):
def distributeCandies(self, candies):
"""
:type candies: List[int]
:rtype: int
""" # python_1_to_1000/581_Shortest_Unsorted_Continuous_Subarray.py - m
return min(len(candies) // 2, len(set(candies)))
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/576_Out_of_Boundary_Paths.py - m
# https://leetcode.com/problems/shortest-unsorted-continuous-subarray/
_author_ = 'jake' # Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending
_project_ = 'leetcode' # order, then the whole array will be sorted in ascending order, too.
# You need to find the shortest such subarray and output its length.
# https://leetcode.com/problems/out-of-boundary-paths/
# There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you can move the ball to adjacent # Iterate over nums from left to right. If any num is less than the previous then the previous must require sorting.
# cell or cross the grid boundary in four directions (up, down, left, right). However, you can at most move N times. # Any number before the previous that is more than the minimum after the previous also requires sorting.
# Find out the number of paths to move the ball out of grid boundary. The answer may be very large, # Follow a similar procedure from right to left finding the first increase and subsequent maximum.
# return it after mod 10^9 + 7. # Alternatively, compare a sorted copy of the list to the original list and find the first and last mismatches.
# Time - O(n)
# Dynamic programming. For each time step, calculate the nb paths to reach each cell. Running total of paths to reach # Space - O(1)
# boundary is increased at each step by number of previous paths to cells next to edge. Update paths at next step
# according to sum of all paths to neighbour cell from previous step. class Solution(object):
# Alternatively, recursion requires more space but is practically faster. def findUnsortedSubarray(self, nums):
# Time - O(m * n * N) """
# Space - O(m * n) :type nums: List[int]
:rtype: int
class Solution(object): """
def findPaths(self, m, n, N, i, j): n = len(nums)
""" right, left = -1, -1 # default values
:type m: int
:type n: int for i in range(1, n):
:type N: int if left == - 1 and nums[i] < nums[i - 1]:
:type i: int left = i - 1 # first index to be sorted
:type j: int min_num = nums[i]
:rtype: int elif left != -1: # update subsequent minimum
""" min_num = min(min_num, nums[i])
# https://leetcode.com/problems/erect-the-fence/
# python_1_to_1000/582_Kill_Process.py - m # There are some trees, where each tree is represented by (x,y) coordinate in a two-dimensional garden. Your job is to
# fence the entire garden using the minimum length of rope as it is expensive. The garden is well fenced only if all
_author_ = 'jake' # the trees are enclosed. Your task is to help find the coordinates of trees which are exactly located on the fence
_project_ = 'leetcode' # perimeter.
# https://leetcode.com/problems/kill-process/ # Find the lowest point (most -ve y coordinate), breaking ties by most negative x-coordinate. Create a convex hull
# Given n processes, each process has a unique PID (process id) and its PPID (parent process id). # starting from this point. Sort other points by gradient, breaking ties with highest y coordinate then lowest x
# Each process only has one parent process, but may have one or more children processes. This is just like a # coordinate. For each point in sorted order (anti-clockwise around the hull), while the cross-product of this point
# tree structure. Only one process has PPID that is 0, which means this process has no parent process. # and the last 2 points on the hull is negative, the 3 points turn clockwise so remove the last point from the hull.
# All the PIDs will be distinct positive integers. # Time - O(n log n)
# We use two list of integers to represent a list of processes, where the first list contains PID for each process # Space - O(n)
# and the second list contains the corresponding PPID.
# Now given the two lists, and a PID representing a process you want to kill, return a list of PIDs of processes that # Definition for a point.
# will be killed in the end. You should assume that when a process is killed, all its children processes will be killed. class Point(object):
# No order is required for the final answer. def __init__(self, a=0, b=0):
self.x = a
# Create a dictionary mapping processes to their children. DFS. Keep processes to be killed in a list. Pop process off self.y = b
# list and add children.
# Time - O(n) class Solution(object):
# Space - O(n) def outerTrees(self, points):
"""
from collections import defaultdict :type points: List[Point]
:rtype: List[Point]
class Solution(object): """
def killProcess(self, pid, ppid, kill): if len(points) < 3:
""" return points
:type pid: List[int]
:type ppid: List[int] def slope(a, b): # of line from a to b
:type kill: int if a.x == b.x:
:rtype: List[int] return float("inf")
""" return (b.y - a.y) / float(b.x - a.x)
node_to_children = defaultdict(list)
def cross_product(p):
for node, parent in zip(pid, ppid): v1 = [result[-1].x - result[-2].x, result[-1].y - result[-2].y]
node_to_children[parent].append(node) v2 = [p.x - result[-2].x, p.y - result[-2].y]
return v1[0] * v2[1] - v1[1] * v2[0]
killed, to_kill = [], [kill]
# find point with lowest x value, then lowest y value
while to_kill: start_point = min(points, key=lambda p: (p.x, p.y))
process = to_kill.pop() points.remove(start_point)
killed.append(process)
to_kill += node_to_children[process] # sort by slope, then closest (largest) y, then closest (smallest) x
points.sort(key=lambda p: (slope(start_point, p), -p.y, p.x))
return killed
result = [start_point, points[0]]
# Retain the longest common subsequence of both words, after deleting all other characters. LCS is found by dynamic
# programming. If the final chars of a word are the same, LCS is 1 + the LCS of the words without their final chars. # python_1_to_1000/588_Design_In-Memory_File_System.py - h
# Else take the longest LCS after ignoring the final char from one word.
# Time - O(m * n) _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'
return result
class FileSystem(object):
def __init__(self):
self.root = Folder() # empty root folder # python_1_to_1000/590_N-ary_Tree_Postorder_Traversal.py
self.files = {} # map from file name to content
_author_ = 'jake'
def ls(self, path): _project_ = 'leetcode'
"""
:type path: str # https://leetcode.com/problems/n-ary-tree-postorder-traversal/
:rtype: List[str] # Given an n-ary tree, return the postorder traversal of its nodes' values.
"""
path = path.split("/") # Visit the nodes in reverse postorder and reverse the result i.e. visit a node, then the children in reverse order.
if path[-1] in self.files: # Stack contains nodes discovered and to be visited.
return [path[-1]] # list of single file # While stack, pop off a node and visit it. Add children to stack in given order, so they are visited in reverse order.
# Time - O(n)
folder = self.root # Space - O(n)
if path[-1] != "": # path of "/" is split to ["", ""]
for folder_string in path[1:]: class Solution(object):
folder = folder.children[folder_string] def postorder(self, root):
return sorted(list(folder.children.keys())) # sorted returns the list """
:type root: Node
def mkdir(self, path): :rtype: List[int]
""" """
:type path: str if not root:
:rtype: void return []
"""
folder = self.root stack = [root]
for folder_string in path.split("/")[1:]: # ignore first empty string result = []
if folder_string not in folder.children: # make new folder
folder.children[folder_string] = Folder() while stack:
folder = folder.children[folder_string]
node = stack.pop()
def addContentToFile(self, filePath, content): result.append(node.val)
"""
:type filePath: str for child in node.children:
:type content: str stack.append(child)
:rtype: void
""" return result[::-1]
path = filePath.split("/")
file_name = path[-1]
# python_1_to_1000/591_Tag_Validator.py - h
if file_name in self.files:
self.files[file_name] += content _author_ = 'jake'
_project_ = 'leetcode'
else:
self.files[file_name] = content # https://leetcode.com/problems/tag-validator/
folder = self.root # Given a string representing a code snippet, you need to implement a tag validator to parse the code and return
for folder_string in path[1:-1]: # whether it is valid. A code snippet is valid if all the following rules hold:
folder = folder.children[folder_string]
folder.children[file_name] = None # 1) The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
# 2) A closed tag (not necessarily valid) has exactly the following format : <TAG_NAME>TAG_CONTENT</TAG_NAME>.
def readContentFromFile(self, filePath): # Among them, <TAG_NAME> is the start tag, and </TAG_NAME> is the end tag. The TAG_NAME in start and end tags should
""" # be the same. A closed tag is valid if and only if the TAG_NAME and TAG_CONTENT are valid.
:type filePath: str # 3) A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME
:rtype: str # is invalid.
""" # 4) A valid TAG_CONTENT may contain other valid closed tags, cdata and any characters (see note1) EXCEPT
file_name = filePath.split("/")[-1] # unmatched <, unmatched start and end tag, and unmatched or closed tags with invalid TAG_NAME.
return self.files[file_name] # Otherwise, the TAG_CONTENT is invalid.
# 5) A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice versa. However, you also need to
# consider the issue of unbalanced when tags are nested.
# python_1_to_1000/589_N-ary_Tree_Preorder_Traversal.py # 6) A < is unmatched if you cannot find a subsequent >. And when you find a < or </, all the subsequent characters
# until the next > should be parsed as TAG_NAME (not necessarily valid).
_author_ = 'jake' # 7) The cdata has the following format : <![CDATA[CDATA_CONTENT]]>. The range of CDATA_CONTENT is defined as the
_project_ = 'leetcode' # characters between <![CDATA[ and the first subsequent ]]>.
# 8) CDATA_CONTENT may contain any characters. The function of cdata is to forbid the validator to parse CDATA_CONTENT,
# https://leetcode.com/problems/n-ary-tree-preorder-traversal/ # so even it has some characters that can be parsed as tag (no matter valid or invalid), you should treat it as
# Given an n-ary tree, return the preorder traversal of its nodes' values. # regular characters.
# Stack contains nodes discovered and to be visited. Pop a node off the stack and append its value to the result. # Iterate over input. status variable tracks whether we are in an opening or closing tag, or in cdata or in text.
# Add child nodes to stack in reverse order, so they are popped off in the original order. # Stack stores open tags.
# Time - O(n) # Time - O(n)
# Space - O(n) # Space - O(n)
# python_1_to_1000/594_Longest_Harmonious_Subsequence.py
return max_r * max_c for bit in range(1, len(binary)): # iterate over prefixes from least significant bit
# can append zero to all shorter valid numbers ending in zero or one
# python_1_to_1000/599_Minimum_Index_Sum_of_Two_Lists.py zero_highest.append(zero_highest[-1] + one_highest[-1])
# can only append one to all shorter valid numbers ending in zero
_author_ = 'jake' one_highest.append(zero_highest[-2])
_project_ = 'leetcode'
if binary[bit] == "1" and binary[bit - 1] == "1":
# https://leetcode.com/problems/minimum-index-sum-of-two-lists/ # prefix ends in "11" so all integers of same length or shorter
# Suppose Andy and Doris want to choose a restaurant for dinner, and they both have a list of favorite restaurants # without consecutive set bits are less than prefix regardless of ending in 0 or 1.
# represented by strings. # reset count to all valid integers
# You need to help them find out their common interest with the least list index sum. count = zero_highest[-1] + one_highest[-1]
# If there is a choice tie between answers, output all of them with no order requirement.
# You could assume there always exists an answer. elif binary[bit] == "1" and binary[bit - 1] == "0":
# prefix ends in "10" so can append "1" to all previous integers
# Create a dictionary of the shorter list mapping restaurant to index. For each restaurant in the longer list, if it # plus can add all integers of this length ending with "0"
# is in the dictionary then find the index sum. If there is a tie then append it to the result, if there is a new count += zero_highest[-1]
# minimum then make it the lone result.
# Time - O(m + n) # else if most significant bit of prefix is "0" then count is unchanged
# Space - O(min(m, n)) # but no incermentail new integers are valid
# https://leetcode.com/problems/non-negative-integers-without-consecutive-ones/ if self.count == 0:
# Given a positive integer n, find the number of non-negative integers less than or equal to n, whose binary self.move()
# representations do NOT contain consecutive ones. self.count -= 1 # decrement count of this letter
return self.letter
# Use dynamic programming to calculate the number of integers without repeated set bits and with most significant bit
# of 0 and of 1, up to the same number of bits as num. def hasNext(self):
# Also dynamically update count of valid integers as num is extended from least significant bit. If last bit is zero, """
# keep count unchanged. If last bits are "11" then reset count since all valid integers ending in zero and one with :rtype: bool
# this length are possible. If last bits are "01" then valid integers ending in 1 are all previous valid integers """
# extended by one, valid integers ending in zero are all valid integers of this length ending in zero. return self.count > 0 or self.i < len(self.s)
# Time - O(log n)
# Space - O(log n) def move(self):
self.letter = self.s[self.i]
class Solution(object): self.count = 0
self.i += 1
if node.right:
while self.i < len(self.s) and self.s[self.i] <= "9": # while digit result.append("(")
self.count = self.count * 10 + int(self.s[self.i]) # update count with digit preorder(node.right)
self.i += 1 result.append(")")
preorder(t)
return "".join(result)
# python_1_to_1000/605_Can_Place_Flowers.py
_author_ = 'jake' return [dup for dup in content_to_path.values() if len(dup) > 1] # only return if at least 2 files
_project_ = 'leetcode'
# https://leetcode.com/problems/construct-string-from-binary-tree/
# You need to construct a string consists of parenthesis and integers from a binary tree in a preorder traversal. # python_1_to_1000/611_Valid_Triangle_Number.py - m
# The null node needs to be represented by empty parenthesis pair "()". And you need to omit all the empty parenthesis
# pairs that don't affect the one-to-one mapping relationship between the string and the original binary tree. _author_ = 'jake'
_project_ = 'leetcode'
# Preorder traversal. Append to the result the string of the node.val. If neither left nor right children, return.
# Add brackets before and after left subtree, since empty brackets are required if left subtree is None. If right # https://leetcode.com/problems/valid-triangle-number/
# subtree exists, add brackets before and after it. # Given an array consists of non-negative integers, your task is to count the number of triplets chosen from the
# Time - O(n) # array that can make triangles if we take them as side lengths of a triangle.
# Space - O(n)
# Iterate over sides in order of decreasing length. With current side as longest of triangle, consider the range of
# Definition for a binary tree node. # all shorter sides. Set shortest_side and middle_side as the shortest and longest sides in this range. If shortest +
# class TreeNode(object): # middle <= longest then cannot make a triangle so increase shortest. If a triangle can be made, then all longer
# def __init__(self, x): # shortest sides can also make a triangle so increment count and decrement middle side.
# self.val = x # Time - O(n**2)
# self.left = None # Space - O(1)
# self.right = None # Alternatively, count sides by length. Try all possible combinations of side lengths in a triple loop. Count the
# number of ways that the sides can be chosen out of those available with a given length. O(n**3) but faster if
class Solution(object): # many duplicate lengths.
def tree2str(self, t):
""" from collections import Counter
:type t: TreeNode
:rtype: str class Solution(object):
""" def triangleNumber(self, nums):
result = [] """
:type nums: List[int]
def preorder(node): :rtype: int
"""
if not node: nums.sort()
return triangles = 0
# Create mapping of start letter to list of words in dictionary. Iterate over string, maintaining a list of words from # python_1_to_1000/621_Task_Scheduler.py - m
# dictionary that have partially matched s up to the current index. Matches list consist of previous matches that also
# match the next c, plus new words with he start letter of c. If all chars of a word are matched, mark all those chars _author_ = 'jake'
# in s as being in_tag. Finally, construct result by inserting opening and closing tags. _project_ = 'leetcode'
# Time - O(n * k * m), n words in dictionary of max length k, len(s) == m
# Space - O(nk + m) # https://leetcode.com/problems/task-scheduler/
# Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters
from collections import defaultdict # represent different tasks.Tasks could be done without original order. Each task could be done in one interval.
# For each interval, CPU could finish one task or just be idle.
class Solution(object): # However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n
def addBoldTag(self, s, dict): # intervals that CPU are doing different tasks or just be idle.
""" # You need to return the least number of intervals the CPU will take to finish all the given tasks.
:type s: str
:type dict: List[str] # Find the most frequent task and calculate the time to complete all instances of this task as the wait between tasks
:rtype: str # (n + 1) times the number of waits (nb_tasks - 1). For each task with the same count as the most frequent, increment
""" # the finishing time. All less frequent tasks can be scheduled to fill the remaining idle time, or else they extend
in_tag = [False for _ in range(len(s))] # bool indicates whether char should be inside bold tag # the finish time without any idle time.
# In other words, the only situation when the tasks cannot be completed without idle time is when the most frequent
start_letters = defaultdict(list) # mapping from start char to list of words with that start char # task(s) cannot be scheduled within the length of tasks.
for word in dict: # Time - O(n * m), nb tasks * nb types of task
start_letters[word[0]].append(word) # Space - O(m)
matches = [] # list of (word, word_index) that partially match s up word_index from collections import Counter
for word in start_letters[c]: # words with first char == c for count in counts.values():
if len(word) == 1: if count == max_count: # each task pushes back finish time
in_tag[i] = True result += 1
"""
return max(result, len(tasks)) # other tasks fill idle time Checks whether the circular queue is full or not.
:rtype: bool
"""
return (self.head + 1) % self.k == self.tail
# python_1_to_1000/622_Design_Circular_Queue.py - m # python_1_to_1000/623_Add_One_Row_to_Tree.py - m
# https://leetcode.com/problems/design-circular-queue/ # https://leetcode.com/problems/add-one-row-to-tree/
# Design your implementation of the circular queue. The circular queue is a linear data structure in which the # Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value v at the given
# operations are performed based on FIFO (First In First Out) principle and the last position is connected back to # depth d. The root node is at depth 1.
# the first position to make a circle. It is also called "Ring Buffer". # The adding rule is: given a positive integer depth d, for each NOT null tree nodes N in depth d-1, create two tree
# One of the benefits of the circular queue is that we can make use of the spaces in front of the queue. # nodes with value v as N's left subtree root and right subtree root. And N's original left subtree should be the left
# In a normal queue, once the queue becomes full, we cannot insert the next element even if there is a space in front # subtree of the new left subtree root, its original right subtree should be the right subtree of the new right subtree
# of the queue. But using the circular queue, we can use the space to store new values. # root. If depth d is 1 that means there is no depth d-1 at all, then create a tree node with value v as the new root
# Your implementation should support following operations: # of the whole original tree, and the original tree is the new root's left subtree.
#
# MyCircularQueue(k): Constructor, set the size of the queue to be k. # If d == 1 create a new root. If d == 2 insert new nodes between root and its children. Else recurse to next depth.
# Front: Get the front item from the queue. If the queue is empty, return -1. # Time - O(n)
# Rear: Get the last item from the queue. If the queue is empty, return -1. # Space - O(n)
# enQueue(value): Insert an element into the circular queue. Return true if the operation is successful.
# deQueue(): Delete an element from the circular queue. Return true if the operation is successful. class Solution(object):
# isEmpty(): Checks whether the circular queue is empty or not. def addOneRow(self, root, v, d):
# isFull(): Checks whether the circular queue is full or not. """
:type root: TreeNode
# Use a python list as a circular array. Add an extra space, which allows us to distinguish between empty and full :type v: int
# queues. :type d: int
# Time - O(1) :rtype: TreeNode
# Space - O(n) """
if not root:
class MyCircularQueue(object): return None
def __init__(self, k): if d == 1: # create a new root and put existing tree on left
""" root, root.left = TreeNode(v), root
Initialize your data structure here. Set the size of the queue to be k. elif d == 2: # new nodes as children of root
:type k: int old_left, old_right = root.left, root.right
""" root.left, root.right = TreeNode(v), TreeNode(v)
self.k = k + 1 # always have one space to separate head from tail root.left.left, root.right.right = old_left, old_right
self.q = [None] * self.k else: # recurse at next depth
self.head = self.tail = 0 # tail is always empty self.addOneRow(root.left, v, d - 1)
self.addOneRow(root.right, v, d - 1)
def enQueue(self, value):
""" return root
Insert an element into the circular queue. Return true if the operation is successful.
:type value: int
:rtype: bool # python_1_to_1000/624_Maximum_Distance_in_Arrays.py - m
"""
if self.isFull(): _author_ = 'jake'
return False _project_ = 'leetcode'
self.q[self.tail] = value
self.tail = (self.tail - 1) % self.k # https://leetcode.com/problems/maximum-distance-in-arrays/
return True # Given m arrays, and each array is sorted in ascending order. Now you can pick up two integers from two different
# arrays (each array picks one) and calculate the distance. We define the distance between two integers a and b to be
def deQueue(self): # their absolute difference |a-b|. Your task is to find the maximum distance.
"""
Delete an element from the circular queue. Return true if the operation is successful. # For each array, update the max_dist using either the maximum from this array and the previous minimum from other
:rtype: bool # arrays, or the minimum from this array and the previous maximum from other arrays. Then update the maximum and
""" # minimum. Only uses the fist and last integer from each array.
if self.isEmpty(): # Time - O(n) number of arrays
return False # Space - O(1)
self.head = (self.head - 1) % self.k # just move head, no need to delete element
return True class Solution(object):
def maxDistance(self, arrays):
def Front(self): """
""" :type arrays: List[List[int]]
Get the front item from the queue. :rtype: int
:rtype: int """
""" low, high = arrays[0][0], arrays[0][-1]
if self.isEmpty(): max_dist = 0
return -1
return self.q[self.head] for array in arrays[1:]:
def isFull(self): # Iterating over the digits from 9 down to 2, find all the factors of each digit. Add each factor to the result from
# the least significant digit first (which minimises the value since we start by removing factors of 9). By starting return 1
# with 9 we minimise the number of factors.
# Time - O(log n) MODULO = 10 ** 9 + 7
# Space - O(1)
# inverse_pairs[i] is nb arrangements for current num with <= i inverse pairs
class Solution(object): inverse_pairs = [0 for _ in range(k + 1)]
def smallestFactorization(self, a):
""" for num in range(1, n + 1): # increment num from 1 up to n
:type a: int
:rtype: int next_inverse_pairs = [1] # always one sorted arrangement with no inverse pairs
"""
if a == 1: for nb_pairs in range(1, k + 1):
return 1
next_inverse_pairs.append(next_inverse_pairs[-1]) # cumulative sum
result = 0 next_inverse_pairs[-1] += inverse_pairs[nb_pairs] # add arrangements for num-1 up to nb_pairs
tens = 1 if nb_pairs - num >= 0: # can only increase by num-1 pairs
next_inverse_pairs[-1] -= inverse_pairs[nb_pairs - num]
for digit in range(9, 1, -1): next_inverse_pairs[-1] %= MODULO
result += digit * tens return (inverse_pairs[-1] - inverse_pairs[-2]) % MODULO # mod is always positive
_author_ = 'jake' # Sort by increasing deadline time. If a set of courses can be done before a deadline, then they can be done
_project_ = 'leetcode' # consecutively from the start time without gaps.
# Given the total length of all courses than can be taken so far, the course with the next deadline can also be taken
# https://leetcode.com/problems/maximum-product-of-three-numbers/ # if it does not extend the total length beyond its deadline.
# Given an integer array, find three numbers whose product is maximum and output the maximum product. # Time - O(n log n)
# Space - O(n)
# For 2 numbers, maximum is either largest pair or smallest (most negative) pair.
# For 3 numbers, use the maximum from 2 numbers and the next largest. import heapq
# Sort the array to find the smallest and largest, alternatively iterate over array tracking top 3 and bottom 2 in O(n).
# Time - O(n log n) class Solution(object):
# Space - O(1) def scheduleCourse(self, courses):
"""
class Solution(object): :type courses: List[List[int]]
def maximumProduct(self, nums): :rtype: int
""" """
:type nums: List[int] total_length = 0
:rtype: int taken_courses = []
"""
nums.sort() courses.sort(key=lambda c: c[1]) # sort by increasing end time
top_3 = nums[-1] * nums[-2] * nums[-3]
top_bottom = nums[-1] * nums[0] * nums[1] for duration, end in courses:
return max(top_3, top_bottom) if total_length + duration <= end: # can take this course
total_length += duration
heapq.heappush(taken_courses, -duration)
elif -taken_courses[0] > duration: # take this course instead of current longest
# python_1_to_1000/629_K_Inverse_Pairs_Array.py - h neg_longest = heapq.heappushpop(taken_courses, -duration)
total_length += neg_longest + duration
_author_ = 'jake'
_project_ = 'leetcode' return len(taken_courses)
# https://leetcode.com/problems/k-inverse-pairs-array/
# Given two integers n and k, find how many different arrays consist of numbers from 1 to n such that there are # python_1_to_1000/631_Design_Excel_Sum_Formula.py - h
# exactly k inverse pairs.
# We define an inverse pair as following: For ith and jth element in the array, if i < j and a[i] > a[j] then it's _author_ = 'jake'
# an inverse pair; Otherwise, it's not. _project_ = 'leetcode'
# Since the answer may be very large, the answer should be modulo 10**9 + 7.
# https://leetcode.com/problems/design-excel-sum-formula/
# Given the counts of arrangements with i inverse pairs of integers up to n, where i <= k, find the counts for n + 1. # Your task is to design the basic function of Excel and implement the function of sum formula. Specifically, you need
# Store the cumulative sums of arrangements by number of inverse pairs. # to implement the following functions:
# We can put n + 1 at any position in the array to increase the number of arrangements by anywhere from 0 to n for # Excel(int H, char W): This is the constructor. The inputs represents the height and width of the Excel form.
# all existing arrangements. To find the cumulative count for n + 1, nb_pairs, add the cumulative count for n + 1, # H is a positive integer, range from 1 to 26. It represents the height. W is a character range from 'A' to 'Z'.
# nb_pairs - 1 to the cumulative count for n, nb_pairs. If nb_pairs cannot be reached by adding n pairs, subtract # It represents that the width is the number of characters from 'A' to W. The Excel form content is represented by a
# these from cumulative sum. # height * width 2D integer array C, it should be initialized to zero. You should assume that the first row of C
# starts from 1, and the first column of C starts from 'A'.
# Time - O(n * k) # void Set(int row, char column, int val): Change the value at C(row, column) to be val.
# Space - O(k) # int Get(int row, char column): Return the value at C(row, column).
# int Sum(int row, char column, List of Strings : numbers): This function calculate and set the value at C(row,
class Solution(object): # column), where the value should be the sum of cells represented by numbers. This function return the sum result
def kInversePairs(self, n, k): # at C(row, column). This sum formula should exist until this cell is overlapped by another value or another
""" # sum formula.
:type n: int # numbers is a list of strings that each string represent a cell or a range of cells. If the string represent a
:type k: int # single cell, then it has the following format : ColRow. For example, "F7" represents the cell at (7, F).
:rtype: int # If the string represent a range of cells, then it has the following format : ColRow1:ColRow2. The range will
""" # always be a rectangle, and ColRow1 represent the position of the top-left cell, and ColRow2 represents the
if k == 0: # position of the bottom-right cell.
class Solution(object):
# Convert excel cell format to indices. Cells store integer or list of sum ranges. To sum, recurse on each cell in def smallestRange(self, nums):
# range until a value is found. """
# Time - O(m * n) for init, get and sum. O(1) for set. :type nums: List[List[int]]
# Alternatively, store sum results in cells and use pointers from dependents to update sums on set(). :rtype: List[int]
# Space - O(m * n) """
n = len(nums) # number of lists
class Excel(object): window = [(nums[i][0], 0, i) for i in range(n)] # (num, index in list, index of list)
def _indices(self, r, c): # convert excel format to indices heapq.heapify(window)
return [r - 1, ord(c) - ord("A")] heap_min, heap_max = window[0][0], max([nums[i][0] for i in range(n)])
best_min, best_max = heap_min, heap_max
def __init__(self, H, W):
""" while True:
:type H: int _, i, i_list = heapq.heappop(window) # remove smalles num from window
:type W: str
""" if i + 1 >= len(nums[i_list]): # end of i_list
rows, cols = self._indices(H, W) return [best_min, best_max]
self.excel = [[0 for _ in range(cols + 1)] for _ in range(rows + 1)]
heapq.heappush(window, (nums[i_list][i + 1], i + 1, i_list)) # push next num from i_list
def set(self, r, c, v): heap_min = window[0][0]
""" heap_max = max(heap_max, nums[i_list][i + 1])
:type r: int if heap_max - heap_min < best_max - best_min: # keep current range if not better
:type c: str best_min, best_max = heap_min, heap_max
:type v: int
:rtype: void
""" # python_1_to_1000/633_Sum_of_Square_Numbers.py - m
r, c, = self._indices(r, c)
self.excel[r][c] = v _author_ = 'jake'
_project_ = 'leetcode'
def get(self, r, c):
""" # https://leetcode.com/problems/sum-of-square-numbers/
:type r: int # Given a non-negative integer c, your task is to decide whether there're two integers a and b such that a2 + b2 = c.
:type c: str
:rtype: int # Incremetn a from 0 until 2 a**2 >= c. Check if b is an integer.
""" # Time - O(sqrt(n))
r, c = self._indices(r, c) # Space - O(1)
return self.get_i(r, c) # call get_i with indices
from math import sqrt
def get_i(self, r, c): # uses indices instead of excel format
""" class Solution(object):
:type r: int def judgeSquareSum(self, c):
:type c: int """
:rtype: int :type c: int
""" :rtype: bool
contents = self.excel[r][c] """
if isinstance(contents, int): # base case of integer a = 0
return contents
while a <= sqrt(c / 2):
total = 0
for cells in contents: b = sqrt(c - a ** 2)
cell_range = cells.split(":") if int(b) == b:
r1, c1 = self._indices(int(cell_range[0][1:]), cell_range[0][0]) return True
a += 1
if len(cell_range) == 1: # single cell
r2, c2 = r1, c1 return False
else: # range
r2, c2 = self._indices(int(cell_range[1][1:]), cell_range[1][0])
# python_1_to_1000/634_Find_the_Derangement_of_An_Array.py - m
for row in range(r1, r2 + 1):
for col in range(c1, c2 + 1): _author_ = 'jake'
total += self.get_i(row, col) # recurse, get_i with indices _project_ = 'leetcode'
""" # https://leetcode.com/problems/decode-ways-ii/
:type root: TreeNode # A message containing letters from A-Z is being encoded to numbers using the following mapping way:
:rtype: List[float] # 'A' -> 1
""" # 'B' -> 2
nodes = [root] # ...
result = [] # 'Z' -> 26
# Beyond that, now the encoded string can also contain the character '*', which can be treated as one of the
while True: # numbers from 1 to 9.
# Given the encoded message containing digits and the character '*', return the total number of ways to decode it.
row_sum, row_count = 0, 0 # no need to use a list to store the values # Also, since the answer may be very large, you should return the output mod 10**9 + 7.
new_nodes = []
# Dynamic programming. Iterate over s. New ways to encode = choices for c * existing ways + choices for c and prev_char
for node in nodes: # * prev_ways. Note that * cannot encode 0.
if not node: # ignore None # Time - O(n)
continue # Space - O(1)
row_sum += node.val
row_count += 1 class Solution(object):
new_nodes.append(node.left) # add children to next queue def numDecodings(self, s):
new_nodes.append(node.right) """
:type s: str
if row_count == 0: :rtype: int
break """
result.append(row_sum / float(row_count)) ways = 0
nodes = new_nodes # check next row even if all nodes are None if s[0] == "*":
ways = 9
return result elif s[0] != "0":
ways = 1
prev_char = s[0]
# python_1_to_1000/638_Shopping_Offers.py - m prev_ways = 1
memo[needs_tuple] = min_cost # On each iteration of while loop, 1) identify any sign, 2) parse num or set to 1 if None, 3) add to total of x or val.
return min_cost # When equals sign is found, reverse base to subtract counts on RHS of equals from LHS.
# Time - O(n)
# Space - O(1)
memo = {}
return helper() class Solution(object):
def solveEquation(self, equation):
"""
# python_1_to_1000/639_Decode_Ways_II.py - h :type equation: str
:rtype: str
_author_ = 'jake' """
_project_ = 'leetcode' x, val = 0, 0 # count of x and sum of integers
base = 1 # set to -1 after seeing "="
self.tail = (self.tail - 1) % self.k
i = 0 return True
while i < len(equation):
def deleteFront(self):
neg = base """
if equation[i] == "+": Deletes an item from the front of Deque. Return true if the operation is successful.
i += 1 :rtype: bool
if equation[i] == "-": """
neg = -base if self.isEmpty():
i += 1 return False
self.head = (self.head - 1) % self.k
num = None return True
while i < len(equation) and "0" <= equation[i] <= "9":
if num is None: def deleteLast(self):
num = 0 """
num = num * 10 + int(equation[i]) Deletes an item from the rear of Deque. Return true if the operation is successful.
i += 1 :rtype: bool
"""
if num is None: if self.isEmpty():
num = 1 return False
self.tail = (self.tail + 1) % self.k
if i < len(equation) and equation[i] == "x": return True
x += num * neg
i += 1 def getFront(self):
else: """
val += num * neg Get the front item from the deque.
:rtype: int
if i < len(equation) and equation[i] == "=": """
base *= -1 if self.isEmpty():
i += 1 return -1
return self.q[self.head]
if x == 0 and val == 0:
return "Infinite solutions" def getRear(self):
if x == 0: """
return "No solution" Get the last item from the deque.
return "x=" + str(-val // x) :rtype: int
"""
if self.isEmpty():
# python_1_to_1000/641_Design_Circular_Deque.py - m return -1
return self.q[(self.tail + 1) % self.k]
_author_ = 'jake'
_project_ = 'leetcode' def isEmpty(self):
"""
# https://leetcode.com/problems/design-circular-deque/ Checks whether the circular deque is empty or not.
# Design your implementation of the circular double-ended queue (deque). :rtype: bool
# Your implementation should support following operations: """
# MyCircularDeque(k): Constructor, set the size of the deque to be k. return self.head == self.tail
# insertFront(): Adds an item at the front of Deque. Return true if the operation is successful.
# insertLast(): Adds an item at the rear of Deque. Return true if the operation is successful. def isFull(self):
# deleteFront(): Deletes an item from the front of Deque. Return true if the operation is successful. """
# deleteLast(): Deletes an item from the rear of Deque. Return true if the operation is successful. Checks whether the circular deque is full or not.
# getFront(): Gets the front item from the Deque. If the deque is empty, return -1. :rtype: bool
# getRear(): Gets the last item from Deque. If the deque is empty, return -1. """
# isEmpty(): Checks whether Deque is empty or not. return (self.head + 1) % self.k == self.tail
# isFull(): Checks whether Deque is full or not.
# Use a python list as a circular array. Adding an extra space allows distinction between sull and empty queues. # python_1_to_1000/642_Design_Search_Autocomplete_System.py - h
# Deleted elements are not removed, pointers are just moved.
# Time - O(n) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/645_Set_Mismatch.py
# If k is low (< 80) then calculate the cumulative sum array of nums and for each length find the average of all # python_1_to_1000/646_Maximum_Length_of_Pair_Chain.py - m
# subarrays. Any subarray longer than 2k can be divided into 2 subarrays of length at least k, at one of which has an
# average at least as good as the whole subarray. Hence restrict to max length less than 2k. _author_ = 'jake'
# For larger k, binary search the space of averages. has_average(x) determines whether there is some subarray of _project_ = 'leetcode'
# length at least k with an average of at least x. Subtract x from all elements of nums, then for all prefixes of
# length at least k, find the minimum sum prefix that still allows subarray to be length k. # https://leetcode.com/problems/maximum-length-of-pair-chain/
# Time - O(n log r) where r is range between max an min values of array. O(nk) for small k. # You are given n pairs of numbers. In every pair, the first number is always smaller than the second number.
# Space - O(n) fro small k, O(1) for binary search. # Define a pair (c, d) can follow another pair (a, b) if and only if b < c.
# Chain of pairs can be formed in this fashion.
class Solution(object): # Given a set of pairs, find the length longest chain which can be formed. You needn't use up all the given pairs.
def findMaxAverage(self, nums, k): # You can select pairs in any order.
"""
:type nums: List[int] # Sort by first number of the pair. For each pair, if first number is after previous chain end then this pair can be
:type k: int # used to extend chain to new pair end. Else last member of chain can be replace with new pair if it reduces chain end.
:rtype: float # Replacement is always possible because new pair must have same or larger first member.
""" # Time - O(n log n)
n = len(nums) # Space - O(1)
node[word[-1]] = word # terminate with word
class Solution(object):
def findLongestChain(self, pairs): sentence = sentence.split(" ")
""" for word in sentence:
:type pairs: List[List[int]] node = root
:rtype: int for c in word:
""" if c not in node:
pairs.sort(key=lambda x: x[0]) result.append(word) # no replacements
chain = 0 break
end = pairs[0][0] - 1 if isinstance(node[c], str): # replacement found
result.append(node[c])
for pair in pairs: break
if end < pair[0]: node = node[c]
chain += 1 else:
end = pair[1] result.append(word)
else:
end = min(end, pair[1]) return " ".join(result)
return chain
# python_1_to_1000/649_Dota2_Senate.py - m
# Create a trie where each letter of a word maps to the next letter, terminating in the word. Insert all words of return "Radiant" if r else "Dire"
# dictionary into trie. Terminate without inserting if perfix of a word is longer than a word already in trie.
# for each word in sentence, traverse through trie until no more nodes or word is found.
# Time - O(m + n) total number of chars in dictionary and sentence. # python_1_to_1000/650_2_Keys_Keyboard.py - m
# Space - O(m) number of chars in dictionary
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def replaceWords(self, dict, sentence):
""" # https://leetcode.com/problems/2-keys-keyboard/
:type dict: List[str] # Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each
:type sentence: str step:
:rtype: str # Copy All: You can copy all the characters present on the notepad (partial copy is not allowed).
""" # Paste: You can paste the characters which are copied last time.
result = [] # Given a number n. You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted.
root = {} # Output the minimum number of steps to get n 'A'.
for word in dict: # If n is prime, we can only make it by copying 'A' and pasting it n - 1 times.
node = root # Consider breaking n down to make a single 'A'. If we find a divisor d of n, then from n // d we can take d steps to
for c in word[:-1]: # make n 'A's. Repeat this process as many times as possible with each divisor starting from 2, until only 1 'A' left.
if c not in node: # create a new mapping # Solution is the sum of the factors (apart from 1).
node[c] = {} # Time - O(n)
elif isinstance(node[c], str): # longer than an existing word # Space - O(1)
break
node = node[c] class Solution(object):
else: def minSteps(self, n):
"""
:type n: int _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
steps = 0 # https://leetcode.com/problems/two-sum-iv-input-is-a-bst/
divisor = 2 # Given a Binary Search Tree and a target number, return true if there exist two elements in the BST such that their
# sum is equal to the given target.
while n > 1:
while n % divisor == 0: # Traverse the BST. Preorder is used but could be postorder or inorder. For each node, check if k - node.val has
steps += divisor # already been visited. If node, add noe.val to the visited set. Would work equally well for a binary tree that is not
n //= divisor # a BST.
divisor += 1 # Time - O(n)
# Space - O(n)
return steps
class Solution(object):
def findTarget(self, root, k):
"""
# python_1_to_1000/651_4_Keys_Keyboard.py - m :type root: TreeNode
:type k: int
_author_ = 'jake' :rtype: bool
_project_ = 'leetcode' """
visited = set()
# https://leetcode.com/problems/4-keys-keyboard/
# Imagine you have a special keyboard with the following keys: def traverse(node):
# Key 1: (A): Print one 'A' on screen.
# Key 2: (Ctrl-A): Select the whole screen. if not node:
# Key 3: (Ctrl-C): Copy selection to buffer. return False
# Key 4: (Ctrl-V): Print buffer on screen appending it after what has already been printed.
# Now, you can only press the keyboard for N times (with the above four keys), find out the maximum numbers of 'A' you if k - node.val in visited:
# can print on screen. return True
visited.add(node.val)
# The maximum for a given N is either just by printing 'A' N times, or producing the maximum maxA(i) from i key presses,
# then using the remaining N - i to create maxA(i) * (N - i). N - i must be at least 4 to create at least one copy. return traverse(node.left) or traverse(node.right)
# In fact the optimal occurs when N - i is 4 or 5.
# Time - O(n) return traverse(root)
# Space - O(n)
# Find the height and calculate the width as 2**height - 1. Create an empty list of lists to hold result. The preorder # Ensure that vertical and horizontal moves balance i.e. number of up and down moves are equal and number of left and
# traverse the tree, placing each value in the result and recursing to subtrees. # right moves are equal.
# Time - O(2 ** (n + 1)), every node visited once but worst case time is to create result when height = n # Time - O(n)
# Space - O(2 ** (n + 1)) # Space - O(1)
while n: # python_1_to_1000/663_Equal_Tree_Partition.py - m
result.append(str(n % 9))
n //= 9 _author_ = 'jake'
_project_ = 'leetcode'
return int("".join(result[::-1]))
# https://leetcode.com/problems/equal-tree-partition/
# Given a binary tree with n nodes, your task is to check if it's possible to partition the tree to two trees which
# python_1_to_1000/661_Image_Smoother.py # have the equal sum of values after removing exactly one edge on the original tree.
_author_ = 'jake' # Modify the tree with bottom-up recursion so the value of each node is the sum of its original subtree. Then find a
_project_ = 'leetcode' # subtree with sum of half the total sum.
# Time - O(n)
# https://leetcode.com/problems/image-smoother/ # Space - O(1)
# Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother to make the gray
# scale of each cell becomes the average gray scale (rounding down) of all the 8 surrounding cells and itself. # Definition for a binary tree node.
# If a cell has less than 8 surrounding cells, then use as many as you can. # class TreeNode(object):
# def __init__(self, x):
# Iterate over M. For each cell, count and sum the neighbours (including self). # self.val = x
# Time - O(mn) # self.left = None
# Space - O(mn) # self.right = None
if (i, j) in memo: def sum_paths(location, partial): # returns sum of all paths to leaves given partial sum so far from root
return memo[(i, j)]
if location not in mapping:
min_prints = 1 + helper(i + 1, j) # print first char, then print remiander return 0
# python_1_to_1000/665_Non-decreasing_Array.py - m
# python_1_to_1000/667_Beautiful_Arrangement_II.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/non-decreasing-array/
# Given an array with n integers, check if it could become non-decreasing by modifying at most 1 element. # https://leetcode.com/problems/beautiful-arrangement-ii/
# We define an array is non-decreasing if array[i] <= array[i + 1] holds for every i (1 <= i < n). # Given two integers n and k, you need to construct a list which contains n different positive integers ranging from
# 1 to n and obeys the following requirement:
# If an element is less than the previous element, if we have already modified the array then return False. Else we can # Suppose this list is [a1, a2, a3, ... , an], then the list [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|]
# either decrease the previous element or increase the current element. Decreasing the previous is preferred # has exactly k distinct integers.
# because it does not have an affect on future elements but is only possible if there is no element before previous # If there are multiple answers, print any of them.
# or it is not more than the previous element. There is no need to actually modify the previous element since it is
# never used again. # The criteria that there are k differences between consecutive numbers means those differences are 1, 2, .. k.
# Time - O(n) # Use the first k + 1 nums to produce a list with all the required differences. Build the list with the largest
# Space - O(1) # difference first, then taking numbers from each end in turn create all the other differences.
# Then append all the remaining nums in order (since any differences will already have been used).
class Solution(object): # Time - O(n)
def checkPossibility(self, nums): # Space - O(n)
"""
:type nums: List[int] class Solution(object):
:rtype: bool def constructArray(self, n, k):
""" """
modified = False :type n: int
:type k: int
for i, num in enumerate(nums[1:], 1): :rtype: List[int]
"""
if num < nums[i - 1]: result = []
low, high = 1, k + 1
if modified: next_low = True
return False
while low <= high:
if i != 1 and nums[i - 2] > nums[i]: # must increase nums[i] if next_low:
nums[i] = nums[i - 1] result.append(low)
low += 1
modified = True else:
result.append(high)
return True high -= 1
next_low = not next_low
# python_1_to_1000/670_Maximum_Swap.py - m
_author_ = 'jake'
# python_1_to_1000/668_Kth_Smallest_Number_in_Multiplication_Table.py - h _project_ = 'leetcode'
left, right = 1, m * n
# python_1_to_1000/671_Second_Minimum_Node_In_a_Binary_Tree.py
while left < right:
_author_ = 'jake'
mid = (left + right) // 2 _project_ = 'leetcode'
if helper(mid):
right = mid # https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/
else: # Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this tree
left = mid + 1 # has exactly two or zero sub-node.
# If the node has two sub-nodes, then this node's value is the smaller value among its two sub-nodes.
return left # Given such a binary tree, output the second minimum value in the set made of all the nodes' value in the whole tree.
# If no such second minimum value exists, output -1 instead.
# python_1_to_1000/669_Trim_a_Binary_Search_Tree.py - m # The root value is the minimum value, since all children are >= root value. Second minimum must be a child of a node
# with the minimum (root) value. If a node has the root value then recursively check its children.
_author_ = 'jake' # Else it has a larger value, so update second_min.
_project_ = 'leetcode' # Time - O(n)
# Space - O(n)
# https://leetcode.com/problems/trim-a-binary-search-tree/
# Given a binary search tree and the lowest and highest boundaries as L and R, trim the tree so that all its elements class Solution(object):
# lies in [L, R] (R >= L). You might need to change the root of the tree, so the result should return the new root of def findSecondMinimumValue(self, root):
# the trimmed binary search tree. """
:type root: TreeNode
# If root val is in [L, R] then return root and trimmed left and right subtrees. If root is ledd than left, root and :rtype: int
# all smaller values in left subtree should be trimmed, so return trimmed right subtree. """
# Time - O(n) min_val = root.val # assumes root exists
# Space - O(1) self.second_min = float("inf")
if m == 1: # one switch
if n == 1: # python_1_to_1000/675_Cut_Off_Trees_for_Golf_Event.py - h
return 2 # off or on
if n == 2: _author_ = 'jake'
return 3 # not both on _project_ = 'leetcode'
return 4 # evens, odds, every third or all off
# https://leetcode.com/problems/cut-off-trees-for-golf-event/
if m == 2: # two switches # You are asked to cut off trees in a forest for a golf event.
if n == 1: # The forest is represented as a non-negative 2D map, in this map:
return 2 # off or on # 0 represents the obstacle can't be reached.
if n == 2: # 1 represents the ground can be walked through.
return 4 # all possibilities # The place with number bigger than 1 represents a tree can be walked through, and this positive number represents
if n >= 3: # the tree's height.
return 7 # all apart from on, on, off # You are asked to cut off all the trees in this forest in the order of tree's height - always cut off the tree with
# lowest height first. And after cutting, the original place has the tree will become a grass (value 1).
return 2 ** min(n, 3) # any combination of evens, odds, every third # You will start from the point (0, 0) and you should output the minimum steps you need to walk to cut off all
# the trees. If you can't cut off all the trees, output -1 in that situation.
# You are guaranteed that no two trees have the same height and there is at least one tree needs to be cut off.
# python_1_to_1000/673_Number_of_Longest_Increasing_Subsequence.py - m
# Find all trees and sort in increasing height order. DFS from (0, 0) to check all treas can be reached.
_author_ = 'jake' # Sum distances between trees by attempting to take the most direct path. Any node that is not closer to destination
_project_ = 'leetcode' # is added to next_queue and is used once queue is exhausted. The number of diversions increases until a path is found.
# Time - O(m**2 n**2) since mn maximum number of trees and each path explores all mn calls.
# https://leetcode.com/problems/number-of-longest-increasing-subsequence/ # Space - O(mn)
# Given an unsorted array of integers, find the number of longest increasing subsequence.
class Solution(object):
# For each num, find the longest increasing subsequence of the array up to and including that num, and the count of def cutOffTree(self, forest):
# such longest subsequences. Fro each num, consider all previous nums that are lower. If we can make a new longest
# subsequence then we can extend every longest subsequence ending at the previous num. If we can make the same longest rows, cols = len(forest), len(forest[0])
# subsequence then we can add every longest subsequence ending at the previous num to the count. trees = sorted((h, r, c) for r, row in enumerate(forest) # trees sorted by increasing height
# Time - O(n**2) for c, h in enumerate(row) if h > 1)
# Space - O(n)
to_visit = set((r, c) for _, r, c in trees) # check if all trees can be reached
class Solution(object): visited = set()
def findNumberOfLIS(self, nums): queue = [(0, 0)]
"""
:type nums: List[int] while queue:
:rtype: int r, c = queue.pop()
""" to_visit.discard((r, c))
if not nums: visited.add((r, c))
return 0 for r1, c1 in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]:
lengths, counts = [], [] # add to queue all neighbours within grid, not obstacles and have not visited already
if 0 <= r1 < rows and 0 <= c1 < cols and forest[r1][c1] and (r1, c1) not in visited:
for i, num in enumerate(nums): queue.append((r1, c1))
length, count = 1, 1 # default if num does not increase any subsequence if to_visit: # cannot reach all trees
return -1
for j in range(i):
if num > nums[j]: # num can extend sequence def distance(r1, c1, r2, c2):
if lengths[j] + 1 > length: # new best length
length = lengths[j] + 1 direct = abs(r1 - r2) + abs(c1 - c2) # manhattan distance
count = counts[j] diversions = 0
elif lengths[j] + 1 == length: # same best length queue = [(r1, c1)] # cells on paths with current number of diversions
count += counts[j] # add to count of best length next_queue = [] # cells on paths with next number of diversions
visited = set()
lengths.append(length)
counts.append(count) while True:
longest = max(lengths) if not queue: # cannot reach r2, c2 on path with current diversions
return sum([count for length, count in zip(lengths, counts) if length == longest]) queue, next_queue = next_queue, [] # try paths with next number of diversions
diversions += 1
r1, c1 = queue.pop()
# python_1_to_1000/674_Longest_Continuous_Increasing_Subsequence.py if (r1, c1) == (r2, c2): # reached destination
return direct + diversions * 2 # for every diversion, must take a step back in correct direction
_author_ = 'jake'
if (r1, c1) in visited: # Implement a MapSum class with insert, and sum methods.
continue # For the method insert, you'll be given a pair of (string, integer). The string represents the key and the integer
visited.add((r1, c1)) # represents the value. If the key already existed, then the original key-value pair will be overridden to the new one.
# For the method sum, you'll be given a string representing the prefix, and you need to return the sum of all the
for r1, c1, closer in (r1 + 1, c1, r1 < r2), (r1 - 1, c1, r1 > r2), (r1, c1 + 1, c1 < c2), ( # pairs' value whose key starts with the prefix.
r1, c1 - 1, c1 > c2):
if 0 <= r1 < rows and 0 <= c1 < cols and forest[r1][c1]: # Create a mapping from each prefix to the sum of vals of words with that prefix, and a separate mapping of vals of
(queue if closer else next_queue).append((r1, c1)) # each words. If inserting a word which has been seen already, update the difference between the new an old val for
# all prefixes.
result = 0 # Time - O(k**2) for insert and O(1) for sum
r1, c1 = 0, 0 # starting location # Space - O(nk)
for _, r2, c2 in trees:
result += distance(r1, c1, r2, c2) # add distance between trees to result from collections import defaultdict
r1, c1 = r2, c2 # set next starting location
class MapSum(object):
return result
def __init__(self):
"""
# python_1_to_1000/676_Implement_Magic_Dictionary.py - m Initialize your data structure here.
"""
_author_ = 'jake' self.dict = defaultdict(int) # map prefix to sum of vals with that prefix
_project_ = 'leetcode' self.words = defaultdict(int) # map whole words to their val
# https://leetcode.com/problems/map-sum-pairs/
# Iterate over time from least significant digit. Attempt to increase each digit by looking for the smallest greater
# python_1_to_1000/679_24_Game.py - h # digit. Maximum allowed digit depends on index in time. If an increase is possible, make it and return. Else try
# again with next digit.
_author_ = 'jake' # Time - O(1)
_project_ = 'leetcode' # Space - O(1)
# Iterate over s from front and back. If chars do not match, check if the remainder after deleting either of the # Maintain a stack of previous scores, summed after applying all operations.
# unmatched chars is a palindrome. # Time - O(n)
# Time - O(n) # Space - O(n)
# Space - O(n)
class Solution(object):
class Solution(object): def calPoints(self, ops):
def validPalindrome(self, s): """
""" :type ops: List[str]
:type s: str :rtype: int
:rtype: bool """
""" points = []
n = len(s)
i = 0 for op in ops:
# python_1_to_1000/681_Next_Closest_Time.py - m
# python_1_to_1000/683_K_Empty_Slots.py - h
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/next-closest-time/
# Given a time represented in the format "HH:MM", form the next closest time by reusing the current digits. # https://leetcode.com/problems/k-empty-slots/
# There is no limit on how many times a digit can be reused. # There is a garden with N slots. In each slot, there is a flower. The N flowers will bloom one by one in N days.
# You may assume the given input string is always valid. For example, "01:34", "12:09" are all valid. "1:34", "12:9" # In each day, there will be exactly one flower blooming and it will be in the status of blooming since then.
# are all invalid. # Given an array flowers consists of number from 1 to N. Each number in the array represents the place where the
# flower will open in that day.
# For example, flowers[i] = x means that the unique flower that blooms at day i will be at position x, where i and x _project_ = 'leetcode'
# will be in the range from 1 to N.
# Also given an integer k, you need to output in which day there exists two flowers in the status of blooming, and # https://leetcode.com/problems/redundant-connection-ii/
# also the number of flowers between them is k and these flowers are not blooming. # In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all
# If there isn't such day, output -1. # other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which
# has no parents.
# Convert to a list where indices represent positions and values represent days. Create a window with k intervening # The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, ..., N),
# flowers and check if any bloom earlier than those at the ends. If so, then reset the window start to the earlier # with one additional directed edge added. The added edge has two different vertices chosen from 1 to N, and was not
# blooming flower, because flowers already visited bloom later and so cannot start a new window. Else if no flower # an edge that already existed.
# blooms earlier than the window ends, update the earliest_day with the later of the flowers at the ends of the # The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] that represents a
# window and start a new window where the current window ends. # directed edge connecting nodes u and v, where u is a parent of child v.
# Time - O(n) # Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes.
# Space - O(n) # If there are multiple answers, return the answer that occurs last in the given 2D-array.
class Solution(object): # Given a valid tree, a redundant connection is either A) to the root, causing all nodes to have one parent or B) not
def kEmptySlots(self, flowers, k): # to the root, causing some node to have 2 parents. If case B, find the node with 2 parents and the root. Remove one
""" # of the incoming edges to the node with 2 parents and if the tree is valid, the removed edge is redundant else the
:type flowers: List[int] # other incoming edge to the node with 2 parents is redundant.
:type k: int # If case A, try removing edges from the last of the input list until a valid tree is found.
:rtype: int # Time - O(n**2)
""" # Space - O(n)
n = len(flowers)
days = [None for _ in range(n)] # index is position and value is day of blooming class Solution(object):
for day, pos in enumerate(flowers, 1): # index days from 1 def findRedundantDirectedConnection(self, edges):
days[pos - 1] = day # positions indexed from 0 """
:type edges: List[List[int]]
left, right = 0, k + 1 # indices in days of ends of window :rtype: List[int]
first_day = n + 1 # first day with a gap of length k between 2 flowers """
n = len(edges)
while right < n: parents = [[] for _ in range(n + 1)]
for i in range(left + 1, right): # check all intervening flowers between ends of window nbors = [set() for _ in range(n + 1)]
if days[i] < days[left] or days[i] < days[right]: # flower at i blooms earlier than ends
left, right = i, i + k + 1 # start new window with earlier blloming flower for a, b in edges: # build parents and nbors lists
break parents[b].append(a)
else: nbors[a].add(b)
first_day = min(first_day, max(days[left], days[right])) # no intervening bloom earlier
left, right = right, right + k + 1 # start new window at end of this window root = None
for i, parent in enumerate(parents): # check if some node has 2 parents
return -1 if first_day == n + 1 else first_day if len(parent) == 2:
two_parents = i
if not parent: # identify the root
root = i
# python_1_to_1000/684_Redundant_Connection.py - m def valid(root): # test if all nodes can be visited once and once only
visited = set()
_author_ = 'jake' queue = [root]
_project_ = 'leetcode' while queue:
node = queue.pop()
# https://leetcode.com/problems/redundant-connection/ if node in visited:
# In this problem, a tree is an undirected graph that is connected and has no cycles. return False
# The given input is a graph that started as a tree with N nodes (with distinct values 1, 2, ..., N), with one visited.add(node)
# additional edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that queue += nbors[node]
# already existed. return len(visited) == n
# The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] with u < v, that
# represents an undirected edge connecting nodes u and v. if root: # case B, edge added to node that was not root
# Return an edge that can be removed so that the resulting graph is a tree of N nodes. If there are multiple answers, p1, p2 = parents[two_parents]
# return the answer that occurs last in the given 2D-array. The answer edge [u, v] should be in the same nbors[p2].discard(two_parents) # discard second edge
# format, with u < v. return [p2, two_parents] if valid(root) else [p1, two_parents]
# Every edge of a tree connects two sets of nodes that are not otherwise connected. Find the edge that connects already for i in range(len(edges) - 1, -1, -1): # remove edges starting with last edge to be added
# connected nodes with union find structure. n1, n2 = edges[i]
# Find parents of both nodes of an edge. If same then there is already a path between nodes. Else connect nbors[n1].discard(n2) # temporarily remove edge from n1 to n2
# the parents. if valid(n2): # n2 becomes the root
# Time - O(n log* n) return edges[i]
# Space - O(n) nbors[n1].add(n2) # put edge back
class Solution(object):
def findRedundantConnection(self, edges): # python_1_to_1000/686_Repeated_String_Match.py - m
"""
:type edges: List[List[int]] _author_ = 'jake'
:rtype: List[int] _project_ = 'leetcode'
"""
parents = {} # https://leetcode.com/problems/repeated-string-match/
# Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it.
def find_parent(n): # If no such solution, return -1.
if n not in parents: # n is a new node or ultimate parent # Repeat A until it is at least the length of B. If B is not a substring, then test with another copy of A added.
return n # More copies of A are not required because at least one copy of A will not be used.
parents[n] = find_parent(parents[n]) # collapse parent to be ultimate parent # Time - O(n + m)
return parents[n] # return ultimate parent # Space - O(n + m)
for i in range(2): probs = [[1 for _ in range(M)] for _ in range(M)] # 100% probability of remaining for no more moves
if B in A * (div + i):
return div + i for _ in range(K):
for r1 in range(M):
for c1 in range(M):
# python_1_to_1000/687_Longest_Univalue_Path.py - m prob = 0
for dr in [2, 1, -1, -2]: # for each possible move
_author_ = 'jake' for dc in [3 - abs(dr), abs(dr) - 3]:
_project_ = 'leetcode'
if 0 <= r1 + dr < N and 0 <= c1 + dc < N: # ignore if outside the board
# https://leetcode.com/problems/longest-univalue-path/ r2, c2 = convert(r1 + dr, c1 + dc)
# Given a binary tree, find the length of the longest path where each node in the path has the same value. prob += probs[r2][c2] / 8.0 # add 1/8 of probability
# This path may or may not pass through the root.
# The length of path between two nodes is represented by the number of edges between them. new_probs[r1][c1] = prob # update cell
probs = new_probs # update board
# Helper function updates longest for the univalue path that goes through each node. Helper returns a tuple of the
# longest paths via the left and right children of each node. r, c = convert(r, c)
# Time - O(n) return probs[r][c]
# Space - O(n)
class Solution(object):
def longestUnivaluePath(self, root):
""" # python_1_to_1000/689_Maximum_Sum_of_3_Non-Overlapping_Subarrays.py - h
:type root: TreeNode
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
self.longest = 0
# https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/
def helper(node): # In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum.
if not node: # Each subarray will be of size k, and we want to maximize the sum of all 3*k entries.
return 0, 0 # Return the result as a list of indices representing the starting position of each interval (0-indexed).
# If there are multiple answers, return the lexicographically smallest one.
max_left = max(helper(node.left)) # longest univalue path from left child
max_right = max(helper(node.right)) # Initialise one, tow and three as the first three contiguous subarrays of length k in nums. Iterate over nums,
# moving the current 3 subarrays forward on every step. Update the best sum first subarray if greater. Update the best
# if left child has the same val as node, add one edge to longest path via left child # sum first 2 subarrays if the new second subarray plus the best first is greater. Update the best all 3 subarrays if
left = 1 + max_left if node.left and node.left.val == node.val else 0 # the new third subarray plus the best first two sum is greater.
right = 1 + max_right if node.right and node.right.val == node.val else 0 # Time - O(n)
# Space - O(1)
self.longest = max(self.longest, left + right)
class Solution(object):
return left, right def maxSumOfThreeSubarrays(self, nums, k):
"""
helper(root) :type nums: List[int]
return self.longest :type k: int
:rtype: List[int]
"""
# python_1_to_1000/688_Knight_Probability_in_Chessboard.py - m one_sum = sum(nums[:k]) # sums of current subarrays
two_sum = sum(nums[k:k * 2])
_author_ = 'jake' three_sum = sum(nums[k * 2:k * 3])
_project_ = 'leetcode'
best_one = one_sum # best sums of one, two and three subarrays
# https://leetcode.com/problems/knight-probability-in-chessboard/ best_two = one_sum + two_sum
# On an NxN chessboard, a knight starts at the r-th row and c-th column and attempts to make exactly K moves. best_three = one_sum + two_sum + three_sum
# The rows and columns are 0 indexed, so the top-left square is (0, 0), and the bottom-right square is (N-1, N-1).
# A chess knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal best_one_i = 0 # start indices of best one, two and three subarrays
# direction, then one square in an orthogonal direction. best_two_i = [0, k]
# Each time the knight is to move, it chooses one of eight possible moves uniformly at random (even if the piece best_three_i = [0, k, k * 2]
# would go off the chessboard) and moves there.
# The knight continues moving until it has made exactly K moves or has moved off the chessboard. Return the one_i = 1 # next array start index
# probability that the knight remains on the board after it has stopped moving. two_i = k + 1
three_i = k * 2 + 1
# Base case for N == 0 is 100% probability of remaining on the board for all cells.
# For each additional remaining move, calculate a grid of probabilities of remaining on the board from each cell. while three_i <= len(nums) - k:
# The new probability from a cell is the sum of the probabilities from each of the 8 reachable cells given one fewer
# remaining move. one_sum += nums[one_i + k - 1] - nums[one_i - 1] # update current subarray sums
# Only consider the upper left quarter of the board, since the remainder is symmetrical. two_sum += nums[two_i + k - 1] - nums[two_i - 1]
# Time - O(K * N**2) three_sum += nums[three_i + k - 1] - nums[three_i - 1]
# Space - O(N**2)
if one_sum > best_one: # one_sum in an improvement
class Solution(object): best_one = one_sum
def knightProbability(self, N, K, r, c): best_one_i = one_i
"""
:type N: int if best_one + two_sum > best_two: # two_sum and best_one are an improvement
:type K: int best_two = best_one + two_sum
:type r: int best_two_i = [best_one_i, two_i]
:type c: int
:rtype: float if best_two + three_sum > best_three: # three_sum and best_two are an improvement
""" best_three = best_two + three_sum
M = N // 2 # M is the side length of the upper quarter best_three_i = best_two_i + [three_i]
if N % 2 == 1: # add central row and column if N is odd
M += 1 one_i += 1
two_i += 1
def convert(r1, c1): # convert a cell to its symmetrical equivalent in the upper quarter three_i += 1
if r1 >= M:
r1 = N - 1 - r1 return best_three_i
if c1 >= M:
while True:
# python_1_to_1000/690_Employee_Importance.py - m
used_words, target_len, target_str = heapq.heappop(heap) # try least used words, then shortest target
_author_ = 'jake'
_project_ = 'leetcode' for sticker in char_to_word[target_str[0]]: # each word that contains first char of target
new_str = target_str[:]
# https://leetcode.com/problems/employee-importance/ for ch in sticker:
# You are given a data structure of employee information, which includes the employee's unique id, his importance if ch in new_str:
# value and his direct subordinates' id. new_str.remove(ch)
# For example, employee 1 is the leader of employee 2, and employee 2 is the leader of employee 3. if not new_str:
# They have importance value 15, 10 and 5, respectively. Then employee 1 has a data structure like [1, 15, [2]], return used_words + 1
# and employee 2 has [2, 10, [3]], and employee 3 has [3, 5, []]. heapq.heappush(heap, (used_words + 1, len(new_str), new_str))
# Note that although employee 3 is also a subordinate of employee 1, the relationship is not direct.
# Now given the employee information of a company, and an employee id, you need to return the total importance value
# of this employee and all his subordinates. # python_1_to_1000/692_Top_K_Frequent_Words.py - m
# Create mapping from employee id to importance and subordinates. Sum importance by recursive depth first search. _author_ = 'jake'
# Get importance of root employee and recursively add importance totals of subordinates. _project_ = 'leetcode'
# Time - O(n)
# Space - O(n) # https://leetcode.com/problems/top-k-frequent-words/
# Given a non-empty list of words, return the k most frequent elements.
class Solution(object): # Your answer should be sorted by frequency from highest to lowest. If two words have the same frequency, then the
def getImportance(self, employees, id): # word with the lower alphabetical order comes first.
"""
:type employees: Employee # Count the frequencies and heapify tuples of (-count, word). The pop the first k entries from the heap.
:type id: int # Time - O(n + k log n) since O(n) to count and heapify, then O(log N) for each of the k pops
:rtype: int # Space - O(N)
"""
importance, subordinates = {}, {} from collections import Counter
import heapq
for employee in employees:
importance[employee.id] = employee.importance class Solution(object):
subordinates[employee.id] = employee.subordinates def topKFrequent(self, words, k):
"""
def sum_importance(emp_id): # return emp_id importance plus recursive sum of subordinates :type words: List[str]
:type k: int
total = importance[emp_id] :rtype: List[str]
"""
for sub in subordinates[emp_id]: freq = Counter(words)
total += sum_importance(sub) pairs = [(-count, word) for word, count in freq.items()]
heapq.heapify(pairs)
return total return [heapq.heappop(pairs)[1] for _ in range(k)]
return sum_importance(id)
# python_1_to_1000/693_Binary_Number_with_Alternating_Bits.py
def BFS(r, c): for i, c in enumerate(s[1:], 1): # first digit already used
queue = [(0, 0)] # relative to (r, c) if c != s[i - 1]: # c is different from previous char
for r_rel, c_rel in queue: # queue is extended during iteration count += min(seq, prev_seq) # add all balanced substrings
seq, prev_seq = 1, seq
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]: else:
seq += 1
new_r, new_c = r_rel + dr + r, c_rel + dc + c
return count + min(seq, prev_seq) # add final balanced substrings
if 0 <= new_r < rows and 0 <= new_c < cols and grid[new_r][new_c] == 1:
grid[new_r][new_c] = 0
queue.append((new_r - r, new_c - c)) # python_1_to_1000/697_Degree_of_an_Array.py
for dr, dc in neighbours: # faster to check valid land cell before recursing shortest = float("inf")
if 0 <= r + dr < rows and 0 <= c + dc < cols and grid[r + dr][c + dc] == 1: for num in max_nums:
area += island_area(r + dr, c + dc) shortest = min(shortest, limits[num][1] - limits[num][0] + 1)
_author_ = 'jake' # Sort in decreasing order. Find some nums that sum to target, flagging each num in used. If a num is used then only
_project_ = 'leetcode' # search smaller nums since any larger would have been used already.
# Alternatively, add each number to each bucket with capacity and recurse, backtracking if a solution is not found.
# https://leetcode.com/problems/count-binary-substrings/ # Time - O(k * 2**n) for k buckets, each number is or is not used in each
# Give a string s, count the number of non-empty (contiguous) substrings that have the same number of 0's and 1's, # Space - O(k * 2**n)
# and all the 0's and all the 1's in these substrings are grouped consecutively.
# Substrings that occur multiple times are counted the number of times they occur. class Solution(object):
def canPartitionKSubsets(self, nums, k):
# When a sequence of one digit ends, count the required substrings using this sequence and the previous sequence
# (which uses the other digit). Count as many substrings as the lower of the sequence length and previous sequence total = sum(nums)
# length. if total % k != 0:
# Time - O(n) return False # nums are not divisible equally
# Space - O(1)
target = total // k if left2 < left + side and left2 + side2 > left: # horizontal overlap
top = max(top, box_heights[i] + side) # on previous box
used = [False] * len(nums)
box_heights.append(top)
nums.sort(reverse = True) max_heights.append(max(top, max_heights[-1]))
if nums[0] > target: # largest num too big
return False return max_heights
return helper(0) # Iterative solution. Move left or right according to whether val is less than or greater than current node.val, until
# an empty node is found.
# Time - O(n)
# python_1_to_1000/699_Falling_Squares.py - h # Space - O(1)
# For each box, check for overlap with each box already dropped. If overlap update top of box as side length + top of if val < node.val:
# overlapping box. if not node.left:
# Time - O(n**2) node.left = new_node
# Space - O(n) return root
node = node.left
class Solution(object):
def fallingSquares(self, positions): else:
""" if not node.right:
:type positions: List[List[int]] node.right = new_node
:rtype: List[int] return root
""" node = node.right
box_heights = [positions[0][1]] # top edge height of dropped boxes
max_heights = [positions[0][1]]
# python_1_to_1000/702_Search_in_a_Sorted_Array_of_Unknown_Size.py - m
for left, side in positions[1:]:
top = side # default to on ground, top of box is side length _author_ = 'jake'
_project_ = 'leetcode'
for i in range(len(box_heights)): # loop over each previously dropped box
left2, side2 = positions[i] # https://leetcode.com/problems/search-in-a-sorted-array-of-unknown-size/
# Given an integer array sorted in ascending order, write a function to search target in nums. # https://leetcode.com/problems/binary-search/
# If target exists, then return its index, otherwise return -1. However, the array size is unknown to you. # Given a sorted (in ascending order) integer array nums of n elements and a target value, write a function to search
# You may only access the array using an ArrayReader interface, where ArrayReader.get(k) returns the element of the # target in nums. If target exists, then return its index, otherwise return -1.
# array at index k (0-indexed).
# You may assume all integers in the array are less than 10000, and if you access the array out of bounds, # Left and right pointers define the range of indices of nums that could contain target. Reduce target by checking
# ArrayReader.get will return 2147483647. # middle element and either returning or then checking left or right side.
# You may assume that all elements in the array are unique. # Time - O(log n)
# The value of each element in the array will be in the range [-9999, 9999]. # Space - O(1)
# Since the array contains unique numbers from -9999 to 9999, there are not more than 20000 numbers. class Solution(object):
# Use 20000 as the upper-bound index in binary search. def search(self, nums, target):
# This works because the ArrayReader returns MAXINT for indices beyond the array, which is exactly the same as """
# searching an array of 20000 elements where the last elements are MAXINT. :type nums: List[int]
# Time - O(1), due to upper bound on size of array :type target: int
# Space - O(1) :rtype: int
"""
class Solution(object): left, right = 0, len(nums) - 1 # left and right most indices of nums that could contain target
def search(self, reader, target):
""" while left <= right:
:type reader: ArrayReader
:type target: int mid = (left + right) // 2 # middle element of range
:rtype: int
""" if target == nums[mid]:
left, right = 0, 20000 return mid
if target > nums[mid]: # check right side
while left <= right: left = mid + 1
else: # check left side
mid = (left + right) // 2 right = mid - 1
return -1 # https://leetcode.com/problems/design-hashset/
# Design a HashSet without using any built-in hash table libraries.
# To be specific, your design should include these functions:
# python_1_to_1000/703_Kth_Largest_Element_in_a_Stream.py # add(value): Insert a value into the HashSet.
# contains(value) : Return whether the value exists in the HashSet or not.
_author_ = 'jake' # remove(value): Remove a value in the HashSet. If the value does not exist in the HashSet, do nothing.
_project_ = 'leetcode'
# Use list of size 10000 since there are at most 10000 operations so we will not fill every element. There may be
# https://leetcode.com/problems/kth-largest-element-in-a-stream/ # collisions, which are handled by separate chaining. Use a simple modulo hash function.
# Design a class to find the kth largest element in a stream. # Time - O(1) average case
# Note that it is the kth largest element in the sorted order, not the kth distinct element. # Space - O(n)
# Your KthLargest class will have a constructor which accepts an integer k and an integer array nums,
# which contains initial elements from the stream. For each call to the method KthLargest.add, class MyHashSet(object):
# return the element representing the kth largest element in the stream.
def __init__(self):
# Create a heap of nums and if there are more than k elements, pop off small elements until it has the k largest. """
# If val cannot change kth largest, discard it and return kth largest. Else insert val, pop off an element if the Initialize your data structure here.
# heap is too big and return the kth largest. """
# Time - O(n + (n - k)log n) for __init__ to heapify and pop off excess elements, O(log k) for add self.size = 10000
# Space - O(k) self.hashset = [[] for _ in range(self.size)]
# python_1_to_1000/706_Design_HashMap.py
def __init__(self): original_head = head # save so can be returned and can tell if full cycle traversed
"""
Initialize your data structure here. while True:
"""
if head.next.val > head.val: # next node is increasing # For each of the 8 possible rotations and rotation + reflections, manipulate the island then translate so the top left
if insertVal >= head.val and insertVal <= head.next.val: # check if insertVal between node vals # cell of the enclosing rectangle is (0, 0). Sort the resulting cells and set the canonical representation to be the
break # maximum.
elif head.next.val < head.val: # next node is decreasing # Time - O(mn * log(mn))
if insertVal >= head.val or insertVal <= head.next.val: # check if insertVal beyond range of cycles # Space - O(mn)
break
elif head.next == original_head: # all nodes same value , insert anywhere class Solution(object):
break def numDistinctIslands2(self, grid):
"""
head = head.next :type grid: List[List[int]]
:rtype: int
insert_after(head) """
return (original_head) if not grid or not grid[0]:
return 0
return "".join(chr(ord(c) + diff) if "A" <= c <= "Z" else c for c in str) reflected = [(r, -c) for r, c in queue] # reflect
min_r, min_c = min([r for r, _ in reflected]), min([c for _, c in reflected])
canonical = max(canonical, sorted([(r - min_r, c - min_c) for r, c in reflected]))
# python_1_to_1000/710_Random_Pick_with_Blacklist.py - h
return tuple(canonical) # tuple allows hashing in set
_author_ = 'jake'
_project_ = 'leetcode' islands = set()
for r in range(rows):
# https://leetcode.com/problems/random-pick-with-blacklist/ for c in range(cols):
# Given a blacklist B containing unique integers from [0, N), write a function to return a uniform random integer if grid[r][c] == 0:
# from [0, N) which is NOT in B. continue
# Optimize it such that it minimizes the call to system’s Math.random(). islands.add(BFS(r, c))
# Create a mapping so that all of the allowed numbers are together. Make the first part of the array the allowed return len(islands)
# whitelist. Find a list of all white numbers that are not in the first part of the array. For each black number that
# is in the first part of the array, map it to a white number that is not in the first part.
# Pick random indices from the length of the whitelist. If a number is mapped from black to white, return its mapping # python_1_to_1000/712_Minimum_ASCII_Delete_Sum_for_Two_Strings.py - m
# else the number is not blacklisted so return it.
# Time - O(n) for init, O(1) for pick. _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'
for i in range(len(s1)):
# python_1_to_1000/711_Number_of_Distinct_Islands_II.py - h
new_dp = [dp[0] + ord(s1[i])] # empty prefix of s2, cost is sum of chars in prefix of s1
_author_ = 'jake'
_project_ = 'leetcode' for j in range(len(s2)):
if s1[i] == s2[j]: # delete neither character
# https://leetcode.com/problems/number-of-distinct-islands-ii/ new_dp.append(dp[j])
# Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected else: # delete either character
# 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. new_dp.append(min(ord(s1[i]) + dp[j + 1], ord(s2[j]) + new_dp[-1]))
# Count the number of distinct islands. An island is considered to be the same as another if they have the same
# shape, or have the same shape after rotation (90, 180, or 270 degrees only) or reflection (left/right direction dp = new_dp
# or up/down direction).
return dp[-1]
# Iterate over array, for each cell with 1 breadth-first search to find a list of all connected cells forming an island.
# Space - O(n)
# python_1_to_1000/713_Subarray_Product_Less_Than_K.py - m
import bisect
_author_ = 'jake'
_project_ = 'leetcode' class RangeModule(object):
def __init__(self):
# https://leetcode.com/problems/subarray-product-less-than-k/ self.points = [0, 10 ** 9] # list of points (not necessarily always ends of ranges after mergers)
# You are given an array of positive integers nums. Count and print the number of (contiguous) subarrays where the self.in_range = [False, False] # is ends[i] and points to ends[i + 1] in a range
# product of all the elements in the subarray is less than k.
def addRange(self, left, right, add=True):
# Maintain a window with product <= k. For each num, add to window product. While window contains some nums and """
# product is too large, remove from window start. Increment result by window length since each subarray ending at end :type left: int
# is valid. If start > end then product == 1. :type right: int
# Time - O(n) :rtype: void
# Space - O(1) """
i = bisect.bisect_left(self.points, left) # find insertion index of left in list of points
class Solution(object): if self.points[i] != left: # if left does not exist in the list already
def numSubarrayProductLessThanK(self, nums, k): self.points.insert(i, left) # insert left to sorted list of points
""" self.in_range.insert(i, self.in_range[i - 1]) # will be overwritten but required when inserting right
:type nums: List[int]
:type k: int j = bisect.bisect_left(self.points, right)
:rtype: int if self.points[j] != right:
""" self.points.insert(j, right)
subarrays = 0 self.in_range.insert(j, self.in_range[j - 1]) # right is in_range if point before it was
start = 0 # index of window start
product = 1 # current product self.points[i:j] = [left] # consolidate points i to (but excluding) j
self.in_range[i:j] = [add] # consolidate in_range
for end, num in enumerate(nums):
def queryRange(self, left, right):
product *= num """
:type left: int
while product >= k and start <= end: # remove from window if product too large and window non-zero :type right: int
product //= nums[start] :rtype: bool
start += 1 """
i = bisect.bisect(self.points, left) - 1 # if left is a point then we include it, else get the previous point
subarrays += end - start + 1 # if start = end + 1 then nothing added j = bisect.bisect_left(self.points, right) # ony check points before right
return all(self.in_range[i:j])
return subarrays
def removeRange(self, left, right):
"""
# python_1_to_1000/714_Best_Time_to_Buy_and_Sell_Stock_with_Transaction_Fee.py - m :type left: int
:type right: int
_author_ = 'jake' :rtype: void
_project_ = 'leetcode' """
self.addRange(left, right, False)
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
# You are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a
# non-negative integer fee representing a transaction fee. # python_1_to_1000/716_Max_Stack.py - h
# You may complete as many transactions as you like, but you need to pay the transaction fee for each sale.
# You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.) _author_ = 'jake'
# Return the maximum profit you can make. _project_ = 'leetcode'
# Track most cash after buying at current price and most cash after selling at current price. Most cash after buying is # https://leetcode.com/problems/max-stack/
# higher of previous most and cash after buying here = sell - price. Most cash after selling is higher of previous most # Design a max stack that supports push, pop, top, peekMax and popMax.
# and cash after selling here = buy + price - fee. # push(x) -- Push element x onto stack.
# Time - O(n) # pop() -- Remove the element on top of the stack and return it.
# Space - O(1) # top() -- Get the element on the top.
# peekMax() -- Retrieve the maximum element in the stack.
class Solution(object): # popMax() -- Retrieve the maximum element in the stack, and remove it. If you find more than one maximum elements,
def maxProfit(self, prices, fee): # only remove the top-most one.
"""
:type prices: List[int] # Stack contains tuples of (element, max element in stack). To popMax, pop until an element equal to max is seen. Then
:type fee: int # push back all elements before max in reverse order.
:rtype: int # Time - O(1) for all operations apart from O(n) for popMax
""" # Space - O(n)
buy, sell = float("-inf"), 0
class MaxStack(object):
for price in prices: def __init__(self):
buy, sell = max(buy, sell - price), max(sell, buy + price - fee) """
initialize your data structure here.
return sell """
self.stack = [(float("-inf"), float("-inf"))] # pairs of (num, max_num)
while x != target: # Sort nums. Binary search for the smallest difference that has at least k pairs. For mid difference, check if
temp.append(x) # k or more piars have that difference. If so, reduce hihg to mid, else increase low to mid + 1.
x, _ = self.stack.pop() # Count number of differences <= diff by iterating over nums and for each num finding the first other num <= diff.
# Time - O(n log n)
for x in reversed(temp): # Space - O(n)
self.push(x)
class Solution(object):
return target def smallestDistancePair(self, nums, k):
"""
:type nums: List[int]
# python_1_to_1000/717_1-bit_and_2-bit_Characters.py :type k: int
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode'
def k_pair_distances(diff):
# https://leetcode.com/problems/1-bit-and-2-bit-characters/ count, j = 0, 0
# We have two special characters. The first character can be represented by one bit 0. for i, num in enumerate(nums): # each starting num
# The second character can be represented by two bits (10 or 11). while num - nums[j] > diff: # increase j until distance <= diff
# Now given a string represented by several bits. Return whether the last character must be a one-bit character or not. j += 1
# The given string will always end with a zero. count += i - j # add all pairs
return count >= k
# If the first bit is 1, it must be a 2-bit character so move 2 spaces forwards. Else move one space forwards.
# Time - O(n) nums.sort()
# Space - O(1) left, right = 0, nums[-1] - nums[0]
return i == len(bits) - 1
# python_1_to_1000/720_Longest_Word_in_Dictionary.py - m
if mutual_subarray(mid): # mid has mutual subarray so search above mid next_candidates = set()
low = mid + 1
else: for longer_word in length_to_words[length + 1]: # check if each longer word can be built from any candidate
high = mid # mid does not have mutual subarray so search mid and below if longer_word[:-1] in candidates:
next_candidates.add(longer_word)
# Iterate over text, checking the string of the next 2 chars. Set comment_block according to opening and closing
if not next_candidates: # comments. At end of line, if not in a comment_block then add to result.
return sorted(list(candidates))[0] # sort to return lexicographically lowest # Time - O(n), total number of chars
# Space - O(n)
length += 1
candidates = next_candidates class Solution(object):
def removeComments(self, source):
"""
# python_1_to_1000/721_Accounts_Merge.py - m :type source: List[str]
:rtype: List[str]
_author_ = 'jake' """
_project_ = 'leetcode' removed = []
comment_block = False
# https://leetcode.com/problems/accounts-merge/ new_line = []
# Given a list accounts, each element accounts[i] is a list of strings, where the first element accounts[i][0] is a
# name, and the rest of the elements are emails representing emails of the account. for line in source:
# Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email i = 0
# that is common to both accounts. Note that even if two accounts have the same name, they may belong to different
# people as people could have the same name. A person can have any number of accounts initially, but all of their while i < len(line):
# accounts definitely have the same name.
# After merging the accounts, return the accounts in the following format: the first element of each account is the test = line[i:i + 2]
# name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order. if not comment_block and test == "/*": # do not skip if in block to handle "/*/"
comment_block = True # else skip 2 chars
# Create mapping from email to list of accounts with that email. For each account dfs to visit the accounts of its i += 2
# emails recursively. elif not comment_block and test == "//": # skip to end of line
# Time - O(n log n) where n is total number of emails. Each email visited once, then list sorted. i = len(line)
# Space - O(n) elif comment_block and test == "*/": # end block, skip 2 chars
comment_block = False
from collections import defaultdict i += 2
elif comment_block: # ignore char
class Solution(object): i += 1
def accountsMerge(self, accounts): else: # add char to result
""" new_line.append(line[i])
:type accounts: List[List[str]] i += 1
:rtype: List[List[str]]
""" if not comment_block and new_line: # newline char is not commented out
email_to_account = defaultdict(list) # email to list of account indices containing that email removed.append("".join(new_line))
new_line = []
for i, account in enumerate(accounts):
for email in account[1:]: if new_line: # add final text
email_to_account[email].append(i) removed.append("".join(new_line))
return removed
result = []
visited = [False for _ in range(len(accounts))]
def dfs(i):
emails = set() # python_1_to_1000/723_Candy_Crush.py - m
if visited[i]:
return emails _author_ = 'jake'
visited[i] = True _project_ = 'leetcode'
for email in accounts[i][1:]:
emails.add(email) # https://leetcode.com/problems/candy-crush/
for account in email_to_account[email]: # This question is about implementing a basic elimination algorithm for Candy Crush.
emails |= dfs(account) # union existing and new emails # Given a 2D integer array board representing the grid of candy, different positive integers board[i][j] represent
return emails # different types of candies. A value of board[i][j] = 0 represents that the cell at position (i, j) is empty. The
# given board represents the state of the game following the player's move. Now, you need to restore the board to a
for i, account in enumerate(accounts): # stable state by crushing candies according to the following rules:
emails = dfs(i) # If three or more candies of the same type are adjacent vertically or horizontally, "crush" them all at the same
if emails: # time - these positions become empty.
result.append([account[0]] + sorted(list(emails))) # After crushing all candies simultaneously, if an empty space on the board has candies on top of itself, then these
# candies will drop until they hit a candy or bottom at the same time. (No new candies will drop outside the
return result # top boundary.)
# After the above steps, there may exist more candies that can be crushed. If so, you need to repeat the above steps.
# If there does not exist more candies that can be crushed (ie. the board is stable), then return the current board.
# You need to perform the above rules until the board becomes stable, then return the current board.
# Iterate over board setting to_crush for rows or columns of 3 identical (but not empty) candies. If nothing found,
# python_1_to_1000/722_Remove_Comments.py - m # return board. For each column, create a new empty column and fill from bottom up with candies that are not crushed.
# Time - O((mn)**2), mn per cycle with mn // 3 max cycles.
_author_ = 'jake' # Space - O(mn)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/remove-comments/ def candyCrush(self, board):
# Given a C++ program, remove comments from it. The program source is an array where source[i] is the i-th line of the """
# source code. This represents the result of splitting the original source code string by the newline character \n. :type board: List[List[int]]
# In C++, there are two types of comments, line comments, and block comments. :rtype: List[List[int]]
# The string // denotes a line comment, which represents that it and rest of the characters to the right of it in the """
# same line should be ignored. rows, cols = len(board), len(board[0])
# The string /* denotes a block comment, which represents that all characters until the next (non-overlapping)
# occurrence of */ should be ignored. (Here, occurrences happen in reading order: line by line from left to right.) while True:
# To be clear, the string /*/ does not yet end the block comment, as the ending would be overlapping the beginning.
# The first effective comment takes precedence over others: if the string // occurs in a block comment, it is ignored. stable = True
# Similarly, if the string /* occurs in a line or block comment, it is also ignored. to_crush = [[False for _ in range(cols)] for _ in range(rows)] # flag which cells to crush
# If a certain line of code is empty after removing comments, you must not output that line: each string in the answer
# list will be non-empty. for c in range(cols):
# There will be no control characters, single quote, or double quote characters. For example, for r in range(rows):
# source = "string s = "/* Not a comment. */";" will not be a test case. (Also, nothing else such as defines or macros # check vertical
# will interfere with the comments.) if r < rows - 2 and board[r][c] == board[r + 1][c] == board[r + 2][c] and board[r][c] != 0:
# It is guaranteed that every open block comment will eventually be closed, so /* outside of a line or block comment to_crush[r][c] = to_crush[r + 1][c] = to_crush[r + 2][c] = True
# always starts a new comment. stable = False
# Finally, implicit newline characters can be deleted by block comments. Please see the examples below for details. # check horizontal
# After removing the comments from the source code, return the source code in the same format. if c < cols - 2 and board[r][c] == board[r][c + 1] == board[r][c + 2] and board[r][c] != 0:
to_crush[r][c] = to_crush[r][c + 1] = to_crush[r][c + 2] = True
stable = False
part_length, odd_parts = divmod(count, k)
if stable: # nothing to crush result = []
return board prev, node = None, root
return result
# python_1_to_1000/724_Find_Pivot_Index.py
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/726_Number_of_Atoms.py - h
# python_1_to_1000/729_My_Calendar_I.py - m
# python_1_to_1000/727_Minimum_Window_Substring.py - h
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/my-calendar-i/
# https://leetcode.com/problems/minimum-window-subsequence/ # Implement a MyCalendar class to store your events. A new event can be added if adding the event will not cause a
# Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequence of W. # double booking.
# If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple # Your class will have the method, book(int start, int end). Formally, this represents a booking on the half open
# such minimum-length windows, return the one with the left-most starting index. # interval [start, end), the range of real numbers x such that start <= x < end.
# A double booking happens when two events have some non-empty intersection (ie., there is some time that is common to
# Find all indices in S matching the first letter of T and create a list of windows. For each letter of T, for each # both events.)
# window find the next letter of S that matches the letter and extend the window. If the letter is not found, remove # For each call to the method MyCalendar.book, return true if the event can be added to the calendar successfully
# the window. Return the smallest window. # without causing a double booking. Otherwise, return false and do not add the event to the calendar.
# Time - O(mn), worst case when all letters are identical means len(S) windows # Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)
# Space - O(m)
# Create sorted list of events. Binary search for position to insert new event and do so if no overlap with previous
class Solution(object): # or next events.
def minWindow(self, S, T): # Time - O(n**2)
""" # Space - O(n)
:type S: str
:type T: str import bisect
:rtype: str
""" class MyCalendar(object):
next_in_s = [None for _ in range(len(S))] # next_in_s[i][j] is the next occurrence of letter j in S[i + 1:]
next_by_letter = [-1 for _ in range(26)] # or -1 if not found def __init__(self):
for i in range(len(S) - 1, -1, -1): self.bookings = [(float("-inf"), float("-inf")), (float("inf"), float("inf"))]
next_in_s[i] = next_by_letter[:]
next_by_letter[ord(S[i]) - ord("a")] = i def book(self, start, end):
"""
# matches is a list of windows [i, j] where i is the index in S matching the first char of T :type start: int
# and j is the index matching the current char of T :type end: int
matches = [[i, i] for i, c in enumerate(S) if c == T[0]] :rtype: bool
if not matches: """
return "" i = bisect.bisect_left(self.bookings, (start, end))
return helper(0, len(S) - 1) - 1 # remove empty string while end > self.bookings[i][0]: # increment all intervals before end
self.bookings[i][1] += 1
self.max_booking = max(self.max_booking, self.bookings[i][1])
# python_1_to_1000/731_My_Calendar_II.py - m i += 1
# Maintain a sorted list bookings of x values where the number of events changes. Each entry [x, n] represents n return image
# overlapping events from point x until the next element of the bookings list.
# Time - O(n**2)
# Space - O(n)
# python_1_to_1000/734_Sentence_Similarity.py
import bisect
_author_ = 'jake'
class MyCalendarThree(object): _project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/sentence-similarity/ _project_ = 'leetcode'
# Given two sentences words1, words2 (each represented as an array of strings), and a list of similar word pairs pairs,
# determine if two sentences are similar. # https://leetcode.com/problems/parse-lisp-expression/
# For example, "great acting skills" and "fine drama talent" are similar, if the similar word pairs are pairs = # You are given a string expression representing a Lisp-like expression to return the integer value of.
# [["great", "fine"], ["acting","drama"], ["skills","talent"]]. # The syntax for these expressions is given as follows.
# Note that the similarity relation is not transitive. For example, if "great" and "fine" are similar, and "fine" # An expression is either an integer, a let-expression, an add-expression, a mult-expression, or an assigned variable.
# and "good" are similar, "great" and "good" are not necessarily similar. # Expressions always evaluate to a single integer. (An integer could be positive or negative.)
# However, similarity is symmetric. E.g., "great" and "fine" means that "fine" and "great" are similar. # A let-expression takes the form (let v1 e1 v2 e2 ... vn en expr), where let is always the string "let", then there
# Also, a word is always similar with itself. # are 1 or more pairs of alternating variables and expressions, meaning that the first variable v1 is assigned the
# Finally, sentences can only be similar if they have the same number of words. # value of the expression e1, the second variable v2 is assigned the value of the expression e2, and so on
# sequentially; and then the value of this let-expression is the value of the expression expr.
# Create a mapping from a word to the set of similar words. Check each word of words1 against the word of the same # An add-expression takes the form (add e1 e2) where add is always the string "add", there are always two
# index in words2 and vica versa. If words are same, continue. # expressions e1, e2, and this expression evaluates to the addition of the evaluation of e1 and the evaluation of e2.
# Else if there is no mapping between the words, return False. # A mult-expression takes the form (mult e1 e2) where mult is always the string "mult", there are always two
# Time - O(m + n), len(pairs) + len(words) # expressions e1, e2, and this expression evaluates to the multiplication of the evaluation of e1 and the evaluation
# Space - O(m) # of e2.
# For the purposes of this question, we will use a smaller subset of variable names. A variable starts with a
from collections import defaultdict # lowercase letter, then zero or more lowercase letters or digits. Additionally for your convenience, the names
# "add", "let", or "mult" are protected and will never be used as variable names.
class Solution(object): # Finally, there is the concept of scope. When an expression of a variable name is evaluated, within the context of
def areSentencesSimilar(self, words1, words2, pairs): # that evaluation, the innermost scope (in terms of parentheses) is checked first for the value of that variable,
""" # and then outer scopes are checked sequentially. It is guaranteed that every expression is legal.
:type words1: List[str]
:type words2: List[str] # Split the input by spaces. This gives a list of tokens, which may be operators, variables or integers. Brackets
:type pairs: List[List[str]] # may be present before or after a token.
:rtype: bool # Create a stack of dictionaries. The top of the stack is dictionary mapping variables to their values in the current
""" # scope.
if len(words1) != len(words2): # The helper function takes an index in the list of tokens and returns the value of the expression from that token
return False # until the corresponding closing bracket. It also return the index of the next token after the closing bracket.
# The helper function first removes any opening bracket from the the current token. If there is an opening bracket then
similar = defaultdict(set) # we have moved up a level of scope, so copy all the previous variables in scope into a new dictionary.
for w1, w2 in pairs: # Count and remove the closing brackets.
similar[w1].add(w2) # map one way only # Then there are 5 cases:
# Integer - return its value.
for w1, w2 in zip(words1, words2): # Add - parse the next expression and subsequent expression then add them.
# Mult - parse the next expression and subsequent expression then multiply them them.
if w1 == w2: # samewords are always similar # Let - for every pair of variable / expression, map the variable to the evaluates expression's value. The continue_let
continue # function determines whether this is the final expression to be returned.
# Variable - find its value from the mapping.
if (w1 not in similar or w2 not in similar[w1]) and (w2 not in similar or w1 not in similar[w2]): # Along with the return value we always also return the index of the next token to parse.
return False # Before returning we pop off and discard any scopes that are removed due to closing brackets.
# Time - O(n)
return True # Space - O(n**2), dictionaries may repeat the same variable
class Solution(object):
def evaluate(self, expression):
# python_1_to_1000/735_Asteroid_Collision.py - m """
:type expression: str
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
tokens = expression.split(" ") # list of operators, variables and integers
scopes = [{}] # stack of dictionaries
# https://leetcode.com/problems/asteroid-collision/
# We are given an array asteroids of integers representing asteroids in a row. def helper(start): # returns (value of expression, next index to parse)
# For each asteroid, the absolute value represents its size, and the sign represents its direction (positive meaning
# right, negative meaning left). Each asteroid moves at the same speed. if start >= len(tokens): # base case
# Find out the state of the asteroids after all collisions. If two asteroids meet, the smaller one will explode. return 0, start
# If both are the same size, both will explode. Two asteroids moving in the same direction will never meet.
operator = tokens[start]
# Stack consists of a stable configuration of asteroids. For each new asteroid add to stack if no collision. Else if operator[0] == "(": # remove opening bracket if any
# determine which to destroy. If top of stack is destroyed then repeat. operator = operator[1:]
# Time - O(n) scopes.append(dict(scopes[-1])) # move up a level of scope, including all previous variables
# Space - O(n)
closing_brackets = 0
class Solution(object): while operator[len(operator) - 1 - closing_brackets] == ")": # remove and count closing brackets if any
def asteroidCollision(self, asteroids): closing_brackets += 1
""" if closing_brackets > 0:
:type asteroids: List[int] operator = operator[:-closing_brackets]
:rtype: List[int]
""" if operator.isdigit() or operator[0] == "-" and operator[1:].isdigit():
stack = [] result = int(operator), start + 1
_author_ = 'jake' # Create a sorted list of nums and their frequencies. Iterate over the list, calculating the max points if a num is
_project_ = 'leetcode' # used and the max if it is not used. If not previous num or previous is not num - 1 then we can choose the max of
# used and not_used for the new not_sed, addind the points from this num for the new used. If previous is num - 1
# https://leetcode.com/problems/monotone-increasing-digits/ # then new used must be not_used + points from num. Again, not_sed chan chosse max of previous used and previous
# Given a non-negative integer N, find the largest number that is less than or equal to N with monotone # not_used.
# increasing digits. Recall that an integer has monotone increasing digits if and only if each pair of adjacent # Time - O(n log n)
if best_time == float("inf"): # best_node has not been reached def f(self, prefix, suffix):
return -1 """
nodes.remove(next_node) # cannot improve time to reach this node :type prefix: str
:type suffix: str
for nbor, time in network[next_node]: # update times to reach neighbours :rtype: int
best_times[nbor] = min(best_times[nbor], best_time + time) """
# Create a trie to store each word in its usual order (forwards) and a trie to store each word backwards. for c in cost[2:]:
# Find the sets of all words that match prexis and suffix from their respective tries. Take the max weight from the prev, step = step, c + min(prev, step)
# set intersection.
# Time - O(n) to __init__ where n is the total umber of chars in all words. O(p + s + k) where p = len(prefix), return min(prev, step) # finish at last or penultimate step
# s = len(suffix), k = number of words.
# Space - O(n)
# python_1_to_1000/747_Largest_Number_At_Least_Twice_of_Others.py
class WordFilter(object):
_author_ = 'jake'
def __init__(self, words): _project_ = 'leetcode'
"""
:type words: List[str] # https://leetcode.com/problems/largest-number-at-least-twice-of-others/
""" # In a given integer array nums, there is always exactly one largest element.
self.prefix_root = [set(), [None for _ in range(26)]] # trie node is set of words and list of next nodes # Find whether the largest element in the array is at least twice as much as every other number in the array.
self.suffix_root = [set(), [None for _ in range(26)]] # for each char # If it is, return the index of the largest element, otherwise return -1.
self.weights = {} # map word to weight
# Iterate over nums, tracking the index of the largest num seen and the second largest num seen.
def insert(word, forwards): # insert a word into a trie # Time - O(n)
if forwards: # Space - O(1)
node = self.prefix_root
iterate_word = word class Solution(object):
else: def dominantIndex(self, nums):
node = self.suffix_root """
iterate_word = word[::-1] :type nums: List[int]
:rtype: int
node[0].add(word) """
for c in iterate_word: first_i = 0 # index of largest num
if not node[1][ord(c) - ord("a")]: # create a new node of None second = 0 # second largest num
node[1][ord(c) - ord("a")] = [set(), [None for _ in range(26)]]
word_freq = Counter(word)
# python_1_to_1000/750_Number_Of_Corner_Rectangles.py - m
for c, count in freq.items():
if c not in word_freq or word_freq[c] < count: _author_ = 'jake'
break _project_ = 'leetcode'
else:
return word # https://leetcode.com/problems/number-of-corner-rectangles/
# Given a grid where each entry is only 0 or 1, find the number of corner rectangles.
# A corner rectangle is 4 distinct 1s on the grid that form an axis-aligned rectangle.
# python_1_to_1000/749_Contain_Virus.py - h # Note that only the corners need to have the value 1. Also, all four 1s used must be distinct.
_author_ = 'jake' # For each row, find the set of column indices that are 1 in the grid. Then for each pair of rows, find the common
_project_ = 'leetcode' # columns and caclulate the numbe of rectangles as each uniqie pair.
# Time - O(m**2 n)
# https://leetcode.com/problems/contain-virus/ # Space - O(mn)
# A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls.
# The world is modeled as a 2-D array of cells, where 0 represents uninfected cells, and 1 represents cells class Solution(object):
# contaminated with the virus. A wall (and only one wall) can be installed between any two 4-directionally adjacent def countCornerRectangles(self, grid):
# cells, on the shared boundary. """
# Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. :type grid: List[List[int]]
# Resources are limited. Each day, you can install walls around only one region -- the affected area (continuous :rtype: int
# block of infected cells) that threatens the most uninfected cells the following night. There will never be a tie. """
# Can you save the day? If so, what is the number of walls required? If not, and the world becomes fully infected, rows, cols = len(grid), len(grid[0])
# return the number of walls used. cols_by_row = []
# Iterate over grid, finding regions of virus with dfs. For each region find its empty neighbours and walls required for r in range(rows):
# to contain it. Contain the region with most neighbours by setting grid cells to 2 and increment wall count. cols_by_row.append(set((c for c in range(cols) if grid[r][c])))
# Infect neighbours of of other regions. Repeat until no uninfected uncontained regions or no more infection possible.
# Time - O(mn * min(m, n)), mn for main loop, at most min(m, n) iterations since expansion by 1 row and col per round rectangles = 0
# Space - O(mn)
for high_row in range(1, rows):
class Solution(object): for low_row in range(high_row):
def containVirus(self, grid): common_cols = len(cols_by_row[high_row] & cols_by_row[low_row])
""" if common_cols >= 2:
:type grid: List[List[int]] rectangles += common_cols * (common_cols - 1) // 2
:rtype: int
""" return rectangles
rows, cols = len(grid), len(grid[0])
used_walls = 0
# python_1_to_1000/751_IP_to_CIDR.py - m
def get_nbors(r, c): # find all neighbouring empty cells and number of walls to contain a region
if (r, c) in visited: _author_ = 'jake'
return _project_ = 'leetcode'
visited.add((r, c))
# https://leetcode.com/problems/ip-to-cidr/
# Given a start IP address ip and a number of ips we need to cover n, return a representation of the range as a list if combo in visited or combo in deadends:
# (of smallest possible length) of CIDR blocks. continue # ignore combinations seen before or not allowed
# A CIDR block is a string consisting of an IP, followed by a slash, and then the prefix length. visited.add(combo)
# For example: "123.45.67.89/20". Prefix length "20" represents the number of common prefix bits in the specified range. new_queue |= shift(combo) # add all shifted combinations
# Convert IP to an integer and convert back when adding to results. Add to the result a block of addresses. The block queue, target = target, new_queue # update queue and swap queue with target
# either covers all of n or all addresses until the least significant bit of the ip address changes.
# Time - O(n) return -1
# Space - O(1)
class Solution(object):
def ipToCIDR(self, ip, n): # python_1_to_1000/753_Cracking_the_Safe.py - h
"""
:type ip: str _author_ = 'jake'
:type n: int _project_ = 'leetcode'
:rtype: List[str]
""" # https://leetcode.com/problems/cracking-the-safe/
results = [] # There is a box protected by a password. The password is n digits, where each letter can be one of the first
# k digits 0, 1, ..., k-1.
def num_to_ip(num): # convert and integer to an IP address # You can keep inputting the password, the password will automatically be matched against the last n digits entered.
ip = [] # For example, assuming the password is "345", I can open it when I type "012345", but I enter a total of 6 digits.
for _ in range(4): # Please return any string of minimum length that is guaranteed to open the box after the entire string is inputted.
num, byte = divmod(num, 256)
ip.append(str(byte)) # Create a directed graph where each node is the last n-1 digits of the pattern used and each node has k outgoing edges
return ".".join(ip[::-1]) # each labeled by a digit such that node + edge represents a pattern (i.e. a password attempt).
# We need to find a Euler cycle that visits every edge of this graph.
ip_num = 0 # From a node, take each edge in turn and if pattern has not been seen already then explore from the next node with
for byte in ip.split("."): # convert the IP address to an integer # depth first search until we reach a dead end, which must be on the current cycle since each node has the same
ip_num = ip_num * 256 + int(byte) # number of incoming and outgoing edges. Record the digit of the last edge in the result, then back-up within the cycle,
# taking alternative paths.
while n > 0: # Time - O(n * k**n) since k**n patterns each of length n
mask = 33 - min((ip_num & -ip_num).bit_length(), n.bit_length()) # Space - O(n * k**n)
# Bidirectional breadth-first search. From the starting position, move one wheel to all next positions. Expand frontier
# until target is found, ignoring deadends and already seen combinations. Swap queue with target after every iteration
# to limit the size of the frontier.
# Time - O(1), limit of 10000 possible combinations # python_1_to_1000/754_Reach_a_Number.py - m
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def openLock(self, deadends, target):
""" # https://leetcode.com/problems/reach-a-number/
:type deadends: List[str] # You are standing at position 0 on an infinite number line. There is a goal at position target.
:type target: str # On each move, you can either go left or right. During the n-th move (starting from 1), you take n steps.
:rtype: int # Return the minimum number of steps required to reach the destination.
"""
queue, target = {"0000"}, {target} # Take steps until we reach or go past target. position = steps * (steps + 1) // 2. Invert this and solve quadratic
visited = set() # polynomial to find the number of steps to reach or exceed position. If we are at exact target or an even number
deadends = set(deadends) # of steps away then can reach target by inverting the sign of some moves. Else take one or two more steps until we
steps = 0 # are an even number of moves from target.
# Time - O(1)
def shift(combo): # find all combinations that can be reached by moving one wheel # Space - O(1)
shifts = set()
for i, c in enumerate(combo): # for each wheel import math
shifted = (int(c) + 1) % 10 # move up
shifts.add(combo[:i] + str(shifted) + combo[i + 1:]) class Solution(object):
shifted = (int(c) - 1) % 10 # move down def reachNumber(self, target):
shifts.add(combo[:i] + str(shifted) + combo[i + 1:]) """
return shifts :type target: int
:rtype: int
while queue: """
target = abs(target) # symmetry of positive and negative solutions
if target & queue: # intersection between queue and target
return steps steps = int(math.ceil((math.sqrt(1 + 8 * target) - 1) / 2)) # ceil to round up
target -= steps * (steps + 1) // 2 # find remaining distance after steps
new_queue = set()
steps += 1 if target % 2 == 0: # includes target == 0
return steps
for combo in queue:
class Solution(object):
def pourWater(self, heights, V, K): # python_1_to_1000/757_Set_Intersection_Size_At_Least_Two.py - h
"""
:type heights: List[int] _author_ = 'jake'
:type V: int _project_ = 'leetcode'
:type K: int
:rtype: List[int] # https://leetcode.com/problems/set-intersection-size-at-least-two/
""" # An integer interval [a, b] (for integers a < b) is a set of all consecutive integers from a to b, including a and b.
heights = [float("inf")] + heights + [float("inf")] # pad before and after with infinite walls # Find the minimum size of a set S such that for every integer interval A in intervals, the intersection of S with A
K += 1 # has size at least 2.
while V > 0: # iterate over drops # Sort intervals by ascending end point. Iterate over intervals. If the current interval starts after the previous
V -= 1 # intersection points then add to the intersection the end and end - 1. These are the maximum values in order to
# maximise overlaps with future intervals, which all end at the same or greater values. Or else if the second largest
i = K # value in intersection is outside the interval, add the interval end point. Or else the last 2 values from intersection
lowest, lowest_i = heights[K], K # are included in interval so no action required.
while heights[i - 1] <= lowest: # move left if same or lower # Time - O(n log n)
i -= 1 # Space - O(n)
if heights[i] < lowest: # update lowest seen
lowest, lowest_i = heights[i], i class Solution(object):
def intersectionSizeTwo(self, intervals):
if lowest < heights[K]: # fallen on left, no need to look right """
heights[lowest_i] += 1 :type intervals: List[List[int]]
continue :rtype: int
"""
i = K intervals.sort(key=lambda x: x[1])
lowest, lowest_i = heights[K], K intersection = []
while heights[i + 1] <= lowest:
i += 1 for start, end in intervals:
if heights[i] < lowest:
lowest, lowest_i = heights[i], i if not intersection or start > intersection[-1]:
intersection.append(end - 1)
if lowest < heights[K]: intersection.append(end)
heights[lowest_i] += 1 elif start > intersection[-2]:
else: intersection.append(end)
heights[K] += 1 # else previous 2 points in intersection are already in interval
# python_1_to_1000/756_Pyramid_Transition_Matrix.py - m # python_1_to_1000/758_Bold_Words_in_String.py - m
# https://leetcode.com/problems/pyramid-transition-matrix/ # https://leetcode.com/problems/bold-words-in-string/
# We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, like `'Z'`. # Given a set of keywords words and a string S, make all appearances of all keywords in S bold. Any letters between
# For every block of color `C` we place not in the bottom row, we are placing it on top of a left block of color `A` # <b> and </b> tags become bold.
# and right block of color `B`. We are allowed to place the block there only if `(A, B, C)` is an allowed triple. # The returned string should use the least number of tags possible, and of course the tags should form a
# We start with a bottom row of bottom, represented as a single string. We also start with a list of allowed triples # valid combination.
# allowed. Each allowed triple is represented as a string of length 3.
# Return true if we can build the pyramid all the way to the top, otherwise false. # For each word, attempt to match with string. If match found, flag that matched chars should be bold then check again
# if word matches next starting position in S until word does not match S.
# Create a mapping from a pair of blocks to a list allowed blocks on top. Then depth-first search for the next block. # Then iterate over S creating the result by inserting opening and closing tags amongst chars when flag changes to or
# If a completed row has one block, we have found the top of the pyramid. If a row has one less block than the previous # from bold.
# row then start the next row. Else find a list of possible next blocks. If there are none then we cannot find any # Time - O(n * m) for S of length n and m chars in all words.
# solution. If any of the next blocks allows us to fill the pyramid then there is a solution, else there is not. # Space - O(n)
# Time - O(k ** (n**2)) where k is the size of the alphabet and n == len(bottom). There are O(n**2) blocks to be added.
# Space - O(n**2) class Solution(object):
def boldWords(self, words, S):
from collections import defaultdict """
:type words: List[str] # Space - O(n)
:type S: str
:rtype: str class Solution(object):
""" def anagramMappings(self, A, B):
S = "#" + S + "#" # add unused letter to avoid special cases for first and last chars """
bold = [False for _ in range(len(S))] # flag which chars should be bold :type A: List[int]
:type B: List[int]
for word in words: :rtype: List[int]
i = S.find(word, 1) """
while i != -1: # while the word is found in S B_to_int = {}
bold[i:i + len(word)] = [True] * len(word) # set bold flags for i, b in enumerate(B):
i = S.find(word, i + 1) # search again for word in S from i + 1 B_to_int[b] = i
result = [] result = []
for a in A:
for i in range(len(S)): result.append(B_to_int[a])
if bold[i] and not bold[i - 1]: # change from not bold to bold, opening tag return result
result.append("<b>")
elif not bold[i] and bold[i - 1]: # change from bold to not vold, closing tag
result.append("</b>") # python_1_to_1000/761_Special_Binary_String.py - h
result.append(S[i])
_author_ = 'jake'
result = result[1:-1] # remove extra chars _project_ = 'leetcode'
return "".join(result)
# https://leetcode.com/problems/special-binary-string/
# Special binary strings are binary strings with the following two properties:
# python_1_to_1000/759_Employee_Free_Time.py - h # The number of 0's is equal to the number of 1's.
# Every prefix of the binary string has at least as many 1's as 0's.
_author_ = 'jake' # Given a special string S, a move consists of choosing two consecutive, non-empty, special substrings of S, and
_project_ = 'leetcode' # swapping them. (Two strings are consecutive if the last character of the first string is exactly one index before the
# first character of the second string.)
# https://leetcode.com/problems/employee-free-time/ # At the end of any number of moves, what is the lexicographically largest resulting string possible?
# We are given a list schedule of employees, which represents the working time for each employee.
# Each employee has a list of non-overlapping Intervals, and these intervals are in sorted order. # Create a list of all optimal special strings, sort in order of most starting 1s and join.
# Return the list of finite intervals representing common, positive-length free time for all employees, # To create an optimal special string, iterate over S finding the point there the next balance of 1s minus 0s falls to
# also in sorted order. # zero. Remove the leading 1 and trailing 0 and recurse on the middle part. Middle part is a special string because
# A) it has an equal number of 1s and 0s and B) if a prefix of the middle has one less 1 and 0, it will already be
# Maintain a heap of the next meeting start time for every employee. Pop the next meeting start time off the heap and # processed, so every prefix of middle has as many 1s as 0s, which is the definition of a special string.
# replace it with the next interval from that employee (if not the last interval). If start time is after last end time, # Time - O(n**2)
# there is free time so add interval to result. Update the last end time to end of this meeting if later than current # Space - O(n)
# last end time.
# Time - O(m log n) where n is the number of employees and m is the number of meetings. class Solution(object):
# Space - O(n) def makeLargestSpecial(self, S):
"""
import heapq :type S: str
:rtype: str
# Definition for an interval. """
class Interval(object): specials = []
def __init__(self, s=0, e=0):
self.start = s if not S:
self.end = e return ""
while next_start_times:
# python_1_to_1000/762_Prime_Number_of_Set_Bits_in_Binary_Representation.py
interval_start_time, interval, employee = heapq.heappop(next_start_times)
if interval + 1 < len(schedule[employee]): # add next interval for this employee to heap _author_ = 'jake'
heapq.heappush(next_start_times, (schedule[employee][interval + 1].start, interval + 1, employee)) _project_ = 'leetcode'
if interval_start_time > last_end_time: # free time between next start time and last end time # https://leetcode.com/problems/prime-number-of-set-bits-in-binary-representation/
result.append(Interval(last_end_time, interval_start_time)) # Given two integers L and R, find the count of numbers in the range [L, R] (inclusive) having a prime number of set
last_end_time = max(last_end_time, schedule[employee][interval].end) # update last end time # bits in their binary representation.
# The number of set bits an integer has is the number of 1s present when written in binary.
return result
# For each number in the range, convert to binary string, count the number of 1s and check if the count is prime.
# Time - O(n log n) where n == R
# Space - O(log n)
# python_1_to_1000/760_Find_Anagram_Mappings.py
class Solution(object):
_author_ = 'jake' def countPrimeSetBits(self, L, R):
_project_ = 'leetcode' """
:type L: int
# https://leetcode.com/problems/find-anagram-mappings/ :type R: int
# Given two lists on integers A and B where B is an anagram of A. :rtype: int
# We want to find an index mapping P, from A to B. A mapping P[i] = j means the ith element in A appears in B at index """
j. result = 0
# These lists A and B may contain duplicates. If there are multiple answers, output any of them. primes = {2, 3, 5, 7, 11, 13, 17, 19}
# Create a mapping from integers in b to their indices in b. If an integer is duplicated then the mapping if to the for i in range(L, R + 1):
# last index. For each num in a, look up its index in the mapping of indices in b. if bin(i).count("1") in primes:
# Time - O(n) result += 1
return result
# python_1_to_1000/765_Couples_Holding_Hands.py - h
# python_1_to_1000/764_Largest_Plus_Sign.py - m print(adjacency)
swaps = n # for each cycle of length x, require x - 1 swaps
_author_ = 'jake' # so swaps = n - number of cycles
_project_ = 'leetcode' for start in range(n):
class Solution(object):
def orderOfLargestPlusSign(self, N, mines): # python_1_to_1000/766_Toeplitz_Matrix.py
"""
:type N: int _author_ = 'jake'
:type mines: List[List[int]] _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/toeplitz-matrix/
mines = {(r, c) for r, c in mines} # convert to set for O(1) lookup # A matrix is Toeplitz if every diagonal from top-left to bottom-right has the same element.
distances = [[0 for _ in range(N)] for _ in range(N)] # min distance to mine in each of the 4 directions # Now given an M x N matrix, return True if and only if the matrix is Toeplitz.
plus = 0
# Iterate over matrix (in any order) apart from last row and last column. For each cell, check that it has the same
for r in range(N): # value as the cell to the bottom right.
distance = 0 # Time - O(mn)
for c in range(N): # Space - O(mn)
distance = 0 if (r, c) in mines else distance + 1 # update distance since last mine
distances[r][c] = distance class Solution(object):
def isToeplitzMatrix(self, matrix):
distance = 0 """
for c in range(N - 1, -1, -1): # reverse direction over rows :type matrix: List[List[int]]
distance = 0 if (r, c) in mines else distance + 1 :rtype: bool
distances[r][c] = min(distances[r][c], distance) """
rows, cols = len(matrix), len(matrix[0])
for c in range(N):
distance = 0 for r in range(rows - 1):
for r in range(N): for c in range(cols - 1):
distance = 0 if (r, c) in mines else distance + 1
distances[r][c] = min(distances[r][c], distance) if matrix[r][c] != matrix[r + 1][c + 1]:
return False
distance = 0
for r in range(N - 1, -1, -1): return True
distance = 0 if (r, c) in mines else distance + 1
distances[r][c] = min(distances[r][c], distance)
plus = max(plus, distances[r][c]) # python_1_to_1000/767_Reorganize_String.py - m
# https://leetcode.com/problems/reorganize-string/ # python_1_to_1000/769_Max_Chunks_To_Make_Sorted.py - m
# Given a string S, check if the letters can be rearranged so that two characters that are adjacent to each other
# are not the same. If possible, output any possible result. If not possible, return the empty string. _author_ = 'jake'
_project_ = 'leetcode'
# Create heap of letter frequencies. Pop the most frequent letter off the heap and append to result if is different
# from the previous letter and add back to heap with decremented count. Else this is the only letter, no solution is # https://leetcode.com/problems/max-chunks-to-make-sorted/
# possible. Else use the next most frequent letter then add the most frequent letter back. # Given an array arr that is a permutation of [0, 1, ..., arr.length - 1], we split the array into some number of
# Time - O(n log k) where len(S) == n and k is the size of the alphabet. # "chunks" (partitions), and individually sort each chunk. After concatenating them, the result equals the sorted array.
# Space - O(n) # What is the most number of chunks we could have made?
import heapq # Iterate from right to left, finding the minimum value to the right of each number. Then iterate from left to right
from collections import Counter # tracking the maximum number in each partition. If the maximum is smaller than all numbers to the right, the partition
# can be sorted and the whole list will be sorted.
class Solution(object): # Time - O(n)
def reorganizeString(self, S): # Space - O(n)
"""
:type S: str class Solution(object):
:rtype: str def maxChunksToSorted(self, arr):
""" """
freq = Counter(S) :type arr: List[int]
if any(count > (len(S) + 1) // 2 for count in freq.values()): # some letter is too frequent :rtype: int
return "" """
min_right = [float("inf") for _ in range(len(arr))] # min_right[-1] == float("inf")
heap = [(-count, letter) for letter, count in freq.items()] # max heap of count
heapq.heapify(heap) for i in range(len(arr) - 2, -1, -1):
min_right[i] = min(min_right[i + 1], arr[i + 1])
result = []
partitions = 0
def add_letter(letter, neg_count): partition_max = None
result.append(letter)
neg_count += 1 for i, num in enumerate(arr):
if neg_count != 0: # remove from hep if no remaining count
heapq.heappush(heap, (neg_count, letter)) partition_max = num if partition_max is None else max(partition_max, num)
class Solution(object): # Create a class that extends Counter by using a __mul__ method.
def maxChunksToSorted(self, arr): # Time - O(2**n + m) where len(expression) == n and len(evalvars) == m
""" # Space - O(n + m)
:type arr: List[int]
:rtype: int from collections import Counter
""" import re
min_right = [float("inf") for _ in range(len(arr))] # min_right[-1] == float("inf")
class Solution(object):
for i in range(len(arr) - 2, -1, -1): def basicCalculatorIV(self, expression, evalvars, evalints):
min_right[i] = min(min_right[i + 1], arr[i + 1]) """
:type expression: str
partitions = 0 :type evalvars: List[str]
partition_max = None :type evalints: List[int]
:rtype: List[str]
for i, num in enumerate(arr): """
# wrap all tokens with a call to make_counter and evaluate to aggregate def calculate(tokens):
counter = eval(re.sub('(\w+)', r'make_counter("\1")', expression))
# '(\w+)' matches groups of 1 or more alphanumeric if isinstance(tokens, int): # base case of single integer
# r'make_counter("\1")' uses \1 to to signify the matched groups and r so that \ is not special return tokens
# sort keys by decreasing length then lexicographically result = [calculate(tokens[0])] # list of integers
sorted_terms = sorted(counter, key=lambda x: (-len(x), x))
for i in range(1, len(tokens), 2): # iterate over pairs of operator and integer
result = [] op, num = tokens[i], calculate(tokens[i + 1])
for term in sorted_terms:
if counter[term]: # ignore zero values if op == "/":
result.append("*".join((str(counter[term]),) + term)) result.append(result.pop() // num)
elif op == "*":
return result result.append(result.pop() * num)
elif op == "+":
result.append(num)
# python_1_to_1000/771_Jewels_and_Stones.py else:
result.append(-num)
_author_ = 'jake'
_project_ = 'leetcode' return sum(result)
return -1 # python_1_to_1000/776_Split_BST.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/774_Minimize_Max_Distance_to_Gas_Station.py - h
# https://leetcode.com/problems/split-bst/
_author_ = 'jake' # Given a Binary Search Tree (BST) with root node root, and a target value V, split the tree into two subtrees where
_project_ = 'leetcode' # one subtree has nodes that are all smaller or equal to the target value, while the other subtree has all nodes that
# are greater than the target value. It's not necessarily the case that the tree contains a node with value V.
# https://leetcode.com/problems/minimize-max-distance-to-gas-station/ # Additionally, most of the structure of the original tree should remain.
# On a horizontal number line, we have gas stations at positions stations[0], stations[1], ..., stations[N-1], # Formally, for any child C with parent P in the original tree, if they are both in the same subtree after the split,
# where N = stations.length. # then node C should still have the parent P.
# Now, we add K more gas stations so that D, the maximum distance between adjacent gas stations, is minimized. # You should output the root TreeNode of both subtrees after splitting, in any order.
# Return the smallest possible value of D.
# Helper function recursively splits BST into a tree with nodes <= V and a tree with nodes > V. One side is always
# Create a list of distances between stations, sorted in descending order. Binary search the possible range of minimum # unchanged and the recursion splits the other side into 2 parst, one of which is added back as a new left or right
# max distances. Initially this range is from zero to the maximum distance between stations. Test the middle distance, # subtree.
# if it is possible to put K stations with this maximum distance, test lower distances else test greater distances. # Time - O(n)
# Stop when required accuracy is achieved. Test if K stations can make the required distance by greedily using as many # Space - O(n)
# stations as required for each interval.
# Time - O(nlogn + ns) where s is the maximum number of search steps = log(r) where r = max_d / accuracy class Solution(object):
# Space - O(n) def splitBST(self, root, V):
"""
class Solution(object): :type root: TreeNode
def minmaxGasDist(self, stations, K): :type V: int
""" :rtype: List[TreeNode]
:type stations: List[int] """
:type K: int def splitter(node):
:rtype: float
""" if not node:
distances = [s1 - s2 for s1, s2 in zip(stations[1:], stations)] return [None, None]
distances.sort(reverse=True)
if V < node.val:
def can_minmax_dist(d): less, more = splitter(node.left) # recurse left, node.right is unchanged
node.left = more # new left is the tree with nodes > V
remaining = K return [less, node]
for dist in distances:
if dist < d or remaining < 0: # no more stations need to be added or no more stations left to add less, more = splitter(node.right) # recurse right, node.left is unchanged if V == node.val
break node.right = less
remaining -= int(dist / d) # use stations to make the required distance return [node, more]
# "L" can only move left and "R" can only move right. "L" and "R" cannot swap places. Maintain the net balance of "L"
# and "R" while iterating over both strings. If there are more "L" of fewer "R" then the first requirement is violated.
# If there is "R" in start and "L" in end then a swap is required. Final check for overall balance.
# python_1_to_1000/775_Global_and_Local_Inversions.py - m # Time - O(n)
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def canTransform(self, start, end):
# https://leetcode.com/problems/global-and-local-inversions/ """
# We have some permutation A of [0, 1, ..., N - 1], where N is the length of A. :type start: str
# The number of (global) inversions is the number of i < j with 0 <= i < j < N and A[i] > A[j]. :type end: str
# The number of local inversions is the number of i with 0 <= i < N and A[i] > A[i+1]. :rtype: bool
# Return true if and only if the number of global inversions is equal to the number of local inversions. """
if len(start) != len(end): # early return
# Every local inversion is also a global inversions, so we only need to check is there are any other global inversions return False
# i.e. inversions separated by more than one index. Track the max value seen before the previous value, if this is
# greater than the current value we haev another global inversions. left, right = 0, 0 # net balance of "L" and "R" in start minus end
# Time - O(n)
# Space - O(1) for c1, c2 in zip(start, end): # iterate over both strings together
if A[i] < max_before_prev: if left > 0 or right < 0: # more "L" in start, cannot move right to reach those in end
return False
if left < 0 and right > 0: # need to swap "L" and "R" length //= 2
return False
return int(inverse)
return left == 0 and right == 0 # must be balanced
# python_1_to_1000/778_Swim_in_Rising_Water.py - h # python_1_to_1000/780_Reaching_Points.py - h
# https://leetcode.com/problems/swim-in-rising-water/ # https://leetcode.com/problems/reaching-points/
# On an N x N grid, each square grid[i][j] represents the elevation at that point (i,j). # A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y).
# Now rain starts to fall. At time t, the depth of the water everywhere is t. You can swim from a square to another # Given a starting point (sx, sy) and a target point (tx, ty), return True if and only if a sequence of moves
# 4-directionally adjacent square if and only if the elevation of both squares individually are at most t. # exists to transform the point (sx, sy) to (tx, ty). Otherwise, return False.
# You can swim infinite distance in zero time. You must stay within the boundaries of the grid during your swim. # sx, sy, tx, ty will all be integers in the range [1, 10^9].
# Start at the top left square (0, 0). What is the least time until you can reach the bottom right square (N-1, N-1)?
# Move back from tx, ty since there can be only one valid step (because sx and sy are both positive). In the other
# Maintain a priority queue of cells on edge of explored region. Pop lowest cell and update the high water mark. # direction from sx, sy there are 2 possible moves. While both tx and ty are more than sx and sy respectively, subtract
# Add neighbours to frontier if not already visited. If lower cells are added to frontier they will be removed before # either ty from ty or ty from tx. Do this as many times as possible in one step with the modulo operator.
# any higher cells. # When either tx <= sx or ty <= sy, check if tx == sx and ty can reach sy by taking steps of sx (or vica versa).
# Time - O(n**2 logn) # Time - O(log n)
# Space - O(n**2) # Space - O(1)
class Solution(object):
def numRabbits(self, answers):
# python_1_to_1000/779_K-th_Symbol_in_Grammar.py - m """
:type answers: List[int]
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
colours = {} # map colour to number of unseen rabbits of that colour
# https://leetcode.com/problems/k-th-symbol-in-grammar/ rabbits = 0
# On the first row, we write a 0. Now in every subsequent row, we look at the previous row and replace each
# occurrence of 0 with 01, and each occurrence of 1 with 10. for rabbit in answers:
# Given row N and index K, return the K-th indexed symbol in row N. (The values of K are 1-indexed.) (1 indexed).
if colours.get(rabbit, 0) > 0: # default 0 if a new colour
# Each row consists of the concatenation of the previous row and the inverse of the previous row. If K is more than colours[rabbit] -= 1
# half way along a row, it belongs to the inverse of the previous row hence flip the logical flag. Repeat moving up else:
# rows until the final row is inversed (return 1) or not (return 0). rabbits += rabbit + 1 # new colour
# Time - O(log n) colours[rabbit] = rabbit
# Space - O(1)
return rabbits
class Solution(object):
def kthGrammar(self, N, K):
""" # python_1_to_1000/782_Transform_to_Chessboard.py - h
:type N: int
:type K: int _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
length = 2 ** (N - 1) # length of current row # https://leetcode.com/problems/transform-to-chessboard/
# An N x N board contains only 0s and 1s. In each move, you can swap any 2 rows with each other,
inverse = False # or any 2 columns with each other.
# What is the minimum number of moves to transform the board into a "chessboard" - a board where no 0s and no 1s
while length > 1: # are 4-directionally adjacent? If the task is impossible, return -1.
if K > length // 2: # on RHS of this row # If two rows are identical, then swapping columns does not change this. The solution has two types of row and since we
inverse = not inverse # cannot change the number of row types by swapping columns, the board must only have two types of row initially.
K -= length // 2 # The two types of row must be opposite and differ in their number of zeros by len(board) % 1.
# If len(board) is odd, find the type with the most zeros and count the moves to convert it to the required target """
# beginning with zero. Else find the minimum steps to either the target beginning with zero or one. :type S: str
# Time - O(mn) :rtype: List[str]
# Space - O(mn) """
permutations = [[]]
class Solution(object):
def movesToChessboard(self, board): for c in S:
"""
:type board: List[List[int]] if "0" <= c <= "9":
:rtype: int for perm in permutations:
""" perm.append(c)
n = len(board)
else:
rows = {tuple(row) for row in board} # set of row tuples
cols = set(zip(*board)) # transpose, converts to column tuples new_permutations = []
upper, lower = c.upper(), c.lower()
moves = 0
for patterns in [rows, cols]: # process rows then columns for perm in permutations:
new_permutations.append(perm + [upper])
if len(patterns) != 2: # 2 types of row or column perm.append(lower)
return -1 new_permutations.append(perm)
zero_p1, zero_p2 = sum(x == 0 for x in p1), sum(x == 0 for x in p2) return ["".join(perm) for perm in permutations] # convert lists of chars to strings
if abs(zero_p1 - zero_p2) != n % 2 or not all(x ^ y for x, y in zip(p1, p2)): # opposites
return -1
# python_1_to_1000/785_Is_Graph_Bipartite.py - m
p = p1 if zero_p1 > zero_p2 else p2 # choose pattern with most zeros
p_moves = sum(x != y for x, y in zip(p, [0, 1] * ((n + 1) // 2))) _author_ = 'jake'
if n % 2 == 0: # need to check steps to both targets for even board lengths _project_ = 'leetcode'
p_moves = min(p_moves, sum(x != y for x, y in zip(p, [1, 0] * ((n + 1) // 2))))
# https://leetcode.com/problems/is-graph-bipartite/
moves += p_moves // 2 # each swap corrects the position of 2 items # Given an undirected graph, return true if and only if it is bipartite.
# Recall that a graph is bipartite if we can split it's set of nodes into two independent subsets A and B such that
return moves # every edge in the graph has one node in A and another node in B.
# The graph is given as follows: graph[i] is a list of indexes j for which the edge between nodes i and j exists.
# Each node is an integer between 0 and graph.length - 1.
# There are no self edges or parallel edges: graph[i] does not contain i, and it doesn't contain any element twice.
# python_1_to_1000/783_Minimum_Distance_Between_BST_Nodes.py
# Set the "colour" of each node to True or False. Iterate over nodes ignoring those that have been visited before.
_author_ = 'jake' # Set the colour of an unvisited node arbitrarily to True and add it to queue. Queue contains all nodes whose
_project_ = 'leetcode' # neighbours still have to be explored. Explore the queue with depth-first search, popping off a node setting its
# colour opposite to parent and failing if has same colour of parent.
# https://leetcode.com/problems/minimum-distance-between-bst-nodes/ # Time - O(n) the number of edges
# Given a Binary Search Tree (BST) with the root node root, return the minimum difference between the values of any # Space - O(m) the number of nodes
# two different nodes in the tree.
class Solution(object):
# Inorder traversal visits nodes in increasing order of value. Update the previous node and minimum difference for def isBipartite(self, graph):
# each node. """
# Time - O(n) :type graph: List[List[int]]
# Space - O(n) :rtype: bool
"""
class Solution(object): n = len(graph)
def minDiffInBST(self, root): colours = [None] * n # initially all nodes are not coloured
"""
:type root: TreeNode for i in range(len(graph)):
:rtype: int
""" if colours[i] is not None:
self.min_diff = float("inf") continue
self.prev = float("-inf")
colours[i] = True
def inorder(node): queue = [i] # coloured nodes whose edges have not been checked
if not node:
return while queue:
inorder(node.left) v = queue.pop()
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/786_K-th_Smallest_Prime_Fraction.py - m
class Solution(object): # Binary search the space of numbers between 0 and 1 for the number with K smaller fractions.
def letterCasePermutation(self, S): # Since max prime is N = 30000 then min difference between two fractions is 1/N**2 > 10**-9. Hence binary search until
for numerator in range(len(A) - 1): # for each numerator, find first denominator so fraction < x # Test each integer. If any digit cannot be rotated then integer is not good. Also if integer does not contain at least
# one digit that is different after rotation, it is bad.
while denominator < len(A) and A[numerator] >= x * A[denominator]: # fraction >= x # Time - O(n log n) since each integer has O(log n) digits.
denominator += 1 # Space - O(log n)
if denominator != len(A) and A[numerator] * largest[1] > largest[0] * A[denominator]: class Solution(object):
largest = [A[numerator], A[denominator]] # new largest def rotatedDigits(self, N):
"""
count += len(A) - denominator # count this and all greater denominators :type N: int
:rtype: int
return count, largest """
count = 0
low, high = 0, 1.0 bad = {"3", "4", "7"}
while high - low > 10 ** -9: opposites = {"2", "5", "6", "9"}
return result
# python_1_to_1000/789_Escape_The_Ghosts.py - m
# python_1_to_1000/787_Cheapest_Flights_Within_K_Stops.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/escape-the-ghosts/
# https://leetcode.com/problems/cheapest-flights-within-k-stops/ # You are playing a simplified Pacman game. You start at the point (0, 0), and your destination is
# There are n cities connected by m flights. Each fight starts from city u and arrives at v with a price w. # (target[0], target[1]). There are several ghosts on the map, the i-th ghost starts at (ghosts[i][0], ghosts[i][1]).
# Now given all the cities and fights, together with starting city src and the destination dst, your task is to find # Each turn, you and all ghosts simultaneously *may* move in one of 4 cardinal directions: north, east, west, or south,
# the cheapest price from src to dst with up to k stops. If there is no such route, output -1. # going from the previous point to a new point 1 unit of distance away.
# You escape if and only if you can reach the target before any ghost reaches you (for any given moves the ghosts
# Create an adjacency list mapping from a city to all cities connected by a direct flight. # may take.) If you reach any square (including the target) at the same time as a ghost, it doesn't count as an escape.
# Create a priority queue ordered by cost. Repeatedly pop city with lowest cost and add it to visited set. If not # Return True if and only if it is possible to escape.
# the destination,
# Time - O(m + n log n) where m == len(flights) and n == number of cities # If any ghost can reach the target before or at the same time as pacman then no escape is possible.
# Space - O(m + n) # Time - O(n)
# Space - O(1)
from collections import defaultdict
import heapq class Solution(object):
def escapeGhosts(self, ghosts, target):
class Solution(object): """
def findCheapestPrice(self, n, flights, src, dst, K): :type ghosts: List[List[int]]
""" :type target: List[int]
:type n: int :rtype: bool
:type flights: List[List[int]] """
:type src: int def manhattan(position):
:type dst: int return abs(position[0] - target[0]) + abs(position[1] - target[1])
:type K: int
:rtype: int target_distance = manhattan((0, 0))
"""
flts = defaultdict(list) # map city to list of (destination, cost) return all(manhattan(ghost) > target_distance for ghost in ghosts)
for start, end, cost in flights:
flts[start].append((end, cost))
# python_1_to_1000/790_Domino_and_Tromino_Tiling.py - m
queue = [(0, -1, src)] # -1 stops since zero stops are direct flights
visited = set() # cities where we know the cheapest cost _author_ = 'jake'
_project_ = 'leetcode'
while queue:
# https://leetcode.com/problems/domino-and-tromino-tiling/
cost, stops, location = heapq.heappop(queue) # We have two types of tiles: a 2x1 domino shape, and an "L" tromino shape. These shapes may be rotated.
visited.add(location) # Given N, how many ways are there to tile a 2 x N board? Return your answer modulo 10^9 + 7.
# In a tiling, every square must be covered by a tile. Two tilings are different if and only if there are two
if location == dst: # 4-directionally adjacent cells on the board such that exactly one of the tilings has both squares occupied by a tile.
return cost
# For each length of board, find the number of tilings that fill the board exactly and the number of tilings that have
if stops == K: # cannot make more stops along this path # one extra tile. To tile a board of length n exactly, we can use either a tiled board of n - 1 and a horizontal
continue # domino, or a tiled board of n - 2 and two vertical dominos, or a board of n - 2 with one extra tile and a tromino.
# To tile a board of length n with one extra tile, we can either use a fully tiled board of length n - 1 and a tromino
for end, next_cost in flts[location]: # in one of two orientations, or a a board of n - 2 with one extra tile and a vertical domino.
if end not in visited: # do not revisit cities where we already have the cheapest cost # Time - O(n)
heapq.heappush(queue, (cost + next_cost, stops + 1, end)) # Space - O(1)
class Solution(object): if len(suffix) == 0: # matched all of this word
def numTilings(self, N): result += 1
""" continue
:type N: int
:rtype: int next_letter, next_suffix = suffix[0], suffix[1:]
""" letter_to_suffixes[next_letter].append(next_suffix)
MOD = 10 ** 9 + 7
prev_tilings, tilings = 0, 1 # one way to fully tile board of length zero return result
prev_one_extra, one_extra = 0, 0 # no ways to tile boards of length -1 or 0 with one extra
# Binary search for the smallest x such that f(x) >= K. If f(x) == K then there is some integer with K trailing zeros
# python_1_to_1000/791_Custom_Sort_String.py - m # hence there are 5 such integers (the integers between successive factors of 5). Else there is no integer with K
# trailing zeros.
_author_ = 'jake' # Time - O(log^2 K), log K for factorial_zeros and log K for binary search
_project_ = 'leetcode' # Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/792_Number_of_Matching_Subsequences.py - m
# https://leetcode.com/problems/valid-tic-tac-toe-state/
_author_ = 'jake' # A Tic-Tac-Toe board is given as a string array board.
_project_ = 'leetcode' # Return True if and only if it is possible to reach this board position during the course of a valid tic-tac-toe game.
# The board is a 3 x 3 array consisting of characters " ", "X", and "O". The " " character represents an empty square.
# https://leetcode.com/problems/number-of-matching-subsequences/ # Here are the rules of Tic-Tac-Toe:
# Given string S and a dictionary of words words, find the number of words[i] that are a subsequences of S. # Players take turns placing characters into empty squares (" ").
# The first player always places "X" characters, while the second player always places "O" characters.
# Maintain a mapping for each word from the next char to be matched to the remainder of the word. For each char in # "X" and "O" characters are always placed into empty squares, never filled ones.
# S, update the mapping by removing the key/value with the current char and adding the words back with keys of their # The game ends when there are 3 of the same (non-empty) character filling any row, column, or diagonal.
# chars to be matched. # The game also ends if all squares are non-empty.
# Time - O(m + n), len(S) + sum of all words # No more moves can be played if the game is over.
# Space - O(n)
# Count the number of Os and X and the number of winning rows of Os and Xs. Check only one winner and number of Os and
from collections import defaultdict # Xs in the cases of either winner and no winner.
# Time - O(1) since board has fixed size of 3 x 3
class Solution(object): # Space - O(1)
def numMatchingSubseq(self, S, words):
""" class Solution(object):
:type S: str def validTicTacToe(self, board):
:type words: List[str] """
:rtype: int :type board: List[str]
""" :rtype: bool
letter_to_suffixes = defaultdict(list) # map next char of a word to suffix after that char """
letter_to_suffixes["#"] = words # special character will be matched initially counts, lines = [0, 0], [0, 0] # counts of O and X, counts of lines of O and X
result = 0
for i, char in enumerate(("O", "X")):
for c in "#" + S:
for j, row in enumerate(board):
suffixes = letter_to_suffixes[c] # cannot pop unless checking whether c is in letter_to_suffixes
del letter_to_suffixes[c] if row == char * 3: # row lines
lines[i] += 1
for suffix in suffixes:
# https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/
# python_1_to_1000/799_Champagne_Tower.py - m # We have two integer sequences A and B of the same non-zero length.
# We are allowed to swap elements A[i] and B[i]. Note that both elements are in the same index position in their
_author_ = 'jake' # respective sequences.
_project_ = 'leetcode' # At the end of some number of swaps, A and B are both strictly increasing.
# A sequence is strictly increasing if and only if A[0] < A[1] < A[2] < ... < A[A.length - 1].
# https://leetcode.com/problems/champagne-tower/ # Given A and B, return the minimum number of swaps to make both sequences strictly increasing.
# We stack glasses in a pyramid, where the first row has 1 glass, the second row has 2 glasses, # It is guaranteed that the given input always makes it possible.
# and so on until the 100th row. Each glass holds one cup (250ml) of champagne.
# Then, some champagne is poured in the first glass at the top. When the top most glass is full, any excess liquid # Dynamic programming. For each index, find the minimum swaps to make an increasing sequence to (and including) that
# poured will fall equally to the glass immediately to the left and right of it. When those glasses become full, # index, with and without swapping elements at that index.
# any excess champagne will fall equally to the left and right of those glasses, and so on. # If the elements at index i in A and B are both increasing relative to their previous elements, the cost without
# A glass at the bottom row has it's excess champagne fall on the floor. # swapping is the previous cost without swapping and the cost with swapping is 1 + the previous cost with swapping
# Now after pouring some non-negative integer cups of champagne, return how full the j-th glass in the i-th row is # (since if i and i-1 are swapped then the lists are in the origina order). If the lists are increasing after swapping
# (both i and j are 0 indexed.) # at index i, update the cost without swapping according to the previous cost with swapping, and the cost with swapping
# as 1 + the previous cost without swapping.
# Calculate the volume of champagne that is added to each glass. For each glass in the current row, subtract 1 glass # Time - O(n)
# which is the champagne that remains and divid the remainder by the 2 glasses below (floored at zero). # Space - O(1)
# Time - O(n**2)
# Space - O(n) class Solution(object):
def minSwap(self, A, B):
class Solution(object): """
def champagneTower(self, poured, query_row, query_glass): :type A: List[int]
""" :type B: List[int]
:type poured: int :rtype: int
:type query_row: int """
:type query_glass: int prev_no_swap, prev_swap = 0, 1 # min swaps without and with swapping at first index
:rtype: float
""" for i in range(1, len(A)): # start from second index
glasses = [poured]
no_swap, swap = float("inf"), float("inf") # default infinity if no increasing subsequences can be made
for row in range(query_row):
if A[i] > A[i - 1] and B[i] > B[i - 1]:
new_glasses = [0 for _ in range(len(glasses) + 1)] no_swap = prev_no_swap
swap = 1 + prev_swap
for i, glass in enumerate(glasses):
pour = max(glass - 1, 0) / 2.0 if A[i] > B[i - 1] and B[i] > A[i - 1]:
new_glasses[i] += pour no_swap = min(no_swap, prev_swap)
new_glasses[i + 1] += pour swap = min(swap, 1 + prev_no_swap)
# python_1_to_1000/800_Similar_RGB_Color.py
# python_1_to_1000/802_Find_Eventual_Safe_States.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/similar-rgb-color/
# In the following, every capital letter represents some hexadecimal digit from 0 to f. # https://leetcode.com/problems/find-eventual-safe-states/
# The red-green-blue color "#AABBCC" can be written as "#ABC" in shorthand. # In a directed graph, we start at some node and every turn, walk along a directed edge of the graph.
# For example, "#15c" is shorthand for the color "#1155cc". # If we reach a node that is terminal (that is, it has no outgoing directed edges), we stop.
# Now, say the similarity between two colors "#ABCDEF" and "#UVWXYZ" is -(AB - UV)^2 - (CD - WX)^2 - (EF - YZ)^2. # Now, say our starting node is eventually safe if and only if we must eventually walk to a terminal node.
# Given the color "#ABCDEF", return a 7 character color that is most similar to #ABCDEF, # More specifically, there exists a natural number K so that for any choice of where to walk,
# and has a shorthand (that is, it can be represented as some "#XYZ" # we must have stopped at a terminal node in less than K steps.
# Which nodes are eventually safe? Return them as an array in sorted order.
# Convert each pair of characters to integer and fins the absolute difference. If the absolute difference is less than # The directed graph has N nodes with labels 0, 1, ..., N-1, where N is the length of graph.
# or equal to 8 then it is optimal to duplicate the first char of the pair. Otherwise the first char is greater than # The graph is given in the following form: graph[i] is a list of labels j such that (i, j) is a directed edge.
# the second, it is a shorter distance to decrement the first char. Else increment the first char.
# Time - O(1) # Topological sort. Start with a list of all safe nodes without outgoing edges. For each node, remove its incoming
# Space - O(1) # edges from the outgoing edges of its neighbours. If any neighbour then has no outgoing edges, add it to the safe list.
# Alternatively DFS marking unvisied nodes as white, known safe nodes as black and visited uncertain node as grey.
class Solution(object): # Time - O(m + n), nodes + edges are all visited once.
def similarRGB(self, color): # Space - O(m + n)
"""
:type color: str class Solution(object):
:rtype: str def eventualSafeNodes(self, graph):
""" """
result = ["#"] :type graph: List[List[int]]
:rtype: List[int]
for i in range(1, 6, 2): # first char of each pair """
outgoing = [set(nbors) for nbors in graph] # convert neigbours to set of O(1) lookup
first, second = int(color[i], 16), int(color[i + 1], 16) # convert hex to integer incoming = [[] for _ in range(len(graph))] # map node to list of nodes with incoming edges
difference = first - second
for node, nbors in enumerate(graph):
if abs(difference) <= 8: for nbor in nbors:
char = color[i] incoming[nbor].append(node)
elif difference > 0:
char = hex(first - 1)[2] # decrement and convert back to hex safe = [node for node, nbors in enumerate(outgoing) if not nbors] # nodes without outgoing edges
else: # difference < 0
char = hex(first + 1)[2] for safe_node in safe: # extended during iteration, could pop or use deque
result.append(char * 2)
nbors = incoming[safe_node]
return "".join(result) for nbor in nbors:
outgoing[nbor].remove(safe_node) # remove edge safe_node -> nbor
if not outgoing[nbor]: # new eventually safe node
# python_1_to_1000/801_Minimum_Swaps_To_Make_Sequences_Increasing.py - h safe.append(nbor)
_author_ = 'jake' return [node for node, nbors in enumerate(outgoing) if not nbors] # all nodes that are now safe
transformation = []
# Convert the volume of soup to a number of portions. Given a number of portions of A and of B, recurse for each of the word_groups = get_groups(word)
# 4 possible operations, sum the results and divide by 4 to get the probability of A being empty first.
# Memoize results to avoid repetition. If N is large enough (4800 found experimentally) then the result is within if word_groups.chars != S_groups.chars: # all chars must match
# 10**-6 of 1 so we simply return 1 to the avoid the time limit being exceeded. continue
# Time - O(1) due to the upper limit on N of 4800
# Space - O(1) for S_count, word_count in zip(S_groups.counts, word_groups.counts):
class Solution(object): if word_count > S_count: # can only extend word groups
def soupServings(self, N): break
""" if word_count < S_count and S_count == 2: # cannot externd word group to be of length 2
:type N: int break
:rtype: float else:
""" result += 1
memo = {}
# If there are an even number of nums and xor is not zero, then there are at least 2 different nums. Alice can always
# remove a number not equal to the xor of all numbers, so the xor will not be zero. # python_1_to_1000/813_Largest_Sum_of_Averages.py - m
# Time - O(n)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
from functools import reduce
import operator # https://leetcode.com/problems/largest-sum-of-averages/
# We partition a row of numbers A into at most K adjacent (non-empty) groups, then our score is the sum of the average
class Solution(object): # of each group. What is the largest score we can achieve?
def xorGame(self, nums): # Note that our partition must use every number in A, and that scores are not necessarily integers.
"""
:type nums: List[int] # Dynamic programming. Base case of k == 1 is the average of the array. For k > 1, try all possible suffix arrays that
:rtype: bool # leave at least k - 1 elements in the prefix for the remainder. Calculate the average of the suffix array and add to
""" # recursion result on prefix.
return reduce(operator.xor, nums) == 0 or len(nums) % 2 == 0 # Time - O(n**2 * k)
# Space - O(n * k)
# For each 3 points, use shoelace formula as per https://en.wikipedia.org/wiki/Shoelace_formula to calculate area. if not node:
# Time - O(n**3) return False
# Space - O(1) left_one, right_one = contains_one(node.left), contains_one(node.right) # explore and prune children
front, back = {S}, {T} # frontier sets # Iterate over list, tracking whether the current node is or is not part of a connected component. Every time a new
visited = set() # stops that should not be visited again # connected component starts, increment the count.
buses = 0 # Time - O(n)
# Space - O(1)
while front and back and not (front & back): # end if either set is empty or there is intersection
class Solution(object):
if len(front) < len(back): # swap to expand smaller set def numComponents(self, head, G):
front, back = back, front """
:type head: ListNode
buses += 1 :type G: List[int]
new_front = set() :rtype: int
visited |= front # add all frontier to visited """
H = set(G) # convert to set for O(1) lookup
for stop in front:
for route in stop_to_routes[stop]: count = 0
new_front |= routes[route] # add all stops on the routes that stop is on to new_front connected = False # is there a current connected component?
return buses if front & back else -1 if head.val in H and not connected: # start new connected component
connected = True
count += 1
elif head.val not in G and connected: # end existing connected component
# python_1_to_1000/816_Ambiguous_Coordinates.py - m connected = False
# for j steps before reversing again. Memoize results to avoid repetition. required = set(words)
# Time - O(n log n) since each distance up to n may be calculated, each taking log n to iterate over j
# Space - O(n) for word in words: # iterate over list, not the required set
for i in range(1, len(word) - 1): # remove from required any suffix of word
class Solution(object): required.discard(word[i:]) # discard() not remove()
def racecar(self, target):
""" return sum(len(w) for w in required) + len(required)
:type target: int
:rtype: int
""" # python_1_to_1000/821_Shortest_Distance_to_a_Character.py
min_steps = {0: 0} # map distance to min steps
_author_ = 'jake'
def helper(dist): _project_ = 'leetcode'
steps = k + 1 + helper(2 ** k - 1 - dist) # k steps goes past target, reverse and recurse # Iterate from left to right, for each character recording the distance from the previous C. The iterate from right
for j in range(k - 1): # k - 1 steps, reverse, j steps of acceleration and reverse # to left, updating the distance from the previous C if lower.
steps = min(steps, k + j + 1 + helper(dist - 2 ** (k - 1) + 2 ** j)) # Time - O(n)
# Space - O(n)
min_steps[dist] = steps
return steps class Solution(object):
def shortestToChar(self, S, C):
return helper(target) """
:type S: str
:type C: str
# python_1_to_1000/819_Most_Common_Word.py :rtype: List[int]
"""
_author_ = 'jake' shortest = []
_project_ = 'leetcode'
prev_C = float("-inf") # index of previous C
# https://leetcode.com/problems/most-common-word/ for i, c in enumerate(S):
# Given a paragraph and a list of banned words, return the most frequent word that is not in the list of banned words.
# It is guaranteed there is at least one word that isn't banned, and that the answer is unique. if c == C:
# Words in the list of banned words are given in lowercase, and free of punctuation. prev_C = i
# Words in the paragraph are not case sensitive. The answer is in lowercase. shortest.append(i - prev_C)
# Split paragraph, convert words to lower case and remove punctuation. Count remaining word frequencies if not banned. next_C = float("inf")
# Time - O(n) total length of all words + banned for i in range(len(S) - 1, -1, -1):
# Space - O(n)
c = S[i]
from collections import defaultdict if c == C:
next_C = i
class Solution(object): shortest[i] = min(shortest[i], next_C - i)
def mostCommonWord(self, paragraph, banned):
""" return shortest
:type paragraph: str
:type banned: List[str]
:rtype: str # python_1_to_1000/822_Card_Flipping_Game.py - m
"""
banned = set(banned) _author_ = 'jake'
punct = {"!", "?", ",", ".", ";", "'"} _project_ = 'leetcode'
counter = defaultdict(int)
# https://leetcode.com/problems/card-flipping-game/
for word in (s.lower() for s in paragraph.split(" ")): # On a table are N cards, with a positive integer printed on the front and back of each card (possibly different).
word = "".join(c for c in word if c not in punct) # We flip any number of cards, and after we choose one card.
if word not in banned: # If the number X on the back of the chosen card is not on the front of any card, then this number X is good.
counter[word] += 1 # What is the smallest number that is good? If no number is good, output 0.
# Here, fronts[i] and backs[i] represent the number on the front and back of card i.
return max(counter.items(), key=lambda x: x[1])[0] # key with max value # A flip swaps the front and back numbers, so the value on the front is now on the back and vice versa.
# Iterate over both lists, finding cards with duplicate number of front and back.
# Then iterate again, if a pair of numbers are different then each number that is not a duplicate can potentially
# be a solution.
# Time - O(n)
# python_1_to_1000/820_Short_Encoding_of_Words.py - m # Space - O(n)
# Create the set of required words, initially as all words without duplicates. For each word, remove all suffixes for f, b in zip(fronts, backs):
# fromt the required set. Sum the lengths of all remaining words + 1 char per word for the sentinel "#". if f != b:
# Time - O(nk) for n words of maximum length k if f not in duplicates:
# Space - O(nk) result = min(result, f)
if b not in duplicates:
class Solution(object): result = min(result, b)
def minimumLengthEncoding(self, words):
""" return 0 if result == float("inf") else result
:type words: List[str]
:rtype: int
""" # python_1_to_1000/823_Binary_Trees_With_Factors.py - m
# Note that if A requests B, B does not necessarily request A. Also, people will not friend request themselves.
_author_ = 'jake' # How many total friend requests are made?
_project_ = 'leetcode'
# Group all people of same age together and sort by age. For each age, only consider younger people. Add to result
# https://leetcode.com/problems/binary-trees-with-factors/ # all pairs where b > 0.5 * a + 7 and (b < 100 or a > 100). Add all pairs of the same age if over 14 (age > 0.5 age + 7)
# Given an array of unique integers, each integer is strictly greater than 1. # Time - O(n**2)
# We make a binary tree using these integers and each number may be used for any number of times. # Space - O(n)
# Each non-leaf node's value should be equal to the product of the values of it's children.
# How many binary trees can we make? Return the answer modulo 10 ** 9 + 7. from collections import Counter
# Sort the numbers in ascending order. For each num, try all previous nums as a left child and if we can find class Solution(object):
# left child * right child == num then add to the count of trees with num as root each tree with all possible def numFriendRequests(self, ages):
# combinations of left and right subtrees. """
# Time - O(n**2) :type ages: List[int]
# Space - O(n) :rtype: int
"""
from collections import Counter freq = Counter(ages)
age_counts = [(k, v) for k, v in freq.items()]
class Solution(object): age_counts.sort()
def numFactoredBinaryTrees(self, A): requests = 0
"""
:type A: List[int] for a, (age_a, count_a) in enumerate(age_counts):
:rtype: int
""" for age_b, count_b in age_counts[:a]: # age_b < age_a
MOD = 10 ** 9 + 7 if age_b > 0.5 * age_a + 7 and (age_b < 100 or age_a > 100):
num_to_trees = Counter(A) # initially each num is a tree, all nums are unique as per question requests += count_a * count_b
A.sort()
if age_a > 14: # people of same age
for i, num in enumerate(A): requests += count_a * (count_a - 1)
# python_1_to_1000/827_Making_A_Large_Island.py - h
# python_1_to_1000/825_Friends_Of_Appropriate_Ages.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/making-a-large-island/
# https://leetcode.com/problems/friends-of-appropriate-ages/ # In a 2D grid of 0s and 1s, we change at most one 0 to a 1.
# Some people will make friend requests. The list of their ages is given and ages[i] is the age of the ith person. # After, what is the size of the largest island? (An island is a 4-directionally connected group of 1s).
# Person A will NOT friend request person B (B != A) if any of the following conditions are true:
# age[B] <= 0.5 * age[A] + 7 # For each cell of the grid, find the area of its island and the set of cells neighbouring the island with depth-first
# age[B] > age[A] # search. Map each neighbour cell to a list of areas of neighbouring islands. Find the cell with the largest sum of
# age[B] > 100 && age[A] < 100 # neighbouring islands.
# Otherwise, A will friend request B. # Time - O(mn)
cell_to_areas = defaultdict(int) # map each neighbour cell to list of areas of islands # python_1_to_1000/830_Positions_of_Large_Groups.py
class Solution(object):
# python_1_to_1000/828_Unique_Letter_String.py - h def largeGroupPositions(self, S):
"""
_author_ = 'jake' :type S: str
_project_ = 'leetcode' :rtype: List[List[int]]
"""
# https://leetcode.com/problems/unique-letter-string/ result = []
# A character is unique in string S if it occurs exactly once in it. start = 0
# For example, in string S = "LETTER", the only unique characters are "L" and "R".
# Let's define UNIQ(S) as the number of unique characters in string S. for i, c in enumerate(S):
# For example, UNIQ("LETTER") = 2.
# Given a string S with only uppercases, calculate the sum of UNIQ(substring) over all non-empty substrings of S. if i == len(S) - 1 or c != S[i + 1]:
# If there are two or more equal substrings at different positions in S, we consider them different. if i - start >= 2:
# Since the answer can be very large, return the answer modulo 10 ^ 9 + 7. result.append([start, i])
start = i + 1 # update start index of next group
# For each letter, make a list of indices in S of the letter. For each in index in each list part from the first and
# last, we can make subarrays where the letter is unique with left edges up to the previous index and right edges up return result
# to the next index.
# Time - O(n)
# Space - O(n) # python_1_to_1000/831_Masking_Personal_Information.py - m
# https://leetcode.com/problems/consecutive-numbers-sum/ # If S contains "@" it is an email. Split email by "@", amend name to first and last letters.
# Given a positive integer N, how many ways can we write it as a sum of consecutive positive integers? # If phone, retain all digits and split into country (maybe empty) and local.
# Time - O(n)
# The sum of consecutive numbers (x + 1) + (x + 2) + ... + (x + k) = kx + k(k + 1)//2. # Space - O(n)
# We seek k and x to make this equation equal to N.
# Rearranging gives kx = N - k(k + 1)//2. Try all values of k from 1 until the RHS of this becomes negative. class Solution(object):
# We have a solution if the RHS is divisible by k. def maskPII(self, S):
"""
:type S: str # python_1_to_1000/834_Sum_of_Distances_in_Tree.py - h
:rtype: str
""" _author_ = 'jake'
if "@" in S: _project_ = 'leetcode'
name, address = S.lower().split("@")
return name[0] + "*****" + name[-1] + "@" + address # https://leetcode.com/problems/sum-of-distances-in-tree/
# An undirected, connected tree with N nodes labelled 0...N-1 and N-1 edges are given.
digits = [c for c in S if "0" <= c <= "9"] # remove all non-digits # The ith edge connects nodes edges[i][0] and edges[i][1] together.
country, local = digits[:-10], digits[-10:] # split country and local numbers # Return a list ans, where ans[i] is the sum of the distances between node i and all other nodes.
result = []
if country: # Create map from node to neighbours. Depth-first search from node 0, counting the number of nodes in each subtree and
result = ["+"] + ["*"] * len(country) + ["-"] # masked country with "+" prefix # calculating the distance from each root to all nodes in subtree. The distances from node 0 is then correct.
result += ["***-***-"] + local[-4:] # masked local apart from last 4 digits # Depth-first search again, calculating the distance to every child as the parent distance minus 1 for every node in
return "".join(result) # the subtree (which is now closer), plus 1 for every node not in subtree (which is now further away).
# Time - O(n)
# Space - O(n)
subtree_distances(0, None)
# python_1_to_1000/833_Find_And_Replace_in_String.py - m update_distances(0, None)
return distances
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/835_Image_Overlap.py - m
# https://leetcode.com/problems/find-and-replace-in-string/
# To some string S, we will perform some replacement operations that replace groups of letters with new ones _author_ = 'jake'
# (not necessarily the same size). _project_ = 'leetcode'
# Each replacement operation has 3 parameters: a starting index i, a source word x and a target word y.
# The rule is that if x starts at position i in the original string S, then we will replace that occurrence of x with y. # https://leetcode.com/problems/image-overlap/
# If not, we do nothing. # Two images A and B are given, represented as binary, square matrices of the same size
# For example, if we have S = "abcd" and we have some replacement operation i = 2, x = "cd", y = "ffff", then # A binary matrix has only 0s and 1s as values.
# because "cd" starts at position 2 in the original string S, we will replace it with "ffff". # We translate one image however we choose (sliding it left, right, up, or down any number of units), and place it on
# Using another example on S = "abcd", if we have both the replacement operation i = 0, x = "ab", y = "eee", # top of the other image. After, the overlap of this translation is the number of positions that are 1 in both images.
# as well as another replacement operation i = 2, x = "ec", y = "ffff", this second operation does nothing because in # What is the largest possible overlap?
# the original string S[2] = 'c', which doesn't match x[0] = 'e'.
# All these operations occur simultaneously. It's guaranteed that there won't be any overlap in replacement: # Convert each 2-d image to a 1-d list of integers. Each integer represents a row, where setting the ith bit of the
# for example, S = "abc", indexes = [0, 1], sources = ["ab","bc"] is not a valid test case. # integer means the pixel at row[i] is set in the image.
# Then slide each image to all possible positions relative to the other image. For each overlapping row, right shift the
# Convert to mutable list of chars. For each index, if substring string of length source is same as source string, # integer representation of the slide row by the row shift, perform the logical AND with the static row and count the
# replace the first char with the target and remaining chars of source with empty strings. # set bits.
# Time - O(min(k, nm)) for n replacements of max length m, len(S) == k # Time - O(n**3)
# Space - O(k + mn) # Space - O(n)
_project_ = 'leetcode'
for slide, static in ((A_bits, B_bits), (B_bits, A_bits)): # keep one image static and slide the other
for row_shift in range(rows): # https://leetcode.com/problems/push-dominoes/
for col_shift in range(cols): # There are N dominoes in a line, and we place each domino vertically upright.
# In the beginning, we simultaneously push some of the dominoes either to the left or to the right.
overlap = 0 # After each second, each domino that is falling to the left pushes the adjacent domino on the left.
for slide_row in range(rows - row_shift): # the numebr of rows to slide # Similarly, the dominoes falling to the right push their adjacent dominoes standing on the right.
shifted = slide[slide_row] >> col_shift # right shift the bits in this row # When a vertical domino has dominoes falling on it from both sides, it stays still due to the balance of the forces.
row_and = bin(shifted & static[slide_row + row_shift]) # AND with the static row # For the purposes of this question, we will consider that a falling domino expends no additional force to a falling
overlap += row_and.count("1") # count the mutual set bits # or already fallen domino.
# Given a string "S" representing the initial state. S[i] = 'L', if the i-th domino has been pushed to the left;
max_overlap = max(max_overlap, overlap) # S[i] = 'R', if the i-th domino has been pushed to the right; S[i] = '.', if the i-th domino has not been pushed.
# Return a string representing the final state.
return max_overlap
# Iterate over dominos from right to left, for each domino finding the closest "R" that reach this domino. Repeat for
# closest "L" and iterating left to right. Then each domino that has not fallen falls according to whether an "R" or
# python_1_to_1000/836_Rectangle_Overlap.py # "L" that can impact it is closer.
# Time - O(n)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/rectangle-overlap/ def pushDominoes(self, dominos):
# A rectangle is represented as a list [x1, y1, x2, y2], where (x1, y1) are the coordinates of its bottom-left corner, """
# and (x2, y2) are the coordinates of its top-right corner. :type dominos: str
# Two rectangles overlap if the area of their intersection is positive. :rtype: str
# To be clear, two rectangles that only touch at the corner or edges do not overlap. """
# Given two (axis-aligned) rectangles, return whether they overlap. prev_R = float("-inf") # current index of previous "R"
rights = [] # indices of previous "R" on the left of each domino
# Find overlap distance in x direction as the overlap of 2 line segments. If positive, check overlap in y direction. for i, c in enumerate(dominos):
# Time - O(1) rights.append(prev_R)
# Space - O(1) if c == "R": # new prev_R
prev_R = i
class Solution(object): elif c == "L": # no "R" can reach this domino
def isRectangleOverlap(self, rec1, rec2): prev_R = float("-inf")
"""
:type rec1: List[int] prev_L = float("inf") # current index of previous "L"
:type rec2: List[int] lefts = [0] * len(dominos) # indices of previous "L" on the right of each domino
:rtype: bool for i in range(len(dominos) - 1, -1, -1):
""" lefts[i] = prev_L
x_overlap = min(max(0, rec1[2] - rec2[0]), max(0, rec2[2] - rec1[0])) if dominos[i] == "L": # new prev_L
if x_overlap == 0: prev_L = i
return False elif dominos[i] == "R": # no "L" can reach this domino
prev_L = float("inf")
return min(max(0, rec1[3] - rec2[1]), max(0, rec2[3] - rec1[1])) > 0
dominos = [c for c in dominos]
for i in range(len(dominos)):
# python_1_to_1000/837_New_21_Game.py - m if dominos[i] == ".": # not fallen already
diff = (lefts[i] - i) - (i - rights[i]) # closest falling domino, negative for left, pos for right
_author_ = 'jake' if diff < 0:
_project_ = 'leetcode' dominos[i] = "L"
elif diff > 0:
# https://leetcode.com/problems/new-21-game/ dominos[i] = "R"
# Alice plays the following game, loosely based on the card game "21".
# Alice starts with 0 points, and draws numbers while she has less than K points. return "".join(dominos)
# During each draw, she gains an integer number of points randomly from the range [1, W], where W is an integer.
# Each draw is independent and the outcomes have equal probabilities.
# Alice stops drawing numbers when she gets K or more points. What is the probability that she has N or less points? # python_1_to_1000/839_Similar_String_Groups.py - h
# Maintain the sum of the probabilities being at all numbers that can reach the next number. Update the next i as the _author_ = 'jake'
# window divided by W since each number in window has 1/W probability of moving to i. Add to window with new _project_ = 'leetcode'
# probability and remove probability from front of window.
# Time - O(N) # https://leetcode.com/problems/similar-string-groups/
# Space - O(N) # Two strings X and Y are similar if we can swap two letters (in different positions) of X, so that it equals Y.
# For example, "tars" and "rats" are similar (swapping at positions 0 and 2), and "rats" and "arts" are similar,
class Solution(object): # but "star" is not similar to "tars", "rats", or "arts".
def new21Game(self, N, K, W): # Together, these form two connected groups by similarity: {"tars", "rats", "arts"} and {"star"}.
""" # Notice that "tars" and "arts" are in the same group even though they are not similar.
:type N: int # Formally, each group is such that a word is in the group if and only if it is similar to at least one other
:type K: int # word in the group.
:type W: int # We are given a list A of strings. Every string in A is an anagram of every other string in A. Count the groups.
:rtype: float
""" # For each word, depth-first search all similar words to visit all words in a group. 2 different approaches are taken
if K == 0 or N >= K + W: # no draws or every reachable number <= N # to find similar words depensing whether there are few long words or many short words.
return 1 # If few long words, create a mapping from each word to the set of its similar words. Mapping is made by iterating over
# all pairs of words and checking if similar.
probability = [0] * (N + 1) # If many short words, find similar words by swapping all pairs of characters in a word.
probability[0] = 1.0 # Time - O(min(W N**2, N W**3)
window = 1.0 # sum of probabilities of numbers that can reach next number # Space - O(N W**3) since each word may have W**2 neighbours
probability[i] = window / W # 1 / W times the probability of each number that can reach i class Solution(object):
if i < K: def numSimilarGroups(self, A):
window += probability[i] # add to window """
if i - W >= 0: :type A: List[str]
window -= probability[i - W] # drop out from window :rtype: int
"""
return sum(probability[K:]) N, W = len(A), len(A[0])
word_swap = defaultdict(set)
groups = 0 # Depth-first search from the first room, recursively visiting all reachable rooms and ignoring those already visited.
visited = set() # Time - O(n)
# Space - O(n)
def dfs(w):
visited.add(w) class Solution(object):
for nbor in get_neighbours(w): def canVisitAllRooms(self, rooms):
if nbor not in visited: """
dfs(nbor) :type rooms: List[List[int]]
:rtype: bool
for word in A: """
if word in visited: visited = set()
continue
groups += 1 def dfs(room):
dfs(word)
if room in visited:
return groups return
visited.add(room)
for key in rooms[room]:
dfs(key)
# python_1_to_1000/840_Magic_Squares_In_Grid.py - m dfs(0)
return len(visited) == len(rooms)
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/842_Split_Array_into_Fibonacci_Sequence.py - m
# https://leetcode.com/problems/magic-squares-in-grid/
# A 3 x 3 magic square is a 3 x 3 grid filled with distinct numbers from 1 to 9 such that each row, column, _author_ = 'jake'
# and both diagonals all have the same sum. _project_ = 'leetcode'
# Given an grid of integers, how many 3 x 3 "magic square" subgrids are there? (Each subgrid is contiguous).
# https://leetcode.com/problems/split-array-into-fibonacci-sequence/
# Iterate over all possible top left corners of 3 x 3 squares. Reject if centre is not 5 or any number outside [0, 9]. # Given a string S of digits, such as S = "123456579", we can split it into a Fibonacci-like sequence [123, 456, 579].
# In each square, sum the rows, columns and diagonals. # Formally, a Fibonacci-like sequence is a list F of non-negative integers such that:
# Time - O(mn) # 0 <= F[i] <= 2^31 - 1, (that is, each integer fits a 32-bit signed integer type);
# Space - O(1) # F.length >= 3;
# and F[i] + F[i+1] = F[i+2] for all 0 <= i < F.length - 2.
class Solution(object): # Also, note that when splitting the string into pieces, each piece must not have extra leading zeroes,
def numMagicSquaresInside(self, grid): # except if the piece is the number 0 itself.
""" # Return any Fibonacci-like sequence split from S, or return [] if it cannot be done.
:type grid: List[List[int]]
:rtype: int # Try all possible lengths of starting number. Max starting number length is less than half the length of S to allow
""" # a sequence of at least 3 numbers. Try all possible lengths of second number, allowing for the remaining string to
def is_magic(row, col): # be at least as long as the longets of the 2 numbers. Attempt to build a sequence for the remainder of S given
# the first 2 numbers.
if grid[row + 1][col + 1] != 5: # centre must be 5 # Time - O(n**2)
return False # Space - O(n)
line_sums = [0 for _ in range(6)] # line_sums[:3] are sums of rows, line_sums[3:] are sums of cols class Solution(object):
diag1, diag2 = 0, 0 # descending and ascending diagonal def splitIntoFibonacci(self, S):
"""
for dr in range(3): :type S: str
for dc in range(3): :rtype: List[int]
"""
val = grid[row + dr][col + dc] MAX_NUM = 2 ** 31 - 1
if val < 1 or val > 9: # reject if number outside range
return False def helper(i, n1, n2): # build sequence from S[i] onwards starting with n1 and n2
line_sums[dr] += val # incerement all sums using this cell fib = [n1, n2]
line_sums[dc + 3] += val
if dr == dc: while i < len(S):
diag1 += val
if dr + dc == 2: next_num = fib[-1] + fib[-2]
diag2 += val if next_num > MAX_NUM:
return []
if any(line_sum != 15 for line_sum in line_sums): next_str = str(next_num)
return False if S[i:i + len(next_str)] != next_str: # next_str must match the next part of S
if diag1 != 15 or diag2 != 15: return []
return False fib.append(next_num)
return True i += len(next_str)
# Space - O(1)
if len1 > 1 and S[0] == "0": # no leading zero unless zero
return [] class Solution(object):
n1 = int(S[:len1]) def backspaceCompare(self, S, T):
if n1 > MAX_NUM: """
return [] :type S: str
:type T: str
len2 = 1 :rtype: bool
while len(S) - len1 - len2 >= max(len1, len2): """
s_i, t_i = len(S) - 1, len(T) - 1
if len2 > 1 and S[len1] == "0": # no leading zero unless zero
break def next_char(string, i): # finds index of next char not deleted
n2 = int(S[len1:len1 + len2]) delete = 0
if n2 > MAX_NUM: while i >= 0 and (delete or string[i] == "#"): # while more chars to be deleted
break delete = delete + 1 if string[i] == "#" else delete - 1
i -= 1
fibonacci = helper(len1 + len2, n1, n2) return i
if fibonacci:
return fibonacci while True:
len2 += 1
s_i = next_char(S, s_i)
return [] t_i = next_char(T, t_i)
candidates = wordlist[:] # all remaining candidates, initially all words elif A[i] > A[i - 1]:
while candidates: if prev == 1: # new peak
peak = i
s = most_overlap_word() # guess the word that overlaps with most others else: # previous index was valley
matches = master.guess(s) valley = i - 1
prev = 1
if matches == 6:
return elif A[i] < A[i - 1]:
if prev == 1: # previous index was peak
candidates = [w for w in candidates if pair_matches(s, w) == matches] # filter words with same matches peak = i - 1
longest = max(longest, i - valley + 1)
else: # more recent peak than valley makes a mountain
if peak > valley:
# python_1_to_1000/844_Backspace_String_Compare.py longest = max(longest, i - valley + 1)
prev = -1
_author_ = 'jake'
_project_ = 'leetcode' return longest
# https://leetcode.com/problems/backspace-string-compare/
# Given two strings S and T, return if they are equal when both are typed into empty text editors. # python_1_to_1000/846_Hand_of_Straights.py - m
# "#" means a backspace character.
_author_ = 'jake'
# Start at the ends of both strings. Step backwards to find the next non-deleted chars in both strings. Increment the _project_ = 'leetcode'
# chars to be deleted when "#" is seen, else decrement the number of chars to be deleted.
# Time - O(max(m, n)) # https://leetcode.com/problems/hand-of-straights/
# Alice has a hand of cards, given as an array of integers.
# Now she wants to rearrange the cards into groups so that each group is size W, and consists of W consecutive cards.
# Return true if and only if she can. # python_1_to_1000/848_Shifting_Letters.py - m
# Sort the integers. Maintain a heap of partial straights. For each integer, if it's the same as the end of partial _author_ = 'jake'
# straight with the lowest end integer, start another partial straight. If it's more than 1 + the end of the first _project_ = 'leetcode'
# partial straight, this straight cannot be completed. Else extend the straight and complete it if length W.
# Time - O(n log n) # https://leetcode.com/problems/shifting-letters/
# Space - O(n) # We have a string S of lowercase letters, and an integer array shifts.
# Call the shift of a letter, the next letter in the alphabet, (wrapping around so that 'z' becomes 'a').
import heapq # For example, shift('a') = 'b', shift('t') = 'u', and shift('z') = 'a'.
# Now for each shifts[i] = x, we want to shift the first i+1 letters of S, x times.
class Solution(object): # Return the final string after all such shifts to S are applied.
def isNStraightHand(self, hand, W):
""" # Iterate backwards over shifts. Maintain the cumulative_shift, adding each shift and shifting the char by the
:type hand: List[int] # cumulative_shift.
:type W: int # Time - O(n)
:rtype: bool # Space - O(n)
"""
if len(hand) % W != 0: # cannot make a whole number of straights class Solution(object):
return False def shiftingLetters(self, S, shifts):
if W == 1: """
return True :type S: str
:type shifts: List[int]
hand.sort() :rtype: str
partials = [] # heap of partial straights (last integer, straight length) """
s = [ord(c) - ord("a") for c in S] # convert to list of integers in [0, 25]
for num in hand:
cumulative_shift = 0
if not partials or partials[0][0] == num: # start a new straight for i in range(len(s) - 1, -1, -1):
heapq.heappush(partials, (num, 1)) cumulative_shift += shifts[i]
continue s[i] = (s[i] + cumulative_shift) % 26 # apply cumulative_shift to char
if num > partials[0][0] + 1: # gap between num and end of first stright cannot be filled return "".join(chr(c + ord("a")) for c in s)
return False
# area covered in the y direction * the distance since the previous x edge to the area. Update the set of rectangles return
# alive at x, then create a sorted list of y direction edges of alive rectangles. Iterate along the y edges, updating
# the y length between y edges provided some rectangle is alive. result[person] = person # default to self
# Time - O(n**2 log n)
# Space - O(n) for rich in richer_than[person]:
update_results(rich) # update the results for richer people
class Solution(object): if quiet[result[rich]] < quiet[result[person]]: # if quiet is lower for result of richer ...
def rectangleArea(self, rectangles): result[person] = result[rich] # ... then result of this person is result of richer person
"""
:type rectangles: List[List[int]] for i in range(n):
:rtype: int update_results(i)
"""
x_events = [] # edges of rectangles along x axis (x, start, index) return result
for i, (x1, y1, x2, y2) in enumerate(rectangles):
x_events.append((x1, True, i))
x_events.append((x2, False, i))
x_events.sort() # python_1_to_1000/852_Peak_Index_in_a_Mountain_Array.py - m
if start: # update the alive set for this edge # Binary search for the first index where the number at the next element is lower.
alive.add(i) # Time - O(log n)
else: # Space - O(l)
alive.discard(i)
class Solution(object):
y_events = [] # edges of alive rectangles along y axis def peakIndexInMountainArray(self, nums):
for i in alive: """
y_events.append((rectangles[i][1], 1)) # opening edge :type A: List[int]
y_events.append((rectangles[i][3], -1)) # closing edge :rtype: int
y_events.sort() """
left, right = 1, len(nums) - 2
y_coverage = 0
prev_y = 0 while left < right:
alive_y = 0 # count of open rectangles
for y, start_y in y_events: mid = (left + right) // 2
if alive_y > 0: # some rectangle(s) are alive so cover length since previous y if nums[mid + 1] < nums[mid]:
y_coverage += y - prev_y right = mid
else:
alive_y += start_y # increment or decrement the alive count left = mid + 1
prev_y = y
return left
return area % (10 ** 9 + 7)
# python_1_to_1000/853_Car_Fleet.py - m
_author_ = 'jake'
# python_1_to_1000/851_Loud_and_Rich.py - m _project_ = 'leetcode'
# python_1_to_1000/854_K-Similar_Strings.py - m max_dist, index = self.seats[0], 0 # max_dist is the distance from zero to the first occupied seat
for word in frontier: # Maintain a stack of opening brackets and the score within each opening bracket. When we see a closing bracket,
# either add or append 1, or multiply the previous top of stack by 2.
if word in visited: # Time - O(n)
continue # Space - O(n)
i = 0 class Solution(object):
while word[i] == B[i]: # find the first word[i] that is not correct def scoreOfParentheses(self, S):
i += 1 """
:type S: str
for j in range(i + 1, len(A)): :rtype: int
"""
if word[j] != B[i]: # reject if word[j] is not the the letter we need at word[i] stack = [] # opening brackets, followed by the score within that open bracket
continue
swapped = word[:i] + word[j] + word[i + 1:j] + word[i] + word[j + 1:] # swap word[i], word[j] for s in S:
new_frontier.add(swapped)
if s == "(":
k += 1 stack.append(s)
visited |= frontier # add old frontier to visited
frontier = new_frontier else: # closing bracket
item = stack.pop()
if item == "(": # matched pair of "()"
num = 1
# python_1_to_1000/855_Exam_Room.py - m else: # item is an integer
stack.pop() # discard opening bracket before integer
_author_ = 'jake' num = 2 * item
_project_ = 'leetcode'
if stack and stack[-1] != "(": # add if top of stack is a num, else append
# https://leetcode.com/problems/exam-room/ stack[-1] += num
# In an exam room, there are N seats in a single row, numbered 0, 1, 2, ..., N-1. else:
# When a student enters the room, they must sit in the seat that maximizes the distance to the closest person. stack.append(num)
# If there are multiple such seats, they sit in the seat with the lowest number.
# Also, if no one is in the room, then the student sits at seat number 0. return stack[0]
# Return a class ExamRoom(int N) that exposes two functions: ExamRoom.seat() returning an int representing what seat
# the student sat in, and ExamRoom.leave(int p) representing that the student in seat number p now leaves the room.
# It is guaranteed that any calls to ExamRoom.leave(p) have a student sitting in seat p.
# python_1_to_1000/857_Minimum_Cost_to_Hire_K_Workers.py - h
# Maintain a sorted list of seats that are occupied. If room is empty use the first seat. Else check the distances to
# the first seat, between all pairs of seats and to the last seat. Insert in sorted order and remove to leave. _author_ = 'jake'
# Time - O(n) for seat() and leave() _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/minimum-cost-to-hire-k-workers/
import bisect # There are N workers. The i-th worker has a quality[i] and a minimum wage expectation wage[i].
# Now we want to hire exactly K workers to form a paid group.
class ExamRoom(object): # When hiring a group of K workers, we must pay them according to the following rules:
# Every worker in the paid group should be paid in the ratio of their quality compared to other workers in the paid
def __init__(self, N): group.
""" # Every worker in the paid group must be paid at least their minimum wage expectation.
:type N: int # Return the least amount of money needed to form a paid group satisfying the above conditions.
"""
self.seats = [] # Sort worker by increasing wage_per_quality. The cost of employing a group is the maximum wage_per_quality * sum of
self.N = N # quality of the group. Form a group of the first K workers and find its total_quality and cost.
# Add each additional worker to the group, which increases the maximum wage_per_quality. Remove the worker with the
def seat(self): # highest quality, since they are most expensive to employ.
""" # Time - O(n logn)
:rtype: int # Space - O(n logn)
"""
import heapq
for c in range(1, cols): # all other columns
class Solution(object): col_count = sum(A[r][c] for r in range(rows)) # count set bits in column
def mincostToHireWorkers(self, quality, wage, K): best_col_count = max(col_count, rows - col_count) # flip if required, so most common bit is set
""" col_val = 2 ** ((cols - 1) - c) # score for a bit in this column
:type quality: List[int] score += col_val * best_col_count
:type wage: List[int]
:type K: int return score
:rtype: float
"""
wage_per_quality = [(w / float(q), q) for w, q in zip(wage, quality)] # python_1_to_1000/860_Lemonade_Change.py
wage_per_quality.sort()
_author_ = 'jake'
workers = [-q for _, q in wage_per_quality[:K]] # -qualities of workers in current group _project_ = 'leetcode'
heapq.heapify(workers)
total_quality = -sum(workers) # https://leetcode.com/problems/lemonade-change/
cost = wage_per_quality[K - 1][0] * total_quality # cost depends on highest wage_per_quality # At a lemonade stand, each lemonade costs $5.
# Customers are standing in a queue to buy from you, and order one at a time (in the order specified by bills).
for wpq, q in wage_per_quality[K:]: # Each customer will only buy one lemonade and pay with either a $5, $10, or $20 bill.
heapq.heappush(workers, -q) # You must provide the correct change to each customer, so that the net transaction is that the customer pays $5.
total_quality += q + heapq.heappop(workers) # remove worker with highest quality # Note that you don't have any change in hand at first.
cost = min(cost, wpq * total_quality) # Return true if and only if you can provide every customer with correct change.
return cost # Maintain a count of the number of 5 and 10 dollar notes held. For $5 paid, no change is given and for $10 paid
# we must give $5 change. For $20 given, try to use $10 in change if possible since there is no other use for $10.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/858_Mirror_Reflection.py - m
class Solution(object):
_author_ = 'jake' def lemonadeChange(self, bills):
_project_ = 'leetcode' """
:type bills: List[int]
# https://leetcode.com/problems/mirror-reflection/ :rtype: bool
# There is a special square room with mirrors on each of the four walls. """
# Except for the southwest corner, there are receptors on each of the remaining corners, numbered 0, 1, and 2. fives, tens = 0, 0 # no need to record twnetys, since they can never be used for change
# The square room has walls of length p, and a laser ray from the southwest corner first meets the east wall at a
# distance q from the 0th receptor. for bill in bills:
# Return the number of the receptor that the ray meets first.
# It is guaranteed that the ray will meet a receptor eventually. if bill == 5: # no change required
fives += 1
# Simulate the reflections. After k steps the vertical distance is kq, if this is divisible by p, we are at a corner.
# Identify which corner according to whether the number of reflections is odd or even and whether the vertical distance elif bill == 10: # must have $5 change
# is an odd or even multiple of the side length. if fives == 0:
# Time - O(p), all possible points on the wall could be visited before finding a corner return False
# Space - O(1) fives -= 1
tens += 1
class Solution(object):
def mirrorReflection(self, p, q): elif bill == 20: # try to use $10 + $5
""" if tens >= 1 and fives >= 1:
:type p: int tens -= 1
:type q: int fives -= 1
:rtype: int elif fives >= 3: # else try 3 * $5
""" fives -= 3
k = 1 else:
while (k * q) % p != 0: # vertical distance kq is not a multiple of side length p return False
k += 1
return True
if k % 2 == 0: # even number of steps
return 2
if ((k * q) // p) % 2 == 0: # vertical distance kq is an even multiple of side length p # python_1_to_1000/861_Score_After_Flipping_Matrix.py - m
return 0
return 1 _author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/859_Buddy_Strings.py # https://leetcode.com/problems/score-after-flipping-matrix/
# We have a two dimensional matrix A where each value is 0 or 1.
_author_ = 'jake' # A move consists of choosing any row or column, and toggling each value in that row or column:
_project_ = 'leetcode' # changing all 0s to 1s, and all 1s to 0s.
# After making any number of moves, every row of this matrix is interpreted as a binary number,
# https://leetcode.com/problems/buddy-strings/ # and the score of the matrix is the sum of these numbers.
# Given two strings A and B of lowercase letters, return true if and only if we can swap two letters in A so that # Return the highest possible score.
# the result equals B.
# Return False if lengths are not equal. If strings are the same then return True if any letter is duplicated in A,
# We can always set all the bits in the first column by either flipping rows that start with zero, or flipping all # else return False. Otherwise find the indices in A of letters that are in the wrong place. If there are not 2 such
# rows that start with one then flipping the whole column. These two cases result in the bits in the other columns # indices, return False. Finally, check if swapping the letters in the out of place positions will change A into B.
# being opposites. In either case we can flip each column so that the most common bit in that column is set. # Time - O(n)
# Time - O(mn) # Space - O(n)
# Space - O(mn)
from collections import Counter
class Solution(object):
def matrixScore(self, A): class Solution(object):
""" def buddyStrings(self, A, B):
:type A: List[List[int]] """
:rtype: int :type A: str
""" :type B: str
rows, cols = len(A), len(A[0]) :rtype: bool
"""
for r in range(rows): if len(A) != len(B):
if A[r][0] == 0: # row starts with zero return False
for c in range(1, cols): # flip all bits in the row
A[r][c] = 1 - A[r][c] if A == B:
return any(count > 1 for count in Counter(A).values())
score = rows * 2 ** (cols - 1) # first columns bits are all set
diffs = [i for i in range(len(A)) if A[i] != B[i]] # indices of letters out of place in A
if len(diffs) != 2: if not node:
return False return -1
return A[diffs[0]] == B[diffs[1]] and A[diffs[1]] == B[diffs[0]] # swapping letters at misplaced indices
if node == target:
nodes_at_distance(node, K) # add to results all nodes at distance K in this subtree
# python_1_to_1000/862_Shortest_Subarray_with_Sum_at_Least_K.py - h return 0
for i in range(n + 1): # Find which keys are in the grid and the starting location. Breadth-first search the graph of states until all keys
# have been found. States consist of a location and sorted string of the keys found so far. In each cycle, every state
while queue and prefix_sums[i] - prefix_sums[queue[0]] >= K: # in the frontier takes a step in all possible directions, potentially updating the locks acquired for the next state.
result = min(result, i - queue.popleft()) # check and discard in order of decreasing subarray length # Visited states are stored in a set so as not to be repeated.
# Time - O(mn * 2**k * k log k) for k keys
while queue and prefix_sums[queue[-1]] >= prefix_sums[i]: # Space - O(mn * k * 2**k)
queue.pop() # remove all greater prefix sums
class Solution(object):
queue.append(i) # append to right of queue def shortestPathAllKeys(self, grid):
"""
return result if result <= n else -1 :type grid: List[str]
:rtype: int
"""
# python_1_to_1000/863_All_Nodes_Distance_K_in_Binary_Tree.py - m rows, cols = len(grid), len(grid[0])
possible_keys = set("abcdef")
_author_ = 'jake' keys = set()
_project_ = 'leetcode'
for r in range(rows): # find the starting position and which keys are in the grid
# https://leetcode.com/problems/all-nodes-distance-k-in-binary-tree/ for c in range(cols):
# We are given a binary tree (with root node root), a target node, and an integer value K. if grid[r][c] == "@":
# Return a list of the values of all nodes that have a distance K from the target node. start_r, start_c = r, c
# The answer can be returned in any order. elif grid[r][c] in possible_keys:
keys.add(grid[r][c])
# Depth-first search until target is found. From target, add to results all nodes in subtree rooted at target that
# are at distance K. If target is in a subtree, if distance to target == K then ad this node to results, else if steps = 0
# distance to target is less than K then explore the subtree that does not contain target, adding to results all nodes frontier = [(start_r, start_c, "")] # states as tuples of (row, column, locks acquired)
# that are total distance K form target. visited = set()
# Time - O(n) neighbours = ((1, 0), (-1, 0), (0, 1), (0, -1))
# Space - O(n)
while frontier:
class Solution(object):
def distanceK(self, root, target, K): new_frontier = set()
"""
:type root: TreeNode for r, c, open_locks in frontier:
:type target: TreeNode
:type K: int if (r, c, open_locks) in visited: # ignore visited, outside grid, obstacle and locked doors
:rtype: List[int] continue
""" if r < 0 or r >= rows or c < 0 or c >= cols:
results = [] continue
if grid[r][c] == "#":
def nodes_at_distance(node, distance): # update results for all subtree nodes at distance from node continue
if "A" <= grid[r][c] <= "F" and grid[r][c] not in open_locks:
if not node: continue
return
if distance == 0: visited.add((r, c, open_locks))
results.append(node.val)
else: if grid[r][c] in keys and grid[r][c].upper() not in open_locks:
nodes_at_distance(node.left, distance - 1) open_locks = "".join(sorted(open_locks + grid[r][c].upper())) # update sorted string of open locks
nodes_at_distance(node.right, distance - 1)
if len(open_locks) == len(keys):
def helper(node): # returns distance to target in this subtree or -1 if no target return steps
while True:
for dr, dc in neighbours: candidate = int(str(lhs) + str(lhs)[-2::-1]) # will have odd length
new_frontier.add((r + dr, c + dc, open_locks)) if candidate >= N and is_prime(candidate):
return candidate
frontier = new_frontier lhs += 1
steps += 1
return -1 # python_1_to_1000/867_Transpose_Matrix.py
_author_ = 'jake'
# python_1_to_1000/865_Smallest_Subtree_with_all_the_Deepest_Nodes.py - m _project_ = 'leetcode'
while N > 0:
# python_1_to_1000/866_Prime_Palindrome.py - m
if N & 1: # bit is set
_author_ = 'jake' if previous is not None:
_project_ = 'leetcode' max_gap = max(max_gap, i - previous)
previous = i
# https://leetcode.com/problems/prime-palindrome/
# Find the smallest prime palindrome greater than or equal to N. N >>= 1 # remove bit
# Recall that a number is prime if it's only divisors are 1 and itself, and it is greater than 1. i += 1
# For example, 2,3,5,7,11 and 13 are primes.
# Recall that a number is a palindrome if it reads the same from left to right as it does from right to left. return max_gap
# For example, 12321 is a palindrome.
# Iterate through palindromes until we find one >= N and prime. For N of length n, build palindromes of length n if n # python_1_to_1000/869_Reordered_Power_of_2.py - m
# is odd, else of length n + 1. Since 11 is the only even length prime palindromes, we only consider odd length
# candidates. Prime checking of x is by testing divisibility by all odd integers <= sqrt(x). _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(log n)
# https://leetcode.com/problems/reordered-power-of-2/
class Solution(object): # Starting with a positive integer N, we reorder the digits in any order (including the original order)
def primePalindrome(self, N): # such that the leading digit is not zero.
""" # Return true if and only if we can do this in a way such that the resulting number is a power of 2.
:type N: int
:rtype: int # Find the smallest power of 2 with the same length as N. Check the digit of this and all subsequent powers of 2
""" # until the length is greater than N.
def is_prime(x): # Time - O(log n)
if x < 2 or x % 2 == 0: # remove 0, 1 and even numbers # Space - O(log n)
return x == 2
for i in range(3, int(x ** 0.5) + 1, 2): # check odds <= sqrt(x) from math import ceil, log
if x % i == 0: from collections import Counter
return False
return True class Solution(object):
def reorderedPowerOf2(self, N):
if 8 <= N <= 11: # 11 is the only result with even number of digits """
return 11 :type N: int
:rtype: bool
n = len(str(N)) """
lhs = 10 ** (n // 2) # left side of candidate, including middle digit digit_count = Counter(str(N)) # count the digits of N
len_N = len(str(N))
power_of_two = 2 ** int(ceil(log(10 ** (len_N - 1), 2))) # the smallest power of 2 of length len_N if not past_fuels: # no more unused previous stations
str_power_of_two = str(power_of_two) return -1
while len(str_power_of_two) == len_N: # until length is too long fuel -= heapq.heappop(past_fuels) # use the previous station with the most fuel
if Counter(str_power_of_two) == digit_count: stops += 1
return True
power_of_two *= 2 heapq.heappush(past_fuels, -station_fuel) # add this station's fuel to unused fuel
str_power_of_two = str(power_of_two)
return stops
return False
# python_1_to_1000/872_Leaf-Similar_Trees.py
# python_1_to_1000/870_Advantage_Shuffle.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/leaf-similar-trees/
# https://leetcode.com/problems/advantage-shuffle/ # Consider all the leaves of a binary tree.
# Given two arrays A and B of equal size, the advantage of A with respect to B is the number of indices i # From left to right order, the values of those leaves form a leaf value sequence.
# for which A[i] > B[i]. # Two binary trees are considered leaf-similar if their leaf value sequence is the same.
# Return any permutation of A that maximizes its advantage with respect to B. # Return true if and only if the two given trees with head nodes root1 and root2 are leaf-similar.
# Sort B, storing the index of each element along with its value. For each element a of sorted(A), if a > smallest # Generate the leaves by inorder traversal. Yield from the left subtree, yield the node value then yield from the
# unused element of B then put a in the result at the index of the smallest unused element of B. Else a is not # right subtree. Zip the inorder traversals together up to the longest sequence and check all values are equal.
# greater than any element of B, so put it in the result at the largest unused element of B. # Time - O(n)
# Time - O(n log n) # Space - O(1)
# Space - O(n)
import itertools
class Solution(object):
def advantageCount(self, A, B): class Solution(object):
""" def leafSimilar(self, root1, root2):
:type A: List[int] """
:type B: List[int] :type root1: TreeNode
:rtype: List[int] :type root2: TreeNode
""" :rtype: bool
B_i = sorted([(b, i) for i, b in enumerate(B)]) """
result = [None] * len(A)
i = 0 def inorder(node):
if node.left: # check left subtree
for a in sorted(A): yield from inorder(node.left)
if not node.left and not node.right: # yield the leaf val
if a > B_i[i][0]: yield node.val
result[B_i[i][1]] = a if node.right: # check right subtree
i += 1 yield from inorder(node.right)
else:
result[B_i.pop()[1]] = a leaves = itertools.zip_longest(inorder(root1), inorder(root2))
# python_1_to_1000/871_Minimum_Number_of_Refueling_Stops.py - h # python_1_to_1000/873_Length_of_Longest_Fibonacci_Subsequence.py - m
# https://leetcode.com/problems/minimum-number-of-refueling-stops/ # https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/
# A car travels from a starting position to a destination which is target miles east of the starting position. # A sequence X_1, X_2, ..., X_n is fibonacci-like if:
# Along the way, there are gas stations. # n >= 3
# Each station[i] represents a gas station that is station[i][0] miles east of the starting position, # X_i + X_{i+1} = X_{i+2} for all i + 2 <= n
# and has station[i][1] liters of gas. # Given a strictly increasing array A of positive integers forming a sequence,
# The car starts with an infinite tank of gas, which initially has startFuel liters of fuel in it. # find the length of the longest fibonacci-like subsequence of A. If one does not exist, return 0.
# It uses 1 liter of gas per 1 mile that it drives. # Recall that a subsequence is derived from another sequence A by deleting any number of elements (including none)
# When the car reaches a gas station, it may stop and refuel, transferring all the gas from the station into the car. # from A, without changing the order of the remaining elements.
# What is the least number of refueling stops the car must make in order to reach its destination?
# If it cannot reach the destination, return -1. # For each pair of numbers, attempt to build a Fibonacci sequence. Copy the integers into a set for O(1) lookup when
# Note that if the car reaches a gas station with 0 fuel left, the car can still refuel there. # testing if a sequence can be extended.
# If the car reaches the destination with 0 fuel left, it is still considered to have arrived. # Time - O(n**2)
# Space - O(n)
# Maintain a heap of fuel at previous stations that has not been used. At each station the total fuel used must not be
# less than the distance. If it is less, use fuel from previous stations starting with the largest amounts. If no more class Solution(object):
# fuel is unused, we cannot reach the target. def lenLongestFibSubseq(self, A):
# Time - O(n log n) """
# Space - O(n) :type A: List[int]
:rtype: int
import heapq """
A_set = set(A)
class Solution: max_length = 0
def minRefuelStops(self, target, startFuel, stations):
""" for i, num in enumerate(A):
:type target: int
:type startFuel: int for num2 in A[i + 1:]:
:type stations: List[List[int]]
:rtype: int prev_num = num2
""" next_num = num + num2
stops = 0 length = 2
fuel = startFuel # total fuel used while next_num in A_set: # sequence can be extended
past_fuels = [] # heap of unused fuel from previous stations length += 1
stations.append([target, 0]) # target is beyond final station next_num, prev_num = next_num + prev_num, next_num
while fuel < distance: # cannot reach this station without more fuel return max_length if max_length >= 3 else 0
time = 0
for pile in piles:
# python_1_to_1000/874_Walking_Robot_Simulation.py - m time += (pile + rate - 1) // rate # time to eat this pile
if time > H: # stop if already taken too long
_author_ = 'jake' break
_project_ = 'leetcode'
if time > H: # increase minimum rate
# https://leetcode.com/problems/walking-robot-simulation/ min_rate = rate + 1
# A robot on an infinite grid starts at point (0, 0) and faces north. else: # result is this rate or lower
# The robot can receive one of three possible types of commands: max_rate = rate
# -2: turn left 90 degrees
# -1: turn right 90 degrees return min_rate
# 1 <= x <= 9: move forward x units
# Some of the grid squares are obstacles.
# The i-th obstacle is at grid point (obstacles[i][0], obstacles[i][1]) # python_1_to_1000/876_Middle_of_the_Linked_List.py
# If the robot would try to move onto them, the robot stays on the previous grid square instead (but still
# continues following the rest of the route.) _author_ = 'jake'
# Return the square of the maximum Euclidean distance that the robot will be from the origin. _project_ = 'leetcode'
# Track the postition and orientation of the robot. When moving forwards, check if the next position is an obstacle # https://leetcode.com/problems/middle-of-the-linked-list/
# and stop if so. # Given a non-empty, singly linked list with head node head, return a middle node of linked list.
# Time - O(n) total number of operations (since at most 9 steps forwards) # If there are two middle nodes, return the second middle node.
# Space - O(m) number of obstacles
# Move fast pointer for 2 steps and slow pointer for 1 step until fast does not have a next next.
class Solution(object): # Time - O(n)
def robotSim(self, commands, obstacles): # Space - O(1)
"""
:type commands: List[int] class Solution(object):
:type obstacles: List[List[int]] def middleNode(self, head):
:rtype: int """
""" :type head: ListNode
NORTH, EAST, SOUTH, WEST = 0, 1, 2, 3 :rtype: ListNode
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] # change of position in each direction """
slow, fast = head, head
position, orientation = (0, 0), NORTH while fast and fast.next:
max_sqr_distance = 0 slow, fast = slow.next, fast.next.next
obstacles = {tuple(obstacle) for obstacle in obstacles} # convert to set for O(1) lookup return slow
for p in range(P, -1, -1): # for schemes with all profits ...
for g in range(G, job_gang - 1, -1): # and enough members to do this job # python_1_to_1000/882_Reachable_Nodes_In_Subdivided_Graph.py - h
capped_profit = min(P, p + job_profit) # cap profit including this job at P
schemes[capped_profit][g] += schemes[p][g - job_gang] # add schemes before this job _author_ = 'jake'
_project_ = 'leetcode'
return sum(schemes[-1]) % MOD # all schemes with profit at least P and gang <= G
# https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/
# Starting with an undirected graph (the "original graph") with nodes from 0 to N-1,
# python_1_to_1000/880_Decoded_String_at_Index.py - m # subdivisions are made to some of the edges.
# The graph is given as follows: edges[k] is a list of integer pairs (i, j, n) such that (i, j) is an edge of the
_author_ = 'jake' # original graph, and n is the total number of new nodes on that edge.
_project_ = 'leetcode' # Then, the edge (i, j) is deleted from the original graph, n new nodes (x_1, x_2, ..., x_n) are added to the
# original graph, and n+1 new edges (i, x_1), (x_1, x_2), (x_2, x_3), ..., (x_{n-1}, x_n), (x_n, j) are added to
# https://leetcode.com/problems/decoded-string-at-index/ # the original graph.
# An encoded string S is given. To find and write the decoded string to a tape, # Now, you start at node 0 from the original graph, and in each move, you travel along one edge.
# the encoded string is read one character at a time and the following steps are taken: # Return how many nodes you can reach in at most M moves.
# If the character read is a letter, that letter is written onto the tape.
# If the character read is a digit (say d), the entire current tape is repeatedly written d-1 more times in total. # Modified Dijkstra's algorithm. Maintain a priority queue of nodes sorted by the minimum number of steps to reach a
# Now for some encoded string S, and an index K, find and return the K-th letter (1 indexed) in the decoded string. # that node. For each node in queue, travel along all adjacent edges visiting as many of the edges along the node as
# possible. If all edge nodes are visited, add the neighbouring node to the queue. Record the number of nodes vistied
# Find the index of S where the decoded string is of length at least K. Iterate backwards in S from the found index. # from both ends of each edge. Sum all real nodes visited plus the node from both sides of each edges, capped at the
# For every digit, divide the decoded length by the digit and update K to be the remainder when dividing by the new # the total number of edge nodes.
# length. For every character, return if the decoded string has the required length else decrement the length. # Time - O(n log n) where n is the length of edges, since each edge can be added to the heap.
# Time - O(n) # Space - O(n)
# Space - O(1)
import heapq
class Solution(object): from collections import defaultdict
def decodeAtIndex(self, S, K):
""" class Solution(object):
:type S: str def reachableNodes(self, edges, M, N):
:type K: int """
:rtype: str :type edges: List[List[int]]
""" :type M: int
length = 0 :type N: int
for index, c in enumerate(S): :rtype: int
if steps + distance + 1 <= M: # visited all node on edge, add nbor to queue # Move in a spiral until all cells of the grid have been visited. Step along each side, then turn to next direction.
heapq.heappush(queue, (steps + distance + 1, nbor)) # Each cell visited within the grid is appended to the result. Spiral has two sides of the same length, then two sides
# of length + 1, etc.
result = len(visited) # all nodes # Time - O(max(m, n)**2)
for (a, b), (distance, covered) in subdivisions.items(): # Space - O(mn)
if a < b:
result += min(distance, covered + subdivisions[(b, a)][1]) # sum edge nodes from both sides class Solution(object):
def spiralMatrixIII(self, R, C, r0, c0):
return result """
:type R: int
:type C: int
# python_1_to_1000/883_Projection_Area_of_3D_Shapes.py :type r0: int
:type c0: int
_author_ = 'jake' :rtype: List[List[int]]
_project_ = 'leetcode' """
moves = [[0, 1], [1, 0], [0, -1], [-1, 0]] # change in r and c foa move in each direction
# https://leetcode.com/problems/projection-area-of-3d-shapes/ r, c = r0, c0
# On a N * N grid, we place some 1 * 1 * 1 cubes that are axis-aligned with the x, y, and z axes. direction = 0
# Each value v = grid[i][j] represents a tower of v cubes placed on top of grid cell (i, j). result = [[r0, c0]]
# Now we view the projection of these cubes onto the xy, yz, and zx planes. side = 1 # current length of side of spiral
# A projection is like a shadow, that maps our 3 dimensional figure to a 2 dimensional plane.
# Here, we are viewing the "shadow" when looking at the cubes from the top, the front, and the side. while len(result) < R * C:
# Return the total area of all three projections.
dr, dc = moves[direction]
# Base area is the count of all cells with height > 0. Side areas are the sums of maximum heights by column and by
# row respectively. for _ in range(side): # step along the side
# Time - O(mn) r += dr
# Space - O(m + n) c += dc
if 0 <= r < R and 0 <= c < C: # append to result if within bounds of grid
class Solution(object): result.append([r, c])
def projectionArea(self, grid):
""" direction = (direction + 1) % 4 # next direction
:type grid: List[List[int]] dr, dc = moves[direction]
:rtype: int
""" for _ in range(side):
n = len(grid) r += dr
row_heights, col_heights = [0] * n, [0] * n c += dc
base_area = 0 if 0 <= r < R and 0 <= c < C:
result.append([r, c])
for row in range(n):
for col in range(n): direction = (direction + 1) % 4
side += 1 # after 2 sides of spiral, increase side length
if grid[row][col] != 0:
base_area += 1 return result
row_heights[row] = max(row_heights[row], grid[row][col])
col_heights[col] = max(col_heights[col], grid[row][col])
# python_1_to_1000/886_Possible_Bipartition.py - m
return base_area + sum(row_heights) + sum(col_heights)
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/884_Uncommon_Words_from_Two_Sentences.py
# https://leetcode.com/problems/possible-bipartition/
_author_ = 'jake' # Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into two groups of any size.
_project_ = 'leetcode' # Each person may dislike some other people, and they should not go into the same group.
# Formally, if dislikes[i] = [a, b], it means it is not allowed to put the people numbered a and b into the same group.
# https://leetcode.com/problems/uncommon-words-from-two-sentences/ # Return true if and only if it is possible to split everyone into two groups in this way.
# We are given two sentences A and B. A sentence is a string of space separated words.
# Each word consists only of lowercase letters. # Map each person to the set of people they dislike. For each person, put them in a group then find all the people
# A word is uncommon if it appears exactly once in one of the sentences, and does not appear in the other sentence. # they dislike. If any of the disliked are in the group then return False, else remove from disliked all those already
# Return a list of all uncommon words in any order. # in the other group, swap the groups and repeat by placing the disliked.
# Time - O(n**2), the length of dislikes
# Add the counts of frequencies of words in each sentence. Return the list of words whose total count is one. # Space - O(n**2)
# Time - O(m + n)
# Space - O(m + n) from collections import defaultdict
# python_1_to_1000/887_Super_Egg_Drop.py - h # The root is the first node of pre and the last node of post. The penultimate node of post is the root of the right
# subtree of root. Find this right root in pre. All nodes before it in pre form the left subtree and all after and
_author_ = 'jake' # including form the right subtree. The nodes in post that form the left subtree are deduced from the length of the
_project_ = 'leetcode' # sile of pre that forms the left subtree. A mapping of pre from value to index ensures finding a node is O(1).
# Time - O(n)
# https://leetcode.com/problems/super-egg-drop/ # Space - O(n)
# You are given K eggs, and you have access to a building with N floors from 1 to N.
# Each egg is identical in function, and if an egg breaks, you cannot drop it again. class Solution(object):
# You know that there exists a floor F with 0 <= F <= N such that any egg dropped at a floor higher than F will break, def constructFromPrePost(self, pre, post):
# and any egg dropped at or below floor F will not break. """
# Each move, you may take an egg (if you have an unbroken one) and drop it from any floor X (with 1 <= X <= N). :type pre: List[int]
# Your goal is to know with certainty what the value of F is. :type post: List[int]
# What is the minimum number of moves that you need to know with certainty what F is, :rtype: TreeNode
# regardless of the initial value of F? """
def helper(pre_start, pre_end, post_start, post_end): # build subtree using pre[pre_start:pre_end]
# If we know the maximum height of building for which we can learn the highest floor that an egg can be dropped from # and post[post_start, post_end]
# without breaking for a certain number of drops (d) and a certain number of eggs (e). Call this f(d, e). if pre_start == pre_end:
# We also know the same result for the same number of drops and one fewer egg = f(d, e - 1). return None
# Now we take an additional drop from floor f(d, e - 1) + 1.
# If it breaks, we know that we can find the result with one less egg f(d, e - 1). root = TreeNode(pre[pre_start])
# If it doesn't break, we can explore the f(d, e) floors above the one we just dropped from. if post_end == post_start + 1:
# So we can get the result for a building of height 1 + f(d, e - 1) + f(d, e). return root
# Time - O(K log N) since floors[K] grows exponentially with each drop. idx = pre_indices[post[post_end - 2]] # index of root of right subtree in pre
# Space - O(K) left_size = idx - pre_start - 1 # number of nodes in left subtree
root.left = helper(pre_start + 1, idx, post_start, post_start + left_size)
class Solution(object): root.right = helper(idx, pre_end, post_start + left_size, post_end - 1)
def superEggDrop(self, K, N):
""" return root
:type K: int
:type N: int pre_indices = {val: i for i, val in enumerate(pre)} # map from node value to index in pre
:rtype: int return helper(0, len(pre), 0, len(post))
"""
drops = 0
floors = [0 for _ in range(K + 1)] # floors[i] is the number of floors that can be checked with i eggs # python_1_to_1000/890_Find_and_Replace_Pattern.py - h
for c in s: # python_1_to_1000/893_Groups_of_Special-Equivalent_Strings.py - m
if c not in mapping: # create a new mapping if c has not been seen before
mapping[c] = value _author_ = 'jake'
value += 1 _project_ = 'leetcode'
result.append(mapping[c])
return tuple(result) # https://leetcode.com/problems/groups-of-special-equivalent-strings/
# You are given an array A of strings.
pattern = canonical(pattern) # Two strings S and T are special-equivalent if after any number of moves, S == T.
return [word for word in words if canonical(word) == pattern] # A move consists of choosing two indices i and j with i % 2 == j % 2, and swapping S[i] with S[j].
# Now, a group of special-equivalent strings from A is a non-empty subset S of A such that any string not in S is
# not special-equivalent with any string in S.
# Return the number of groups of special-equivalent strings from A.
# python_1_to_1000/891_Sum_of_Subsequence_Widths.py - h
# For each string create a canonical representation, which is the same for special-equivalent strings.
_author_ = 'jake' # Strings are special-equivalent if their chars at even indices can be arranged to be identical and their chars at
_project_ = 'leetcode' # odd indices can be arranged to be identical.
# The representation is the sorted chars at even indices concatenated to the sorted chars at odd indices.
# https://leetcode.com/problems/sum-of-subsequence-widths/ # Create a set of the unique representations.
# Given an array of integers A, consider all non-empty subsequences of A. # Time - O(n), total length of all strings
# For any sequence S, let the width of S be the difference between the maximum and minimum element of S. # Space - O(n)
# Return the sum of the widths of all subsequences of A.
# As the answer may be very large, return the answer modulo 10^9 + 7. class Solution(object):
def numSpecialEquivGroups(self, A):
# Sort the numbers. For each number A[i] there are 2**i subsequences where A[i] is the maximum. Add to the result the """
# maximum value of all such subsequences. :type A: List[str]
# There are 2**(len(A)-1-i) subsequences where A[i] is the minimum. Subtract from the result the minimum value of all :rtype: int
# such subsequences. For every subsequence the maximum is added and the minimum is subtracted, resulting in the width. """
# Bitwise shift is faster than pow() or the ** operator. def canonical(s):
# Time - O(n log n) evens = sorted([s[i] for i in range(0, len(s), 2)])
# Space - O(1) odds = sorted([s[i] for i in range(1, len(s), 2)])
return "".join(evens + odds)
class Solution(object):
def sumSubseqWidths(self, A): return len({canonical(s) for s in A})
"""
:type A: List[int]
:rtype: int # python_1_to_1000/894_All_Possible_Full_Binary_Trees.py - m
"""
result = 0 _author_ = 'jake'
n = len(A) _project_ = 'leetcode'
A.sort()
# https://leetcode.com/problems/all-possible-full-binary-trees/
for i, num in enumerate(A): # A full binary tree is a binary tree where each node has exactly 0 or 2 children.
result += (1 << i) * num # Return a list of all possible full binary trees with N nodes.
result -= (1 << (n - 1 - i)) * num # Each element of the answer is the root node of one possible tree.
# Each node of each tree in the answer must have node.val = 0.
return result % (10 ** 9 + 7) # You may return the final list of trees in any order.
# If N is even we cannot build a full tree. To build a tree of size N, create a root and for each odd sized left
# python_1_to_1000/892_Surface_Area_of_3D_Shapes.py # subtree, build all possible left and right subtrees. Combine the left and right subtrees in all possible ways.
# Memoize intermediate results to avoid repetition.
_author_ = 'jake' # Time - O(2**n)
_project_ = 'leetcode' # Space - O(2**n)
class Solution(object): if n % 2 == 0:
def surfaceArea(self, grid): return []
""" if n == 1:
:type grid: List[List[int]] return [TreeNode(0)]
:rtype: int if n in memo:
""" return memo[n]
n = len(grid)
area = 0 result = []
return num
# python_1_to_1000/899_Orderly_Queue.py - h
# https://leetcode.com/problems/increasing-order-search-tree/ # python_1_to_1000/900_RLE_Iterator.py - m
# Given a tree, rearrange the tree in in-order so that the leftmost node in the tree is now the root of the tree,
# and every node has no left child and only 1 right child. _author_ = 'jake'
_project_ = 'leetcode'
# Amend the function signature so it converts a tree and then appends a tail tree.
# Create a new node with same value as the root, so references to the root's children are retained. Convert the right # https://leetcode.com/problems/rle-iterator/
# subtree and append the tail. Convert the left subtree and append the right subtree. # Write an iterator that iterates through a run-length encoded sequence.
# Time - O(n) # The iterator is initialized by RLEIterator(int[] A), where A is a run-length encoding of some sequence.
# More specifically, for all even i, A[i] tells us the number of times that the non-negative integer value A[i+1] is # with the same number of digits as the suffix. Attempt to use each digit d of D as the first digit of the suffix.
# repeated in the sequence. # If d is less than the first digit of suffix the all combinations of other digits are allowed. If d is the same as the
# The iterator supports one function: next(int n), which exhausts the next n elements (n >= 1) and returns the last # first digit of the suffix, the results for the previous suffix are allowed.
# element exhausted in this way. If there is no element left to exhaust, next returns -1 instead. # Finally add all solutions that use fewer digits.
# For example, we start with A = [3,8,0,9,2,5], which is a run-length encoding of the sequence [8,8,8,5,5]. # Time - O(log N) (since len(D) is at most 9)
# This is because the sequence can be read as "three eights, zero nines, two fives". # Space - O(log N)
# Maintain index of the count of the next element to be checked. While next requires mode elements than the current class Solution(object):
# count, decrement the required n by the count and move to the next element. The decrement the count by n and return def atMostNGivenDigitSet(self, D, N):
# that element. """
# Time - O(1) to initialize, O(n) for next :type D: List[str]
# Space - O(n) :type N: int
:rtype: int
class RLEIterator(object): """
S = str(N)
def __init__(self, A): K = len(S)
"""
:type A: List[int] dp = [0] * K + [1] # dp[i] is the result for suffix N[i:] with the same number of digits as N[i:]
"""
self.encoding = A for i in range(K - 1, -1, -1):
self.length = len(A)
self.i = 0 # index of next count to be used for d in D:
def next(self, n): if d < S[i]: # every combination of less significant digits is allowed
""" dp[i] += len(D) ** (K - i - 1)
:type n: int elif d == S[i]: #
:rtype: int dp[i] += dp[i + 1]
"""
while self.i < self.length and self.encoding[self.i] < n: # require more elements than current count return dp[0] + sum(len(D) ** i for i in range(1, K)) # add solutions with fewer digits
n -= self.encoding[self.i] # use all elements
self.i += 2 # move to next count
# https://leetcode.com/problems/valid-permutations-for-di-sequence/
# python_1_to_1000/901_Online_Stock_Span.py - m # We are given S, a length n string of characters from the set {'D', 'I'}.
# These letters stand for "decreasing" and "increasing".
_author_ = 'jake' # A valid permutation is a permutation P[0], P[1], ..., P[n] of integers {0, 1, ..., n}, such that for all i:
_project_ = 'leetcode' # If S[i] == 'D', then P[i] > P[i+1], and;
# If S[i] == 'I', then P[i] < P[i+1].
# https://leetcode.com/problems/online-stock-span/ # How many valid permutations are there? Since the answer may be large, return your answer modulo 10^9 + 7.
# Write a class StockSpanner which collects daily price quotes for some stock, and returns the span of that stock's
# price for the current day. # Dynamic programming. For each character dp[i] is the number of results where the last number of the permutation is
# The span of the stock's price today is defined as the maximum number of consecutive days (starting from today and # the i + 1th smallest amongst all numbers unused so far in that permutation (including that last number).
# going backwards) for which the price of the stock was less than or equal to today's price. # If the next character is "D" then update dp[i] with the sum of all existing dp[j] where j > i, since we can move down
# For example, if the price of a stock over the next 7 days were [100, 80, 60, 70, 60, 75, 85], # from any solution where the final digit was ranked higher.
# then the stock spans would be [1, 1, 1, 2, 1, 4, 6]. # Time - O(n**2)
# Space - O(n)
# Maintain a stack of descending prices and their spans. While the next price is greater than or equal to the previous
# price, remove the previous price from the stack and add its count to the result. Append the price and its span to class Solution:
# the stack before returning the span. def numPermsDISequence(self, S):
# Time - O(n), worst case is everything must be popped off stack """
# Space - O(n) :type S: str
:rtype: int
class StockSpanner(object): """
dp = [1] * (len(S) + 1) # dp[i] is nb solutions where the last number
def __init__(self): # is the i+1th smallest amongst all unused numbers
self.stack = [] for move in S:
self.stack.append([price, result])
return result # python_1_to_1000/904_Fruit_Into_Baskets.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/902_Numbers_At_Most_N_Given_Digit_Set.py - h # https://leetcode.com/problems/fruit-into-baskets/
# In a row of trees, the i-th tree produces fruit with type tree[i].
_author_ = 'jake' # You start at any tree of your choice, then repeatedly perform the following steps:
_project_ = 'leetcode' # Add one piece of fruit from this tree to your baskets. If you cannot, stop.
# Move to the next tree to the right of the current tree. If there is no tree to the right, stop.
# https://leetcode.com/problems/numbers-at-most-n-given-digit-set/ # Note that you do not have any choice after the initial choice of starting tree: you must perform step 1,
# We have a sorted set of digits D, a non-empty subset of {'1','2','3','4','5','6','7','8','9'}. # then step 2, then back to step 1, then step 2, and so on until you stop.
# Note that '0' is not included. # You have two baskets, and each basket can carry any quantity of fruit, but you want each basket to only carry
# Now, we write numbers using these digits, using each digit as many times as we want. # one type of fruit each.
# For example, if D = {'1','3','5'}, we may write numbers such as '13', '551', '1351315'. # What is the total amount of fruit you can collect with this procedure?
# Return the number of positive integers that can be written (using the digits of D) that are less than or equal to N.
# The problem is to find the longest contiguous subarray containing only 2 different elements.
# Iterate over N from the least to most significant digit. For each suffix of N, calculate the number of solutions # For the 2 fruits in baskets, store the fruit and their first and last indices in the subarray.
# For each new fruit there are 5 cases: :type R: str
# No previous fruits - set prev :rtype: int
# Only one previous fruit - swap prev to other and update prev and the result """
# Fruit same as prev - update last index of prev and result L_sqrt = int(int(L) ** 0.5)
# Fruit same as other - update last index of prev, swap prev and other and update result R_sqrt = int((int(R) + 1) ** 0.5)
# Different fruit - replace other with prev and start index after the end index of other digits = [str(i) for i in range(10)]
# Time - O(n)
# Space - O(1) def is_palindrome(i):
return str(i) == str(i)[::-1]
class Solution:
def totalFruit(self, tree): prev_palis, palis = [""], digits[:] # palindromes with zero and one digit
""" result = sum(L_sqrt <= i <= R_sqrt and is_palindrome(i ** 2) for i in range(10))
:type tree: List[int]
:rtype: int for _ in range(2, 11): # gradually increase the palindrome length
"""
prev = [None, float("inf"), float("inf")] # [fruit, first_i, last_i] new_palis = []
other = [None, float("inf"), float("inf")]
for digit in digits:
result = 1 for pal in prev_palis: # palindromes of length - 2
for i, fruit in enumerate(tree): new_pal = digit + pal + digit # make new palindrome
new_palis.append(new_pal)
if fruit == prev[0]:
prev[2] = i if new_pal[0] == "0": # do not check if superpalindrome
result = max(result, i + 1 - min(prev[1], other[1])) continue
elif prev[0] is None: if L_sqrt <= num and is_palindrome(num ** 2): # superpalindrome
prev = [fruit, i, i] result += 1
# python_1_to_1000/905_Sort_Array_By_Parity.py # Stack contains indices of elements that have not been used as the minimum of some subarray.
# Stack refers to elements in non-decreasing order. Iterate over A. While the current element of A is less than the
_author_ = 'jake' # top of the stack, then the top of the stack is the minimum of all subarrays bounded by the previous stack item
_project_ = 'leetcode' # and the current element. Add to the result the value of the element * number of subarrays with all possible left
# and right boundaries.
# https://leetcode.com/problems/sort-array-by-parity/ # Time - O(n)
# Given an array A of non-negative integers, return an array consisting of all the even elements of A, # Space - O(n)
# followed by all the odd elements of A.
# You may return any answer array that satisfies this condition class Solution:
def sumSubarrayMins(self, A):
# Iterate over A, alternately adding elements to lists of elements at add and even indices. Concatenate result. """
# In Pythonn the iteration is achieved by list comprehension. :type A: List[int]
# Time - O(n) :rtype: int
# Space - O(n) """
A = [float("-inf")] + A + [float("-inf")]
class Solution(object): result = 0
def sortArrayByParity(self, A): stack = []
"""
:type A: List[int] for i, num in enumerate(A):
:rtype: List[int]
""" while stack and num < A[stack[-1]]:
return [num for num in A if num % 2 == 0] + [num for num in A if num % 2 == 1] j = stack.pop()
result += A[j] * (j - stack[-1]) * (i - j) # left boundaries of (j - top of stack), right of (i - j)
# python_1_to_1000/906_Super_Palindromes.py - h stack.append(i)
# https://leetcode.com/problems/super-palindromes/
# Let's say a positive integer is a superpalindrome if it is a palindrome, and it is also the square of a palindrome. # python_1_to_1000/908_Smallest_Range_I.py
# Now, given two positive integers L and R (represented as strings), return the number of superpalindromes
# in the inclusive range [L, R]. _author_ = 'jake'
_project_ = 'leetcode'
# For all palindromes between sqrt(L) and sqrt(R), test if their square is a palindrome.
# Build ordered lists of palindromes of length x by surrounding all palindromes of length x - 2 with each digit. # https://leetcode.com/problems/smallest-range-i/
# Palindromes that begin with 0 are built but not check if they are superpalindromes. # Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <= K, and add x to A[i].
# Time - O(n log n) # After this process, we have some array B.
# Max length of palindrome to check is k = log(R ** 0.5) = 0.5 * log R # Return the smallest possible difference between the maximum value of B and the minimum value of B.
# Number of palindromes of length <= k is O(10 ** ((k + 1) // 2)), each takes O(k) time to build and check if square is
# a super palindrome. # Each element of A can be adjusted by some number in [-K, K]. If the difference between the max and min of A is <= 2K
# Space - O(n log n) # then all elements can be equalized. Else the range can be decreased by 2K.
# Time - O(n)
class Solution(object): # Space - O(1)
def superpalindromesInRange(self, L, R):
""" class Solution:
:type L: str def smallestRangeI(self, A, K):
# https://leetcode.com/problems/snakes-and-ladders/ left_min = A[0] + K # min of left and max of right are fixed
# On an N x N board, the numbers from 1 to N*N are written boustrophedonically starting from the bottom left of the right_max = A[-1] - K
# board, and alternating direction each row.
# You start on square 1 of the board (which is always in the last row and first column). for i in range(len(A) - 1): # A[i] is the last index moved up, A[i + 1] is first moved down
# Each move, starting from square x, consists of the following:
# You choose a destination square S with number x+1, x+2, x+3, x+4, x+5, or x+6, provided this number is <= N*N. lower = min(left_min, A[i + 1] - K) # min of left and right
# (This choice simulates the result of a standard 6-sided die roll: ie., there are always at most 6 destinations.) upper = max(right_max, A[i] + K) # max of left and right
# If S has a snake or ladder, you move to the destination of that snake or ladder. Otherwise, you move to S. result = min(upper - lower, result)
# A board square on row r and column c has a "snake or ladder" if board[r][c] != -1.
# The destination of that snake or ladder is board[r][c]. return result
# Note that you only take a snake or ladder at most once per move: if the destination to a snake or ladder is the
# start of another snake or ladder, you do not continue moving.
# For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination square is `2`, then you # python_1_to_1000/911_Online_Election.py - m
# finish your first move at `3`, because you do not continue moving to `4`.
# Return the least number of moves required to reach square N*N. If it is not possible, return -1. _author_ = 'jake'
_project_ = 'leetcode'
# Breadth-first search. First convert the board to a 1-dimensional list of the squares in order.
# Queue contains all current indices. In each cycle of the while loop, for each index move up or down any ladder # https://leetcode.com/problems/online-election/
# or snake, then take from 1 to 6 steps. # In an election, the i-th vote was cast for persons[i] at time times[i].
# Time - O(n**2) # Now, we would like to implement the following query function: TopVotedCandidate.q(int t) will return the number
# Space - O(n**2) # of the person that was leading the election at time t.
# Votes cast at time t will count towards our query.
class Solution: # In the case of a tie, the most recent vote (among tied candidates) wins.
def snakesAndLadders(self, board):
""" # Create a list of the leading candidate at each time. Add each candidate to a dictionary of counts. If there is a
:type board: List[List[int]] # clear leader, update leader with thie candidate alone, else append candidate to leaders. Use max_count to identify
:rtype: int # whether a candidate is a leader.
""" # Binary search to look up a time. If time at index returned is later than t then return the leading candidate at
linear = [-1] # convert board to a list (deboustrophedonization) # the previous index. If time at index returned == t then return the leading candidate at that index.
reverse = False # alternate rows are appended not reversed and reversed # Time - O(n) for init, O(log n) for q
# Space - O(n)
for row in board[::-1]: # start from last row
linear += row[::-1] if reverse else row from collections import defaultdict
reverse = not reverse import bisect
_author_ = 'jake' # Count the number of each card. Attempt all values of X from 2 to the size of the smallest group. Check whether
_project_ = 'leetcode' # each group is divisible by X.
# Time - O(n**2)
# https://leetcode.com/problems/cat-and-mouse/ # Space - O(n)
# A game on an undirected graph is played by two players, Mouse and Cat, who alternate turns.
# The graph is given as follows: graph[a] is a list of all nodes b such that ab is an edge of the graph. from collections import Counter
# Mouse starts at node 1 and goes first, Cat starts at node 2 and goes second, and there is a Hole at node 0.
# During each player's turn, they must travel along one edge of the graph that meets where they are. class Solution:
# For example, if the Mouse is at node 1, it must travel to any node in graph[1]. def hasGroupsSizeX(self, deck):
# Additionally, it is not allowed for the Cat to travel to the Hole (node 0.) """
# Then, the game can end in 3 ways: :type deck: List[int]
# If ever the Cat occupies the same node as the Mouse, the Cat wins. :rtype: bool
# If ever the Mouse reaches the Hole, the Mouse wins. """
# If ever a position is repeated (ie. the players are in the same position as a previous turn, and it is the freq = Counter(deck)
# same player's turn to move), the game is a draw.
# Given a graph, and assuming both players play optimally, return 1 if the game is won by Mouse, 2 if the game min_count = min(freq.values())
# is won by Cat, and 0 if the game is a draw. if min_count == 1: # each group must have at least 2 cards
return False
# Create a graphs of states of (mouse_node, cat_node, next_mover). Attempt to find the winner from each state.
# Initially states with mouse at node 0 has mouse as winner and states with cat at node of mouse have cat as winner. for X in range(2, min_count + 1):
# All other states are drawn initially. Add states with known winners to a queue. if all(count % X == 0 for count in freq.values()):
# Initialise a count of the number of nodes that are connected to each state and do not have known winners. return True
# For each state in the queue, check each predecessor state with an unknown winner. If we can move from the predecessor
# to the state with the known winner, predecessor state has the same winner. Else reduce the count of unknown winners return False
# linked to the predecessor. If the count is zero, the animal whose turn it is to move at the predecessor cannot win.
# Time - O(n**3) since there are O(n**2) states each with O(n) links.
# Space - O(n**2) # python_1_to_1000/915_Partition_Array_into_Disjoint_Intervals.py - m
state_winner = defaultdict(int) # map from state to its winner, DRAW by default class Solution:
def partitionDisjoint(self, A):
degree = {} # map node to count of connected states that are not winners """
for mouse in range(n): :type A: List[int]
for cat in range(n): :rtype: int
degree[mouse, cat, MOUSE] = len(graph[mouse]) """
degree[mouse, cat, CAT] = len(graph[cat]) - (0 in graph[cat]) last_left = 0
max_left = max_overall = A[0]
queue = deque() # queue contains all states with known winner
for i in range(n): for i, num in enumerate(A[1:], 1):
for turn in [MOUSE, CAT]:
state_winner[0, i, turn] = MOUSE # mouse wins if at hole for any turn and any cat position max_overall = max(max_overall, num)
queue.append((0, i, turn, MOUSE))
if i > 0: # cat wins if at mouse unless at hole, for any turn and any mouse position if num < max_left: # smaller must be included in left
state_winner[i, i, turn] = CAT last_left = i
queue.append((i, i, turn, CAT)) max_left = max_overall
# Find the maximum required number of each letter for all words in B. def maxSubarraySumCircular(self, A):
# Check each word in A to see if it has at least the required number of each letter in B. """
# Time - O(m + n), total length of all words in A and B :type A: List[int]
# Space - O(1) since dictionary keys are limited by the number of distinct letters :rtype: int
"""
from collections import Counter, defaultdict if all(num <= 0 for num in A):
return max(A)
class Solution:
def wordSubsets(self, A, B): overall_max, overall_min = float('-inf'), float('inf')
""" max_ending_here, min_ending_here = 0, 0
:type A: List[str]
:type B: List[str] for num in A:
:rtype: List[str]
""" max_ending_here = max(max_ending_here, 0) + num # if previous max negative, set to zero
required = defaultdict(int) # map of each required letter in B to its required count min_ending_here = min(min_ending_here, 0) + num # if previous min positive, set to zero
results = []
for a in A: # python_1_to_1000/919_Complete_Binary_Tree_Inserter.py - m
class Solution(object): # We can extend a partial playlist by A) adding any song that has not been played before (if any), or
# B) adding a song that has been played before but is not in the K most recent songs. """
# Create a mapping from the number of different songs used to the count of playlists. odd = 1
# Initially there is one playlist with no songs.
# For each additional song, add playlists with every new song, If we have used more than K songs, add playlists with for even in range(0, len(A), 2):
# all songs not in the most recent K. Note the most recent K are all different songs.
# Time - O(LN) if A[even] % 2 == 1:
# Space - O(N)
while A[odd] % 2 == 1:
from collections import defaultdict odd += 2
A[odd], A[even] = A[even], A[odd]
class Solution:
def numMusicPlaylists(self, N, L, K): return A
"""
:type N: int
:type L: int # python_1_to_1000/923_3Sum_With_Multiplicity.py - m
:type K: int
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
used_count = {0: 1} # used_count[i] is the number of playlists that have used i different songs
# https://leetcode.com/problems/3sum-with-multiplicity/
for song in range(L): # Given an integer array A, and an integer target, return the number of tuples i, j, k such that i < j < k
# and A[i] + A[j] + A[k] == target.
new_used_count = defaultdict(int) # As the answer can be very large, return it modulo 10^9 + 7.
for used, count in used_count.items():
# Count the frequency of each number in A. For each pair of numbers, determine the other number required for the sum
new_used_count[used + 1] += count * (N - used) # add any of the (N - used) unused songs # to equal the target. Reject cases when the other number is outside the possible range or any count is zero.
if used > K: # If all numbers are the same, add to the result the count of combinations of 3 indices with that number.
new_used_count[used] += count * (used - K) # add any used song not in the most recent K songs # If the 2 numbers in the pair are the same, add to the result the count of combinations of 2 indices with that
# number times the count of other.
used_count = new_used_count # If other > med, add all combinations of the 3 numbers. These are only added to the result when in order to avoid
# double counting.
return used_count[N] % (10 ** 9 + 7) # Time - O(n + k**2) where k is the range of values of A
# Space - O(k)
_author_ = 'jake'
# python_1_to_1000/922_Sort_Array_By_Parity_II.py _project_ = 'leetcode'
if second_start < first_end + 1 or third_start < second_end + 1: # cannot have overlap of parts # Split by "@" then discard any part of the local name afte the "+" and remove all ".".
return [-1, -1] # Time - O(n)
# Space - O(n)
return [first_end, second_end + 1]
class Solution:
def numUniqueEmails(self, emails):
"""
# python_1_to_1000/928_Minimize_Malware_Spread_II.py - h :type emails: List[str]
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode' unique = set()
for removed in sorted(initial): # sort so lowest index is returned first in the event of a tie # python_1_to_1000/931_Minimum_Falling_Path_Sum.py - m
for c in range(n): # An island is a 4-directionally connected group of 1s not connected to any other 1s.
new_row_minima[c] += min(row_minima[max(0, c - 1):c + 2]) # add the lowest of the 3 cells below # Now, we may change 0s to 1s so as to connect the two islands together to form 1 island.
# Return the smallest number of 0s that must be flipped. (It is guaranteed that the answer is at least 1.)
row_minima = new_row_minima
# Traverse the grid until we any cell from an island. Then depth-first search to find all perimeter cells of the island
return min(row_minima) # start from any cell of top row # which are at the edge of the island. Breath-first search from the perimeter. Ignore cells that are already visited.
# Return when any island cell is found.
# Time - O(mn)
# Space - O(mn)
# python_1_to_1000/932_Beautiful_Array.py - m
class Solution:
_author_ = 'jake' def shortestBridge(self, A):
_project_ = 'leetcode' """
:type A: List[List[int]]
# https://leetcode.com/problems/beautiful-array/ :rtype: int
# For some fixed N, an array A is beautiful if it is a permutation of the integers 1, 2, ..., N, such that: """
# For every i < j, there is no k with i < k < j such that A[k] * 2 = A[i] + A[j]. rows, cols = len(A), len(A[0])
# Given N, return any beautiful array A. (It is guaranteed that one exists.) visited = set()
perimeter = set()
# The condition is equivalent to saying that the average of a pair of numbers cannot be between those numbers.
# Make separate arrays of even and odd numbers, since when concatenated the average of an even and and odd number is def neighbours(r, c): # yields cells neighbouring (r, c) that are within the grid A
# not an integer so does not violate the required condition. if r != 0:
# Note also that if an array is beautiful a common factor can be added to or multiplied by all elements and it yield (r - 1, c)
# remains beautiful. Hence create odds and evens arrays of the required lengths using integers, then scale the if r != rows - 1:
# elements to the required odd or even numbers. yield (r + 1, c)
# Time - O(n log n) if c != 0:
# Space - O(n log n) yield (r, c - 1)
if c != rows - 1:
class Solution: yield (r, c + 1)
def beautifulArray(self, N):
""" def get_perimeter(r, c):
:type N: int
:rtype: List[int] if r < 0 or r >= rows or c < 0 or c >= cols:
""" return
if N == 1: if A[r][c] == 0 or (r, c) in visited:
return [1] return
visited.add((r, c))
evens = self.beautifulArray(N // 2)
if N % 2 == 0: # reuse same array if odds and evens are same length for r1, c1 in neighbours(r, c):
odds = evens[:] if A[r1][c1] == 0: # neighbours of an island cell that are not part of the island
else: perimeter.add((r1, c1))
odds = self.beautifulArray((N + 1) // 2) else: # recurse to explore island
get_perimeter(r1, c1)
odds = [(2 * i) - 1 for i in odds]
evens = [2 * i for i in evens] for r in range(rows):
for c in range(cols):
return evens + odds if perimeter: # stop when any perimeter is found
break
get_perimeter(r, c)
# python_1_to_1000/933_Number_of_Recent_Calls.py
steps = 1 # perimeter is one step from the island
_author_ = 'jake'
_project_ = 'leetcode' while True:
class RecentCounter:
# python_1_to_1000/935_Knight_Dialer.py - m
def __init__(self):
self.times = deque() _author_ = 'jake'
self.WINDOW = 3000 _project_ = 'leetcode'
return len(self.times) # Create a mapping of which digits can be reached from each digit.
# Store the count of distinct numbers ending with each digit.
# For each move, add the count of solutions ending with each digit to the count of solutions ending with each
# python_1_to_1000/934_Shortest_Bridge.py - m # reachable next digit.
# Time - O(n) since there are 10 digits and so at most 10 reachable next digits.
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution:
# https://leetcode.com/problems/shortest-bridge/ def knightDialer(self, N):
# In a given 2D binary array A, there are two islands. """
:type N: int result = helper(i + 1, 0, results + [i + 1])
:rtype: int
""" memo[(i, j)] = result
can_reach = [[4, 6], # can_reach[i] is the list of digits that can be reached from i return result
[6, 8],
[7, 9], return helper(0, 0, [0])
[4, 8],
[0, 3, 9],
[],
[0, 1, 7],
[2, 6], # python_1_to_1000/937_Reorder_Log_Files.py - m
[1, 3],
[2, 4]] _author_ = 'jake'
_project_ = 'leetcode'
counts = [1] * 10 # one distinct number ending with each digit
for _ in range(N - 1): # https://leetcode.com/problems/reorder-log-files/
# You have an array of logs. Each log is a space delimited string of words.
new_counts = [0] * 10 # For each log, the first word in each log is an alphanumeric identifier. Then, either:
# Each word after the identifier will consist only of lowercase letters, or;
for digit, count in enumerate(counts): # Each word after the identifier will consist only of digits.
for next_digit in can_reach[digit]: # We will call these two varieties of logs letter-logs and digit-logs.
new_counts[next_digit] += count # It is guaranteed that each log has at least one word after its identifier.
# Reorder the logs so that all of the letter-logs come before any digit-log.
counts = new_counts # The letter-logs are ordered lexicographically ignoring identifier, with the identifier used in case of ties.
# The digit-logs should be put in their original order.
return sum(counts) % (10 ** 9 + 7) # Return the final order of the logs.
# For each log, find the first char after the space. If it is a digit, append to list of numbers logs.
# python_1_to_1000/936_Stamping_The_Sequence.py - h # If it is a letter, create a tuple of the log with the identifier moved to the end and the original log.
# Sort the letter tuples and retain only the original logs in the solution.
_author_ = 'jake' # Time - O(kn log n) to sort n strings of maximum length k
_project_ = 'leetcode' # Space - O(nk)
def helper(i, j, results): # stamp from target[i] and stamp[j] given list of partial results # If the node value is more than R then recurse left only because all node values in right subtree are even greater.
# If the node value is less than L then recurse right only because all node values in left subtree are even lower.
if (i, j) in memo: # Else return the sum of the node value (since it is in the target range) plus the results from the left and right
return memo[(i, j)] # subtrees.
# Time - O(n)
if len(results) > 10 * len(target): # too many stamps # Space - O(n)
return []
class Solution:
if i == len(target): # end of target, check if end of stamp def rangeSumBST(self, root, L, R):
return results if j == len(stamp) else [] """
:type root: TreeNode
if j == len(stamp): # end of stamp :type L: int
for k in range(len(stamp)): :type R: int
temp = helper(i, k, [i - k] + results) # stamp before existing result so only suffix shows :rtype: int
if temp: """
result = temp def helper(node):
break
else: if not node:
result = [] return 0
# python_1_to_1000/941_Valid_Mountain_Array.py
if (c1, c2) in col_pair_to_row: # previous row has this column pair class Solution(object):
result = min(result, (r - col_pair_to_row[c1, c2]) * (c2 - c1)) def diStringMatch(self, S):
col_pair_to_row[c1, c2] = r """
:type S: str
return 0 if result == float('inf') else result :rtype: List[int]
"""
result = []
# python_1_to_1000/940_Distinct_Subsequences_II.py - h low, high = 0, len(S)
dp = [[0] * N for _ in range(1 << N)] # dp[mask][i] is most overlap with mask, ending with ith element class Solution:
parent = [[None] * N for _ in range(1 << N)] # parent[mask][i] is word index of previous word def minIncrementForUnique(self, A):
"""
for mask in range(1, 1 << N): # mask has a set bit for each used word index :type A: List[int]
for bit in range(N): :rtype: int
"""
if (mask >> bit) & 1: # for each word used in mask increments = 0
last_used = -1
prev_mask = mask ^ (1 << bit) # get mask without this word
if prev_mask == 0: for num in sorted(A):
continue
if num <= last_used:
for i in range(N): increments += last_used + 1 - num
last_used += 1
if (prev_mask >> i) & 1: # for each word in previous mask else:
last_used = num
overlap = dp[prev_mask][i] + overlaps[i][bit]
if overlap > dp[mask][bit]: # better overlap return increments
dp[mask][bit] = overlap
parent[mask][bit] = i
# python_1_to_1000/946_Validate_Stack_Sequences.py - m
mask = (1 << N) - 1
i = max(range(N), key=lambda x: dp[-1][x]) # index of last word used _author_ = 'jake'
result = [A[i]] _project_ = 'leetcode'
used = {i}
# https://leetcode.com/problems/validate-stack-sequences/
while True: # Given two sequences pushed and popped with distinct values, return true if and only if this could have been the
# result of a sequence of push and pop operations on an initially empty stack.
mask, j = mask ^ (1 << i), parent[mask][i] # get parent word and update mask
if j is None: # Build the stack by iterating over pushed.
break # Pop off top off stack whenever it matched the next element of popped.
overlap = overlaps[j][i] # At the end, the stack must be empty.
prefix = A[j] if overlap == 0 else A[j][:-overlap] # Time - O(n)
result.append(prefix) # Space - O(n)
used.add(j)
i = j class Solution:
def validateStackSequences(self, pushed, popped):
result = result[::-1] + [A[i] for i in range(N) if i not in used] # reverse, add unused words """
:type pushed: List[int]
return "".join(result) :type popped: List[int]
:rtype: bool
"""
stack = []
# python_1_to_1000/944_Delete_Columns_to_Make_Sorted.py i = 0 # next index of popped
if best_minutes == -1:
# python_1_to_1000/948_Bag_of_Tokens.py - m return ""
# https://leetcode.com/problems/bag-of-tokens/
# You have an initial power P, an initial score of 0 points, and a bag of tokens. # python_1_to_1000/950_Reveal_Cards_In_Increasing_Order.py - m
# Each token can be used at most once, has a value token[i], and has potentially two ways to use it.
# If we have at least token[i] power, we may play the token face up, losing token[i] power, and gaining 1 point. _author_ = 'jake'
# If we have at least 1 point, we may play the token face down, gaining token[i] power, and losing 1 point. _project_ = 'leetcode'
# Return the largest number of points we can have after playing any number of tokens.
# https://leetcode.com/problems/reveal-cards-in-increasing-order/
# Sort the tokens. Use as many low value tokens to get as many points as possible. Then repeatedly use the highest # In a deck of cards, every card has a unique integer. You can order the deck in any order you want.
# value token to convert one point into power and use as many low value tokens to convert all available # Initially, all the cards start face down (unrevealed) in one deck.
# power into points. # Now, you do the following steps repeatedly, until all cards are revealed:
# Time - O(n) # Take the top card of the deck, reveal it, and take it out of the deck.
# Space - O(1) # If there are still cards in the deck, put the next top card of the deck at the bottom of the deck.
# If there are still unrevealed cards, go back to step 1. Otherwise, stop.
class Solution: # Return an ordering of the deck that would reveal the cards in increasing order.
def bagOfTokensScore(self, tokens, P): # The first entry in the answer is considered to be the top of the deck.
"""
:type tokens: List[int] # For each card from lowest to highest, add the card to the next empty index in the result.
:type P: int # Then move to next empty index to the back of the queue of indices - the card that is ultimately placed here will
:rtype: int # be moved to the bottom of the deck.
""" # Time - O(n log n)
points, power = 0, P # Space - O(n)
left, right = 0, len(tokens) - 1
from collections import deque
tokens.sort()
class Solution:
while left < len(tokens) and tokens[left] <= power: def deckRevealedIncreasing(self, deck):
power -= tokens[left] """
points += 1 :type deck: List[int]
left += 1 :rtype: List[int]
"""
if not points: # never possible to have any points n = len(deck)
return 0 index = deque(range(n))
result = [None] * n
while right - left > 1:
for card in sorted(deck):
points -= 1
power += tokens[right] result[index.popleft()] = card
right -= 1 if index:
index.append(index.popleft())
while right - left >= 0 and tokens[left] <= power:
power -= tokens[left] return result
points += 1
left += 1
# python_1_to_1000/951_Flip_Equivalent_Binary_Trees.py - m
return points
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/949_Largest_Time_for_Given_Digits.py - m
# https://leetcode.com/problems/flip-equivalent-binary-trees/
_author_ = 'jake' # For a binary tree T, we can define a flip operation as follows: choose any node, and swap the left and right
_project_ = 'leetcode' # child subtrees.
# A binary tree X is flip equivalent to a binary tree Y if and only if we can make X equal to Y after some number of
# https://leetcode.com/problems/largest-time-for-given-digits/ # flip operations.
# Given an array of 4 digits, return the largest 24 hour time that can be made. # Write a function that determines whether two binary trees are flip equivalent.
# The smallest 24 hour time is 00:00, and the largest is 23:59. # The trees are given by root nodes root1 and root2.
# Starting from 00:00, a time is larger if more time has elapsed since midnight.
# Return the answer as a string of length 5. If no valid time can be made, return an empty string. # Base cases are when at least one root is None. Else root values must be the same. Then recursively check whether
# the subtrees are flip equivalent either with or without swapping right and left.
# Check all permutations of the digits. Reject those which are not valid times. # Time - O(n)
# Time - O(1) since 4! times are possible # Space - O(n)
# Space - O(1)
class Solution:
from itertools import permutations def flipEquiv(self, root1, root2):
"""
class Solution(object): :type root1: TreeNode
def largestTimeFromDigits(self, A): :type root2: TreeNode
""" :rtype: bool
:type A: List[int] """
:rtype: str if not root1 and not root2: # equivalent because both empty
""" return True
best_minutes = -1 # most minutes past midnight if not root1 or not root2: # only one empty
return False
# alphabet. Compare the mapped list lexicographically to the previous word's mapped list.
if root1.val != root2.val: # Time - O(nk) for n words of maximum length k
return False # Space - O(k)
def find(x): # return ultimate parent of x and collapse tree for num in sorted(counts, key=abs): # iterate over keys sorted by absolute value
while x != parents[x]:
parents[x] = parents[parents[x]] # link x to grandparent if counts[num] > counts[num * 2]:
x = parents[x] return False
return x counts[num * 2] -= counts[num]
n = len(A) # https://leetcode.com/problems/delete-columns-to-make-sorted-ii/
parents = [i for i in range(n)] # index to parent mapping # We are given an array A of N lowercase letter strings, all of the same length.
sizes = [1] * n # sizes[i] is the size of component with A[i] parent # Now, we may choose any set of deletion indices, and for each string, we delete all the characters in those indices.
prime_to_index = {} # prime factor mapped to index in A of first num to use that factor # For example, if we have an array A = ["abcdef","uvwxyz"] and deletion indices {0, 2, 3}, then the final array after
# deletions is ["bef","vyz"].
for i, a in enumerate(A): # Suppose we chose a set of deletion indices D such that after deletions,
# the final array has its elements in lexicographic order (A[0] <= A[1] <= A[2] ... <= A[A.length - 1]).
primes = prime_factors(a) # Return the minimum possible value of D.length.
for p in primes: # Iterate over columns, tracking which rows must be checked (i.e. are not known to be sorted).
if p in prime_to_index: # For each column, compare the char at each row to be checked against the previous row. If any char is not sorted, the
union(i, prime_to_index[p]) # column must be deleted. Chars that are in the correct order are flagged so as not to be tested again, unless the
prime_to_index[p] = i # column is deleted. Identical chars are left to be checked in the next column.
# Time - O(mn)
return max(sizes) # Space - O(m), number of rows
class Solution(object):
# python_1_to_1000/953_Verifying_an_Alien_Dictionary.py def minDeletionSize(self, A):
"""
_author_ = 'jake' :type A: List[str]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/verifying-an-alien-dictionary/ rows, cols = len(A), len(A[0])
# In an alien language, surprisingly they also use english lowercase letters, but possibly in a different order. cols_deleted = 0
# The order of the alphabet is some permutation of lowercase letters. rows_to_check = {row for row in range(1, rows)} # all rows apart from first
# Given a sequence of words written in the alien language, and the order of the alphabet,
# return true if and only if the given words are sorted lexicographically in this alien language. for col in range(cols):
# Create a mapping from each char to its index in the alphabet. For each word, map each char to its index in the new_checks = set(rows_to_check)
if char < prev_char: # incorrect order while day < N and state not in state_to_day: # until cycle in states
cols_deleted += 1 state_to_day[state] = day
break day += 1
elif char > prev_char: # correct order, do not check again state = next_state(state)
new_checks.remove(row)
if day < N:
else: # col not deleted cycle = day - state_to_day[state]
if not new_checks: # finished remaining = (N - state_to_day[state]) % cycle
break for _ in range(remaining):
rows_to_check = new_checks # update rows_to_check state = next_state(state)
# python_1_to_1000/958_Check_Completeness_of_a_Binary_Tree.py - m
# python_1_to_1000/956_Tallest_Billboard.py - h
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/check-completeness-of-a-binary-tree/
# https://leetcode.com/problems/tallest-billboard/ # Given a binary tree, determine if it is a complete binary tree.
# You are installing a billboard and want it to have the largest height. # Definition of a complete binary tree from Wikipedia:
# The billboard will have two steel supports, one on each side. Each steel support must be an equal height. # In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the
# You have a collection of rods which can be welded together. # last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
# For example, if you have rods of lengths 1, 2, and 3, you can weld them together to make a support of length 6.
# Return the largest possible height of your billboard installation. If you cannot support the billboard, return 0. # Maintain a queue of nodes discovered. Explore the tree layer by layer (breadth-first search).
# When the first empty node is found, check if all other nodes are empty. Else add children to the queue.
# Maintain a dictionary mapping the difference in side heights to the greatest total length used with that difference. # Time - O(n)
# Use only non-negative differences. # Space - O(n)
# For each rod, update each height difference by both adding and subtracting the rod.
# Return the greatest total length used with a difference of zero. from collections import deque
# Time - O(2 ** n) since 2 ** (n - 1) possible diffs.
# Space - O(2 ** (n - 1)) class Solution:
def isCompleteTree(self, root):
from collections import defaultdict """
:type root: TreeNode
class Solution: :rtype: bool
def tallestBillboard(self, rods): """
""" queue = deque([root])
:type rods: List[int]
:rtype: int while True:
"""
diffs = {0 : 0} # key is difference, value is max total length node = queue.popleft()
if not node:
for rod in rods: return all(not nd for nd in queue)
low = word.lower()
# python_1_to_1000/965_Univalued_Binary_Tree.py result = lower_words.get(low, "") # return empty string if not found
if result == "":
_author_ = 'jake' replaced = replace_vowels(low)
_project_ = 'leetcode' result = vowel_words.get(replaced, "")
return result
# https://leetcode.com/problems/univalued-binary-tree/
# A binary tree is univalued if every node in the tree has the same value. return [check(query) for query in queries]
# Return true if and only if the given tree is univalued.
# Store root value. Check if each node has the same value and recurse for children. # python_1_to_1000/967_Numbers_With_Same_Consecutive_Differences.py - m
# Time - O(n)
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution:
def isUnivalTree(self, root): # https://leetcode.com/problems/numbers-with-same-consecutive-differences/
""" # Return all non-negative integers of length N such that the absolute difference between every two consecutive
:type root: TreeNode # digits is K.
:rtype: bool # Note that every number in the answer must not have leading zeros except for the number 0 itself.
""" # For example, 01 has one leading zero and is invalid, but 0 is valid.
value = root.val # root is guaranteed not to be None # You may return the answer in any order.
def helper(node): # Starting from each of the digits apart from zero, repeatedly add and subtract K to the last_digit of each number to
if not node: # build up the results to N digits.
return True # Time - O(2**n)
if node.val != value: # Space - O(2**n)
return False
return helper(node.left) and helper(node.right) class Solution(object):
def numsSameConsecDiff(self, N, K):
return helper(root) """
:type N: int
:type K: int
# python_1_to_1000/966_Vowel_Spellchecker.py - m :rtype: List[int]
"""
_author_ = 'jake' partials = [i for i in range(1, 10)]
_project_ = 'leetcode'
for _ in range(N - 1):
# https://leetcode.com/problems/vowel-spellchecker/ new_partials = []
# Given a wordlist, we want to implement a spellchecker that converts a query word into a correct word.
# for p in partials:
# For a given query word, the spell checker handles two categories of spelling mistakes:
# last_digit = p % 10
# Capitalization: If the query matches a word in the wordlist (case-insensitive), then the query word is returned with if last_digit - K >= 0:
# the same case as the case in the wordlist. new_partials.append(p * 10 + last_digit - K)
# Example: wordlist = ["yellow"], query = "YellOw": correct = "yellow" if K != 0 and last_digit + K < 10:
# Example: wordlist = ["Yellow"], query = "yellow": correct = "Yellow" new_partials.append(p * 10 + last_digit + K)
# Example: wordlist = ["yellow"], query = "yellow": correct = "yellow"
# Vowel Errors: If after replacing the vowels ('a', 'e', 'i', 'o', 'u') of the query word with any vowel individually, partials = new_partials
# it matches a word in the wordlist (case-insensitive), then the query word is returned with the same case as the
# match in the wordlist. if N == 1:
# Example: wordlist = ["YellOw"], query = "yollow": correct = "YellOw" partials.append(0)
# Example: wordlist = ["YellOw"], query = "yeellow": correct = "" (no match)
# Example: wordlist = ["YellOw"], query = "yllw": correct = "" (no match) return partials
# In addition, the spell checker operates under the following precedence rules:
# Return a list of all powerful integers that have value less than or equal to bound.
# You may return the answer in any order. In your answer, each value should occur at most once.
# python_1_to_1000/968_Binary_Tree_Cameras.py - h
# Create lists of all powers of x and y less than bound.
_author_ = 'jake' # Time - O((log b)**2) where b is the bound
_project_ = 'leetcode' # Space - O((log b)**2)
def helper(node, parent): # returns number of cameras to cover subtree apart from node for x_num in x_list:
for y_num in y_list:
if not node: if x_num + y_num > bound:
return 0 break
result.add(x_num + y_num)
result = helper(node.left, node) + helper(node.right, node) # recurse for children first (bottom-up)
return list(result)
if node.left not in covered or node.right not in covered: # must put a camera at node
covered.update({parent, node, node.left, node.right}) # node and neighbours are now covered
result += 1 # python_1_to_1000/971_Flip_Binary_Tree_To_Match_Preorder_Traversal.py - m
# https://leetcode.com/problems/powerful-integers/ # python_1_to_1000/972_Equal_Rational_Numbers.py - h
# Given two non-negative integers x and y, an integer is powerful if it is equal to x^i + y^j for some integers
# i >= 0 and j >= 0. _author_ = 'jake'
# Convert each string to a fraction. As a fraction, the repeating part is divided by nines. return result
# For example 0.(52) is 52/99 and 0.1(52) is 1/10 + 52/990
# Time - O(n + m), lengths of input strings
# Space - O(n + m) # python_1_to_1000/975_Odd_Even_Jump.py - h
class Solution:
# python_1_to_1000/973_K_Closest_Points_to_Origin.py - m def oddEvenJumps(self, A):
"""
_author_ = 'jake' :type A: List[int]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/k-closest-points-to-origin/ n = len(A)
# We have a list of points on the plane. Find the K closest points to the origin (0, 0).
# Here, the distance between two points on a plane is the Euclidean distance. def next_list(): # returns list of index next larger or smaller element
# You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.) result = [None] * n
stack = []
# Build a heap of the K smallest distances from the origin. for i in indices:
# Time - O(n log k) while stack and i > stack[-1]: # i is after top of stack
# Space - O(k) result[stack.pop()] = i # i is index of next larger or smaller element after stack top
stack.append(i)
import heapq return result
class Solution: indices = sorted(range(n), key=lambda x: A[x]) # sort indices of A by increasing A[x]
def kClosest(self, points, K): next_larger = next_list()
""" indices.sort(key=lambda x: -A[x]) # sort indices of A by decreasing A[x]
:type points: List[List[int]] next_smaller = next_list()
:type K: int
:rtype: List[List[int]] odd = [False] * (n - 1) + [True] # default can reach the end only from last element
""" even = [False] * (n - 1) + [True]
return heapq.nsmallest(K, points, lambda x, y: x * x + y * y)
for i in range(n - 2, -1, -1): # iterate form back to front
if next_larger[i] is not None:
odd[i] = even[next_larger[i]]
# python_1_to_1000/974_Subarray_Sums_Divisible_by_K.py - m if next_smaller[i] is not None:
even[i] = odd[next_smaller[i]]
_author_ = 'jake'
_project_ = 'leetcode' return sum(odd) # count of odd indices that can reach end
# https://leetcode.com/problems/subarray-sums-divisible-by-k/
# Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum divisible by K.
# python_1_to_1000/976_Largest_Perimeter_Triangle.py
# A sum divisible by K means sum of zero modulo K.
# Dictionary counts the number of prefix sums modulo K. For each element, update the running sum and add to the result _author_ = 'jake'
# the count of prefix sums equal to the running sum (subtracting the prefix from the running sum makes a subarray of _project_ = 'leetcode'
# sum 0 modulo K). Then update the dictionary.
# Time - O(n) # https://leetcode.com/problems/largest-perimeter-triangle/
# Space - O(n) # Given an array A of positive lengths, return the largest perimeter of a triangle with non-zero area,
# formed from 3 of these lengths.
from collections import defaultdict # If it is impossible to form any triangle of non-zero area, return 0.
class Solution: # For each side s, if the sum of the next 2 smaller sides is lower then a triangle can be formed.
# If no such triangle can be formed with s as the longest side, then other shorter sides cannot form a triangle. up = 0
# When the sides are sorted by decreasing length, the first such triangle has the largest perimeter. else: # extend neither sequence
# Time - O(n log n) down = 0
# Space - O(n) up = 0
return 0 # https://leetcode.com/problems/distribute-coins-in-binary-tree/
# Given the root of a binary tree with N nodes, each node in the tree has node.val coins, and there are N coins total.
# In one move, we may choose two adjacent nodes and move one coin from one node to another.
# python_1_to_1000/977_Squares_of_a_Sorted_Array.py # The move may be from parent to child, or from child to parent.
# Return the number of moves required to make every node have exactly one coin.
_author_ = 'jake'
_project_ = 'leetcode' # Bottom-up recursion. Helper function takes a node and its parent and distributes coins evenly in the subtree rooted
# at the node, by pushing or pulling excess coins to or from the parent.
# https://leetcode.com/problems/squares-of-a-sorted-array/ # Time - O(n)
# Given an array of integers A sorted in non-decreasing order, return an array of the squares of each number, # Space - O(n)
# also in sorted non-decreasing order.
class Solution:
# Left and right pointers mark next elements to be squared. Add the larger square to the result and move pointers def distributeCoins(self, root):
# until they cross. """
# Time - O(n) :type root: TreeNode
# Space - O(n) :rtype: int
"""
class Solution: def helper(node, parent):
def sortedSquares(self, A):
""" if not node:
:type A: List[int] return 0
:rtype: List[int]
""" left = helper(node.left, node) # distribute coins evenly in subtrees
left, right = 0, len(A) - 1 right = helper(node.right, node)
result = []
upshift = node.val - 1 # the number of coins to be pushed up to the parent (may be -ve)
while left <= right: if upshift != 0: # no parent if node is root
if abs(A[left]) > abs(A[right]): parent.val += upshift
result.append(A[left] * A[left]) node.val = 1 # node is now balanced
left += 1 return left + right + abs(upshift) # total coins moved
else:
result.append(A[right] * A[right]) return helper(root, None)
right -= 1
_author_ = 'jake'
# python_1_to_1000/978_Longest_Turbulent_Subarray.py - m _project_ = 'leetcode'
if not unvisited and (r, c) == end: # end reached and no more cells to visit for pair, count in pairs.items():
return 1 for num3 in A:
if not unvisited or (r, c) == end: # end reached with cells to visit or no more cells to visit if pair & num3 == 0:
return 0 result += count
return result
paths = 0
for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
nbor_r, nbor_c = r + dr, c + dc
if (nbor_r, nbor_c) in unvisited: # python_1_to_1000/983_Minimum_Cost_For_Tickets.py - m
unvisited.remove((nbor_r, nbor_c))
paths += make_paths(nbor_r, nbor_c) _author_ = 'jake'
unvisited.add((nbor_r, nbor_c)) # add back after exploring this path _project_ = 'leetcode'
return paths
# https://leetcode.com/problems/minimum-cost-for-tickets/
return make_paths(*start) # In a country popular for train travel, you have planned some train travelling one year in advance.
# The days of the year that you will travel is given as an array days. Each day is an integer from 1 to 365.
# Train tickets are sold in 3 different ways:
# python_1_to_1000/981_Time_Based_Key-Value_Store.py - m # a 1-day pass is sold for costs[0] dollars;
# a 7-day pass is sold for costs[1] dollars;
_author_ = 'jake' # a 30-day pass is sold for costs[2] dollars.
_project_ = 'leetcode' # The passes allow that many days of consecutive travel.
# For example, if we get a 7-day pass on day 2, then we can travel for 7 days: day 2, 3, 4, 5, 6, 7, and 8.
# https://leetcode.com/problems/time-based-key-value-store/ # Return the minimum number of dollars you need to travel every day in the given list of days.
# Create a timebased key-value store class TimeMap, that supports two operations.
# 1. set(string key, string value, int timestamp) # For each travel day, for each pass length, find the next travel day not covered by the pass and add the cost of the
# Stores the key and value, along with the given timestamp. # pass to the cost of covering from the next uncovered day onwards. Take the minimum over the 3 pass lengths.
# 2. get(string key, int timestamp) # Memoize previous results.
# Returns a value such that set(key, value, timestamp_prev) was called previously, with timestamp_prev <= timestamp. # Time - O(n), length of days
# If there are multiple such values, it returns the one with the largest timestamp_prev. # Space - O(n)
# If there are no values, it returns the empty string ("").
from typing import *
# Two dictionaries map keys to a list of values and a list of times. Binary search the list of times to find the from functools import lru_cache
# first index less than or equal to the required timestamp. If an index is found, lookup the value at that index.
# Time - O(1) for set, O(log n) for get class Solution:
# Space - O(n) def mincostTickets(self, days: 'List[int]', costs: 'List[int]') -> 'int':
_author_ = 'jake'
# python_1_to_1000/982_Triples_with_Bitwise_AND_Equal_To_Zero.py - h _project_ = 'leetcode'
# python_1_to_1000/987_Vertical_Order_Traversal_of_a_Binary_Tree.py - h
# python_1_to_1000/985_Sum_of_Even_Numbers_After_Queries.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/
# https://leetcode.com/problems/sum-of-even-numbers-after-queries/ # Given a binary tree, return the vertical order traversal of its nodes values.
# We have an array A of integers, and an array queries of queries. # For each node at position (X, Y), its left and right children respectively will be at positions
# For the i-th query val = queries[i][0], index = queries[i][1], we add val to A[index]. # (X-1, Y-1) and (X+1, Y-1).
# Then, the answer to the i-th query is the sum of the even values of A. # Running a vertical line from X = -infinity to X = +infinity, whenever the vertical line touches some nodes,
# Here, the given index = queries[i][1] is a 0-based index, and each query permanently modifies the array A. # we report the values of the nodes in order from top to bottom (decreasing Y coordinates).
# Return the answer to all queries. Your answer array should have answer[i] as the answer to the i-th query. # If two nodes have the same position, then the value of the node that is reported first is the value that is smaller.
# Return an list of non-empty reports in order of X coordinate. Every report will have a list of values of nodes.
# Calculate the initial sum of even values. For each query, if the value to be adjusted is even, decrement the
# even sum by this amount. Adjust the value, then if the new value is even, increment the even sum by the value. # Traverse the tree, creating a mapping from the x-coordinate of each node to a tuple of its y-coordinate and value.
# Time - O(n) # For each x-coordinate sorted in ascending order, sort the nodes by descending y-coordinate and value.
# Space - O(n) # Time - O(n log n), to sort the x-coord. Sorting the y-coords takes the same or less.
# Space - O(n)
class Solution(object):
def sumEvenAfterQueries(self, A, queries): from collections import defaultdict
"""
:type A: List[int] class Solution(object):
:type queries: List[List[int]] def verticalTraversal(self, root):
:rtype: List[int] """
""" :type root: TreeNode
sum_even = sum(x for x in A if x % 2 == 0) :rtype: List[List[int]]
result = [] """
x_to_y_and_val = defaultdict(list)
for val, i in queries:
def helper(node, x, y):
if A[i] % 2 == 0: if not node:
sum_even -= A[i] return
A[i] += val x_to_y_and_val[x].append((-y, node.val)) # negative y-coordinate to later sort descending
if A[i] % 2 == 0: helper(node.left, x - 1, y - 1)
sum_even += A[i] helper(node.right, x + 1, y - 1)
result.append(sum_even) helper(root, 0, 0)
result = []
return result
xs = sorted(x_to_y_and_val.keys())
for x in xs:
x_to_y_and_val[x].sort()
# python_1_to_1000/986_Interval_List_Intersections.py result.append([val for _, val in x_to_y_and_val[x]])
# https://leetcode.com/problems/interval-list-intersections/
# Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted order. # python_1_to_1000/988_Smallest_String_Starting_From_Leaf.py - m
# Return the intersection of these two interval lists.
# Formally, a closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b. _author_ = 'jake'
# The intersection of two closed intervals is a set of real numbers that is either empty, _project_ = 'leetcode'
# or can be represented as a closed interval.
# For example, the intersection of [1, 3] and [2, 4] is [2, 3].) # https://leetcode.com/problems/smallest-string-starting-from-leaf/
# Given the root of a binary tree, each node has a value from 0 to 25 representing the letters 'a' to 'z':
# Maintain pointers to the next indices of A and B to be checked for overlap. # a value of 0 represents 'a', a value of 1 represents 'b', and so on.
# Indices overlap if the greatest starting edge is before or equal to the least ending edge. # Find the lexicographically smallest string that starts at a leaf of this tree and ends at the root.
# Move the pointer past the interval with the lowest ending edge to the next interval in that list. # As a reminder, any shorter prefix of a string is lexicographically smaller: for example, "ab" is lexicographically
# Time - O(m + n) # smaller than "aba". A leaf of a node is a node that has no children.
# Space - O(m + n), every interval overlaps at both ends
# Bottom-up recursion. Find the results for left and right children. If either or both are the empty string, the
# Definition for an interval. # result is the none empty string concatenated to the node letter. Else return the smallest string plus the node letter.
class Interval(object): # The less-than operator "<" finds the smallest string.
def __init__(self, s=0, e=0): # Time - O(n**2)
self.start = s # Space - O(n**2)
self.end = e
class Solution(object):
class Solution(object): def smallestFromLeaf(self, root):
def intervalIntersection(self, A, B): """
""" :type root: TreeNode
:type A: List[Interval] :rtype: str
:type B: List[Interval] """
:rtype: List[Interval] def helper(node):
"""
result = [] if not node: # base case
i, j = 0, 0 # next indices of A and B to be tested return ""
return left + right + node_char # only one of left and right are not ""
# python_1_to_1000/991_Broken_Calculator.py - m
return left + node_char if left < right else right + node_char
_author_ = 'jake'
return helper(root) _project_ = 'leetcode'
# https://leetcode.com/problems/broken-calculator/
# On a broken calculator that has a number showing on its display, we can perform two operations:
# python_1_to_1000/989_Add_to_Array-Form_of_Integer.py # Double: Multiply the number on the display by 2, or;
# Decrement: Subtract 1 from the number on the display.
_author_ = 'jake' # Initially, the calculator is displaying the number X.
_project_ = 'leetcode' # Return the minimum number of operations needed to display the number Y.
return X - Y + operations
# python_1_to_1000/990_Satisfiability_of_Equality_Equations.py - m
# Create mapping of value to node and node to parent. If both x and y are mapped to nodes, check if they have the same
# parent. If only one of x and y is mapped to a node, they are not at the same depth so are not cousins.
# Add the children of each node to the mapping. # python_1_to_1000/995_Minimum_Number_of_K_Consecutive_Bit_Flips.py - h
# Time - O(n)
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def isCousins(self, root, x, y): # https://leetcode.com/problems/minimum-number-of-k-consecutive-bit-flips/
""" # In an array A containing only 0s and 1s, a K-bit flip consists of choosing a (contiguous) subarray of length K and
:type root: TreeNode # simultaneously changing every 0 in the subarray to 1, and every 1 in the subarray to 0.
:type x: int # Return the minimum number of K-bit flips required so that there is no 0 in the array.
:type y: int # If it is not possible, return -1.
:rtype: bool
""" # Add flips to a queue. Iterate over A, first removing from the queue all earlier flips that impact elements before
val_to_node = {root.val: root} # value to nodes at current depth # A[i]. Check the bit A[i], adding all the flips in the current window to the initial bit. Take modulo 2 to find the
node_to_parent = {root: None} # updated bit. If bit is 0, make a new flip.
# Time - O(n)
while True: # Space - O(K)
new_root = TreeNode(float("inf")) # new root to handle special case of val > root.val
def helper(num, length): # returns the nb permutations given previous num and permutation length new_root.right = root
node = new_root
if length == len(A): # used all elements successfully
return 1 while node.right and node.right.val > val:
node = node.right
count = 0
for next_num in pairs[num]: # for each next num that makes a square sum right_subtree = node.right
if freq[next_num] > 0: # must have some elements remaining node.right = TreeNode(val)
freq[next_num] -= 1 # decrement count node.right.left = right_subtree
count += helper(next_num, length + 1)
freq[next_num] += 1 # increment count return new_root.right
return count
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/997_Find_the_Town_Judge.py
# https://leetcode.com/problems/available-captures-for-rook/
_author_ = 'jake' # On an 8 x 8 chessboard, there is one white rook. There also may be empty squares, white bishops, and black pawns.
_project_ = 'leetcode' # These are given as characters 'R', '.', 'B', and 'p' respectively.
# Uppercase characters represent white pieces, and lowercase characters represent black pieces.
# https://leetcode.com/problems/find-the-town-judge/ # The rook moves as in the rules of Chess: it chooses one of four cardinal directions (north, east, west, and south),
# In a town, there are N people labelled from 1 to N. # then moves in that direction until it chooses to stop, reaches the edge of the board,
# There is a rumor that one of these people is secretly the town judge. # or captures an opposite colored pawn by moving to the same square it occupies.
# If the town judge exists, then: # Also, rooks cannot move into the same square as other friendly bishops.
# The town judge trusts nobody. # Return the number of pawns the rook can capture in one move.
# Everybody (except for the town judge) trusts the town judge.
# There is exactly one person that satisfies properties 1 and 2. # Find the coordinates of the rook. For each of the 4 directions, move until the edge of the board is reached, or a
# You are given trust, an array of pairs trust[i] = [a, b] representing that person labelled a trusts person labelled b. # bishop, or a pawn. If a pawn is found first, increment the count of pawns that can be captured.
# If the town judge exists and can be identified, return the label of the town judge. Otherwise, return -1. # Time - O(n**2) for board of size n
# Space - O(1)
# Count the net balance of the number of people trusting each person. If person A trusts person B, increment the count
# of B and decrement the count of A. The judge must be trusted by everybody and trust nobody, so has a count of N - 1. class Solution(object):
# Time - O(n**2) for n people def numRookCaptures(self, board):
# Space - O(n) """
:type board: List[List[str]]
class Solution(object): :rtype: int
def findJudge(self, N, trust): """
""" SIZE = 8
:type N: int
:type trust: List[List[int]] for r in range(SIZE):
:rtype: int for c in range(SIZE):
""" if board[r][c] == "R":
trust_count = [0] * (N + 1) start_r, start_c = r, c
break
for trustee, trusted in trust:
trust_count[trusted] += 1 pawns = 0
trust_count[trustee] -= 1 for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
row, col = start_r, start_c
for person in range(1, N + 1): while True:
if trust_count[person] == N - 1: row += dr
return person col += dc
if row < 0 or row >= SIZE or col < 0 or col >= SIZE:
return -1 break
if board[row][col] == "B":
break
if board[row][col] == "p":
# python_1_to_1000/998_Maximum_Binary_Tree_II.py - m pawns += 1
break
_author_ = 'jake'
_project_ = 'leetcode' return pawns
# https://leetcode.com/problems/maximum-binary-tree-ii/
# We are given the root node of a maximum tree: a tree where every node has a value greater than any other value in # python_1_to_1000/1000_Minimum_Cost_to_Merge_Stones.py - h
# its subtree.
# The given tree was constructed from an list A (root = Construct(A)) recursively with the following Construct(A) fn: _author_ = 'jake'
# If A is empty, return null. _project_ = 'leetcode'
# Otherwise, let A[i] be the largest element of A. Create a root node with value A[i].
# The left child of root will be Construct([A[0], A[1], ..., A[i-1]]) # https://leetcode.com/problems/minimum-cost-to-merge-stones/
# The right child of root will be Construct([A[i+1], A[i+2], ..., A[A.length - 1]]) # There are N piles of stones arranged in a row. The i-th pile has stones[i] stones.
# Return root. # A move consists of merging exactly K consecutive piles into one pile, and the cost of this move is equal to the
# Note that we were not given A directly, only a root node root = Construct(A). # total number of stones in these K piles.
# Suppose B is a copy of A with the value val appended to it. It is guaranteed that B has unique values. # Find the minimum cost to merge all piles of stones into one pile. If it is impossible, return -1.
# Return Construct(B).
# Return -1 if repeated merges will not leave one stone.
# The new value will always be a right child, since it is the last element of the input list. # For a given subarray, try all possible splits into a prefix and a suffix, which are separately merged.
# Move along the path of right children until there are no more right children or the node val is less than the new val. # The prefix may be a single pile (which ensures that there is some value passed to the min function) or any prefixe of
# Add the new node as a right child. The old right subtree is the new left subtree of the new node, since all its # a length that can be merged.
# elements are to the left of the new node in the list. # If the subarray is of the correct length to be merged, each pile is counted once.
# Create a dummy root with infinite value to ensure the new node is always a child of some node. # Time - O(n**3)
# Time - O(n) # Space - O(n**2)
# Space - O(1)
import functools
class Solution(object):
def insertIntoMaxTree(self, root, val): class Solution:
""" def mergeStones(self, stones, K):
:type root: TreeNode
:type val: int n = len(stones)
:rtype: TreeNode if (n - 1) % (K - 1) != 0: # each merge removes K - 1 and must leave 1 remaining
""" return -1
# Time - O(mn) for m words of length n
prefix_sum = [0] * (n + 1) # prefix_sum allows calculation of the sum of stones in a subarray # Space - O(mn)
for i in range(n):
prefix_sum[i + 1] = prefix_sum[i] + stones[i] from collections import Counter
result = []
# python_1001_to_2000/1001_Grid_Illumination.py - h for char, count in counts.items():
result += [char] * count # append count copies of each char
_author_ = 'jake' return result
_project_ = 'leetcode'
# https://leetcode.com/problems/grid-illumination/
# On a N x N grid of cells, each cell (x, y) with 0 <= x < N and 0 <= y < N has a lamp. # python_1001_to_2000/1003_Check_If_Word_Is_Valid_After_Substitutions.py - m
# Initially, some number of lamps are on. lamps[i] tells us the location of the i-th lamp that is on.
# Each lamp that is on illuminates every square on its x-axis, y-axis, and both diagonals (similar to a Queen in chess). _author_ = 'jake'
# For the i-th query queries[i] = (x, y), the answer to the query is 1 if the cell (x, y) is illuminated, else 0. _project_ = 'leetcode'
# After each query (x, y) [in the order given by queries], we turn off any lamps that are at cell (x, y) or are
# adjacent 8-directionally (ie., share a corner or edge with cell (x, y).) # https://leetcode.com/problems/check-if-word-is-valid-after-substitutions/
# Return an array of answers. Each value answer[i] should be equal to the answer of the i-th query queries[i]. # We are given that the string "abc" is valid.
# From any valid string V, we may split V into two pieces X and Y such that X + Y (X concatenated with Y) is equal to V.
# For each of the 4 directions (horizontal, vertical and 2 diagonals) count the number of lamps in each line. # (X or Y may be empty.) Then, X + "abc" + Y is also valid.
# For each query call, sum the number of lamps shining on that cell across all 4 directions. # If for example S = "abc", then examples of valid strings are: "abc", "aabcbc", "abcabc", "abcabcababcc".
# If there is at least one lamp shining on the query cell, check the 9 cells in and around the query for lamps and # Examples of invalid strings are: "abccba", "ab", "cababc", "bac".
# decrement the count in each direction for each lamp found. # Return true if and only if the given string S is valid.
# Time - O(m + n), nb lamps + nb queries
# Space - O(m) # Maintain a stack of characters seen but are not part of "abc". Iterate over S. When "a" is encountered, add it to the
# stack. For "b", the previous unmatched char must be "a". For "c", there must be "a" and "b" on the stack or else it
from collections import defaultdict # cannot be matched.
# Time - O(n)
class Solution(object): # Space - O(n)
def gridIllumination(self, N, lamps, queries):
""" class Solution:
:type N: int def isValid(self, S: str) -> bool:
:type lamps: List[List[int]]
:type queries: List[List[int]] if len(S) % 3 != 0: # S must consist of an integer number of "abc" strings
:rtype: List[int] return False
"""
lamps = {tuple(lamp) for lamp in lamps} # convert to set of O(1) lookup stack = []
x_lamps, y_lamps = defaultdict(int), defaultdict(int) # x_lamps[i] is the count of lamps with x-value of i
up_diag_lamps, down_diag_lamps = defaultdict(int), defaultdict(int) for c in S:
if c == "a":
for x, y in lamps: stack.append(c)
x_lamps[x] += 1 elif c == "b":
y_lamps[y] += 1 if stack and stack[-1] == "a":
up_diag_lamps[x - y] += 1 stack.append(c)
down_diag_lamps[x + y] += 1 else:
return False
result = [] elif c == "c":
for x, y in queries: if len(stack) >= 2 and stack[-2:] == ["a", "b"]:
illuminated = x_lamps[x] + y_lamps[y] + up_diag_lamps[x - y] + down_diag_lamps[x + y] stack.pop() # match with "a" and "b"
result.append(min(illuminated, 1)) # result of 1 if at least one lamp illuminating x, y stack.pop()
else:
if illuminated != 0: return False
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]: return not stack # all chars must be matched
if (x + dx, y + dy) in lamps:
lamps.discard((x + dx, y + dy))
x_lamps[x + dx] -= 1
y_lamps[y + dy] -= 1 # python_1001_to_2000/1004_Max_Consecutive_Ones_III.py - m
up_diag_lamps[x + dx - y - dy] -= 1
down_diag_lamps[x + dx + y + dy] -= 1 _author_ = 'jake'
_project_ = 'leetcode'
return result
# https://leetcode.com/problems/max-consecutive-ones-iii/
# Given an array A of 0s and 1s, we may change up to K values from 0 to 1.
# Return the length of the longest (contiguous) subarray that contains only 1s.
# python_1001_to_2000/1002_Find_Common_Characters.py
# Maintain a sliding window of length the maximum contiguous subarray. Iterate over A. If we have a zero, decrement
_author_ = 'jake' # the balance of additional ones we can add. If the balance becomes negative, we have used too many ones so move the
_project_ = 'leetcode' # start of the window forward, which increases the balance of additional ones if the element at the start of window
# was zero.
# https://leetcode.com/problems/find-common-characters/ # Time - O(n)
# Given an array A of strings made only from lowercase letters, return a list of all characters that show up in # Space - O(1)
# all strings within the list (including duplicates).
# For example, if a character occurs 3 times in all strings but not 4 times, you need to include that character three class Solution(object):
# times in the final answer. def longestOnes(self, A, K):
# You may return the answer in any order. """
:type A: List[int]
# Count the frequency of each character in the first word. For each other word, set the count of each character to the :type K: int
# lower of the existing character count and count in the other word. :rtype: int
""" return N + 1
i = 0 # index of start of window if (N - 4) % 4 <= 2: # (N+1) + ... + 6 - (5*4/3) + 2 - 1 or (N+1) + ... + 7 - (6*5/4) + 3 - 2 * 1
return N + 2
for j in range(len(A)): # index of end of window
return N - 1 # (N+1) + ... + 8 - (7*6/5) + 4 - 3 * 2 / 1
K -= 1 - A[j]
if K < 0: # length of window only increases if K >= 0
K += 1 - A[i]
i += 1 # python_1001_to_2000/1007_Minimum_Domino_Rotations_For_Equal_Row.py - m
# https://leetcode.com/problems/minimum-domino-rotations-for-equal-row/
# python_1001_to_2000/1005_Maximize_Sum_Of_Array_After_K_Negations.py # In a row of dominoes, A[i] and B[i] represent the top and bottom halves of the i-th domino.
# A domino is a tile with two numbers from 1 to 6 - one on each half of the tile.
_author_ = 'jake' # We may rotate the i-th domino, so that A[i] and B[i] swap values.
_project_ = 'leetcode' # Return the minimum number of rotations so that all the values in A are the same, or all the values in B are the same.
# If it cannot be done, return -1.
# https://leetcode.com/problems/maximize-sum-of-array-after-k-negations/
# Given an array A of integers, we must modify the array in the following way: we choose an i and # For each number from 1 to 6 inclusive, check if each domino has that number. There can be only one such number, or
# replace A[i] with -A[i], and we repeat this process K times in total. # 2 numbers with an identical number of rotations, so we take the first such number found.
# We may choose the same index i multiple times. # For that number, either rotate for every A that is not the number, or every B that is not the number.
# Return the largest possible sum of the array after modifying it in this way. # Time - O(n)
# Space - O(1)
# Sort the array in ascending order. Iterate along the array flipping all negative elements to positive until no more
# flips are required or there are no more negatives. If there are an odd number of flips remaining, flip the smallest class Solution(object):
# element, which is either the last element flipped (if any) or the next element. def minDominoRotations(self, A, B):
# Time - O(n log n) """
# Space - O(n) :type A: List[int]
:type B: List[int]
class Solution(object): :rtype: int
def largestSumAfterKNegations(self, A, K): """
""" n = len(A)
:type A: List[int]
:type K: int for num in range(1, 7):
:rtype: int if all(a == num or b == num for a, b in zip(A, B)):
""" return min(n - A.count(num), n - B.count(num))
A.sort()
return -1
i = 0
while K > 0 > A[i]: # K positive and A[i] negative
A[i] = -A[i]
i += 1 # python_1001_to_2000/1008_Construct_Binary_Search_Tree_from_Preorder_Traversal.py - m
K -= 1
_author_ = 'jake'
result = sum(A) _project_ = 'leetcode'
if K % 2 == 1:
result -= 2 * min(A[i], float("inf") if i == 0 else A[i - 1]) # https://leetcode.com/problems/construct-binary-search-tree-from-preorder-traversal/
# Return the root node of a binary search tree that matches the given preorder traversal.
return result # Recall that a binary search tree is a binary tree where for every node, any descendant of node.left has a
# value < node.val, and any descendant of node.right has a value > node.val.
# Also recall that a preorder traversal displays the value of the node first, then traverses node.left,
# python_1001_to_2000/1006_Clumsy_Factorial.py - m # then traverses node.right.
_author_ = 'jake' # Helper function builds tree, provided the next value is below max_value.
_project_ = 'leetcode' # Create the subtree root and increment the next index of preorder. Then build the left subtree from elements < root,
# then build the right subtree from elements < max_value (value of parent of root).
# https://leetcode.com/problems/clumsy-factorial/ # Time - O(n)
# Normally, the factorial of a positive integer n is the product of all positive integers less than or equal to n. # Space - O(n)
# For example, factorial(10) = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1.
# We instead make a clumsy factorial: using the integers in decreasing order, we swap out the multiply operations class Solution(object):
# for a fixed rotation of operations: multiply (*), divide (/), add (+) and subtract (-) in this order. def bstFromPreorder(self, preorder):
# For example, clumsy(10) = 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1. """
# However, these operations are still applied using the usual order of operations of arithmetic: we do all :type preorder: List[int]
# multiplication and division steps before any addition or subtraction steps, and multiplication and division steps :rtype: TreeNode
# are processed left to right. """
# Additionally, the division that we use is floor division such that 10 * 9 / 8 equals 11. self.i = 0 # index of next element to be added to tree
# This guarantees the result is an integer.
# Implement the clumsy function as defined above: given an integer N, it returns the clumsy factorial of N. def helper(max_value=float("inf")):
if self.i >= len(preorder) or preorder[self.i] > max_value:
# For N from 1 to 4 the results are 1, 2 * 1 = 2, 3 * 2 // 1 = 6 and 4 * 3 // 2 + 1 = 7. return None
# For larger N (>= 5), N * (N - 1) // (N - 2) = N + 1. Hence we can simplify the series,
# N * (N - 1) // (N - 2) + (N - 3) - (N - 4) * (N - 5) // (N - 6) + (N - 7) - (N - 8) .... = root = TreeNode(preorder[self.i])
# (N + 1) + (N - 3) - (N - 4) * (N - 5) // (N - 6) + (N - 7) - (N - 8) * .... = self.i += 1
# (N + 1) + (N - 3) - (N - 3) + (N - 7) - (N - 8) * .... = root.left = helper(root.val) # left subtree uses elements < root.val
# (N + 1) + (N - 3) - (N - 3) + (N - 7) - (N - 7) * .... = root.right = helper(max_value) # right subtree uses elements < max_value
# (N + 1) + ... return root
# Time - O(1)
# Space - O(1) return helper()
class Solution(object):
def clumsy(self, N):
""" # python_1001_to_2000/1009_Complement_of_Base_10_Integer.py
:type N: int
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
if N <= 2:
return N # https://leetcode.com/problems/complement-of-base-10-integer/
if N <= 4: # Every non-negative integer N has a binary representation.
return N + 3 # For example, 5 can be represented as "101" in binary, 11 as "1011" in binary, and so on.
# Note that except for N = 0, there are no leading zeroes in any binary representation.
if (N - 4) % 4 == 0: # (N+1) + ... + 5 - (4*3/2) + 1 # The complement of a binary representation is the number in binary you get when changing every 1 to a 0 and 0 to a 1.
# For example, the complement of "101" in binary is "010" in binary.
# For a given number N in base-10, return the complement of it's binary representation as a base-10 integer. return True
# Flip the sign of a bit by subtracting the bit from 1. Do this for all bits simultaneously by creating a mask with min_capacity = max(weights)
# all bits set. The mask is 2**bit_length - 1. max_capacity = sum(weights)
# Time - O(log n)
# Space - O(1) while min_capacity < max_capacity:
# python_1001_to_2000/1012_Numbers_With_Repeated_Digits.py - h
class Solution(object):
# python_1001_to_2000/1014_Best_Sightseeing_Pair.py - m def queryString(self, S, N):
"""
_author_ = 'jake' :type S: str
_project_ = 'leetcode' :type N: int
:rtype: bool
# https://leetcode.com/problems/best-sightseeing-pair/ """
# Given an array A of positive integers, A[i] represents the value of the i-th sightseeing spot, and two sightseeing for num in range(N, 0, -1):
# spots i and j have distance j - i between them. if bin(num)[2:] not in S: # ignore "0b" prefix of bin()
# The score of a pair (i < j) of sightseeing spots is (A[i] + A[j] + i - j) : the sum of the values of the sightseeing return False
# spots, minus the distance between them.
# Return the maximum score of a pair of sightseeing spots. return True
# Iterate along the array, tracking the best previous (value - distance).
# For each element, update the result with the element value + best_minus_dist if it is greater than the current
# result. Also update best_minus_dist if it increases and decrement due to the increased distance. # python_1001_to_2000/1017_Convert_to_Base_-2.py - m
# Time - O(n)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def maxScoreSightseeingPair(self, A): # https://leetcode.com/problems/convert-to-base-2/
""" # Given a number N, return a string consisting of "0"s and "1"s that represents its value in base -2 (negative two).
:type A: List[int] # The returned string must have no leading zeroes, unless the string is "0".
:rtype: int
""" # In base -2 a number is expressed as a + -2*b + 4*c + -8*d + 16*e + ... for some bits a, b, c, d, e ...
best_minus_dist = 0 # Repeatedly divide by 2 to determine if the least significant bit should be set. Flip the sign of the number after
result = 0 # each division so the next number becomes b + -2*c + 4*d + -8*e + ... and repeat until zero.
# Bits are found in order from least to most significant, so reverse the result.
for num in A: # Time - O(log n)
result = max(result, num + best_minus_dist) # Space - O(log n)
best_minus_dist = max(best_minus_dist - 1, num - 1)
class Solution(object):
return result def baseNeg2(self, N):
"""
:type N: int
:rtype: str
# python_1001_to_2000/1015_Smallest_Integer_Divisible_by_K.py - m """
if N == 0:
_author_ = 'jake' return "0"
_project_ = 'leetcode' result = []
# https://leetcode.com/problems/smallest-integer-divisible-by-k/ while N != 0:
# Given a positive integer K, you need find the smallest positive integer N such that N is divisible by K, N, bit = divmod(N, 2)
# and N only contains the digit 1. N *= -1
# Return the length of N. If there is no such N, return -1. result.append(str(bit))
# If K is divisible by 2 or 5 then we can never find a multiplier m such that Km has least significant digit of 1. return "".join(reversed(result))
# Try all possible N in the sequence 1, 11, 111, 1111, ... testing whether there is no remainder from N // K.
# If no remainder, return the length of N. Else retain the remainder and add to set of remainders seen.
# If the same remainder is repeated then there is a cycle and a result cannot be found.
# Time - O(K) since there may be upto K possible reminders # python_1001_to_2000/1018_Binary_Prefix_Divisible_By_5.py
# Space - O(K)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def smallestRepunitDivByK(self, K):
""" # https://leetcode.com/problems/binary-prefix-divisible-by-5/
:type K: int # Given an array A of 0s and 1s, consider N_i: the i-th subarray from A[0] to A[i] interpreted as a binary number,
:rtype: int # from most-significant-bit to least-significant-bit.
""" # Return a list of booleans answer, where answer[i] is true if and only if N_i is divisible by 5.
if K % 10 not in {1, 3, 7, 9}:
return -1 # Iterate over A. For each bit, multiply the existing num by 2 (bit shift left) and add the bit. Take modulo 5, since
# mod is preserved under multiplication and addition.
mod_N, mod_set = 0, set() # Time - O(n)
# Space - O(n)
for length in range(1, K + 1): # iterate the length of N upto K
mod_N = (10 * mod_N + 1) % K class Solution(object):
if mod_N == 0: def prefixesDivBy5(self, A):
return length """
if mod_N in mod_set: # mod_N has been seen before :type A: List[int]
return -1 :rtype: List[bool]
mod_set.add(mod_N) """
result = []
return -1 num = 0
for bit in A:
num = (num * 2 + bit) % 5
# python_1001_to_2000/1016_Binary_String_With_Substrings_Representing_1_To_N.py - m result.append(num == 0)
# https://leetcode.com/problems/next-greater-node-in-linked-list/ # python_1001_to_2000/1021_Remove_Outermost_Parentheses.py
# We are given a linked list with head as the first node.
# Let's number the nodes in the list: node_1, node_2, node_3, ... etc. _author_ = 'jake'
# Each node may have a next larger value: for node_i, next_larger(node_i) is the node_j.val such that j > i, _project_ = 'leetcode'
# node_j.val > node_i.val, and j is the smallest possible choice.
# If such a j does not exist, the next larger value is 0. # https://leetcode.com/problems/remove-outermost-parentheses/
# Return an array of integers answer, where answer[i] = next_larger(node_{i+1}). # A valid parentheses string is either empty (""), "(" + A + ")", or A + B, where A and B are valid parentheses strings,
# and + represents string concatenation.
# Iterate along the list, maintaining a stack of nodes without greater elements. Stack contains nodes in descending # For example, "", "()", "(())()", and "(()(()))" are all valid parentheses strings.
# order (otherwise next greater value would be known), and node indices. # A valid parentheses string S is primitive if it is nonempty, and there does not exist a way to split it into S = A+B,
# For each node, pop all smaller values off the stack and update their next greater values with the # with A and B nonempty valid parentheses strings.
# current node value. # Given a valid parentheses string S, consider its primitive decomposition: S = P_1 + P_2 + ... + P_k,
# Time - O(n) # where P_i are primitive valid parentheses strings.
# Space - O(n) # Return S after removing the outermost parentheses of every primitive string in the primitive decomposition of S.
class Solution(object): # Maintain the net balance of opening - closing brackets. Iterate over S.
def nextLargerNodes(self, head): # If the balance is zero, we must have an opening bracket of a primitie string which is not added to the result.
""" # Update the balance and add the char to the result.
:type head: ListNode # Then if the balance is zero, we have a closing bracket of a primitive string, which is removed from the result.
:rtype: List[int] # Time - O(n)
""" # Space - O(n)
result = []
stack = [] # (index, val) tuples of nodes without next greater, ordered by decreasing val class Solution(object):
node = head def removeOuterParentheses(self, S):
i = 0 # index of node in list """
:type S: str
while node: :rtype: str
"""
result.append(0) # add a new entry to result with default of 0 if no greater node result = []
balance = 0
while stack and stack[-1][1] < node.val: # all smaller vals have the current node as the next greater
j, _ = stack.pop() for c in S:
result[j] = node.val
if balance != 0: # do not add opening bracket if all pairs are matched
stack.append((i, node.val)) result.append(c)
i += 1
node = node.next change = 1 if c == "(" else -1
balance += change
return result
if balance == 0: # remove closing bracket if all pairs are matched
result.pop()
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1022_Sum_of_Root_To_Leaf_Binary_Numbers.py
# https://leetcode.com/problems/number-of-enclaves/
# Given a 2D array A, each cell is 0 (representing sea) or 1 (representing land) _author_ = 'jake'
# A move consists of walking from one land square 4-directionally to another land square, _project_ = 'leetcode'
# or off the boundary of the grid.
# Return the number of land squares in the grid for which we cannot walk off the boundary of the grid # https://leetcode.com/problems/sum-of-root-to-leaf-binary-numbers/
# in any number of moves. # Given a binary tree, each node has value 0 or 1.
# Each root-to-leaf path represents a binary number starting with the most significant bit.
# For each cell of the grid, explore the connected (land) cells with depth-first search. # For example, if the path is 0 -> 1 -> 1 -> 0 -> 1, then this could represent 01101 in binary, which is 13.
# A flag indicates whether any connected cell touches the edge of the grid, so the island is not an enclave. # For all leaves in the tree, consider the numbers represented by the path from the root to that leaf.
# Set the value of each cell visited to zero to avoid repetition. # Return the sum of these numbers.
# Time - O(mn)
# Space - O(mn) # For each node, update the previous value by multiplying by 2 (left bit shift) and adding the new bit.
# If the node is a leaf, return the updated value. Else recurse and sum the leaves in the left and right subtrees.
class Solution(object): # Time - O(n)
def numEnclaves(self, A): # Space - O(n)
"""
:type A: List[List[int]] class Solution(object):
:rtype: int def sumRootToLeaf(self, root):
""" """
rows, cols = len(A), len(A[0]) :type root: TreeNode
result = 0 :rtype: int
self.edge = False # flag indicating whether current group of cells touches an edge of the grid """
def helper(node, running):
def enclave(r, c): # return count of enclave cells, or zero if not an enclave
if r < 0 or c < 0 or r >= rows or c >= cols: if not node:
return 0 return 0
if A[r][c] != 1:
return 0 running = running * 2 + node.val
if not node.left and not node.right:
if r == 0 or c == 0 or r == rows - 1 or c == cols - 1: return running
self.edge = True
A[r][c] = 0 return helper(node.left, running) + helper(node.right, running)
count = 1
for dr, dc in [(0, 1), (1, 0), (-1, 0), (0, -1)]: # recursively add all neighbours return helper(root, 0) % (10 ** 9 + 7)
count += enclave(r + dr, c + dc)
return count if not self.edge else 0 # return 0 if not an enclave
_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/camelcase-matching/ _project_ = 'leetcode'
# A query word matches a given pattern if we can insert lowercase letters to the pattern so that it equals the query.
# We may insert each character at any position, and may insert 0 characters. # https://leetcode.com/problems/divisor-game/
# Given a list of queries, and a pattern, return an answer list of booleans, # Alice and Bob take turns playing a game, with Alice starting first.
# where answer[i] is true if and only if queries[i] matches the pattern. # Initially, there is a number N on the chalkboard. On each player's turn, that player makes a move consisting of:
# Choosing any x with 0 < x < N and N % x == 0.
# For each query, iterate over the pattern and track the index of the next char of query to be matched. # Replacing the number N on the chalkboard with N - x.
# If the query is upper case and does not match the pattern then they cannot match. # Also, if a player cannot make a move, they lose the game.
# Move past all the chars in the query that are lower case and do not match the pattern, since they can be inserted. # Return True if and only if Alice wins the game, assuming both players play optimally.
# If the query ends before all the pattern is matched, return False. Else there is a match.
# Return False if there are any unmatched upper case chars in the pattern after all the query is matched. # If N is even, Alice can always subtract 1 and make N - x odd for Bob.
# Repeat for each query. # If N is odd, then it only has odd factors so N - x will always be even or no move is possible if N == 1.
# Time - O(nm) for n queries of length m. # Thus N will alternate between even and odd and the person with the even numbers will always be able to make a move.
# Space - O(m) # The person with odd numbers will eventually have 1 and lose.
# Time - O(1)
class Solution(object): # Space - O(1)
def camelMatch(self, queries, pattern):
""" class Solution:
:type queries: List[str] def divisorGame(self, N: int) -> bool:
:type pattern: str return N % 2 == 0
:rtype: List[bool]
"""
def can_match(query):
i = 0 # index of next char to match in query # python_1001_to_2000/1026_Maximum_Difference_Between_Node_and_Ancestor.py - m
for c in pattern:
_author_ = 'jake'
while i < len(query) and c != query[i]: _project_ = 'leetcode'
if query[i].isupper():
return False # https://leetcode.com/problems/maximum-difference-between-node-and-ancestor/
i += 1 # Given the root of a binary tree, find the maximum value V for which there exists different
# nodes A and B where V = |A.val - B.val| and A is an ancestor of B.
if i == len(query): # reached end of query with some pattern remaining # A node A is an ancestor of B if either: any child of A is equal to B, or any child of A is an ancestor of B.
return False
i += 1 # Recursive helper function tracks the max and min values seen along the current path from the root.
# The max and min values are updated at each node, returning the max difference after any leaf.
return query[i:] == query[i:].lower() # remainder is all lower case # Recurse left and right with the updated max and min and return the biggest difference from either subtree.
# Time - O(n)
return [can_match(query) for query in queries] # Space - O(n)
class Solution(object):
def maxAncestorDiff(self, root):
# python_1001_to_2000/1024_Video_Stitching.py - m """
:type root: TreeNode
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
def helper(node, min_val, max_val):
# https://leetcode.com/problems/video-stitching/ if not node:
# You are given a series of video clips from a sporting event that lasted T seconds. return max_val - min_val
# These video clips can be overlapping with each other and have varied lengths.
# Each video clip clips[i] is an interval: it starts at time clips[i][0] and ends at time clips[i][1]. min_val = min(node.val, min_val)
# We can cut these clips into segments freely: max_val = max(node.val, max_val)
# for example, a clip [0, 7] can be cut into segments [0, 1] + [1, 3] + [3, 7].
# Return the minimum number of clips needed so that we can cut the clips into segments that cover the entire return max(helper(node.left, min_val, max_val), helper(node.right, min_val, max_val))
# sporting event ([0, T]). If the task is impossible, return -1.
return helper(root, float("inf"), float("-inf"))
# Sort the clips in ascending start order, with ties broken by ascending end order.
# Maintain the two greatest ends of the clips used (not necessarily the ends of the last 2 used clips).
# Iterate over the clips, breaking if there is a gap between the start of the clip and the previous end or we have
# reached the required length. # python_1001_to_2000/1027_Longest_Arithmetic_Sequence.py - m
# If the start is greater than the prev_stitch_end then we must add another clip (otherwise we can replace the
# previous clip). _author_ = 'jake'
# Note that if end < stitch_end we may still increment the count and set prev_stitch_end = stitch_end and the clip _project_ = 'leetcode'
# will later be replaced.
# Time - O(n log n) # https://leetcode.com/problems/longest-arithmetic-sequence/
# Space - O(1) # Given an array A of integers, return the length of the longest arithmetic subsequence in A.
# Recall that a subsequence of A is a list A[i_1], A[i_2], ..., A[i_k] with 0 <= i_1 < i_2 < ... < i_k <= A.length - 1,
class Solution(object): # and that a sequence B is arithmetic if B[i+1] - B[i] are all the same value (for 0 <= i < B.length - 1).
def videoStitching(self, clips, T):
""" # For each element of the array, maintain a mapping from a subsequence difference to the length of the subsequence.
:type clips: List[List[int]] # For each pair of elements, calculate the difference between their values.
:type T: int # Update the mapping for the later element with the greater of its current length and 1 + the length of the
:rtype: int # subsequence ending at the earlier element.
""" # The result is the maximum length from all sequences, plus one since we have counted the number of difference in a
prev_stitch_end, stitch_end = -1, 0 # two greatest ends of used clips # subsequence and require the number of elements.
result = 0 # count of used clips # Time - O(n**2)
# Space - O(n**2)
for start, end in sorted(clips):
if start > stitch_end or stitch_end >= T: from collections import defaultdict
break
class Solution(object):
if start > prev_stitch_end: def longestArithSeqLength(self, A):
result += 1 """
prev_stitch_end = stitch_end :type A: List[int]
:rtype: int
stitch_end = max(stitch_end, end) """
# map sequence difference to its length for each element of A
return -1 if stitch_end < T else result sequences = [defaultdict(int) for _ in range(len(A))]
return node
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1029_Two_City_Scheduling.py - m
# https://leetcode.com/problems/maximum-sum-of-two-non-overlapping-subarrays/
_author_ = 'jake' # Given an array A of non-negative integers, return the maximum sum of elements in two non-overlapping (contiguous)
_project_ = 'leetcode' # subarrays, which have lengths L and M.
# For clarification, the L-length subarray could occur before or after the M-length subarray.
# https://leetcode.com/problems/two-city-scheduling/ # Formally, return the largest V for which V = (A[i] + A[i+1] + ... + A[i+L-1]) +
# There are 2N people a company is planning to interview. # (A[j] + A[j+1] + ... + A[j+M-1]) and either:
# The cost of flying the i-th person to city A is costs[i][0], # 0 <= i < i + L - 1 < j < j + M - 1 < A.length, or
# and the cost of flying the i-th person to city B is costs[i][1]. # 0 <= j < j + M - 1 < i < i + L - 1 < A.length.
# Return the minimum cost to fly every person to a city such that exactly N people arrive in each city.
# Iterate over A. At each index we check the 2 cases of either L or M ending at that index.
# Sort the costs by the difference between flying to city A and city B. # Update the sum of L by adding the latest element and subtracting the element leaving L.
# Fly the first half of the sorted list to city A and the second half to city B. # Update the sum of M ending immediately before L by adding and subtracting elements, then update the maximum seen
# Time - O(n log n) # sum of M ending before L.
# Space - O(n) # Update the result if the sum of L plus any earlier M array sum is greater than seen already.
# Check the second case by reversing the roles of L and M.
class Solution(object): # Time - O(n)
def twoCitySchedCost(self, costs): # Space - O(1)
"""
:type costs: List[List[int]] class Solution(object):
:rtype: int def maxSumTwoNoOverlap(self, A, L, M):
""" """
costs.sort(key = lambda x: x[0] - x[1]) :type A: List[int]
n = len(costs) // 2 :type L: int
return sum(a for a, _ in costs[:n]) + sum(b for _, b in costs[n:]) :type M: int
:rtype: int
"""
L_sum, M_sum = sum(A[M:L + M]), sum(A[L:L + M]) # sums of L and M ending at current index
# python_1001_to_2000/1030_Matrix_Cells_in_Distance_Order.py L_before_M_sum, M_before_L_sum = sum(A[:L]), sum(A[:M]) # sum of L ending before current M
L_before_M_best, M_before_L_best = L_before_M_sum, M_before_L_sum # max seen of above
_author_ = 'jake'
_project_ = 'leetcode' result = sum(A[:L + M]) # start from index L + M
for i in range(L + M, len(A)): # The maximum number of moves happens when the outer stones are moved in 1 place every turn.
L_sum = L_sum + A[i] - A[i - L] # Time - O(1)
M_before_L_sum = M_before_L_sum + A[i - L] - A[i - L - M] # Space - O(1)
M_before_L_best = max(M_before_L_best, M_before_L_sum)
result = max(result, L_sum + M_before_L_best) class Solution(object):
def numMovesStones(self, a, b, c):
M_sum = M_sum + A[i] - A[i - M] """
L_before_M_sum = L_before_M_sum + A[i - M] - A[i - M - L] :type a: int
L_before_M_best = max(L_before_M_best, L_before_M_sum) :type b: int
result = max(result, M_sum + L_before_M_best) :type c: int
:rtype: List[int]
return result """
stones = sorted([a, b, c])
gap1, gap2 = stones[1] - stones[0] - 1, stones[2] - stones[1] - 1
min_moves = 1 if gap1 == 1 or gap2 == 1 else int(gap1 > 0) + int(gap2 > 0)
# python_1001_to_2000/1032_Stream_of_Characters.py - h max_moves = gap1 + gap2
return [min_moves, max_moves]
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/stream-of-characters/ # python_1001_to_2000/1034_Coloring_A_Border.py - m
# Implement the StreamChecker class as follows:
# StreamChecker(words): Constructor, init the data structure with the given words. _author_ = 'jake'
# query(letter): returns true if and only if for some k >= 1, the last k characters queried _project_ = 'leetcode'
# (in order from oldest to newest, including this letter just queried) spell one of the words in the given list.
# https://leetcode.com/problems/coloring-a-border/
# Query is true if some word ends with the most recent query. # Given a 2-dimensional grid of integers, each value in the grid represents the color of
# Store the reversed words in a trie. Each node of the trie is a dictionary keyed by characters and with values of # the grid square at that location.
# the child node corresponding to that character. The presence of a character of "#" indicates that a word terminates # Two squares belong to the same connected component if and only if they have the same color and
# at that node. Also store the list of query characters. # are next to each other in any of the 4 directions.
# Add each query to list of previous query characters. Starting from the root of the trie, iterate backwards along the # The border of a connected component is all the squares in the connected component that are either
# list of queries. # 4-directionally adjacent to a square not in the component, or on the boundary of the grid
# If a character is not found, there is no word with the previous queries as a suffix. # (the first or last row or column).
# Return True if a complete word is found. # Given a square at location (r0, c0) in the grid and a color, color the border of the connected component of
# Time - O(n) for __init__ where n is the total length of all words. O(m) to query where m is the number of queries. # that square with the given color, and return the final grid.
# Space - O(m + n)
# Depth-first search helper function return True if a cell is part of the connected component.
class StreamChecker(object): # If a cell is outside the grid or no the the colour of grid[r0][c0] return False.
# Recurse in all 4 directions and if not all neighbours are connected then this cell is on the border.
def __init__(self, words): # Important to recurse in all directions and not check for any not connected (stopping for the first found) because
""" # the border colour can only be set when the cell will not be checked again.
:type words: List[str] # Time - O(mn)
""" # Space - O(mn)
self.root = {} # Trie root, each node maps char to next node
class Solution(object):
for word in words: def colorBorder(self, grid, r0, c0, color):
node = self.root """
for c in reversed(word): :type grid: List[List[int]]
if c not in node: :type r0: int
node[c] = {} :type c0: int
node = node[c] :type color: int
node["#"] = True # "#" signifies complete word :rtype: List[List[int]]
"""
self.queries = [] original = grid[r0][c0]
rows, cols = len(grid), len(grid[0])
def query(self, letter): connected = set()
"""
:type letter: str def dfs(r, c):
:rtype: bool if (r, c) in connected: # already known to be connected, do not explore again
""" return True
self.queries.append(letter) if r < 0 or c < 0 or r >= rows or c >= cols or grid[r][c] != original:
node = self.root return False
connected.add((r, c))
for c in reversed(self.queries): if not sum(dfs(r + dr, c + dc) for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]) == 4:
if c not in node: grid[r][c] = color
return False return True
node = node[c]
if "#" in node: dfs(r0, c0)
return True return grid
# python_1001_to_2000/1035_Uncrossed_Lines.py - m
# Sort the stones and calculate the length of the 2 gaps between stones. class Solution(object):
# If either gap is 1 then the minimum moves if 1 since a stone can fill the gap. Else move each outer stone next to def maxUncrossedLines(self, A, B):
# the middle stone if there is a gap. """
:type A: List[int]
:type B: List[int] visited.add((r, c))
:rtype: int for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]:
""" new_frontier.add((r + dr, c + dc))
if len(A) < len(B): # ensure B is shorter to use less space
A, B = B, A frontier = new_frontier
max_uncrossed = [0] * (len(B) + 1)
return False
for i in range(len(A)):
new_max_uncrossed = [0]
for j in range(len(B)):
new_max_uncrossed.append(max(max_uncrossed[j] + int(A[i] == B[j]), # python_1001_to_2000/1037_Valid_Boomerang.py
max_uncrossed[j + 1], new_max_uncrossed[-1]))
max_uncrossed = new_max_uncrossed _author_ = 'jake'
_project_ = 'leetcode'
return max_uncrossed[-1]
# https://leetcode.com/problems/valid-boomerang/
# A boomerang is a set of 3 points that are all distinct and not in a straight line.
# Given a list of three points in the plane, return whether these points are a boomerang.
# python_1001_to_2000/1036_Escape_a_Large_Maze.py - h
# Check if points are unique by calculating the length of the set of points.
_author_ = 'jake' # Points are a boomerang if the slopes between any 2 pairs of points are not equal.
_project_ = 'leetcode' # dx_1 / dy_1 != dx_2 / dy_2 but we multiply by dy_1 * dy_2 to avoid division by zero.
# Time - O(1)
# https://leetcode.com/problems/escape-a-large-maze/ # Space - O(1)
# In a 1 million by 1 million grid, the coordinates of each grid square are (x, y) with 0 <= x, y < 10^6.
# We start at the source square and want to reach the target square. class Solution(object):
# Each move, we can walk to a 4-directionally adjacent square in the grid that isn't in the list of blocked squares. def isBoomerang(self, points):
# Return true if and only if it is possible to reach the target square through a sequence of moves. """
# 0 <= blocked.length <= 200 :type points: List[List[int]]
:rtype: bool
# Compress the grid so that gaps between populated rows and columns are at most one square wide. """
# Then perform breadth-first search. if len({tuple(point) for point in points}) != 3: # convert to tuple to allow use of set
# Time - O(1) since there are at most 200 blocked squares. return False
# Space - O(1)
dx_1 = points[1][0] - points[0][0]
class Solution(object): dy_1 = points[1][1] - points[0][1]
def isEscapePossible(self, blocked, source, target): dx_2 = points[2][0] - points[0][0]
""" dy_2 = points[2][1] - points[0][1]
:type blocked: List[List[int]] return dy_1 * dx_2 != dy_2 * dx_1
:type source: List[int]
:type target: List[int]
:rtype: bool
""" # python_1001_to_2000/1038_Binary_Search_Tree_to_Greater_Sum_Tree.py - m
# make sorted lists of all rows and cols used in blocked, source or target
rows, cols = set(), set() _author_ = 'jake'
for r, c in blocked + [source, target]: _project_ = 'leetcode'
rows.add(r)
cols.add(c) # https://leetcode.com/problems/binary-search-tree-to-greater-sum-tree/
rows, cols = sorted(list(rows)), sorted(list(cols)) # Given the root of a binary search tree with distinct values, modify it so that every node has a new value equal to
# the sum of the values of the original tree that are greater than or equal to node.val.
# map original rows and cols to compressed values that reduce gaps to 1 element # As a reminder, a binary search tree is a tree that satisfies these constraints:
row_to_compressed, col_to_compressed = {}, {} # The left subtree of a node contains only nodes with keys less than the node's key.
new_row, new_col = int(rows[0] != 0), int(cols[0] != 0) # add a gap if not starting at row or col zero # The right subtree of a node contains only nodes with keys greater than the node's key.
# Both the left and right subtrees must also be binary search trees.
for i, r in enumerate(rows):
if i != 0 and rows[i - 1] != r - 1: # not consecutive, add a gap of a single row # Perform a reversed inorder traversal, visiting nodes from highest to lowest value.
new_row += 1 # For each node, add its value to the running sum then update its value.
row_to_compressed[r] = new_row # Time - O(n)
new_row += 1 # Space - O(n)
if frontier & back - blocked: # overlap between back and frontier that is not blocked # python_1001_to_2000/1039_Minimum_Score_Triangulation_of_Polygon.py - m
return True
if len(frontier) > len(back): # expand smaller of frontier and back _author_ = 'jake'
frontier, back = back, frontier _project_ = 'leetcode'
new_frontier = set()
# https://leetcode.com/problems/minimum-score-triangulation-of-polygon/
for r, c in frontier: # Given N, consider a convex N-sided polygon with vertices labelled A[0], A[i], ..., A[N-1] in clockwise order.
if (r, c) in blocked or (r, c) in visited: # Suppose you triangulate the polygon into N-2 triangles.
continue # For each triangle, the value of that triangle is the product of the labels of the vertices,
if r < 0 or r >= new_row or c < 0 or c >= new_col: # and the total score of the triangulation is the sum of these values over all N-2 triangles in the triangulation.
continue # Return the smallest possible total score that you can achieve with some triangulation of the polygon.
# Each edge forms a triangle with another vertex not along the edge. # Track the robot's position and direction, updating after every move.
# Recursively choose any edge (last vertex to first vertex) and build triangles with all other vertices. Add the # If the direction is changed after all moves then the position will return to the origin after 2 or 4 repeats of the
# product of the triangle vertices from the recursive results of the smaller left and right polygons. Memoize. # instructions. If the direction is unchanged then the position must also be unchanged.
# Time - O(n**3) # Time - O(n)
# Space - O(n**2) # Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1042_Flower_Planting_With_No_Adjacent.py - m
# https://leetcode.com/problems/moving-stones-until-consecutive-ii/
# On an infinite number line, the position of the i-th stone is given by stones[i]. _author_ = 'jake'
# Call a stone an endpoint stone if it has the smallest or largest position. _project_ = 'leetcode'
# Each turn, pick up an endpoint stone and move it to an unoccupied position so that it is no longer an endpoint stone.
# In particular, if the stones are at say, stones = [1,2,5], you cannot move the endpoint stone at position 5, # https://leetcode.com/problems/flower-planting-with-no-adjacent/
# since moving it to any position (such as 0, or 3) will still keep that stone as an endpoint stone. # You have N gardens, labelled 1 to N. In each garden, you want to plant one of 4 types of flowers.
# The game ends when you cannot make any more moves, ie. the stones are in consecutive positions. # paths[i] = [x, y] describes the existence of a bidirectional path from garden x to garden y.
# When the game ends, what is the minimum and maximum number of moves that you could have made? # Also, there is no garden that has more than 3 paths coming into or leaving it.
# Return the answer as an length 2 array: answer = [minimum_moves, maximum_moves] # Your task is to choose a flower type for each garden such that, for any two gardens connected by a path,
# they have different types of flowers.
# The maximum moves happens when we move either the laft or right stone first then gradually fill all the gaps # Return any such a choice as an array answer, where answer[i] is the type of flower planted in the (i+1)-th garden.
# between stones, apart from the first or last gap depending on which stone moves first. # The flower types are denoted 1, 2, 3, or 4. It is guaranteed an answer exists.
# To find the minimum gap, consider a sliding window of length n where n is the number of stones.
# Find the number of moves required to fill each window for each stone at the right end of the window. # For each garden, plant a flower randomly chosen from the set of flowers that are not
# The number of moves is the number of stones outside the window, plus one if only the first position of the window # planted in any neighbouring garden.
# is unoccupied (because we cannot move a stone to an endpoint). # Time - O(n) since there are at most 3 paths for each garden.
# Time - O(n) # Space - O(n)
# Space - O(n)
from collections import defaultdict
from collections import deque
class Solution(object):
class Solution(object): def gardenNoAdj(self, N, paths):
def numMovesStonesII(self, stones): """
""" :type N: int
:type stones: List[int] :type paths: List[List[int]]
:rtype: List[int] :rtype: List[int]
""" """
n = len(stones) edges = defaultdict(set) # convert to map from garden to set of neighbouring gardens
stones.sort() for i, j in paths:
edges[i].add(j)
sum_gaps = stones[-1] - stones[0] - n + 1 # all gaps between stones edges[j].add(i)
max_moves = sum_gaps - min(stones[1] - stones[0] - 1, stones[-1] - stones[-2] - 1)
flowers = [None] * (N + 1) # flowers[0] is not used
window = deque() # stones in the sliding window
min_moves = n for garden in range(1, N + 1):
# python_1001_to_2000/1041_Robot_Bounded_In_Circle.py - m # https://leetcode.com/problems/partition-array-for-maximum-sum/
# Given an integer array A, you partition the array into (contiguous) subarrays of length at most K.
_author_ = 'jake' # After partitioning, each subarray has their values changed to become the maximum value of that subarray.
_project_ = 'leetcode' # Return the largest sum of the given array after partitioning.
# https://leetcode.com/problems/robot-bounded-in-circle/ # For each index i of A, create new subarrays of lengths 1, 2... K ending with A[i]. Track the maximum value in the
# On an infinite plane, a robot initially stands at (0, 0) and faces north. # subarray and add the maximum value * subarray length to the result for A ending before the subarray.
# The robot can receive one of three instructions: # Time - O(nK)
# "G": go straight 1 unit; # Space - O(n)
# "L": turn 90 degrees to the left;
# "R": turn 90 degress to the right. class Solution(object):
# The robot performs the instructions given in order, and repeats them forever. def maxSumAfterPartitioning(self, A, K):
# Return true if and only if there exists a circle in the plane such that the robot never leaves the circle. """
:type A: List[int]
:type K: int import heapq
:rtype: int
""" class Solution(object):
results = [0] # results[i] for array A[:i] (of length i) def lastStoneWeight(self, stones):
"""
for i in range(len(A)): :type stones: List[int]
:rtype: int
subarray_max, max_result = 0, 0 """
stones = [-stone for stone in stones] # negative so largest values are popped first
for j in range(i, max(-1, i - K), -1): # first element of new subarray heapq.heapify(stones)
subarray_max = max(subarray_max, A[j])
max_result = max(max_result, subarray_max * (i - j + 1) + results[j]) while len(stones) > 1:
results.append(max_result) new = heapq.heappop(stones) - heapq.heappop(stones)
if new != 0:
return results[-1] heapq.heappush(stones, new)
# python_1001_to_2000/1044_Longest_Duplicate_Substring.py - h
class Solution(object):
# python_1001_to_2000/1046_Last_Stone_Weight.py def longestStrChain(self, words):
"""
_author_ = 'jake' :type words: List[str]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/last-stone-weight/ longest = defaultdict(int)
# We have a collection of rocks, each rock has a positive integer weight.
# Each turn, we choose the two heaviest rocks and smash them together. for word in sorted(words, key=len):
# Suppose the stones have weights x and y with x <= y. for i in range(len(word)):
# The result of this smash is: prev = longest[word[:i] + word[i + 1:]] # result for word with word[i] removed
# If x == y, both stones are totally destroyed; longest[word] = max(longest[word], prev + 1)
# If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x.
# At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.) return max(longest.values())
# Create a heap of the stones. While the are at least 2 stones, pop off the largest 2 weights and smash them.
# Add the resulting stone back to the heap if it has non-zero weight.
# Time - O(n log n) # python_1001_to_2000/1049_Last_Stone_Weight_II.py - m
# Space - O(n)
# We need to partition the stones into two disjoint sets where the difference between the sums of the sets is as # python_1001_to_2000/1053_Previous_Permutation_With_One_Swap.py - m
# small as possible.
# Make the set of all possible sums by including or excluding each stone. _author_ = 'jake'
# Return the minimum of the absolute difference between any s sum and its compliment (sum(stones) - s). _project_ = 'leetcode'
# Time - O(2**n)
# Space - O(2**n) # https://leetcode.com/problems/previous-permutation-with-one-swap/
# Given an array A of positive integers (not necessarily distinct),
class Solution(object): # return the lexicographically largest permutation that is smaller than A, that can be made with one swap.
def lastStoneWeightII(self, stones): # A swap exchanges the positions of two numbers A[i] and A[j]).
""" # If it cannot be done, then return the same array.
:type stones: List[int]
:rtype: int # Iterate from the least significant digit to the most significant.
""" # If a digit is grater than the previous digit then A can be made smaller by swapping A[i] with the next smallest
all_sums = {0} # digit. Search for the next smallest digit, taking the most significant in the event of a tie.
# Time - O(n)
for stone in stones: # add stone to all previous sums, also retain all previous sums # Space - O(1)
all_sums |= {stone + prev_sum for prev_sum in all_sums}
class Solution(object):
return min(abs(sum(stones) - s - s) for s in all_sums) def prevPermOpt1(self, A):
"""
:type A: List[int]
:rtype: List[int]
# python_1001_to_2000/1051_Height_Checker.py """
for i in range(len(A) - 2, -1, -1):
_author_ = 'jake'
_project_ = 'leetcode' if A[i] > A[i + 1]: # A can be made smaller by swapping a smaller digit to A[i]
# https://leetcode.com/problems/height-checker/ max_seen = -1
# Students are asked to stand in non-decreasing order of heights for an annual photo. for j in range(len(A) - 1, i, -1):
# Return the minimum number of students not standing in the right positions. if A[j] >= max_seen and A[j] < A[i]:
# This is the number of students that must move in order for all students to be standing in non-decreasing max_seen = A[j]
# order of height. max_seen_index = j
# Compare the sorted ordering with the original ordering. A[i], A[max_seen_index] = A[max_seen_index], A[i] # swap
# Time - O(n log n) break
# Space - O(n)
return A
class Solution(object):
def heightChecker(self, heights):
"""
:type heights: List[int] # python_1001_to_2000/1054_Distant_Barcodes.py - m
:rtype: int
""" _author_ = 'jake'
return sum(h1 != h2 for h1, h2 in zip(heights, sorted(heights))) _project_ = 'leetcode'
# https://leetcode.com/problems/distant-barcodes/
# In a warehouse, there is a row of barcodes, where the i-th barcode is barcodes[i].
# python_1001_to_2000/1052_Grumpy_Bookstore_Owner.py - m # Rearrange the barcodes so that no two adjacent barcodes are equal.
# You may return any answer, and it is guaranteed an answer exists.
_author_ = 'jake'
_project_ = 'leetcode' # Count the number of each barcode then sort the counts from most to least frequent.
# Iterate along the sorted barcodes, updating the result for each barcode then moving 2 places to fill the even indices.
# https://leetcode.com/problems/grumpy-bookstore-owner/ # When we reach the end of the result, move back to index 1 to fill the odd indices.
# Today, the bookstore owner has a store open for customers.length minutes. # Time - O(n log n)
# Every minute, some number of customers (customers[i]) enter the store, and all those customers # Space - O(n)
# leave after the end of that minute.
# On some minutes, the bookstore owner is grumpy. from collections import Counter
# If the bookstore owner is grumpy on the i-th minute, grumpy[i] = 1, otherwise grumpy[i] = 0.
# When the bookstore owner is grumpy, the customers of that minute are not satisfied, otherwise they are satisfied. class Solution(object):
# The bookstore owner knows a secret technique to keep themselves not grumpy for X minutes, but can only use it once. def rearrangeBarcodes(self, barcodes):
# Return the maximum number of customers that can be satisfied throughout the day. """
:type barcodes: List[int]
# Count the base case number of satisfied customers if the special technique is not used. :rtype: List[int]
# Then for a sliding window of length X minutes, count the additional number of customers that can be satisfied. """
# Time - O(n) n = len(barcodes)
# Space - O(1) freq = Counter(barcodes)
freq = sorted([(count, num) for num, count in freq.items()], reverse=True)
class Solution(object):
def maxSatisfied(self, customers, grumpy, X): result = [0] * n
""" i = 0 # next index of result to be updated
:type customers: List[int]
:type grumpy: List[int] for count, num in freq: # from most to least frequent
:type X: int for _ in range(count): # use all occurrences of num
:rtype: int result[i] = num
""" i += 2
base_satisfied = 0 if i >= n:
window, best_window = 0, 0 i = 1
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1058_Minimize_Rounding_Error_to_Meet_Target.py - m
# https://leetcode.com/problems/confusing-number/
# Given a number N, return true if and only if it is a confusing number, which satisfies the following condition: _author_ = 'jake'
# We can rotate digits by 180 degrees to form new digits. _project_ = 'leetcode'
# When 0, 1, 6, 8, 9 are rotated 180 degrees, they become 0, 1, 9, 8, 6 respectively.
# When 2, 3, 4, 5 and 7 are rotated 180 degrees, they become invalid. # https://leetcode.com/problems/minimize-rounding-error-to-meet-target/
# A confusing number is a number that when rotated 180 degrees becomes a different number with each digit valid. # Given an array of prices [p1,p2...,pn] and a target, round each price pi to Roundi(pi) so that the rounded array
# [Round1(p1),Round2(p2)...,Roundn(pn)] sums to the given target.
# Iterate along the digits of S in reverse. # Each operation Roundi(pi) could be either Floor(pi) or Ceil(pi).
# If any digit cannot be rotated, return False. Else add the rotated digit to the result. # Return the string "-1" if the rounded array is impossible to sum to target.
# Finally check if the result is different from the original number. # Otherwise, return the smallest rounding error, which is defined as Σ |Roundi(pi) - (pi)| for i from 1 to n,
# Time - O(n) # as a string with three places after the decimal.
# Space - O(n)
# For each price, add the floor to the base and record the remaining decimal digits.
class Solution(object): # If the target is below the base or above the total ceiling, return "-1".
def confusingNumber(self, N): # Sort the remainders then iterate along, rounding up the largest remainders until the target is reached.
""" # Round down all reaminders not rounded up and add to result.
:type N: int # Time - O(n log n)
:rtype: bool # Space - O(n)
"""
S = str(N) class Solution(object):
rotation = {"0": "0", "1": "1", "6": "9", "8": "8", "9": "6"} def minimizeError(self, prices, target):
result = [] """
:type prices: List[str]
for c in S[::-1]: # iterate in reverse :type target: int
if c not in rotation: :rtype: str
return False """
result.append(rotation[c]) base = 0 # sum of price floors
remainders = [] # decimal places, ints between 0 and 1000
return "".join(result) != S
for price in prices:
integer, remainder = price.split(".")
base += int(integer)
# python_1001_to_2000/1057_Campus_Bikes.py - m if remainder != "000":
remainders.append(int(remainder))
_author_ = 'jake'
_project_ = 'leetcode' if target < base or target > base + len(remainders):
return "-1"
prev = num
remainders.sort(reverse=True)
result = 0
i = 0
# python_1001_to_2000/1061_Lexicographically_Smallest_Equivalent_String.py - m
while i < len(remainders) and base + i < target:
result += 1000 - remainders[i] # round up largest remainders first _author_ = 'jake'
i += 1 _project_ = 'leetcode'
# python_1001_to_2000/1060_Missing_Element_in_Sorted_Array.py - m
# python_1001_to_2000/1062_Longest_Repeating_Substring.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/missing-element-in-sorted-array/
# Given a sorted array A of unique numbers, find the K-th missing number starting from the leftmost number of the array. # https://leetcode.com/problems/longest-repeating-substring/
# Given a string S, find out the length of the longest repeating substring(s).
# Iterate along nums, subtracting the number of missing elements from k until no more missing elements are required. # Return 0 if no repeating substring exists.
# Time - O(n)
# Space - O(1) # Binary search the range of possible lengths of repeated substring.
# Helper function checks all substrings of a given length.
class Solution(object): # Alternatively, for a pair of strings of the same length we can check if there is a repeated substring starting and
def missingElement(self, nums, k): # ending at the same indices in O(n) time. Compare S against itself with an offset for all possible offsets.
""" # Time - O(n**2 log n)
:type nums: List[int] # Space - O(n**2)
:type k: int
:rtype: int class Solution(object):
""" def longestRepeatingSubstring(self, S):
nums.append(float("inf")) # add infinity so we check after the final element of nums """
prev = nums[0] :type S: str
:rtype: int
for num in nums[1:]: """
missing = num - prev - 1 # count of missing elements between num and prec def helper(guess):
if k - missing <= 0: # missing element is between num and prev seen = set()
return prev + k for i in range(n - guess + 1):
k -= missing substring = S[i:i + guess]
if substring in seen: :rtype: int
return True """
seen.add(substring) left, right = 0, len(A) - 1
return False
while left <= right:
n = len(S) mid = (left + right) // 2
low, high = 0, n if A[mid] == mid:
return mid
while low <= high: # until low > high if A[mid] > mid:
mid = (low + high) // 2 right = mid - 1
if helper(mid): else:
low = mid + 1 left = mid + 1
else:
high = mid - 1 return -1
return low - 1
while stack and stack[-1] > num: # remove elements from stack # Maintain a heap of the smallest total distance for each number of workers and some set of used bikes.
stack.pop() # Workers are allocated to bikes in their order in the initial list.
stack.append(num) # The set of used bikes ir represented by an integer with a set bit indicating bikes that are used.
# Until all workers have a bike, pop the smallest distance and allocate all available (unused) bikes to the next worker.
result += len(stack) # Do not repeat cases where the same bikes are allocated.
# Time - O(X log X) where X = b! / (b - w)!.
return result # Space - O(b! / (b - w)!), the number of ways to choose w from b.
import heapq
class Solution(object):
def digitsCount(self, d, low, high): # python_1001_to_2000/1073_Adding_Two_Negabinary_Numbers.py - m
"""
:type d: int _author_ = 'jake'
:type low: int _project_ = 'leetcode'
:type high: int
:rtype: int # https://leetcode.com/problems/adding-two-negabinary-numbers/
""" # Given two numbers arr1 and arr2 in base -2, return the result of adding them together.
def count_digits(n): # return count of d in integers less than n # Each number is given in array format:
if n == 0 or (d == 0 and n <= 10): # as an array of 0s and 1s, from most significant bit to least significant bit.
return 0 # For example, arr = [1,1,0,1] represents the number (-2)^3 + (-2)^2 + (-2)^0 = -3.
# A number arr in array format is also guaranteed to have no leading zeros: either arr == [0] or arr[0] == 1.
result = 0 # Return the result of adding arr1 and arr2 in the same format: as an array of 0s and 1s with no leading zeros.
prefix, units = divmod(n, 10) # assume n = ppppu for prefix pppp and units u
if units > d: # count the d in ppppd # Iterate over arrays from least to most significant digits.
result += 1 # Add digits from both arrays to carry.
if prefix > 0: # count of d in prefix, followed by any units < d # If sum of digits and carry is 1 or 0, append that to result.
result += str(prefix).count(str(d)) * units # If sum of digits and carry is 2, append 0, increment carry and next carry since 2**(n+2) - 2**(n+1) = 2*2**n.
result += prefix if d else prefix - 1 # any int < prefix, followed by d (exclude 0 then 0) # If sum of digits and carry is 3, append 1, increment carry and next carry since 2**(n+2) - 2**(n+1) = 2*2**n.
result += count_digits(prefix) * 10 # count of any int < prefix, followed by any digit # If next carry is 1 and carry is 2 then these are netted to zero.
return result
# Time - O(max(m, n))
return count_digits(high + 1) - count_digits(low) # Space - O(max(m, n))
class Solution(object):
def addNegabinary(self, arr1, arr2):
# python_1001_to_2000/1071_Greatest_Common_Divisor_of_Strings.py """
:type arr1: List[int]
_author_ = 'jake' :type arr2: List[int]
_project_ = 'leetcode' :rtype: List[int]
"""
# https://leetcode.com/problems/greatest-common-divisor-of-strings/ carry, next_carry = 0, 0 # carry over to the following 2 digits
# For strings S and T, we say "T divides S" if and only if S = T + ... + T (T concatenated with itself 1 or more times) result = []
# Return the largest string X such that X divides str1 and X divides str2.
while arr1 or arr2 or carry or next_carry:
# Find the GCD of the lengths of the strings. digit = carry
# Check whether both strings consist of repeated prefix of GCD length. if arr1:
# Time - O(m + n) digit += arr1.pop()
# Space - O(1) if arr2:
digit += arr2.pop()
class Solution(object):
def gcdOfStrings(self, str1, str2): carry, next_carry = next_carry, 0
""" result.append(digit % 2)
:type str1: str if digit == 2 or digit == 3:
:type str2: str carry += 1
:rtype: str if digit >= 2:
""" if carry >= 2:
a, b = len(str1), len(str2) carry -= 2
if a < b: else:
a, b = b, a next_carry += 1
# python_1001_to_2000/1074_Number_of_Submatrices_That_Sum_to_Target.py - h
return result # Move down the tree, subtracting each node's value form the limit.
# If a leaf node has a value less than the limit then it is insufficient so remove it.
# Recurse to left and right subtrees if they exist.
# If either subtree is not removed then there is a path through a node greater than or equal to the limit,
# python_1001_to_2000/1078_Occurrences_After_Bigram.py # so retain the node, else remove it.
# Time - O(n)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/occurrences-after-bigram/ def sufficientSubset(self, root, limit):
# Given words first and second, consider occurrences in some text of the form "first second third", """
# where second comes immediately after first, and third comes immediately after second. :type root: TreeNode
# For each such occurrence, add "third" to the answer, and return the answer. :type limit: int
:rtype: TreeNode
# Split text by space and check for consecutive appearances of first and second. """
# Time - O(n) if root.left is None and root.right is None:
# Space - O(n) return None if root.val < limit else root
for i, c in enumerate(text): # Create a list of lists where each inner list is a sorted group of words.
if c in stack: # Then depth-first search. For each group, add all words to the current partial result and recurse to the next group.
continue # Time - O(g**2 * n**g) - as space complexity below except each result is built by adding individual chars.
while stack and stack[-1] > c and last_index[stack[-1]] > i: # Space - O(g * n**g) for g groups of length n since each result is of length g and there are n possibilities for
stack.pop() # each char.
stack.append(c)
class Solution(object):
return "".join(stack) def expand(self, S):
"""
:type S: str
:rtype: List[str]
# python_1001_to_2000/1085_Sum_of_Digits_in_the_Minimum_Number.py """
group_start = 0
_author_ = 'jake' groups = []
_project_ = 'leetcode'
while group_start < len(S):
# https://leetcode.com/problems/sum-of-digits-in-the-minimum-number/ while S[group_start] in "}{": # ignore previous closing or current opening braces
# Given an array A of positive integers, let S be the sum of the digits of the minimal element of A. group_start += 1
# Return 0 if S is odd, otherwise return 1. group_end = group_start
while group_end < len(S) and S[group_end] not in "{}": # find end of current group
# Find the minimum and sum the digits. group_end += 1
# Time - O(n + log m) where n is the length of A and m is the minimum value. groups.append(sorted(S[group_start:group_end].split(","))) # sort words in group
# Space - O(1) group_start = group_end + 1
# python_1001_to_2000/1088_Confusing_Number_II.py - h
# For each id, maintain a heap of the top 5 scores. # Helper function take a number and its rotation and updates count for number and all greater confusing numbers <= N.
# Add each result to its heap, popping off a value if the heap has more 3 elements. # Update result if confusing, then recurse for all 5 valid digits appended to number.
# Then take the average of each heap and sort by id. # Time - O(5 ** log n), where log is base 10
# Time - O(n log n) since heap is of fixed size. # Space - O(5 ** log n)
# Space - O(n)
class Solution(object):
from collections import defaultdict def confusingNumberII(self, N):
import heapq """
:type N: int
class Solution(object): :rtype: int
def highFive(self, items): """
""" valid = [0, 1, 6, 8, 9]
:type items: List[List[int]] rotations = {0: 0, 1: 1, 6: 9, 8: 8, 9: 6}
:rtype: List[List[int]]
""" self.count = 0
TOP_SCORES = 5
heaps = defaultdict(list) def helper(num, rotation):
length = len(str(num))
for id, score in items: if num != rotation:
if len(heaps[id]) < TOP_SCORES: self.count += 1
heapq.heappush(heaps[id], score) for i in valid:
else: if num * 10 + i > N:
heapq.heappushpop(heaps[id], score) return
helper(num * 10 + i, rotations[i] * 10 ** length + rotation)
result = [[id, sum(scores) // 5] for id, scores in heaps.items()]
return sorted(result) for num in valid[1:]: # do not start with zero
helper(num, rotations[num])
return self.count
# python_1001_to_2000/1087_Brace_Expansion.py - m
_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1089_Duplicate_Zeros.py
# Iterate along arr, updating the new length after duplicating zeros. # Bidirectional breadth-first search.
# Find the index i in arr when the array with duplicates is full. # Maintain frontiers of valid (within grid), empty cells.
# Then iterate backwards from i, moving each element to its new index and duplicating zeros. # Expand the smaller frontier by visiting all neighbours.
# Time - O(n) # Time - O(mn)
# Space - O(1) # Space - O(mn)
i += 1
while str2[j] != c: import heapq
result.append(str2[j])
j += 1 class Solution(object):
result.append(c) # add the lcs char def carPooling(self, trips, capacity):
i += 1 """
j += 1 :type trips: List[List[int]]
:type capacity: int
return "".join(result) + str1[i:] + str2[j:] # add remainders of str and str2 :rtype: bool
"""
trips.sort(key=lambda x: x[1])
dropoff = [] # heap of (location, nb passengers)
# python_1001_to_2000/1093_Statistics_from_a_Large_Sample.py - m
for pickup, start, end in trips:
_author_ = 'jake' while dropoff and dropoff[0][0] <= start:
_project_ = 'leetcode' _, dropped = heapq.heappop(dropoff)
capacity += dropped
# https://leetcode.com/problems/statistics-from-a-large-sample/
# We sampled integers between 0 and 255, and stored the results in an array count: capacity -= pickup
# count[k] is the number of integers we sampled equal to k. if capacity < 0:
# Return the minimum, maximum, mean, median, and mode of the sample respectively, as an array of floating point numbers. return False
# The mode is guaranteed to be unique. heapq.heappush(dropoff, (end, pickup))
# Recall that the median of a sample is:
# The middle element, if the elements of the sample were sorted and the number of elements is odd; return True
# The average of the middle two elements, if the elements of the sample were sorted and the number of elements is even.
while len(stack) > 1 and isinstance(stack[-1], set) and isinstance(stack[-2], set): # python_1001_to_2000/1101_The_Earliest_Moment_When_Everyone_Become_Friends.py - m
second = stack.pop() # pop sets off in reverse order
first = stack.pop() _author_ = 'jake'
stack.append(set(w1 + w2 for w1 in first for w2 in second)) _project_ = 'leetcode'
# python_1001_to_2000/1103_Distribute_Candies_to_People.py # python_1001_to_2000/1105_Filling_Bookcase_Shelves.py - m
# https://leetcode.com/problems/distribute-candies-to-people/ # https://leetcode.com/problems/filling-bookcase-shelves/
# We distribute some number of candies, to a row of n = num_people people in the following way: # We have a sequence of books: the i-th book has thickness books[i][0] and height books[i][1].
# We then give 1 candy to the first person, 2 candies to the second person, # We want to place these books in order onto bookcase shelves that have total width shelf_width.
# and so on until we give n candies to the last person. # We choose some of the books to place on this shelf (such that the sum of their thickness is <= shelf_width),
# Then, we go back to the start of the row, giving n + 1 candies to the first person, # then build another level of shelf of the bookcase so that the total height of the bookcase has increased by
# n + 2 candies to the second person, and so on until we give 2 * n candies to the last person. # the maximum height of the books we just put down.
# This process repeats (with us giving one more candy each time, and moving to the start of the row # We repeat this process until there are no more books to place.
# after we reach the end) until we run out of candies. # Note again that at each step of the above process,
# The last person will receive all of our remaining candies (not necessarily one more than the previous gift). # the order of the books we place is the same order as the given sequence of books.
# Return an array (of length num_people and sum candies) that represents the final distribution of candies. # For example, if we have an ordered list of 5 books, we might place the first and second book onto the first shelf,
# the third book on the second shelf, and the fourth and fifth book on the last shelf.
# The total number of candies distributed for n people = n * (n + 1) // 2. # Return the minimum possible height that the total bookshelf can be after placing shelves in this manner.
# Invert this to find the number of people served given the candies (ignoring cycle back to beginning).
# The first person gets 1 + (1 + num_people) + (1 + 2 * num_people) + .... where the sum of the num_people # Dynamic programming. Find the result for all books up to and including each book.
# series is a base amount which is the same for every person. # For each end book, make a new shelf and repeatedly add books to that shelf until it has no remaining width.
# After adding candies for the completed cycles, add candies until one remain. # While the next book to be moved fits on the shelf, decrease the remaining width and update the height on the shelf.
# Time - O(n) # Update the total height result with the latest shelf + result up to the last book not moved.
# Space - O(n)
# Time - O(n**2), since we may need to look at all previous books for each book.
class Solution(object): # Space - O(n)
def distributeCandies(self, candies, num_people):
""" class Solution(object):
:type candies: int def minHeightShelves(self, books, shelf_width):
:type num_people: int """
:rtype: List[int] :type books: List[List[int]]
:type shelf_width: int """
:rtype: int return address.replace(".", "[.]")
"""
results = [0] # no height for no books
# String replace.
# Time - O(n) # python_1001_to_2000/1111_Maximum_Nesting_Depth_of_Two_Valid_Parentheses_Strings.py - m
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def defangIPaddr(self, address):
""" # https://leetcode.com/problems/maximum-nesting-depth-of-two-valid-parentheses-strings/
:type address: str # A string is a valid parentheses string (denoted VPS) if and only if it consists of "(" and ")" characters only, and:
:rtype: str # It is the empty string, or
# It can be written as AB (A concatenated with B), where A and B are VPS's, or :rtype: str
# It can be written as (A), where A is a VPS. """
# We can similarly define the nesting depth depth(S) of any VPS S as follows: vowels = set("aeiou")
# depth("") = 0 return "".join(c for c in S if c not in vowels)
# depth(A + B) = max(depth(A), depth(B)), where A and B are VPS's
# depth("(" + A + ")") = 1 + depth(A), where A is a VPS.
# For example, "", "()()", and "()(()())" are VPS's (with nesting depths 0, 1, and 2),
# and ")(" and "(()" are not VPS's. # python_1001_to_2000/1120_Maximum_Average_Subtree.py - m
# Given a VPS seq, split it into two disjoint subsequences A and B,
# such that A and B are VPS's (and A.length + B.length = seq.length). _author_ = 'jake'
# Now choose any such A and B such that max(depth(A), depth(B)) is the minimum possible value. _project_ = 'leetcode'
# Return an answer array (of length seq.length) that encodes such a choice of A and B:
# answer[i] = 0 if seq[i] is part of A, else answer[i] = 1. # https://leetcode.com/problems/maximum-average-subtree/
# Note that even though multiple answers may exist, you may return any of them. # Share
# Given the root of a binary tree, find the maximum average value of any subtree of that tree.
# Track the nesting depth. # A subtree of a tree is any node of that tree plus all its descendants.
# Iterate over seq. A closing bracket causes the depth to decrease, an opening bracket increases depth. # The average value of a tree is the sum of its values, divided by the number of nodes.
# When depth is even, the bracket is part of sunbsequence A (result is 0), else part of B (result is 1).
# Update result after processing closing brackets and before processing opening brackets. # Helper function returns the count of nodes and their sum for subtree.
# Time - O(n) # Recurse left and right, updating the result from the subtree results.
# Space - O(1) # Time - O(n)
# Space - O(n)
class Solution(object):
def maxDepthAfterSplit(self, seq): class Solution(object):
""" def maximumAverageSubtree(self, root):
:type seq: str """
:rtype: List[int] :type root: TreeNode
""" :rtype: float
result = [] """
depth = 0 self.result = 0
helper(root)
# python_1001_to_2000/1118_Number_of_Days_in_a_Month.py return self.result
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1121_Divide_Array_Into_Increasing_Sequences.py - h
# https://leetcode.com/problems/number-of-days-in-a-month/
# Given a year Y and a month M, return how many days there are in that month. _author_ = 'jake'
_project_ = 'leetcode'
# If February, leap years are divisible by 4 except if divisible by 100 but not 400.
# Else if not February, return 30 or 31 depending on the month. # https://leetcode.com/problems/divide-array-into-increasing-sequences/
# Time - O(1) # Given a non-decreasing array of positive integers nums and an integer K,
# Space - O(1) # find out if this array can be divided into one or more disjoint increasing subsequences of length at least K.
# python_1001_to_2000/1122_Relative_Sort_Array.py
# Create a set of vowels and return the join of all chars of S that are not in the set. # Count each element of arr1.
# Time - O(n) # Iterate over arr2. If an element is in arr1 then add all instances from r1 to the result and delete from the count.
# Space - O(n) # Sort all remaining elements from arr1 that not in arr2 and all their instances to the result in sorted order.
# Time - O(m)
class Solution(object): # Space - O(m log m + n)
def removeVowels(self, S):
""" from collections import Counter
:type S: str
class Solution(object):
def relativeSortArray(self, arr1, arr2): result = 0
""" net_tiring = 0 # balance of tiring - non-tiring days
:type arr1: List[int] first_net_tiring = {} # map the first occurrence of each net_tiring to its index in hours
:type arr2: List[int]
:rtype: List[int] for i, day in enumerate(hours):
""" net_tiring += 1 if day > TIRING else -1
arr1_counts = Counter(arr1) if net_tiring > 0: # hours[:i + 1] is well-performing, must be best result
result = [] result = i + 1
for val in arr2: if net_tiring - 1 in first_net_tiring: # removing some prefix of hours leaves a net_tiring of 1
if val in arr1_counts: result = max(result, i - first_net_tiring[net_tiring - 1])
result += [val] * arr1_counts[val]
del arr1_counts[val] if net_tiring not in first_net_tiring:
first_net_tiring[net_tiring] = i
for val in sorted(arr1_counts.keys()):
result += [val] * arr1_counts[val] return result
return result
# python_1001_to_2000/1125_Smallest_Sufficient_Team.py - h
# Helper function returns lca of deepest leaves and deepest leaf depth. # Represent the skills of each person as an int, with a bit set for each required skill.
# Recurse to left and right subtrees. # For each required skill, if we already have that skill then move to the next skill.
# If depths are equal, current node is the lowest common ancestor. # Else for each person who has that skill, add their skill to the current skills and recurse for the next skill.
# Else return the lca with the deepest depth and increment the depth. # When returning form recursion, reset the team and current skills.
# Time - O(n) # Time - O(m ** n) for m people and n required skills.
# Space - O(n) # Space - O(m ** n)
# Iterate over hours, updating the net balance of tiring days. helper(0)
# If the net balance is positive, the array so far is the longest well-performing interval. return self.smallest_team
# If there is a prefix array such that an intermediate array has a net balance of 1 tiring day, then update the result
# if this is an improvement.
# Update the mapping from index to the first occurrence of a net tiring balance.
# Time - O(n) # python_1001_to_2000/1128_Number_of_Equivalent_Domino_Pairs.py
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def longestWPI(self, hours):
""" # https://leetcode.com/problems/number-of-equivalent-domino-pairs/
:type hours: List[int] # Given a list of dominoes, dominoes[i] = [a, b] is equivalent to dominoes[j] = [c, d] if and only if
:rtype: int # either (a==c and b==d), or (a==d and b==c) - that is, one domino can be rotated to be equal to another domino.
""" # Return the number of pairs (i, j) for which 0 <= i < j < dominoes.length,
TIRING = 8 # and dominoes[i] is equivalent to dominoes[j].
_project_ = 'leetcode'
# Dictionary counts previously seen dominoes.
# Iterate over dominoes, rotating each so the greatest number is first. # https://leetcode.com/problems/minimum-cost-tree-from-leaf-values/
# Convert to tuple so they can be added to dictionary. # Given an array arr of positive integers, consider all binary trees such that:
# Add to the result all pairs formed with equivalent dominoes. # Each node has either 0 or 2 children;
# Time - O(n) # The values of arr correspond to the values of each leaf in an in-order traversal of the tree.
# Space - O(1) # Recall that a node is a leaf if and only if it has 0 children.
# The value of each non-leaf node is equal to the product of the largest leaf value in its left and
from collections import defaultdict # right subtree respectively.
# Among all possible binary trees considered, return the smallest possible sum of the values of each non-leaf node.
class Solution(object): # It is guaranteed this sum fits into a 32-bit integer.
def numEquivDominoPairs(self, dominoes):
""" # Maintain a stack of leaves in descending order. Iterate over the list of leaves.
:type dominoes: List[List[int]] # While the top of the stack is less than or equal to a leaf, the top of the stack is the smallest leaf.
:rtype: int # Pop off the top of the stack and add to the result the top of stack multiplied by its smallest neighbour,
""" # (combining the smallest with another leaf). The smallest is no longer used. Add the current leaf to the stack.
seen = defaultdict(int) # map canonical dominoe to its count # After iterting over leaves, add to the result the product of each remaining pair.
result = 0 # Time - O(n)
# Space - O(n)
for domino in dominoes:
if domino[0] > domino[1]: # put greatest first class Solution(object):
domino = domino[::-1] def mctFromLeafValues(self, arr):
"""
domino_tuple = tuple(domino) :type arr: List[int]
result += seen[domino_tuple] # add pairs with all equivalent :rtype: int
seen[domino_tuple] += 1 """
result = 0
return result stack = [float('inf')] # nodes by descending value
for a in arr:
while stack[-1] <= a:
# python_1001_to_2000/1129_Shortest_Path_with_Alternating_Colors.py - m smallest = stack.pop()
result += smallest * min(stack[-1], a)
_author_ = 'jake' stack.append(a)
_project_ = 'leetcode'
while len(stack) > 2: # until root and sentinel
# https://leetcode.com/problems/shortest-path-with-alternating-colors/ result += stack.pop() * stack[-1]
# Consider a directed graph, with nodes labelled 0, 1, ..., n-1.
# In this graph, each edge is either red or blue, and there could be self-edges or parallel edges. return result
# Each [i, j] in red_edges denotes a red directed edge from node i to node j.
# Similarly, each [i, j] in blue_edges denotes a blue directed edge from node i to node j.
# Return an array answer of length n, where each answer[X] is the length of the shortest path from node 0 to node X
# such that the edge colors alternate along the path (or -1 if such a path doesn't exist). # python_1001_to_2000/1131_Maximum_of_Absolute_Value_Expression.py - m
return result # Count the frequency of each number and return the maximum of numbers with a count of 1.
# Time - O(n)
# Space - O(n)
_author_ = 'jake'
# python_1001_to_2000/1134_Armstrong_Number.py _project_ = 'leetcode'
sequence += 1
else:
sequence = 0
# python_1001_to_2000/1138_Alphabet_Board_Path.py - m if best >= sequence : # insufficient sequence to make a bigger square
continue
_author_ = 'jake'
_project_ = 'leetcode' for side in range(min(sequence, rows - row), best, -1): # check decreasing side from largest possible
if not all(grid[r][col] and grid[r][col - side + 1] for r in range(row + 1, row + side)):
# https://leetcode.com/problems/alphabet-board-path/ continue # left and right edges must be populated
# On an alphabet board, we start at position (0, 0), corresponding to character board[0][0]. if not all(grid[row + side - 1][col - side + 1:col + 1]):
# Here, board = ["abcde", continue # bottom edge must be populated
# "fghij", best = side
# "klmno", break # no need to check smaller sides
# "pqrst",
# "uvwxy", return best * best
# "z"].
# We may make the following moves:
# 'U' moves our position up one row, if the position exists on the board;
# 'D' moves our position down one row, if the position exists on the board;
# 'L' moves our position left one column, if the position exists on the board; # python_1001_to_2000/1140_Stone_Game_II.py - m
# 'R' moves our position right one column, if the position exists on the board;
# '!' adds the character board[r][c] at our current position (r, c) to the answer. _author_ = 'jake'
# (Here, the only positions that exist on the board are positions with letters on them.) _project_ = 'leetcode'
# Return a sequence of moves that makes our answer equal to target in the minimum number of moves.
# You may return any path that does so. # https://leetcode.com/problems/stone-game-ii/
# Alex and Lee continue their games with piles of stones.
# Track the current location and for each char, find the target location. # There are a number of piles arranged in a row, and each pile has a positive integer number of stones piles[i].
# Move left and up before right and down so we do not visit any other columns on the last row. # The objective of the game is to end with the most stones.
# Time - O(n) # Alex and Lee take turns, with Alex starting first. Initially, M = 1.
# Space - O(n) # On each player's turn, that player can take all the stones in the first X remaining piles,
# where 1 <= X <= 2M. Then, we set M = max(M, X).
class Solution(object): # The game continues until all the stones have been taken.
def alphabetBoardPath(self, target): # Assuming Alex and Lee play optimally, return the maximum number of stones Alex can get.
"""
:type target: str # Convert the array so piles[i] is the sum of all remaining piles.
:rtype: str # Recursive helper function calculates the result from pile i for a given value of M.
""" # Return the best result for each value of x of taking the remaining piles minus the best case for the next player.
def location(char): # return (row, col) of cher on the board. # Memoize to avoid repetition.
val = ord(char) - ord("a") # Time - O(n**3) since there are O(n**2) states, each taking O(n) to compute.
return divmod(val, 5) # Space - O(n**2)
_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1146_Snapshot_Array.py - m
class Solution(object):
def longestDecomposition(self, text):
""" # python_1001_to_2000/1152_Analyze_User_Website_Visit_Pattern.py - m
:type text: str
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
n = len(text)
start_prefix = 0 # https://leetcode.com/problems/analyze-user-website-visit-pattern/
result = 0 # We are given some website visits: the user with name username[i] visited the website website[i] at time timestamp[i].
# A 3-sequence is a list of websites of length 3 sorted in ascending order by the time of their visits.
while start_prefix <= (n - 1) // 2: # until half of text # The websites in a 3-sequence are not necessarily distinct.
for length in range(1, ((n - 2 * start_prefix) // 2) + 1): # Find the 3-sequence visited by the largest number of users. If there is more than one solution,
prefix = text[start_prefix:start_prefix + length] # return the lexicographically smallest such 3-sequence.
suffix = text[n - start_prefix - length:n - start_prefix]
if prefix == suffix: # Make a time-ordered list of sites for each user.
result += 2 # prefix and suffix are removed # For each list, find all patterns of 3 ordered sites.
start_prefix += length # start of next prefix # Map each pattern to all users with that pattern.
break # Find the pattern with the most users.
else: # middle of text, not a palindrome # Time - O(n**3) for n visits.
result += 1 # Space - O(n**3)
break
from collections import defaultdict
return result
class Solution(object):
def mostVisitedPattern(self, username, timestamp, website):
"""
# python_1001_to_2000/1150_Check_If_a_Number_Is_Majority_Element_in_a_Sorted_Array.py :type username: List[str]
:type timestamp: List[int]
_author_ = 'jake' :type website: List[str]
_project_ = 'leetcode' :rtype: List[str]
"""
# https://leetcode.com/problems/check-if-a-number-is-majority-element-in-a-sorted-array/ user_sites = defaultdict(list) # user mapped to list of sites in time order.
# Given an array nums sorted in non-decreasing order, and a number target, for _, user, site in sorted(zip(timestamp, username, website)):
# return True if and only if target is a majority element. user_sites[user].append(site)
# A majority element is an element that appears more than N/2 times in an array of length N.
pattern_to_count = defaultdict(set) # map 3-sequence to users with that 3-sequence
# Use binary search to find the first instance of target in nums. for user, sites in user_sites.items():
# If target is not in nums, return False. n = len(sites)
# Check if for i in range(n - 2):
# Time - O(log n) for j in range(i + 1, n - 1):
# Space - O(1) for k in range(j + 1, n):
pattern_to_count[(sites[i], sites[j], sites[k])].add(user)
import bisect
max_count = len(max(pattern_to_count.values(), key=len)) # count of mos popular 3-sequence
class Solution(object): return min(key for key, value in pattern_to_count.items() if len(value) == max_count)
def isMajorityElement(self, nums, target):
"""
:type nums: List[int]
:type target: int # python_1001_to_2000/1153_String_Transforms_Into_Another_String.py - h
:rtype: bool
""" _author_ = 'jake'
n = len(nums) _project_ = 'leetcode'
i = bisect.bisect_left(nums, target)
if i == n or nums[i] != target: # https://leetcode.com/problems/string-transforms-into-another-string/
return False # Given two strings str1 and str2 of the same length,
# determine whether you can transform str1 into str2 by doing zero or more conversions.
return nums[(i + n // 2) % n] == target # In one conversion you can convert all occurrences of one character in str1 to any other lowercase English character.
# Return true if and only if you can transform str1 into str2.
# If the stings are not identical and str2 uses all 26 possible characters, then changing any character of str1
# python_1001_to_2000/1151_Minimum_Swaps_to_Group_All_1's_Together.py - m # would make it the same as some other character in str2, which means we cannot perform the transformation.
# Else find all indices in str1 of each char. Find the chars in str2 at the indices of each char in str1.
_author_ = 'jake' # If a char of str1 maps to more than one char of str2,
_project_ = 'leetcode' # then we cannot transform it into those 2 or more different chars.
# Time - O(n)
# https://leetcode.com/problems/minimum-swaps-to-group-all-1s-together/ # Space - O(n)
# Given a binary array data,
# return the minimum number of swaps required to group all 1’s present in the array together in any place in the array. from collections import defaultdict
class Solution(object): if i != 0 and substrings[i - 1][1] == start - 2: # gap of 1 char to previous substring
def dayOfYear(self, date): prev_length = substrings[i - 1][1] - substrings[i - 1][0] + 1
""" # move a char from another substring to fill the gap, else move from the end of one substring
:type date: str result = max(result, length + prev_length + int(len(substrings) >= 3))
:rtype: int
""" return result
cumulative_days = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
if month >= 3 and year % 4 == 0 and year != 1900: # 1900 was not a leap year _author_ = 'jake'
result += 1 _project_ = 'leetcode'
return result
# https://leetcode.com/problems/online-majority-element-in-subarray/
# Implementing the class MajorityChecker, which has the following API:
# MajorityChecker(int[] arr) constructs an instance of MajorityChecker with the given array arr;
# python_1001_to_2000/1155_Number_of_Dice_Rolls_With_Target_Sum.py - m # int query(int left, int right, int threshold) has arguments such that:
# 0 <= left <= right < arr.length representing a subarray of arr;
_author_ = 'jake' # 2 * threshold > right - left + 1, ie. the threshold is always a strict majority of the length of the subarray
_project_ = 'leetcode' # Each query(...) returns the element in arr[left], arr[left+1], ..., arr[right]
# that occurs at least threshold times, or -1 if no such element exists.
# https://leetcode.com/problems/number-of-dice-rolls-with-target-sum/
# You have d dice, and each die has f faces numbered 1, 2, ..., f. # Create a map from each val of arr to an ordered list of indices with that val.
# Return the number of possible ways (out of f**d total ways) modulo 10^9 + 7 # Create a list of unique vals, in descending order of number of occurrences in arr.
# to roll the dice so the sum of the face up numbers equals target. # To query, start with the the num with the most indices and binary search for the left and right indices.
# Repeat with the next num, until a result or the num has fewer than threshold indices in arr.
# Dynamic programming. # Time - O(n log n) for __init__ and O(n log n) for query.
# For each dice roll, each total can be achieved by adding any score s from 1 to f (inclusive) # Space - O(n)
# to total - s for the previous dice roll.
# Time - O(mnk) for target of m, n dice with k sides. from collections import defaultdict
# Space - O(mn) for target of m and n dice. import bisect
# For each char, make a list of the start and end indices of substrings containing only that char.
# For each list of substrings, we can update the result with:
# - the substring length (no swap) if there are no other substrings with this char # python_1001_to_2000/1160_Find_Words_That_Can_Be_Formed_by_Characters.py
# - the length + 1, if there is another substring
# - the sum of adjacent substrings, if the gap between them is one char _author_ = 'jake'
# - the sum of adjacent substrings + 1, if the gap between them is one char and there is at least one other substring _project_ = 'leetcode'
# Time - O(n)
# Space - O(n) # https://leetcode.com/problems/find-words-that-can-be-formed-by-characters/
# You are given an array of strings words and a string chars. def maxDistance(self, grid):
# A string is good if it can be formed by characters from chars (each character can only be used once). """
# Return the sum of lengths of all good strings in words. :type grid: List[List[int]]
:rtype: int
# Count the chars. """
# For each char of each word, if there are more instances of that char in the word than in chars, rows, cols = len(grid), len(grid[0])
# we cannot make the word. visited = 0
# Time - O(m + n), length of chars + lengths of all words frontier = {(r, c) for r in range(rows) for c in range(cols) if grid[r][c] == 1}
# Space - O(m)
visited += len(frontier)
from collections import Counter if not frontier or visited == rows * cols: # all water or all land
return -1
class Solution(object):
def countCharacters(self, words, chars): neighbours = [(1, 0), (-1, 0), (0, 1), (0, -1)]
""" distance = 0
:type words: List[str]
:type chars: str while visited < rows * cols: # until all grid visited
:rtype: int new_frontier = set()
"""
chars_count = Counter(chars) for r, c in frontier:
result = 0 for dr, dc in neighbours:
if r + dr < 0 or r + dr >= rows:
for word in words: continue
for c in set(word): # each unique char in word if c + dc < 0 or c + dc >= cols:
if word.count(c) > chars_count[c]: continue
break if grid[r + dr][c + dc] == 0:
else: visited += 1
result += len(word) grid[r + dr][c + dc] = 1
new_frontier.add((r + dr, c + dc))
return result
frontier = new_frontier
distance += 1
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1163_Last_Substring_in_Lexicographical_Order.py - h
# https://leetcode.com/problems/maximum-level-sum-of-a-binary-tree/
# Given the root of a binary tree, the level of its root is 1, the level of its children is 2, and so on. _author_ = 'jake'
# Return the smallest level X such that the sum of all the values of nodes at level X is maximal. _project_ = 'leetcode'
# Traverse the tree with depth-first search, updating the sum of values at each level. # https://leetcode.com/problems/last-substring-in-lexicographical-order/
# Find the greatest sum of levels, then return the lowest level with that sum. # Given a string s, return the last substring of s in lexicographical order.
# Time - O(n)
# Space - O(n) # Find all indices in s of the greatest char (lexicographically last).
# These are the stating indices of candidate substrings.
from collections import defaultdict # While there is more than one candidate, find the next char and index of each candidate substring.
# Form the next chars, retain on the substrings with the greatest char.
class Solution(object): # If the end of one candidate runs into the start of another candidate, reject the shorter candidate.
def maxLevelSum(self, root): # Return the substring from the last remaining candidate to the end of s.
""" # Time - O(n)
:type root: TreeNode # Space - O(n)
:rtype: int
""" from collections import defaultdict
level_sums = defaultdict(int) # map level to sum of node values
class Solution(object):
def helper(node, level): def lastSubstring(self, s):
if not node: """
return :type s: str
:rtype: str
level_sums[level] += node.val """
helper(node.left, level + 1) n = len(s)
helper(node.right, level + 1) max_char = max(s)
candidates = {i for i in range(n) if s[i] == max_char} # indices of max_char
helper(root, 1) length = 0
max_level_sum = max(level_sums.values())
return min(level for level, level_sum in level_sums.items() if level_sum == max_level_sum) while len(candidates) > 1:
char_indices = defaultdict(set)
for i in candidates:
if i == n - 1:
# python_1001_to_2000/1162_As_Far_from_Land_as_Possible.py - m continue
if i - length - 1 in candidates: # another candidate runs into this candidate
_author_ = 'jake' continue
_project_ = 'leetcode' char_indices[s[i + 1]].add(i + 1)
# helper function, returns the last node from a path of folders or None class Solution(object):
def traverse(self, folders): def minCostToSupplyWater(self, n, wells, pipes):
node = self.root """
for folder in folders[1:]: :type n: int
if folder not in node.children: :type wells: List[int]
return None :type pipes: List[List[int]]
node = node.children[folder] :rtype: int
return node """
neighbours = defaultdict(list) # map each house to list of connected (nbor, cost)
def createPath(self, path, value): for house1, house2, cost in pipes:
""" neighbours[house1].append((house2, cost))
:type path: str neighbours[house2].append((house1, cost))
:type value: int
:rtype: bool heap = [(cost, i + 1) for i, cost in enumerate(wells)] # each house can be connected by a well
""" heapq.heapify(heap)
folders = path.split("/")
node = self.traverse(folders[:-1]) # find the node of parent of last folder supplied = set() # houses that are connected
if node is None or folders[-1] in node.children: result = 0
return False
node.children[folders[-1]] = Node(value) # insert the value while len(supplied) < n:
return True cost, house = heapq.heappop(heap) # smallest cost connection
if house in supplied:
def get(self, path): continue
""" supplied.add(house)
:type path: str result += cost
:rtype: int for nbor, nbor_cost in neighbours[house]: # add all unconnected neighbours to the heap
""" if nbor not in supplied:
node = self.traverse(path.split("/")) heapq.heappush(heap, (nbor_cost, nbor))
if not node:
return -1 return result
return node.value
# python_1001_to_2000/1169_Invalid_Transactions.py - m
# https://leetcode.com/problems/dinner-plate-stacks/
# You have an infinite number of stacks arranged in a row and numbered (left to right) from 0,
# python_1001_to_2000/1170_Compare Strings_by_Frequency_of_the_Smallest_Character.py - m # each of the stacks has the same maximum capacity.
# Implement the DinnerPlates class:
_author_ = 'jake' # DinnerPlates(int capacity) Initializes the object with the maximum capacity of the stacks.
_project_ = 'leetcode' # void push(int val) pushes the given positive integer val into the leftmost stack with size less than capacity.
# int pop() returns the value at the top of the rightmost non-empty stack and removes it from that stack,
# https://leetcode.com/problems/compare-strings-by-frequency-of-the-smallest-character/ # and returns -1 if all stacks are empty.
# Let's define a function f(s) over a non-empty string s, # int popAtStack(int index) returns the value at the top of the stack with the given index and removes it
# which calculates the frequency of the smallest character in s. # from that stack, and returns -1 if the stack with that given index is empty.
# For example, if s = "dcce" then f(s) = 2 because the smallest character is "c" and its frequency is 2.
# Now, given string arrays queries and words, return an integer array answer, # Maintain a list of stacks, where the last stack cannot be empty.
# where each answer[i] is the number of words such that f(queries[i]) < f(W), where W is a word in words. # Also maintain a heap of indices of stacks which are incomplete due to popAtStack(), i.e. not including the last stack.
# Push onto the first available incomplete stack, or the final stack (adding a new one if final stack is at capacity).
# Create a list to count the number of words with each f(word). # When popping, remove all empty stacks (which may be more than 1 due to popAtStack).
# Populate the list for each word, then iterate over the list in reverse order so it contains the cumulative count # For popAtStack, use pop if popping from the final stack, else add to the incomplete stacks heap.
# of words with the same or greater f(word). # Time - O(n log n) for n operations of push and popAtStack since all existing stacks could be touched. O(n) for pop.
# For each query, lookup f(query) + 1 in the cumulative frequency list, to return the number of words with a # Space - O(n)
# greater f(word).
# Time - O(m + n), the number of chars in words + the number of chars in queries import heapq
# Space - O(1), since words have at most 10 chars
class DinnerPlates(object):
class Solution(object):
def numSmallerByFrequency(self, queries, words): def __init__(self, capacity):
""" """
:type queries: List[str] :type capacity: int
:type words: List[str] """
:rtype: List[int] self.capacity = capacity
""" self.stacks = []
word_freq = [0] * 12 # word_freq[i] is count of words with f(word) == i self.incomplete_stacks = [] # heap of indices of stacks that have had pop_index
for word in words:
word_freq[word.count(min(word))] += 1 def push(self, val):
"""
for i in range(10, 0, -1): # update word_freq[i] to be the count of words with f(word) >= i :type val: int
word_freq[i] += word_freq[i + 1] :rtype: None
"""
# look up the count of words with f(word) > f(query) while self.incomplete_stacks: # check or discard all incomplete_stacks in order
return [word_freq[query.count(min(query)) + 1] for query in queries] i = heapq.heappop(self.incomplete_stacks)
if i >= len(self.stacks): :type lower: int
continue :type upper: int
self.stacks[i].append(val) :rtype: int
return """
calories.append(0) # append extra dummy element
if not self.stacks or len(self.stacks[-1]) == self.capacity: window = sum(calories[:k])
self.stacks.append([]) # start a new stack points = 0
self.stacks[-1].append(val)
for i in range(k, len(calories)):
def pop(self): if window < lower:
""" points -= 1
:rtype: int elif window > upper:
""" points += 1
if not self.stacks: window += calories[i]
return -1 window -= calories[i - k]
val = self.stacks[-1].pop()
while self.stacks and not self.stacks[-1]: # discard all empty stacks return points
self.stacks.pop()
return val
# python_1001_to_2000/1175_Prime_Arrangements.py # For each prefix of s, create an integer with a bit set for every char in the prefix that has an odd count.
# For each query, find the integers for the left and right + 1 prefixes.
_author_ = 'jake' # Count the number of chars in the query that have an odd number of bits set. These chars need to be changed to
_project_ = 'leetcode' # make a palindrome, apart from the central char if the query is of odd length.
# Time - O(m + n) where m is len(s) and there are n queries.
# https://leetcode.com/problems/prime-arrangements/ # Space - O(n)
# Return the number of permutations of 1 to n so that prime numbers are at prime indices (1-indexed.)
# Recall that an integer is prime if and only if it is greater than 1, class Solution(object):
# and cannot be written as a product of two positive integers both smaller than it. def canMakePaliQueries(self, s, queries):
# Since the answer may be large, return the answer modulo 10^9 + 7. """
:type s: str
# Binary search the list of prines to find how many primes are <= n. :type queries: List[List[int]]
# Multiply the number of permutations of primes (primes!) by the number of permutations of non-primes. :rtype: List[bool]
# Time - O(1) """
# Space - O(1) char_odd_bits = [0]
for c in s:
import bisect, math char_odd_bits.append(char_odd_bits[-1] ^ (1 << ord(c) - ord("a")))
return result
# python_1001_to_2000/1176_Diet_Plan_Performance.py
class Solution(object):
def shortestDistanceColor(self, colors, queries):
# python_1001_to_2000/1180_Count_Substrings_with_Only_One_Distinct_Letter.py """
:type colors: List[int]
_author_ = 'jake' :type queries: List[List[int]]
_project_ = 'leetcode' :rtype: List[int]
"""
# https://leetcode.com/problems/count-substrings-with-only-one-distinct-letter/ shortest = []
# Given a string S, return the number of substrings that have only one distinct letter. distances = [float("inf")] * 3 # to next element of each color on left
for color in colors:
# Iterate along S, tracking the start of the current sequence of identical letters. distances = [d + 1 for d in distances] # add 1 to distance for each color
# If a char if different from the previous, then update the previous and the start. distances[color - 1] = 0 # zero distance to thie color
# Time - O(n) shortest.append(list(distances))
# Space - O(1)
for i in range(len(colors) - 2, -1, -1): # update with closest color on right, if smaller
class Solution(object): distances = [d + 1 for d in shortest[i + 1]]
def countLetters(self, S): for color in range(3):
""" shortest[i][color] = min(shortest[i][color], distances[color])
:type S: str
:rtype: int result = []
""" for i, color in queries:
previous = "#" shortest_dist = shortest[i][color - 1]
start = 0 result.append(-1 if shortest_dist == float("inf") else shortest_dist)
substrings = 0
return result
for end, c in enumerate(S):
if c != previous:
start = end
previous = c # python_1001_to_2000/1183_Maximum_Number_of_Ones.py - h
substrings += end - start + 1 # add all substrings with current end
_author_ = 'jake'
return substrings _project_ = 'leetcode'
# https://leetcode.com/problems/maximum-number-of-ones/
# Consider a matrix M with dimensions width * height, such that every cell has value 0 or 1,
# python_1001_to_2000/1181_Before_and_After_Puzzle.py - m # and any square sub-matrix of M of size sideLength * sideLength has at most maxOnes ones.
# Return the maximum possible number of ones that the matrix M can have.
_author_ = 'jake'
_project_ = 'leetcode' # For each cell of the sub-matrix, count how many times that cell is repeated in the matrix.
# The count is equal to the number of times a cell appears in a row * the number of times a cell appears in a column.
# https://leetcode.com/problems/before-and-after-puzzle/ # A cell appears in a row the number of times the sub-matrix is repeated along the width, adding 1 if the cell is in
# Given a list of phrases, generate a list of Before and After puzzles. # the remaining rows.
# A phrase is a string that consists of lowercase English letters and spaces only. # Sort the number of times each cell appears, add ones to the maxOnes most frequent cells.
# No space appears in the start or the end of a phrase. There are no consecutive spaces in a phrase. # Time - O(n**2 log n) for sideLength n
# Before and After puzzles are phrases that are formed by merging two phrases where the last word of # Space - O(n**2)
# the first phrase is the same as the first word of the second phrase.
# Return the Before and After puzzles that can be formed by every two phrases phrases[i] and phrases[j] where i != j. class Solution(object):
# Note that the order of matching two phrases matters, we want to consider both orders. def maximumNumberOfOnes(self, width, height, sideLength, maxOnes):
# You should return a list of distinct strings sorted lexicographically. """
:type width: int
# Split all phrases by space. :type height: int
# For each pair of split phrases, add to the result the concatenation if the last and first words are the same. :type sideLength: int
# Sort the result. :type maxOnes: int
# Time - O(n**2 log n) :rtype: int
# Space - O(n**2) """
whole_width, remainder_width = divmod(width, sideLength)
class Solution(object): whole_height, remainder_height = divmod(height, sideLength)
def beforeAndAfterPuzzles(self, phrases):
""" matrix = []
:type phrases: List[str] for r in range(sideLength):
:rtype: List[str] for c in range(sideLength):
""" repeats = (whole_width + int(r < remainder_width)) * (whole_height + int(c < remainder_height))
split_phrases = [phrase.split(" ") for phrase in phrases] matrix.append(repeats)
result = set() # eliminates duplicates
return sum(sorted(matrix, reverse=True)[:maxOnes]) # Iterate over the array, tracking the max sum ending at each index and the max sum ending at each index with one
# deletion.
# Max sum takes the previous max sum if positive or zero, and adds the current num.
# Max sum with deletion take the max sum and deletes the current num,
# python_1001_to_2000/1184_Distance_Between_Bus_Stops.py # or the previous max with deletion and adds the current num.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/distance-between-bus-stops/ def maximumSum(self, arr):
# A bus has n stops numbered from 0 to n - 1 that form a circle. """
# We know the distance between all pairs of neighboring stops where distance[i] is the distance between the :type arr: List[int]
# stops number i and (i + 1) % n. :rtype: int
# The bus goes along both directions i.e. clockwise and counterclockwise. """
# Return the shortest distance between the given start and destination stops. if all(a <= 0 for a in arr): # no positive, return largest value
return max(arr)
# Ensure destination stop is not before start stop by swapping if necessary.
# Find the sum of the distances from start to destination. overall_max_deleted = 0
# Also find the sum of the distances round a complete circuit of all stops. max_here, max_here_deleted = 0, 0
# Return the minimum of the direct distance and the distance in the reverse direction.
# Time - O(n) for a in arr:
# Space - O(1) max_here_deleted = max(max_here_deleted + a, max_here)
max_here = max(max_here, 0) + a
class Solution(object):
def distanceBetweenBusStops(self, distance, start, destination): overall_max_deleted = max(overall_max_deleted, max_here_deleted, max_here)
"""
:type distance: List[int] return overall_max_deleted
:type start: int
:type destination: int
:rtype: int
""" # python_1001_to_2000/1187_Make_Array_Strictly_Increasing.py - h
if destination < start:
start, destination = destination, start _author_ = 'jake'
_project_ = 'leetcode'
start_to_dest = sum(distance[start:destination])
circuit = sum(distance) # distance of complete circuit # https://leetcode.com/problems/make-array-strictly-increasing/
return min(start_to_dest, circuit - start_to_dest) # Given two integer arrays arr1 and arr2,
# return the minimum number of operations (possibly zero) needed to make arr1 strictly increasing.
# In one operation, you can choose two indices 0 <= i < arr1.length and 0 <= j < arr2.length
# and do the assignment arr1[i] = arr2[j].
# python_1001_to_2000/1185_Day_of_the_Week.py # If there is no way to make arr1 strictly increasing, return -1.
_author_ = 'jake' # Maintain a mapping from the last num of the array so far and the number of operations to make this array.
_project_ = 'leetcode' # For each num of arr1, create a new mapping with default value of infinity.
# For each ending num of previous arrays,
# https://leetcode.com/problems/day-of-the-week/ # If num > prev_num then we can make an array ending num with the same operations as made prev_num
# Given a date, return the corresponding day of the week for that date. # Find the next number in arr2 greater than prev_num. if num <= prev_num then we can make an array ending in arr2[i]
# The input is given as three integers representing the day, month and year respectively. # with an extra operation. Similarly we can use the extra operation if num > prev_num only if arr2[i] < num (else we
# Return the answer as one of the following values {"Sunday", "Monday", "Tuesday", "Wednesday", # are better extending with no additional operation).
# "Thursday", "Friday", "Saturday"}. # Time - O(n**2)
# Space - O(n)
# Find the number of days since 1 Jan 1971.
# Sum the day of the month + days in previous months + 365 * years since 1971. from collections import defaultdict
# Add an offset of 4 since 1/1/71 was Friday. import bisect
# Add extra days for any previous leap yeas and current leap year.
# Time - O(1) class Solution(object):
# Space - O(1) def makeArrayIncreasing(self, arr1, arr2):
"""
class Solution(object): :type arr1: List[int]
def dayOfTheWeek(self, day, month, year): :type arr2: List[int]
""" :rtype: int
:type day: int """
:type month: int arr2.sort()
:type year: int num_to_ops = {-1: 0} # map last number of array to number of ops to make array increasing
:rtype: str
""" for num in arr1:
weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] new_num_to_ops = defaultdict(lambda: float("inf"))
cumulative_days = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
for prev_num in num_to_ops:
days = 4 + day + cumulative_days[month - 1] + 365 * (year - 1971) # 4 for offset from 1/1/1974 if num > prev_num: # same nb ops to extend with num
new_num_to_ops[num] = min(new_num_to_ops[num], num_to_ops[prev_num])
leap_days = (year - 1969) // 4 # number of completed leap years
print(leap_days) i = bisect.bisect_right(arr2, prev_num)
if year % 4 == 0 and month >= 3: # include 29th February in current year if i < len(arr2) and (num <= prev_num or arr2[i] < num):
leap_days += 1 new_num_to_ops[arr2[i]] = min(new_num_to_ops[arr2[i]], num_to_ops[prev_num] + 1)
days += leap_days
num_to_ops = new_num_to_ops
return weekdays[days % 7]
if num_to_ops:
return min(num_to_ops.values())
return -1
# python_1001_to_2000/1186_Maximum_Subarray_Sum_with_One_Deletion.py - m
_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1189_Maximum_Number_of_Balloons.py
total = sum(arr)
# Count the frequency of each letter.
# For each unique letter in "balloons", update the result with the minimum of the current result and the count of the max_prefix, max_end_here, max_subarray = 0, 0, 0
# letter in text divided by the count in "balloons". cumulative = 0
# Time - O(n) for a in arr:
# Space - O(1) cumulative += a
max_prefix = max(max_prefix, cumulative)
from collections import Counter max_end_here = max(max_end_here, 0) + a
max_subarray = max(max_subarray, max_end_here)
class Solution(object):
def maxNumberOfBalloons(self, text): max_suffix = 0
""" cumulative = 0
:type text: str for a in arr[::-1]:
:rtype: int cumulative += a
""" max_suffix = max(max_suffix, cumulative)
counts = Counter(text)
result = float("inf") if k == 1:
return max_subarray % MOD
for c, count in Counter("balloon").items(): return max(max_subarray, max_prefix + max_suffix + max(total, 0) * (k - 2)) % MOD
result = min(result, counts[c] // count) # integer division
return result
# python_1001_to_2000/1192_Critical_Connections_in_a_Network.py - h
_author_ = 'jake'
# python_1001_to_2000/1190_Reverse_Substrings_Between_Each_Pair_of_Parentheses.py - m _project_ = 'leetcode'
return stack[0] + s[start:] # add remaining text connections = {tuple(sorted(connection)) for connection in connections}
rank = [-float("inf")] * n
class Solution(object):
def kConcatenationMaxSum(self, arr, k): # python_1001_to_2000/1196_How_Many_Apples_Can_You_Put_into_the_Basket.py
"""
:type arr: List[int] _author_ = 'jake'
:type k: int _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/how-many-apples-can-you-put-into-the-basket/
MOD = 10 ** 9 + 7 # You have some apples, where arr[i] is the weight of the i-th apple.
# You also have a basket that can carry up to 5000 units of weight. # For each other row, retain common elements from that row and all previous rows.
# Return the maximum number of apples you can put in the basket. # Time - O(mn)
# Space - O(m)
# Form a heap of the apples.
# Remove apples from the heap by increasing weight, class Solution(object):
# until there are no more apples or there is insufficient capacity to fit the next apple in the basket. def smallestCommonElement(self, mat):
# Time - O(n log n) """
# Space - O(n) :type mat: List[List[int]]
:rtype: int
import heapq """
candidates = set(mat[0])
class Solution(object):
def maxNumberOfApples(self, arr): for row in mat[1:]:
""" candidates &= set(row)
:type arr: List[int]
:rtype: int return min(candidates) if candidates else -1
"""
capacity = 5000
apples = 0
heapq.heapify(arr) # python_1001_to_2000/1199_Minimum_Time_to_Build_Blocks.py - h
while arr and capacity - arr[0] >= 0:
capacity -= heapq.heappop(arr) _author_ = 'jake'
apples += 1 _project_ = 'leetcode'
for a, b in pairs:
parents[find(a)] = find(b)
# python_1001_to_2000/1201_Ugly_Number_III.py - m
parent_to_children = defaultdict(list)
_author_ = 'jake' for i in range(n):
_project_ = 'leetcode' parent_to_children[find(i)].append(i)
# https://leetcode.com/problems/unique-number-of-occurrences/ for c in s:
# Given an array of integers arr, write a function that returns true if and only if the number of if stack and stack[-1][0] == c: # extend sequence of same char
# occurrences of each value in the array is unique. if stack[-1][1] == k - 1: # remove sequence of k chars
stack.pop()
# Count the occurrences of each value and check whether the set of counts is the same size as the number of counts, else:
# i.e. no count is duplicated. stack[-1][1] += 1
# Time - O(n) else:
# Space - O(n) stack.append([c, 1])
from collections import Counter return "".join(c * count for c, count in stack) # join remaining stack
class Solution(object):
def uniqueOccurrences(self, arr):
"""
:type arr: List[int] # python_1001_to_2000/1210_Minimum_Moves_to_Reach_Target_with_Rotations.py - h
:rtype: bool
""" _author_ = 'jake'
counts = Counter(arr) _project_ = 'leetcode'
return len(set(counts.values())) == len(counts.values())
# https://leetcode.com/problems/minimum-moves-to-reach-target-with-rotations/
# In an n*n grid, there is a snake that spans 2 cells and starts moving from the top left corner at (0, 0) and (0, 1).
# The grid has empty cells represented by zeros and blocked cells represented by ones.
# python_1001_to_2000/1208_Get_Equal_Substrings_Within_Budget.py - m # The snake wants to reach the lower right corner at (n-1, n-2) and (n-1, n-1).
# In one move the snake can:
_author_ = 'jake' # Move one cell to the right if there are no blocked cells there.
_project_ = 'leetcode' # This move keeps the horizontal/vertical position of the snake as it is.
# Move down one cell if there are no blocked cells there.
# https://leetcode.com/problems/get-equal-substrings-within-budget/ # This move keeps the horizontal/vertical position of the snake as it is.
# You are given two strings s and t of the same length. # Rotate clockwise if it's in a horizontal position and the two cells under it are both empty.
# You want to change s to t. # In that case the snake moves from (r, c) and (r, c+1) to (r, c) and (r+1, c).
# Changing the i-th character of s to i-th character of t costs |s[i] - t[i]| that is, # Rotate counterclockwise if it's in a vertical position and the two cells to its right are both empty.
# the absolute difference between the ASCII values of the characters. # In that case the snake moves from (r, c) and (r+1, c) to (r, c) and (r, c+1).
# You are also given an integer maxCost. # Return the minimum number of moves to reach the target.
# Return the maximum length of a substring of s that can be changed to be the same as the corresponding substring # If there is no way to reach the target, return -1.
# of t with a cost less than or equal to maxCost.
# If there is no substring from s that can be changed to its corresponding substring from t, return 0. # Breadth-first search.
# Frontier consists of a set of states signifying the head position and whether the snake is horizontal.
# Maintain a sliding window of a substring with cost < maxCost. # For each move, update the frontier with all possible next states depending on the orientation and whether
# Iterate along the strings, adding the cost of changing the current character to the window cost. # neighbouring cells are in the grid and unoccupied.
# While the window cost is more than maxCost, remove characters from the front of the window. # Set of seen states avoids repetition.
# Time - O(n) # Time - O(mn)
# Space - O(1) # Space - O(mn)
if not horizontal and c != cols - 1 and grid[r][c + 1] == 0 and grid[r - 1][c + 1] == 0: # https://leetcode.com/problems/stepping-numbers/
new_frontier.add((r, c + 1, False)) # right # A Stepping Number is an integer such that all of its adjacent digits have an absolute difference of exactly 1.
new_frontier.add((r - 1, c + 1, True)) # anti-clockwise rotation # For example, 321 is a Stepping Number while 421 is not.
# Given two integers low and high,
seen |= frontier # find and return a sorted list of all the Stepping Numbers in the range [low, high] inclusive.
frontier = new_frontier
moves += 1 # Breadth-first search, starting with single digit integers.
# For each number in the frontier, reject if greater than high and add to result if greater than or equal to low.
return -1 # Extend the number with its final digit - 1 and final digit + 1, unless this would be < 0 or > 9.
# Repeat until there are no more numbers to extend.
# Time - O(n)
# Space - O(n)
# python_1001_to_2000/1213_Intersection_of_Three_Sorted_Arrays.py
class Solution(object):
_author_ = 'jake' def countSteppingNumbers(self, low, high):
_project_ = 'leetcode' """
:type low: int
# https://leetcode.com/problems/intersection-of-three-sorted-arrays/ :type high: int
# Given three integer arrays arr1, arr2 and arr3 sorted in strictly increasing order, :rtype: List[int]
# return a sorted array of only the integers that appeared in all three arrays. """
result = []
# Count the frequency across all arrays. if low == 0: # do not add zero unless low is 0, since we cannot start other integers with 0
# Return the items that occur 3 times. result.append(0)
# This works because the arrays are strictly increasing, i.e. no duplicates.
# Also works if the arrays are not sorted. nums = [i for i in range(1, 10)]
# Time - O(n)
# Space - O(n) while nums:
new_nums = []
from collections import Counter for num in nums:
if num > high:
class Solution(object): continue
def arraysIntersection(self, arr1, arr2, arr3): if num >= low:
""" result.append(num)
:type arr1: List[int] last_digit = num % 10
:type arr2: List[int] if last_digit != 0:
:type arr3: List[int] new_nums.append(num * 10 + last_digit - 1)
:rtype: List[int] if last_digit != 9:
""" new_nums.append(num * 10 + last_digit + 1)
return [i for i, count in Counter(arr1 + arr2 + arr3).items() if count == 3]
nums = new_nums
return result
# python_1001_to_2000/1214_Two_Sum_BSTs.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1216_Valid_Palindrome_III.py - h
# https://leetcode.com/problems/two-sum-bsts/
# Given two binary search trees, return True if and only if there is a node in the first tree and a node in _author_ = 'jake'
# the second tree whose values sum up to a given integer target. _project_ = 'leetcode'
# Explore the first tree by depth-first search, adding all values to a set. # https://leetcode.com/problems/valid-palindrome-iii/
# Explore the second tree by depth-first search, checking for each node if its complement to sum to target is in the # Given a string s and an integer k, find out if the given string is a K-Palindrome or not.
# set of values from the first tree. # A string is K-Palindrome if it can be transformed into a palindrome by removing at most k characters from it.
# Note that this works for a binary tree even if it is not a search tree.
# Time - O(m + n) for trees of size m and n. # Helper function returns the number of removals to transform the string between s[start] and s[end], inclusive.
# Space - O(m + n) # If s[start] is the same as s[end], recurse without both ends.
# Else take the best case of removing either start or end.
class Solution(object): # Memoize to avoid repetition.
def twoSumBSTs(self, root1, root2, target): # Time - O(n**2)
""" # Space - O(n**2)
:type root1: TreeNode
:type root2: TreeNode class Solution(object):
:type target: int def isValidPalindrome(self, s, k):
:rtype: bool """
""" :type s: str
seen = set() :type k: int
:rtype: bool
def explore(node): """
if not node: memo = {}
return
seen.add(node.val) def helper(start, end):
explore(node.left) if start >= end: # <= 1 char is a palindrome
explore(node.right) return 0
if (start, end) in memo:
explore(root1) return memo[(start, end)]
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1218_Longest_Arithmetic_Subsequence_of_Given_Difference.py - m
# https://leetcode.com/problems/count-vowels-permutation/
_author_ = 'jake' # Given an integer n, your task is to count how many strings of length n can be formed under the following rules:
_project_ = 'leetcode' # Each character is a lower case vowel ('a', 'e', 'i', 'o', 'u')
# Each vowel 'a' may only be followed by an 'e'.
# https://leetcode.com/problems/longest-arithmetic-subsequence-of-given-difference/ # Each vowel 'e' may only be followed by an 'a' or an 'i'.
# Given an integer array arr and an integer difference, # Each vowel 'i' may not be followed by another 'i'.
# return the length of the longest subsequence in arr which is an arithmetic sequence such that # Each vowel 'o' may only be followed by an 'i' or a 'u'.
# the difference between adjacent elements in the subsequence equals difference. # Each vowel 'u' may only be followed by an 'a'.
# Since the answer may be too large, return it modulo 10^9 + 7.
# Create a map from each number in the array to the maximum length of any subsequence ending with that number.
# Iterate over the array, updating the map by extending the sequence ending with num - difference. # Create a mapping from each vowel to the number of permutations ending with that vowel.
# If num - difference is not in the map then we start a new sequence of length 1. # For each new letter, update the permutations from all previous vowels that can be followed by the new vowel.
# Return the greatest length. # Time - O(n)
# Time - O(n) # Space - O(1)
# Space - O(n)
class Solution(object):
from collections import defaultdict def countVowelPermutation(self, n):
"""
class Solution(object): :type n: int
def longestSubsequence(self, arr, difference): :rtype: int
""" """
:type arr: List[int] counts = {vowel: 1 for vowel in "aeiou"} # 1 permutation for each letter
:type difference: int
:rtype: int for _ in range(n - 1):
""" new_counts = {}
num_to_length = defaultdict(int) new_counts["a"] = counts["e"] + counts["i"] + counts["u"]
new_counts["e"] = counts["a"] + counts["i"]
for num in arr: new_counts["i"] = counts["e"] + counts["o"]
num_to_length[num] = num_to_length[num - difference] + 1 new_counts["o"] = counts["i"]
new_counts["u"] = counts["i"] + counts["o"]
return max(num_to_length.values()) counts = new_counts
# python_1001_to_2000/1219_Path_with_Maximum_Gold.py - m
""" for k in range(1, rollMax[j] + 1): # number of consecutive rolls of j at end of sequence
:type s: str if i - k < 0:
:rtype: int break
""" dp[i][j] += dp_total[i - k] - dp[i - k][j] # sequences of length i - k that do not end in k
balance = 0 dp_total[i] = sum(dp[i])
result = 0
return dp_total[n] % (10 ** 9 + 7)
for c in s:
balance += 1 if c == "L" else -1
if balance == 0:
result += 1 # python_1001_to_2000/1224_Maximum_Equal_Frequency.py - h
# https://leetcode.com/problems/maximum-equal-frequency/
# python_1001_to_2000/1222_Queens_That_Can_Attack_the_King.py - m # Given an array nums of positive integers, return the longest possible length of an array prefix of nums,
# such that it is possible to remove exactly one element from this prefix so that every number that has
_author_ = 'jake' # appeared in it will have the same number of occurrences.
_project_ = 'leetcode' # If after removing one element there are no remaining elements,
# it's still considered that every appeared number has the same number of ocurrences (0).
# https://leetcode.com/problems/queens-that-can-attack-the-king/
# On an 8x8 chessboard, there can be multiple Black Queens and one White King. # Iterate over nums, counting the occurrences of each num amd tracking the maximum count of any num.
# Given an array of integer coordinates queens that represents the positions of the Black Queens, # Also maintain a mapping from the count of a num to the number of different nums with that count.
# and a pair of coordinates king that represent the position of the White King, # If the maximum count is 1, we can remove any num and all others appear once.
# return the coordinates of all the queens (in any order) that can attack the King. # If all numbers apart from one have have a count of max_count - 1, we can remove one of the number with max_count and
# then all numbers appear max_count - 1 times.
# For each of the 8 directions outwards from the king, move until a queen is reaches or the edge of the board. # If all numbers apart from one have have a count of max_count and the pther number has a count of 1, we can remove
# Time - O(1), since board is 8 x 8 # the other number so all have counts of max_count.
# Space - O(1) # Time - O(n)
# Space - O(n)
class Solution(object):
def queensAttacktheKing(self, queens, king): from collections import defaultdict
"""
:type queens: List[List[int]] class Solution(object):
:type king: List[int] def maxEqualFreq(self, nums):
:rtype: List[List[int]] """
""" :type nums: List[int]
queen_set = {tuple(queen) for queen in queens} :rtype: int
"""
result = [] num_to_count, count_of_counts = defaultdict(int), defaultdict(int)
for dr, dc in [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]: result = 0
r, c = king max_count = 0
while 0 <= r + dr < 8 and 0 <= c + dc < 8:
r += dr for i, num in enumerate(nums):
c += dc count = num_to_count[num] + 1
if (r, c) in queen_set: num_to_count[num] = count
result.append([r, c]) max_count = max(max_count, count)
break
if count != 1:
return result count_of_counts[count - 1] -= 1 # remove previous count_of_counts
count_of_counts[count] += 1
if max_count == 1:
# python_1001_to_2000/1223_Dice_Roll_Simulation.py - h result = i + 1
elif count_of_counts[max_count - 1] == len(num_to_count) - 1:
_author_ = 'jake' result = i + 1
_project_ = 'leetcode' elif count_of_counts[max_count] == len(num_to_count) - 1 and count_of_counts[1] == 1:
result = i + 1
# https://leetcode.com/problems/dice-roll-simulation/
# A die simulator generates a random number from 1 to 6 for each roll. return result
# You introduced a constraint to the generator such that it cannot roll the number i more than rollMax[i]
# (1-indexed) consecutive times.
# Given an array of integers rollMax and an integer n,
# return the number of distinct sequences that can be obtained with exact n rolls. # python_1001_to_2000/1227_Airplane_Seat_Assignment_Probability.py - m
# Two sequences are considered different if at least one element differs from each other.
# Since the answer may be too large, return it modulo 10^9 + 7. _author_ = 'jake'
_project_ = 'leetcode'
# Dynamic programming. Find the number of sequences for each number of rolls and each final number.
# A sequence ending in j after i rolls can end in any number of j from 1 to rollMax[j]. # https://leetcode.com/problems/airplane-seat-assignment-probability/
# For each number k of sequence ending j, we can append [j] * k to any sequence of length i - k that does not end in j. # n passengers board an airplane with exactly n seats.
# Time - O(m n**2), for m sides and n rolls. # The first passenger has lost the ticket and picks a seat randomly.
# Space - O(mn) # But after that, the rest of passengers will:
# Take their own seat if it is still available,
class Solution(object): # Pick other seats randomly when they find their seat occupied
def dieSimulator(self, n, rollMax): # What is the probability that the n-th person can get his own seat?
"""
:type n: int # For n > 1, the first person chooses their own seat with probability 1 / n,
:type rollMax: List[int] # in which case everybody gets their own seat.
:rtype: int # Else the next person chooses the first person's seat with probability 1 /(n - 1) and
""" # everybody else gets their own seat. Summing the series results in 0.5.
sides = len(rollMax) # Time - O(1)
# dp[i][j] is the number of ways we can end with a roll of j + 1 after i rolls # Space - O(1)
dp = [[0 for j in range(sides)] for i in range(n + 1)]
dp_total = [0] * (n + 1) # dp_total[i] is the sum over j of dp[i][j] class Solution(object):
def nthPersonGetsNthSeat(self, n):
dp_total[0], dp_total[1] = 1, 6 """
for j in range(sides): :type n: int
dp[1][j] = 1 :rtype: float
"""
for i in range(2, n + 1): return 1 if n == 1 else 0.5
for j in range(sides):
# You have some coins. The i-th coin has a probability prob[i] of facing heads when tossed.
# Return the probability that the number of coins facing heads equals target if you toss every coin exactly once.
# python_1001_to_2000/1228_Missing_Number_In_Arithmetic_Progression.py
# Dynamic programming. Given the probability of each number of heads from n - 1 tosses,
_author_ = 'jake' # we calculate the probability of each number of heads from n tosses.
_project_ = 'leetcode' # For each previous number of each, we can toss a head and get an additional head,
# or toss a tail and keep the same number of heads.
# https://leetcode.com/problems/missing-number-in-arithmetic-progression/ # Time - O(n**2)
# In some array arr, the values were in arithmetic progression: # Space - O(n)
# the values arr[i+1] - arr[i] are all equal for every 0 <= i < arr.length - 1.
# Then, a value from arr was removed that was not the first or last value in the array. class Solution(object):
# Return the removed value. def probabilityOfHeads(self, prob, target):
"""
# If the first difference is twice the second difference, then the missing value should be second. :type prob: List[float]
# Else if any difference is twice the first difference, the missing value is between the current values. :type target: int
# Time - O(n) :rtype: float
# Space - O(1) """
probs = [1] # probs[i] is probability of i heads, initially from 0 tosses
class Solution(object):
def missingNumber(self, arr): for coin in prob:
""" new_probs = [0] * (len(probs) + 1)
:type arr: List[int] for heads, p in enumerate(probs[:target + 1]):
:rtype: int new_probs[heads] += p * (1 - coin)
""" new_probs[heads + 1] += p * coin
first_diff = arr[1] - arr[0]
if first_diff == 2 * (arr[2] - arr[1]): probs = new_probs
return arr[0] + first_diff // 2
return probs[target]
for i in range(1, len(arr) - 1):
if (arr[i + 1] - arr[i]) == first_diff * 2:
return arr[i] + first_diff
# python_1001_to_2000/1231_Divide_Chocolate.py - h
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1229_Meeting_Scheduler.py - m
# https://leetcode.com/problems/divide-chocolate/
_author_ = 'jake' # You have one chocolate bar that consists of some chunks.
_project_ = 'leetcode' # Each chunk has its own sweetness given by the array sweetness.
# You want to share the chocolate with your K friends so you start cutting the chocolate bar into K+1
# https://leetcode.com/problems/meeting-scheduler/ # pieces using K cuts, each piece consists of some consecutive chunks.
# Given the availability time slots arrays slots1 and slots2 of two people and a meeting duration duration, # Being generous, you will eat the piece with the minimum total sweetness and give the other pieces to your friends.
# return the earliest time slot that works for both of them and is of duration duration. # Find the maximum total sweetness of the piece you can get by cutting the chocolate bar optimally.
# If there is no common time slot that satisfies the requirements, return an empty array.
# The format of a time slot is an array of two elements [start, end] # Binary search the range of possible results.
# representing an inclusive time range from start to end. # For each guess, check whether it is possible to split the bar into at least K pieces with each piece having at
# It is guaranteed that no two availability slots of the same person intersect with each other. # least guess sweetness.
# That is, for any two time slots [start1, end1] and [start2, end2] of the same person, # If it is possible, the guess is the new lower bound, ele the new upper bound is less than guess.
# either start1 > end2 or start2 > end1. # Time - O(n log m) for n pieces and m total sweetness
# Space - O(1)
# Sort both lists by ascending start time.
# Use pointers i and j to the next slot in each list. class Solution(object):
# While neither pointer is at the end, find the overlapping time of the current slots. def maximizeSweetness(self, sweetness, K):
# If this is long enough, return the meeting. """
# Else move the pointer forward for the slot with the earlier start. :type sweetness: List[int]
# Time - O(m log m + n log n) :type K: int
# Space - O(m + n) :rtype: int
"""
class Solution(object): K += 1 # add piece for myself
def minAvailableDuration(self, slots1, slots2, duration): left, right = 1, sum(sweetness) // K # possible result bounds (inclusive)
"""
:type slots1: List[List[int]] def can_split(x): # can split into >= K pieces with at least x sweetness per piece?
:type slots2: List[List[int]] piece, count = 0, 0
:type duration: int for sweet in sweetness:
:rtype: List[int] piece += sweet
""" if piece >= x:
i, j = 0, 0 count += 1
m, n = len(slots1), len(slots2) piece = 0
slots1.sort()
slots2.sort() return count >= K
# python_1001_to_2000/1230_Toss_Strange_Coins.py - m # https://leetcode.com/problems/check-if-it-is-a-straight-line/
# You are given an array coordinates, coordinates[i] = [x, y], where [x, y] represents the coordinate of a point.
_author_ = 'jake' # Check if these points make a straight line in the XY plane.
_project_ = 'leetcode'
# Find the initial slope between the first 2 points.
# https://leetcode.com/problems/toss-strange-coins/ # If the slopes between the first point and all other points are the same as the initial slope, return True.
# https://leetcode.com/problems/remove-sub-folders-from-the-filesystem/ # python_1001_to_2000/1235_Maximum_Profit_in_Job_Scheduling.py - h
# Given a list of folders, remove all sub-folders in those folders and return in any order the folders after removing.
# If a folder[i] is located within another folder[j], it is called a sub-folder of it. _author_ = 'jake'
# The format of a path is one or more concatenated strings of the form: _project_ = 'leetcode'
# / followed by one or more lowercase English letters.
# For example, /leetcode and /leetcode/problems are valid paths while an empty string and / are not. # https://leetcode.com/problems/maximum-profit-in-job-scheduling/
# We have n jobs, where every job is scheduled to be done from startTime[i] to endTime[i],
# Insert the paths in a trie in order of increasing length. # obtaining a profit of profit[i].
# Signify the terminal node when a path is fully inserted. # You're given the startTime , endTime and profit arrays, you need to output the maximum profit you
# If a path reaches a node that is already terminal, it is a subfolder. # can take such that there are no 2 jobs in the subset with overlapping time range.
# Time - O(n log n) for n folders. # If you choose a job that ends at time X you will be able to start another job that starts at time X.
# Space - O(n)
# Dynamic programming. Build a list of [end_time, max_profit] for the profit that can be made by end_time,
class Solution(object): # where profit is strictly ascending.
def removeSubfolders(self, folder): # Zip the end, start and profits together into tuples and sort by ascending end time.
""" # For each start time, find the max profit that can be made for all previous jobs finishing at or before that end time.
:type folder: List[str] # If that previous profit + the job profit is more than the best profit, append [end_time, max_profit] to the
:rtype: List[str] # dynamic programming list.
""" # Time - O(n log n)
paths = [f.split("/") for f in folder] # Space - O(n)
paths.sort(key=len)
result = [] import bisect
root = {}
class Solution(object):
for i, path in enumerate(paths): def jobScheduling(self, startTime, endTime, profit):
"""
node = root :type startTime: List[int]
for level in path[1:]: # path[0] is empty due to leading "/" :type endTime: List[int]
if level not in node: # make a new node :type profit: List[int]
node[level] = {} :rtype: int
node = node[level] """
if "TERMINAL" in node: # subfolder, do not add to result dp = [[0, 0]] # list of [end_time, max_profit] with ascending max_profit
break
else: jobs = sorted(zip(endTime, startTime, profit))
node["TERMINAL"] = {}
result.append("/".join(path)) for end, start, gain in jobs:
i = bisect.bisect_right(dp, [start, float("inf")])
return result if gain + dp[i - 1][1] > dp[-1][1]:
dp.append([end, gain + dp[i - 1][1]])
return dp[-1][1]
# python_1001_to_2000/1234_Replace_the_Substring_for_Balanced_String.py - m
_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1236_Web_Crawler.py
# https://leetcode.com/problems/maximum-length-of-a-concatenated-string-with-unique-characters/
# Given an array of strings arr.
# String s is a concatenation of a sub-sequence of arr which have unique characters.
# Return the maximum possible length of s.
# python_1001_to_2000/1237_Find_Positive_Integer_Solution_for_a_Given_Equation.py - m
# Remove all words with duplicated letters and convert words to sets of letters.
_author_ = 'jake' # For each set of chars, check overlap with each previous result.
_project_ = 'leetcode' # If there is no overlap, append the combined char set to the previous results.
# Time - O(mn) for n words of length m, since length of dp is bounded by alphabet size.
# https://leetcode.com/problems/find-positive-integer-solution-for-a-given-equation/ # Space - O(n)
# Given a function f(x, y) and a value z, return all positive integer pairs x and y where f(x,y) == z.
# The function is constantly increasing, i.e.: class Solution(object):
# f(x, y) < f(x + 1, y) def maxLength(self, arr):
# f(x, y) < f(x, y + 1) """
# The function interface is defined like this: :type arr: List[str]
# interface CustomFunction { :rtype: int
# public: """
# // Returns positive integer f(x, y) for any given positive integer x and y. char_sets = [set(s) for s in arr if len(s) == len(set(s))]
# int f(int x, int y); dp = [set()] # candidate resulting sets of chars after using each word
# };
# For custom testing purposes you're given an integer function_id and a target z as input, for char_set in char_sets:
# where function_id represent one function from an secret internal list. for prev_char_set in dp[:]:
# You may return the solutions in any order. combo = char_set | prev_char_set
if len(combo) == len(char_set) + len(prev_char_set):
# For each value of x, try all values of y until the function returns more than z. dp.append(combo)
# When it returns more than z, increment x and again try all values of y.
# Repeat for all values of x. return max(len(char_set) for char_set in dp)
# Time - O(mn)
# Space - O(1)
class Solution(object):
def findSolution(self, customfunction, z): # python_1001_to_2000/1240_Tiling_a_Rectangle_with_the_Fewest_Squares.py - h
"""
:type num: int _author_ = 'jake'
:type z: int _project_ = 'leetcode'
:rtype: List[List[int]]
""" # https://leetcode.com/problems/tiling-a-rectangle-with-the-fewest-squares/
result = [] # Given a rectangle of size n x m, find the minimum number of integer-sided squares that tile the rectangle.
for i in range(1, 101): # State consists of the height of each column already tiled.
for j in range(1, 101): # Given a state, find the lowest column and its index.
temp = customfunction.f(i, j) # For each adjacent column with the height of the lowest column, add a square and recurse.
if temp == z: # Time - O(m**3 n), mn possible states each taking O(m ** 2) to construct
result.append([i, j]) # Space - O(m**2 n)
elif temp > z:
break class Solution(object):
def tilingRectangle(self, rows, cols):
return result """
:type n: int
:type m: int
:rtype: int
# python_1001_to_2000/1238_Circular_Permutation_in_Binary_Representation.py - m """
if cols > rows: # swap so cols <= rows
_author_ = 'jake' cols, rows = rows, cols
_project_ = 'leetcode'
memo = {}
class Leaderboard(object):
def dp(state):
if min(state) == rows: # each col has height of rows def __init__(self):
return 0 self.user_score = defaultdict(int)
if state in memo:
return memo[state] def addScore(self, playerId, score):
"""
min_height = min(state) :type playerId: int
start = state.index(min_height) :type score: int
result = cols * rows :rtype: None
"""
state_list = list(state) self.user_score[playerId] += score
for end in range(start, cols):
if state[end] != min_height: def top(self, K):
break """
side = end - start + 1 :type K: int
if min_height + side > rows: # insufficient height :rtype: int
break """
state_list[start: end + 1] = [min_height + side] * side return sum(heapq.nlargest(K, self.user_score.values()))
result = min(result, dp(tuple(state_list)))
def reset(self, playerId):
memo[state] = result + 1 """
return result + 1 :type playerId: int
:rtype: None
return dp(tuple([0] * cols)) """
del self.user_score[playerId]
# python_1001_to_2000/1243_Array_Transformation.py
node_to_nbors[nbor].remove(leaf)
if len(node_to_nbors[nbor]) == 1:
# python_1001_to_2000/1244_Design_A_Leaderboard.py - m new_leaves.add(nbor)
else:
_author_ = 'jake' result += 2 # path extends in both directions
_project_ = 'leetcode'
leaves = new_leaves
# https://leetcode.com/problems/design-a-leaderboard/
# Design a Leaderboard class, which has 3 functions: return result
# addScore(playerId, score): Update the leaderboard by adding score to the given player's score.
# If there is no player with such id in the leaderboard, add him to the leaderboard with the given score.
# top(K): Return the score sum of the top K players.
# reset(playerId): Reset the score of the player with the given id to 0.
# It is guaranteed that the player was added to the leaderboard before calling this function. # python_1001_to_2000/1246_Palindrome_Removal.py - h
# Initially, the leaderboard is empty.
_author_ = 'jake'
# Map the user to a score. _project_ = 'leetcode'
# Make a heap of the K largest values for top.
# Time - O(1) for addScore and reset, O(n log n) for top # https://leetcode.com/problems/palindrome-removal/
# Space - O(n) # Given an integer array arr, in one move you can select a palindromic subarray
# arr[i], arr[i+1], ..., arr[j] where i <= j, and remove that subarray from the given array.
from collections import defaultdict # Note that after removing a subarray, the elements on the left and on the right of that subarray move
import heapq # to fill the gap left by the removal.
# Return the minimum number of moves needed to remove all numbers from the array.
# A subarray is called nice if there are k odd numbers on it.
# For each subarray there are 3 cases: # Return the number of nice sub-arrays.
# 1) We can always remove each integer individually.
# 2) If the last 2 integers are the same, we can remove them together and then find the result from the remainder. # Find the indices of odd numbers.
# 3) If any other integer is the same as the last integer, we can remove them and all the integers between for the same # For each block of consecutive k indices, find the number of even indices before and after this block.
# cost of removing all integers between. # Multiple the even indices before and after, since for each starting index we can construct a valid subarray with
# Time - O(n**3) # any odd index.
# Space - O(n**2) # Time - O(n)
# Space - O(n)
class Solution(object):
def minimumMoves(self, arr): class Solution(object):
""" def numberOfSubarrays(self, nums, k):
:type arr: List[int] """
:rtype: int :type nums: List[int]
""" :type k: int
memo = {} # memo[(i, j)] is the result for arr[i:j + 1] :rtype: int
"""
def dp(i, j): odds = [-1] + [i for i, num in enumerate(nums) if num % 2 == 1] + [len(nums)]
if i > j: result = 0
return 0
if (i, j) in memo: for j, end in enumerate(odds[k:-1], k): # ending indices of each consecutive k odd numbers
return memo[(i, j)] ends = odds[j + 1] - end # array can end from end to (excluding) next odd
starts = odds[j - k + 1] - odds[j - k]
result = dp(i, j - 1) + 1 # remove each number individually result += starts * ends
return result
if arr[j] == arr[j - 1]:
result = min(result, dp(i, j - 2) + 1)
if c1 == "x": # python_1001_to_2000/1250_Check_If_It_Is_a_Good_Array.py - h
if s1_excess_x: # convert "xx" and "yy" to "xy" in both strings
result += 1 _author_ = 'jake'
s1_excess_x = not s1_excess_x # toggle flag _project_ = 'leetcode'
else:
if s1_excess_y: # https://leetcode.com/problems/check-if-it-is-a-good-array/
result += 1 # Given an array nums of positive integers.
s1_excess_y = not s1_excess_y # Your task is to select some subset of nums, multiply each element by an integer and add all these numbers.
# The array is said to be good if you can obtain a sum of 1 from the array by any possible subset and multiplicand.
if s1_excess_x ^ s1_excess_y: # cannot equalize if only x or y are in excess # Return True if the array is good otherwise return False.
return -1
return result + int(s1_excess_x) + int(s1_excess_y) # swap "xy" and "yx" to "xy" and "xy" in 2 moves # If 2 numbers have a common denominator greater than 1, they can only combine to make multiples of that
# common denominator.
# Hence we iterate along the array finding the common denominator af all previous nums until it is 1.
# python_1001_to_2000/1248_Count_Number_of_Nice_Subarrays.py - m # Time - O(n log m) for n nums of maximum value m.
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def isGoodArray(self, nums):
# https://leetcode.com/problems/count-number-of-nice-subarrays/ """
# Given an array of integers nums and an integer k. :type nums: List[int]
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1254_Number_of_Closed_Islands.py - m
# https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/
# Given n and m which are the dimensions of a matrix initialized by zeros and given an array indices _author_ = 'jake'
# where indices[i] = [ri, ci]. _project_ = 'leetcode'
# For each pair of [ri, ci] you have to increment all cells in row ri and column ci by 1.
# Return the number of cells with odd values in the matrix after applying the increment to all indices. # https://leetcode.com/problems/number-of-closed-islands/
# Given a 2D grid consists of 0s (land) and 1s (water).
# Count whether the number of increments of each row and column is even or odd. # An island is a maximal 4-directionally connected group of 0s and a closed island
# For each cell, if the XOR of the row and column increments is odd then the value is odd. # is an island totally (all left, top, right, bottom) surrounded by 1s.
# Time - O(k + mn) for k increments # Return the number of closed islands.
# Space - O(m + n)
# Depth first search each land square.
class Solution(object): # Return boolean whether the island is closed or not.
def oddCells(self, n, m, indices): # Base cases of water and off grid are True.
""" # Explore all neighbours recursively, setting explored land to water to avoid cycles.
:type n: int # Time - O(mn)
:type m: int # Space - O(mn)
:type indices: List[List[int]]
:rtype: int class Solution(object):
""" def closedIsland(self, grid):
rows = [True] * n # True if even increments for each row """
cols = [True] * m # True if even increments for each col :type grid: List[List[int]]
:rtype: int
for r, c in indices: """
rows[r] = not rows[r] rows, cols = len(grid), len(grid[0])
cols[c] = not cols[c] nbors = [[1, 0], [0, 1], [-1, 0], [0, - 1]]
result = 0 def closed(r, c): # explore an island and return whether it is closed
for r in range(n): if r < 0 or r >= rows or c < 0 or c >= cols:
for c in range(m): return True # stop exploration if off grid or water
result += int(rows[r] ^ cols[c]) if grid[r][c] == 1:
return True
return result
is_closed = 0 < r < rows - 1 and 0 < c < cols - 1 # closed if not edge of grid
grid[r][c] = 1 # set visited land to water to avoid revisiting
for dr, dc in nbors:
# python_1001_to_2000/1253_Reconstruct_a_2-Row_Binary_Matrix.py - m is_closed = closed(r + dr, c + dc) and is_closed # recurse before and to ensure exploration
return is_closed
_author_ = 'jake'
_project_ = 'leetcode' islands = 0
for r in range(rows):
# https://leetcode.com/problems/reconstruct-a-2-row-binary-matrix/ for c in range(cols):
# Given the following details of a matrix with n columns and 2 rows : if grid[r][c] == 0: # only explore land
# The matrix is a binary matrix, which means each element in the matrix can be 0 or 1. islands += int(closed(r, c))
# The sum of elements of the 0-th(upper) row is given as upper.
# The sum of elements of the 1-st(lower) row is given as lower. return islands
# The sum of elements in the i-th column(0-indexed) is colsum[i],
# where colsum is given as an integer array with length n.
# Your task is to reconstruct the matrix with upper, lower and colsum.
# Return it as a 2-D integer array. # python_1001_to_2000/1255_Maximum_Score_Words_Formed_by_Letters.py - h
# If there are more than one valid solution, any of them will be accepted.
# If no valid solution exists, return an empty 2-D array. _author_ = 'jake'
_project_ = 'leetcode'
# Iterate along colsum.
# If colsum is 2, set both the upper and lower rows to 1 and decrement their required counts. # https://leetcode.com/problems/maximum-score-words-formed-by-letters/
# If colsum is 1, set the row with the greatest required count to 1. # Given a list of words, list of single letters (might be repeating) and score of every character.
# If we have to set more than upper or lower, or have not set all required upper or lower at the end, return []. # Return the maximum score of any valid set of words formed by using
# Time - O(n) # the given letters (words[i] cannot be used two or more times).
# Space - O(n) # It is not necessary to use all characters in letters and each letter can only be used once.
# Score of letters 'a', 'b', 'c', ... ,'z' is given by score[0], score[1], ... , score[25] respectively.
class Solution(object):
def reconstructMatrix(self, upper, lower, colsum): # Convert each word to a score.
""" # If we have insufficient letters to make the word, we can only get the score from the next word onwards.
:type upper: int # Else we can either make the word or not.
:type lower: int # If we make the word, reduce the counts of all letters in the word and recurse,
:type colsum: List[int] # then increment the counts after returning from recursion.
:rtype: List[List[int]] # Time - O(2 ** n)
""" # Space - O(n)
n = len(colsum)
upper_row, lower_row = [0] * n, [0] * n # default zeros from collections import Counter
class Solution(object): # Then starting from region2, recursively find each parent and if it is in region1's path,
def maxScoreWords(self, words, letters, score): # this is the smallest common region.
""" # Time - O(n) for n regions.
:type words: List[str] # Space - O(n)
:type letters: List[str]
:type score: List[int] class Solution(object):
:rtype: int def findSmallestRegion(self, regions, region1, region2):
""" """
char_counts = Counter(letters) # counts of letters that can be used :type regions: List[List[str]]
:type region1: str
word_scores = [] :type region2: str
a = ord("a") :rtype: str
for word in words: """
word_scores.append(sum(score[ord(c) - a] for c in word)) region_to_parent = {}
def can_make(word_counts): # is there sufficient remaining count to make a word? for region_list in regions:
for c, count in word_counts.items(): parent = region_list[0]
if c not in char_counts or char_counts[c] < count: for region in region_list[1:]:
return False region_to_parent[region] = parent
return True
region1_parents = [region1]
def helper(i): while region1_parents[-1] in region_to_parent:
if i == len(words): region1_parents.append(region_to_parent[region1_parents[-1]]) # parent of last member of list
return 0
region1_parents = set(region1_parents)
not_use = helper(i + 1) # score if we do not use words[i], try i + 1
while region2 not in region1_parents:
word_counts = Counter(words[i]) region2 = region_to_parent[region2]
if not can_make(word_counts):
return not_use # cannot make this word return region2
# Fins the intersection of the paths from each region to the root in the tree of regions.
# Create a mapping of each region to its parent. # python_1001_to_2000/1259_Handshakes_That_Don't_Cross.py - h
# Starting from region 1, recursively move up the tree creating the set of parents.
# https://leetcode.com/problems/greatest-sum-divisible-by-three/
# Given an array nums of integers,
# python_1001_to_2000/1260_Shift_2D_Grid.py # we need to find the maximum possible sum of elements of the array such that it is divisible by three.
return max(candidates)
# python_1001_to_2000/1261_Find_Elements_in_a_Contaminated_Binary_Tree.py - m
_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1263_Minimum_Moves_to_Move_a_Box_to_Their_Target_Location.py - h
return -1 # https://leetcode.com/problems/minimum-time-visiting-all-points/
# On a plane there are n points with integer coordinates points[i] = [xi, yi].
# Your task is to find the minimum time in seconds to visit all points.
# python_1001_to_2000/1265_Print_Immutable_Linked_List_in_Reverse.py - m # You can move according to the next rules:
# In one second always you can either move vertically, horizontally by one unit or diagonally
_author_ = 'jake' # (which means to move one unit vertically and one unit horizontally in one second).
_project_ = 'leetcode' # You have to visit the points in the same order as they appear in the array.
# https://leetcode.com/problems/print-immutable-linked-list-in-reverse/ # To move between points take the maximum of the move in the x direction and the move in the y direction.
# You are given an immutable linked list, # This is because we can move diagonally to cover the move in the shorter direction,
# print out all values of each node in reverse with the help of the following interface: # while also moving in the longer direction.
# ImmutableListNode: An interface of immutable linked list, you are given the head of the list. # Time - O(n)
# You need to use the following functions to access the linked list (you can't access the ImmutableListNode directly): # Space - O(1)
# ImmutableListNode.printValue(): Print value of the current node.
# ImmutableListNode.getNext(): Return the next node. class Solution(object):
# The input is only given to initialize the linked list internally. def minTimeToVisitAllPoints(self, points):
# You must solve this problem without modifying the linked list. """
# In other words, you must operate the linked list using only the mentioned APIs. :type points: List[List[int]]
:rtype: int
# If last node of the list, print it and return. """
# Else recurse for the next node, printing it out after the recursion returns. x1, y1 = points[0] # current point
# Time - O(n) time = 0
# Space - O(n), call stack of n functions.
# Alternatively, find the length of the list and iterate to each node in reverse order, for x2, y2 in points[1:]:
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1269_Number_of_Ways_to_Stay_in_the_Same_Place_After_Some_Steps.py - h
# https://leetcode.com/problems/count-servers-that-communicate/
# You are given a map of a server center, represented as a m * n integer matrix grid, _author_ = 'jake'
# where 1 means that on that cell there is a server and 0 means that it is no server. _project_ = 'leetcode'
# Two servers are said to communicate if they are on the same row or on the same column.
# Return the number of servers that communicate with any other server. # https://leetcode.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/
# You have a pointer at index 0 in an array of size arrLen.
# Iterate over grid, counting the number of servers in each row and each column. # At each step, you can move 1 position to the left, 1 position to the right in the array or stay in the same place.
# The iterate over grid again, incrementing the result for each server that has another server on the same # The pointer should not be placed outside the array at any time.
# row or column. # Given two integers steps and arrLen,
# Alternatively, store all servers in first loop to avoid iterateing over entire grid twice but use more space. # return the number of ways such that your pointer still at index 0 after exactly steps steps.
# Time - O(mn) # Since the answer may be too large, return it modulo 10^9 + 7.
# Space - O(m + n)
# Count the number of way to reach each index.
class Solution(object): # Do not count all indices of the array, since initially most are zero and if the array is much longer than
def countServers(self, grid): # the number of steps, we cannot return to index zero from all indices.
""" # For each step, iterate over the existing array elements that can reach index zero in the remaining steps.
:type grid: List[List[int]] # For x ways to reach index i, add x to the number of ways to reach indices i - 1, i and i + 1 on the next step,
:rtype: int # provided those new indices are within the bounds of the array.
""" # Time - O(n**2) for n steps
rows, cols = len(grid), len(grid[0]) # Space - O(n)
row_servers, cols_servers = [0] * rows, [0] * cols
class Solution(object):
for r in range(rows): def numWays(self, steps, arrLen):
for c in range(cols): """
if grid[r][c] == 1: :type steps: int
row_servers[r] += 1 :type arrLen: int
cols_servers[c] += 1 :rtype: int
"""
result = 0 i_to_count = [1] # i_to_count[i] is the number of ways to reach index i
for r in range(rows):
for c in range(cols): for step in range(steps):
if grid[r][c] == 1 and (row_servers[r] > 1 or cols_servers[c] > 1): new_i_to_count = [0] * (len(i_to_count) + 1) # extend length by 1 since we may move +1 index
result += 1
for i, count in enumerate(i_to_count[:steps - step + 1]): # only consider indices where we can move
return result if i + 1 < arrLen: # back to index 0 in remaining steps
new_i_to_count[i + 1] += count
class Solution2(object): new_i_to_count[i] += count
def countServers(self, grid): if i - 1 >= 0:
rows, cols = len(grid), len(grid[0]) new_i_to_count[i - 1] += count
row_servers, cols_servers = [0] * rows, [0] * cols
servers = set() i_to_count = new_i_to_count
# https://leetcode.com/problems/hexspeak/
# python_1001_to_2000/1268_Search_Suggestions_System.py - m # A decimal number can be converted to its Hexspeak representation
# by first converting it to an uppercase hexadecimal string,
_author_ = 'jake' # then replacing all occurrences of the digit 0 with the letter O, and the digit 1 with the letter I.
_project_ = 'leetcode' # Such a representation is valid if and only if it consists only of the letters in the set
# {"A", "B", "C", "D", "E", "F", "I", "O"}.
# https://leetcode.com/problems/search-suggestions-system/ # Given a string num representing a decimal integer N,
# Given an array of strings products and a string searchWord. # return the Hexspeak representation of N if it is valid, otherwise return "ERROR".
# We want to design a system that suggests at most three product names from products
# after each character of searchWord is typed. # Convert to hex.
# Suggested products should have common prefix with the searchWord. # Return ERROR if any digit apart from 0 or 1 remains.
# If there are more than three products with a common prefix return the three lexicographically minimums products. # Replace 0 with O and replace 1 with I.
# Return list of lists of the suggested products after each character of searchWord is typed. # Time - O(n)
# Space - O(n)
# Sort the list of products.
# For each prefix of searchWord, binary search the list of products class Solution(object):
# and add the list of the next 3 with the same prefix to the result. def toHexspeak(self, num):
# Time - O(n log n + k log n) for n products and searchWord of length k """
# Space - O(n) :type num: str
:rtype: str
import bisect """
s = format(int(num), "X") # upper case hex without 0X prefix.
class Solution(object): if any(str(i) in s for i in range(3, 10)):
def suggestedProducts(self, products, searchWord): return "ERROR"
""" s = s.replace("0", "O")
:type products: List[str] return s.replace("1", "I")
:type searchWord: str
:rtype: List[List[str]]
"""
# python_1001_to_2000/1272_Remove_Interval.py - m
# Map each node to its children (note this is not a binary tree, there can be any number of children). _author_ = 'jake'
# Recursive helper function sums all the subtrees including the node itself, and counts the nodes. _project_ = 'leetcode'
# If the sum is zero, delete the subtree by setting the node count to zero.
# Time - O(n) # https://leetcode.com/problems/find-winner-on-a-tic-tac-toe-game/
# Space - O(n) # Tic-tac-toe is played by two players A and B on a 3 x 3 grid.
# Here are the rules of Tic-Tac-Toe:
from collections import defaultdict # Players take turns placing characters into empty squares (" ").
# The first player A always places "X" characters, while the second player B always places "O" characters.
class Solution(object): # "X" and "O" characters are always placed into empty squares, never on filled ones.
def deleteTreeNodes(self, nodes, parents, values): # The game ends when there are 3 of the same (non-empty) character filling any row, column, or diagonal.
""" # The game also ends if all squares are non-empty.
:type nodes: int # No more moves can be played if the game is over.
:type parents: List[int] # Given an array moves where each element is another array of size 2 corresponding to the
:type values: List[int] # row and column of the grid where they mark their respective character in the order in which A and B play.
:rtype: int # Return the winner of the game if it exists (A or B),
""" # in case the game ends in a draw return "Draw",
node_children = defaultdict(list) # if there are still movements to play return "Pending".
for child, parent in enumerate(parents): # You can assume that moves is valid (It follows the rules of Tic-Tac-Toe),
node_children[parent].append(child) # the grid is initially empty and A will play first.
def helper(node): # return (sum, node count) of subtree from node # Denominate player A as 1 and player B as -1.
subtree_sum = values[node] # Find the sum of move for each row, column and diagonal.
subtree_count = 1 # If any line sums to 3 times the value of a player, that player wins.
# Else there is a draw if all squares are full, else pending.
for child in node_children[node]: # sum and count all subtrees # Time - O(1)
child_sum, child_count = helper(child) # Space - O(1)
subtree_sum += child_sum
subtree_count += child_count class Solution(object):
def tictactoe(self, moves):
if subtree_sum == 0: # reset count to zero since subtree is deleted """
subtree_count = 0 :type moves: List[List[int]]
:rtype: str
return (subtree_sum, subtree_count) """
A, B = 1, -1
_, result = helper(0) player = A
return result row_sums, col_sums = [0 for _ in range(3)], [0 for _ in range(3)]
player = -player # change player # Helper function returns the minimum chars to change to make k palindromes from a suffix of s.
# If the length of the suffix is the same as k, each char can be a palindrome and no changes are needed.
lines = row_sums + col_sums + [up_diag, down_diag] # If k == 1, the suffix must be changed to a single palindrome.
if any(line == 3 * A for line in lines): # Else convert the substring s[i:j + 1] to a palindrome and recurse for k - 1 remaining substrings.
return "A" # Time - O(n ** 3 * k) since O(nk) calls to helper, each with O(n) iterations over j, each taking O(n) for cost().
if any(line == 3 * B for line in lines): # Space - O(nk)
return "B"
return "Draw" if len(moves) == 9 else "Pending" class Solution(object):
def palindromePartition(self, s, k):
"""
:type s: str
:type k: int
# python_1001_to_2000/1276_Number_of_Burgers_with_No_Waste_of_Ingredients.py - m :rtype: int
"""
_author_ = 'jake' n = len(s)
_project_ = 'leetcode'
def cost(left, right): # cost to change s[i:j + 1] into a palindrome
# https://leetcode.com/problems/number-of-burgers-with-no-waste-of-ingredients/ result = 0
# Given two integers tomatoSlices and cheeseSlices. The ingredients of different burgers are as follows: while left < right:
# Jumbo Burger: 4 tomato slices and 1 cheese slice. if s[left] != s[right]:
# Small Burger: 2 Tomato slices and 1 cheese slice. result += 1
# Return [total_jumbo, total_small] so that the number of remaining tomatoSlices equal to 0 left += 1
# and the number of remaining cheeseSlices equal to 0. right -= 1
# If it is not possible to make the remaining tomatoSlices and cheeseSlices equal to 0 return []. return result
# We cannot reach a solution for an odd number of tomato or tomato less than 2 * cheese or tomato more than 4 * cheese. memo = {}
# Else solve the linear equations:
# jumbo + small = cheese def helper(i, k): # chars to change s[i:] into k palindromes
# 4 * jumbo + 2 * small = tomato if k >= n - i:
# Time - O(1) return 0
# Space - O(1) if k == 1:
return cost(i, n - 1)
class Solution(object): if (i, k) in memo:
def numOfBurgers(self, tomatoSlices, cheeseSlices): return memo[(i, k)]
"""
:type tomatoSlices: int chars_changed = float("inf")
:type cheeseSlices: int for j in range(i, n - k + 1): # until k - 1 == remaining string length
:rtype: List[int] chars_changed = min(chars_changed, cost(i, j) + helper(j + 1, k - 1))
"""
if tomatoSlices % 2 == 1 or tomatoSlices < 2 * cheeseSlices or tomatoSlices > 4 * cheeseSlices: memo[(i, k)] = chars_changed
return [] return chars_changed
# python_1001_to_2000/1281_Subtract_the_Product_and_Sum_of_Digits_of_an_Integer.py
return sum(map(sum, matrix)) # map sums each row, then sum row sums _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/group-the-people-given-the-group-size-they-belong-to/
# There are n people whose IDs go from 0 to n - 1 and each person belongs exactly to one group.
# python_1001_to_2000/1278_Palindrome_Partitioning_III.py - h # Given the array groupSizes of length n telling the group size each person belongs to,
# return the groups there are and the people's IDs each group includes. # Time - O(mn * 2 ** mn), since there are 2 ** mn states
# You can return any solution in any order and the same applies for IDs. # Space - O(mn * 2 ** mn)
# Also, it is guaranteed that there exists at least one solution.
from collections import defaultdict
# Create a mapping of group size to its members.
# Iterate over the group sizes, adding each member to a group of the corresponding size. class Solution(object):
# A new group is started if there is no group of the correct size. def minFlips(self, mat):
# When a group has the correct number of members, add it to result and start a new empty group. """
# Time - O(n) :type mat: List[List[int]]
# Space - O(n) :rtype: int
"""
from collections import defaultdict rows, cols = len(mat), len(mat[0])
linear = []
class Solution(object): for row in mat:
def groupThePeople(self, groupSizes): linear += [bool(cell) for cell in row]
"""
:type groupSizes: List[int] linear_nbors = defaultdict(list) # map linear index to nbors
:rtype: List[List[int]] for r in range(rows):
""" for c in range(cols):
size_to_group = defaultdict(list) i = r * cols + c
result = [] linear_nbors[i].append(i)
for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]:
for i, size in enumerate(groupSizes): if 0 <= r + dr < rows and 0 <= c + dc < cols: # within matrix only
size_to_group[size].append(i) j = (r + dr) * cols + (c + dc)
linear_nbors[i].append(j)
if len(size_to_group[size]) == size: # group is full
result.append(size_to_group[size]) frontier = {tuple(linear)} # immutable tuple can be added to set
size_to_group[size] = [] # start a new group steps = 0
seen = set() # avoid repeating states
return result
while frontier:
new_frontier = set()
class Solution(object):
def smallestDivisor(self, nums, threshold): # python_1001_to_2000/1286_Iterator_for_Combination.py - m
"""
:type nums: List[int] _author_ = 'jake'
:type threshold: int _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/iterator-for-combination/
def le_threshold(divisor): # check if sum of (nums divided by divisor) is <= threshold # Design an Iterator class, which has:
return sum((num + divisor - 1) // divisor for num in nums) <= threshold # A constructor that takes a string characters of sorted distinct lowercase English letters
# and a number combinationLength as arguments.
low, high = 1, max(nums) # A function next() that returns the next combination of length combinationLength in lexicographical order.
while low < high: # A function hasNext() that returns True if and only if there exists a next combination.
guess = (low + high) // 2
if le_threshold(guess): # Maintain a combination, which is a list of indices of characters of the next combination.
high = guess # Also set the final combination as combinationLength indices ending with the last index of characters.
else: # Find the next combination by iterating backwards to find an index that is less than its final index.
low = guess + 1 # Increment the index and set all later indices in ascending order.
# Time - O(1) for init and hasNext, O(n) for next
return low # Space - O(n)
class CombinationIterator(object):
# python_1001_to_2000/1284_Minimum_Number_of_Flips_to_Convert_Binary_Matrix_to_Zero_Matrix.py - h
def __init__(self, characters, combinationLength):
_author_ = 'jake' """
_project_ = 'leetcode' :type characters: str
:type combinationLength: int
# https://leetcode.com/problems/minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix/ """
# Given a m x n binary matrix mat. self.chars = characters
# In one step, you can choose one cell and flip it and all the four neighbours of it if they exist self.combination = list(range(combinationLength)) # the previous combination of indices of characters
# Flip is changing 1 to 0 and 0 to 1. self.combination[-1] -= 1 # set to combination before the first
# A pair of cells are called neighboors if they share one edge. n = len(characters)
# Return the minimum number of steps required to convert mat to a zero matrix or -1 if you cannot. self.final = list(range(n - combinationLength, n)) # the final combination of indices of characters
# Binary matrix is a matrix with all cells equal to 0 or 1 only.
# Zero matrix is a matrix with all cells equal to 0. def next(self):
"""
# Convert the matrix to a linear list of bool, by row. :rtype: str
# Create a mapping from each linear index to its neighbours in the matrix. """
# Breadth-first search the matrix states. i = len(self.combination) - 1
# Frontier consists of reachable states. while self.combination[i] == self.final[i]: # first index that can be incremented
# For each state in frontier, flip each cell and its neighbours to create a new state. i -= 1
# For each row, each column is incremented by the smallest path from the previous row if the smallest path from
self.combination[i] += 1 # the previous row is not the smallest, else is incremented by the second smallest path from the previous row.
for j in range(i + 1, len(self.combination)): # Time - O(mn)
self.combination[j] = self.combination[j - 1] + 1 # set all next indices in ascending order # Space - O(mn)
return result if (r, c) in visited and neg_elims >= visited[(r, c)]: # have visited with same or more eliminations
continue
visited[(r, c)] = neg_elims
# python_1001_to_2000/1292_Maximum_Side_Length_of_a_Square_with_Sum_Less_than_or_Equal_to_Threshold.py - m for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]:
r2, c2 = r + dr, c + dc
_author_ = 'jake' if r2 < 0 or r2 >= rows or c2 < 0 or c2 >= cols:
_project_ = 'leetcode' continue
heapq.heappush(queue, (heuristic(r2, c2) + steps + 1, neg_elims + grid[r2][c2], steps + 1, r2, c2))
# https://leetcode.com/problems/maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold/
# Given a m x n matrix mat and an integer threshold. return -1
# Return the maximum side-length of a square with a sum less than or equal to threshold
# or return 0 if there is no such square.
# Iterate over matrix, converting each cell to the cumulative sum from (0, 0) to the cell. # python_1001_to_2000/1295_Find_Numbers_with_Even_Number_of_Digits.py
# For each cell, if there is sufficient space to create a square of side length max_side + 1,
# find the sum of the square and increment max_side if the sum is <= threshold. _author_ = 'jake'
# Time - O(mn) _project_ = 'leetcode'
# Space - O(mn)
# https://leetcode.com/problems/find-numbers-with-even-number-of-digits/
class Solution(object): # Given an array nums of integers, return how many of them contain an even number of digits.
def maxSideLength(self, mat, threshold):
""" # Convert each num to string and check if length is divisible by 2.
:type mat: List[List[int]] # Time - O(n log k) for k numbers of max value k
:type threshold: int # Space - O(log k)
:rtype: int
""" class Solution(object):
rows, cols = len(mat), len(mat[0]) def findNumbers(self, nums):
max_side = 0 """
:type nums: List[int]
def val_or_zero(row, col): # return matrix value or 0 if not in matrix :rtype: int
return mat[row][col] if row >= 0 and col >= 0 else 0 """
return sum(len(str(num)) % 2 == 0 for num in nums)
for r in range(rows):
for c in range(cols):
mat[r][c] += val_or_zero(r - 1, c) + val_or_zero(r, c - 1) - val_or_zero(r - 1, c - 1)
# python_1001_to_2000/1296_Divide_Array_in_Sets_of_K_Consecutive_Numbers.py - m
if r >= max_side and c >= max_side:
next_side_square = val_or_zero(r, c) _author_ = 'jake'
next_side_square -= val_or_zero(r - max_side - 1, c) _project_ = 'leetcode'
next_side_square -= val_or_zero(r, c - max_side - 1)
next_side_square += val_or_zero(r - max_side - 1, c - max_side - 1) # https://leetcode.com/problems/divide-array-in-sets-of-k-consecutive-numbers/
if next_side_square <= threshold: # Given an array of integers nums and a positive integer k,
max_side += 1 # find whether it's possible to divide this array into sets of k consecutive numbers
# Return True if its possible otherwise return False.
return max_side
# Count each num.
# Find the count of each num in sorted order,
# and check if there are at least as many of each k - 1 subsequent digits.
# python_1001_to_2000/1293_Shortest_Path_in_a_Grid_with_Obstacles_Elimination.py - h # Time - O(n log n)
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' from collections import Counter
# Maintain a sliding window of length minSize, counting the frequency of each letter in the window.
# Update the window with each end letter.
# If window is of length >= minSise then check if window has <= maxLetters, then remove start letter.
# Time - O(n) # python_1001_to_2000/1299_Replace_Elements_with_Greatest_Element_on_Right_Side.py
# Space - O(n)
_author_ = 'jake'
from collections import defaultdict _project_ = 'leetcode'
# python_1001_to_2000/1298_Maximum_Candies_You_Can_Get_from_Boxes.py - h # python_1001_to_2000/1300_Sum_of_Mutated_Array_Closest_to_Target.py - m
# https://leetcode.com/problems/maximum-candies-you-can-get-from-boxes/ # https://leetcode.com/problems/sum-of-mutated-array-closest-to-target/
# Given n boxes, each box is given in the format [status, candies, keys, containedBoxes] where: # Given an integer array arr and a target value target,
# status[i]: an integer which is 1 if box[i] is open and 0 if box[i] is closed. # return the integer value such that when we change all the integers larger than value
# candies[i]: an integer representing the number of candies in box[i]. # in the given array to be equal to value,
# keys[i]: an array contains the indices of the boxes you can open with the key in box[i]. # the sum of the array gets as close as possible (in absolute difference) to target.
# containedBoxes[i]: an array contains the indices of the boxes found in box[i]. # In case of a tie, return the minimum such integer.
# You will start with some boxes given in initialBoxes array. # Notice that the answer is not necessarily a number from arr.
# You can take all the candies in any open box and you can use the keys in it to
# open new boxes and you also can use the boxes you find in it. # Binary search for the first integer ceiling that makes the array sum >= target.
# Return the maximum number of candies you can get following the rules above. # Then check if integer - 1 ceiling can make the array sum closer to the target.
# Time - O(n log k) where k is the range of values in arr
# Breadth first search. # Space - O(1)
# Maintain sets of all open and unopened boxes reached.
# For each opened box in each round, take all candies, use keys to open all boxes and update set of unopened boxes. class Solution(object):
# After visiting each opened box, update the opened boxes. def findBestValue(self, arr, target):
# Time - O(n + m) for n boxes and m total keys (same key may be in multiple boxes). """
# Space - O(n) :type arr: List[int]
:type target: int
class Solution(object): :rtype: int
def maxCandies(self, status, candies, keys, containedBoxes, initialBoxes): """
""" low, high = 0, max(arr)
:type status: List[int]
:type candies: List[int] def ceiling(x):
:type keys: List[List[int]] return sum(min(a, x) for a in arr)
:type containedBoxes: List[List[int]]
:type initialBoxes: List[int] while low < high:
:rtype: int mid = (low + high) // 2
""" value = ceiling(mid) - target
OPEN, VISITED = 1, 2 if value >= 0:
high = mid
result = 0 else:
open_boxes, closed_boxes = set(), set() low = mid + 1
for initial_box in initialBoxes: # put in either opened or unopened set
container = open_boxes if status[initial_box] == OPEN else closed_boxes value = ceiling(low) - target
container.add(initial_box) lower = ceiling(low - 1) - target
return low - 1 if abs(lower) <= abs(value) else low # return low - 1 if closer or same diff to target
while open_boxes:
def helper(i):
if i < 0 or i >= n:
return False
if arr[i] == 0:
return True
if i in visited:
return False
visited.add(i)
return helper(start)
# python_1001_to_2000/1309_Decrypt_String_from_Alphabet_to_Integer_Mapping.py
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/decrypt-string-from-alphabet-to-integer-mapping/
# Given a string s formed by digits ('0' - '9') and '#' . We want to map s to English lowercase characters as follows:
# Characters ('a' to 'i') are represented by ('1' to '9') respectively.
# Characters ('j' to 'z') are represented by ('10#' to '26#') respectively.
# Return the string formed after mapping.
# It's guaranteed that a unique mapping will always exist.
# Iterate along s. If the char at position i + 2 is "#" then convert s[i:i + 2] to an integer.
# Else convert s[i] to an integer.
# Time - O(n)
# Space - O(n)
class Solution(object):
def freqAlphabets(self, s):
"""
:type s: str
:rtype: str
"""
result = []
n = len(s)
i = 0
while i < n:
if i + 2 < n and s[i + 2] == "#":
result.append(chr(int(s[i:i + 2]) + ord("a") - 1))
i += 3
else:
result.append(chr(int(s[i]) + ord("a") - 1))
i += 1
return "".join(result)
# python_1001_to_2000/1310_XOR_Queries_of_a_Subarray.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/xor-queries-of-a-subarray/
# Given the array arr of positive integers and the array queries where queries[i] = [Li, Ri],
# for each query i compute the XOR of elements from Li to Ri (that is, arr[Li] xor arr[Li+1] xor ... xor arr[Ri] ).
# Return an array containing the result for the given queries.
class Solution(object):
def xorQueries(self, arr, queries):
"""
:type arr: List[int]
:type queries: List[List[int]]
:rtype: List[int]
"""
xor = [0]
for num in arr:
xor.append(xor[-1] ^ num)
result = []
for start, end in queries:
result.append(xor[end + 1] ^ xor[start])
return result