0% found this document useful (0 votes)
2 views

github_jakehoare_leetcode_4splits_75scale_with_difficulty

The document contains Python solutions to various LeetCode problems, including algorithms for finding the longest substring without repeating characters, adding two numbers represented by linked lists, and converting strings to integers. Each solution is accompanied by a brief description of the problem, the time and space complexity, and the approach used. The solutions are structured in a class format with methods that implement the respective algorithms.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

github_jakehoare_leetcode_4splits_75scale_with_difficulty

The document contains Python solutions to various LeetCode problems, including algorithms for finding the longest substring without repeating characters, adding two numbers represented by linked lists, and converting strings to integers. Each solution is accompanied by a brief description of the problem, the time and space complexity, and the approach used. The solutions are structured in a class format with methods that implement the respective algorithms.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 149

class Solution(object):

# python_1_to_1000/001_Two_Sum.py def lengthOfLongestSubstring(self, s):


"""
_author_ = 'jake' :type s: str
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/two-sum/ last_seen = {} # mapping from character to its last seen index in s
# Given an array of integers, return indices of the two numbers start = 0 # start index of current substring
# such that they add up to a specific target. longest = 0
# You may assume that each input would have exactly one solution.
for i, c in enumerate(s):
# Maintain a mapping from each number to its index.
# Check if target - num has already been found. if c in last_seen and last_seen[c] >= start:
# Time - O(n) # start a new substring after the previous sighting of c
# Space - O(n) for the dictionary start = last_seen[c] + 1
else:
class Solution(object): longest = max(longest, i - start + 1)
def twoSum(self, nums, target):
""" last_seen[c] = i # update the last sighting index
:type nums: List[int]
:type target: int return longest
:rtype: List[int]
"""

num_to_index = {} # key is number, value is index in nums # python_1_to_1000/004_Median_of_Two_Sorted_Arrays.py - h

for i, num in enumerate(nums): _author_ = 'jake'


_project_ = 'leetcode'
if target - num in num_to_index:
return [num_to_index[target - num], i] # https://leetcode.com/problems/median-of-two-sorted-arrays/
# There are two sorted arrays nums1 and nums2 of size m and n respectively.
num_to_index[num] = i # Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

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]

while l1 or l2 or carry: if mid_A < mid_B:


if l1: return get_kth_smallest(a_start + k // 2, b_start, k - k // 2)
carry += l1.val return get_kth_smallest(a_start, b_start + k // 2, k - k // 2)
l1 = l1.next
if l2: right = get_kth_smallest(0, 0, 1 + (len(A) + len(B)) // 2)
carry += l2.val if (len(A) + len(B)) % 2 == 1: # odd total length
l2 = l2.next return right
prev.next = ListNode(carry % 10)
prev = prev.next left = get_kth_smallest(0, 0, (len(A) + len(B)) // 2)
carry //= 10 return (left + right) / 2.0

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()

# python_1_to_1000/006_ZigZag_Conversion.py - m class Solution(object):


def myAtoi(self, str):
_author_ = 'jake' """
_project_ = 'leetcode' :type str: str
:rtype: int
# https://leetcode.com/problems/zigzag-conversion/ """
# The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: str = str.strip() # remove padding spaces
# P A H N
# A P L S I I G negative = False # remove leading + or -
# Y I R if str and str[0] == '-':
# And then read line by line: "PAHNAPLSIIGYIR" negative = True
# Write the code that will take a string and make this conversion given a number of rows. if str and (str[0] == '+' or str[0] == '-'):
str = str[1:]
# Build a list of chars for each row by tracking the direction of movement up or down and if not str:
# reversing direction at end rows. return 0
# Time - O(n), use a list of chars and join instead of adding to immutable strings.
# Space - O(n) digits = {i for i in '0123456789'}
result = 0
class Solution(object): for c in str: # record integer upto first non-digit
def convert(self, s, numRows): if c not in digits:
""" break
:type s: str result = result * 10 + int(c)
:type numRows: int
:rtype: str if negative:
""" result = -result
if numRows == 1:
return s result = max(min(result, 2**31 - 1), -2**31) # keep within 4 byte signed integer bounds
return result
zigzag = [[] for _ in range(numRows)]
row = 0
direction = -1 # -1 for up, +1 for down
# python_1_to_1000/009_Palindrome_Number.py
for c in s:
zigzag[row].append(c) _author_ = 'jake'
if row == 0 or row == numRows-1: # change direction _project_ = 'leetcode'
direction = -direction
row += direction # https://leetcode.com/problems/palindrome-number/
# Determine whether an integer is a palindrome. Do this without extra space.
return "".join([c for r in zigzag for c in r]) # flatten list of lists
# Check equivalence of first and last characters, moving inwards.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/007_Reverse_Integer.py - m
class Solution(object):
_author_ = 'jake' def isPalindrome(self, x):
_project_ = 'leetcode' """
:type x: int
# https://leetcode.com/problems/reverse-integer/ :rtype: bool
# Reverse digits of an integer. """
# Example1: x = 123, return 321 s = str(x)
left, right = 0, len(s)-1 # Input is guaranteed to be within the range from 1 to 3999.

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)

for i in range(len(s)+1): return "".join(roman)


for j in range(1, len(p)+1):
pattern = p[j-1]

if pattern == '.': # dot matches any last character of s # python_1_to_1000/013_Roman_to_Integer.py


matched[i][j] = (i != 0 and matched[i-1][j-1])
_author_ = 'jake'
elif pattern == '*': # either ignore last 2 chars of p, or ignore last char of s provided it _project_ = 'leetcode'
star = p[j-2] # matches the star char
matched[i][j] = matched[i][j-2] or (i > 0 and matched[i-1][j] and (star == s[i-1] or star == '.')) # https://leetcode.com/problems/roman-to-integer/
# Given a roman numeral, convert it to an integer.
else: # pattern must match the last character of s # Input is guaranteed to be within the range from 1 to 3999.
matched[i][j] = (i != 0 and matched[i-1][j-1] and s[i-1] == pattern)
# Iterate along s, checking if the next 2 characters match any valid roman numeral.
return matched[-1][-1] # If so, add the value of the numeral to the result. Otherwise the next single
# character must match a numeral, which is added to the result.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/011_Container_With_Most_Water.py - m
class Solution(object):
_author_ = 'jake' def romanToInt(self, s):
_project_ = 'leetcode' """
:type s: str
# https://leetcode.com/problems/container-with-most-water/ :rtype: int
# Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai), """
# n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). doubles = {'CM' : 900, 'CD' : 400, 'XC' : 90, 'XL' : 40, 'IX' :9, 'IV' : 4}
# Find two lines, which together with x-axis forms a container, such that the container contains the most water. singles = {'M' : 1000, 'D' : 500, 'C' : 100, 'L' : 50, 'X' : 10, 'V' : 5, 'I' : 1}

# 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]

:rtype: str :type target: int


""" :rtype: int
if not strs: """
return '' nums.sort()
closest = float('inf') # default if len(nums) < 3
strs.sort()
first = strs[0] for i in range(len(nums) - 2):
last = strs[-1] j = i + 1
k = len(nums) - 1
i = 0
while i < len(first) and i < len(last) and first[i] == last[i]: while j < k:
i += 1
return first[:i] triple = nums[i] + nums[j] + nums[k]
if triple == target: # early return, cannot do better
return target
if abs(triple - target) < abs(closest - target):
# python_1_to_1000/015_3Sum.py - m closest = triple

_author_ = 'jake' if triple - target > 0:


_project_ = 'leetcode' k -= 1
else:
# https://leetcode.com/problems/3sum/ j += 1
# Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0?
# Find all unique triplets in the array which gives the sum of zero. return closest
# Note: The solution set must not contain duplicate triplets.

# 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

if n == 2: # base case of linear bidirectional search for n == 2


left = 0
right = len(nums)-1 # python_1_to_1000/021_Merge_Two_Sorted_Lists.py
while left < right:
if nums[left] + nums[right] == target: _author_ = 'jake'
results.append(partial + [nums[left], nums[right]]) _project_ = 'leetcode'
left += 1
right -= 1 # https://leetcode.com/problems/merge-two-sorted-lists/
while nums[right] == nums[right+1] and right > left: # move to next different number if target # Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes
found of the first two lists.
right -=1
elif nums[left] + nums[right] < target: # Whilst there are nodes in both lists, link to lowest head node and increment that list. Finally link to
left += 1 # the list with remaining nodes.
else: # Time - O(m+n)
right -= 1 # Space - O(1)

else: # Definition for singly-linked list.


for i in range(len(nums)-n+1): # for all possible first numbers nums[i] class ListNode(object):
if i == 0 or nums[i] != nums[i-1]: # if not duplicate def __init__(self, x):
self.n_sum(nums[i+1:], target-nums[i], partial + [nums[i]], n-1, results) self.val = x
self.next = None

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

# Definition for singly-linked list. for i in range(len(nums)):


class ListNode(object): if i == 0 or nums[i] != nums[i - 1]:
def __init__(self, x): nums[next_new] = nums[i]
self.val = x next_new += 1
self.next = None
return next_new
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode # python_1_to_1000/027_Remove_Element.py
:rtype: ListNode
""" _author_ = 'jake'
prev = dummy = ListNode(None) _project_ = 'leetcode'

while head and head.next: # https://leetcode.com/problems/remove-element/


next_head = head.next.next # Given an array and a value, remove all instances of that value in place and return the new length.
prev.next = head.next # Do not allocate extra space for another array, you must do this in place with constant memory.
head.next.next = head # The order of elements can be changed. It doesn't matter what you leave beyond the new length.
prev = head
head = next_head # Maintain pointer to next index to be used for any number not equal to val.
# Time - O(n)
prev.next = head # Space - O(1)
return dummy.next
class Solution(object):
def removeElement(self, nums, val):
"""
# python_1_to_1000/025_Reverse_Nodes_in_k-Group.py - h :type nums: List[int]
:type val: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
next_free = 0
# https://leetcode.com/problems/reverse-nodes-in-k-group/ for i, num in enumerate(nums):
# Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. if num != val:
# If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. nums[next_free] = num
next_free += 1
return next_free # For each stripe, maintain a sliding window of matched words.
# Time - O(n) where n = len(s). word_len stripes, each of which we move the start or end of the matched window
# forwards n / word_len times.
# Space - O(len(words)*word_len) for dictionary
# python_1_to_1000/028_Implement_strStr().py
from collections import Counter
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def findSubstring(self, s, words):
# https://leetcode.com/problems/implement-strstr/ """
# Implement strStr(). :type s: str
# Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. :type words: List[str]
:rtype: List[int]
# For each pssible starting point in haystack, check characters match with needle and break if not. """
# Alternatively KMP would improve expected time complexity. result = []
# Time - O(n^2) word_len = len(words[0])
# Space - O(1)
for stripe in range(word_len): # each stripe starts at a different position in s, modulo word_len
class Solution(object):
def strStr(self, haystack, needle): i = stripe # the next index in s that we want to match a word
""" to_match = len(words) # number of words still to be matched
:type haystack: str freq = Counter(words) # frequency of each words to be matched
:type needle: str
:rtype: int while i + to_match*word_len <= len(s): # remainder of s is long enough to hold remaining unmatched words
"""
for i in range(len(haystack) - len(needle) + 1): word = s[i:i+word_len] # next part of s attempting to be matched
for j in range(len(needle)): if word in freq: # match, decrement freq count
if haystack[i + j] != needle[j]: freq[word] -= 1
break if freq[word] == 0:
else: # for/else reaches here if no break del freq[word]
return i to_match -= 1
return -1 i += word_len
if to_match == 0: # all matched
result.append(i - word_len*len(words))

# python_1_to_1000/029_Divide_Two_Integers.py - m elif to_match != len(words): # some words have been matched


nb_matches = len(words) - to_match
_author_ = 'jake' first_word = s[i - nb_matches*word_len:i - (nb_matches-1)*word_len]
_project_ = 'leetcode' freq.setdefault(first_word, 0) # put first word matched back in dictionary
freq[first_word] += 1
# https://leetcode.com/problems/divide-two-integers/ to_match += 1
# Divide two integers without using multiplication, division and mod operator.
# If overflow, return MAX_INT. else: # no words matched
i += word_len
# Repeatedly double the divisor until it would exceed the dividend. Then repeatedly halve the divisor, subtracting
# it from the dividend whenever possible. return result
# Time - O(log n)
# Space - O(1)

class Solution(object): # python_1_to_1000/031_Next_Permutation.py - m


def divide(self, dividend, divisor):
""" _author_ = 'jake'
:type dividend: int _project_ = 'leetcode'
:type divisor: int
:rtype: int # https://leetcode.com/problems/next-permutation/
""" # Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
if divisor == 0: # If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending
return None order).
diff_sign = (divisor < 0) ^ (dividend < 0) # The replacement must be in-place, do not allocate extra memory.
dividend = abs(dividend)
divisor = abs(divisor) # Starting from the last number, move forward to find the first decrease nums[i].
# Find the smallest number bigger than nums[i], nums[j]. Swap nums[i] and nums[j].
result = 0 # Reverse all from i+1 onwards, or whole array if no decrease found in first step.
max_divisor = divisor # Time - O(n)
shift_count = 1 # Space - O(1)

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

for i, c in enumerate(s): mid = (left + right) // 2


if c == ")" and stack and s[stack[-1]] == '(': if target > nums[mid]:
stack.pop() # close matches an open on the stack left = mid + 1
else: else:
stack.append(i) # puch open brackets or unmatched close brackets right = mid - 1

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'

_author_ = 'jake' # https://leetcode.com/problems/search-insert-position/


_project_ = 'leetcode' # Given a sorted array and a target value, return the index if the target is found.
# If not, return the index where it would be if it were inserted in order.
# https://leetcode.com/problems/search-in-rotated-sorted-array/ # You may assume no duplicates in the array.
# Suppose a sorted array is rotated at some pivot unknown to you beforehand.
# (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). # Iterative binary search until left > right or left or right move outside array.
# You are given a target value to search. If found in the array return its index, otherwise return -1. # Return left (the greater index), which would be the new index of inserted entry (could be len(nums) but not -1).
# You may assume no duplicate exists in the array. # Time - O(log n)
# Space - O(1)
# Binary search. If one side is sorted and target is in that region then rescurse on that side or else other side.
# Time - O(log n), half of the array is eliminated for every recursion. class Solution(object):
# Space - O(1) def searchInsert(self, nums, target):
"""
class Solution(object): :type nums: List[int]
def search(self, nums, target): :type target: int
""" :rtype: int
:type nums: List[int] """
:type target: int left = 0
:rtype: int right = len(nums)
"""
left, right = 0, len(nums) - 1 while left <= right and left < len(nums) and right >= 0:
mid = (left + right) // 2
while left <= right: if target == nums[mid]:
return mid
mid = (left + right) // 2 if target < nums[mid]:
right = mid - 1
if nums[mid] == target: else:
return mid left = mid + 1

if nums[left] <= nums[mid]: # LHS is sorted return left


if target >= nums[left] and target < nums[mid]: # target is on LHS
right = mid - 1
else: # python_1_to_1000/036_Valid_Sudoku.py - m
left = mid + 1
else: # RHS is sorted _author_ = 'jake'
if target <= nums[right] and target > nums[mid]: # target is on RHS _project_ = 'leetcode'
left = mid + 1
else: # https://leetcode.com/problems/valid-sudoku/
right = mid - 1 # Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
# The Sudoku board could be partially filled, where empty cells are filled with the character '.'.
return -1
# Create a set of digits seen in each row, column and box. False if any duplicates.
# Time - O(n^2) for board of side n
# Space - O(n)

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

def find_new(self): class Solution(object):


for row in range(self.size): def combinationSum(self, candidates, target):
for col in range(self.size): """
if isinstance(self.board[row][col], set) and len(self.board[row][col]) == 1: :type candidates: List[int]
self.board[row][col] = self.board[row][col].pop() :type target: int
self.new_digits.append((row,col)) :rtype: List[List[int]]
"""
result = []
def solve_recursive(self): self.helper(candidates, 0, target, [], result)

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

from collections import Counter _author_ = 'jake'


_project_ = 'leetcode'
class Solution(object):
def combinationSum2(self, candidates, target): # https://leetcode.com/problems/trapping-rain-water/
""" # Given n non-negative integers representing an elevation map where the width of each bar is 1,
:type candidates: List[int] # compute how much water it is able to trap after raining.
:type target: int
:rtype: List[List[int]] # Calculate the highest elevation to the right and to the left of every bar. Min of these is the max depth of water.
""" # Subtract the bar height from the max possible depth and floor at zero.
results = [] # Time - O(n)
freq = list(Counter(candidates).items()) # Space - O(n)
self.combos(freq, 0, target, [], results)
return results class Solution(object):
def trap(self, height):
def combos(self, freq, next, target, partial, results):
if target == 0: highest_right = [0] * len(height)
results.append(partial) for i in range(len(height)-2, -1, -1):
return highest_right[i] = max(highest_right[i+1], height[i+1])
if next == len(freq):
return highest_left, depth = [0] * len(height), 0
for i in range(1, len(height)): # depth[0] will be 0 so ok for range to start at 1
for i in range(freq[next][1]+1): highest_left[i] = max(highest_left[i-1], height[i-1])
if i * freq[next][0] > target: depth += max(0, min(highest_left[i], highest_right[i]) - height[i])
break
self.combos(freq, next+1, target-i*freq[next][0], partial + [freq[next][0]]*i, results) return depth

# Iterative version of same procedure.


class Solution_Iterative(object):
def combinationSum2(self, candidates, target):
results = []
partials = [[]] # python_1_to_1000/043_Multiply_Strings.py - m
freq = list(Counter(candidates).items())
_author_ = 'jake'
for candidate, count in freq: _project_ = 'leetcode'

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))

partials = new_partials class Solution(object):


def multiply(self, num1, num2):
return results """
:type num1: str
:type num2: str
# python_1_to_1000/041_First_Missing_Positive.py - h :rtype: str
"""
_author_ = 'jake' num1, num2 = num1[::-1], num2[::-1] # easier to work with lowest digits first
_project_ = 'leetcode' result = [0] * (len(num1) + len(num2))

# 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

# python_1_to_1000/045_Jump_Game_II.py - m return permutations

_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

# Space - O(n * n!)

from collections import Counter # python_1_to_1000/050_Power_Function.py - m

class Solution(object): _author_ = 'jake'


def permuteUnique(self, nums): _project_ = 'leetcode'
"""
:type nums: List[int] # https://leetcode.com/problems/powx-n/
:rtype: List[List[int]] # Implement pow(x, n).
"""
freq = Counter(nums) # Recursively calculate (pow(x, n//2))^2 if n is even or with additional factor of x if n is odd.
permutations = [] # Time - O(log n)
self.permute_helper(len(nums), [], freq, permutations) # Space - O(log n)
return permutations
class Solution(object):
def permute_helper(self, to_add, partial, freq, permutations): def myPow(self, x, n):
if to_add == 0: """
permutations.append(partial) :type x: float
:type n: int
for item in freq: :rtype: float
if freq[item] > 0: """
freq[item] -= 1 neg = n < 0
self.permute_helper(to_add-1, partial + [item], freq, permutations) pos_result = self.pos_pow(x, abs(n))
freq[item] += 1 return 1/pos_result if neg else pos_result

def pos_pow(self, x, n):


if n == 0:
return 1
# python_1_to_1000/048_Rotate_Image.py - m
temp = self.pos_pow(x, n//2)
_author_ = 'jake' temp *= temp
_project_ = 'leetcode'
return temp if n % 2 == 0 else temp * x
# https://leetcode.com/problems/rotate-image/
# You are given an n x n 2D matrix representing an image.
# Rotate the image by 90 degrees (clockwise).
# python_1_to_1000/051_N-Queens.py - h
# Number of layer to rotate is n//2. For each item along the top side of each layer, save as temp and
# move in the item from the next side, repeating until temp is put into the last side. _author_ = 'jake'
# Alternatively - matrix[:] = list(map(list, zip(*matrix[::-1]))). Reverse the order of row, unpack, _project_ = 'leetcode'
# zip and convert back to lists.
# Time - O(n^2) # https://leetcode.com/problems/n-queens/
# Space - O(1) # The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
# Given an integer n, return all distinct solutions to the n-queens puzzle.
class Solution(object): # Each solution contains a distinct board configuration of the n-queens' placement,
def rotate(self, matrix): # where 'Q' and '.' both indicate a queen and an empty space respectively.
"""
:type matrix: List[List[int]] # For each column, place a queen in each possible row that does not conflict with an existing queen.
:rtype: void Do not return anything, modify matrix in-place instead. # Time - O(n^2 * n!), n possible rows for first col, n-1 for second ... etc. each result size n^2
""" # Space - O(n^2 * n!)
n = len(matrix)
layers = n//2 class Solution(object):
def solveNQueens(self, n):
for layer in range(layers): """
for i in range(layer, n - layer - 1): :type n: int
temp = matrix[layer][i] :rtype: List[List[str]]
matrix[layer][i] = matrix[n - 1 - i][layer] """
matrix[n - 1 - i][layer] = matrix[n - 1 - layer][n - 1- i] partials = [[]] # solutions up to current row
matrix[n - 1 - layer][n - 1 - i] = matrix[i][n - 1 - layer] for col in range(n):
matrix[i][n - 1 - layer] = temp new_partials = []
for partial in partials:
for row in range(n):
if not self.conflict(partial, row):
# python_1_to_1000/049_Group_Anagrams.py - m new_partials.append(partial + [row])
partials = new_partials
_author_ = 'jake'
_project_ = 'leetcode' results = []
for partial in partials: # convert result to strings
# https://leetcode.com/problems/anagrams/ result = [['.'] * n for _ in range(n)]
# Given an array of strings, group anagrams together. for col, row in enumerate(partial):
result[row][col] = 'Q'
# Sort the letters in each word. Use sorted words as dictionary keys, values are unsorted words. for row in range(n):
# Anagrams have equivalent sorted words. result[row] = ''.join(result[row])
# Time - O(k log k * n) for n words of length k results.append(result)
# Space - O(k * n)
return results
from collections import defaultdict
def conflict(self, partial, new_row):
class Solution(object): for col, row in enumerate(partial):
def groupAnagrams(self, strs): if new_row == row: # same row
""" return True
:type strs: List[str] col_diff = len(partial) - col
:rtype: List[List[str]] if abs(new_row - row) == col_diff: # same diagonal
""" return True
sorted_words = defaultdict(list)
return False
for word in strs:
letter_list = [c for c in word]
letter_list.sort()
sorted_word = "".join(letter_list) # python_1_to_1000/052_N-Queens_II.py - h
sorted_words[sorted_word].append(word)
_author_ = 'jake'
return list(sorted_words.values()) _project_ = 'leetcode'
leg_count = 0 # count of steps in current direction
# https://leetcode.com/problems/n-queens-ii/
# Follow up for N-Queens problem. for _ in range(len(matrix[0]) * len(matrix)):
# Now, instead outputting board configurations, return the total number of distinct solutions.
row += d_row
# As for N-Queens except just count solutions instead of converting to boards. col += d_col
# Time - O(n!) spiral.append(matrix[row][col])
# Space - O(n!) leg_count += 1

class Solution(object): # change direction


def totalNQueens(self, n): if (d_col != 0 and leg_count == row_leg) or (d_row != 0 and leg_count == col_leg):
""" if d_col != 0:
:type n: int row_leg -= 1
:rtype: List[List[str]] else:
""" col_leg -= 1
partials = [[]] d_row, d_col = d_col, -d_row
for col in range(n): leg_count = 0
new_partials = []
for partial in partials: return spiral
for row in range(n):
if not self.conflict(partial, row):
new_partials.append(partial + [row])
partials = new_partials # python_1_to_1000/055_Jump_Game.py - m

return len(partials) _author_ = 'jake'


_project_ = 'leetcode'
def conflict(self, partial, new_row):
for col, row in enumerate(partial): # https://leetcode.com/problems/jump-game/
if new_row == row: # Given an array of non-negative integers, you are initially positioned at the first index of the array.
return True # Each element in the array represents your maximum jump length at that position.
col_diff = len(partial) - col # Determine if you are able to reach the last index.
if row + col_diff == new_row or row - col_diff == new_row:
return True # Record the maximum index that can be reached. Initially this is index 0.
return False # Iterate through nums, returning False an index cannot be reached.
# Else update the maximum index with the current index + its value (the maximum jump).
# Time - O(n)
# python_1_to_1000/053_Maximum_Subarray.py - m # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def canJump(self, nums):
"""
# https://leetcode.com/problems/maximum-subarray/ :type nums: List[int]
# Find the contiguous subarray within an array (containing at least one number) which has the largest sum. :rtype: bool
"""
# For each num calculate the max subarray sum ending with that num as either num alone (if previous sum was -ve) or max_index = 0
# num + previous sum (if previous sum was +ve)
# Time - O(n) for i, num in enumerate(nums):
# Space - O(1) if i > max_index:
return False
class Solution(object): max_index = max(max_index, i + num)
def maxSubArray(self, nums):
""" return True
:type nums: List[int]
:rtype: int
"""
overall_max = float('-inf') # python_1_to_1000/056_Merge_Intervals.py - m
max_ending_here = 0
_author_ = 'jake'
for num in nums: _project_ = 'leetcode'
if max_ending_here > 0:
max_ending_here += num # https://leetcode.com/problems/merge-intervals/
else: # Given a collection of intervals, merge all overlapping intervals.
max_ending_here = num
overall_max = max(overall_max, max_ending_here) # Sort intervals by start points. If interval starts before previous interval ends then merge, else add to result.
# Time - O(n log n)
return overall_max # Space - O(1)

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)

class Solution(object): # python_1_to_1000/060_Permutation_Sequence.py - h


def insert(self, intervals, newInterval):
""" _author_ = 'jake'
:type intervals: List[List[int]] _project_ = 'leetcode'
:type newInterval: List[int]
:rtype: List[List[int]] # https://leetcode.com/problems/permutation-sequence/
""" # The set [1,2,3,…,n] contains a total of n! unique permutations.
left, right = 0, len(intervals) - 1 # By listing and labeling all of the permutations in order, we get the following sequence (ie, for n = 3):
while left < len(intervals) and intervals[left][1] < newInterval[0]: # "123", "132", "213", "231", "312", "321"
left += 1 # Given n and k, return the kth permutation sequence.

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

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def rotateRight(self, head, k):
"""
# https://leetcode.com/problems/spiral-matrix-ii/ :type head: ListNode
# Given an integer n, generate a square matrix filled with elements from 1 to n**2 in spiral order. :type k: int
:rtype: ListNode
# Change direction clockwise when edge of matrix or non-zero cell is reached. """
# Time - O(n**2) if not head:
# Space - O(n**2) return

class Solution(object): count = 1


def generateMatrix(self, n): node = head
"""
:type n: int while node.next:
:rtype: List[List[int]] node = node.next
""" count += 1
spiral = [[0 for _ in range(n)] for _ in range(n)] node.next = head # connect tail to head
row, col = 0, 0
d_r, d_c = 0, 1 to_move = count - (k % count) #nb steps to move node before breaking
while to_move > 0:
count = 1 node = node.next
while count <= n*n: to_move -= 1
spiral[row][col] = count head = node.next # new head
count += 1 node.next = None
if row+d_r < 0 or row+d_r >= n or col+d_c < 0 or col+d_c >= n or spiral[row+d_r][col+d_c] != 0:
d_r, d_c = d_c, -d_r return head
# Note: You can only move either down or right at any point in time.

# 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

class Solution(object): for row in range(1, m + 1):


def uniquePaths(self, m, n): new_min_path = [float('inf') for _ in range(n + 1)]
""" for col in range(1, n + 1):
:type m: int cols new_min_path[col] = grid[row - 1][col - 1] + min(min_path[col], new_min_path[col - 1])
:type n: int rows min_path = new_min_path
:rtype: int
""" return min_path[-1]
if m == 0 or n == 0:
return 0
# python_1_to_1000/065_Valid_Number.py - h
row_paths = [1 for _ in range(n)] # first row, one path to each column
_author_ = 'jake'
for row in range(m-1): _project_ = 'leetcode'
new_row_paths = [1] # one path to first col of each row
for col in range(1, n): # https://leetcode.com/problems/valid-number/
new_row_paths.append(new_row_paths[-1] + row_paths[col]) # Validate if a given string is numeric.
row_paths = new_row_paths # Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before
implementing one.
return row_paths[-1]
# Test if integer or float or scientific. Allow for first character signs.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/063_Unique_Paths_II.py - m
class Solution(object):
_author_ = 'jake' def isNumber(self, s):
_project_ = 'leetcode' self.digits = {str(i) for i in range(10)}
s = [c for c in s.strip().lower()]
# https://leetcode.com/problems/unique-paths-ii/ if not s:
# Follow up for "Unique Paths": return False
# Now consider if some obstacles are added to the grids. How many unique paths would there be? return self.is_int(s, True) or self.is_float(s) or self.is_sci(s)
# An obstacle and empty space is marked as 1 and 0 respectively in the grid.

# 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

def is_sci(self, s):


try:
# python_1_to_1000/064_Minimum_Path_Sum.py - m e = s.index('e')
before = s[:e]
_author_ = 'jake' after = s[e+1:]
_project_ = 'leetcode'
if not before or not after:
# https://leetcode.com/problems/minimum-path-sum/ return False
# Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes if not self.is_int(before, True) and not self.is_float(before):
# the sum of all numbers along its path. return False

return self.is_int(after, True) # Space - O(maxWidth * nb_lines)


except:
return False class Solution(object):
def fullJustify(self, words, maxWidth):
"""
# python_1_to_1000/066_Plus_One.py :type words: List[str]
:type maxWidth: int
_author_ = 'jake' :rtype: List[str]
_project_ = 'leetcode' """
line_chars = 0 # number of chars on current line (without spaces)
# https://leetcode.com/problems/plus-one/ line_words = [] # list of words on current line
# Given a non-negative number represented as an array of digits, plus one to the number. justified = [] # output, list of justified strings
# The digits are stored such that the most significant digit is at the head of the list.
for word in words:
# Starting from least significant digit, replace with zeros until we find the first non 9, which is incremented.
# Time - O(n) if line_chars + len(line_words) + len(word) <= maxWidth: # add word to current line
# Space - O(1) line_words.append(word)
line_chars += len(word)
class Solution(object):
def plusOne(self, digits): else: # word cannot be added to current line
""" gaps = len(line_words) - 1 # nb gaps between words
:type digits: List[int] spaces = maxWidth - line_chars # nb of spaces to make line maxWidth
:rtype: List[int] line = [line_words[0]] # list of words and spaces
""" if gaps == 0: # pad end if single word
i = len(digits)-1 line.append(" " * spaces)
while i >= 0 and digits[i] == 9:
digits[i] = 0 for line_word in line_words[1:]: # distribute spaces between other words
i -= 1 space = spaces//gaps
if spaces % gaps != 0: # round up if uneven division of spaces
if i == -1: space += 1
return [1] + digits line.append(" " * space) # add space
return digits[:i] + [digits[i]+1] + digits[i+1:] spaces -= space # reduce remaining spaces and gaps
gaps -= 1
line.append(line_word)

# python_1_to_1000/067_Add_Binary.py justified.append("".join(line))

_author_ = 'jake' line_words = [word] # add word to next line.


_project_ = 'leetcode' line_chars = len(word)

# https://leetcode.com/problems/add-binary/ final_line = " ".join(line_words) # pad final line with spaces


# Given two binary strings, return their sum (also a binary string). final_line += " " * (maxWidth - len(final_line))
justified.append(final_line)
# Starting with least significant digits, add digits. Reverse result string.
# Time - O(max(m, n)) return justified
# Space - O(1)

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

_author_ = 'jake' # python_1_to_1000/070_Climbing_Stairs.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/text-justification/ _project_ = 'leetcode'
# Given an array of words and a length L, format the text such that each line has exactly L characters and is fully
(left and right) justified. # https://leetcode.com/problems/climbing-stairs/
# Pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly L # You are climbing a stair case. It takes n steps to reach to the top.
characters. # Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
# Extra spaces between words should be distributed as evenly as possible.
# If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned # Dynamic programming. Base cases of no ways for n <= 0, 1 way for n == 1 and 2 ways for n == 2.
more spaces than the slots on the right. # For each additional step, the number of ways is taking one step from the previous step + taking two steps from the
# For the last line of text, it should be left justified and no extra space is inserted between words. # step before that. Result is a Fibonacci sequence.
# Each word is guaranteed not to exceed L in length. # Time - O(n)
# Space - O(1)
# Fill lines with words and single spaces until full. Then justify by distributing remaining spaces
# Time - O(maxWidth * nb_lines) class Solution(object):
def climbStairs(self, n): return edit_distance(len(word1) - 1, len(word2) - 1)
"""
:type n: int
:rtype: int
""" # python_1_to_1000/073_Set_Matrix_Zeroes.py - m
if n <= 0:
return 0 _author_ = 'jake'
if n <= 2: _project_ = 'leetcode'
return n
# https://leetcode.com/problems/set-matrix-zeroes/
stairs, prev = 2, 1 # 2 ways to reach second step, one way to reach first # Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
for _ in range(3, n + 1):
stairs, prev = stairs + prev, stairs # Record whether first row and forst col contains zero. Then use first for and first col to flag whether body of
# matrix contains a zero in that row or col.
return stairs # Time - O(m * n)
# Space - O(1)

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:

high = mid - 1 start += 1

return False if best_end == float('inf'):


return ''
return s[best_start:best_end+1]

# python_1_to_1000/075_Sort_Colors.py - m # python_1_to_1000/077_Combinations.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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 < 2: return with_last + without_last


nums[next_white] = 1
next_white += 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 = []

class Solution(object): for subset_nb in range(nb_subsets):


def minWindow(self, s, t):
""" subset = []
:type s: str for num in nums:
:type t: str if subset_nb % 2 == 1:
:rtype: str subset.append(num)
""" subset_nb //= 2
freq = Counter(t)
best_start, best_end = 0, float('inf') all_subsets.append(subset)
start, end = 0, -1 # first and last indices of window in s
to_match = len(t) return all_subsets

while end < len(s)-1 or to_match == 0: # can extend end or all matched so will increase start

if to_match != 0: # not all matched, extend end # python_1_to_1000/079_Word_Search.py - m


end += 1
if s[end] in freq: # reduce count, can be negative _author_ = 'jake'
freq[s[end]] -= 1 _project_ = 'leetcode'
if freq[s[end]] >= 0: # reduce to_match if count not negative
to_match -= 1 # https://leetcode.com/problems/word-search/
# Given a 2D board and a word, find if the word exists in the grid.
else: # all matched, check if new min window, increment start # The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally
if end - start < best_end - best_start: # or vertically neighboring. The same letter cell may not be used more than once.
best_end = end
best_start = start # For each starting position, depth first search moving in all 4 directions and marking visited cells.
if s[start] in freq: # add start letter back to count # Time - O(m * n * s), for each starting board position, try upto s characters
freq[s[start]] += 1 # Space - O(1)
if freq[s[start]] > 0:
to_match += 1 # increment to_match if positive count class Solution(object):
def exist(self, board, word): :type target: int
""" :rtype: bool
:type board: List[List[str]] """
:type word: str return self.binary(nums, 0, len(nums)-1, target)
:rtype: bool
""" def binary(self, nums, left, right, target):
if not board or not board[0]:
return False if left > right:
rows, cols = len(board), len(board[0]) return False

for r in range(rows): mid = (left + right) // 2


for c in range(cols): if nums[mid] == target:
if self.can_find(word, 0, board, r, c): return True
return True
return False if nums[left] < nums[mid]: # LHS is sorted
if target < nums[mid] and target >= nums[left]: # check target in range of both ends
return self.binary(nums, left, mid-1, target) # target cannot be on RHS
def can_find(self, word, i, board, r, c): return self.binary(nums, mid+1, right, target) # target cannot be on LHS

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)

# Space - O(1) heights = [0] * cols

# Definition for singly-linked list. for row in range(rows):


class ListNode(object):
def __init__(self, x): heights = [heights[i]+1 if matrix[row][i]=='1' else 0 for i in range(cols)]
self.val = x heights.append(0)
self.next = None stack = [0]

class Solution(object): for col in range(1, len(heights)):


def deleteDuplicates(self, head): while stack and heights[col] < heights[stack[-1]]:
""" height = heights[stack.pop()]
:type head: ListNode if not stack:
:rtype: ListNode width = col
""" else:
node = head width = col - stack[-1] - 1
max_area = max(max_area, height * width)
while node and node.next:
if node.val == node.next.val: stack.append(col)
node.next = node.next.next
else: return max_area
node = node.next

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'

_author_ = 'jake' # https://leetcode.com/problems/partition-list/


_project_ = 'leetcode' # Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or
equal to x.
# https://leetcode.com/problems/largest-rectangle-in-histogram/ # You should preserve the original relative order of the nodes in each of the two partitions.
# Given n non-negative integers representing the histogram's bar height where the width of each bar is 1,
# find the area of largest rectangle in the histogram. # Create new pseudo heads for lists of nodes lesser and greater than x.
# Time - O(n)
# For each bar, find the largest rectangle including that bar as the lowest bar. # Space - O(1)
# An index is popped from the stack when a lower bar to the right is found.
# We calculate the largest area with the bar at the popped index as the height (lowest bar in rectangle). # Definition for singly-linked list.
# Width is determined by the closest lower bar to the left and right. class ListNode(object):
# Time - O(n) def __init__(self, x):
# Space - O(n) self.val = x
self.next = None
class Solution(object):
def largestRectangleArea(self, heights): class Solution(object):
""" def partition(self, head, x):
:type heights: List[int] """
:rtype: int :type head: ListNode
""" :type x: int
max_area = 0 :rtype: ListNode
heights = [0] + heights + [0] # stack will not be empty and last genuine bar will be popped """
stack = [0] # indices of bars in non-decreasing height order lesser_head = lesser = ListNode(None)
greater_head = greater = ListNode(None)
for i, bar in enumerate(heights[1:], 1):
node = head
while heights[stack[-1]] > bar: # pop taller off stack while node:
if node.val < x:
height = heights[stack.pop()] # form rectangle with popped bar determining height lesser.next = node
width = i - stack[-1] - 1 # i and stack[-1] - 1 are the first lower bars on left and right lesser = node
max_area = max(max_area, height * width) else: # node.val >= x
greater.next = node
stack.append(i) greater = node
node = node.next
return max_area
greater.next = None # if last node not greater then break link to last node
lesser.next = greater_head.next # join lists
return lesser_head.next

# 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

while i >= 0 and j >= 0: class Solution(object):


if nums1[i] > nums2[j]: def numDecodings(self, s):
nums1[k] = nums1[i] """
i -= 1 :type s: str
else: :rtype: int
nums1[k] = nums2[j] """
j -= 1 if not s:
k -= 1 return 0

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'

class Solution(object): # https://leetcode.com/problems/reverse-linked-list-ii/


def grayCode(self, n): # Reverse a linked list from position m to n. Do it in-place and in one-pass.
""" # m, n satisfy the following condition: 1 ≤ m ≤ n ≤ length of list.
:type n: int
:rtype: List[int] # Find tail of non-reversed section, reverse nodes between m and n, link back between non-reversed sections.
""" # Time - O(n)
gray = [0] # Space - O(1)

for i in range(n): # Definition for singly-linked list.


gray += [x + 2 ** i for x in reversed(gray)] class ListNode(object):
def __init__(self, x):

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)

return pseudo.next if node.right:


node = node.right
while node:
# python_1_to_1000/093_Restore_IP_Addresses.py - m stack.append(node)
node = node.left
_author_ = 'jake'
_project_ = 'leetcode' return result

# 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

results = [[]] class Solution(object):


def generateTrees(self, n):
while NB_SECTIONS > 0: """
:type n: int
new_results = [] :rtype: List[TreeNode]
"""
for result in results: if n <= 0:
return []
used = sum((len(section) for section in result)) # number of used characters in this partial result return self.generate(1, n)
remaining = len(s) - used # number of remaining chars in s
def generate(self, left, right):
if 3 * (NB_SECTIONS - 1) >= remaining - 3 >= NB_SECTIONS - 1 and 100 <= int(s[used:used + 3]) <= 255:
new_results.append(result + [s[used:used + 3]]) if left > right:
if 3 * (NB_SECTIONS - 1) >= remaining - 2 >= NB_SECTIONS - 1 and 10 <= int(s[used:used + 2]): return [None]
new_results.append(result + [s[used:used + 2]])
if 3 * (NB_SECTIONS - 1) >= remaining - 1 >= NB_SECTIONS - 1: results = []
new_results.append(result + [s[used]]) for i in range(left, right+1):

NB_SECTIONS -= 1 left_trees = self.generate(left, i-1)


results = new_results right_trees = self.generate(i+1, right)
for l in left_trees:
return ['.'.join(result) for result in results] for r in right_trees:
root = TreeNode(i)
root.left = l
root.right = r
results.append(root)
# python_1_to_1000/094_Binary_Tree_Inorder_Traversal.py
return results
_author_ = 'jake'
_project_ = 'leetcode'

# 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

if memo[n] != -1: def inorder(self, node):


return memo[n] if not node or not self.correct: # return if already found out of order
return
count = 0
for i in range(1, n+1): # take each number 1...n as root self.inorder(node.left)
# all numbers < i form left subtree, all > i form right subtree
# multiply possibilities if node.val <= self.prev:
count += self.helper(i-1, memo) * self.helper(n-i, memo) self.correct = False
memo[n] = count return # halt exploration
return count self.prev = node.val

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'

def inorder(self, node): if not left_node or not right_node:


if not node: return False
return
if left_node.val != right_node.val:
self.inorder(node.left) return False

if node.val <= self.prev.val: return self.is_mirror(right_node.right, left_node.left) and \


if not self.swapped1: self.is_mirror(left_node.right, right_node.left)
self.swapped1 = self.prev
if self.swapped1:
self.swapped2 = node # python_1_to_1000/102_Binary_Tree_Level_Order_Traversal.py - m

self.prev = node _author_ = 'jake'


_project_ = 'leetcode'
self.inorder(node.right)
# https://leetcode.com/problems/binary-tree-level-order-traversal/
# Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

# 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]])

for node in level: # python_1_to_1000/106_Construct_Binary_Tree_from_Postorder_and_Inorder_Traversal.py - m


if node.left:
new_level.append(node.left) _author_ = 'jake'
if node.right: _project_ = 'leetcode'
new_level.append(node.right)
# https://leetcode.com/problems/construct-binary-tree-from-postorder-and-inorder-traversal/
level = new_level # Given inorder and postorder traversal of a tree, construct the binary tree.
forward = not forward # You may assume that duplicates do not exist in the tree.

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/104_Maximum_Depth_of_Binary_Tree.py # Definition for a binary tree node.


class TreeNode(object):
_author_ = 'jake' def __init__(self, x):
_project_ = 'leetcode' self.val = x
self.left = None
# https://leetcode.com/problems/maximum-depth-of-binary-tree/ self.right = None
# Given a binary tree, find its maximum depth.
# The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. class Solution(object):
def buildTree(self, inorder, postorder):
# Base case of zer for null node, else 1 + max of left and right subtrees. """
# Time - O(n) :type inorder: List[int]
# Space - O(n) :type postorder: List[int]
:rtype: TreeNode
# Definition for a binary tree node. """
# class TreeNode(object): if not inorder: # no inorder signifies null tree even if postorder is not null
# def __init__(self, x): return None
# self.val = x
# self.left = None inorder_index = inorder.index(postorder.pop())
# self.right = None root = TreeNode(inorder[inorder_index])

class Solution(object): root.right = self.buildTree(inorder[inorder_index+1:], postorder) # right first


def maxDepth(self, root): root.left = self.buildTree(inorder[:inorder_index], postorder)
"""
:type root: TreeNode return root
:rtype: int
"""
if not root: # python_1_to_1000/107_Binary_Tree_Level_Order_Traversal_II.py - m
return 0
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) _author_ = 'jake'
_project_ = 'leetcode'

# 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

# Definition for a binary tree node. class Solution(object):


class TreeNode(object): def levelOrderBottom(self, root):
def __init__(self, x): """
self.val = x :type root: TreeNode
self.left = None :rtype: List[List[int]]
self.right = None """
traversal = []
class Solution(object): self.inorder(root, 0, traversal)
def buildTree(self, preorder, inorder): return traversal[::-1]
"""
:type preorder: List[int] def inorder(self, node, depth, traversal):
:type inorder: List[int]
:rtype: TreeNode if not node:
""" return
def build(stop):
if len(traversal) == depth:
if not inorder or inorder[-1] == stop: traversal.append([])
return None
self.inorder(node.left, depth+1, traversal)
root_val = preorder.pop()
root = TreeNode(root_val) traversal[depth].append(node.val)
root.left = build(root_val) # build left subtree until inorder reaches root_val
inorder.pop() # then discard root_val self.inorder(node.right, depth+1, traversal)
root.right = build(stop) # build right subtree until inorder reaches original stop

root.left = left_subtree
node_as_list[0] = node_as_list[0].next # update entry to next node of linked-list

# python_1_to_1000/108_Convert_Sorted_Array_to_Binary_Search_Tree.py root.right = self.list_to_bst(node_as_list, mid + 1, end)

_author_ = 'jake' return root


_project_ = 'leetcode'

# 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'

# Definition for a binary tree node. # https://leetcode.com/problems/balanced-binary-tree/


class TreeNode(object): # Given a binary tree, determine if it is height-balanced.
def __init__(self, x): # A height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node
self.val = x # never differ by more than 1.
self.left = None
self.right = None # Helper function balanced returns the depth of the root if the tree is balance or else -1 if not balanced.
# A tree is not balance if either left or right subtree is not balanced, or the difference in left and right subtree
class Solution(object): # depths is greater than 1.
def sortedArrayToBST(self, nums): # Time - O(n), visit all nodes
""" # Space - O(n)
:type nums: List[int]
:rtype: TreeNode class Solution(object):
""" def isBalanced(self, root):
return self.convert(nums, 0, len(nums)-1) """
:type root: TreeNode
def convert(self, nums, left, right): :rtype: bool
if left > right: """
return None def balanced(node):
mid = (left + right) // 2
root = TreeNode(nums[mid]) if not node:
root.left = self.convert(nums, left, mid-1) return 0
root.right = self.convert(nums, mid+1, right)
return root left_depth = balanced(node.left)
right_depth = balanced(node.right)

if left_depth == -1 or right_depth == -1:


# python_1_to_1000/109_Convert_Sorted_List_to_Binary_Search_Tree.py - m return -1
if abs(left_depth - right_depth) > 1:
_author_ = 'jake' return -1
_project_ = 'leetcode'
return 1 + max(left_depth, right_depth)

# https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ return balanced(root) != -1


# Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.

# 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

# Definition for singly-linked list. _author_ = 'jake'


class ListNode(object): _project_ = 'leetcode'
def __init__(self, x):
self.val = x # https://leetcode.com/problems/minimum-depth-of-binary-tree/
self.next = None # Given a binary tree, find its minimum depth.
# The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
# Definition for a binary tree node.
class TreeNode(object): # If either subtrees is not present, return 1 + minDepth of existing subtree. If both (or neither) subtrees, return
def __init__(self, x): # 1 + min of subtree minDepths
self.val = x # Time - O(n)
self.left = None # Space - O(n)
self.right = None
# Definition for a binary tree node.
class TreeNode(object):
class Solution(object): def __init__(self, x):
def sortedListToBST(self, head): self.val = x
""" self.left = None
:type head: ListNode self.right = None
:rtype: TreeNode
""" class Solution(object):
count = 0 def minDepth(self, root):
node = head """
while node: :type root: TreeNode
count += 1 :rtype: int
node = node.next """
return self.list_to_bst([head], 0, count - 1) # [head] is mutable list of next list node to be converted if not root:
return 0

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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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

self.preorder(node.left, target, partial, paths) return prev_subsequences[-1]


self.preorder(node.right, target, partial, paths)

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)

# python_1_to_1000/117_Populating_Next_Right_Pointers_in_Each_Node_II.py - m class Solution(object):


def getRow(self, rowIndex):
_author_ = 'jake' """
_project_ = 'leetcode' :type rowIndex: int
:rtype: List[int]
# https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ """
# Follow up for problem "Populating Next Right Pointers in Each Node". row = [1]
# What if the given tree could be any binary tree? Would your previous solution still work? for i in range(rowIndex):
row = [1] + [row[i]+row[i+1] for i in range(len(row)-1)] + [1]
# Breadth first search by level. Only append non-null nodes to level list. return row
# Time - O(n)
# Space - O(n)
# python_1_to_1000/120_Triangle.py - m
# Definition for binary tree with next pointer.
class TreeLinkNode(object): _author_ = 'jake'
def __init__(self, x): _project_ = 'leetcode'
self.val = x
self.left = None # https://leetcode.com/problems/triangle/
self.right = None # Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row
self.next = None below.

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

# python_1_to_1000/122_Best_Time_to_Buy_and_Sell_Stock_II.py - m left_via, left_down = self.helper(node.left)


right_via, right_down = self.helper(node.right)
_author_ = 'jake'
_project_ = 'leetcode' # either use this node and go down left and/or right if positive, or best of left and right via.
via = max(node.val + max(0, left_down) + max(0, right_down), left_via, right_via)
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ # use this node and go down max of right or left if positive.
# Say you have an array for which the ith element is the price of a given stock on day i. down = node.val + max(0, left_down, right_down)
# Design an algorithm to find the maximum profit. You may complete as many transactions as you like
# (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple return via, down
# transactions at the same time (ie, you must sell the stock before you buy again).

# Sum all price increases.


# Time - O(n)
# Space - O(n), could be O(1) without creating a new list
# python_1_to_1000/125_Valid_Palindrome.py
class Solution(object):
def maxProfit(self, prices): _author_ = 'jake'
""" _project_ = 'leetcode'
:type prices: List[int]
:rtype: int # https://leetcode.com/problems/valid-palindrome/
""" # Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
return sum([max(prices[i]-prices[i-1], 0) for i in range(1,len(prices))])
# Convert to lower case and remove non-alphanumeric characters.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/123_Best_Time_to_Buy_and_Sell_Stock_III.py - h
import string
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def isPalindrome(self, s):
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ """
# Say you have an array for which the ith element is the price of a given stock on day i. :type s: str
# Design an algorithm to find the maximum profit. You may complete at most two transactions. :rtype: bool
# You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). """
allowed = set(string.ascii_lowercase + string.digits)
# As per problem 121 with an additional buy and sell. s = [c for c in s.lower() if c in allowed]
# Time - O(n)
# Space - O(1) i, j = 0, len(s)-1
while i < j:
class Solution(object): if s[i] != s[j]:
def maxProfit(self, prices): return False
""" i += 1
:type prices: List[int] j -= 1
:rtype: int return True
"""
buy1, buy2 = float('-inf'), float('-inf')
sell1, sell2 = 0, 0

for price in prices: # python_1_to_1000/126_Word_Ladder_II.py - h


buy1 = max(buy1, -price)
sell1 = max(sell1, price + buy1) _author_ = 'jake'
buy2 = max(buy2, sell1 - price) _project_ = 'leetcode'
sell2 = max(sell2, price + buy2)
# https://leetcode.com/problems/word-ladder-ii/
return sell2 # Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s)
# from beginWord to endWord, such that:
# Only one letter can be changed at a time
# python_1_to_1000/124_Binary_Tree_Maximum_Path_Sum.py - h # Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
# Note:
_author_ = 'jake' # Return an empty list if there is no such transformation sequence.
_project_ = 'leetcode' # All words have the same length.
# All words contain only lowercase alphabetic characters.
# https://leetcode.com/problems/binary-tree-maximum-path-sum/ # You may assume no duplicates in the word list.
# Given a binary tree, find the maximum path sum. # You may assume beginWord and endWord are non-empty and are not the same.
# For this problem, a path is defined as any sequence of nodes from some starting node to any node in
# the tree along the parent-child connections. # Bidirectional breadth first search. Frontiers of valid neighbouring words are gradually expanded. Swap to use the
# The path must contain at least one node and does not need to go through the root. # smaller frontier in each round, stop when either frontier is empty (return empty list) or an intersection is found.
# Build ladders to srat using left parents and to end using right parents.
# Recursive helper function calculates max path downwards from and including any node and max path via a node or via # Time - O(b^(d/2)) where b is branching factor and d is depth between start and end
# any node below.
# Time - O(n) from collections import defaultdict
# Space - O(1) import string

# Definition for a binary tree node. class Solution(object):


# class TreeNode(object): def findLadders(self, beginWord, endWord, wordList):

"""
: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:

# python_1_to_1000/127_Word_Ladder.py - h if num-1 in numset: # not the start of a sequence


continue
_author_ = 'jake'
_project_ = 'leetcode' seq = 0
while num in numset: # move along this sequence
# https://leetcode.com/problems/word-ladder/ seq += 1
# Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation num += 1
# sequence from beginWord to endWord, such that: longest = max(longest, seq)
# Only one letter can be changed at a time.
# Each transformed word must exist in the word list. Note that beginWord is not a transformed word. return longest
# Note:
# Return 0 if there is no such transformation sequence.
# All words have the same length.
# All words contain only lowercase alphabetic characters.
# You may assume no duplicates in the word list.
# python_1_to_1000/129_Sum_Root_to_Leaf_Numbers.py - m
# Bidirectional depth first search. Process wordList to be able to find neighbours.
# Time - O(n*k*k) to build graph for n words of length k. O(b^(d/2)) for bidirectional BFS with branching _author_ = 'jake'
# factor b and depth d _project_ = 'leetcode'
# Space - O(n*k) for graph
# https://leetcode.com/problems/sum-root-to-leaf-numbers/
from collections import defaultdict # Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
# An example is the root-to-leaf path 1->2->3 which represents the number 123.
class Solution(object): # Find the total sum of all root-to-leaf numbers.
def ladderLength(self, beginWord, endWord, wordList):
""" # Recursively find the sum of all paths from a node to all leaves having already seen path value of partial.
:type beginWord: str # Time - O(n)
:type endWord: str # Space - O(n)
:type wordList: List[str]
:rtype: int # Definition for a binary tree node.
""" class TreeNode(object):
length = 1 def __init__(self, x):
visited = set() self.val = x
if endWord not in wordList: self.left = None
return 0 self.right = None

graph = defaultdict(set) class Solution(object):


for word in wordList: # build a mapping of words reachable by changing one letter def sumNumbers(self, root):
for i in range(len(word)): """
wildcard = word[:i] + '_' + word[i + 1:] :type root: TreeNode
graph[wildcard].add(word) :rtype: int
"""
front, back = {beginWord}, {endWord} # frontiers in both directions return self.helper(root, 0)

while front: def helper(self, node, partial):

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

class Solution(object): left, right = i, i # expand to find all odd-length palindromes


def solve(self, board): while left >= 0 and right < len(s) and s[left] == s[right]:
""" min_cuts[right + 1] = min(min_cuts[right + 1], 1 + min_cuts[left])
:type board: List[List[str]] left -= 1
:rtype: void Do not return anything, modify board in-place instead. right += 1
"""
if not board or not board[0]: left, right = i, i+1 # expand to find all even-length palindromes
return while left >= 0 and right < len(s) and s[left] == s[right]:
min_cuts[right + 1] = min(min_cuts[right + 1], 1 + min_cuts[left])
rows, cols = len(board), len(board[0]) left -= 1
right += 1
to_expand = [] # stack of cells to be checked
return min_cuts[-1]
for row in range(rows): # add all edge cells to stack
to_expand += [(row, 0), (row, cols - 1)]
for col in range(1, cols-1):
to_expand += [(0, col), (rows - 1, col)] # python_1_to_1000/133_Clone_Graph.py - m

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 = []

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def cloneGraph(self, node):
"""
# https://leetcode.com/problems/palindrome-partitioning/ :type node: UndirectedGraphNode
# Given a string s, partition s such that every substring of the partition is a palindrome. :rtype: UndirectedGraphNode
# Return all possible palindrome partitioning of s. """
if not node:
# If any prefix of s is a palindrome, then recursively partition the suffix into palindromes. return
# Time - O(2**n), for string of length n there we can partition or not after each letter cloned_start = UndirectedGraphNode(node.label)
# Space - O(2**n) to_clone = [node] # list (or set) of original nodes
node_mapping = {node : cloned_start} # original to cloned nodes
class Solution(object):
def partition(self, s): while to_clone:
"""
:type s: str node = to_clone.pop() # node is in mapping but does not have links to neighbors
:rtype: List[List[str]] clone_node = node_mapping[node]
"""
partitons = [] for neighbor in node.neighbors:
self.find_partitions(s, [], partitons) if neighbor not in node_mapping: # create copies of neighbors if not already existing
return partitons clone_neightbor = UndirectedGraphNode(neighbor.label)
node_mapping[neighbor] = clone_neightbor
to_clone.append(neighbor)
def find_partitions(self, s, partial, partitions): else:
if not s: clone_neightbor = node_mapping[neighbor]
partitions.append(partial)
clone_node.neighbors.append(clone_neightbor) # directed edges from clone_node
for i in range(1, len(s)+1):
prefix = s[:i] return cloned_start
if prefix == prefix[::-1]:
self.find_partitions(s[i:], partial + [s[:i]], partitions)

# 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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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

return candies node = head


while node:
if node.random:
# python_1_to_1000/136_Single_Number.py node.next.random = node.random.next
node = node.next.next
_author_ = 'jake'
_project_ = 'leetcode' pseudo = prev = RandomListNode(0)
node = head
# https://leetcode.com/problems/single-number/ while node:
# Given an array of integers, every element appears twice except for one. Find that single one. prev.next = node.next
node.next = node.next.next
# Any number xor with itself is zero. node = node.next
# Time - O(n) prev = prev.next
# Space - O(1)
return pseudo.next
class Solution(object):
def singleNumber(self, nums):
""" # python_1_to_1000/139_Word_Break.py - m
:type nums: List[int]
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
xor = 0
for num in nums: # https://leetcode.com/problems/word-break/
xor ^= num # Given a string s and a dictionary of words dict, determine if s can be segmented into a
# space-separated sequence of one or more dictionary words. # Given a linked list, determine if it has a cycle in it.

# 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)

class Solution(object): # Definition for singly-linked list.


def wordBreak(self, s, wordDict): class ListNode(object):
""" def __init__(self, x):
:type s: str self.val = x
:type wordDict: Set[str] self.next = None
:rtype: bool
""" class Solution(object):
can_make = [False] * (len(s)+1) # can_make[i] is True if can make prefix of length i def hasCycle(self, head):
can_make[0] = True """
:type head: ListNode
for i in range(1, len(s)+1): # prefix length :rtype: bool
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: fast, slow = head, head
can_make[i] = True while fast and fast.next:
break slow = slow.next
fast = fast.next.next
return can_make[-1] if fast == slow:
return True
return False

# python_1_to_1000/140_Word_Break_II.py - h

_author_ = 'jake' # python_1_to_1000/142_Linked_List_Cycle_II.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/word-break-ii/ _project_ = 'leetcode'
# Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid
dictionary word. # https://leetcode.com/problems/linked-list-cycle-ii/
# Return all such possible sentences. # Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

# 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

if left >= len(s): # base case


return [[]]
if left in memo: # python_1_to_1000/143_Reorder_List.py - m
return memo[left]
_author_ = 'jake'
results = [] _project_ = 'leetcode'
for i in range(left+1, len(s)+1): # try all possible prefixes
prefix = s[left:i] # https://leetcode.com/problems/reorder-list/
suffix_breaks = self.break_word(s, i, wordDict, memo) # Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
if suffix_breaks and prefix in wordDict: # Do this in-place without altering the nodes' values.
for suffix_break in suffix_breaks:
results.append([prefix] + suffix_break) # Find the mid point, reverse list after mid point, then interleave the 2 sides.
# Time - O(n)
memo[left] = results[:] # Space - O(1)
return results
# Definition for singly-linked list.
class ListNode(object):
def __init__(self, x):
# python_1_to_1000/141_Linked_List_Cycle.py self.val = x
self.next = None
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def reorderList(self, head):
# https://leetcode.com/problems/linked-list-cycle/ """

:type head: ListNode # which is reversed before returning result).


:rtype: void Do not return anything, modify head in-place instead. # Add left children to stack before right so right subtrees are visited before left.
""" # Alternatively, recurse left, recurse right then visit node.
if not head: # Time - O(n)
return None # Space - O(n)

# 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 []

result = deque() # deque instead of list so we can append at front


# python_1_to_1000/144_Binary_Tree_Preorder_Traversal.py stack = [root]

_author_ = 'jake' while stack:


_project_ = 'leetcode' node = stack.pop()
result.appendleft(node.val)
# https://leetcode.com/problems/binary-tree-preorder-traversal/
# Given a binary tree, return the preorder traversal of its nodes' values. if node.left:
stack.append(node.left)
# Maintain a stack of nodes discovered and to be visited. Add right children to stack before left so left subtrees if node.right:
# are visited before right. stack.append(node.right)
# Alternatively, visit node, recurse left then recurse right.
# Time - O(n) return list(result)
# Space - O(n)

# Definition for a binary tree node. class Solution2(object):


class TreeNode(object): def postorderTraversal(self, root):
def __init__(self, x): result = []
self.val = x self.postorder(root, result)
self.left = None return result
self.right = None
def postorder(self, node, result):
class Solution(object): if not node:
def preorderTraversal(self, root): return
""" self.postorder(node.left, result)
:type root: TreeNode self.postorder(node.right, result)
:rtype: List[int] result.append(node.val)
"""
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

# https://leetcode.com/problems/binary-tree-postorder-traversal/ def remove_at_head(self):


# Given a binary tree, return the postorder traversal of its nodes' values. node = self.head.next
node.next.prev = self.head
# Maintain a stack of nodes discovered and to be visited. Nodes are added to front of result (or the end of a list self.head.next = self.head.next.next
key = node.key
del node insertion = dummy
return key while insertion.next.val <= node.val:
insertion = insertion.next
def update(self, node):
node.prev.next = node.next # take out from existing position node.next = insertion.next # put node after insertion
node.next.prev = node.prev insertion.next = node
self.insert(node) # put back at tail
return dummy.next

class LRUCache(object):

def __init__(self, capacity): # python_1_to_1000/148_Sort_List.py - m


"""
:type capacity: int _author_ = 'jake'
""" _project_ = 'leetcode'
self.capacity = capacity
self.queue = DLL() # https://leetcode.com/problems/sort-list/
self.mapping = {} # Sort a linked list in O(n log n) time using constant space complexity.

# 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)

while one and two:

# python_1_to_1000/147_Insertion_Sort_List.py - m if one.val <= two.val:


merged.next = one
_author_ = 'jake' one = one.next
_project_ = 'leetcode' else:
merged.next = two
# https://leetcode.com/problems/insertion-sort-list/ two = two.next
# Sort a linked list using insertion sort. merged = merged.next

# 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

# Definition for singly-linked list.


class ListNode(object): # python_1_to_1000/149_Max_Points_on_a_Line.py - h
def __init__(self, x):
self.val = x _author_ = 'jake'
self.next = None _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/max-points-on-a-line/


def insertionSortList(self, head): # Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
"""
:type head: ListNode # For each point, calculate the gradient of the line to all other points and store in dictionary. Python accepts
:rtype: ListNode # floats as dictionary keys and floating point accuracy is not an issue for sufficiently small x and y.
""" # Infinite slopes are stored with key of 'inf'. If both x and y are the same, both points lie on all lines with the
sorted_tail = dummy = ListNode(float('-inf')) # sorted_tail is last node of sorted section # first point. Calculate the max number of points on a line with each base point in turn, only considering other points
dummy.next = head # that have not already been the base point.
# Time - O(n**2)
while sorted_tail.next: # Space - O(n)

node = sorted_tail.next # Definition for a point.


class Point(object):
if node.val >= sorted_tail.val: # node already in correct place def __init__(self, a=0, b=0):
sorted_tail = sorted_tail.next self.x = a
continue self.y = b

sorted_tail.next = sorted_tail.next.next # cut out node from collections import defaultdict

: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)

if point.x == point_2.x: class Solution(object):


if point.y == point_2.y: # same point, on all lines def maxProduct(self, nums):
max_points += 1 """
else: # infinite gradient :type nums: List[int]
gradients['inf'] += 1 :rtype: int
"""
else: largest_product = float('-inf')
gradient = (point_2.y - point.y) / float(point_2.x - point.x) most_neg, most_pos = 1, 1
gradients[gradient] += 1
for num in nums:
if gradients: most_pos, most_neg = max(num, most_pos * num, most_neg * num), min(num, most_pos * num, most_neg * num)
max_points += max(gradients.values()) largest_product = max(largest_product, most_pos, most_neg)
overall_max = max(overall_max, max_points)
return largest_product
return overall_max

# python_1_to_1000/153_Find_Minimum_in_Rotated_Sorted_Array.py - m

# python_1_to_1000/150_Evaluate_Reverse_Polish_Notation.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
# Suppose a sorted array is rotated at some pivot unknown to you beforehand.
# https://leetcode.com/problems/evaluate-reverse-polish-notation/ # (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
# Evaluate the value of an arithmetic expression in Reverse Polish Notation. # Find the minimum element.
# Valid operators are +, -, *, /. Each operand may be an integer or another expression. # You may assume no duplicate exists in the array.

# 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]

return stack[-1] return nums[left]

# 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)

_author_ = 'jake' # The read4 API is already defined for you.


_project_ = 'leetcode' # @param buf, a list of characters
# @return an integer
# https://leetcode.com/problems/binary-tree-upside-down/ def read4(buf):
# Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the pass
# same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned
# into left leaf nodes. Return the new root. from collections import deque

# 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. """

:type buf: Destination buffer (List[str]) """


:type n: Maximum number of characters to read (int) :type head1, head1: ListNode
:rtype: The number of characters read (int) :rtype: ListNode
""" """
total_chars, added_chars, read_chars = 0, 4, 0 if not headA or not headB:
return None
while self.leftover and total_chars < n: # add leftover chars to buf
buf[total_chars] = self.leftover.popleft() savedA, savedB = headA, headB
total_chars += 1
while headA != headB:
while added_chars == 4 and total_chars < n: # add blocks of 4 chars up to eof headA = savedB if not headA else headA.next
buf4 = [""] * 4 # temporary buffer headB = savedA if not headB else headB.next
read_chars = read4(buf4)
added_chars = min(read_chars, n - total_chars) gc.collect() # required to pass leetocde strict memory usage
buf[total_chars:total_chars+added_chars] = buf4 return headA
total_chars += added_chars

while read_chars > added_chars: # save extra chars class Solution2(object):


self.leftover.append(buf4[added_chars]) def getIntersectionNode(self, headA, headB):
added_chars += 1 """
:type head1, head1: ListNode
return total_chars :rtype: ListNode
"""
if not headA or not headB:
# python_1_to_1000/159_Longest Substring_with_At_Most_Two_Distinct_Characters.py - m return None

_author_ = 'jake' savedA, savedB = headA, headB


_project_ = 'leetcode' len_diff = 0

# https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/ while headA.next:


# Given a string, find the length of the longest substring T that contains at most 2 distinct characters. len_diff += 1
headA = headA.next
# Maintain a window of the longest substring. If a 3rd char is found, reset the window start to after the first while headB.next:
# seen char. len_diff -= 1
# Time - O(n) headB = headB.next
# Space - O(1)
if headA != headB: # no intersection
class Solution(object): return
def lengthOfLongestSubstringTwoDistinct(self, s):
""" headA, headB = savedA, savedB
:type s: str
:rtype: int while len_diff != 0: # traverse longer list for length difference
""" if len_diff > 0:
start, max_substring = 0, 0 headA = headA.next
last_seen = {} # key is char, value is last index of char len_diff -= 1
else:
for i, c in enumerate(s): headB = headB.next
len_diff += 1
if c in last_seen or len(last_seen) < 2: # extend substring with same start
max_substring = max(max_substring, i - start + 1) while headA != headB:
headA = headA.next
else: # c not in current substring and 2 chars seen headB = headB.next
for seen in last_seen:
if seen != s[i-1]: # find the char that is not the previous char gc.collect()
start = last_seen[seen] + 1 # move start to after this char return headA
del last_seen[seen]
break
# python_1_to_1000/161_One_Edit_Distance.py - m
last_seen[c] = i
_author_ = 'jake'
return max_substring _project_ = 'leetcode'

# 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)

# https://leetcode.com/problems/intersection-of-two-linked-lists/ class Solution(object):


# Write a program to find the node at which the intersection of two singly linked lists begins. def isOneEditDistance(self, s, t):
# If the two linked lists have no intersection at all, return null. """
# The linked lists must retain their original structure after the function returns. :type s: str
# You may assume there are no cycles anywhere in the entire linked structure. :type t: str
:rtype: bool
# Traverse both lists, when reach end switch to start of other list. If lists have l1 and l2 nodes before intersect """
# and k nodes after then both traversals intersect after l1 + l2 + k nodes. If no intersection, k = 0 and both pointers diff = len(s) - len(t)
# meet at None. if abs(diff) > 1: # early break
# Alternatively, count lengths and traverse longer list for length difference before traversing both in step. return False
# Time - O(n)
# Space - O(1) edit = False
if diff == 0: # one replacement
import gc # used to manually clear the memory for c_s, c_t in zip(s, t):
if c_s != c_t:
# Definition for singly-linked list. if edit: # already seen a replacement
class ListNode(object): return False
def __init__(self, x): edit = True
self.val = x return edit # False if no replacement
self.next = None
else: # abs(diff) == 1
class Solution(object): long, short = s, t
def getIntersectionNode(self, headA, headB): if diff < 0:
long, short = short, long # Return 0 if the array contains less than 2 elements.
i = 0 # find the mismatch # You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.
while i < len(short) and long[i] == short[i]:
i += 1 # Bucket sort. By pigeon-hole principle we ensure at least one bucket is empty or numbers are equally separated
return long[i+1:] == short[i:] # remainders must be same # by the same distance.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/162_Find_Peak_Element.py - m
class Solution(object):
_author_ = 'jake' def maximumGap(self, nums):
_project_ = 'leetcode' """
:type nums: List[int]
# https://leetcode.com/problems/find-peak-element/ :rtype: int
# A peak element is an element that is greater than its neighbors. """
# Given an input array where num[i] ≠ num[i+1], find a peak element and return its index. if len(nums) < 2:
# The array may contain multiple peaks, in that case return the index to any one of the peaks is fine. return 0
# You may imagine that num[-1] = num[n] = -∞.
lower = min(nums)
# If array has 3 or more elements, return mid if it is a peak else recurse on the side with a higher element. difference = max(nums) - lower
# If array has < 3 elements, return index of greater. gaps = len(nums) - 1 # number of spaces between sorted nums
# Time - O(log n) if difference == 0: # all nums are same
# Space - O(1) return 0

class Solution(object): width = difference // gaps # range of integers // number of gaps


def findPeakElement(self, nums): if width == 0:
""" width = 1
:type nums: List[int]
:rtype: int nb_buckets = 1 + difference // width # ensure max(nums) goes in final bucket
"""
left, right = 0, len(nums)-1 buckets = [[None, None] for _ in range(nb_buckets)] # max and min of each bucket

while left < right - 1: # at least 3 elements for num in nums:


bucket = (num - lower) // width
mid = (left + right) // 2 buckets[bucket][0] = min(buckets[bucket][0], num) if buckets[bucket][0] != None else num
buckets[bucket][1] = max(buckets[bucket][1], num) if buckets[bucket][1] != None else num
if nums[mid] >= nums[mid+1] and nums[mid] >= nums[mid-1]:
return mid last_used_bucket = 0
if nums[mid+1] > nums[mid]: # RHS is higher (LHS could be also but arbitrarily choose RHS) max_gap = difference // gaps # default case of no empty buckets
left = mid + 1 for i in range(nb_buckets - 1):
else: # LHS must be higher if RHS is not if not buckets[i][0] and buckets[i + 1][0]:
right = mid - 1 max_gap = max(max_gap, buckets[i + 1][0] - buckets[last_used_bucket][1])
elif buckets[i][0]:
if nums[left] >= nums[right]: last_used_bucket = i
return left
return right return max_gap

# python_1_to_1000/163_Missing_Ranges.py # python_1_to_1000/165_Compare_Version_Numbers.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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)

class Solution(object): import itertools


def findMissingRanges(self, nums, lower, upper):
""" class Solution(object):
:type nums: List[int] def compareVersion(self, version1, version2):
:type lower: int """
:type upper: int :type version1: str
:rtype: List[str] :type version2: str
""" :rtype: int
last_seen = lower-1 """
nums.append(upper+1) v1 = [int(v) for v in version1.split('.')] # split by "." and convert to int
missing = [] v2 = [int(v) for v in version2.split('.')]

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

# python_1_to_1000/164_Maximum_Gap.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/fraction-to-recurring-decimal/
# Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
# https://leetcode.com/problems/maximum-gap/ # If the fractional part is repeating, enclose the repeating part in parentheses.
# Given an unsorted array, find the maximum difference between the successive elements in its sorted form.

# 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)

while remainder != 0: class Solution(object):


if remainder in seen: def majorityElement(self, nums):
return "".join(decimal[:seen[remainder]] + ['('] + decimal[seen[remainder]:] + [')']) """
seen[remainder] = len(decimal) :type nums: List[int]
output, remainder = divmod(remainder*10, abs(denominator)) :rtype: int
decimal.append(str(output)) """
count, candidate = 0, None
return "".join(decimal)
for i, num in enumerate(nums):

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

_author_ = 'jake' # python_1_to_1000/179_Largest_Number.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/binary-search-tree-iterator/ _project_ = 'leetcode'
# Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.
# Calling next() will return the next smallest number in the BST. # https://leetcode.com/problems/largest-number/
# next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is the height of the tree. # Given a list of non negative integers, arrange them such that they form the largest number.
# For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.
# Iterative inorder traversal. Go left to smallest node, pushing all nodes onto stack. After popping a node, # Note: The result may be very large, so you need to return a string instead of an integer.
# add to stack all nodes on path to its inorder successor by moving to right child then as far left as possible.
# Time - O(n) worst case and O(1) average for __init__() and next(). # Comparator sorts by checking which order of concatenation gives the larger result.
# Space - O(n) worst case, log n if balanced. # Time - O(n log n)
# Space - O(n)
# Definition for a binary tree node
class TreeNode(object): import functools
def __init__(self, x):
self.val = x class Solution:
self.left = None # @param {integer[]} nums
self.right = None # @return {string}
def largestNumber(self, nums):
class BSTIterator(object):
def __init__(self, root): def comparator(x, y): # inputs are string representations of non-negative ints
""" if x+y > y+x: # no need to convert to int because x+y and y+x are same length
:type root: TreeNode return -1 # so lexicographic string sort behaves like numeric sort
""" else:
self.stack = [] return 1
while root:
self.stack.append(root) nums = list(map(str, nums)) # convert to strings
root = root.left nums.sort(key=functools.cmp_to_key(comparator))

def hasNext(self): return str(int("".join(nums))) # remove excess leading zeroes


"""
:rtype: bool
"""
return True if self.stack else False # python_1_to_1000/186_Reverse_Words_in_a_String_II.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()

def reverse(self, s, left, right):


while left < right: # python_1_to_1000/189_Rotate_Array.py - m
s[left], s[right] = s[right], s[left]
left += 1 _author_ = 'jake'
right -= 1 _project_ = 'leetcode'

# 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)

class Solution(object): # python_1_to_1000/190_Reverse_Bits.py


def findRepeatedDnaSequences(self, s):
""" _author_ = 'jake'
:type s: str _project_ = 'leetcode'
:rtype: List[str]
""" # https://leetcode.com/problems/reverse-bits/
substrings, repeated = set(), set() # Reverse bits of a given 32 bits unsigned integer.
TARGET = 10 # For example, given input 43261596 (represented in binary as 00000010100101000001111010011100),
# return 964176192 (represented in binary as 00111001011110000010100101000000).
for i in range(len(s)-TARGET+1):
# Convert to string of binary. Reverse and convert base 2 string back to int.
substring = s[i:i+TARGET] # Alternatively, if bit i is set than add 2**(31-i) to the result.
if substring in substrings: # Time - O(log n)
repeated.add(substring) # Space - O(log n)
else:
substrings.add(substring) class Solution:
# @param n, an integer
return list(repeated) # convert set to list # @return an integer
def reverseBits(self, n):
binary = bin(n)
# python_1_to_1000/188_Best_Time_to_Buy_and_Sell_Stock_IV.py - h binary = binary[2:] # remove header '0b'
reversed_binary = binary[::-1] + ''.join(['0' for _ in range(32 - len(binary))])
_author_ = 'jake' return int(reversed_binary, 2) # convert from base 2
_project_ = 'leetcode'

# https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/ class Solution2:


# Say you have an array for which the ith element is the price of a given stock on day i. # @param n, an integer
# Design an algorithm to find the maximum profit. You may complete at most k transactions. # @return an integer
# You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). def reverseBits(self, 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 = []

for node in layer:


# python_1_to_1000/191_Number_of_1_Bits.py if node.left:
next_layer.append(node.left)
_author_ = 'jake' if node.right:
_project_ = 'leetcode' next_layer.append(node.right)

# https://leetcode.com/problems/number-of-1-bits/ layer = next_layer


# Write a function that takes an unsigned integer and returns the number of ’1' bits (known as the Hamming weight).
return right_view
# Convert to string and count '1' chars.
# Time - O(log n)
# Space - O(log n) class Solution2(object):
def rightSideView(self, root):
class Solution(object): right_side = []
def hammingWeight(self, n): self.recursive(root, 0, right_side)
""" return right_side
:type n: int
:rtype: int def recursive(self, node, depth, right_side):
"""
return sum(c == "1" for c in bin(n)[2:]) if not node:
return

# python_1_to_1000/198_House_Robber.py - m if depth >= len(right_side): # update right_side with this node


right_side.append(node.val)
_author_ = 'jake' else:
_project_ = 'leetcode' right_side[depth] = node.val

# https://leetcode.com/problems/house-robber/ self.recursive(node.left, depth+1, right_side) # recurse left before right


# You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, self.recursive(node.right, depth+1, right_side)
# the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and
# it will automatically contact the police if two adjacent houses were broken into on the same night.
# Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount # python_1_to_1000/200_Number_of_Islands.py - m
# of money you can rob tonight without alerting the police.
_author_ = 'jake'
# Either do not rob current house and take max from all previous houses, or rob current house, skip previous and _project_ = 'leetcode'
# take max of all others.
# Time - O(n) # https://leetcode.com/problems/number-of-islands/
# Space - O(1) # Given a 2d grid map of '1's (land) and '0's (water), count the number of islands.
# An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically.
class Solution(object): # You may assume all four edges of the grid are all surrounded by water.
def rob(self, nums):
""" # If cell is '1' then set to '0' and recurse for all adjacent cells.
:type nums: List[int] # Time - O(m * n)
:rtype: int # Space - O(1)
"""
if not nums: class Solution(object):
return 0 def numIslands(self, grid):
loot, prev = nums[0], 0 # max from robbing this and previous adjacent houses """
:type grid: List[List[str]]
for num in nums[1:]: :rtype: int
loot, prev = max(num + prev, loot), loot """
if not grid:
return loot return 0

rows, cols = len(grid), len(grid[0])


# python_1_to_1000/199_Binary_Tree_Right_Side_View.py - m islands = 0
for r in range(rows):
_author_ = 'jake' for c in range(cols):
_project_ = 'leetcode' if grid[r][c] == '1':
islands += 1
# https://leetcode.com/problems/binary-tree-right-side-view/ self.set_island(r, c, grid)
# Given a binary tree, imagine yourself standing on the right side of it,
# return the values of the nodes you can see ordered from top to bottom. return islands

# 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 Solution(object): if sieve[i]: # i is prime


def isHappy(self, n):
""" sieve[i*i:n:i] = [False] * len(sieve[i*i:n:i]) # list comprehension faster than loop
:type n: int # start at i*i since i*(i-1) already eliminated
:rtype: bool return sum(sieve)
"""
if n == 1:
return True, 1 # python_1_to_1000/205_Isomorphic_Strings.py
slow = sum([int(c)*int(c) for c in str(n)])
fast = sum([int(c)*int(c) for c in str(slow)]) _author_ = 'jake'
_project_ = 'leetcode'
while fast != slow:
slow = sum([int(c)*int(c) for c in str(slow)]) # https://leetcode.com/problems/isomorphic-strings/
fast = sum([int(c)*int(c) for c in str(fast)]) # Given two strings s and t, determine if they are isomorphic.
fast = sum([int(c)*int(c) for c in str(fast)]) # Two strings are isomorphic if the characters in s can be replaced to get t.
# All occurrences of a character must be replaced with another character while preserving the order of characters.
return slow == 1 # No two characters may map to the same character but a character may map to itself.

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/implement-trie-prefix-tree/ while subarray_sum >= s: # decrease window


# Implement a trie with insert, search, and startsWith methods. min_length = min(min_length, i - start + 1)
# You may assume that all inputs are consist of lowercase letters a-z subarray_sum -= nums[start]

start += 1 for w in self.words[len(word)]:


for i, c in enumerate(w):
return 0 if min_length > len(nums) else min_length if word[i] != '.' and word[i] != c:
break
else:
# python_1_to_1000/210_Course_Schedule_II.py - m return True
return False
_author_ = 'jake'
_project_ = 'leetcode'

# 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):

loot, prev = 0, 0 rand_index = random.randint(left, right)


for num in nums[1:]: # do not rob first house rand_entry = nums[rand_index]
loot, prev = max(num + prev, loot), loot nums[rand_index], nums[right] = nums[right], nums[rand_index] # swap rand_index to 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/shortest-palindrome/ _author_ = 'jake'


# Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. _project_ = 'leetcode'
# Find and return the shortest palindrome you can find by performing this transformation.
# https://leetcode.com/problems/combination-sum-iii/
# Least number of characters added implies finding the longest prefix palindrome. Use KMP failure function # Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can
# algorithm to find the longest prefix of s that is also a suffix of s[::-1]. # be used and each combination should be a unique set of numbers.
# Time - O(n)
# Space - O(n) # Recursively add to partial solution all numbers greater than the previous number.
# Time - O(1), finite digits 1 to 9 implies fixed bound
class Solution(object): # Space - O(1)
def shortestPalindrome(self, s):
""" class Solution(object):
:type s: str def combinationSum3(self, k, n):
:rtype: str """
""" :type k: int
longest_prefix_suffix = self.kmp_table(s + '*' + s[::-1]) :type n: int
return s[:longest_prefix_suffix:-1] + s :rtype: List[List[int]]
"""
results = []
def kmp_table(self, word): self.cs3([], n, results, k)
failure = [-1] + [0 for _ in range(len(word)-1)] return results
pos = 2 # the next index of failure table to be computed
candidate = 0 def cs3(self, partial, target, results, k):

while pos < len(word): if len(partial) == k and target == 0: # result found


results.append(partial)
if word[pos-1] == word[candidate]: # prefix/suffix of word[:i] extends the previous prefix/suffix by 1 char
failure[pos] = candidate + 1 if len(partial) >= k or target <= 0: # cannot make sum of n with k elements
candidate += 1 return
pos += 1
elif candidate > 0: # no extension, update candidate to earlier prefix/suffix last_used = 0 if not partial else partial[-1]
candidate = failure[candidate] for i in range(last_used+1, 10): # add all greater digits than last_used
failure[pos] = 0 self.cs3(partial + [i], target-i, results, k)
else: # candidate == 0
failure[pos] = 0
pos += 1
# python_1_to_1000/217_Contains_Duplicate.py
return failure[-1]
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/215_Kth_Largest_in_an_Array.py - m
# https://leetcode.com/problems/contains-duplicate/
_author_ = 'jake' # Given an array of integers, find if the array contains any duplicates. Your function should return true if any value
_project_ = 'leetcode' # appears at least twice in the array, and it should return false if every element is distinct.

# 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()

for x, neg_h, r in edges: # python_1_to_1000/221_Maximal_Square.py - m

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'

return False # https://leetcode.com/problems/count-complete-tree-nodes/


# Given a complete binary tree, count the number of nodes.
# In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last
# level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
# python_1_to_1000/220_Contains_Duplicate_III.py - h
# Find depth of left most path in left and right subtrees. If equal then left subtree is complete, if different
_author_ = 'jake' # then right subtree is complete.
_project_ = 'leetcode' # Alternatively, find depth of left path and right path, if equal return 2**depth -1. If not recurse on subtrees,
# retaining know left path depth of left subtree and right path depth of right subtree.
# https://leetcode.com/problems/contains-duplicate-iii/ # Time - O((log n)**2), height is log n since complete. Recurse either left or right at each layer.
# Given an array of integers, find out whether there are two distinct indices i and j in the array such that the # Space - O(1)
# difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.
# Definition for a binary tree node.
# Map each num to a bucket of width t+1 so collision in bucket implies numbers are within t. Also check class TreeNode(object):
# higher and lower buckets. Remove numbers from sliding window if more than k indices earlier. def __init__(self, x):
# Time - O(n) self.val = x
# Space - O(n) self.left = None
self.right = None if c == ' ': # ignore blanks
continue
class Solution(object): if c not in digits: # operator or bracket
def countNodes(self, root): expression.append(c)
""" elif isinstance(expression[-1], int): # extending integer
:type root: TreeNode expression[-1] = expression[-1]*10 + int(c)
:rtype: int else: # new integer
""" expression.append(int(c))
if not root:
return 0 expression.append(')')
result, _ = self.evaluate(expression, 1)
left_subtree = self.left_depth(root.left) return result
right_subtree = self.left_depth(root.right)

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)

# python_1_to_1000/223_Rectangle_Area.py - m if operator == '+': # apply operator to num


calc += num
_author_ = 'jake' else:
_project_ = 'leetcode' calc -= num
i += 1
# https://leetcode.com/problems/rectangle-area/
# Find the total area covered by two rectilinear rectangles in a 2D plane. return calc, i # return calculation and index of closing bracket
# Each rectangle is defined by its bottom left corner (A, B) or (E, F) and top right corner (C, D) or (G, H).

# 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'

class Solution(object): # https://leetcode.com/problems/implement-stack-using-queues/


def computeArea(self, A, B, C, D, E, F, G, H): # Implement the following operations of a stack using queues.
""" # push(x) -- Push element x onto stack.
:type A: int # pop() -- Removes the element on top of the stack.
:type B: int # top() -- Get the top element.
:type C: int # empty() -- Return whether the stack is empty.
:type D: int # Notes:
:type E: int # You must use only standard operations of a queue -- which means only push to back, peek/pop from front, size,
:type F: int # and is empty operations are valid.
:type G: int # Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or
:type H: int # deque (double-ended queue), as long as you use only standard operations of a queue.
:rtype: int # You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
"""
x_lhs = max(A, E) # To insert, append to deque. To pop, move ell elements to new_queue until there is only one element and return that.
x_rhs = min(C, G) # To top, similar to pop except all elements are moved to new_queue. After pop or top, set queue to new_queue.
x_overlap = max(x_rhs - x_lhs, 0) # Time - O(1) for push and empty, O(n) for pop and top.
# Space - O(n)
y_lhs = max(B, F)
y_rhs = min(D, H) from collections import deque
y_overlap = max(y_rhs - y_lhs, 0)
class MyStack(object):
rect1 = (C - A) * (D - B)
rect2 = (G - E) * (H - F) def __init__(self):
"""
return rect1 + rect2 - y_overlap * x_overlap Initialize your data structure here.
"""
self.queue = deque()
# python_1_to_1000/224_Basic_Calculator.py - h
def push(self, x):
_author_ = 'jake' """
_project_ = 'leetcode' Push element x onto stack.
:type x: int
# https://leetcode.com/problems/basic-calculator/ :rtype: void
# Implement a basic calculator to evaluate a simple expression string. """
# The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative self.queue.appendleft(x)
# integers and empty spaces . You may assume that the given expression is always valid.
def pop(self):
# Preprocess string to identify integers. Recursively apply operator and bracket expression to previous result. """
# Time - O(n) Removes the element on top of the stack and returns that element.
# Space - O(n) :rtype: int
"""
class Solution(object): new_queue = deque()
def calculate(self, s): while True:
""" x = self.queue.pop()
:type s: str if not self.queue:
:rtype: int self.queue = new_queue
""" return x
digits = {str(i) for i in range(10)} new_queue.appendleft(x)
expression = ['('] # wrap whole expression with brackets, easily identifies end
def top(self):
for c in s: # pre-process string into list of operators, brackets and ints """

Get the top element.


:rtype: int
""" # python_1_to_1000/228_Summary_Ranges.py
new_queue = deque()
while self.queue: _author_ = 'jake'
x = self.queue.pop() _project_ = 'leetcode'
new_queue.appendleft(x)
self.queue = new_queue # https://leetcode.com/problems/summary-ranges/
return x # Given a sorted integer array without duplicates, return the summary of its ranges.
# For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"].
def empty(self):
""" # Create a list of pair [start, end] for each range. Extend previous range if new num is previous + 1, else
Returns whether the stack is empty. # start a new range.
:rtype: bool # Time - O(n)
""" # Space - O(n)
return len(self.queue) == 0
class Solution(object):
def summaryRanges(self, nums):
# python_1_to_1000/226_Invert_Binary_Tree.py """
:type nums: List[int]
_author_ = 'jake' :rtype: List[str]
_project_ = 'leetcode' """
summary = []
# https://leetcode.com/problems/invert-binary-tree/ for num in nums:
# Invert a binary tree. if not summary or num > summary[-1][1] + 1:
summary.append([num, num])
# Left substree is old right subtree inverted. Right subtree is old left subtree inverted. else:
# Time - O(n) summary[-1][1] = num
# Space - O(n)
result = [str(i) if i == j else str(i) + '->' + str(j) for i, j in summary]
class Solution(object): return result
def invertTree(self, root):
"""
:type root: TreeNode # python_1_to_1000/229_Majority_Element_II.py - m
:rtype: TreeNode
""" _author_ = 'jake'
if not root: _project_ = 'leetcode'
return None
# https://leetcode.com/problems/majority-element-ii/
root.left, root.right = self.invertTree(root.right), self.invertTree(root.left) # Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.
# The algorithm should run in linear time and in O(1) space.
return root
# There can be at most 2 elements that make up more than 1/3 of the input. Maintain 2 candidates, incrementing their
# counts as we find new instances. If an element is neither candidate then decrement count of both candidates.
# If an element is more than 1/3 of an array then it will remain so when 3 different elements are removed.
# python_1_to_1000/227_Basic_Calculator_II.py - m # If a count reduces to zero then the next element is a new candidate.
# Finally check if candidates are actually > 1/3 of array.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/basic-calculator-ii/ class Solution(object):


# Implement a basic calculator to evaluate a simple expression string. def majorityElement(self, nums):
# The expression string contains only non-negative integers, +, -, *, / operators and empty spaces. """
# The integer division should truncate toward zero. :type nums: List[int]
# You may assume that the given expression is always valid. :rtype: List[int]
"""
# Create a stack of partial results to be summed to get the full result. Iterate over s. When c is a digit cand1, count1 = None, 0
# increase the current integer num. When c is an operator or at end of string, apply the previous operator cand2, count2 = None, 0
# to num. For '*' and '/' this uses the previous integer on the stack.
# Time - O(n) for num in nums:
# Space - O(n) if num == cand1: # increment count of candidate
count1 += 1
class Solution(object): elif num == cand2: # increment count of candidate
def calculate(self, s): count2 += 1
""" elif count1 == 0: # new cancidate
:type s: str cand1 = num
:rtype: int count1 = 1
""" elif count2 == 0: # new cancidate
stack = [] cand2 = num
num = 0 count2 = 1
op = '+' else: # 'remove' 3 different elements (cand1, cand2, num) from count
count1 -= 1
for i, c in enumerate(s): count2 -= 1

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]

if (not c.isdigit() and c != ' ') or i == len(s)-1: # c is an operator or end of string


if op == '+': # use previous operator op
stack.append(num)
elif op == '-': # python_1_to_1000/230_Kth_Smallest_Element_in_a_BST.py - m
stack.append(-num)
elif op == '*': _author_ = 'jake'
stack.append(stack.pop() * num) _project_ = 'leetcode'
else: # op == '/'
left = stack.pop() # https://leetcode.com/problems/kth-smallest-element-in-a-bst/
stack.append(left // num) # Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
if left // num < 0 and left % num != 0:
stack[-1] += 1 # # negative integre division result with remainder rounds down by default # Iterative inorder traversal.
num = 0 # num has been used so reset # Alternatively, recursive inorder traversal tracking remaining count with instance variable.
op = c # Time - O(n)
# Space - O(n)
return sum(stack)
# Definition for a binary tree node. """
class TreeNode(object): self.stack = []
def __init__(self, x): self.reversed = []
self.val = x self.top = None
self.left = None
self.right = None def push(self, x):
"""
class Solution(object): Push element x to the back of queue.
def kthSmallest(self, root, k): :type x: int
""" :rtype: void
:type root: TreeNode """
:type k: int if not self.stack:
:rtype: int self.top = x
""" self.stack.append(x)
stack = []
while root: def pop(self):
stack.append(root) """
root = root.left Removes the element from in front of queue and returns that element.
:rtype: int
while stack: """
node = stack.pop() if not self.reversed:
k -= 1 while self.stack:
if k == 0: self.reversed.append(self.stack.pop())
return node.val return self.reversed.pop()
node = node.right
while node: def peek(self):
stack.append(node) """
node = node.left Get the front element.
:rtype: int
class Solution2(object): """
def kthSmallest(self, root, k): if self.reversed:
self.k = k # instance variables return self.reversed[-1]
self.result = None return self.top
self.helper(root)
return self.result def empty(self):
"""
def helper(self, node): Returns whether the queue is empty.
if not node: :rtype: bool
return """
self.helper(node.left) return not self.stack and not self.reversed
self.k -= 1
if self.k == 0:
self.result = node.val # python_1_to_1000/233_Number_of_Digit_One.py - h
return
self.helper(node.right) _author_ = 'jake'
_project_ = 'leetcode'

# 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))):

_author_ = 'jake' blocks, rem = divmod(n + 1, block_size)


_project_ = 'leetcode' ones += blocks * block_size // 10 # nb blocks * nb ones in a block
ones += min(block_size // 10, max(0, rem - block_size // 10)) # partial blocks
# https://leetcode.com/problems/implement-queue-using-stacks/ block_size *= 10
# Implement the following operations of a queue using stacks.
# push(x) -- Push element x to the back of queue. return ones
# pop() -- Removes the element from in front of queue.
# peek() -- Get the front element. print(Solution().countDigitOne(524))
# empty() -- Return whether the queue is empty.
# You may assume that all operations are valid (e.g., no pop or peek operations will be called on an empty queue).

# 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'

class MyQueue(object): # https://leetcode.com/problems/palindrome-linked-list/


# Given a singly linked list, determine if it is a palindrome.
def __init__(self):
""" # Move a fast pointer and a slow pointer along the list. Slow pointer nodes are added to reversed list.
Initialize your data structure here. # When no more fast move is possible, iterate along slow and back along reversed list checking for val equality.

# Time - O(n) """


# Space - O(1)
if not root or p == root or q == root: # base cases
class Solution(object): return root
def isPalindrome(self, head):
""" left_lca = self.lowestCommonAncestor(root.left, p, q)
:type head: ListNode right_lca = self.lowestCommonAncestor(root.right, p, q)
:rtype: bool
""" if left_lca and right_lca:
fast, slow = head, head return root
rev = None # head of the already-reversed part return left_lca or right_lca

while fast and fast.next:


fast = fast.next.next # python_1_to_1000/237_Delete_Node_in_a_Linked_List.py - m
next_slow = slow.next
slow.next = rev _author_ = 'jake'
rev = slow _project_ = 'leetcode'
slow = next_slow
# https://leetcode.com/problems/delete-node-in-a-linked-list/
# if fast is not null, slow is middle element of odd length list which is skipped # Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
# if fast is null, slow is first element of 2nd half of even length list # Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, the linked list should
if fast: # become 1 -> 2 -> 4 after calling your function.
slow = slow.next
# Copy the value of the next node to the given node and connext the node to the next after next. I.e. remove the next
while slow: # node after moving its value to the given node.
if slow.val != rev.val: # Time - O(1)
return False # Space - O(1)
slow = slow.next
rev = rev.next class Solution(object):
def deleteNode(self, node):
return True """
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
# python_1_to_1000/235_Lowest_Common_Ancestor_of_a_Binary_Search_Tree.py - m """
node.val = node.next.val
_author_ = 'jake' node.next = node.next.next
_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]

# https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/ return products


# Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
# The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v
# and w as descendants (where we allow a node to be a descendant of itself). # python_1_to_1000/239_Sliding_Window_Maximum.py - h

# 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)

_author_ = 'jake' memo[(left, right)] = ways


_project_ = 'leetcode' return ways

# 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):

for i in range(len(input)): if word == word1:


if not input[i].isdigit(): i_1 = i
parsed.append(int(input[start:i])) # append integer shortest = min(shortest, i_1 - i_2)
parsed.append(input[i]) # append operator if word == word2:
start = i+1 i_2 = i
parsed.append(int(input[start:len(input)])) shortest = min(shortest, i_2 - i_1)

return self.diff_ways(parsed, 0, len(parsed)-1, {}) return shortest

# 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

if min_len == 1: left_uni = self.is_univariate(root.left)


strobo_count += len([i for i in other_list if low <= int(i) <= high]) right_uni = self.is_univariate(root.right)

for i in range(2, max_len+1): if left_uni and right_uni:


live_list = [c + r + strobo[c] for r in live_list for c in strobo] # wrap c and strobo[c] around previous if (not root.left or root.left.val == root.val) and (not root.right or root.right.val == root.val):
numbers self.univariates += 1
return True
if min_len < i < max_len: # add all numbers in list not beginning with zero
strobo_count += len([True for result in live_list if result[0] != '0']) return False
elif i == min_len or i == max_len: # add numbers not beginning with zero and between low and high
strobo_count += len([True for result in live_list if result[0] != '0' and low <= int(result) <= high])

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

# python_1_to_1000/249_Group_Shifted_Strings.py - m def preorder(self, root):


if not root:
_author_ = 'jake' return
_project_ = 'leetcode' if self.is_univariate(root):
self.univariates += 1
# https://leetcode.com/problems/group-shifted-strings/ self.preorder(root.left)
# Given a string, we can "shift" each of its letter to its successive letter, for example: "abc" -> "bcd". We can self.preorder(root.right)
# keep "shifting" which forms the sequence: "abc" -> "bcd" -> ... -> "xyz"
# Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same def is_univariate(self, root):
# shifting sequence. if not root:
return True
# For each string, shift so first character is "a". Map shifted string to list of all unshifted strings. if root.left and root.left.val != root.val:
# Time - O(n), total number of chars of all strings return False
# Space - O(n) if root.right and root.right.val != root.val:
return False
from collections import defaultdict return self.is_univariate(root.left) and self.is_univariate(root.right)

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):

def __init__(self, vec2d):


# python_1_to_1000/250_Count_Univalue_Subtrees.py - m """
Initialize your data structure here.
_author_ = 'jake' :type vec2d: List[List[int]]
_project_ = 'leetcode' """
self.vec2d = vec2d
# https://leetcode.com/problems/count-univalue-subtrees/ self.list_nb, self.item_nb = 0, 0
# Given a binary tree, count the number of uni-value subtrees. # while empty sublist, move to next sublist until end of vec2d
# A Uni-value subtree means all nodes of the subtree have the same value. while self.list_nb < len(self.vec2d) and len(self.vec2d[self.list_nb]) == 0:
self.list_nb += 1
# Bottom-up count univariate subtrees in left and right subtrees than add 1 if both subtrees are univariate with the
# same value as the root. def next(self):
# Alternatively define a function to test if the subtree rooted at that node is univariate (which explores the subtree) """
# and preorder (or inorder/postorder) traverse the tree to test all nodes. O(n**2) time but runs faster on the :rtype: int
# leetcode test cases. """
# Time - O(n) result = self.vec2d[self.list_nb][self.item_nb]
# Space - O(1) if self.item_nb < len(self.vec2d[self.list_nb]) - 1:
self.item_nb += 1 # not end of sublist, increment item
# Definition for a binary tree node. else: # end of sublist, reset item and find next non-empty sublist or end of vec2d
class TreeNode(object): self.item_nb = 0
def __init__(self, x): self.list_nb += 1
self.val = x while self.list_nb < len(self.vec2d) and len(self.vec2d[self.list_nb]) == 0:
self.left = None self.list_nb += 1
self.right = None return result

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

if interval.start < intervals[i - 1].end: if n % trial == 0: # trial is a factor


return False factors.append(partial + [n//trial, trial]) # append this result
self.factorise(n//trial, trial, partial + [trial], factors) # try and factorise again with trial
return True trial += 1

return factors
# python_1_to_1000/253_Meeting_Rooms_II.py - m

_author_ = 'jake' class Solution2(object):


_project_ = 'leetcode' def getFactors(self, n):
stack = [(n, 2, [])] # tuples of number to factorise, trial factor, list of previous factors
# https://leetcode.com/problems/meeting-rooms-ii/ factors = []
# Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei),
# find the minimum number of conference rooms required. while stack:
num, trial, partial = stack.pop()
# Use a heap to store the end times of meetings that have not finished. For each new meeting in start time order,
# push it onto heap, pop all meetings that have already ended and update max_rooms being used. while trial * trial <= num: # as per recursive with push to stack replacing function call
# Alternatively, use heap to store the end times of all meetings that need their own rooms. If a new meeting does
# not overlap with the earliest ending existing meeting then replace existing with new meeting. New meet will overlap if num % trial == 0:
# with all others on heap. factors.append(partial + [num//trial, trial])
# Time - O(n log n) stack.append((num//trial, trial, partial + [trial]))
# Space - O(n) trial += 1

# Definition for an interval. return factors


class Interval(object):
def __init__(self, s=0, e=0):
self.start = s
self.end = e

import heapq

class Solution(object): # python_1_to_1000/255_Verify_Preorder_Sequence_in_Binary_Search_Tree.py - m


def minMeetingRooms(self, intervals):
""" _author_ = 'jake'
:type intervals: List[Interval] _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/
max_rooms = 0 # Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary search tree.
rooms = [] # heap of end times of overlapping meetings # You may assume each number in the sequence is unique.
intervals.sort(key=lambda x: x.start) # sort by start time
# Whilst the values are decreasing they are left children and we push them onto a stack. When we see a higher value
for interval in intervals: # it must be a right child so pop off all smaller values, the last of which is the parent of the current value.
# Anything smaller than the parent should have been traversed already so parent is the minimum of future values.
heapq.heappush(rooms, interval.end) # Time - O(n)
while rooms[0] <= interval.start: # pop all meetings that have ended before this meeting starts # Space - O(n)
heapq.heappop(rooms)
max_rooms = max(max_rooms, len(rooms)) class Solution(object):
def verifyPreorder(self, preorder):
return max_rooms """
:type preorder: List[int]
:rtype: bool
class Solution2(object): """
def minMeetingRooms(self, intervals): stack = [float('inf')] # added so do not need to check is empty
overlaps = [] minimum = float('-inf')
intervals.sort(key=lambda x: x.start)
for value in preorder:
for interval in intervals:
if value < minimum:
if overlaps and interval.start >= overlaps[0]: # starts after earliest end time so replace return False
heapq.heapreplace(overlaps, interval.end)
else: # overlaps so push to heap while value > stack[-1]:
heapq.heappush(overlaps, interval.end) minimum = stack.pop() # will only ever increase
stack.append(value)
return len(overlaps)
return True

# 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):

for i in range(1, len(costs)): left, right = i+1, len(nums)-1


costs[i][0] += min(costs[i-1][1], costs[i-1][2]) while left < right:
costs[i][1] += min(costs[i-1][0], costs[i-1][2]) if nums[i] + nums[left] + nums[right] < target:
costs[i][2] += min(costs[i-1][0], costs[i-1][1]) count += right - left
left += 1
return min(costs[-1]) else:
right -= 1

# python_1_to_1000/257_Binary_Tree_Paths.py return count

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/260_Single_number_III.py - m

# https://leetcode.com/problems/binary-tree-paths/ _author_ = 'jake'


# Given a binary tree, return all root-to-leaf paths. _project_ = 'leetcode'

# 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'

class Solution(object): # https://leetcode.com/problems/graph-valid-tree/


def addDigits(self, num): # Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes),
""" # write a function to check whether these edges make up a valid tree.
:type num: int
:rtype: int # Tree has the minimum number of edges to whilst still being connected. If not n-1 edges then must be loop and/or not
""" # connected so not a tree. If n-1 edges then graph is either a tree or (not connected and loop).
while num > 9: # Test for not connected by depth first search. From any starting node, remove node from graph and recurse on all
num = sum([int(c) for c in str(num)]) # neighbours. If any node not removed then graph is not connected so not a tree.
return num # Alternatively identify loops by keeping an array of the furthest node reachable from any starting node. Union-find
# identifies connected regions.
# Time - O(n + m), nodes + edges
# python_1_to_1000/259_3Sum_Smaller.py - m # Space - O(n + m)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def validTree(self, n, edges):
"""
# https://leetcode.com/problems/3sum-smaller/ :type n: int

:type edges: List[List[int]]


:rtype: bool
""" # python_1_to_1000/264_Ugly_Number_II.py - m

class Solution(object): _author_ = 'jake'


def validTree(self, n, edges): _project_ = 'leetcode'
"""
:type n: int # https://leetcode.com/problems/ugly-number-ii/
:type edges: List[List[int]] # Write a program to find the n-th ugly number.
:rtype: bool # Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.
""" # For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
# Note that 1 is typically treated as an ugly number, and n does not exceed 1690.
def dfs(node): # recursively removes nbors from mapping
nbors = adjacency.pop(node, []) # Create the sequence of ugly numbers and track the last index that has not been multiplied by 2 to generate another
for nbor in nbors: # number in the sequence as i_2. Similarly track i_3 and i_5. The next number is the lowest new number that can be
dfs(nbor) # generated. Increment all indices that can generate thhe latest ugly number (since more than one of 2, 3 and 5 may be
# able to generate the last number.
if len(edges) != n - 1: # eliminate if too many/few edges for n nodes # Time - O(n)
return False # Space - O(n)

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

class Solution2(object): while len(ugly) < n:


def validTree(self, n, edges):
""" ugly.append(min(2 * ugly[i_2], 3 * ugly[i_3], 5 * ugly[i_5])) # append smallest
:type n: int
:type edges: List[List[int]] if ugly[-1] == 2 * ugly[i_2]: # increment i_2 if latest ugly can be generated from 2 * ugly[i_2]
:rtype: bool i_2 += 1
""" if ugly[-1] == 3 * ugly[i_3]: # increment i_3 if latest ugly can be generated from 3 * ugly[i_3]
def find(node): i_3 += 1
if parents[node] == -1: if ugly[-1] == 5 * ugly[i_5]: # increment i_5 if latest ugly can be generated from 5 * ugly[i_5]
return node i_5 += 1
return find(parents[node])
return ugly[-1]
if len(edges) != n - 1:
return False
# python_1_to_1000/265_Paint_House_II.py - h
parents = [-1] * n
_author_ = 'jake'
for a, b in edges: _project_ = 'leetcode'

a_parent = find(a) # https://leetcode.com/problems/paint-house-ii/


b_parent = find(b) # There are a row of n houses, each house can be painted with one of the k colors.
# The cost of painting each house with a certain color is different. You have to paint all the houses such that
if a_parent == b_parent: # already have same parent before this edge # no two adjacent houses have the same color.
return False
parents[a_parent] = b_parent # For each house, calculate the min cost of painting that house each colour given min costs of painting upto the
# previous house each colour.
return True # Find the colour that minimises the cost of painting upto and including the previous house. The min cost of painting
# the next house any colour apart from the previous min cost colour is the cost of the previous min cost + new colour.
# The min cost of painting the next house the same as the previous min colour is the cost of painting previous house
# is second lowest cost colout + new colour.
# python_1_to_1000/263_Ugly_Number.py # Time - O(nk)
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def minCostII(self, costs):
# https://leetcode.com/problems/ugly-number/ """
# Write a program to check whether a given number is an ugly number. :type costs: List[List[int]]
# Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is :rtype: int
# not ugly since it includes another prime factor 7. """
# 1 is typically treated as an ugly number. if not costs or not costs[0]:
# Input is within the 32-bit signed integer range. return 0

# 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 letter, count in freq.items(): _author_ = 'jake'


if count % 2 == 1: _project_ = 'leetcode'
if odd: # amother char has odd count
return False # https://leetcode.com/problems/alien-dictionary/
odd = True # There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you.
# You receive a list of words from the dictionary, where words are sorted lexicographically by the rules of this
return True # new language. Derive the order of letters in this language.

# 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

from collections import Counter for i in range(1, len(words)):


diff_to_prev = False
class Solution(object):
def generatePalindromes(self, s): for j, c in enumerate(words[i]):
""" seen.add(c) # add every char of every word to seen
:type s: str
:rtype: List[str] # new difference from previous word at this position
""" if j < len(words[i-1]) and not diff_to_prev and c != words[i-1][j]:
char_counts = Counter(s) if c not in order[words[i-1][j]]: # have not seen this ordering before
odd_char = "" # char with an odd count order[words[i-1][j]].add(c)
after[c] += 1
for char, count in char_counts.items(): diff_to_prev = True
if count % 2 != 0:
if odd_char: if not diff_to_prev and len(words[i-1]) > len(words[i]): # no differences and longer word first
return [] # more than one odd count, cannot form palindromes return ""
odd_char = char
char_counts[odd_char] -= 1 # decrement counter for c in seen: # all chars depend on at least zero previous chars
if c not in after:
palindromes = [] after[c] = 0
self.build_palindromes(palindromes, [], char_counts, len(s)//2)
return ["".join(p + [odd_char] + p[::-1]) for p in palindromes] frontier = set() # frontier have no dependencies
for a in after:
if after[a] == 0:
def build_palindromes(self, palindromes, partial, char_counts, remaining): frontier.add(a)

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

_author_ = 'jake' # python_1_to_1000/270_Closest_Binary_Search_Tree_Value.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): # https://leetcode.com/problems/find-the-celebrity/


def hIndex(self, citations): # Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity.
""" # The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them.
:type citations: List[int] # Now you want to find out who the celebrity is or verify that there is not one.
:rtype: int # The only thing you are allowed to do is to ask questions "Does A know B?". You need to find out the celebrity (or
""" # verify there is not one) by asking as few questions as possible (in the asymptotic sense).
buckets = [0] * (len(citations)+1) # each bucket index represents a number of citations
for citation in citations: # buckets[i] is the number of papers cited i times # Find the only candidate by testing each person. If the candidate knows that person, the candidate is not a celebrity
buckets[min(citation, len(citations))] += 1 # and the new candidate is the test person. If the candidate doesn't know that person, then that person is not a
# celebrity. Note that there can be only one or zero celebrities.
papers = 0 # count of papers with at least buckets citations # Then verify whether the candidate if valid.
for bucket in range(len(buckets)-1, -1, -1): # Time - O(n)
papers += buckets[bucket] # Space - O(1)
if papers >= bucket:
return bucket # The knows API is already defined for you.
# @param a, person a
# @param b, person b
# python_1_to_1000/275_H-Index_II.py - m # @return a boolean, whether a knows b
def knows(a, b):
_author_ = 'jake' return
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/h-index-ii/ def findCelebrity(self, n):
# Follow up for 274_H-Index: What if the citations array is sorted in ascending order? """
:type n: int
# Binary search. If the number of citations of the paper at index mid is at least the count of papers with :rtype: int
# a smaller or equal number of citations then search on the left, else search right. """
# Time - O(log n) candidate = 0
# Space - O(1) for i in range(1, n):
if knows(candidate, i):
class Solution(object): candidate = i
def hIndex(self, citations):
""" for i in range(n):
:type citations: List[int] if i == candidate:
:rtype: int continue
""" if not knows(i, candidate) or knows(candidate, i):
n = len(citations) return -1
left, right = 0, n-1 return candidate

while left <= right:


mid = (left + right) // 2
# python_1_to_1000/278_First_Bad_Version.py
if citations[mid] >= n-mid:
right = mid - 1 _author_ = 'jake'
else: _project_ = 'leetcode'
left = mid + 1
# https://leetcode.com/problems/first-bad-version/
return n-left # You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version
# of your product fails the quality check. Since each version is developed based on the previous version, all the
# versions after a bad version are also bad.
# python_1_to_1000/276_Paint_Fence.py - m # Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the
# following ones to be bad.
_author_ = 'jake' # You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to
_project_ = 'leetcode' # find the first bad version. You should minimize the number of calls to the API.

# https://leetcode.com/problems/paint-fence/ # Binary search.


# There is a fence with n posts, each post can be painted with one of the k colors. # Time - O(log n)
# You have to paint all the posts such that no more than two adjacent fence posts have the same color. # Space - O(1)

"""
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]

return left def hasNext(self):


"""
:rtype: bool
# python_1_to_1000/279_Perfect_Squares.py - m """
return bool(self.q)
_author_ = 'jake'
_project_ = 'leetcode'

# 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

class Solution(object): if i != index and self.num[index] == '0':


def wiggleSort(self, nums): break # no leading zeros unless single digit
"""
:type nums: List[int] cur_str = self.num[index:i+1] # insert operator then cur
:rtype: void Do not return anything, modify nums in-place instead. cur_int = int(cur_str)
"""
for i in range(1, len(nums)): if index == 0: # no operator if start of nums
if i%2 ^ (nums[i] >= nums[i-1]): self.helper(path + cur_str, i + 1, cur_int, cur_int)
nums[i], nums[i-1] = nums[i-1], nums[i] else:
self.helper(path + "+" + cur_str, i + 1, eval + cur_int , cur_int)
self.helper(path + "-" + cur_str, i + 1, eval - cur_int, -cur_int)
self.helper(path + "*" + cur_str, i + 1, eval - multed + multed * cur_int, multed * cur_int)
# python_1_to_1000/281_Zigzag_Iterator.py - m

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/283_Move_Zeros.py

# https://leetcode.com/problems/zigzag-iterator/ _author_ = 'jake'


# Given two 1d vectors, implement an iterator to return their elements alternately. _project_ = 'leetcode'

# 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

nums[i:] = [0] * (len(nums) - i) class Solution2(object):


def inorderSuccessor(self, root, p):
if not root:
return None
# python_1_to_1000/284_Peeking_Iterator.py - m
if p.val >= root.val:
_author_ = 'jake' return self.inorderSuccessor(root.right, p)
_project_ = 'leetcode'
left_succ = self.inorderSuccessor(root.left, p)
# https://leetcode.com/problems/peeking-iterator/
# Given an Iterator class interface with methods: next() and hasNext(), design and implement a PeekingIterator that return root if not left_succ else left_succ
# supports the peek() operation -- i.e. returns the element that will be returned by the next call to next().

# 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

# https://leetcode.com/problems/inorder-successor-in-bst/ _author_ = 'jake'


# Given a binary search tree and a node in it, find the in-order successor of that node in the BST. _project_ = 'leetcode'
# If the given node has no in-order successor in the tree, return None.
# https://leetcode.com/problems/find-the-duplicate-number/
# Iterate through tree, whenever we go left update the successor. # Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive),
# Alternatively recursively explore right subtree if target value >= node value since successor must then be on right. # assume that there is only one duplicate number, find the duplicate one.
# If target value < node value and successor is not in left subtree then node is the successor. # You must not modify the array (assume the array is read only).
# Time - O(n), height of tree so log n if balanced # There is only one duplicate number in the array, but it could be repeated more than once.
# Space - O(1)
# For each integer i in nums, nums[i] is also in nums. Since there are more slots in nums than unique integers in
# Definition for a binary tree node. # the range [1 .. n] inclusive then some integer must be duplicated. By following a path i, nums[i], nums[nums[i]], ...
class TreeNode(object): # the path must eventually repeat. There is a cycle whereby nums[j] has already been visited. Find cycle as per
def __init__(self, x): # problem 142_Linked_List_Cycle_II - advance fast and slow pointers until they meet then reset one pointer to starting
self.val = x # position and advance together until meet again.
self.left = None # Time - O(n)
self.right = None # Space - O(1)

class Solution(object): class Solution(object):


def inorderSuccessor(self, root, p): def findDuplicate(self, nums):
""" """

:type nums: List[int] return


:rtype: int rows, cols = len(board), len(board[0])
"""
slow = nums[0] for r in range(rows):
fast = nums[slow] for c in range(cols):
nbors = self.count_neighbours(r, c, board)
while fast != slow: # move slow pointer 1 step and fast 2 steps until collide if nbors == 3 or (board[r][c] and nbors == 2):
slow = nums[slow] board[r][c] += 2 # set second bit so signify next status is alive
fast = nums[nums[fast]]
for r in range(rows):
fast = 0 # restart fast from index zero and move both pointers one step at a time for c in range(cols):
while fast != slow: board[r][c] >>= 1 # 2nd bit determines next status
slow = nums[slow]
fast = nums[fast]
return fast def count_neighbours(self, r, c, board):

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

# python_1_to_1000/289_Game_of_Life.py - m return True

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/291_Word_Pattern_II.py - m

# https://leetcode.com/problems/game-of-life/ _author_ = 'jake'


# Given a board with m by n cells, each cell has an initial state live (1) or dead (0). _project_ = 'leetcode'
# Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules::
# Any live cell with fewer than two live neighbors dies, as if caused by under-population. # https://leetcode.com/problems/word-pattern-ii/
# Any live cell with two or three live neighbors lives on to the next generation. # Given a pattern and a string str, find if str follows the same pattern.
# Any live cell with more than three live neighbors dies, as if by over-population.. # Follow means a full match, such that there is a bijection between a letter in pattern and a non-empty substring in
# Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. str.
# Write a function to compute the next state (after one update) of the board given its current state. # Each letter in pattern maps to a substring of str e.g. pattern = "abab", str = "redblueredblue" should return true.
# You may assume both pattern and str contain only lowercase letters.
# For each cell in current board count neighbours and if 3 or 2 and cell is alive, set the second bit to signify
# that in the next timestep the cell will be alive. Then update the fisrt bit to the second bit. # For each character c in pattern, attempt to match this with test_s, a prefix of str. If neither c nor the prefix
# Time - O(m * n) # have been used before, set this mapping and recurse. Delete mapping if recursion does not match remainders.
# Space - O(1) # If c is already mapped to prefix, recurse. Invalid mapping if either c or test_s are mapped but not to each other.
# Time - O(m*n), for each char of pattern, try each prefix of str
class Solution(object): # Space - O(n)
def gameOfLife(self, board):
""" class Solution(object):
:type board: List[List[int]]
:rtype: void Do not return anything, modify board in-place instead. def wordPatternMatch(self, pattern, str):
""" """
if not board or not board[0]: :type pattern: str
:type str: str _project_ = 'leetcode'
:rtype: bool
""" # https://leetcode.com/problems/flip-game-ii/
m, n = len(pattern), len(str) # You are playing the following Flip Game with your friend: Given a string that contains only these two characters:
# + and -, you and your friend take turns to flip two consecutive "++" into "--". The game ends when a person can
def is_match(i, j): # no longer make a move and therefore the other person will be the winner.
# Write a function to determine if the starting player can guarantee a win.
if i >= m and j >= n:
return True # Find every '++' in s and if there is no winning strategy for opponent after converting it to '--' then this is a
if i >= m: # no pattern but some str remains unmatched # winning strategy.
return False # Time - O(n * n!), if string contains only '+' then n - 1 choices for first pair to replace, (n - 1)(n - 3)
# for second pair .. each replacement takes O(n)
for end in range(j, n - (m - i) + 1): # leave at least 1 char in str for each of remaining pattern # Space - O(n * n!)

p, test_s = pattern[i], str[j:end + 1] # try to match test_s with p class Solution(object):


if p not in mapping and test_s not in s_used: # neither p nor test_s are used def canWin(self, s):
mapping[p] = test_s """
s_used.add(test_s) :type s: str
if is_match(i + 1, end + 1): :rtype: bool
return True """
del mapping[p] # revert mapping and s_used since failed
s_used.discard(test_s) def helper(s):

elif p in mapping and mapping[p] == test_s: # p already mapped to test_s if s in memo:


if is_match(i + 1, end + 1): return memo[s]
return True
for i in range(len(s) - 1):
return False if s[i:i + 2] == '++' and not helper(s[:i] + '--' + s[i + 2:]):
memo[s] = True
mapping = {} return True
s_used = set()
return is_match(0, 0) memo[s] = False
return False

# 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

# python_1_to_1000/293_Flip_Game.py class MedianFinder:


def __init__(self):
_author_ = 'jake' """
_project_ = 'leetcode' Initialize your data structure here.
"""
# https://leetcode.com/problems/flip-game/ self.lower = [] # lower half of numbers, and the extra num if count is odd
# You are playing the following Flip Game with your friend: Given a string that contains only these two characters: self.higher = [] # higher half of numbers
# + and -, you and your friend take turns to flip two consecutive "++" into "--".
# The game ends when a person can no longer make a move and therefore the other person will be the winner. def addNum(self, num):
# Write a function to compute all possible states of the string after one valid move. """
Adds a num into the data structure.
# Iterate over s looking at pairs of chars and chaning any "++" to "--". :type num: int
# Time - O(n**2) :rtype: void
# Space - O(n**2) """
if not self.lower or num <= -self.lower[0]: # push onto appropriate heap
class Solution(object): heapq.heappush(self.lower, -num)
def generatePossibleNextMoves(self, s): else:
""" heapq.heappush(self.higher, num)
:type s: str
:rtype: List[str] if len(self.higher) > len(self.lower): # rebalance if more than half on higher heap
""" heapq.heappush(self.lower, -heapq.heappop(self.higher))
result = [] elif len(self.lower) > 1 + len(self.higher): # or more than half+1 on lower
heapq.heappush(self.higher, -heapq.heappop(self.lower))
for i in range(len(s) - 1):
if s[i:i + 2] == "++": def findMedian(self):
result.append(s[:i] + "--" + s[i + 2:]) """
Returns the median of current data stream
return result :rtype: float
"""
if len(self.lower) > len(self.higher):
# python_1_to_1000/294_Flip_Game_II.py - m return float(-self.lower[0])
return (-self.lower[0] + self.higher[0]) / 2.0
_author_ = 'jake'

def deserialize(self, data):


"""Decodes your encoded data to tree.
# python_1_to_1000/296_Best_Meeting_Point.py - h :type data: str
:rtype: TreeNode
_author_ = 'jake' """
_project_ = 'leetcode' node_list = deque(data.split(","))

# https://leetcode.com/problems/best-meeting-point/ def rebuild():


# A group of two or more people wants to meet and minimize the total travel distance.
# You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. if not node_list:
# Calculated the minimum travel using Manhattan Distance, return None

# 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'

def serialize(self, root): # https://leetcode.com/problems/bulls-and-cows/


"""Encodes a tree to a single string. # You are playing the following Bulls and Cows game with your friend: You write down a number and ask your friend to
:type root: TreeNode # guess what the number is. Each time your friend makes a guess, you provide a hint that indicates how many digits in
:rtype: str # said guess match your secret number exactly in both digit and position (called "bulls") and how many digits match
""" # the secret number but locate in the wrong position (called "cows"). Your friend will use successive guesses and
nodes = [] # hints to eventually derive the secret number.
# For example: Secret number: "1807" Friend's guess: "7810"
def preorder(node): # Hint: 1 bull and 3 cows. (The bull is 8, the cows are 0, 1 and 7.)
if not node: # Write a function to return a hint according to the secret number and friend's guess, use A to indicate the bulls
nodes.append("null") # and B to indicate the cows. In the above example, your function should return "1A3B".
else: # Please note that both secret number and friend's guess may contain duplicate digits.
nodes.append(str(node.val)) # You may assume that the secret number and your friend's guess only contain digits, and their lengths are always equal.
preorder(node.left)
preorder(node.right) # Iterate over secret and guess together. If digits match increment bulls, else increment counts of unmatched digits in
# secret and guess. Then iterate over unmatched_guess digits, incrementing cows by the lower of unmatched_secret
preorder(root) # and unmatched_guess counts for each digit.
return ",".join(nodes) # assumes TreeNode.val do not include comma # Time - O(n)
# Space - O(1)
return valid
from collections import defaultdict

class Solution(object): def remove(self, s, valid, start, removed, par):


def getHint(self, secret, guess): net_open = 0
"""
:type secret: str for i in range(start, len(s)):
:type guess: str net_open += ((s[i] == par[0]) - (s[i] == par[1]))
:rtype: str if net_open >= 0:
""" continue
bulls, cows = 0, 0
unmatched_secret, unmatched_guess = defaultdict(int), defaultdict(int) # string is invalid so remove a closing bracket
for j in range(removed, i+1):
for s, g in zip(secret, guess): if s[j] == par[1] and (j == removed or s[j - 1] != par[1]):
if s == g: self.remove(s[:j] + s[j+1:], valid, i, j, par)
bulls += 1 return
else:
unmatched_secret[s] += 1 reversed = s[::-1]
unmatched_guess[g] += 1 if par[0] == '(': # finished left to right
self.remove(reversed, valid, 0, 0, (')', '('))
for g, count in unmatched_guess.items(): else: # finished right to left
cows += min(unmatched_secret[g], count) valid.append(reversed)

return str(bulls) + "A" + str(cows) + "B"

# python_1_to_1000/300_Longest_Increasing_Subsequence.py - m # python_1_to_1000/302_Smallest_Rectangle_Enclosing_Black_Pixels.py - h

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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)

# find lowest index of a row with any white cells


def binary_search(self, num, LIS): # return the index in LIS of the smallest number < num bottom_edge = self.find_edge(x+1, len(image), True, False, image)
left, right = 0, len(LIS)-1 # or -1 if no such number
# find lowest index of a col with any black cells
while left <= right: left_edge = self.find_edge(0, y, False, 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

return right def find_edge(self, left, right, column, black, image):


while left < right:
mid = (left + right) // 2
# python_1_to_1000/301_Remove_Invalid_Parentheses.py - h if black == self.any_black(mid, column, image):
right = mid
_author_ = 'jake' else:
_project_ = 'leetcode' left = mid + 1
return left
# https://leetcode.com/problems/remove-invalid-parentheses/
# Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.
# The input string may contain letters other than the parentheses ( and ). def any_black(self, i, column, image):
if column: # if checking all columns, return True if any '1' in row i
# When there are more closing than opening brackets, remove any previous closing bracket at the last removed position return ('1' in image[i])
# or without a closing bracket before it (to avoid duplicate solutions) and recurse for remainder of string. If else: # if checking all rows, return True if any '1' in column i
# string is then valid, reverse string and switch opening and closing brackets to repeat in other direction. return any(image[r][i] == '1' for r in range(len(image)))

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:

def sumRange(self, i, j): if (r, c) in parent: # ignore duplicate land


""" island_count.append(island_count[-1])
:type i: int continue
:type j: int
:rtype: int nbors = set()
"""
return self.cumul[j + 1] - self.cumul[i] for nbor in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]:
if nbor in parent:
island = parent[nbor]
# python_1_to_1000/304_Range_Sum_Query_2D-Immutable.py - m while island != parent[island]:
parent[island] = parent[parent[island]] # path compression
_author_ = 'jake' island = parent[island]
_project_ = 'leetcode' nbors.add(island)

# https://leetcode.com/problems/range-sum-query-2d-immutable/ if not nbors:


# Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner parent[(r, c)] = (r, c) # own parent
# (row1, col1) and lower right corner (row2, col2) where row1 ≤ row2 and col1 ≤ col2. island_count.append(island_count[-1] + 1)
# You may assume that the matrix does not change. There are many calls to sumRegion function. else:
this_island = nbors.pop()
# Store cumulative sums to each cell as cell value + cumulative sum to previous row + cumulative sum to previous col - for nbor in nbors:
# cumulative sum to previous row and col. parent[nbor] = this_island
# Time - O(m * n) to initialise, O(1) for sumRegion() parent[(r, c)] = this_island
# Space - O(1) island_count.append(island_count[-1] - len(nbors))

class NumMatrix(object): return island_count[1:]

def __init__(self, matrix):


"""
:type matrix: List[List[int]]
""" # python_1_to_1000/306_Additive_Number.py - m
if not matrix or not matrix[0]:
return _author_ = 'jake'
_project_ = 'leetcode'
rows, cols = len(matrix), len(matrix[0])
for r in range(rows): # https://leetcode.com/problems/additive-number/
for c in range(cols): # Additive number is a string whose digits can form additive sequence. A valid additive sequence should contain at
if c != 0: # least three numbers. Except for the first two numbers, each subsequent number in the sequence must be the sum of
matrix[r][c] += matrix[r][c-1] # the preceding two.
if r != 0:
matrix[r][c] += matrix[r-1][c] # Try all possible starting digit pairs with lengths such that the remainder has at least as many digits as the
if c != 0 and r != 0: # longer of the 2 starting digits. Break out of loop if any number begins with 0 and has length > 1.
matrix[r][c] -= matrix[r-1][c-1] # For each starting pair, repeatedly add the last 2 numbers and check if this is equal to the next number until end.
# Time - O(n**3)
self.matrix = matrix # Space - O(1)

def sumRegion(self, row1, col1, row2, col2): class Solution(object):


""" def isAdditiveNumber(self, num):
:type row1: int """
:type col1: int :type num: str
:type row2: int :rtype: bool
:type col2: int """
:rtype: int n = len(num)
""" if n < 3:
region = self.matrix[row2][col2] return False
if col1 != 0:
region -= self.matrix[row2][col1-1] for second in range(1, 1 + (n - 1) // 2): # first digit of second integer
if row1 != 0: if num[0] == "0" and second > 1:
region -= self.matrix[row1-1][col2] break
if row1 !=0 and col1 != 0: third = second + 1 # first digit of third integer
region += self.matrix[row1-1][col1-1]
return region while n - third >= max(second, third - second):
if num[second] == "0" and third > second + 1:
break
# python_1_to_1000/305_Number_of_Islands_II.py - h
n1, n2 = int(num[0:second]), int(num[second:third])
_author_ = 'jake' start = third
_project_ = 'leetcode' while True:
next_int = n1 + n2
# https://leetcode.com/problems/number-of-islands-ii/ next_start = start + len(str(next_int))
# A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which if num[start] == "0" and next_start > start + 1:
# turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of break
# islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent if next_int != int(num[start:next_start]):
# lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. break
if next_start == n:
# Union-find structure. parent stores the parent island, self if not attached to any other land. Number of return True
# unique neighbour islands are counted by ascending to ultimate parents, updating links to grandparents to compress n1, n2, start = n2, next_int, next_start
# paths and speed future lookups. All connected neighbours are combined by union.
third += 1 for r in range(rows):
for c in range(1, self.cols):
return False matrix[r][c] += matrix[r][c - 1]
self.matrix = matrix

def update(self, row, col, val):


# python_1_to_1000/307_Range_Sum_Query-Mutable.py - m """
:type row: int
_author_ = 'jake' :type col: int
_project_ = 'leetcode' :type val: int
:rtype: void
# https://leetcode.com/problems/range-sum-query-mutable/ """
# Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. prev = self.matrix[row][col]
# The update(i, val) function modifies nums by updating the element at index i to val. if col != 0:
# You may assume the number of calls to update and sumRange function is distributed evenly. prev -= self.matrix[row][col - 1]
diff = val - prev
# Break nums into bins, each of size approx n**0.5 and containing approx n**0.5 nums. Calculate the sum of each bin.
# To sumRange(), sum the bins from and including i to and excluding j, then add the sum of nums from the bin containing for c in range(col, self.cols):
# j and subtract the nums before i from the bin containing i. Update nums as well as bin_sums. self.matrix[row][c] += diff
# Alternatively calculate the running cumulative sums within each bin and of each bin, which makes O(n**0.5) to update
# and O(1) sumRange(). def sumRegion(self, row1, col1, row2, col2):
# Time - O(n) to initialise, O(1) to update, O(n**0.5) to sumRange(). """
# Space - O(n) :type row1: int
:type col1: int
class NumArray(object): :type row2: int
:type col2: int
def __init__(self, nums): :rtype: int
""" """
:type nums: List[int] sum_region = 0
""" for r in range(row1, row2 + 1):
self.width = int(len(nums)**0.5) # width of each bin (apart from last) sum_region += self.matrix[r][col2]
self.bin_sums = [] # sum of each bin if col1 != 0:
self.nums = nums sum_region -= self.matrix[r][col1 - 1]
return sum_region
for i, num in enumerate(nums):
if i % self.width == 0: # start a new bin
self.bin_sums.append(num) # python_1_to_1000/309_Best_Time_to_Buy_and_Sell_Stock_with_Cooldown.py - m
else: # add to last bin
self.bin_sums[-1] += num _author_ = 'jake'
_project_ = 'leetcode'

def update(self, i, val): # https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/


""" # Say you have an array for which the ith element is the price of a given stock on day i.
:type i: int # Design an algorithm to find the maximum profit. You may complete as many transactions as you like
:type val: int # (ie, buy one and sell one share of the stock multiple times) with the following restrictions:
:rtype: void # You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
""" # After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
bin_i = i // self.width
diff = val - self.nums[i] # Dynamic programming. Max cash if last transaction was a buy is either the max cash after an earlier last buy or
self.bin_sums[bin_i] += diff # update bin_sums # the max cash after an earlier sell at least 2 days ago and buying now. The max cash after selling on a given day is
self.nums[i] = val # update nums # either the max cash after an earlier last sell or the max cash after an earlier buy and selling now.
# Max cash after selling = max profit since the stock is no longer held.
# Time - O(n)
def sumRange(self, i, j): # Space - O(1)
"""
:type i: int class Solution(object):
:type j: int def maxProfit(self, prices):
:rtype: int """
""" :type prices: List[int]
bin_i, bin_j = i // self.width, j // self.width :rtype: int
range_sum = sum(self.bin_sums[bin_i:bin_j]) # sum of whole bins """
range_sum += sum(self.nums[bin_j*self.width:j+1]) # add partial last bin buy, sell, prev_sell = float("-inf"), 0, 0
range_sum -= sum(self.nums[bin_i*self.width:i]) # subtract partial first bin
return range_sum for i, price in enumerate(prices):
buy = max(buy, prev_sell-price)
prev_sell = sell
sell = max(sell, buy+price)
print(buy, sell, prev_sell)
# python_1_to_1000/308_Range_Sum_Query_2D-Mutable.py - h
return sell
_author_ = 'jake'
_project_ = 'leetcode'

# 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])

for a, b in edges: return max_coins[-1][1]


connections[a].add(b)
connections[b].add(a)

leaves = set(node for node in connections if len(connections[node]) == 1) # python_1_to_1000/313_Super_Ugly_Number.py - m

while len(connections) > 2: _author_ = 'jake'


new_leaves = set() _project_ = 'leetcode'
for leaf in leaves:
nbor = connections[leaf].pop() # https://leetcode.com/problems/super-ugly-number/
connections[nbor].remove(leaf) # Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all prime factors
if len(connections[nbor]) == 1: # are in a given list of primes.
new_leaves.add(nbor) # 1 is a super ugly number for any given primes.
del connections[leaf] # The given numbers in primes are in ascending order.
leaves = new_leaves
# Each super ugly number is the product of a prime and a previous super ugly number. Track the last super ugly number
return list(connections.keys()) # to have been multiplied by each prime to create a list of candidates. Take the smallest candidate(s) from the list
# and replace with it/their next in sequence.
# Alternatively, use a heap to find min(candidates) in log k time if len(primes) is large.
# python_1_to_1000/311_Sparse_Matrix_Multiplication.py - m # Time - O(n * k) where k is the length of primes list.
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def nthSuperUglyNumber(self, n, primes):
# https://leetcode.com/problems/sparse-matrix-multiplication/ """
# Given two sparse matrices A and B, return the result of AB. :type n: int
# You may assume that A's column number is equal to B's row number. :type primes: List[int]
:rtype: int
# When an element of A is non-zero update all elements of C using that element. Skip if element of A is sero. """
# Scales linearly with the density of A. super_ugly = [1]
# Time - O(m*n*p) for A being (m by n) and B being (n by p) # super_ugly[indices[i]] is the last super_ugly number to be multiplied by primes[i] to generate candidates[i]
# Space - O(m*p) indices = [0 for _ in range(len(primes))]
candidates = primes[:]
class Solution(object):
def multiply(self, A, B): while len(super_ugly) < n:
"""
:type A: List[List[int]] ugly = min(candidates)
:type B: List[List[int]] super_ugly.append(ugly)
:rtype: List[List[int]]
""" for i in range(len(candidates)): # update all candidates equal to ugly (avoids duplicates)
rows_A, cols_A = len(A), len(A[0]) if ugly == candidates[i]:
cols_B = len(B[0]) # rows_B = cols_A indices[i] += 1
candidates[i] = primes[i] * super_ugly[indices[i]]
C = [[0 for _ in range(cols_B)] for _ in range(rows_A)]
return super_ugly[-1]
for r in range(rows_A):
for c in range(cols_A):
# python_1_to_1000/314_Binary_Tree_Vertical_Order_Traversal.py - m
if A[r][c] != 0:
for i in range(cols_B): _author_ = 'jake'
C[r][i] += A[r][c] * B[c][i] _project_ = 'leetcode'

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)

# https://leetcode.com/problems/burst-balloons/ # Definition for a binary tree node.


# Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. # class TreeNode(object):
# You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] # def __init__(self, x):
# coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent. # self.val = x
# Find the maximum coins you can collect by bursting the balloons wisely. # self.left = None
# self.right = None
# Dynamic programming. Calculate the max coins for subarrays of increasing lengths by considering the max coins from
# all possible balloons to be burst last. Coins gained from bursting a balloon last = coins from that balloon * from collections import defaultdict
# coins from balloon before the subarray * coins from balloon after the subarray + coins from left subarray + coins
# from right subarray. class Solution(object):
# Time - O(n**3) def verticalOrder(self, root):
# Space - O(n**2) """
:type root: TreeNode
class Solution(object): :rtype: List[List[int]]
def maxCoins(self, nums): """
""" vertical = defaultdict(list)
:type nums: List[int] frontier = [(root, 0)] # (node, column) pairs
:rtype: int
""" for node, col in frontier:
n = len(nums)
nums = [1] + nums + [1] if node:
max_coins = [[0 for _ in range(n + 2)] for _ in range(n + 1)] # row = length, col = left vertical[col].append(node.val)
frontier += [(node.left, col-1), (node.right, col+1)] # You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where:
# ok but not great to extend frontier whilst iterating over it # Each 0 marks an empty land which you can pass by freely.
# Each 1 marks a building which you cannot pass through.
return [vertical[col] for col in sorted(vertical)] # Each 2 marks an obstacle which you cannot pass through.
# There will be at least one building. If it is not possible to build such house, return -1.

# 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)

# python_1_to_1000/315_Count_of_Smaller_Numbers_After_Self.py - h from copy import deepcopy

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def shortestDistance(self, grid):
"""
# https://leetcode.com/problems/count-of-smaller-numbers-after-self/ :type grid: List[List[int]]
# You are given an integer array nums and you have to return a new counts array. The counts array has the property :rtype: int
# where counts[i] is the number of smaller elements to the right of nums[i]. """
rows, cols = len(grid), len(grid[0])
# Merge sort, counting the smaller elements to the right during merging. house = 0 # number of the current house performing BFS
# Helper function sorts the original indices of the input. distances = deepcopy(grid) # sum of distances from all explored houses to each point
# Merge in decreasing order, incrementing smallest when all right array are smaller than largest of left array.
# Time - O(n log n) for row in range(rows):
# Space - O(n) for col in range(cols):

class Solution(object): if grid[row][col] != 1: # not a house


def countSmaller(self, nums): continue
""" q = [(row, col)] # frontier of all cells to be explored
:type nums: List[int] house_dist = 1
:rtype: List[int]
""" while q:
def helper(indices): new_q = []
mid = len(indices) / 2 for r, c in q:
if mid == 0: for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
return indices # if within grid and has been explored by all previous houses
if 0 <= r + dr < rows and 0 <= c + dc < cols and grid[r + dr][c + dc] == -house:
left, right = helper(indices[:mid]), helper(indices[mid:]) grid[r + dr][c + dc] -= 1 # signify that another house has reached here
new_q.append((r + dr, c + dc)) # add to list to explore
for i in range(len(indices))[::-1]: # Rebuild indices from largest to smallest num. distances[r + dr][c + dc] += house_dist # add to cumulative distances
if not right or left and nums[left[-1]] > nums[right[-1]]:
indices[i] = left.pop() house_dist += 1
smaller[indices[i]] += len(right) # All right are smaller than largest left. q = new_q
else:
indices[i] = right.pop() house += 1

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'

_author_ = 'jake' # https://leetcode.com/problems/maximum-product-of-word-lengths/


_project_ = 'leetcode' # Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do not
# share common letters. You may assume that each word will contain only lower case letters.
# https://leetcode.com/problems/remove-duplicate-letters/ # If no such two words exist, return 0.
# Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once
# and only once. You must make sure your result is the smallest in lexicographical order among all possible results. # Encode each word as an integer (up to (2^26)-1) with each set bit indicating the presence of a letter. Check all
# pairs of codes, if the logical AND of the codes is zero then they have no letters in common.
# Find the first instance of the lexicographically first letter in the string. If the suffix starting from this letter # Alternatively sort worst in decreasing length order and break code comparison when max_product can no longer be
# contains all of the letters in the string, then add this to the result and recurse on the remainder of the string # exceeded.
# having removed all of this letter. If the suffix does not contain all letters, try the lexicographically next letter. # Time - O(n**2)
# A letter is added to the result when the prefix does not contain all instances of any other letter. # Space - O(n)
# Time - O(n * k) where k is the size of the alphabet
# Space - O(n) class Solution(object):
def maxProduct(self, words):
class Solution(object): """
def removeDuplicateLetters(self, s): :type words: List[str]
""" :rtype: int
:type s: str """
:rtype: str codes = [] # set a bit for each letter present in word
""" for word in words:
s_set = sorted(set(s)) codes.append(sum(1 << (ord(c) - ord('a')) for c in set(word)))
for c in s_set:
suffix = s[s.index(c):] max_product = 0
if len(set(suffix)) == len(s_set): for i in range(len(codes)-1):
return c + self.removeDuplicateLetters(suffix.replace(c, "")) for j in range(i+1, len(codes)):
return "" if not (codes[i] & codes[j]):
max_product = max(max_product, len(words[i]) * len(words[j]))
return max_product

# 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 = []

while i < len(nums1) and j < len(nums2):


# python_1_to_1000/320_Generalized_Abbreviation.py - m
if nums1[i] < nums2[j]:
_author_ = 'jake' use1 = False
_project_ = 'leetcode' elif nums1[i] > nums2[j]:
use1 = True
# https://leetcode.com/problems/generalized-abbreviation/ else: # nums1[i] == nums2[j]
# Write a function to generate the generalized abbreviations of a word. shift = 1
# Example: Given word = "word", return the following list (order does not matter): while i+shift < len(nums1) and j+shift < len(nums2) and nums1[i+shift] == nums2[j+shift]:
# ["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2", "2r1", "3d", "w3", "4"] shift += 1
if i+shift == len(nums1):
# For each letter, either abbreviate that letter by converting it to an integer and possibly adding to the count of use1 = False
# previously abbreviated letters, or do not abbreviate and leave the letter as it is. elif j+shift == len(nums2):
# Time - O(2**n) use1 = True
# Space - O(n * 2**n) elif nums2[j+shift] > nums1[i+shift]:
use1 = False
class Solution(object): else:
def generateAbbreviations(self, word): use1 = True
"""
:type word: str if use1:
:rtype: List[str] merged.append(nums1[i])
""" i += 1
abbreviations = [[]] else:
merged.append(nums2[j])
for c in word: j += 1
new_abbreviations = []
for abbr in abbreviations: return merged + nums1[i:] + nums2[j:]

# 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)

# https://leetcode.com/problems/create-maximum-number/ class Solution(object):


# Given two arrays of length m and n with digits 0-9 representing two numbers. Create the maximum number of def coinChange(self, coins, amount):
# length k <= m + n from digits of the two. The relative order of the digits from the same array must be preserved. """
# Return an array of the k digits. :type coins: List[int]
:type amount: int
# For each partition of i digits from nums1 and (i from 0 to k) and k-i digits from nums 2, find the max number from :rtype: int
# each nums list using that many digits. The overall max is the merge of 2 individual max numbers. Merge by taking """
# the larger digit from the front, if equal look forward to the next position where the digits are different and take coins.sort(reverse = True)
# the larger. Single num largest uses a stack, popping all smaller digits provided there are enough remaining and self.result = float("inf")
# and adding whenever the stack has capacity.
# Time - O(k * n**3), k*n to check each partition and convert to int, n**2 to merge (n to max_single() irrelevant) def dfs(largest_coin, remainder, used_coins):
# Space - O(n)
if remainder == 0:
class Solution(object): self.result = min(self.result, used_coins)
def maxNumber(self, nums1, nums2, k):
""" for i in range(largest_coin, len(coins)): # try coins with largest first
:type nums1: List[int]
:type nums2: List[int] if remainder >= coins[i] * (self.result - used_coins): # cannot improve on result
:type k: int break
:rtype: List[int] if coins[i] <= remainder: # use this coin
""" dfs(i, remainder - coins[i], used_coins + 1)
max_number = 0
for i in range(k + 1): dfs(0, amount, 0)
if i <= len(nums1) and k - i <= len(nums2): return self.result if self.result != float("inf") else -1
max1 = self.max_single(nums1, i)
max2 = self.max_single(nums2, k - i)
merged = self.merge(max1, max2) # python_1_to_1000/323_Number_of_Connected_Components_in_an_Undirected_Graph.py - m
# If there isn't one, return 0 instead.
_author_ = 'jake'
_project_ = 'leetcode' # Store the first index of every cumulative sum in a dictionary. For each cumulative sum, lookup the prefix sum that
# would give a subarray ending at i and summing to k.
# https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/ # Time - O(n)
# Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), # Space - O(n)
# write a function to find the number of connected components in an undirected graph.
class Solution(object):
# Union find. Each node is initially its own parent. For each edge, find ultimate parent of each node. def maxSubArrayLen(self, nums, k):
# If ultimate parents are different, union the components. Collapse unnecessary links while finding parents. """
# Alternatively, BFS or DFS (better with adjacency list representation). :type nums: List[int]
# Time - O(m log* n) for m edges and n nodes :type k: int
# Space - O(n) :rtype: int
"""
class Solution(object): cumul, max_length = 0, 0
def countComponents(self, n, edges): first_index = {}
"""
:type n: int for i, num in enumerate(nums):
:type edges: List[List[int]] cumul += num
:rtype: int
""" if cumul == k:
parents = [i for i in range(n)] max_length = i + 1 # must be the longest
components = n elif cumul - k in first_index:
max_length = max(max_length, i - first_index[cumul - k])
def update_parent(node):
while node != parents[node]: if cumul not in first_index: # add if cumul not seen before
parents[node] = parents[parents[node]] # collapse, set parent to grandparent first_index[cumul] = i
node = parents[parents[node]] # go up to parent
return node return max_length

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

# https://leetcode.com/problems/wiggle-sort-ii/ class Solution(object):


# Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3].... def isPowerOfThree(self, n):
# You may assume all input has valid answer. """
:type n: int
# Find the median (can be O(n) QuickSelect as per "215_Kth_Largest_Element_in_an_Array"). Partition the array :rtype: bool
# with numbers larger than median at swapped to the left, numbers higher swapped to the right and numbers same """
# unswapped. Remap indices such that odd are filled first, then wrap around to start again with even. if n <= 0:
# Time - O(n log n) return False
# Space - O(1) max_int = 2 ** 31 - 1
max_power = int(math.log(max_int, 3))
class Solution(object): return 3 ** max_power % n == 0
def wiggleSort(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead. # python_1_to_1000/327_Count_of_Range_Sum.py - h
"""
nums.sort() _author_ = 'jake'
median = nums[len(nums)//2] _project_ = 'leetcode'

# map larger to last even, smaller to first odd # https://leetcode.com/problems/count-of-range-sum/


def mapping(i): # Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.
return (i*2 + 1) % (len(nums) | 1) # modulo next odd number # Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j (i ≤ j), inclusive.

# < 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])

_author_ = 'jake' def mergesort(cumul, left, right): # sorting cumul[left:right]


_project_ = 'leetcode' count = 0
if right - left <= 1:
# https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/?tab=Description return count
# Given an array nums and a target value k, find the maximum length of a subarray that sums to k.

mid = (left + right) // 2 return memo[r][c]


count += mergesort(cumul, left, mid) + mergesort(cumul, mid, right) # range counts within both sides longest_here = 1 # can visit at least this cell
i, j = mid, mid for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
for prefix_sum in cumul[left:mid]: # range count across mid if 0 <= r + dr < len(matrix) and 0 <= c + dc < len(matrix[0]) and matrix[r + dr][c + dc] > matrix[r][c]:
while i < right and cumul[i] - prefix_sum < lower: # find first index in RHS that sums >= lower longest_here = max(longest_here, self.dfs(r + dr, c + dc, matrix, memo) + 1)
i += 1 memo[r][c] = longest_here
while j < right and cumul[j] - prefix_sum <= upper: # find last index in RHS that sums > upper return longest_here
j += 1
count += (j - i) # for next prefix_sum, restart at i and j since they can only increase

cumul[left:right] = sorted(cumul[left:right]) # merge # python_1_to_1000/330_Patching_Array.p - mh


return count
_author_ = 'jake'
return mergesort(cumul, 0, len(cumul)) _project_ = 'leetcode'

# 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)

while head: # python_1_to_1000/331_Verify_Preorder_Serialization_of_a_Binary_Tree.py - m


odd.next = head # append head to odd list
odd = odd.next # update head of odd list _author_ = 'jake'
even.next = head.next # append head.next to even list _project_ = 'leetcode'
even = even.next # update head of even list
# https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/
head = head.next.next if even else None # will break if no even or no even.next # One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record the
# node's value. If it is a null node, we record a sentinel value such as #. Given a string of comma separated values,
odd.next = even_head.next # join lists, break link from last odd to last even # verify whether it is a correct preorder traversal serialization of a binary tree.
return odd_head.next
# The number of leaves = number of internal nodes + 1. Count the number of future leaves based upon the internal
# nodes seen. If this is zero and there are other nodes left then we already have a complete tree and there can be
# python_1_to_1000/329_Longest_Increasing_Path_in_a_Matrix.py - h # no more nodes. Likewise if there are any expected leaves remaining after parsing the tree it is not complete.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/longest-increasing-path-in-a-matrix/ def isValidSerialization(self, preorder):
# Given an integer matrix, find the length of the longest increasing path. """
# From each cell, you can either move to four directions: left, right, up or down. :type preorder: str
# You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed). :rtype: bool
"""
# For each starting cell, depth first search to explore all greater neighbours within the matrix. Memoise results. if not preorder:
# Time - O(m * n) return True
# Space - O(m * n) expected_leaves = 1

class Solution(object): for node in preorder.split(","):


def longestIncreasingPath(self, matrix): if expected_leaves == 0:
""" return False
:type matrix: List[List[int]] if node == "#":
:rtype: int expected_leaves -= 1
""" else:
if not matrix or not matrix[0]: expected_leaves += 1
return 0
longest = 0 return expected_leaves == 0
memo = [[-1 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]

for r in range(len(matrix)): # python_1_to_1000/332_Reconstruct_Itinerary.py - h


for c in range(len(matrix[0])):
longest = max(longest, self.dfs(r, c, matrix, memo)) _author_ = 'jake'
return longest _project_ = 'leetcode'

def dfs(self, r, c, matrix, memo): # https://leetcode.com/problems/reconstruct-itinerary/


if memo[r][c] != -1: # Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the
# itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK. return float("-inf"), float("inf"), 0
# If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when
# read as a single string. For example, the itinerary ["JFK", "LGA"] has a smaller lexical order than ["JFK", "LGB"]. left_bst = is_bst(node.left)
# You may assume all tickets form at least one valid itinerary. right_bst = is_bst(node.right)

# 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

for start, end in tickets: return False


flights[start].append(end)

route, stack = [], ['JFK'] # python_1_to_1000/335_Self_Crossing.py - h

while stack: _author_ = 'jake'


while flights[stack[-1]]: # while some flight out of top of stack airport _project_ = 'leetcode'
stack.append(flights[stack[-1]].pop()) # add first flight out to stack
route.append(stack.pop()) # no flights out of top of stack - add to result # https://leetcode.com/problems/self-crossing/
# You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north,
return route[::-1] # then x[1] metres to the west, x[2] metres to the south, x[3] metres to the east and so on.
# In other words, after each move your direction changes counter-clockwise.

# 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 = {}

for i, word in enumerate(words):


word_to_index[word] = i # python_1_to_1000/339_Nested_List_Weighted_Sum.py - m

for i, word in enumerate(words): _author_ = 'jake'


_project_ = 'leetcode'
for first_right in range(len(word) + 1):

left, right = word[:first_right], word[first_right:] # https://leetcode.com/problems/nested-list-weight-sum/


rev_left, rev_right = left[::-1], right[::-1] # Given a nested list of integers, return the sum of all integers in the list weighted by their depth.
# Each element is either an integer, or a list -- whose elements may also be integers or other lists.
if first_right != 0 and left == rev_left and rev_right in word_to_index and word_to_index[rev_right] !=
i: # Iterate over the nestedList. If an element isInteger, add it to the total multiplied by its depth. Else increment
palindromes.append([word_to_index[rev_right], i]) # the depth and recurse to sum the deeper list.
# Time - O(n)
if right == rev_right and rev_left in word_to_index and word_to_index[rev_left] != i: # Space - O(1)
palindromes.append([i, word_to_index[rev_left]])
class Solution(object):
return palindromes def depthSum(self, nestedList):
"""
:type nestedList: List[NestedInteger]
:rtype: int
# python_1_to_1000/337_House_Robber_III.py - m """
def helper(nested, depth):
_author_ = 'jake'
_project_ = 'leetcode' total = 0
for item in nested:
# https://leetcode.com/problems/house-robber-iii/
# The thief has found himself a new place for his thievery again. There is only one entrance to this area, if item.isInteger():
# called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief total += depth * item.getInteger()
# realized that "all houses in this place forms a binary tree". It will automatically contact the police if two else:
# directly-linked houses were broken into on the same night. total += helper(item.getList(), depth + 1)
# Determine the maximum amount of money the thief can rob tonight without alerting the police.
return total
# Bottom-up recursion. For each node find the max gain with and without robbing that node. With = value of that node
# and gain from subtrees without robbing their roots. Without = max of left subtree gain with and without robbing its return helper(nestedList, 1)
# root + same for right subtree.
# Time - O(n)
# Space - O(1) # python_1_to_1000/340_Longest_Substring_with_At_Most_K_Distinct_Characters.py - m

# Definition for a binary tree node. _author_ = 'jake'


class TreeNode(object): _project_ = 'leetcode'
def __init__(self, x):
self.val = x # https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/
self.left = None # Given a string, find the length of the longest substring T that contains at most k distinct characters.
self.right = None
# Maintain that last index of each character seen in a sliding window. Extend the window by adding a new character
class Solution(object): # and if there are then more than k distinct characters, slide the start of the window forward until a char is removed.
def rob(self, root): # Time - O(n)
""" # Space - O(k)
:type root: TreeNode
:rtype: int from collections import defaultdict
"""
return max(self.helper(root)) class Solution(object):
def lengthOfLongestSubstringKDistinct(self, s, k):
def helper(self, node): """
if not node: :type s: str
return 0, 0 :type k: int
:rtype: int
left_with, left_without = self.helper(node.left) """
right_with, right_without = self.helper(node.right) start, longest = 0, 0
last_seen = defaultdict(int) # key is char, value is last index of key
max_with = node.val + left_without + right_without
max_without = max(left_with, left_without) + max(right_with, right_without) for end, c in enumerate(s):
last_seen[c] = end # add c to mapping
return max_with, max_without
while len(last_seen) > k: # too many distinct chars in s[start:end + 1]
if last_seen[s[start]] == start: # last_seen of start char is start index
del last_seen[s[start]] # remove start char class Solution(object):
start += 1 # move front of window forwards def isPowerOfFour(self, num):
"""
else: # longest can increase if have not entered while loop :type num: int
longest = max(longest, end - start + 1) :rtype: bool
"""
return longest if num <= 0:
return False

# python_1_to_1000/341_Flatten_Nested_List_Iterator.py - m return 4 ** int(math.log(num, 4)) == num

_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):

def __init__(self, nestedList): class Solution2(object):


""" def integerBreak(self, n):
Initialize your data structure here. """
:type nestedList: List[NestedInteger] :type n: int
""" :rtype: int
self.flat = [] """
def flatten(nested): max_breaks = [0, 1]
for n in nested:
if n.isInteger(): for i in range(2, n + 1):
self.flat.append(n.getInteger()) max_break = 0
else:
flatten(n.getList()) for j in range(1, (i // 2) + 1):
flatten(nestedList) # either split k or keep, same for i - j
self.flat = self.flat[::-1] max_break = max(max_break, max(j, max_breaks[j]) * max(i - j, max_breaks[i - j]))

def next(self): max_breaks.append(max_break)


"""
:rtype: int return max_breaks[-1]
"""
return self.flat.pop()
# python_1_to_1000/344_Reverse_String.py

def hasNext(self): _author_ = 'jake'


""" _project_ = 'leetcode'
:rtype: bool
""" # https://leetcode.com/problems/reverse-string/
return bool(self.flat) # Write a function that takes a string as input and returns the string reversed.

# Reverse with slice operator.


# Time - O(n)
# python_1_to_1000/342_Power_of_Four.py # Space - O(n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def reverseString(self, s):
"""
# https://leetcode.com/problems/power-of-four/ :type s: str
# Given an integer (signed 32 bits), write a function to check whether it is a power of 4. :rtype: str
"""
# If log base 4 is not an integer then rounding to integer and raising to power 4 will not return the original num. return s[::-1]
# Time - O(1)
# Space - O(1)
# python_1_to_1000/345_Reverse_Vowels_of_a_String.py
import math
_author_ = 'jake'

_project_ = 'leetcode' """


n = len(nums)
# https://leetcode.com/problems/reverse-vowels-of-a-string/ frequencies = [[] for _ in range(n + 1)]
# Write a function that takes a string as input and reverse only the vowels of a string.
for num, freq in Counter(nums).items():
# Find list of indices of vowels in s. Swap vowel at first index with vowel at last index, until meeting in middle frequencies[freq].append(num)
# of list of vowels.
# Time - O(n) top_k = []
# Space - O(n) while k:
while not frequencies[n]:
class Solution(object): n -= 1
def reverseVowels(self, s): top_k.append(frequencies[n].pop())
""" k -= 1
:type s: str
:rtype: str return top_k
"""
vowels = {"a", "e", "i", "o", "u"}
vowels |= {c.upper() for c in vowels} # python_1_to_1000/348_Design_Tic-Tac-Toe.py - m

vowel_i = [i for i, c in enumerate(s) if c in vowels] _author_ = 'jake'


n_vowel = len(vowel_i) _project_ = 'leetcode'

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)

# python_1_to_1000/350_Intersection_of_Two_Arrays_II.py return patterns

_author_ = 'jake' return 4 * count_patterns(1) + 4 * count_patterns(2) + count_patterns(5) # symmetry


_project_ = 'leetcode'

# https://leetcode.com/problems/intersection-of-two-arrays-ii/ class Solution2(object):


# Given two arrays, write a function to compute their intersection. def numberOfPatterns(self, m, n):
# Each element in the result should appear as many times as it shows in both arrays. """
# The result can be in any order. :type m: int
:type n: int
# Count frequencies of nums in nums1. Iterate over nums2, for every num in nums1 with a positive count, append to :rtype: int
# result and decrement count in nums1. """
# Time - O(m + n) patterns = [0, 9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704]
# Space - O(m) return sum(patterns[m:n+1])

from collections import Counter

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

new_paths = [] lower = self.get_parent(val - 1)


for visited, last in paths: upper = self.get_parent(val + 1)

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)

# python_1_to_1000/353_Design_Snake_Game.py - m class Solution(object):


def maxEnvelopes(self, envelopes):
_author_ = 'jake' """
_project_ = 'leetcode' :type envelopes: List[List[int]]
:rtype: int
# https://leetcode.com/problems/design-snake-game/ """
# Design a Snake game that is played on a device with screen size = width x height. # increasing width, ties broken by decreasing height
# The snake is initially positioned at the top left corner (0,0) with length = 1 unit. envelopes.sort(key = lambda x : (x[0], -x[1]))
# You are given a list of food's positions in row-column order. When a snake eats the food, its length and the game's
# score both increase by 1. Each food appears one by one on the screen. For example, the second food will not appear # nested[i] is smallest height outer envelope for i - 1 in total
# until the first food was eaten by the snake. When a food does appear on the screen, it is guaranteed that it will not nested = []
# appear on a block occupied by the snake.
# find the index of the first number in nested >= target
# Dictionary maps one segment of snake body to the next. Check for collision with wall or body apart from tail. # i.e. the first nested that can be improved (or stay same) by target
# Score is len(snake) - 1. # i.e. index after last nested than target can increase
# Time - O(f) for constructor (nb food), O(1) to move() def bin_search(target):
# Space - O(n) left, right = 0, len(nested) - 1
while left <= right:
class SnakeGame(object): mid = (left + right) // 2
if target > nested[mid]: # first greater than target must be on RHS
def __init__(self, width,height,food): left = mid + 1
""" else: # target <= nested[mid], target cannot fit around nested[mid] so look st LHS
Initialize your data structure here. right = mid - 1
@param width - screen width return left
@param height - screen height
@param food - A list of food positions for _, h in envelopes:
E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. i = bin_search(h)
:type width: int if i == len(nested):
:type height: int nested.append(h)
:type food: List[List[int]] else:
""" nested[i] = h # h <= nested[i] so nested[i] can only improve
self.rows, self.cols = height, width
self.food = [tuple(f) for f in food] # convert to tuples return len(nested)
self.snake = {(0, 0) : None} # map from position to next position
self.head, self.tail = (0, 0), (0, 0)
self.moves = {"U" : (-1, 0), "D" : (1, 0), "L" : (0, -1), "R" : (0, 1)}

def move(self, direction): # python_1_to_1000/355_Design_Twitter.py - m


"""
Moves the snake. _author_ = 'jake'
@param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down _project_ = 'leetcode'
@return The game's score after the move. Return -1 if game over.
Game over when snake crosses the screen boundary or bites its body. # https://leetcode.com/problems/design-twitter/
:type direction: str # Design a simplified version of Twitter where users can post tweets, follow/unfollow another user and is able to
:rtype: int # see the 10 most recent tweets in the user's news feed. Your design should support the following methods:
""" # - postTweet(userId, tweetId): Compose a new tweet.
# get new head position # - getNewsFeed(userId): Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must
new_head = (self.head[0] + self.moves[direction][0], self.head[1] + self.moves[direction][1]) be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least
recent.
# check collision with wall # - follow(followerId, followeeId): Follower follows a followee.
if new_head[0] < 0 or new_head[0] >= self.rows or new_head[1] < 0 or new_head[1] >= self.cols: # - unfollow(followerId, followeeId): Follower unfollows a followee.
return -1
# check if hits body (apart from tail which will move or not be hit since eating food) # Map users to set of followers and list of tweets with timestamps. getNewsFeed by creating a heap of the most recent
if new_head in self.snake and new_head != self.tail: # tweet from each followed (including self).
return -1 # Time - O(1) for init, postTweet, follow and unfollow. O(n) where n is nb followed to getNewsFeed
# Space - O(max(u**2), t) where u is nb users who could potentially all folow each other, t is nb tweets
# update head
self.snake[self.head] = new_head from collections import defaultdict
self.head = new_head import heapq

# move tail if not eaten food class Twitter(object):


if len(self.snake) - 1 >= len(self.food) or new_head != self.food[len(self.snake) - 1]:
old_tail = self.tail def __init__(self):
self.tail = self.snake[self.tail] """
del self.snake[old_tail] # head has moved on fo safe even if length 1 Initialize your data structure here.
"""
# extend length self.followers = defaultdict(set)
self.snake[self.head] = None self.tweets = defaultdict(list)
self.time = 0
return len(self.snake) - 1
def postTweet(self, userId, tweetId): return False
""" left += 1
Compose a new tweet. right -= 1
:type userId: int
:type tweetId: int return True
:rtype: void
"""
self.tweets[userId].append([-self.time, tweetId])
self.time += 1 # python_1_to_1000/357_Count_Numbers_with_Unique_Digits.py - m

def getNewsFeed(self, userId): _author_ = 'jake'


""" _project_ = 'leetcode'
Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by
users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. # https://leetcode.com/problems/count-numbers-with-unique-digits/
:type userId: int # Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10**n.
:rtype: List[int]
""" # For a single digit there are 10 choices. For exactly 2 digits, all of the single digit results apart from 0 can have
self.followers[userId].add(userId) # always follow self (even if unfollowed earlier) # any of the 9 unused digit appended. For exactly 3 digits we can append any of the 8 unused digits to each of the
following = {u for u in self.followers[userId] if self.tweets[u]} # list of people followed who have tweeted # 2 digit solutions. With more than 10 digits there are no more uniquie combinations.
last_tweet_i = {u : len(self.tweets[u]) - 1 for u in following} # mapping from followed user to index of # Time - O(1) since at most 10 digits
last tweet # Space - O(1)
tweet_heap = [self.tweets[u][last_tweet_i[u]] + [u] for u in following] # most recent tweet from each
followed class Solution(object):
heapq.heapify(tweet_heap) def countNumbersWithUniqueDigits(self, n):
feed = [] """
while following and len(feed) < 10: # stop if 10 tweets or no more from followed :type n: int
_, tweetId, u = heapq.heappop(tweet_heap) # uses included so can update with next most recent tweet :rtype: int
feed.append(tweetId) """
last_tweet_i[u] -= 1 if n == 0:
if last_tweet_i[u] == -1: return 1
following.remove(u) # no more tweets
else: uniques = 10 # for 1 digit
heapq.heappush(tweet_heap, self.tweets[u][last_tweet_i[u]] + [u]) can_expand = 9 # numbers that can be expanded by adding another digit

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

def unfollow(self, followerId, followeeId): _author_ = 'jake'


""" _project_ = 'leetcode'
Follower unfollows a followee. If the operation is invalid, it should be a no-op.
:type followerId: int # https://leetcode.com/problems/rearrange-string-k-distance-apart/
:type followeeId: int # Given a non-empty string s and an integer k, rearrange the string such that the same characters are at least
:rtype: void # distance k from each other. All input strings are given in lowercase letters. If it is not possible to rearrange
""" # the string, return an empty string
self.followers[followerId].discard(followeeId)
# Count the frequency of each letter. Greedily add the most frequent letter to the result if it has not been used
# in the last k letters. Keep a heap of remaining frequency of each letter. Remove most frequent until letter can be
# python_1_to_1000/356_Line_Reflection.py - m # used, decrement remaining count and add back most frequent.
# Time - O(n log k)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
from collections import Counter
# https://leetcode.com/problems/line-reflection/ import heapq
# Given n points on a 2D plane, find if there is such a line parallel to y-axis that reflect the given points.
class Solution(object):
# Find the set of the x-values of all points with the same y-value. For each y-value make a sorted list of distinct def rearrangeString(self, s, k):
# x-values. Reflection axis is the mid-point between outer elements of the list. Only if all other pairs (moving """
# from outside of list inwards) match same reflection axis then all points can be reflected. :type s: str
# Time - O(n log n) due to sorting of x-values :type k: int
# Space - O(n) :rtype: str
"""
from collections import defaultdict freq = Counter(s)
heap = [(-count, letter) for letter, count in freq.items()]
class Solution(object): heapq.heapify(heap)
def isReflected(self, points):
""" last_used = {} # map from letter to index in result of last use
:type points: List[List[int]] rearranged = []
:rtype: bool
""" while heap:
y_to_x = defaultdict(set) # set since multiple points can map to same point too_close = [] # save most frequent letters that cannot be used
for x, y in points: neg_f, letter = heapq.heappop(heap)
y_to_x[y].add(x)
while letter in last_used and len(rearranged) - last_used[letter] < k: # keep letter to add back later
reflection = None # x-value of reflection line too_close.append((neg_f, letter))
for y in y_to_x: if not heap: # no more letters can be used
xs = sorted(list(y_to_x[y])) return ""
left, right = 0, len(xs) - 1 neg_f, letter = heapq.heappop(heap)

if reflection is None: last_used[letter] = len(rearranged)


reflection = xs[left] + xs[right] # store sum (= 2 * x-axis of reflection) to maintain integer rearranged.append(letter)
left += 1 neg_f += 1
right -= 1 if neg_f: # do not put back in heap if freq is zero
heapq.heappush(heap, (neg_f, letter))
while left <= right:
if xs[right] + xs[left] != reflection : for item in too_close: # add back to heap

heapq.heappush(heap, item) # python_1_to_1000/361_Bomb_Enemy.py - m

return "".join(rearranged) _author_ = 'jake'


_project_ = 'leetcode'

# 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

_author_ = 'jake' # python_1_to_1000/362_Design_Hit_Counter.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/sort-transformed-array/ _project_ = 'leetcode'
# Given a sorted array of integers nums and integer values a, b and c. Apply a function of the form f(x) = ax2 + bx + c
# to each element x in the array. The returned array must be in sorted order. # https://leetcode.com/problems/design-hit-counter/
# Design a hit counter which counts the number of hits received in the past 5 minutes.
# Shape of transformed function is U if a is positive. # Each function accepts a timestamp parameter (in seconds granularity) and you may assume that calls are being made to
# If a is +ve largest values are at ends. Take largest and mve inwards, reverse final order. # the system in chronological order (ie, the timestamp is monotonically increasing). The earliest timestamp starts at 1.
# If a is -ve or zero then smallest values are at ends. Take smallest and move inwards.
# Time - O(n) # Store each hit in a deque. For getHits() remove all hits longer than or equal to 300 seconds ago.
# Space - O(n) # Alternatively, to reduce memory use and increase performance of getHits() store the count along with timestamp so
# multiple hits at same timestamp are grouped.
class Solution(object): # Time - O(1) for init and hit(), O(n) for getHits(), number of hits since previous getHits
def sortTransformedArray(self, nums, a, b, c): # Space - O(n)
"""
:type nums: List[int] from collections import deque
:type a: int
:type b: int class HitCounter(object):
:type c: int
:rtype: List[int] def __init__(self):
""" """
def transform(x): Initialize your data structure here.
return a * x * x + b * x + c """
self.time_diff = 300
transformed = [transform(num) for num in nums] self.q = deque()
left, right = 0, len(nums) - 1
result = [] def hit(self, timestamp):
"""
while left <= right: Record a hit.
@param timestamp - The current timestamp (in seconds granularity).
if (a > 0 and transformed[left] > transformed[right]) or (a <= 0 and transformed[right] > :type timestamp: int
transformed[left]): :rtype: void
result.append(transformed[left]) """
left += 1 self.q.append(timestamp)
else:
result.append(transformed[right]) def getHits(self, timestamp):
right -= 1 """
Return the number of hits in the past 5 minutes.
return result[::-1] if a > 0 else result @param timestamp - The current timestamp (in seconds granularity).
:type timestamp: int
:rtype: int
"""
while self.q and timestamp - self.q[0] >= self.time_diff:
self.q.popleft() # Time - O(n)
return len(self.q) # Space - O(n)

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)

if nested.isInteger(): # add to sum at depth


# python_1_to_1000/363_Max_Sum_of_Rectangle_No_Larger_Than_K.py - h depth_sums[depth] += nested.getInteger()
else:
_author_ = 'jake' for n in nested.getList(): # recurse at greater depth
_project_ = 'leetcode' self.dfs(n, depth + 1, depth_sums)

# https://leetcode.com/problems/max-sum-of-sub-matrix-no-larger-than-k/ class Solution2(object):


# Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix such that def depthSumInverse(self, nestedList):
# its sum is no larger than k. unweighted, weighted = 0, 0
q = nestedList
# For each column forming the left edge of the rectangle, calculate cumulative row_sums for each column at the right
# edge of the rectangle. For each right edge column, iterate over rows and maintain a sorted list of the sum of the while q:
# cells between those columns for each row. For each row, find the value in the list that makes a rectangle with sum new_q = []
# not more than k. Insert cumulative row sum into list.
# Alternatively use skip list or self-balancing tree to maintain sorted list. for nested in q:
# Time - O(n**2 * m**2) if nested.isInteger():
# Space - O(m) unweighted += nested.getInteger()
else:
import bisect new_q += nested.getList()

class Solution(object): q = new_q


def maxSumSubmatrix(self, matrix, k): weighted += unweighted
"""
:type matrix: List[List[int]] return weighted
:type k: int
:rtype: int
"""
if not matrix or not matrix[0]: # python_1_to_1000/365_Water_And_Jug_Problem.py - m
return 0
rows, cols = len(matrix), len(matrix[0]) _author_ = 'jake'
max_sum = float("-inf") _project_ = 'leetcode'

for i in range(cols): # https://leetcode.com/problems/water-and-jug-problem/


row_sums = [0 for _ in range(rows)] # You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available.
# You need to determine whether it is possible to measure exactly z litres using these two jugs.
for j in range(i, cols): # If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end.
sorted_sums = [0] # sum of rows between these columns # Operations allowed:
all_row_sum = 0 # sum of cols i to j (inclusive), rows 0 to r (inclusive) # Fill any of the jugs completely with water.
# Empty any of the jugs.
for r in range(rows): # Pour water from one jug into another till the other jug is completely full or the first jug itself is empty.
row_sums[r] += matrix[r][j]
all_row_sum += row_sums[r] # z must be a multiple of the greatest common divisor of x and y, and not more than the sum of x and y
# Time - O(log n)
larger = bisect.bisect_left(sorted_sums, all_row_sum - k) # # Space - O(1)
if larger != len(sorted_sums):
if all_row_sum - sorted_sums[larger] == k: # cannot improve, early return
return k class Solution(object):
max_sum = max(max_sum, all_row_sum - sorted_sums[larger]) def canMeasureWater(self, x, y, z):
"""
bisect.insort_left(sorted_sums, all_row_sum) # insert all_row_sum in sorted list :type x: int
:type y: int
return max_sum :type z: int
:rtype: bool
"""
def gcd(a, b):
# python_1_to_1000/364_Nested_List_Weight_Sum_II.py - m while b != 0:
a, b = b, a % b
_author_ = 'jake' return a
_project_ = 'leetcode'
if z == 0:
# https://leetcode.com/problems/nested-list-weight-sum-ii/ return True
# Given a nested list of integers, return the sum of all integers in the list weighted by their depth. g = gcd(x, y)
# Each element is either an integer, or a list -- whose elements may also be integers or other lists. if g == 0:
# Different from the previous question where weight is increasing from root to leaf, now the weight is defined from return False
# bottom up. i.e., the leaf level integers have weight 1, and the root level integers have the largest weight. return z % g == 0 and z <= x + y

# 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.

_author_ = 'jake' :rtype: List[int]


_project_ = 'leetcode' """
max_to_set = {-1 : set()} # mapping from largest value in a set to its elements
# https://leetcode.com/problems/find-leaves-of-binary-tree/ nums.sort()
# Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves,
# repeat until the tree is empty. for num in nums:

# 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

# python_1_to_1000/367_Valid_Perfect_Square.py - m class Solution(object):


def plusOne(self, head):
_author_ = 'jake' """
_project_ = 'leetcode' :type head: ListNode
:rtype: ListNode
# https://leetcode.com/problems/valid-perfect-square/ """
# Given a positive integer num, write a function which returns True if num is a perfect square else False. new_head = ListNode(0) # make a new head with zero digit
new_head.next = head
# Binary search between 1 and num. Test if middle of earch region is the square root of num. If not, search region i, j = new_head, new_head # pointers
# to left or right until solution or no more search region.
# Time - O(log n) while i.next: # iterate along the list
# Space - O(1) i = i.next
if i.val != 9: # update j to find the last node that is not 9
class Solution(object): j = i
def isPerfectSquare(self, num):
""" j.val += 1 # increment j
:type num: int j = j.next
:rtype: bool while j: # set all after j to zero
""" j.val = 0
left, right = 1, num j = j.next

while left <= right: if new_head.val == 0: # not incremented new_head


return head
mid = (left + right) // 2 return new_head
square = mid * mid

if square == num:
return True # python_1_to_1000/370_Range_Addition.py - m

if square > num: _author_ = 'jake'


right = mid - 1 _project_ = 'leetcode'
else:
left = mid + 1 # https://leetcode.com/problems/range-addition/
# Assume you have an array of length n initialized with all 0's and are given k update operations.
return False # Each operation is represented as a triplet: [startIndex, endIndex, inc] which increments each element of
# subarray A[startIndex ... endIndex] (startIndex and endIndex inclusive) with inc.
# Return the modified array after all k operations were executed.
# python_1_to_1000/368_Largest_Divisible_Subset.py - m
# To a list of length length + 1, add increments at starting index of each update and decrements after ending index.
_author_ = 'jake' # Iterate over shifts, creating a cumulative sum.
_project_ = 'leetcode' # Time - O(n + k) where n = length and k = len(updates)
# Space - O(n)
# https://leetcode.com/problems/largest-divisible-subset/
# Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this class Solution(object):
# subset satisfies: Si % Sj = 0 or Sj % Si = 0. If there are multiple solutions, return any subset. def getModifiedArray(self, length, updates):
"""
# For each num starting with smallest, create a set where every pair is divisible. Search through all existing sets :type length: int
# to find the largest where num is divisible by its largest element (therefore num is divisible by all of its elements) :type updates: List[List[int]]
# Time - O(n**2) :rtype: List[int]
# Space - O(n) """
if length <= 0:
class Solution(object): return []
def largestDivisibleSubset(self, nums):
""" shifts = [0] * (length + 1)
:type nums: List[int] for start, end, inc in updates:
shifts[start] += inc def kSmallestPairs(self, nums1, nums2, k):
shifts[end + 1] -= inc """
:type nums1: List[int]
output = [shifts[0]] :type nums2: List[int]
for i in range(1, length): :type k: int
output.append(output[-1] + shifts[i]) :rtype: List[List[int]]
"""
return output if not nums1 or not nums2:
return []

# 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))

class Solution(object): return smallest


def getSum(self, a, b):
"""
:type a: int # python_1_to_1000/374_Guess_Number_Higher_or_Lower.py
:type b: int
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
MASK = 0xFFFFFFFF # 2**32 - 1
MAX_INT = 0x7FFFFFFF # 2**31 - 1 # https://leetcode.com/problems/guess-number-higher-or-lower/
# We are playing the Guess Game. The game is as follows:
while b != 0: # I pick a number from 1 to n. You have to guess which number I picked
# Every time you guess wrong, I'll tell you whether the number is higher or lower.
total = (a ^ b) & MASK # You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):
carry = ((a & b) << 1) & MASK # shift pattern when both bits are set
print(a, b, total, carry) # Binary search.
a, b = total, carry # Time - O(log n)
# Space - O(1)
return a if a < MAX_INT else ~(a ^ MASK) # a - 2**321
class Solution(object):
def guessNumber(self, n):
"""
:type n: int
# python_1_to_1000/372_Super_Pow.py - m :rtype: int
"""
_author_ = 'jake' low, high = 1, n
_project_ = 'leetcode'
while True:
# https://leetcode.com/problems/super-pow/
# Your task is to calculate a**b mod 1337 where a is a positive integer and b is an extremely large positive integer mid = (low + high) // 2
# given in the form of an array. g = guess(mid)

# 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'

for digit in b: # pow() takes modulo as input # https://leetcode.com/problems/guess-number-higher-or-lower-ii/


result = (pow(result, 10, 1337) * pow(a, digit, 1337)) % 1337 # We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have to guess which
# number I picked. Every time you guess wrong, I'll tell you whether the number I picked is higher or lower. However,
return result # when you guess a number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.
# Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.

# 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):

for range_length in range(3, n + 1): combos += self.helper(nums, target - num, memo)


min_money.append([]) memo[target] = combos
for lower in range(1, n + 2 - range_length): return combos
upper = lower + range_length - 1
min_cost = float('inf')
for guess in range((lower + upper) // 2, upper): # guesses of LHS and upper are never optimal class Solution2(object):
cost = guess + max(min_money[guess - lower - 1][lower - 1], min_money[upper - guess - 1][guess]) def combinationSum4(self, nums, target):
min_cost = min(min_cost, cost) combos = [0] * (target + 1) # combos[i] is nb ways wo make i
combos[0] = 1
min_money[-1].append(min_cost)
for i in range(1, target + 1):
return min_money[n - 1][0] for num in nums:
if i >= num:
combos[i] += combos[i - num]

# python_1_to_1000/376_Wiggle_Subsequence.py - m return combos[-1]

_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])

for num in nums[1:]: if k > (rows * cols) // 2:


if direction != -1 and num < prev: back = True
max_length += 1 k = rows * cols - k + 1
direction = -1 frontier = [(-matrix[rows - 1][cols - 1], rows - 1, cols - 1)]
elif direction != 1 and num > prev: else:
max_length += 1 back = False
direction = 1 frontier = [(matrix[0][0], 0, 0)]
prev = num
while k:
return max_length val, r, c = heapq.heappop(frontier)
k -= 1
if not back:
# python_1_to_1000/377_Combination_Sum_IV.py - m if c != len(matrix[0]) - 1:
heapq.heappush(frontier, (matrix[r][c + 1], r, c + 1))
_author_ = 'jake' if c == 0 and r != len(matrix) - 1:
_project_ = 'leetcode' heapq.heappush(frontier, (matrix[r + 1][c], r + 1, c))
else:
# https://leetcode.com/problems/combination-sum-iv/ if c != 0:
# Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that heapq.heappush(frontier, (-matrix[r][c - 1], r, c - 1))
# add up to a positive integer target. if c == cols - 1 and r != 0:
heapq.heappush(frontier, (-matrix[r - 1][c], r - 1, c))
# Top-down nb ways to make k for any num in nums is 1 if num == k, 0 if num > k, recurse if num < k.
# Alternatively, bottom up dynamic programming. return -val if back else val
# Time - O(k) where k = target
# Space - O(k * n) where n = len(nums)

class Solution(object): # python_1_to_1000/379_Design_Phone_Directory.py - h


def combinationSum4(self, nums, target):
""" _author_ = 'jake'
:type nums: List[int] _project_ = 'leetcode'
:type target: int
:rtype: int # https://leetcode.com/problems/design-phone-directory/
""" # Design a Phone Directory which supports the following operations:
memo = {} # get: Provide a number which is not assigned to anyone.
self.helper(nums, target, memo) # check: Check if a number is available or not.
return memo[target] # release: Recycle or release a number.

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

def get(self): _author_ = 'jake'


""" _project_ = 'leetcode'
Provide a number which is not assigned to anyone.
@return - Return an available number. Return -1 if none is available. # https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/
:rtype: int # Design a data structure that supports all following operations in average O(1) time.
""" # Note: Duplicate elements are allowed.
return self.free.pop() if self.free else -1 # insert(val): Inserts an item val to the collection.
# remove(val): Removes an item val from the collection if present.
def check(self, number): # getRandom: Returns a random element from current collection of elements. The probability of each element being
""" # returned is linearly related to the number of same value the collection contains.
Check if a number is available or not.
:type number: int # Maintain a list of vals and a mapping from val to all indices in list with that val. To remove, replace in list
:rtype: bool # with last val and update mapping of replacement.
""" # Time - O(1)
return number in self.free # Space - O(n)

def release(self, number): from collections import defaultdict


""" import random
Recycle or release a number.
:type number: int
:rtype: void class RandomizedCollection(object):
""" def __init__(self):
self.free.add(number) """
Initialize your data structure here.
"""
# python_1_to_1000/380_Insert_Delete_GetRandom_O(1).py - m self.nums = []
self.indices = defaultdict(set) # value is the set of indices in self.nums with values of key
_author_ = 'jake'
_project_ = 'leetcode' def insert(self, val):
"""
# https://leetcode.com/problems/insert-delete-getrandom-o1/ Inserts a value to the collection. Returns true if the collection did not already contain the specified element.
# Design a data structure that supports all following operations in average O(1) time. :type val: int
# insert(val): Inserts an item val to the set if not already present. :rtype: bool
# remove(val): Removes an item val from the set if present. """
# getRandom: Returns a random element from current set of elements. Each element must have the same probability result = True
# of being returned. if val in self.indices:
result = False
# Maintain a list of the vals as they are added and a mapping from each val to its index in the list.
# Upon removal replace with last val in list (self if removing last val), update mapping for replacement val then self.nums.append(val)
# delete mapping for removed val. self.indices[val].add(len(self.nums) - 1)
# Note that using a set and no list is also O(1) but pop() does not produce a random val and random.sample is slow. return result
# Time - O(1)
# Space - O(n) def remove(self, val):
"""
import random Removes a value from the collection. Returns true if the collection contained the specified element.
:type val: int
:rtype: bool
class RandomizedSet(object): """
def __init__(self): if val not in self.indices:
""" return False
Initialize your data structure here.
""" i = self.indices[val].pop() # remove any index with this val
self.mapping = {} # key is item, value is index in items list
self.items = [] # list of items if not self.indices[val]: # delete val from mapping
del self.indices[val]
def insert(self, val):
""" if i == len(self.nums) - 1: # only need to remove from list
Inserts a value to the set. Returns true if the set did not already contain the specified element. self.nums.pop()
:type val: int else:
:rtype: bool replacement = self.nums[-1]
""" self.nums[i] = replacement
if val not in self.mapping: # append to list and update mapping self.nums.pop()
self.items.append(val) self.indices[replacement].discard(len(self.nums)) # change index in replacement mapping
self.mapping[val] = len(self.items) - 1 self.indices[replacement].add(i)
return True return True
return False
def getRandom(self):
def remove(self, val): """
""" Get a random element from the collection.
Removes a value from the set. Returns true if the set contained the specified element. :rtype: int
:type val: int """
:rtype: bool return self.nums[random.randint(0, len(self.nums) - 1)]
"""
if val not in self.mapping:
return False # python_1_to_1000/382_Linked_List_Random_Node.py - m
index = self.mapping[val]
self.items[index] = self.items[-1] # replace removed item with last item _author_ = 'jake'
self.mapping[self.items[index]] = index # update mapping for replacemnt item _project_ = 'leetcode'
self.items.pop()
del self.mapping[val] # https://leetcode.com/problems/linked-list-random-node/
return True # Given a singly linked list, return a random node's value from the linked list. Each node must have the same
# probability of being chosen.
def getRandom(self):
""" # Count length and move along a random number of nodes. Alternatively if getRandom() is called many times, store
Get a random element from the set. # vals in a list and choose a random index (O(n) space and O(1) getRandom).
:rtype: int # Alternatively, reservoir sampling. Choose first item, for each subsequent ith item, replace chosen with ith with
""" # probability 1/(1+i). Slow due to multiple random samples.

# Time - O(n) """


# Space - O(1) return self.nums

import random def shuffle(self):


"""
class Solution(object): Returns a random shuffling of the array.
def __init__(self, head): :rtype: List[int]
""" """
@param head The linked list's head. result = self.nums[:]
Note that the head is guaranteed to be not null, so it contains at least one node. for i in range(len(result)):
:type head: ListNode swap = random.randint(i, len(result) - 1)
""" result[i], result[swap] = result[swap], result[i]
self.head = head return result
self.count = 0
while head:
self.count += 1 # python_1_to_1000/385_Mini_Parser.py - m
head = head.next
_author_ = 'jake'
def getRandom(self): _project_ = 'leetcode'
"""
Returns a random node's value. # https://leetcode.com/problems/mini-parser/
:rtype: int # Given a nested list of integers represented as a string, implement a parser to deserialize it.
""" # Each element is either an integer, or a list -- whose elements may also be integers or other lists.
randnode = random.randint(0, self.count - 1) # Note: You may assume that the string is well-formed:
node = self.head # String is non-empty.
for _ in range(randnode): # String does not contain white spaces.
node = node.next # String contains only digits 0-9, [, - ,, ].
return node.val
# Evaluate the string to convert to a nested list of ints. If s_eval is an int, return NestedInteger with that int.
# Else create a NestedInteger of an empty list and recursively add all elements of s_eval.
# Time - O(n)
# python_1_to_1000/383_Ransom_Note.py # Space - O(n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def deserialize(self, s):
"""
# https://leetcode.com/problems/ransom-note/ :type s: str
# Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function :rtype: NestedInteger
# that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false. """
# Each letter in the magazine string can only be used once in your ransom note. return self.helper(eval(s)) # eval converts string to expression (nested list of ints)
# You may assume that both strings contain only lowercase letters.
def helper(self, s_eval):
# Count all chars in ransom note asd magazines. If any char is in ransom note but not magazine or has a lower count in
# magazine then return False. if isinstance(s_eval, int):
# Time - O(m + n) return NestedInteger(s_eval)
# Space - O(1)
nested = NestedInteger() # nested is empty list
from collections import Counter for item in s_eval:
nested.add(self.helper(item))
class Solution(object):
def canConstruct(self, ransomNote, magazine): return nested
"""
:type ransomNote: str
:type magazine: str # python_1_to_1000/386_Lexicographical_Numbers.py - m
:rtype: bool
""" _author_ = 'jake'
mag_count = Counter(magazine) _project_ = 'leetcode'
ransom_count = Counter(ransomNote)
# https://leetcode.com/problems/lexicographical-numbers/
for c in ransom_count: # Given an integer n, return 1 - n in lexicographical order.
if c not in mag_count or mag_count[c] < ransom_count[c]:
return False # Next lexical num is previous * 10 if less than n.
# Else divide by 10 and increment until less than n, rhen remove all zeros.
return True # Alternatively, enumerate list id strings, sort and convert back to ints.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/384_Shuffle_an_Array.py - m
class Solution(object):
_author_ = 'jake' def lexicalOrder(self, n):
_project_ = 'leetcode' """
:type n: int
# https://leetcode.com/problems/shuffle-an-array/ :rtype: List[int]
# Shuffle a set of numbers without duplicates. """
lexical = [1]
# Copy original array and swap each entry with entry in a random position.
# Time - O(n) while len(lexical) < n:
# Space - O(n)
num = lexical[-1] * 10
import random while num > n: # increment the smallest digit possible
num //= 10
class Solution(object): num += 1
while num % 10 == 0: # strip off zeros
def __init__(self, nums): num //= 10
""" lexical.append(num)
:type nums: List[int]
:type size: int return lexical
"""
self.nums = nums class Solution2(object):
def lexicalOrder(self, n):
def reset(self): strings = list(map(str, range(1, n + 1)))
""" strings.sort()
Resets the array to its original configuration and return it. return list(map(int, strings))
:rtype: List[int]
:type t: str
:rtype: str
# python_1_to_1000/387_First_Unique_Character_in_a_String.py """
counts = [0 for _ in range(26)]
_author_ = 'jake'
_project_ = 'leetcode' for c in s:
counts[ord(c) - ord("a")] += 1
# https://leetcode.com/problems/first-unique-character-in-a-string/
# Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1. for c in t:
index = ord(c) - ord("a")
# Count frequency of each letter. Then iterate over s again, finding the index of the first letter with count of 1. counts[index] -= 1
# Time - O(n) if counts[index] < 0:
# Space - O(1) return c

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.

for line in input.splitlines(): # python_1_to_1000/391_Perfect_Rectangle.py - h

stripped = line.lstrip("\t") _author_ = 'jake'


depth = len(line) - len(stripped) _project_ = 'leetcode'

if "." in line: # https://leetcode.com/problems/perfect-rectangle/


longest = max(longest, len(stripped) + depth + depths[depth]) # Given N axis-aligned rectangles where N > 0, determine if they together form an exact cover of a rectangular region.
else: # Each rectangle is represented as a bottom-left point and a top-right point.
if len(depths) <= depth + 1:
depths.append(0) # Total area of all rectangles must equal covered region area. Corners of region must be counted once, other corners
depths[depth + 1] = depths[depth] + len(stripped) # match either 2 or 4 rectangles.
# Time - O(n), number of rectangles
return longest # Space - O(n)

from collections import defaultdict


# python_1_to_1000/389_Find_the_Difference.py
class Solution(object):
_author_ = 'jake' def isRectangleCover(self, rectangles):
_project_ = 'leetcode' """
:type rectangles: List[List[int]]
# https://leetcode.com/problems/find-the-difference/ :rtype: bool
# Given two strings s and t which consist of only lowercase letters. """
# String t is generated by random shuffling string s and then add one more letter at a random position. min_r, min_c = float("inf"), float("inf") # find extent of all rectangles
# Find the letter that was added in t. max_r, max_c = float("-inf"), float("-inf")
area = 0 # sum of areas of all rectangles
# Count frequencies of letters in s. For each letter in t, decrement count. If any letter count is negative then it corners = defaultdict(int) # count of number of corner by (r, c)
# is the additional letter in t.
# Time - O(n) for r1, c1, r2, c2 in rectangles:
# Space - O(1) area += (r2 - r1) * (c2 - c1)
min_r = min(min_r, r1)
class Solution(object): min_c = min(min_c, c1)
def findTheDifference(self, s, t): max_r = max(max_r, r2)
""" max_c = max(max_c, c2)
:type s: str

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))

class Solution(object): def decode(self, s):


def validUtf8(self, data): result = []
"""
:type data: List[int] while self.i < len(s) and s[self.i] != "]": # loop until end of s or closing bracket
:rtype: bool
""" if s[self.i] not in "0123456789": # add characters to result
i = 0 result.append(s[self.i])
while i < len(data): self.i += 1
else:
byte = data[i] repeats = 0
while s[self.i] in "0123456789": # calculate number of repetitions
if byte & (1 << 7) == 0: # first bit is a zero repeats = repeats * 10 + int(s[self.i])
i += 1 self.i += 1
continue self.i += 1 # skip over "["
result += (self.decode(s) * repeats) # recurse inside brackets and repeat
bit = 6 self.i += 1 # skip over "]"
while byte & (1 << bit) and bit > 3:
bit -= 1 return result
if byte & (1 << bit) or bit == 6: # 1 or more than 4 leading 1 bits
return False

bytes = 6 - bit # expeted number of bytes starting with 10 # python_1_to_1000/395_Longest_Substring_with_At_Least_K_Repeating_Characters.py - m


# If n is even, half it. If (n-1)%4 == 0 then the last 2 bits of n are 01, decrementing will make the last 2 bits 00
_author_ = 'jake' # which is better than incrementing to make last 2 bits 10.
_project_ = 'leetcode' # If (n-1)%4 != 0 then the last 2 bits of n are 11, decrementing will make the last 2 bits 10, incrementing will
# make the last 2 bits 00 and carry will at worst change one bit from 0 to 1 but potentiall reduce the number of set
# https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/ # bits. Incrementing is at least as good as decrementing.
# Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every # 3 is the exception where n-1 is not divisible by 4 bit it is still better to decrement.
# character in T appears no less than k times. # Time - O(log n)
# Space - O(1)
# Split string by all chars with frequency less than k. Repeat with substrings until all chars are present >= k times.
# Discard substrings shorter than current longest. class Solution(object):
# Time - O(n**3), every while loop removes one char from original s, for every c in freq, splitting is O(n) def integerReplacement(self, n):
# Space - O(n) """
:type n: int
from collections import Counter :rtype: int
"""
class Solution(object): operations = 0
def longestSubstring(self, s, k):
""" while n > 1:
:type s: str
:type k: int operations += 1
:rtype: int
""" if n % 2 == 0:
longest = 0 n //= 2
to_split = [s] # list of all substrings that may have infrequent chars
elif n == 3 or (n - 1) % 4 == 0:
while to_split: n -= 1
t = to_split.pop() # any substring to be checked
freq = Counter(t) else:
splitted = [t] # the result of removing all infrequent chars from t n += 1

for c in freq: return operations


if freq[c] < k: # split t by every infrequent character
new_splitted = []
for spl in splitted: # python_1_to_1000/398_Random_Pick_Index.py - m
new_splitted += spl.split(c)
splitted = new_splitted _author_ = 'jake'
_project_ = 'leetcode'
if len(splitted) == 1: # cound not be split, candicate for longest
longest = max(longest, len(splitted[0])) # https://leetcode.com/problems/random-pick-index/
else: # only add back candidates that are sufficiently long # Given an array of integers with possible duplicates, randomly output the index of a given target number.
to_split += [spl for spl in splitted if len(spl) > longest] # You can assume that the given target number must exist in the array.
# The array size can be very large. Solution that uses too much extra space will not pass the judge.
return longest
# To pick, reservoir sample indices by replacing previous result with probability 1 / count of targets seen.
# Alternatively create a list of i where nums[i] == target and randomly choose and index of that list. Only one
# python_1_to_1000/396_Rotate_Function.py - m # random choice but more memory.
# Alternatively map each num to a list of indices which adds O(n) memory and time to intialise pick but reduces time to
_author_ = 'jake' # pick.
_project_ = 'leetcode' # Time - O(1) to initialise, O(n) to pick
# Space - O(1)
# https://leetcode.com/problems/rotate-function/
# Given an array of integers A and let n to be its length. import random
# Assume Bk to be an array obtained by rotating the array A k positions clock-wise, we define a "rotation function" F
# on A as follow: class Solution(object):
# F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1]. def __init__(self, nums):
# Calculate the maximum value of F(0), F(1), ..., F(n-1). """

# 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

class Solution(object): def pick(self, target):


def maxRotateFunction(self, A): """
""" :type target: int
:type A: List[int] :rtype: int
:rtype: int """
""" count = 0
rotate_val, sum_A = 0, 0 for i, num in enumerate(self.nums):
if num == target:
for i, num in enumerate(A): if random.randint(0, count) == 0:
sum_A += num result = i
rotate_val += i * num count += 1
return result
max_rotate = rotate_val
for i in range(len(A) - 1, -1, -1):
rotate_val += sum_A - (len(A) * A[i]) # last element net n-1 reduction # python_1_to_1000/399_Evaluate_Division.py - m
max_rotate = max(max_rotate, rotate_val)
_author_ = 'jake'
return max_rotate _project_ = 'leetcode'

# 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

class Solution(object): """


def calcEquation(self, equations, values, queries): if num == 0:
""" return ["0:00"]
:type equations: List[List[str]]
:type values: List[float] bits_set = [[i] for i in range(10)] # list if times, each time is a list of which bits are set
:type queries: List[List[str]]
:rtype: List[float] for max_bit in range(10 - num + 1, 10): # allow space for other bits to be set
"""
graph = defaultdict(dict) # outer dict key is source node, value is destination node new_bits_set = []
for i in range(len(equations)): # innder dict key is destination node, value is ratio
num, den, val = equations[i][0], equations[i][1], values[i] for time in bits_set:
graph[num][den] = val for bit in range(time[-1] + 1, max_bit + 1):
graph[den][num] = 1 / val new_bits_set.append(time + [bit]) # set all possible next bits

for i in graph: bits_set = new_bits_set


for j in graph[i]:
for k in graph[i]: result = []
graph[j][k] = graph[j][i] * graph[i][k] # graph[j][j] = 1
for time in bits_set:
results = []
for num, den in queries: hours, mins = 0, 0
if num in graph and den in graph[num]:
results.append(graph[num][den]) for bit in time:
else: if bit >= 6: # hours bits
results.append(-1) hours += 1 << (bit - 6)
return results else: # minutes bits
mins += 1 << bit

if hours < 12 and mins < 60: # valid time

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

_author_ = 'jake' result.append(c)


_project_ = 'leetcode'
while k:
# https://leetcode.com/problems/binary-watch/ result.pop()
# A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom represent k -= 1
# the minutes (0-59). Each LED represents a zero or one, with the least significant bit on the right.
# Given a non-negative integer n which represents the number of LEDs that are currently on, return all possible times return "".join(result).lstrip("0") or "0" # "0" if result is empty
# the watch could represent. The order of output does not matter.
# The hour must not contain a leading zero, for example "01:00" is not valid, it should be "1:00".
# The minute must be consist of two digits and may contain a leading zero, for example "10:2" is not valid. # python_1_to_1000/403_Frog_Jump.py - h

# 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)

# https://leetcode.com/problems/convert-a-number-to-hexadecimal/ import heapq


# Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s complement method
# is used.
# All letters in hexadecimal (a-f) must be in lowercase. class Solution(object):
# The hexadecimal string must not contain extra leading 0s. If the number is zero, it is represented by a single zero def trapRainWater(self, heightMap):
# character '0'; otherwise, the first character in the hexadecimal string will not be the zero character. """
# The given number is guaranteed to fit within the range of a 32-bit signed integer. :type heightMap: List[List[int]]
:rtype: int
# Repeatedly divide by 16, converting the remainder to a digit or letter (if > 9). Reverse the result so most """
# significant bit is first. if not heightMap or not heightMap[0]:
# Time - O(log n) return 0
# Space - O(log n)
rows, cols = len(heightMap), len(heightMap[0])
class Solution(object): water = 0
def toHex(self, num): q = []
"""
:type num: int for r in range(rows):
:rtype: str heapq.heappush(q, (heightMap[r][0], r, 0))
""" heapq.heappush(q, (heightMap[r][cols - 1], r, cols - 1))
if num == 0: # special case, while loop is not entered for c in range(1, cols - 1):
return "0" heapq.heappush(q, (heightMap[0][c], 0, c))
if num < 0: # 2s complement of negative numbers heapq.heappush(q, (heightMap[rows - 1][c], rows - 1, c))
num += 2 ** 32
visited = {(r, c) for _, r, c in q}
result = []
while q:
while num != 0:
h, r, c = heapq.heappop(q)
num, digit = divmod(num, 16) for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
if digit > 9: # convert to char r1, c1 = r + dr, c + dc
result.append(chr(ord("a") + digit - 10)) if (r1, c1) not in visited and r1 >= 0 and c1 >= 0 and r1 < rows and c1 < cols:
else: visited.add((r1, c1))
result.append(str(digit)) water += max(0, h - heightMap[r1][c1])
heapq.heappush(q, (max(h, heightMap[r1][c1]), r1, c1))
return "".join(result[::-1]) # reverse
return water

# 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 ?

while j < len(abbr): subarray_sum = 0


for num in nums:
if abbr[j] < "a": # digit if num + subarray_sum > max_subarray: # num makes sum too big
m -= 1 # one less subarray
if abbr[j] == "0": # cannot lead with zero or skip zero letters if m <= 0: # at least num remain with no more subarrays to use
return False return False
count = 0 subarray_sum = num # num in next subarray
while j < len(abbr) and abbr[j] < "a": else:
count = count * 10 + int(abbr[j]) subarray_sum += num
j += 1
i += count return True

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 = []

for i in range(1, n + 1): # python_1_to_1000/415_Add_Strings.py


if i % 15 == 0:
result.append("FizzBuzz") _author_ = 'jake'
elif i % 3 == 0: _project_ = 'leetcode'
result.append("Fizz")
elif i % 5 == 0: # https://leetcode.com/problems/add-strings/
result.append("Buzz") # Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.
else:
result.append(str(i)) # Reverse the numbers so we start iterating over the least significant digit. Pad the shorter number with leading zeros.
# Add each pair of digits plus carry, mod 10 to update the carry. Append the final carry then reverse the result.
return result # Time - O(max(m, n)) where m and n are the lengths of the input strings
# Space - O(max(m, n))

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 Solution(object): result, carry = [], 0


def numberOfArithmeticSlices(self, A): for d1, d2 in zip(num1, num2):
""" carry, digit = divmod(int(d1) + int(d2) + carry, 10)
:type A: List[int] result.append(str(digit))
:rtype: int
""" if carry:
n = len(A) result.append(str(carry))
if n < 3:
return 0 return "".join(result[::-1])

diff = A[1] - A[0]


start, slices = 0, 0 # start of current progression
# python_1_to_1000/416_Partition_Equal_Subset_Sum.py - m
for i in range(2, n):
_author_ = 'jake'
next_diff = A[i] - A[i - 1] _project_ = 'leetcode'

if next_diff == diff: # https://leetcode.com/problems/partition-equal-subset-sum/


slices += i - start - 1 # Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets
else: # such that the sum of elements in both subsets is equal.
diff = next_diff
start = i - 1 # Dynamic programming. Maintain array of which sums can be reached. Initially only zero. For each num starting with
# largest, add this to all xisting sums starting with largest existing.
return slices # Alternatively, recursively use each remaining unique num and subtract from remaining target.
# Time - O(n * sum(nums))
# Space - O(sum(nums))
# python_1_to_1000/414_Third_Maximum_Number.py
class Solution(object):
_author_ = 'jake' def canPartition(self, nums):

""" for r, c in frontier:


:type nums: List[int] for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
:rtype: bool r1, c1 = r + dr, c + dc # neighbouring cell
""" if r1 < 0 or r1 >= rows or c1 < 0 or c1 >= cols or (r1, c1) in ocean:
sum_nums = sum(nums) continue # ignore already found or outside matrix
if sum_nums % 2 == 1: if matrix[r1][c1] >= matrix[r][c]: # nbor flows to ocean
return False new_frontier.add((r1, c1))
frontier = new_frontier # update frontier
nums.sort(reverse = True) # try largest nums first ocean |= new_frontier # add newly discovered to ocean
target = sum_nums // 2
return list(atlantic & pacific) # set intersection
subset_sum = [True] + [False] * target

for num in nums:


for i in range(target - 1, -1, -1): # backwards so cannot use same num repeatedly # python_1_to_1000/418_Sentence_Screen_Fitting.py - m
if subset_sum[i] and i + num <= target:
if i + num == target: # early return, solution found _author_ = 'jake'
return True _project_ = 'leetcode'
subset_sum[i + num] = True # mark this value
# https://leetcode.com/problems/sentence-screen-fitting/
return False # Given a rows x cols screen and a sentence represented by a list of non-empty words, find how many times the given
# sentence can be fitted on the screen.
# A word cannot be split into two lines.
from collections import Counter # Two consecutive words in a line must be separated by a single space.

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)

freq = Counter(nums) class Solution(object):


return self.partition(freq, nums_sum // 2) def wordsTyping(self, sentence, rows, cols):
"""
def partition(self, freq, target): :type sentence: List[str]
if target == 0: :type rows: int
return True :type cols: int
if target < 0: :rtype: int
return False """
sentence_len = sum(len(w) for w in sentence) + len(sentence)
for num in freq:
if freq[num] == 0: # line_fits[i] = (number of complete sentences, index of next starting word) for a row starting with
continue sentences[i]
freq[num] -= 1 # remove from frequency count line_fits = []
if self.partition(freq, target - num):
return True for start_word_index in range(len(sentence)):
freq[num] += 1 # add back to frequency count
row_length, sentences = 0, 0
return False word_index = start_word_index

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

class Solution(object): return fits


def pacificAtlantic(self, matrix):
"""
:type matrix: List[List[int]] # python_1_to_1000/419_Battleships_in_a_Board.py - m
:rtype: List[List[int]]
""" _author_ = 'jake'
if not matrix or not matrix[0]: _project_ = 'leetcode'
return []
# https://leetcode.com/problems/battleships-in-a-board/
rows, cols = len(matrix), len(matrix[0]) # Given an 2D board, count how many battleships are in it. The battleships are represented with 'X's, empty slots are
atlantic, pacific = set(), set() # cells that flow to each ocean # represented with '.'s. You may assume the following rules:
# You receive a valid board, made of only battleships or empty slots.
for r in range(rows): # Battleships can only be placed horizontally or vertically. In other words, they can only be made of the shape 1xN
atlantic.add((r, cols - 1)) # (1 row, N columns) or Nx1 (N rows, 1 column), where N can be of any size.
pacific.add((r, 0)) # At least one horizontal or vertical cell separates between two battleships - there are no adjacent battleships.
for c in range(cols):
atlantic.add((rows - 1, c)) # Sweep from top to bottom, left to right. New ship found if cell contains X and no X to left or above.
pacific.add((0, c)) # Time - O(mn)
# Space - O(1)
for ocean in [atlantic, pacific]:
class Solution(object):
frontier = set(ocean) def countBattleships(self, board):
while frontier: """
new_frontier = set() :type board: List[List[str]]
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
if not board or not board[0]:
return 0 # https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/
# Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 2**31.
rows, cols = len(board), len(board[0]) # Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.
ships = 0
# Starting from prefix of 1st bit, create a set of all prefixes. For each prefix, check the set for another prefix
for r in range(rows): # that when xored together extend the max_xor by a bit.
for c in range(cols): # Time - O(n)
# Space - O(n)
if board[r][c] == ".":
continue class Solution(object):
if r != 0 and board[r - 1][c] == "X": def findMaximumXOR(self, nums):
continue """
if c != 0 and board[r][c - 1] == "X": :type nums: List[int]
continue :rtype: int
ships += 1 """
mask = 0 # used to isolate the prefix bits of each num
return ships max_xor = 0 # current best result

for bit in range(31, -1, -1): # most significant bit first


# python_1_to_1000/420_Strong_Password_Checker.py - h
mask |= (1 << bit) # update mask with latest bit set
_author_ = 'jake' prefixes = {mask & num for num in nums}
_project_ = 'leetcode' target = max_xor | (1 << bit) # xor of 2 prefixes with bit set

# https://leetcode.com/problems/strong-password-checker/ for prefix in prefixes: # if p ^ t = q then p ^ t ^ p = t = q ^ p


# A password is considered strong if below conditions are all met: if prefix ^ target in prefixes:
# It has at least 6 characters and at most 20 characters. max_xor = target
# It must contain at least one lowercase letter, at least one uppercase letter, and at least one digit. break
# It must NOT contain three repeating characters in a row.
# Write a function that takes a string s as input, and return the MINIMUM change required to make s a strong password. return max_xor
# If s is already strong, return 0.
# Insertion, deletion or replace of any one character are all considered as one change.

# 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 s[i].isdigit(): class Solution(object):


digit = True def validWordSquare(self, words):
if s[i].isupper(): """
upper = True :type words: List[str]
if s[i].islower(): :rtype: bool
lower = True """
if len(words) != len(words[0]): # ensure the sides of the square have the same length
if i >= 2 and s[i] == s[i - 1] == s[i - 2]: # sequence of 3 return False
seq = 2
while i < len(s) and s[i] == s[i - 1]: # find length of sequence n = len(words[0])
seq += 1
i += 1 for i, word in enumerate(words[1:], 1):
m = len(word)
subs += seq // 3 if m > n: # no other word can be longer than first word
if seq % 3 == 0: return False
singles += 1 words[i] += (n - m) * " " # pad words with spaces to make complete square
if seq % 3 == 1:
doubles += 1 for i in range(n):
for j in range(n):
else: if words[i][j] != words[j][i]:
i += 1 return False

types_missing = 3 - (digit + upper + lower) return True

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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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)

class Solution(object): class Solution(object):


def characterReplacement(self, s, k): def treeToDoublyList(self, root):
""" """
:type s: str :type root: Node
:type k: int :rtype: Node
:rtype: int """
""" if not root:
longest, start = 0, 0 return None
freq = defaultdict(int)
left_head = self.treeToDoublyList(root.left)
for end in range(len(s)): right_head = self.treeToDoublyList(root.right)
freq[s[end]] += 1
# while more than k chars in window that are not the most frequent if left_head:
while (end - start + 1) - max(freq.values()) > k: root.left = left_head.left # link root to tail of left subtree
freq[s[start]] -= 1 left_head.left.right = root
start += 1 else:
left_head = root # no subtree on left, root is left_head
longest = max(longest, end - start + 1)
if right_head:
return longest root.right = right_head # link root to head of right_subtree
right_tail = right_head.left # store right_tail
right_head.left = root
else:
# python_1_to_1000/425_Word_Squares.py - h right_tail = root # no subtree on right, root is right_tail

_author_ = 'jake' left_head.left = right_tail # link head and tail


_project_ = 'leetcode' right_tail.right = left_head

# https://leetcode.com/problems/word-squares/ return left_head


# Given a set of words (without duplicates), find all word squares you can build from them.
# A sequence of words forms a valid word square if the kth row and column read the exact same string.
# All words will have the exact same length. # python_1_to_1000/427_Construct_Quad_Tree.py - m

# 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'

class Codec: # https://leetcode.com/problems/flatten-a-multilevel-doubly-linked-list/


# You are given a doubly linked list which in addition to the next and previous pointers,
def serialize(self, root): # it could have a child pointer, which may or may not point to a separate doubly linked list.
"""Encodes a tree to a single string. # These child lists may have one or more children of their own, and so on, to produce a multilevel data structure.
:type root: Node # Flatten the list so that all the nodes appear in a single-level, doubly linked list.
:rtype: str # You are given the head of the first level of the list.
"""
serial = [] # Iterate along the main list, inserting child lists. Ensure links are in both directions and remove links to
# children when flattened.
def preorder(node): # Time - O(n)
# Space - O(n)
if not node:
return class Solution(object):
def flatten(self, head):
serial.append(str(node.val)) """
:type head: Node
for child in node.children: :rtype: Node
preorder(child) """
node = head # save the head to be returned
serial.append("#") # indicates no more children, continue serialization from parent
while node: # iterate over the list
preorder(root)
return " ".join(serial) if node.child:

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

def helper(node): node = node.next # move to the next node

if not tokens: return head

new_block.after = old_after
old_after.before = new_block
# python_1_to_1000/431_Encode_N-ary_Tree_to_Binary_Tree.py - h

_author_ = 'jake' class AllOne(object):


_project_ = 'leetcode' def __init__(self):
"""
# https://leetcode.com/problems/encode-n-ary-tree-to-binary-tree/ Initialize your data structure here.
# Design an algorithm to encode an N-ary tree into a binary tree and decode the binary tree to get the original """
# N-ary tree. An N-ary tree is a rooted tree in which each node has no more than N children. self.begin = Block() # sentinel
# Similarly, a binary tree is a rooted tree in which each node has no more than 2 children. self.end = Block() # sentinel
# There is no restriction on how your encode/decode algorithm should work. You just need to ensure that an N-ary tree self.begin.after = self.end
# can be encoded to a binary tree and this binary tree can be decoded to the original N-nary tree structure. self.end.before = self.begin
self.mapping = {} # key to block
# The left child of a binary node is the subtree encoding all the children of the corresponding n-ary node.
# The right child of a binary node is a chain of the binary root nodes encoding each sibling of the n-ary node. def inc(self, key):
# Hence the root node has no right binary child, because the root has no sibilings. """
# Time - O(n) Inserts a new key <Key> with value 1. Or increments an existing key by 1.
# Space - O(n) :type key: str
:rtype: void
class Codec: """
if not key in self.mapping: # find current block and remove key
def encode(self, root): current_block = self.begin
"""Encodes an n-ary tree to a binary tree. else:
:type root: Node current_block = self.mapping[key]
:rtype: TreeNode current_block.keys.remove(key)
"""
if not root: if current_block.val + 1 != current_block.after.val: # insert new block
return None new_block = Block(current_block.val + 1)
current_block.insert_after(new_block)
binary = TreeNode(root.val) # create a binary root else:
if not root.children: new_block = current_block.after
return binary
new_block.keys.add(key) # update new_block
binary.left = self.encode(root.children[0]) # left child of binary is the encoding of all n-ary children, self.mapping[key] = new_block # ... and mapping of key to new_block
node = binary.left # starting with the first child.
for child in root.children[1:]: # other children of n-ary root are right child of previous child if not current_block.keys and current_block.val != 0: # delete current block if not seninel
node.right = self.encode(child) current_block.remove()
node = node.right
def dec(self, key):
return binary """
Decrements an existing key by 1. If Key's value is 1, remove it from the data structure.
def decode(self, data): :type key: str
"""Decodes your binary tree to an n-ary tree. :rtype: void
:type data: TreeNode """
:rtype: Node if not key in self.mapping:
""" return
if not data:
return None current_block = self.mapping[key]
del self.mapping[key] # could use self.mapping.pop(key)
nary = Node(data.val, []) # create n-ary root current_block.keys.remove(key)
node = data.left # move to first child of n-ary root
while node: # while more children of n-ary root if current_block.val != 1:
nary.children.append(self.decode(node)) # append to list if current_block.val - 1 != current_block.before.val: # insert new block
node = node.right # and move to next child new_block = Block(current_block.val - 1)
current_block.before.insert_after(new_block)
return nary else:
new_block = current_block.before
new_block.keys.add(key)
# python_1_to_1000/432_All_Oone_Data_Structure.py - h self.mapping[key] = new_block

_author_ = 'jake' if not current_block.keys: # delete current block


_project_ = 'leetcode' current_block.remove()

# https://leetcode.com/problems/all-oone-data-structure/ def getMaxKey(self):


# Implement a data structure supporting the following operations: """
# Inc(Key) - Inserts a new key with value 1. Or increments existing key by 1. Key is guaranteed to be non-empty string. Returns one of the keys with maximal value.
# Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If the :rtype: str
# key does not exist, this function does nothing. Key is guaranteed to be a non-empty string. """
# GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string "". if self.end.before.val == 0:
# GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string "". return ""
key = self.end.before.keys.pop() # pop and add back to get arbitrary (but not random) element
# Create doubly linked list of blocks. Each block contains all the keys for a given value. Blocks are in value order. self.end.before.keys.add(key)
# Also maintain a mapping from key to its block. return key
# Time - O(1), all operations
# Space - O(n) def getMinKey(self):
"""
class Block(object): Returns one of the keys with Minimal value.
def __init__(self, val=0): :rtype: str
self.val = val """
self.keys = set() if self.begin.after.val == 0:
self.before = None return ""
self.after = None key = self.begin.after.keys.pop()
self.begin.after.keys.add(key)
def remove(self): return key
self.before.after = self.after
self.after.before = self.before
self.before, self.after = None, None

def insert_after(self, new_block):


old_after = self.after # python_1_to_1000/433_Minimum_Genetic_Mutation.py - m
self.after = new_block
new_block.before = self _author_ = 'jake'
_project_ = 'leetcode' # You may assume the interval's end point is always bigger than its start point.
# Intervals like [1,2] and [2,3] have borders "touching" but they don't overlap each other.
# https://leetcode.com/problems/minimum-genetic-mutation/
# A gene string can be represented by an 8-character long string, with choices from "A", "C", "G", "T". # Sort by increasing start point. If the next interval starts before the current end, set current end to be lesser of
# Suppose we need to investigate about a mutation (mutation from "start" to "end"), where ONE mutation is defined as # current and next ends. Else set current end to be next end if no overlap.
# ONE single character changed in the gene string. # Time - O(n log n)
# Also, there is a given gene "bank", which records all the valid gene mutations. A gene must be in the bank to make # Space - O(1)
# it a valid gene string.
# Given start, end, bank, your task is to determine what is the minimum number of mutations needed to mutate from # Definition for an interval.
# "start" to "end". If there is no such a mutation, return -1. class Interval(object):
# Starting point is assumed to be valid, so it might not be included in the bank. def __init__(self, s=0, e=0):
# You may assume start and end string is not the same. self.start = s
self.end = e
# NOTE THAT THIS PROBLEM IS IN DRAFT STATUS IN LEETCODE
# BFS. For each gene in frontier, try all possible mutations. If mutation is in bank then remove, hence no need to
# check for loops. class Solution(object):
# Time - O(n) where n is size of bank def eraseOverlapIntervals(self, intervals):
# Space - O(n) """
:type intervals: List[Interval]
class Solution(object): :rtype: int
def minMutation(self, start, end, bank): """
""" erase = 0
:type start: str if not intervals:
:type end: str return 0
:type bank: List[str]
:rtype: int intervals.sort(key=lambda x: x.start) # sort by increasing start
""" current_end = intervals[0].start # does not overlap with first interval
chars = set("ACGT")
bank = set(bank) # convert to a set for interval in intervals:
if end not in bank: # early return if current_end > interval.start: # overlap
return -1 erase += 1
distance = 0 if interval.end > current_end: # retain current since end is less so fewer future overlaps
continue
frontier = [start] current_end = interval.end # update current if no overlap or best choice
while frontier:
return erase
new_frontier = []
distance += 1
# python_1_to_1000/436_Find_Right_Interval.py - m
for gene in frontier:
_author_ = 'jake'
for i in range(len(gene)): _project_ = 'leetcode'
for c in chars:
# https://leetcode.com/problems/find-right-interval/
if c == gene[i]: # Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is
continue # bigger than or equal to the end point of the interval i, which can be called that j is on the "right" of i.
# For any interval i, you need to store the minimum interval j's index, which means that the interval j has the
mutation = list(gene) # convert to list, mutate and back to string # minimum start point to build the "right" relationship for interval i. If the interval j doesn't exist, store -1 for
mutation[i] = c # the interval i. Finally, you need output the stored value of each interval as an array.
mutation = "".join(mutation)
# Sort tuples of intervals and original indices. For each interval, binary search for start point that is not less than
if mutation == end: # ok since have returned early if end not in bank # end point.
return distance # Time - O(n log n)
if mutation in bank: # Space - O(n)
bank.discard(mutation) # will not be shorter if same mutation is revisited
new_frontier.append(mutation) # Definition for an interval.
class Interval(object):
frontier = new_frontier def __init__(self, s=0, e=0):
self.start = s
return -1 self.end = e

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

_author_ = 'jake' if not freq:


_project_ = 'leetcode' result.append(len(s) - n)
return result
# https://leetcode.com/problems/path-sum-iii/
# You are given a binary tree in which each node contains an integer value.
# Find the number of paths that sum to a given value.
# The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent # python_1_to_1000/439_Ternary_Expression_Parser.py - m
# nodes to child nodes).
_author_ = 'jake'
# Maintain dictionary counting the paths from root to current node. Visit each node and count the paths ending at that _project_ = 'leetcode'
# node with target sum. Increment the count of the path to the node in the dictionary and recurse left and right.
# Decremetn count after recursion. # https://leetcode.com/problems/ternary-expression-parser/
# Time - O(n) # Given a string representing arbitrarily nested ternary expressions, calculate the result of the expression. You can
# Space - O(n) # always assume that the given expression is valid and only consists of digits 0-9, ?, :, T and F.
# Each number will contain only one digit.
from collections import defaultdict # The conditional expressions group right-to-left (as usual in most languages).
# The condition will always be either T or F. That is, the condition will never be a digit.
class Solution(object): # The result of the expression will always evaluate to either a digit 0-9, T or F.
def pathSum(self, root, sum):
""" # Move form left to right adding all chars to a stack unless top of stack is '?'. In which case pop off true_val and
:type root: TreeNode # false_val, then push back to stack result depending on current char.
:type sum: int # Time - O(n)
:rtype: int # Space - O(n)
"""
paths = defaultdict(int) # key is sum of path from root, value is the count of such paths class Solution(object):
paths[0] = 1 # one path has zero sum def parseTernary(self, expression):
"""
def helper(node, partial): :type expression: str
:rtype: str
if not node: """
return 0 stack = []

partial += node.val for c in expression[::-1]:


count = paths[partial - sum] # paths ending at node
if stack and stack[-1] == "?":
paths[partial] += 1 stack.pop() # remove '?'
count += helper(node.left, partial) true_val = stack.pop()
count += helper(node.right, partial) stack.pop() # remove ':'
paths[partial] -= 1 false_val = stack.pop()
if c == "T":
return count stack.append(true_val)
else:
return helper(root, 0) stack.append(false_val)

else:
# python_1_to_1000/438_Find_All_Anagrams_in_a_String.py - m stack.append(c)

_author_ = 'jake' return stack.pop()


_project_ = 'leetcode'

# 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.

from collections import defaultdict # Time - O(logn ** 2)


# Space - O(1)
class Solution(object):
def findAnagrams(self, s, p): class Solution(object):
""" def findKthNumber(self, n, k):
:type s: str """
:type p: str :type n: int
:rtype: List[int] :type k: int
""" :rtype: int
n = len(p) """
freq = defaultdict(int) # map from char to net count of char in sliding window kth = 1
result = [] k -= 1

if n > len(s): # no anagrams are possible while k > 0:


return result
lower, upper = kth, kth + 1 # check range including lower, excluding upper
def update_freq(c, step): # updates dictionary and deletes zero values count = 0
freq[c] += step
if freq[c] == 0: while lower <= n: # at least some of range is valid
del freq[c] count += min(upper, n + 1) - lower
lower *= 10
for c1, c2 in zip(p, s[:n]): # populate initial window upper *= 10
update_freq(c1, -1)
update_freq(c2, 1) if count <= k: # count numbers do not reach k
k -= count # use all count numbers
for i in range(len(s) - n): kth += 1 # increment start point for next range
if not freq: else:
result.append(i) k -= 1 # use kth
update_freq(s[i], -1) # remove char at back of window kth *= 10 # next range start
update_freq(s[i + n], 1) # add char at front of window
return kth if c != chars[char_start]: # not extending same sequence of chars

chars[result_length] = chars[char_start] # add this char to result


# python_1_to_1000/441_Arranging_Coins.py result_length += 1

_author_ = 'jake' seq_length = i - char_start


_project_ = 'leetcode'
if seq_length > 1: # can compress
# https://leetcode.com/problems/arranging-coins/ digits = list(str(seq_length))
# You have a total of n coins that you want to form in a staircase, where every k-th row must have exactly k coins. digits_length = len(digits)
# Given n, find the total number of full staircase rows that can be formed. chars[result_length:result_length + digits_length] = digits # insert digits
# n is a non-negative integer and fits within the range of a 32-bit signed integer. result_length += digits_length

# 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

class Solution(object): # python_1_to_1000/444_Sequence_Reconstruction.py - m


def arrangeCoins(self, n):
""" _author_ = 'jake'
:type n: int _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/sequence-reconstruction/
return int(math.sqrt(1 + 8.0 * n) - 1) / 2 # Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. The org sequence
# is a permutation of the integers from 1 to n, with 1 ≤ n ≤ 104. Reconstruction means building a shortest common
# supersequence of the sequences in seqs (i.e., a shortest sequence so that all sequences in seqs are subsequences
# python_1_to_1000/442_Find_All_Duplicates_in_an_Array.py - m # of it). Determine whether there is only one sequence that can be reconstructed from seqs and it is the org sequence.

_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:

for i in range(len(nums)): for n1, n2 in zip([None] + seq, seq):

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

for i, c in enumerate(chars): node = l1


while node:

num1 = num1 * 10 + node.val


node = node.next boomerangs = 0
node = l2
while node: for middle in points:
num2 = num2 * 10 + node.val distances = defaultdict(int)
node = node.next
for i, other in enumerate(points):
total = num1 + num2 distances[dist_squared(middle, other)] += 1
if total == 0: # return single node with zero
return ListNode(0) for count in distances.values():
result = None boomerangs += count * (count - 1)

while total: return boomerangs


total, digit = divmod(total, 10)
new_node = ListNode(digit)
new_node.next = result # make digit start of result # python_1_to_1000/448_Find_All_Numbers_Disappeared_in_an_Array.py
result = new_node
_author_ = 'jake'
return result _project_ = 'leetcode'

# 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)

from collections import defaultdict


# python_1_to_1000/449_Serialize_and_Deserialize_BST.py - m
class Solution(object):
def numberOfArithmeticSlices(self, A): _author_ = 'jake'
""" _project_ = 'leetcode'
:type A: List[int]
:rtype: int # https://leetcode.com/problems/serialize-and-deserialize-bst/
""" # Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your
count = 0 # serialization/deserialization algorithm should work. You just need to ensure that a binary search tree can be
subsequences = [] # list of dicts, each dict maps from a difference value to the count of subsequence slices # serialized to a string and this string can be deserialized to the original tree structure.
# ending at A[i] with that difference and of length 2 or more
for i in range(len(A)): # Serialize by preorder traversal. String of values joined by spaces, no None markers.
subsequences.append(defaultdict(int)) # Deserialze from deque. If first value is in range, use value as root and recurse left and right subtrees with ranges
# less than and more than value respectively.
for j in range(i): # for each previous num # Time - O(n)
diff = A[i] - A[j] # Space - O(n)
diff_count = subsequences[j].get(diff, 0) # default to zero
count += diff_count # all sequences (length 2 or more) can be extended and end here # Definition for a binary tree node.
subsequences[-1][diff] += diff_count + 1 # add new sequence from i to j class TreeNode(object):
def __init__(self, x):
return count self.val = x
self.left = None
self.right = None
# python_1_to_1000/447_Number_of_Boomerangs.py - m
from collections import deque
_author_ = 'jake'
_project_ = 'leetcode'
def serialize(self, root):
# https://leetcode.com/problems/number-of-boomerangs/ """Encodes a tree to a single string.
# Given n points in the plane that are all pairwise distinct, a "boomerang" is a tuple of points (i, j, k) such that :type root: TreeNode
# the distance between i and j equals the distance between i and k (the order of the tuple matters). :rtype: str
# Find the number of boomerangs. """
serial_list = []
# For each point, calculate the distances to all other points and create a mapping from each distance to the number of
# points with that distance. For each distance, calculate the the number of ways that the points at that distance def serial(node):
# can mane a boomerang, which is the number of pairs of points. if not node:
# Time - O(n**2) return
# Space - O(n**2) serial_list.append(str(node.val))
serial(node.left)
from collections import defaultdict serial(node.right)

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

class Solution(object): return arrows


def deleteNode(self, root, key):
"""
:type root: TreeNode # python_1_to_1000/453_Minimum_Moves_to_Equal_Array_Elements.py - m
:type key: int
:rtype: TreeNode _author_ = 'jake'
""" _project_ = 'leetcode'
if not root:
return None # https://leetcode.com/problems/minimum-moves-to-equal-array-elements/
# Given a non-empty integer array of size n, find the minimum number of moves required to make all array elements
if key > root.val: # key in right subtree, keep root and update right subtree # equal, where a move is incrementing n - 1 elements by 1.
root.right = self.deleteNode(root.right, key)
elif key < root.val: # Incrementing n - 1 elements is equivalent to incrementing all n elements and decrementing 1 element. Incrementing all
root.left = self.deleteNode(root.left, key) # elements does not equalize the array, so we need to count the number of moves to decrement all elements to be equal.
# For each element, this is the difference between its value and the minimum value.
else: # Time - O(n)
if not (root.left and root.right): # one or no children # Space - O(1)
root = root.left or root.right
else: # both children class Solution(object):
next_largest = root.right def minMoves(self, nums):
while next_largest.left: """
next_largest = next_largest.left :type nums: List[int]
root.val = next_largest.val :rtype: int
root.right = self.deleteNode(root.right, root.val) """
return sum(nums) - min(nums) * len(nums)
return root

# 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)

from collections import Counter from collections import defaultdict

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):

class Solution(object): pos = num > 0 # direction of movements


def findContentChildren(self, g, s): j = (i + num) % n # take the first step
""" steps = 1
:type g: List[int]
:type s: List[int] while steps < n and nums[j] % n != 0 and (nums[j] > 0) == pos:
:rtype: int j = (j + nums[j]) % n # take the next step
""" steps += 1
content = 0 # number of content children
child = 0 # index of next child if steps == n: # loop is found
g.sort() return True
s.sort()
nums[i] = 0
for cookie in s: j = (i + num) % n # set everything visited to zero to avoid repeating
while nums[j] % n != 0 and (nums[j] > 0) == pos:
if child == len(g): # early return, no more children j, nums[j] = (j + nums[j]) % n, 0
break
return False
if g[child] <= cookie: # child accepts cookie
content += 1
child += 1
# python_1_to_1000/458_Poor_Pigs.py - h
return content
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/456_132_Pattern.py - m
# https://leetcode.com/problems/poor-pigs/
_author_ = 'jake' # There are 1000 buckets, one and only one of them contains poison, the rest are filled with water.
_project_ = 'leetcode' # They all look the same. If a pig drinks that poison it will die within 15 minutes.
# What is the minimum amount of pigs you need to figure out which bucket contains the poison within one hour.
# https://leetcode.com/problems/132-pattern/ # Answer this question, and write an algorithm for the follow-up general case.
# Given a sequence of n integers a1, a2, ..., an, a 132 pattern is a subsequence ai, aj, ak such that i < j < k # If there are n buckets and a pig drinking poison will die within m minutes, how many pigs (x) you need to figure out
# and ai < ak < aj. Design an algorithm that takes a list of n numbers as input and checks whether there is a # the "poison" bucket within p minutes? There is exact one bucket with poison.
# 132 pattern in the list.
# Find the number of rounds of tests that can be run as the integer division of the total time over time to die.
# Iterate over nums in reverse order. If num < two then we have a solution because some number greater than two was # Arrange the buckets in a hypercube with side of rounds + 1.
# seen after two (and caused two to be popped off stack). Stack is ascending from top to bottom, so last pop is # Each pig finds the coordinate in one dimension of the hypercube by drinking from rounds + 1 buckets in each round.
# greatest number less than num. # If a pig dies, we find the coordinate in that dimension, if it doesn't we know the coordinate is the final index.
# Time - O(n) # Hence buckets in hypercube = (rounds + 1) ** pigs. So pigs = ln(buckets) / ln(rounds + 1), rounded up to the next
# Space - O(n) # integer.
# Time - O(1)
class Solution(object): # Space - O(1)
def find132pattern(self, nums):
""" from math import log, ceil
:type nums: List[int]
:rtype: bool class Solution(object):
""" def poorPigs(self, buckets, minutesToDie, minutesToTest):
two = float("-inf") """
stack = [] :type buckets: int
:type minutesToDie: int
for i in range(len(nums) - 1, -1, -1): :type minutesToTest: int
:rtype: int
if nums[i] < two: """
return True rounds = minutesToTest // minutesToDie

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

return False _author_ = 'jake'


_project_ = 'leetcode'

# 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

class LFUCache(object): return hamming


def __init__(self, capacity):
"""
:type capacity: int # python_1_to_1000/462_Minimum_Moves_to_Equal_Array_Elements_II.py - m
"""
self.capacity = capacity _author_ = 'jake'
self.time = 0 _project_ = 'leetcode'
self.map = {} # key to value
self.freq_time = {} # key to (freq, time) # https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/
self.priority_queue = [] # (freq, time, key), only updated when new key is added # Given a non-empty integer array, find the minimum number of moves required to make all array elements equal, where a
self.update = set() # keys that have been get/put since last new key was added # move is incrementing a selected element by 1 or decrementing a selected element by 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

self.time += 1 _author_ = 'jake'


if not key in self.map: _project_ = 'leetcode'

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))

perimiter = 0 for lender, receiver, amount in transactions:


balances[lender] += amount
for r in range(rows): balances[receiver] -= amount
for c in range(cols):
if grid[r][c] == 1: net_balances = [b for b in balances.values() if b != 0]
perimiter += 4
if grid[r + 1][c] == 1: def transfers(net_balances):
perimiter -= 2
if grid[r][c + 1] == 1: if not net_balances: # base case
perimiter -= 2 return 0

return perimiter b = net_balances[0]


for i in range(1, len(net_balances)): # optimal to net exactly
if b == -net_balances[i]:
# python_1_to_1000/464_Can_I_Win.py - m return 1 + transfers(net_balances[1:i] + net_balances[i + 1:])

_author_ = 'jake' min_transfers = float("inf")


_project_ = 'leetcode' for i in range(1, len(net_balances)):
if b * net_balances[i] < 0: # opposite signs
# https://leetcode.com/problems/can-i-win/ count = 1 + transfers(net_balances[1:i] + net_balances[i + 1:] + [b + net_balances[i]])
# In the "100 game," two players take turns adding, to a running total, any integer from 1..10. The player who first min_transfers = min(min_transfers, count)
# causes the running total to reach or exceed 100 wins. What if we change the game so that players cannot re-use
# integers? return min_transfers
# Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can
# force a win, assuming both players play optimally. return transfers(net_balances)

# 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 unused[-1] >= target: class Solution(object):


return True def getMaxRepetitions(self, s1, n1, s2, n2):
"""
tup = tuple(unused) :type s1: str
if tup in memo: :type n1: int
return memo[tup] :type s2: str
:type n2: int
for i in range(len(unused) - 1, -1, -1): :rtype: int
"""
opposition_win = self.next_player_win(target - unused[i], unused[:i] + unused[i + 1:], memo) if any(c for c in set(s2) if c not in set(s1)): # early return if no result possible
if not opposition_win: return 0
memo[tup] = True
return True i, j = 0, 0 # index counters in s1 and s2
s1_reps, s2_reps = 0, 0 # numbers of complete repetitions of s1 and s2 used
memo[tup] = False s2_index_to_reps = {0 : (0, 0)} # map from j to (s1_reps, s2_reps)
return False
while s1_reps < n1: # break if n1 copies of s1 used

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

substring_ending[ord(c) - ord("a")] = max(substring_ending[ord(c) - ord("a")], length) # python_1_to_1000/470_Implement_Rand10()_Using_Rand7().py - m

return sum(substring_ending) _author_ = 'jake'


_project_ = 'leetcode'

# 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

# https://leetcode.com/problems/concatenated-words/ _author_ = 'jake'


# Given a list of words (without duplicates), please write a program that returns all concatenated words in the given _project_ = 'leetcode'
# list of words. A concatenated word is defined as a string that is comprised entirely of at least two shorter words
# in the given array. # https://leetcode.com/problems/ones-and-zeroes/
# In the computer world, use restricted resource you have to generate maximum benefit is what we always want to pursue.
# For each prefix of each word, if prefix is a word test whether suffix is a word or a concatenation of words # For now, suppose you are a dominator of m 0s and n 1s respectively. On the other hand, there is an array with
# Time - O(n * k**2) for n words of max length k # strings consisting of only 0s and 1s. Now your task is to find the maximum number of strings that you can form with
# Space - O(k) # given m 0s and n 1s. Each 0 and 1 can be used at most once.

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:

word_set = set(words) s_zeros = sum([True for c in s if c == "0"])


results = [] s_ones = len(s) - s_zeros
for word in words:
for i in range(1, len(word)): # prefix/suffix where prefix is in dict and suffix is not empty for i in range(m, -1, -1):
if word[:i] in word_set and is_concat(word[i:]): for j in range(n, -1, -1):
results.append(word) if i >= s_zeros and j >= s_ones: # keep max_form[i][j] unchanged if insufficient 0s or 1s
break max_form[i][j] = max(max_form[i][j], 1 + max_form[i - s_zeros][j - s_ones])
return results
return max_form[-1][-1] # for all strs, max_form from m, n

# python_1_to_1000/473_Matchsticks_to_Square.py - m

_author_ = 'jake' # python_1_to_1000/475_Heaters.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/matchsticks-to-square/ _project_ = 'leetcode'
# Your input will be several matchsticks, represented with their stick length. Your output will either be true or
# false, to represent whether you could make one square using all the matchsticks. # https://leetcode.com/problems/heaters/
# Winter is coming! Your first job during the contest is to design a standard heater with fixed warm radius to warm
# Put each match in each side with capacity then recurse for next match. # all the houses.
# 3 heuristics to improve speed, 1) sort in descending order, 2) avoid duplicate recursive call, 3) pre-fill sides # Now, you are given positions of houses and heaters on a horizontal line, find out minimum radius of heaters so that
# with exact matches # all houses could be covered by those heaters.
# Time - O(4**n) # So, your input will be the positions of houses and heaters seperately, and your expected output will be the minimum
# Space - O(1) # radius standard of heaters.

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

class Solution(object): def randPoint2(self):


def findComplement(self, num): radius = random.random() ** 0.5 * self.radius
""" angle = random.random() * 2 * math.pi
:type num: int return [radius * math.sin(angle) + self.x_center, radius * math.cos(angle) + self.y_center]
:rtype: int
"""
i = 1 # python_1_to_1000/479_Largest_Palindrome_Product.py - h

while i <= num: _author_ = 'jake'


i <<= 1 _project_ = 'leetcode'

return (i - 1) ^ num # https://leetcode.com/problems/largest-palindrome-product/


# Find the largest palindrome made from the product of two n-digit numbers.
# Since the result could be very large, you should return the largest palindrome mod 1337.

# 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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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

class Solution(object): i = 2 # next index to be processed


def medianSlidingWindow(self, nums, k): s = [1, 2, 2]
""" ones = 1
:type nums: List[int]
:type k: int while len(s) < n:
:rtype: List[float]
""" digit = s[-1] ^ 3 # next digits(s) are different from previous end
lower, upper = [], [] # heaps of nums in window
s.append(digit)
for i in range(k): # push k nums onto upper if s[i] == 2:
heapq.heappush(upper, nums[i]) s.append(digit)
for i in range(k // 2): # swap k//2 nums onto lower
heapq.heappush(lower, -heapq.heappop(upper)) if digit == 1:
ones += s[i]
medians = []
junk = defaultdict(int) # key is num, val is count i += 1

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' """

# https://leetcode.com/problems/find-permutation/ def helper(left, right):


# You are given a secret signature consisting of character 'D' and 'I'. 'D' represents a decreasing relationship
# between two numbers, 'I' represents an increasing relationship between two numbers. And our secret signature was if right < left: # base case
# constructed by a special integer array, which contains uniquely all the different number from 1 to n (n is the return 0
# length of the secret signature plus 1). if right == left: # base case
# For example, the secret signature "DI" can be constructed by array [2,1,3] or [3,1,2], but won't be constructed by return nums[left]
# array [3,2,4] or [2,1,3,4]. if (left, right) in memo:
# Your job is to find the lexicographically smallest permutation of [1, 2, ... n] that could refer to the given secret return memo[(left, right)]
# signature in the input.
left_right = helper(left + 1, right - 1)
# Using a stack, iterate over integers i to n - 1, pushing each integer. If the next letter is "I", we have reached left_left = helper(left + 2, right)
# the end of a sequence of "D"s (potentialy of length zero). Pop entire stack and append to result (hence appearing take_left = nums[left] + min(left_right - nums[right], left_left - nums[left + 1])
# in decreasing order).
# Time - O(n) right_right = helper(left, right - 2) # reuse left_right
# Space - O(n) take_right = nums[right] + min(left_right - nums[left], right_right - nums[right - 1])

class Solution(object): result = max(take_left, take_right)


def findPermutation(self, s): memo[(left, right)] = result
""" return result
:type s: str
:rtype: List[int] memo = {}
""" return helper(0, len(nums) - 1) >= 0
permutation, stack = [], []

for i in range(1, len(s) + 1):


stack.append(i) # python_1_to_1000/487_Max_Consecutive_Ones_II.py - m
if s[i - 1] == "I":
while stack: _author_ = 'jake'
permutation.append(stack.pop()) _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)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def findMaxConsecutiveOnes(self, nums):
"""
# https://leetcode.com/problems/max-consecutive-ones/ :type nums: List[int]
# Given a binary array, find the maximum number of consecutive 1s in this array. :rtype: int
"""
# Iterate over nums. If we see a zero, update max_consecutive and reset consecutive. If we see a one, increment max_consecutive = 0
# consecutive. i = 0
# Time - O(n) while i < len(nums) and nums[i] == 0: # find first one
# Space - O(1) i += 1
start, prev_start = i, max(i - 1, 0)
class Solution(object):
def findMaxConsecutiveOnes(self, nums): for j in range(i + 1, len(nums)):
"""
:type nums: List[int] if nums[j] == 0:
:rtype: int if j != 0 and nums[j - 1] == 0:
""" prev_start = j # prefix new sequence by 1
consecutive, max_consecutive = 0, 0 else:
max_consecutive = max(max_consecutive, j - prev_start)
for num in nums: prev_start = start # use 1 to fill gap
if num == 0:
max_consecutive = max(max_consecutive, consecutive) start = j + 1 # start new sequence at next index
consecutive = 0
else: return max(max_consecutive, len(nums) - prev_start) # cover case of final sequence

# 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

if (r, c) not in visited:


# python_1_to_1000/489_Robot_Room_Cleaner.py - h if [r, c] == destination:
return True
_author_ = 'jake' queue.append((r, c)) # DFS since add to end of queue
_project_ = 'leetcode'
return False
# https://leetcode.com/problems/robot-room-cleaner/
# Given a robot cleaner in a room modeled as a grid.
# Each cell in the grid can be empty or blocked. # python_1_to_1000/491_Increasing_Subsequences.py - m
# The robot cleaner with 4 given APIs can move forward, turn left or turn right. Each turn it made is 90 degrees.
# When it tries to move into a blocked cell, its bumper sensor detects the obstacle and it stays on the current cell. _author_ = 'jake'
# Design an algorithm to clean the entire room using only the 4 given APIs shown below. _project_ = 'leetcode'
# boolean move() - returns True if it is possible to move in the current facing direction
# void turnLeft() # https://leetcode.com/problems/increasing-subsequences/
# void turnRight() # Given an integer array, your task is to find all the different possible increasing subsequences of the given array,
# void clean() # and the length of an increasing subsequence should be at least 2 .
j += 1
# For each number, create a set of subsequences by extending all previous subsequences. self.pairs += j # num is greater than right[j-1] and lower
# Time - O(n**4), sum from i = 1 to n of i**3
# Space - O(n**3), n**2 subsequences of length n # return sorted(left + right) is faster than manual merge below
merged = []
class Solution(object): i, j = 0, 0
def findSubsequences(self, nums): while i < len(left) and j < len(right):
""" if left[i] < right[j]:
:type nums: List[int] merged.append(left[i])
:rtype: List[List[int]] i += 1
""" else:
subsequences = set() merged.append(right[j])
j += 1
for num in nums:
new_subsequences = set() return merged + left[i:] + right[j:]
new_subsequences.add((num,))
for s in subsequences: mergesort(nums)
if num >= s[-1]: return self.pairs
new_subsequences.add(s + (num,)) # tuple not list so can store in set

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'

_author_ = 'jake' # https://leetcode.com/problems/target-sum/


_project_ = 'leetcode' # You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols + and -.
# For each integer, you should choose one from + and - as its new symbol.
# https://leetcode.com/problems/construct-the-rectangle/ # Find out how many ways to assign symbols to make sum of integers equal to target S.
# For a web developer, it is very important to know how to design a web page's size.
# So, given a specific rectangular web page’s area, your job by now is to design a rectangular web page, whose # Keep count of frequency of all possible sums that could reach target in dictionary. For each num, increment and
# length L and width W satisfy the following requirements: # decreement all sums, removing those that cannot reach target.
# 1. The area of the rectangular web page you designed must equal to the given target area. # Time - O(2**(n+1))
# 2. The width W should not be larger than the length L, which means L >= W. # Space - O(2**n)
# 3. The difference between length L and width W should be as small as possible.
# You need to output the length L and the width W of the web page you designed in sequence. from collections import defaultdict

# 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

# https://leetcode.com/problems/reverse-pairs/ if S not in sums:


# Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j]. return 0
# You need to return the number of important reverse pairs in the given array. return sums[S]

# 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

timeSeries.append(float("inf")) x, y = self.rects[i - 1][:2]


for i in range(1, len(timeSeries)): return [x + dx, y + dy]
poisoned += min(duration, timeSeries[i] - timeSeries[i- 1])
return poisoned
# python_1_to_1000/498_Diagonal_Traverse.py - m

# python_1_to_1000/496_Next_Greater_Element_I.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/diagonal-traverse/
# Given a matrix of M x N elements (M rows, N columns), return all elements of the matrix in diagonal order as shown
# https://leetcode.com/problems/next-greater-element-i/ # below. Input:
# You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. # [
# Find all the next greater numbers for nums1's elements in the corresponding places of nums2. # [ 1, 2, 3 ],
# The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. # [ 4, 5, 6 ],
# If it does not exist, output -1 for this number. # [ 7, 8, 9 ]
# ]
# Map the integers to be found to their indices in the result. Iterate over nums2, maintaining a stack of nums seen # Output: [1,2,4,7,5,3,6,8,9]
# without a greater number, hence stack is descending. For each num, pop from stack all smaller nums and update the
# result if they are in nums1. Add each num to stack. # Boolan up_right determines direction of travel. Reverse when reach an edge.
# Time - O(n) len(nums2) # Time - O(mn)
# Space - O(m) len(nums1) # Space - O(1)

class Solution(object): class Solution(object):


def nextGreaterElement(self, nums1, nums2): def findDiagonalOrder(self, matrix):
""" """
:type findNums: List[int] :type matrix: List[List[int]]
:type nums: List[int] :rtype: List[int]
:rtype: List[int] """
""" diagonal = []
result = [-1] * len(nums1) # default -1 if not overwritten if not matrix or not matrix[0]:
return diagonal
find_to_i = {} # key is num to be found, value is index
for i, num in enumerate(nums1): rows, cols = len(matrix), len(matrix[0])
find_to_i[num] = i up_right = True
r, c = 0, 0
stack = []
for num in nums2: while len(diagonal) < rows * cols:
while stack and num > stack[-1]: # num is first greater than top of stack
smaller = stack.pop() diagonal.append(matrix[r][c])
if smaller in find_to_i:
result[find_to_i[smaller]] = num if up_right:
stack.append(num) if c == cols - 1: # right edge, move down 1 row
r += 1
return result up_right = False # top edge, move across 1 column
elif r == 0:
c += 1
up_right = False
# python_1_to_1000/497_Random_Point_in_Non-overlapping_Rectangles.py - m else:
r -= 1
_author_ = 'jake' c += 1
_project_ = 'leetcode'
else:
# https://leetcode.com/problems/random-point-in-non-overlapping-rectangles/ if r == rows - 1: # bottom edge, move across 1 column
# Given a list of non-overlapping axis-aligned rectangles rects, write a function pick which randomly and uniformly c += 1
# picks an integer point in the space covered by the rectangles. up_right = True
# An integer point is a point that has integer coordinates. elif c == 0: # left edge, move down 1 row
# A point on the perimeter of a rectangle is included in the space covered by the rectangles. r += 1
# ith rectangle = rects[i] = [x1,y1,x2,y2], where [x1, y1] are the integer coordinates of the bottom-left corner, up_right = True
# and [x2, y2] are the integer coordinates of the top-right corner. else:
r += 1
# Create a list of the cumulative areas of the rectangles. Choose random n in [1, total area] and find the c -= 1
# corresponding rectangle by binary search of the cumulative list. Subtract the areas of all previous rectangles
# to get a point in the rectangle, which is converteed to an x, y coordinate by divide and modulo. return diagonal
# Time - O(n) for __init__, O(log n) for pick
# Space - O(n)
# python_1_to_1000/499_The_Maze_III.py - h
import bisect, random
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'

def __init__(self, rects): # https://leetcode.com/problems/the-maze-iii/


""" # There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up (u),
:type rects: List[List[int]] # down (d), left (l) or right (r), but it won't stop rolling until hitting a wall. When the ball stops, it could choose
""" # the next direction. There is also a hole in this maze. The ball will drop into the hole if it rolls on to the hole.
self.cumul_area = [0] # cumul_area[i] == sum of areas of rects[:i] # Given the ball position, the hole position and the maze, find out how the ball could drop into the hole by moving
self.x_dimensions = [0] # x_dimensions[i] == rects[i - 1][2] - rects[i - 1][0] # the shortest distance. The distance is defined by the number of empty spaces traveled by the ball from the start
self.rects = rects # position (excluded) to the hole (included). Output the moving directions by using 'u', 'd', 'l' and 'r'. Since there
# could be several different shortest ways, you should output the lexicographically smallest way.
for x1, y1, x2, y2 in rects: # If the ball cannot reach the hole, output "impossible".
x_dim, y_dim = x2 - x1 + 1, y2 - y1 + 1
self.x_dimensions.append(x_dim) # Deque stores positions and previous direction. If can move in same direction, add to back of deque. If cannot, try
self.cumul_area.append(self.cumul_area[-1] + x_dim * y_dim) # to move in perpendicular directions by adding to front of deque.
# Time - O(mn)
def pick(self): # Space - O(mn)
"""
:rtype: List[int] from collections import deque
"""
n = random.randint(1, self.cumul_area[-1]) # random n in [1, total area] class Solution(object):
i = bisect.bisect_left(self.cumul_area, n) # index of chosen rectangle def findShortestWay(self, maze, ball, hole):
n -= (self.cumul_area[i - 1] + 1) # point in rectangle """
:type maze: List[List[int]]
dy, dx = divmod(n, self.x_dimensions[i]) # convert n to dx, dy :type ball: List[int]
:type hole: List[int]
:rtype: str _author_ = 'jake'
""" _project_ = 'leetcode'

def maze_cell(r, c): # https://leetcode.com/problems/find-mode-in-binary-search-tree/


if [r, c] == hole: # Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequent elements) in the BST.
return -1 # Assume a BST is defined as follows:
elif 0 <= r < len(maze) and 0 <= c < len(maze[0]) and maze[r][c] == 0: # The left subtree of a node contains only nodes with keys less than or equal to the node's key.
return 0 # The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
return 1 # Both the left and right subtrees must also be binary search trees.

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.

visited = set() # stores tuples (r, c, dirn) class Solution(object):


queue = deque() def findMode(self, root):
dirns = {"d": (1, 0), "u": (-1, 0), "r": (0, 1), "l": (0, -1)} """
for dirn in "dlru": :type root: TreeNode
queue.append((ball[0], ball[1], [dirn])) :rtype: List[int]
"""
while queue: self.prev = float("inf")
r, c, moves = queue.popleft() self.count = 0
if (r, c, moves[-1]) in visited: self.mode_count = 0
continue modes = [] # mutable, not an instance variable
visited.add((r, c, moves[-1]))
def inorder(node):
dr, dc = dirns[moves[-1]]
nm = maze_cell(r + dr, c + dc) if not node: # base case
return
if nm == -1:
return "".join(moves) inorder(node.left) # recurse left

# 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

# python_1_to_1000/501_Find_Mode_in_Binary_Search_Tree.py while k > 0:

# 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

# https://leetcode.com/problems/base-7/ _author_ = 'jake'


# Given an integer, return its base 7 string representation. _project_ = 'leetcode'

# 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

_author_ = 'jake' return result


_project_ = 'leetcode'

# 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)

# https://leetcode.com/problems/perfect-number/ class Solution:


# We define a Perfect Number as a positive integer that is equal to the sum of all its positive divisors except itself. def fib(self, N):
# Now, given an integer n, write a function that returns true when it is a perfect number and false when it is not. """
:type N: int
# Check all divisor integers up to and including sqrt(num). If divisor has no remainder, add divisor and result of :rtype: int
# division. """
# Time - O(n**0.5) i, j = 0, 1
# Space - O(1) for _ in range(N):
i, j = j, i + j
import math
return i
class Solution(object):
def checkPerfectNumber(self, num):
"""
:type num: int # python_1_to_1000/510_Inorder_Successor_in_BST_II.py - m
:rtype: bool
""" _author_ = 'jake'
if num <= 1: # negative, 0 and 1 are not perfect _project_ = 'leetcode'
return False
# https://leetcode.com/problems/inorder-successor-in-bst-ii/
sum_divisors = 1 # Given a binary search tree and a node in it, find the in-order successor of that node in the BST.
# The successor of a node p is the node with the smallest key greater than p.val.
for i in range(2, int(math.sqrt(num)) + 1): # sqrt slightly faster than num**0.5 # You will have direct access to the node but not to the root of the tree.
# Each node will have a reference to its parent node.
div, mod = divmod(num, i)
if mod == 0: # We want to perform the next visit in an inorder traversal from a given starting node. There are 2 cases:
sum_divisors += i + div # 1) If the starting node has a right child we move to the right child then repeatedly moves to the left child.
# When inorder(node.left) returns, there is no left child and we have found the successor.
return sum_divisors == num # 2) Otherwise (no starting node right child) the next node visited is after returning to the parent.
# We move up the tree until we find a node that is the left child of its parent. The parent is then the successor.
# The first case is when the successor is further down the tree and within the subtree rooted at the starting node.
# python_1_to_1000/508_Most_Frequent_Subtree_Sum.py - m # In the second case we must move up the tree.
# Note that there may be no node that is a left child of its parent,
_author_ = 'jake' # in which case we have the last node of the inorder traversal (highest value) which has no successor.
_project_ = 'leetcode'
# Time - O(n)
# https://leetcode.com/problems/most-frequent-subtree-sum/ # Space - O(1)
# Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is defined
# as the sum of all the node values formed by the subtree rooted at that node (including the node itself). So what is class Solution(object):
# the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order. def inorderSuccessor(self, node):
"""
# Bottom-up recursion finding sum for each each subtree and adding to counter. Find max value of counter then find :type node: Node
# all keys with max value. :rtype: Node
# Time - O(n) """
# Space - O(n) if node.right:
node = node.right # move right
from collections import defaultdict while node.left:
node = node.left # then as far left as possible
class Solution(object): return node
def findFrequentTreeSum(self, root):
""" while node.parent and node == node.parent.right:
:type root: TreeNode node = node.parent
:rtype: List[int] return node.parent
"""

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.

_author_ = 'jake' result.append(max_val)


_project_ = 'leetcode' queue = new_queue

# https://leetcode.com/problems/freedom-trail/ return result


# In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a metal dial called the "Freedom
# Trail Ring", and use the dial to spell a specific keyword in order to open the door.
# Given a string ring, which represents the code engraved on the outer ring and another string key, which represents # python_1_to_1000/516_Longest_Palindromic_Subsequence.py - m
# the keyword needs to be spelled. You need to find the minimum number of steps in order to spell all the characters
# in the keyword.
# Initially, the first character of the ring is aligned at 12:00 direction. You need to spell all the characters in _author_ = 'jake'
# the string key one by one by rotating the ring clockwise or anticlockwise to make each character of the string key _project_ = 'leetcode'
# aligned at 12:00 direction and then by pressing the center button.
# At the stage of rotating the ring to spell the key character key[i]: # https://leetcode.com/problems/longest-palindromic-subsequence/
# You can rotate the ring clockwise or anticlockwise one place, which counts as 1 step. The final purpose of the # Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length
# rotation is to align one of the string ring's characters at the 12:00 direction, where this character must equal to # of s is 1000.
# the character key[i].
# If the character key[i] has been aligned at the 12:00 direction, you need to press the center button to spell, which # Dynamic progrmming. Iterate over lengths. If end chars of substring of s of length l starting at index i are same,
# also counts as 1 step. After the pressing, you could begin to spell the next character in the key (next stage), # max length is 2 + max length without end chars. Else take max of leaving off one end char.
# otherwise, you've finished all the spelling. # Time - O(n**2)
# Space - O(n)
# For each char of key, for all indices in ring of this char, calculate the min distance to reach that index from
# every index of previous char. Store min distances to previous char in dictionary. class Solution(object):
# Time - O(k * r**2) where k is length of k and r is length of ring def longestPalindromeSubseq(self, s):
# Space - O(r) """
:type s: str
from collections import defaultdict :rtype: int
"""
class Solution(object): n = len(s)
def findRotateSteps(self, ring, key): if s == s[::-1]: # early return for palindromes
""" return n
:type ring: str
:type key: str subsequence_2 = [0 for _ in range(n)] # subsequences of length - 2 for each starting index
:rtype: int subsequence_1 = [1 for _ in range(n)] # subsequences of length - 1 for each starting index
"""
for length in range(2, n + 1):
def dist(i, j): subsequence = []
return min(abs(i - j), len(ring) - abs(i - j)) for i in range(0, n - length + 1):

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)

from collections import Counter


# python_1_to_1000/520_Detect_Capital.py
class Solution(object):
_author_ = 'jake' def findLUSlength(self, strs):
_project_ = 'leetcode' """
:type strs: List[str]
# https://leetcode.com/problems/detect-capital/ :rtype: int
# Given a word, you need to judge whether the usage of capitals in it is right or not. """
# We define the usage of capitals in a word to be right when one of the following cases holds: def is_subsequence(s, t): # return True if s is a subsequence of t
# All letters in this word are capitals, like "USA". i, j = 0, 0
# All letters in this word are not capitals, like "leetcode". while i < len(s) and j < len(t):
# Only the first letter in this word is capital if it has more than one letter, like "Google". if s[i] == t[j]:
# Otherwise, we define that this word doesn't use capitals in a right way. i += 1

j += 1
if i == len(s): for word in d:
return True if is_subsequence(word, s):
return False return word

counts = Counter(strs) return ""


unique_strs = list(counts.keys())
unique_strs.sort(key=len, reverse=True)
seen = set() # python_1_to_1000/525_Contiguous_Array.py - m

for s in unique_strs: _author_ = 'jake'


_project_ = 'leetcode'
if counts[s] == 1:
if not any([is_subsequence(s, t) for t in seen]):
return len(s) # https://leetcode.com/problems/contiguous-array/
else: # Given a binary array, find the maximum length of a contiguous subarray with equal number of 0 and 1.
seen.add(s)
# Store in dictionary net balance of 1s and 0s for every prefix array. Search for same net balance.
return -1 # Time - O(n)
# Space - O(n)

# python_1_to_1000/523_Continuous_Subarray_Sum.py - m class Solution(object):


def findMaxLength(self, nums):
_author_ = 'jake' """
_project_ = 'leetcode' :type nums: List[int]
:rtype: int
# https://leetcode.com/problems/continuous-subarray-sum/ """
# Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous max_len = 0
# subarray of size at least 2 that sums up to the multiple of k, that is, sums up to n*k where n is also an integer. balance = 0 # net 1s - 0s
balances = {0: -1} # key is balance, value is index
# Subarray is difference between prefix sums a and b. a - b = nk. (a - b) % k = 0 hence a%k - b%k = 0.
# Store prefix sums % k in dictionary. for i, num in enumerate(nums):
# prefix sums % k is zero.
# Time - O(n) if num == 1:
# Space - O(n) balance += 1
else:
class Solution(object): balance -= 1
def checkSubarraySum(self, nums, k):
""" if balance in balances:
:type nums: List[int] max_len = max(max_len, i - balances[balance])
:type k: int else:
:rtype: bool balances[balance] = i
"""
prefix_sum, prefix_sums = 0, {0: -1} # key is prefix sum mod k, value is index in nums return max_len

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)

def make_abbreviation(word, i): class Solution(object):


abbreviation = word[:i + 1] + str(len(word) - (i + 2)) + word[-1] def updateBoard(self, board, click):
return word if len(abbreviation) >= len(word) else abbreviation """
:type board: List[List[str]]
def abbreviate(group, prefix_end): # prefix_end is last char of prefix :type click: List[int]
new_groups = defaultdict(list) :rtype: List[List[str]]
for i in group: """
new_groups[dictionary[i][prefix_end]].append(i) # key is char, value is list of words r, c = click
for new_group in new_groups.values(): rows, cols = len(board), len(board[0])
if len(new_group) == 1:
abbreviations[new_group[0]] = make_abbreviation(dictionary[new_group[0]], prefix_end) for row in range(rows): # convert row string to list of chars
else: board[row] = [col for col in board[row]]
abbreviate(new_group, prefix_end + 1)
if board[r][c] == "M": # return if mine
n = len(dictionary) board[r][c] = "X"
abbreviations = ["" for _ in range(n)] return board

# group words by initial abbreviation def helper(r, c):


groups = defaultdict(list) if board[r][c] == "B": # return unchanged if blank
for i, word in enumerate(dictionary): return
groups[make_abbreviation(word, 0)].append(i)
mines = 0 # count adjacent mines
# iterate over groups for dr in [-1, 0, 1]:
for abbreviation, group in groups.items(): for dc in [-1, 0, 1]:
if len(group) == 1: if dr == dc == 0:
abbreviations[group[0]] = abbreviation continue
else: if 0 <= r + dr < rows and 0 <= c + dc < cols and board[r + dr][c + dc] == "M":
abbreviate(group, 1) mines += 1

return abbreviations if mines != 0: # update with count or blank


board[r][c] = str(mines)
return
# python_1_to_1000/528_Random_Pick_with_Weight.py - m board[r][c] = "B"

_author_ = 'jake' for dr in [-1, 0, 1]: # recurse


_project_ = 'leetcode' for dc in [-1, 0, 1]:
if 0 <= r + dr < rows and 0 <= c + dc < cols:
# https://leetcode.com/problems/random-pick-with-weight/ helper(r + dr, c + dc)
# Given an array w of positive integers, where w[i] describes the weight of index i, write a function pickIndex which
# randomly picks an index in proportion to its weight. helper(r, c)
return board
# Create a list of cumulative weights. Choose a random integer between 1 and the sum of all weights. Binary search the
# cumulative list for the index where the random integer would be inserted and return that index. Probability of
# choosing an index is proprtional to its weight. # python_1_to_1000/530_Minimum_Absolute_Difference_in_BST.py
# Time - O(n log n) for number of weights n
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
import random, bisect
# https://leetcode.com/problems/minimum-absolute-difference-in-bst/
class Solution(object): # Given a binary search tree with non-negative values, find the minimum absolute difference between values of
# any two nodes.
def __init__(self, w):
""" # Inorder traversal, visits nodes in order of ascending value. Track the value of the previous node visited. For each
:type w: List[int] # node update the min_diff with the difference between node.val and prev, if lower than current min_diff.
""" # Time - O(n)
self.cumulative = [] # Space - O(1)
total = 0
for weight in w: class Solution(object):
total += weight def getMinimumDifference(self, root):
self.cumulative.append(total) """
:type root: TreeNode
def pickIndex(self): :rtype: int
""" """
:rtype: int self.min_diff = float("inf")
""" self.prev = float("-inf")
x = random.randint(1, self.cumulative[-1])
return bisect.bisect_left(self.cumulative, x) def inorder(node):

if not node:

return pairs += 1

inorder(node.left) return pairs

self.min_diff = min(self.min_diff, node.val - self.prev)


self.prev = node.val # python_1_to_1000/533_Lonely_Pixel_II.py - m

inorder(node.right) _author_ = 'jake'


_project_ = 'leetcode'
inorder(root)
return self.min_diff # https://leetcode.com/problems/lonely-pixel-ii/
# Given a picture consisting of black and white pixels, and a positive integer N, find the number of black pixels
# located at some specific row R and column C that align with all the following rules:
# python_1_to_1000/531_Lonely_Pixel_I.py - m # Row R and column C both contain exactly N black pixels.
# For all rows that have a black pixel at column C, they should be exactly the same as row R
_author_ = 'jake' # The picture is represented by a 2D char array consisting of 'B' and 'W' pixels.
_project_ = 'leetcode'
# Iterate over picture, for each row that contains N black pixels, increment row_strings counter which maps from a
# https://leetcode.com/problems/lonely-pixel-i/ string
# Given a picture consisting of black and white pixels, find the number of black lonely pixels. # representation of that row to its frequency. Also count black pixels by column.
# The picture is represented by a 2D char array consisting of 'B' and 'W', which means black and white pixels # Then for each row_string with N copies, increment the result by N for each pixel for a column with a count of N.
# respectively. A black lonely pixel is character 'B' that located at a specific position where the same row and same # if a row string does not have N copies then each black pixel either cannot have col_count of N or is not from
# column don't have any other black pixels. # an identical row.
# Time - O(mn)
# Record black pixels in each row and counts by column. Then for each row with 1 pixel, check if that column also # Space - O(mn)
# has 1 pixel.
# Time - O(mn) from collections import defaultdict
# Space - O(mn)
class Solution(object):
class Solution(object): def findBlackPixel(self, picture, N):
def findLonelyPixel(self, picture): """
""" :type picture: List[List[str]]
:type picture: List[List[str]] :type N: int
:rtype: int :rtype: int
""" """
pixels = 0 pixels = 0
rows, cols = len(picture), len(picture[0]) rows, cols = len(picture), len(picture[0])

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

for r in range(rows): for r in range(rows):


for c in range(cols): row_count = 0 # black pixels in this row
if picture[r][c] == "B": for c in range(cols):
col_counts[c] += 1 if picture[r][c] == "B":
row_pixels[r].append(c) col_counts[c] += 1
row_count += 1
for r in range(rows): if row_count == N:
if len(row_pixels[r]) == 1: row_strings["".join(picture[r])] += 1
c = row_pixels[r][0]
if col_counts[c] == 1: for row_string in row_strings:
pixels += 1 if row_strings[row_string] == N: # else not all rows with black pixel in a given col are identical
for i, col in enumerate(row_string):
return pixels if col == "B" and col_counts[i] == N:
pixels += N

return pixels
# python_1_to_1000/532_K-diff_Pairs_in_an_Array.py - m

_author_ = 'jake' # python_1_to_1000/535_Encode_and_Decode_TinyURL.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/k-diff-pairs-in-an-array/ _project_ = 'leetcode'
# Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in the array.
# Here a k-diff pair is defined as an integer pair (i, j), where i and j are both numbers in the array and their # https://leetcode.com/problems/encode-and-decode-tinyurl/
# absolute difference is k. # TinyURL is a URL shortening service where you enter a URL such as https://leetcode.com/problems/design-tinyurl and
# it returns a short URL such as http://tinyurl.com/4e9iAk.
# Count the frequency of each num. If k is zero, count the duplicated nums. Else for each num, add to the result count # Design the encode and decode methods for the TinyURL service. There is no restriction on how your encode/decode
# if num + k is in nums. # algorithm should work. You just need to ensure that a URL can be encoded to a tiny URL and the tiny URL can be
# Time - O(n) # decoded to the original URL.
# Space - O(n)
# Encode as a random selection of 6 letters and digits. If encoding already used, repeat.
from collections import Counter # Time - O(1) average if load factor sufficiently low
# Space - O(nk) for n URLs of max length k
class Solution(object):
def findPairs(self, nums, k): import random
"""
:type nums: List[int] class Codec:
:type k: int letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" # class variable
:rtype: int
""" def __init__(self):
if k < 0: self.map = {} # shortUrl to longUrl
return 0
def encode(self, longUrl):
freq = Counter(nums) """Encodes a URL to a shortened URL.
pairs = 0 :type longUrl: str
:rtype: str
for num in freq: """
if k == 0: encoding = []
if freq[num] > 1: for i in range(6):
pairs += 1 encoding.append(self.letters[random.randint(0, 61)])
else: encoding = "".join(encoding)
if num + k in freq:
if encoding in self.map: # repeat if collision :type a: str
encoding = self.encode(longUrl) :type b: str
:rtype: str
self.map[encoding] = longUrl """
return encoding a_real, a_im = a.split("+")
a_real, a_im = int(a_real), int(a_im[:-1])
def decode(self, shortUrl):
"""Decodes a shortened URL to its original URL. b_real, b_im = b.split("+")
:type shortUrl: str b_real, b_im = int(b_real), int(b_im[:-1])
:rtype: str
""" c_real = a_real * b_real - a_im * b_im
return self.map[shortUrl] c_im = a_real * b_im + a_im * b_real

return str(c_real) + "+" + str(c_im) + "i"


# python_1_to_1000/536_Construct_Binary_Tree_from_String.py - m

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/538_Convert_BST_to_Greater_Tree.py - m

# https://leetcode.com/problems/construct-binary-tree-from-string/ _author_ = 'jake'


# You need to construct a binary tree from a string consisting of parenthesis and integers. _project_ = 'leetcode'
# The whole input represents a binary tree. It contains an integer followed by zero, one or two pairs of parenthesis.
# The integer represents the root value and a pair of parenthesis contains a child binary tree with the same structure. # https://leetcode.com/problems/convert-bst-to-greater-tree/
# You always start to construct the left child node of the parent first if it exists. # Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to
# the original key plus sum of all keys greater than the original key in BST.
# Instance variable i records next char to be processed. Convert root to TreeNode and increment i. If open bracket,
# skip and process left subtree. If another open bracket, skip and process right subtree. Skip closing bracket after # Reverse inorder traversal. Visit right subtree (containing all greater values), update node value and running sum,
# either subtree. # then visit left subtree.
# Time - O(n) # Time - O(n)
# Space - O(1) # Space - O(1)

# Definition for a binary tree node. class Solution(object):


class TreeNode(object): def convertBST(self, root):
def __init__(self, x): """
self.val = x :type root: TreeNode
self.left = None :rtype: TreeNode
self.right = None """
self.running_sum = 0
class Solution(object):
def __init__(self): def inorder(node):
self.i = 0 # index of next char of s to be processed if not node:
return
def str2tree(self, s):
""" inorder(node.right)
:type s: str
:rtype: TreeNode node.val += self.running_sum
""" self.running_sum = node.val

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

class Solution(object): _author_ = 'jake'


def complexNumberMultiply(self, a, b): _project_ = 'leetcode'
"""

# https://leetcode.com/problems/single-element-in-a-sorted-array/ max_dist = max(rows, cols)


# Given a sorted array consisting of only integers where every element appears twice except for one element which for r in range(rows):
# appears once. Find this single element that appears only once. for c in range(cols):
if matrix[r][c] == 1:
# Binary search of even indices. Find first even index whose next number is different or missing. matrix[r][c] = max_dist
# Time - O(log n) else:
# Space - O(1) frontier.append((r, c))

class Solution(object): while frontier:


def singleNonDuplicate(self, nums): r, c = frontier.popleft()
""" for dr, dc in deltas:
:type nums: List[int] if 0 <= r + dr < rows and 0 <= c + dc < cols and matrix[r][c] + 1 < matrix[r + dr][c + dc]:
:rtype: int matrix[r + dr][c + dc] = matrix[r][c] + 1
""" frontier.append((r + dr, c + dc))
left, right = 0, len(nums) - 1 # len(nums) - 1 is always even
return matrix
while left < right:
mid = (left + right) // 2
if mid % 2 == 1: # take lower even index class Solution2(object):
mid -= 1 def updateMatrix(self, matrix):
"""
if mid + 1 == len(nums) or nums[mid + 1] != nums[mid]: :type matrix: List[List[int]]
right = mid :rtype: List[List[int]]
else: """
left = mid + 2 rows, cols = len(matrix), len(matrix[0])
deltas = [(1, 0), (-1, 0), (0, 1), (0, -1)]
return nums[left] unknown = set() # tuples of matrix coordinates where distance to nearest zero is unknown

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)

# python_1_to_1000/542_01_Matrix.py - m class Solution(object):


def diameterOfBinaryTree(self, root):
_author_ = 'jake' """
_project_ = 'leetcode' :type root: TreeNode
:rtype: int
# https://leetcode.com/problems/01-matrix/ """
# Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell. self.result = 0
# The distance between two adjacent cells is 1.
def helper(node): # return longest downwards path
# Queue of cells with known distances, initially 0 cells. 1 cells are set max possible distance. For each cell in\ if not node:
# frontier, reduce distance of all neighbours to 1 + frontier distance and add neighbours back to queue. return -1 # so leaf returns zero
# Alternatively maintain set of cells with unknown distances. If any cell with unknown distance is next to a known left = helper(node.left)
# cell then set distance. May iterate over unknowns many times but faset in practice. right = helper(node.right)
# Time - O(mn) self.result = max(self.result, 2 + left + right)
# Space - O(mn) return max(1 + left, 1 + right)

from collections import deque helper(root) # ignore return value


return self.result
class Solution(object):
def updateMatrix(self, matrix):
""" # python_1_to_1000/544_Output_Contest_Matches.py - m
:type matrix: List[List[int]]
:rtype: List[List[int]] _author_ = 'jake'
""" _project_ = 'leetcode'
rows, cols = len(matrix), len(matrix[0])
deltas = [(1, 0), (-1, 0), (0, 1), (0, -1)] # https://leetcode.com/problems/output-contest-matches/
frontier = deque() # tuples of matrix coordinates # During the NBA playoffs, we always arrange the rather strong team to play with the rather weak team, like make the
# rank 1 team play with the rank nth team, which is a good strategy to make the contest more interesting. Now, you're
# given n teams, you need to output their final contest matches in the form of a string. return boundary + right_edge[::-1]
# The n teams are given in the form of positive integers from 1 to n, which represents their initial rank. (Rank 1 is
# the strongest team and Rank n is the weakest team.) We'll use parentheses('(', ')') and commas(',') to represent the
# contest team pairing - parentheses('(' , ')') for pairing and commas(',') for partition. During the pairing process # python_1_to_1000/546_Remove_Boxes.py - h
# in each round, you always need to follow the strategy of making the rather strong one pair with the rather weak one.
_author_ = 'jake'
# Create list of strings of all teams. While length of list > 1, iterate over list pairing first and last teams/matches _project_ = 'leetcode'
# (with brackets and comma to make new string) until middle.
# Time - O(n log n), final result is of length O(n log n) since each loop multiplies total string length by 2.5 times. # https://leetcode.com/problems/remove-boxes/
# Space - O(n) # Given several boxes with different colors represented by different positive numbers.
# You may experience several rounds to remove boxes until there is no box left. Each time you can choose some continuous
class Solution(object): # boxes with the same color (composed of k boxes, k >= 1), remove them and get k*k points.
def findContestMatch(self, n): # Find the maximum points you can get.
"""
:type n: int # Dynamic programming. Consider subarray from boxes[left:right+1] with same boxes of same colour as boxes[right] in a
:rtype: str # continuous subarray to the right of boxes[right]. Best score is either a) removing right and all same boxes, then
""" # best score form remaining subarray with no same, or b) is any box in subarray is same as boxes[right] then get best
result = [str(i) for i in range(1, n + 1)] # score from the subarray between this box and right, plus best score from left part of bubarray with same + 1.
# Time - O(n**3)
while len(result) > 1: # Space - O(n**3)
new_result = []
for i in range(len(result) // 2): class Solution(object):
new_result.append("(" + result[i] + "," + result[len(result) - i - 1] + ")") def removeBoxes(self, boxes):
result = new_result """
:type boxes: List[int]
return result[0] :rtype: int
"""

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):

for j in range(i): # iterate over lower triangle of M


if M[i][j] == 1: # Helper return longest increasing and decreasing paths from a node. Update longest increasing and decreasing paths
group[get_group(i)] = get_group(j) # set exemplar of i's group to exemplar of j's group # according to whether children exist and their values are +/-1 of node.val. Update longest path without double-
# counting node.
return len(set(get_group(i) for i in range(n))) # Time - O(n)
# Space - O(1)
class Solution2(object):
def findCircleNum(self, M): class Solution(object):
""" def longestConsecutive(self, root):
:type M: List[List[int]] """
:rtype: int :type root: TreeNode
""" :rtype: int
"""
def dfs(i): self.longest = 0 # instance variable to store longest path length
for j in range(len(M)):
if M[i][j] == 1: def helper(node): # return tuple (longest increasing, longest decreasing) (including node)
if j not in seen: if not node:
seen.add(j) return 0, 0
dfs(j)
l_i, l_d = helper(node.left)
circles = 0 r_i, r_d = helper(node.right)
seen = set()
incr, decr = 1, 1 # leaf node
for i in range(len(M)):
if i not in seen: if node.left:
circles += 1 if node.left.val == node.val + 1: # increasing path
dfs(i) incr = 1 + l_i
elif node.left.val == node.val - 1: # decreasing path
return circles decr = 1 + l_d

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

# https://leetcode.com/problems/split-array-with-equal-sum/ self.longest = max(self.longest, incr + decr - 1) # -1 so as to not double count node


# Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies following conditions:
# 0 < i, i + 1 < j, j + 1 < k < n - 1 return incr, decr
# Sum of subarrays (0, i - 1), (i + 1, j - 1), (j + 1, k - 1) and (k + 1, n - 1) should be equal.
# where we define that subarray (L, R) represents a slice of the original array starting from the element indexed L to helper(root)
# the element indexed R return self.longest

# 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'

class Solution(object): # https://leetcode.com/problems/student-attendance-record-i/


def splitArray(self, nums): # You are given a string representing an attendance record for a student.
""" # The record only contains the following three characters:
:type nums: List[int] # 'A' : Absent.
:rtype: bool # 'L' : Late.
""" # 'P' : Present.
n = len(nums) # A student could be rewarded if his attendance record doesn't contain more than one 'A' (absent) or more than
if n < 7: # two continuous 'L' (late).
return False # You need to return whether the student could be rewarded according to his attendance record.

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)

for j in range(3, n - 3): # possible value of middle index class Solution(object):


candidates = set() def checkRecord(self, s):
"""
for i in range(1, j - 1): :type s: str
left_sum = cumul[i - 1] :rtype: bool
right_sum = cumul[j - 1] - cumul[i] """
if left_sum == right_sum: return s.count("A") < 2 and "LLL" not in s
candidates.add(left_sum)

for k in range(j + 2, n - 1): # python_1_to_1000/552_Student_Attendance_Record_II.py - h


left_sum = cumul[k - 1] - cumul[j]
right_sum = cumul[n - 1] - cumul[k] _author_ = 'jake'
if left_sum == right_sum and left_sum in candidates: _project_ = 'leetcode'
return True
# https://leetcode.com/problems/student-attendance-record-ii/
return False # Given a positive integer n, return the number of all possible attendance records with length n, which will be
# regarded as rewardable. The answer may be very large, return it after mod 10**9 + 7.
# A student attendance record is a string that only contains the following three characters:
# 'A' : Absent.
# 'L' : Late.
# python_1_to_1000/549_Binary_Tree_Longest_Consecutive_Sequence_II.py - m # 'P' : Present.
# A record is regarded as rewardable if it doesn't contain more than one 'A' (absent) or more than two
_author_ = 'jake' # continuous 'L' (late).
_project_ = 'leetcode'
# Ignoring 'A', find the number of rewardable records for records of lengths up to n with dynamic programming. Modulo
# https://leetcode.com/problems/binary-tree-longest-consecutive-sequence-ii/ # all additions. Final result is case of no 'A' or an 'A' in any position.
# Given a binary tree, you need to find the length of Longest Consecutive Path in Binary Tree. # Time - O(n)
# Especially, this path can be either increasing or decreasing. For example, [1,2,3,4] and [4,3,2,1] are both considered # Space - O(n)
# valid, but the path [1,2,4,3] is not valid. On the other hand, the path can be in the child-Parent-child order, where
# not necessarily be parent-child order. class Solution(object):
def checkRecord(self, n): edge = 0
"""
:type n: int for brick in row:
:rtype: int edge += brick
""" edges[edge] += 1
BASE = 10 ** 9 + 7
records = [1, 2] # rewardable records of lengths 0 and 1 del edges[sum(wall[0])] # delete RHS vertical edge
zero, one, two = 1, 1, 0 # rewardable records ending in zero, one or two 'L'
crossed = len(wall) # cross all brick if no edges, else choose path with most edges
# new zero formed from previous zero, one and two + 'P' return crossed if not edges else crossed - max(edges.values())
# new one formed form previous zero + 'L'
# new two formed form previous one + 'L'
for _ in range(2, n + 1): # python_1_to_1000/555_Split_Concetenated_Strings.py - m
zero, one, two = (zero + one + two) % BASE, zero, one
records.append((zero + one + two) % BASE) # all possible numbers of 'L' _author_ = 'jake'
_project_ = 'leetcode'
# if A not present
result = records[-1] # https://leetcode.com/problems/split-concatenated-strings/
# Given a list of strings, you could concatenate these strings together into a loop, where for each string you could
# for each position of A # choose to reverse it or not. Among all the possible loops, you need to find the lexicographically biggest string
for i in range(n): # after cutting the loop, which will make the looped string into a regular one.
result += records[i] * records[n - 1 - i] # records on LHS of 'A' * records on RHS # Specifically, to find the lexicographically biggest string, you need to experience two phases:
result %= BASE # Concatenate all the strings into a loop, where you can reverse some strings or not and connect them in the same order
as given.
return result # Cut and make one breakpoint in any place of the loop, which will make the looped string into a regular one starting
from the character at the cutpoint.
# And your job is to find the lexicographically biggest one among all the possible regular strings.
# python_1_to_1000/553_Optimal_Division.py - m
# For each split point of each string and each reversed string, build the loop where each other string is oriented to
_author_ = 'jake' # its highest value.
_project_ = 'leetcode' # Time - O(n**2) for n total chars.
# Space - O(n)
# https://leetcode.com/problems/optimal-division/
# Given a list of positive integers, the adjacent integers will perform the float division. class Solution(object):
# For example, [2,3,4] -> 2 / 3 / 4. def splitLoopedString(self, strs):
# However, you can add any number of parenthesis at any position to change the priority of operations. You should """
# find out how to add parenthesis to get the maximum result, and return the corresponding expression in string format. :type strs: List[str]
# Your expression should NOT contain redundant parenthesis. :rtype: str
"""
# First number is always numerator, second number is always denominator. Subsequent numbers should all be in result = None
# numerator (since all >= 1). This is achieved by bracketing all other numbers together. best = [max(s, s[::-1]) for s in strs]
# Time - O(n)
# Space - O(n) for i, s in enumerate(strs):
t = s[::-1]
class Solution(object): for j in range(len(s)):
def optimalDivision(self, nums): test = s[j:] + "".join(best[i + 1:] + best[:i]) + s[:j]
""" test2 = t[j:] + "".join(best[i + 1:] + best[:i]) + t[:j]
:type nums: List[int] result = max(result, test, test2)
:rtype: str
""" return result
nums = [str(s) for s in nums]
result = nums[0]
# python_1_to_1000/556_Next_Greater_Element_III.py - m
if len(nums) == 1:
return result _author_ = 'jake'
if len(nums) == 2: _project_ = 'leetcode'
return result + "/" + nums[1]
# https://leetcode.com/problems/next-greater-element-iii/
return result + "/(" + "/".join(nums[1:]) + ")" # Given a positive 32-bit integer n, you need to find the smallest 32-bit integer which has exactly the same
# digits existing in the integer n and is greater in value than n. If no such positive 32-bit integer exists,
# you need to return -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

for row in wall:

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

# python_1_to_1000/558_Quad_Tree_Intersection.py - m class Solution(object):


def subarraySum(self, nums, k):
_author_ = 'jake' """
_project_ = 'leetcode' :type nums: List[int]
:type k: int
# https://leetcode.com/problems/quad-tree-intersection/ :rtype: int
# A quadtree is a tree data in which each internal node has exactly four children: topLeft, topRight, bottomLeft """
# and bottomRight. Quad trees are often used to partition a two-dimensional space by recursively subdividing it into total = 0
# four quadrants or regions. sums = defaultdict(int) # key is prefix sum, value is count of number of prefixes
# We want to store True/False information in our quad tree. running_sum = 0
# The quad tree is used to represent a N * N boolean grid. For each node, it will be subdivided into four children
# nodes until the values in the region it represents are all the same. Each node has another two boolean for num in nums:
# attributes : isLeaf and val. isLeaf is true if and only if the node is a leaf node.
# The val attribute for a leaf node contains the value of the region it represents. running_sum += num

# 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

class Solution(object): return total


def intersect(self, quadTree1, quadTree2):
"""
:type quadTree1: Node # python_1_to_1000/561_Array_Partition_I.py
:type quadTree2: Node
:rtype: Node _author_ = 'jake'
""" _project_ = 'leetcode'
if quadTree1.isLeaf:
return quadTree1 if quadTree1.val else quadTree2 # https://leetcode.com/problems/array-partition-i/
if quadTree2.isLeaf: # Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1, b1), (a2, b2),
return quadTree2 if quadTree2.val else quadTree1 # ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible.

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

class Solution(object): class Solution(object):


def maxDepth(self, root): def longestLine(self, M):
""" """
:type root: Node :type M: List[List[int]]
:rtype: int :rtype: int
""" """
if not root: if not M or not M[0]:
return 0 # Time - O(n)
# Space - O(n)
rows, cols = len(M), len(M[0])
max_len = 0 class Solution(object):
def nearestPalindromic(self, n):
# row_dp[i] is a list of be longest line ending at column i on the current row """
# for horizontal, vertical, descending and ascending diagonal lines :type n: str
previous_dp = [[0 for _ in range(4)] for c in range(cols)] :rtype: str
"""
for r in range(rows): digits = len(n)
row_dp = [] candidates = {int("1" + "0" * (digits - 1) + "1")} # longer length e.g. 88 -> 101
if len(n) > 1:
for c in range(cols): candidates.add(int("9" * (digits - 1))) # shorter length e.g. 12 -> 9

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

# python_1_to_1000/564_Find_the_Closest_Palindrome.py - h current = set() # start a new set


while num not in current:
_author_ = 'jake' current.add(num) # add num
_project_ = 'leetcode' num = nums[num] # move to next num

# https://leetcode.com/problems/find-the-closest-palindrome/ longest = max(longest, len(current))


# Given an integer n, find the closest integer (not including itself), which is a palindrome. if longest >= len(nums) - i - 1: # early return
# The 'closest' is defined as absolute difference minimized between two integers. break
# The input n is a positive integer represented by string, whose length will not exceed 18.
# If there is a tie, return the smaller one as answer. visited |= current # add all of current to visited

# There are 5 possible candidates. return longest


# 1) A number 1 digit shorter than n of all 9s
# 2) A number 1 digit longer than n ending and starting in 1 with all other zeros
# 3) Reversed LHS replacing RHS and middle digit(s) same
# 4) as 3) but middle index incremented # python_1_to_1000/566_Reshape_the_Matrix.py
# 5) as 3) but middle index decremented
# Make all candidates that exist (care of single digit n, 0 and 9 in middle. If length is odd them middle is a _author_ = 'jake'
# single digit, else it is a pair. _project_ = 'leetcode'
# Find closest of candidates or lower if tie.

# https://leetcode.com/problems/reshape-the-matrix/ # city j, flights[i][j] = 0; Otherwise, flights[i][j] = 1. Also, flights[i][i] = 0 for all i.


# In MATLAB, there is a very useful function called 'reshape', which can reshape a matrix into a new one with different # You totally have K weeks (each week has 7 days) to travel. You can only take flights at most once per day and can
# size but keep its original data. # only take flights on each week's Monday morning. Since flight time is so short, we don't consider the impact of
# You're given a matrix represented by a two-dimensional array, and two positive integers r and c representing the # flight time.
# row number and column number of the wanted reshaped matrix, respectively. # For each city, you can only have restricted vacation days in different weeks, given an N*K matrix called days
# The reshaped matrix need to be filled with all the elements of the original matrix in the same row-traversing order # representing this relationship. For the value of days[i][j], it represents the maximum days you could take vacation
# as they were. If the 'reshape' operation with given parameters is possible and legal, output the new reshaped matrix. # in the city i in the week j.
# Otherwise, output the original matrix. # You're given the flights matrix and days matrix, and you need to output the maximum vacation days you could take
# during K weeks.
# Iterate over nums, appending elements to reshape and starting new rows when full.
# Time - O(mn) # Dynamic programming. List stores max vacation days per city starting with the previous week, initally all zero.
# Space - O(mn) # For each week starting from the last and working forward, calculate the max vacation for each city as a) vacation
# from staying in that city and b) for each city with flight, vacation from flying to that city
class Solution(object): # Time - O(n**2 * w) cities * weeks
def matrixReshape(self, nums, r, c): # Space - O(n) number of cities
"""
:type nums: List[List[int]] class Solution(object):
:type r: int def maxVacationDays(self, flights, days):
:type c: int """
:rtype: List[List[int]] :type flights: List[List[int]]
""" :type days: List[List[int]]
rows, cols = len(nums), len(nums[0]) :rtype: int
if rows * cols != r * c: # return if different number of elements """
return nums cities = len(flights)
weeks = len(days[0])
reshaped = [[]] if not cities or not weeks:
return 0
for i in range(rows):
for j in range(cols): prev_week_max_days = [0 for _ in range(cities)]

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

for end in range(cities):


# python_1_to_1000/567_Permutation_in_String.py - m if flights[start][end]: # try all cities with flights
max_vacation = max(max_vacation, days[end][week] + prev_week_max_days[end])
_author_ = 'jake'
_project_ = 'leetcode' this_week_max_days[start] = max_vacation
prev_week_max_days = this_week_max_days
# https://leetcode.com/problems/permutation-in-string/
# Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. return this_week_max_days[0]
# In other words, one of the first string's permutations is the substring of the second string.
# The input strings only contain lower case letters.
# python_1_to_1000/572_Subtree_of_Another_Tree.py
# Count frequencies of letters in s1 in an array. Slide window of length len(s1) over s2. Array maintains balance of
# counts in s1 - counts in window. _author_ = 'jake'
# Time - O(m + n), sum of string lengths _project_ = 'leetcode'
# Space - O(1)
# https://leetcode.com/problems/subtree-of-another-tree/
class Solution(object): # Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a
def checkInclusion(self, s1, s2): # subtree of s. A subtree of s is a tree consists of a node in s and all of this node's descendants.
""" # The tree s could also be considered as a subtree of itself.
:type s1: str
:type s2: str # Preorder traversal over s and t to serialize. Nodes are separated by commas (e.g. to distinguish 1 and 0 from 10).
:rtype: bool # None nodes are identified with special symbol '#'. Check whether serialization of t is contained in s.
""" # Time - O(m + n)
n1 = len(s1) # Space - O(m + n)
freq = [0] * 26 # counts of each char
class Solution(object):
for c in s1: def isSubtree(self, s, t):
freq[ord(c) - ord("a")] += 1 """
:type s: TreeNode
for i, c in enumerate(s2): :type t: TreeNode
:rtype: bool
freq[ord(c) - ord("a")] -= 1 # decrement count of letter added to window """
if i >= n1: def serialize(node):
freq[ord(s2[i - n1]) - ord("a")] += 1 # increment count of letter exiting window if not node:
serial.append("#")
if not any(freq): return
return True serial.append(",")
serial.append(str(node.val))
return False serialize(node.left)
serialize(node.right)

# python_1_to_1000/568_Maximum_Vacation_Days.py - h serial = [] # list so append each symbol in O(1)


serialize(s)
_author_ = 'jake' s_serial = "".join(serial)
_project_ = 'leetcode' serial = []
serialize(t)
# https://leetcode.com/problems/maximum-vacation-days/ t_serial = "".join(serial)
# LeetCode wants to give one of its best employees the option to travel among N cities to collect algorithm problems.
# But all work and no play makes Jack a dull boy, you could take vacations in some particular cities and weeks. Your return t_serial in s_serial
# job is to schedule the traveling to maximize the number of vacation days you could take, but there are certain
# rules and restrictions you need to follow.
# python_1_to_1000/573_Squirrel_Simulation.py - m
# Rules and restrictions:
# You can only travel among N cities, represented by indexes from 0 to N-1. Initially, you are in the city _author_ = 'jake'
# indexed 0 on Monday. _project_ = 'leetcode'
# The cities are connected by flights. The flights are represented as a N*N matrix (not necessary symmetrical), called
# flights representing the airline status from the city i to the city j. If there is no flight from the city i to the # https://leetcode.com/problems/squirrel-simulation/
# There's a tree, a squirrel, and several nuts. Positions are represented by the cells in a 2D grid. Your goal is to paths = 0
# find the minimal distance for the squirrel to collect all the nuts and put them under the tree one by one. The dp = [[0 for _ in range(n)] for _ in range(m)] # nb paths to reach each cell
# squirrel can only take at most one nut at one time and can move in four directions - up, down, left and right, to dp[i][j] = 1 # intially 1 for start position
# the adjacent cell. The distance is represented by the number of moves.
for _ in range(N):
# The only choice to make is which nut to collect first. The distance for all other nuts is from the tree to the nut
# and back. For each starting nut, calculate the change in distance by going from squirrel to nut and not from new_dp = [[0 for _ in range(n)] for _ in range(m)]
# tree to nut. Add the greatest reduction in distance to the round-trips for all nuts.
# Time - O(n) number of nuts for r in range(m):
# Space - O(1) for c in range(n):

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

for nut in nuts:


nut_to_tree = distance(nut, tree)
squirrel_to_nut = distance(squirrel, nut) class Solution2(object):
nuts_to_tree += nut_to_tree def findPaths(self, m, n, N, i, j):
best_gain = min(best_gain, squirrel_to_nut - nut_to_tree)
def helper(r, c, steps):
return 2 * nuts_to_tree + best_gain
if steps == 0:
return 0

if (r, c, steps) in memo:


# python_1_to_1000/575_Distribute_Candies.py return memo[(r, c, steps)]

_author_ = 'jake' paths = 0


_project_ = 'leetcode' for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
if 0 <= r + dr < m and 0 <= c + dc < n:
# https://leetcode.com/problems/distribute-candies/ paths += helper(r + dr, c + dc, steps - 1)
# Given an integer array with even length, where different numbers in this array represent different kinds of candies. else:
# Each number means one candy of the corresponding kind. You need to distribute these candies equally in number to paths += 1 # one path to exit grid
# brother and sister. Return the maximum number of kinds of candies the sister could gain. paths %= 10 ** 9 + 7

# 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])

for j in range(1, len(word2) + 1): # length of word2 prefix


if left == -1: # still default, list already sorted if word1[i - 1] == word2[j - 1]:
return 0 dp.append(1 + prev_dp[j - 1])
else:
for i in range(n - 2, -1, -1): dp.append(max(dp[-1], prev_dp[j]))
if right == -1 and nums[i] > nums[i + 1]:
right = i + 1 # last index to be sorted prev_dp = dp
max_num = nums[i]
elif right != -1: # update subsequent maximum return prev_dp[-1]
max_num = max(max_num, nums[i])
return len(word1) + len(word2) - 2 * LCS(word1, word2)
while left > 0 and nums[left - 1] > min_num: # nums[left - 1] requires sorting
left -= 1
while right < n - 1 and nums[right + 1] < max_num: # nums[right + 1] requires sorting # python_1_to_1000/587_Erect_The_Fence.py - h
right += 1
_author_ = 'jake'
return right - left + 1 _project_ = 'leetcode'

# 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]]

# python_1_to_1000/583_Delete_Operation_for_Two_Strings.py - m for point in points[1:]:


while cross_product(point) < 0:
_author_ = 'jake' result.pop()
_project_ = 'leetcode' result.append(point)

# https://leetcode.com/problems/delete-operation-for-two-strings/ return result


# Given two words word1 and word2, find the minimum number of steps required to make word1 and word2 the same, where
# in each step you can delete one character in either string.

# 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'

class Solution(object): # https://leetcode.com/problems/design-in-memory-file-system/


def minDistance(self, word1, word2): # Design an in-memory file system to simulate the following functions:
""" # ls: Given a path in string format. If it is a file path, return a list that only contains this file's name. If it is
:type word1: str # a directory path, return the list of file and directory names in this directory. Your output (file and directory
:type word2: str # names together) should in lexicographic order.
:rtype: int # mkdir: Given a directory path that does not exist, you should make a new directory according to the path. If the
""" # middle directories in the path don't exist either, you should create them as well. This function has void return type.
def LCS(s, t): # addContentToFile: Given a file path and file content in string format. If the file doesn't exist, you need to create
prev_dp = [0 for _ in range(len(word2) + 1)] # that file containing given content. If the file already exists, you need to append given content to original content.
# This function has void return type.
for i in range(1, len(word1) + 1): # length of word1 prefix # readContentFromFile: Given a file path, return its content in string format.
dp = [0]
# Define a Folder as a mapping from names of files/folders to other Folders or None (for files). File system consists
# of root folder and mapping from file names to their contents. Separate file mapping speeds content retrieval/update. result = []
# Time - O(1) for constructor. O(s + n + m log m) for ls where s = path number of chars, n = number of folders in
# path, m = number of results in final folder. O(s + n) for mkdir. O(s + n + t) for addContentToFile where t is while stack:
# total content. O(t) for readContentFromFile.
# Space - O(total nb folders + total content length) node = stack.pop()
result.append(node.val)
class Folder(object):
def __init__(self): for child in reversed(node.children):
self.children = {} # map from child names to Folders or None stack.append(child)

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)

class Solution(object): class Solution(object):


def preorder(self, root): def isValid(self, code):
""" """
:type root: Node :type code: str
:rtype: List[int] :rtype: bool
""" """
if not root: status = "text"
return [] tag_stack = []
upper = set("ABCDEFGHIJKLMNOPQRSTUVWXYZ") # chars allowed in tags
stack = [root] i = 0

lcm = fraction[1] * result[1] // GCD(fraction[1], result[1])


while i < len(code):
c = code[i] result = [(result[0] * lcm // result[1]) + (fraction[0] * lcm // fraction[1]), lcm]
start = end + 1
if status == "text":
if c == "<": if result[0] == 0:
if i + 1 < len(code) and code[i + 1] == "/": return "0/1"
status = "closing"
i += 2 gcd = GCD(result[0], result[1])
tag_start = i # record starting index in oreedr to check length return str(result[0] // gcd) + "/" + str(result[1] // gcd)
elif i + 8 < len(code) and code[i + 1:i + 9] == "![CDATA[" and tag_stack: # must have opened a tag
status = "cdata"
i += 9 # python_1_to_1000/593_Valid_Square.py - m
else:
status = "opening" _author_ = 'jake'
i += 1 _project_ = 'leetcode'
tag_start = i
elif not tag_stack: # must have opened a tag # https://leetcode.com/problems/valid-square/
return False # Given the coordinates of four points in 2D space, return whether the four points could construct a square.
else: # The coordinate (x,y) of a point is represented by an integer array with two integers.
i += 1
# Calculate the squared distance from each point to each other point. A square has 4 sides of the same distance and 2
elif status in ["opening", "closing"]: # diagonals of twice the squared distance of the sides.
if code[i] == ">": # Time - O(1)
tag = code[tag_start:i] # Space - O(1)
if len(tag) < 1 or len(tag) > 9:
return False class Solution(object):
if status == "opening": def validSquare(self, p1, p2, p3, p4):
tag_stack.append(tag) """
else: :type p1: List[int]
if not tag_stack or tag_stack.pop() != tag: :type p2: List[int]
return False :type p3: List[int]
if not tag_stack and i != len(code) - 1: # cannot close all tags if not at end of code :type p4: List[int]
return False :rtype: bool
status = "text" """
elif c not in upper: def square_dist(a, b):
return False return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
i += 1
points = [p1, p2, p3, p4]
elif status == "cdata": square_dists = [square_dist(points[i], points[j]) for i in range(4) for j in range(i + 1, 4)]
if i + 2 < len(code) and code[i:i + 3] == "]]>":
i += 3 side = min(square_dists)
status = "text" if max(square_dists) != 2 * side:
else: return False
i += 1
return square_dists.count(side) == 2 * square_dists.count(2 * side)
return status == "text" and not tag_stack

# python_1_to_1000/594_Longest_Harmonious_Subsequence.py

# python_1_to_1000/592_Fraction_Addition_And_Subtraction.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/longest-harmonious-subsequence/
# We define a harmonious array is an array where the difference between its maximum value and its minimum value
# https://leetcode.com/problems/fraction-addition-and-subtraction/ # is exactly 1. Given an integer array, you need to find the length of its longest harmonious subsequence among all
# Given a string representing an expression of fraction addition and subtraction, you need to return the calculation # its possible subsequences.
# result in string format. The final result should be irreducible fraction. If your final result is an integer, say 2,
# you need to change it to the format of fraction that has denominator 1. So in this case, 2 should be converted to 2/1. # Count the frequency of each num in nums. For each num we create a subsequence of that num and num + 1. If num + 1 is
# not in nums then no subsequence can be created. Else update max_harmonious according to counts of num and num + 1.
# Parse the expression into integers, delimited by "/" for numerator and "+" or "-" for denominator. For each fraction, # Time - O(n)
# find the lowest common multiple of the fraction denominator and the current result denominator. Convert both # Space - O(n)
# fractions to this denominator and add their numerators to update the result. Repeat for all fractions.
# Divide the result by the lowest common multiple of its numerator and denominator. from collections import Counter
# Time - O(n log m) there n is number of fractions and m is hte maximum numerator or denominator
# Space - O(1) class Solution(object):
def findLHS(self, nums):
class Solution(object): """
def fractionAddition(self, expression): :type nums: List[int]
""" :rtype: int
:type expression: str """
:rtype: str freq = Counter(nums)
""" max_harmonious = 0
def GCD(a, b): # Euclid's algortihm for greatest common divisor
div, mod = divmod(a, b) for num, count in freq.items():
if mod == 0: if num + 1 in freq: # difference must be exactly one, not zero
return b max_harmonious = max(max_harmonious, count + freq[num + 1])
return GCD(b, mod)
return max_harmonious
result = [0, 1] # list of numerator and denominator
start = 0

while start < len(expression): # python_1_to_1000/598_Range_Addition_II.py


end = start
while expression[end + 1] != "/": _author_ = 'jake'
end += 1 _project_ = 'leetcode'
fraction = [int(expression[start:end + 1])]
# https://leetcode.com/problems/range-addition-ii/
start = end = end + 2 # Given an m * n matrix M initialized with all 0's and several update operations.
while end + 1 < len(expression) and expression[end + 1] not in ["+", "-"]: # Operations are represented by a 2D array, and each operation is represented by an array with two positive
end += 1 # integers a and b, which means M[i][j] should be added by one for all 0 <= i < a and 0 <= j < b.
fraction.append(int(expression[start:end + 1])) # You need to count and return the number of maximum integers in the matrix after performing all the operations.
# Track the row and column edges of the part of the matrix containing the max integer. For each operation, update def findIntegers(self, num):
# the row and column edges according to the minimum of the current values and the row and columns of the operation. """
# Time - O(n) :type num: int
# Space - O(1) :rtype: int
"""
class Solution(object): # remove "0b" prefix and reverse so least significant bit has lowest index
def maxCount(self, m, n, ops): binary = bin(num)[2:][::-1]
"""
:type m: int # zero_highest[i] is the number of non-negative integers with i + 1 bits and highest bit of zero
:type n: int # that do not contain consecutive set bits. Note that zero_highest[i - 1] overlaps with and is a
:type ops: List[List[int]] # subset of zero_highest[i]
:rtype: int zero_highest = [1]
""" one_highest = [1]
max_r, max_c = m, n # initially whole matrix contains max integer
if binary[0] == "0":
for r, c in ops: count = 1
max_r = min(max_r, r) else:
max_c = min(max_c, c) count = 2

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

class Solution(object): return count


def findRestaurant(self, list1, list2):
"""
:type list1: List[str] # python_1_to_1000/604_Design_Compressed_String_Iterator.py
:type list2: List[str]
:rtype: List[str] _author_ = 'jake'
""" _project_ = 'leetcode'
if len(list1) > len(list2): # swap to make list1 shorter
list1, list2 = list2, list1 # https://leetcode.com/problems/design-compressed-string-iterator/
# Design and implement a data structure for a compressed string iterator.
dict1 = {rest: i for i, rest in enumerate(list1)} # It should support the following operations: next and hasNext.
# The given compressed string will be in the form of each letter followed by a positive integer representing the
result = [] # number of this letter existing in the original uncompressed string.
min_sum = float("inf") # next() - if the original string still has uncompressed characters, return the next letter; Otherwise return a space.
# hasNext() - Judge whether there is any letter needs to be uncompressed.
for i, rest in enumerate(list2):
# Serve the next letter on demand. Maintain the current letter and count of how many remaining unused instances.
if i > min_sum: # subsequent list2 entries cannot improve # Also maintain index of next letter in compressedString.
break # Time - O(n) for next, O(1) for init and hasNext.
# Space - O(1)
if rest not in dict1:
continue class StringIterator(object):

sum_i = i + dict1[rest] def __init__(self, compressedString):


"""
if sum_i < min_sum: # new best :type compressedString: str
min_sum = sum_i """
result = [rest] self.letter = None
elif sum_i == min_sum: # tie with current best self.count = 0 # number of current letter remaining
result.append(rest) self.i = 0 # index of next letter after current is used
self.s = compressedString
return result
def next(self):
"""
# python_1_to_1000/600_Non-negative_Integers_without_Consecutive_Ones.py - h :rtype: str
"""
_author_ = 'jake' if not self.hasNext():
_project_ = 'leetcode' return " "

# 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' # python_1_to_1000/609_Find_Duplicate_File_in_System.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/can-place-flowers/ _project_ = 'leetcode'
# Suppose you have a long flowerbed in which some of the plots are planted and some are not.
# However, flowers cannot be planted in adjacent plots - they would compete for water and both would die. # https://leetcode.com/problems/find-duplicate-file-in-system/
# Given a flowerbed (represented as an array containing 0 and 1, where 0 means empty and 1 means not empty), # Given a list of directory info including directory path, and all the files with contents in this directory, you
# and a number n, return if n new flowers can be planted in it without violating the no-adjacent-flowers rule. # need to find out all the groups of duplicate files in the file system in terms of their paths.
# A group of duplicate files consists of at least two files that have exactly the same content.
# Iterate over flowerbed. Check for flowers at i + 1, i and i - 1 in that order. If flower found, jump to next # A single directory info string in the input list has the following format:
# possible empty index. Else plant flower (decrement count, no need to amend flowerbed) and jump 2 indices. # "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)"
# Time - O(n) # It means there are n files (f1.txt, f2.txt ... fn.txt with content f1_content, f2_content ... fn_content,
# Space - O(1) # respectively) in directory root/d1/d2/.../dm. Note that n >= 1 and m >= 0. If m = 0, it means the directory is just
# the root directory.
class Solution(object): # The output is a list of group of duplicate file paths. For each group, it contains all the file paths of the files
def canPlaceFlowers(self, flowerbed, n): # that have the same content. A file path is a string that has the following format:
""" # "directory_path/file_name.txt"
:type flowerbed: List[int]
:type n: int # Create mapping of file content to its path (including file name).
:rtype: bool # Time - O(n * k), number of paths * max path length
""" # Space - O(n * k)
flowerbed.append(0) # avoid special case for last index
i = 0 from collections import defaultdict

while n > 0 and i < len(flowerbed) - 1: class Solution(object):


def findDuplicate(self, paths):
if flowerbed[i + 1] == 1: """
i += 3 :type paths: List[str]
elif flowerbed[i] == 1: :rtype: List[List[str]]
i += 2 """
elif i != 0 and flowerbed[i - 1] == 1: content_to_path = defaultdict(list)
i += 1
else: for path in paths:
n -= 1 path_list = path.split(" ") # path_list[0] is the path, other entries are files
i += 2
for f in path_list[1:]:
return n == 0 open_bracket = f.index("(")
close_bracket = f.index(")")
content = f[open_bracket + 1:close_bracket]
# python_1_to_1000/606_Construct_String_from_Binary_Tree.py - m content_to_path[content].append(path_list[0] + "/" + f[:open_bracket])

_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

result.append(str(node.val)) for i, longest_side in enumerate(nums):


left, right = 0, i - 1
if not node.left and not node.right:
return while left < right:
shortest_side, middle_side = nums[left], nums[right]
result.append("(")
preorder(node.left) if shortest_side + middle_side > longest_side: # equality is not a triangle
result.append(")") triangles += right - left # current shortest and all longer up to middle can make triangles
right -= 1 # decrement middle_side else:
else: new_matches.append([word, 0])
left += 1 # increment shortest_side
matches = new_matches
return triangles
result = []
for i, c in enumerate(s):
from math import factorial
class Solution2(object): if in_tag[i] and (i == 0 or not in_tag[i - 1]): # open tag
def triangleNumber(self, nums): result.append("<b>")
""" elif not in_tag[i] and (i != 0 and in_tag[i - 1]): # close tag
:type nums: List[int] result.append("</b>")
:rtype: int
""" result.append(c)
sides = Counter(nums)
if 0 in sides: if in_tag[-1]:
del sides[0] result.append("</b>") # final close tag
sides = list(sides.items()) # tuples of (side length, count) return "".join(result)
sides.sort()
triangles = 0
# python_1_to_1000/617_Merge_Two_Binary_Trees.py
def binom(n, k):
if k > n: _author_ = 'jake'
return 0 _project_ = 'leetcode'
return factorial(n) // (factorial(n - k) * factorial(k))
# https://leetcode.com/problems/merge-two-binary-trees/
for i, (s1, c1) in enumerate(sides): # Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees
for j, (s2, c2) in enumerate(sides[i:]): # are overlapped while the others are not.
j2 = j + i # You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then sum node values
for s3, c3 in sides[j2:]: # up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of new tree.
if s1 == s2 == s3: # all sides same length
triangles += binom(c1, 3) # If either or both of t1 and t2 are None, return t1 or t2. Else create a root node with the sum of the values and
elif s1 == s2: # shortest 2 sides are same lenght # recursively create the left and right subtrees.
if s1 + s2 > s3: # Time - O(n)
triangles += c3 * binom(c1, 2) # Space - O(1)
elif s2 == s3: # longest sides are same length
triangles += c1 * binom(c2, 2) class Solution(object):
else: # all different lengths def mergeTrees(self, t1, t2):
if s1 + s2 > s3: """
triangles += c1 * c2 * c3 :type t1: TreeNode
:type t2: TreeNode
return triangles :rtype: TreeNode
"""
if t1 and t2:
# python_1_to_1000/616_Add_Bold_Tag_in_String.py - m root = TreeNode(t1.val + t2.val)

_author_ = 'jake' root.left = self.mergeTrees(t1.left, t2.left)


_project_ = 'leetcode' root.right = self.mergeTrees(t1.right, t2.right)

# https://leetcode.com/problems/add-bold-tag-in-string/ return root


# Given a string s and a list of strings dict, you need to add a closed pair of bold tag <b> and </b> to wrap the
# substrings in s that exist in dict. If two such substrings overlap, you need to wrap them together by only one pair return t1 or t2
# of closed bold tag. Also, if two substrings wrapped by bold tags are consecutive, you need to combine them.

# 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 i, c in enumerate(s): class Solution(object):


def leastInterval(self, tasks, n):
new_matches = [] """
:type tasks: List[str]
for word, word_index in matches: :type n: int
if c == word[word_index + 1]: :rtype: int
if word_index + 1 == len(word) - 1: # end of word so mark range of in_tag """
for j in range(i - len(word) + 1, i + 1): counts = Counter(tasks)
in_tag[j] = True max_count = max(counts.values())
else:
new_matches.append([word, word_index + 1]) # add to new list with next word_index result = (max_count - 1) * (n + 1) # n + 1 time between max_count tasks

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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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 Rear(self): max_dist = max(max_dist, abs(array[-1] - low), abs(array[0] - high))


""" low = min(low, array[0])
Get the last item from the queue. high = max(high, array[-1])
:rtype: int
""" return max_dist
if self.isEmpty():
return -1
return self.q[(self.tail + 1) % self.k] # python_1_to_1000/625_Minimum_Factorization.py - m

def isEmpty(self): _author_ = 'jake'


""" _project_ = 'leetcode'
Checks whether the circular queue is empty or not.
:rtype: bool # https://leetcode.com/problems/minimum-factorization/
""" # Given a positive integer a, find the smallest positive integer b whose multiplication of each digit equals to a.
return self.head == self.tail # If there is no answer or the answer is not fit in 32-bit signed integer, then return 0.

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

while a != 1 and a % digit == 0: inverse_pairs = next_inverse_pairs

result += digit * tens return (inverse_pairs[-1] - inverse_pairs[-2]) % MODULO # mod is always positive

if result > 2 ** 31:


return 0 # python_1_to_1000/630_Course_Schedule_III.py - h

a //= digit _author_ = 'jake'


if a == 1: _project_ = 'leetcode'
return result
tens *= 10 # https://leetcode.com/problems/course-schedule-iii/
# There are n different online courses numbered from 1 to n. Each course has some duration(course length) t and closed
return 0 # on dth day. A course should be taken continuously for t days and must be finished before or on the dth day.
# You will start at the 1st day.
# Given n online courses represented by pairs (t,d), your task is to find the maximal number of courses that
# python_1_to_1000/628_Maximum_Product_of_Three_Numbers.py # can be taken.

_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'

return total # https://leetcode.com/problems/find-the-derangement-of-an-array/


# In combinatorial mathematics, a derangement is a permutation of the elements of a set, such that no element appears
def sum(self, r, c, strs): # in its original position.
""" # There's originally an array consisting of n integers from 1 to n in ascending order, you need to find the number
:type r: int # of derangement it can generate.
:type c: str # Also, since the answer may be very large, you should return the output mod 1^9 + 7.
:type strs: List[str]
:rtype: int # Dynamic programming. Derangements of n numbers can be constructed by,
""" # 1) putting n at any of the n - 1 locations in a derangement of n - 1 numbers, and moving the number that was at i
r, c = self._indices(r, c) # to the end (location n) +
self.excel[r][c] = strs # 2) taking any arrangement of n - 1 number with one number in the correct place, replacing that correct number with n
return self.get_i(r, c) # call get_i with indices # and moving n to the end.
# Arrangements with one correct are created by putting any number in its correct place and deranging the remainder.
# Time - O(n)
# python_1_to_1000/632_Smallest_Range.py - h # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def findDerangement(self, n):
"""
# https://leetcode.com/problems/smallest-range/ :type n: int
# You have k lists of sorted integers in ascending order. Find the smallest range that includes at least one :rtype: int
# number from each of the k lists. """
# We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a == d-c. MODULO = 10 ** 9 + 7
derange, one_correct = 0, 1
# Maintain a priority queue 'window' with one number from each list, initially the first. Remove lowest num from
# window and add next num from its list. Update the heap min and max, and potentially overall min and max. for i in range(2, n + 1):
# Time - O(m log n) where m is the total number of nums and n is number of lists derange, one_correct = (derange * (i - 1) + one_correct) % MODULO, (i * derange) % MODULO
# Space - O(n)
return derange
import heapq
break
# python_1_to_1000/635_Design_Log_Storage_Function.py - m if gra == self.periods[i]: # add terminal node ids
later |= s_child.ids
_author_ = 'jake' break
_project_ = 'leetcode'
s_node = s_child
# https://leetcode.com/problems/design-log-storage-system/
# You are given several logs that each log contains a unique id and timestamp. Timestamp is a string that has the for i in range(len(e_list)): # find all ids earlier or eqaul to end
# following format: Year:Month:Day:Hour:Minute:Second, for example, 2017:01:01:23:59:59.
# All domains are zero-padded decimal numbers. e_val = int(e_list[i])
# Design a log storage system to implement the following functions: e_child = e_node.children[e_val] # could be None
# void Put(int id, string timestamp): Given a log's unique id and timestamp, store the log in your storage system. for node in e_node.children[:e_val]:
# int[] Retrieve(String start, String end, String granularity): Return the id of logs whose timestamps are within the if not node:
# range from start to end. Start and end all have the same format as timestamp. However, granularity means the time continue
# level for consideration. For example, start = "2017:01:01:23:59:59", end = "2017:01:02:23:59:59", earlier |= node.ids
# granularity = "Day", it means that we need to find the logs within the range from Jan. 1st 2017 to Jan. 2nd 2017. if not e_child:
break
# Store ids and timestamps in list. Retrieve by matching timestamp prefix up to gra. if gra == self.periods[i]:
# Time - O(1) for put, O(n) for retrieve. earlier |= e_child.ids
# Space - O(n) break
# Alternatively create a tree (similar to a prefix trie) where each node stores all ids with a specific prefix. Tree
# has 6 levels. Nodes are created as required by put(). Retrieve by finding all ids greater than or equal to start that e_node = e_child
# are also less than or equal to end. Faster to retrieve because does not have string comparison with all ids.
return list(earlier & later) # set intersection
class LogSystem(object):
def __init__(self):
self.prefixes = {"Year": 4, "Month": 7, "Day": 10, "Hour": 13, "Minute": 16, "Second": 19}
self.logs = []
# python_1_to_1000/636_Exclusive_Time_of_Functions.py - m
def put(self, id, timestamp):
""" _author_ = 'jake'
:type id: int _project_ = 'leetcode'
:type timestamp: str
:rtype: void # https://leetcode.com/problems/exclusive-time-of-functions/
""" # Given the running logs of n functions that are executed in a nonpreemptive single threaded CPU, find the exclusive
self.logs.append((id, timestamp)) # time of these functions.
# Each function has a unique id, start from 0 to n-1. A function may be called recursively or by another function.
def retrieve(self, s, e, gra): # A log is a string has this format : function_id:start_or_end:timestamp. For example, "0:start:0" means function 0
""" # starts from the very beginning of time 0. "0:end:0" means function 0 ends to the very end of time 0.
:type s: str # Exclusive time of a function is defined as the time spent within this function, the time spent by calling other
:type e: str # functions should not be considered as this function's exclusive time. You should return the exclusive time of each
:type gra: str # function sorted by their function id.
:rtype: List[int]
""" # When a function starts, if there is a current function already running then update its exclusive time. Push
result = [] # new function onto stack and update time. Else if finish then update exclusive time of finished
pref = self.prefixes[gra] # function (extra +1 because start is at perriod start and end is at end) and update time.
s_prefix, e_prefix = s[:pref], e[:pref] # Time - O(n)
# Space - O(n)
for id, timestamp in self.logs:
if s_prefix <= timestamp[:pref] <= e_prefix: class Solution(object):
result.append(id) def exclusiveTime(self, n, logs):
"""
return result :type n: int
:type logs: List[str]
:rtype: List[int]
# Alternative solution """
class LogNode(object): stack = []
def __init__(self, nb_children): exclusive = [0 for _ in range(n)]
self.ids = set() start = None
self.children = [None for _ in range(nb_children)]
for log in logs:
class LogSystem2(object): fn, state, time = log.split(":")
def __init__(self): fn, time = int(fn), int(time)
self.periods = ["Year", "Month", "Day", "Hour", "Minute", "Second"]
self.nb_children = {"Year": 13, "Month": 32, "Day": 24, "Hour": 60, "Minute": 60, "Second": 0} if state == "start":
self.root = LogNode(18) if stack:
exclusive[stack[-1]] += time - start
def put(self, id, timestamp): stack.append(fn)
timelist = timestamp.split(":") start = time
timelist[0] = int(timelist[0]) - 2000
node = self.root else:
exclusive[stack.pop()] += time - start + 1
for t, period in zip(timelist, self.periods): start = time + 1
if not node.children[int(t)]:
node.children[int(t)] = LogNode(self.nb_children[period]) return exclusive
node = node.children[int(t)]
node.ids.add(id)

def retrieve(self, s, e, gra):


s_list, e_list = s.split(":"), e.split(":") # python_1_to_1000/637_Average_of_Levels_in_Binary_Tree.py
s_list[0], e_list[0] = int(s_list[0]) - 2000, int(e_list[0]) - 2000
s_node, e_node = self.root, self.root _author_ = 'jake'
_project_ = 'leetcode'
later, earlier = set(), set()
for i in range(len(s_list)): # find all ids later or eqaul to start # https://leetcode.com/problems/average-of-levels-in-binary-tree/
# Given a non-empty binary tree, return the average value of the nodes on each level in the form of an array.
s_val = int(s_list[i]) # get time period value
s_child = s_node.children[s_val] # could be None # Breadth first search. Maintain a queue of nodes in the current level.
for node in s_node.children[s_val + 1:]: # all later nodes # Time - O(n)
if not node: # Space - O(n)
continue
later |= node.ids class Solution(object):
if not s_child: def averageOfLevels(self, root):

""" # 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

_author_ = 'jake' for c in s[1:]:


_project_ = 'leetcode'
new = 0
# https://leetcode.com/problems/shopping-offers/ # multiply ways by choices for c
# In LeetCode Store, there are some kinds of items to sell. Each item has a price. if c == "*":
# However, there are some special offers, and a special offer consists of one or more different kinds of items with new = 9 * ways
# a sale price. elif c != "0":
# You are given the each item's price, a set of special offers, and the number we need to buy for each item. new = ways
# The job is to output the lowest price you have to pay for exactly certain items as given, where you could make
# optimal use of the special offers. # multiply prev_ways by choices for c and prev_char
# Each special offer is represented in the form of an array, the last number represents the price you need to pay if prev_char == "*":
# for this special offer, other numbers represents how many specific items you could get if you buy this offer. if c == "*": # 11 to 19 and 21 to 26
# You could use any of special offers as many times as you want. new += prev_ways * 15
elif "0" <= c <= "6": # prev_char is 1 or 2
# Given a list of needs, find the cost of buying all items without special offers. Then for each special offer, if it new += prev_ways * 2
# does not involve more than needed of each item, use that offer and recurse. elif "7" <= c <= "9": # prev_char is 1
# Space - O(n**m) where n is nb items and m is max nb of each item (nb tuples in memo) new += prev_ways
# Time - O(kn * n**m) where k is nb specials. For each tuple, iterate over each item of each special.
elif prev_char == "1":
class Solution(object): if c == "*":
def shoppingOffers(self, price, special, needs): new += prev_ways * 9
""" else:
:type price: List[int] new += prev_ways
:type special: List[List[int]]
:type needs: List[int] elif prev_char == "2":
:rtype: int if c == "*":
""" new += prev_ways * 6
def helper(): elif c <= "6":
new += prev_ways
needs_tuple = tuple(needs)
if needs_tuple in memo: new %= 10 ** 9 + 7
return memo[needs_tuple]
prev_ways, ways = ways, new
min_cost = 0 prev_char = c
for cost, need in zip(price, needs):
min_cost += need * cost return ways
if min_cost == 0: # base case
return 0
# python_1_to_1000/640_Solve_the_Equation.py - m
for offer in special:
for i, need in enumerate(needs): _author_ = 'jake'
if offer[i] > need: _project_ = 'leetcode'
break # cannot use this offer
else: # https://leetcode.com/problems/solve-the-equation/
for i, need in enumerate(needs): # Solve a given equation and return the value of x in the form of string "x=#value".
needs[i] -= offer[i] # The equation contains only '+', '-' operation, the variable x and its coefficient.
min_cost = min(min_cost, offer[-1] + helper()) # If there is no solution for the equation, return "No solution".
for i, need in enumerate(needs): # If there are infinite solutions for the equation, return "Infinite solutions".
needs[i] += offer[i] # If there is exactly one solution for the equation, we ensure that the value of x is an integer.

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'

class MyCircularDeque(object): # https://leetcode.com/problems/design-search-autocomplete-system/


# Design a search autocomplete system for a search engine. Users may input a sentence (at least one word and end with
def __init__(self, k): # a special character '#'). For each character they type except '#', you need to return the top 3 historical hot
""" # sentences that have prefix the same as the part of sentence already typed. Here are the specific rules:
Initialize your data structure here. Set the size of the deque to be k. # The hot degree for a sentence is defined as the number of times a user typed the exactly same sentence before.
:type k: int # The returned top 3 hot sentences should be sorted by hot degree (The first is the hottest one). If several
""" # sentences have the same degree of hot, you need to use ASCII-code order (smaller one appears first).
self.k = k + 1 # If less than 3 hot sentences exist, then just return as many as you can.
self.q = [None] * self.k # When the input is a special character, it means the sentence ends, and in this case, you need to return
self.head = self.tail = 0 # an empty list.
# Your job is to implement the following functions:
def insertFront(self, value): # The constructor function:
""" # AutocompleteSystem(String[] sentences, int[] times): This is the constructor. The input is historical data.
Adds an item at the front of Deque. Return true if the operation is successful. # Sentences is a string array consists of previously typed sentences. Times is the corresponding times a sentence
:type value: int # has been typed. Your system should record these historical data.
:rtype: bool # Now, the user wants to input a new sentence. The following function will provide the next character the user types:
""" # List<String> input(char c): The input c is the next character typed by the user. The character will only be
if self.isFull(): # lower-case letters ('a' to 'z'), blank space (' ') or a special character ('#'). Also, the previously typed
return False # sentence should be recorded in your system. The output will be the top 3 historical hot sentences that have prefix
self.head = (self.head + 1) % self.k # the same as the part of sentence already typed.
self.q[self.head] = value
return True # Store sentences that have already been seen in a map (key = sentence, value = count).
# When the first char of a new sentence is input, create a list of all previously seen sentences that match the first
def insertLast(self, value): # char, sorted by decreasing count. Then for each subsequent char, all we need to do is filter the existing list,
""" # keeping only sentences that match the char in its correct position.
Adds an item at the rear of Deque. Return true if the operation is successful. # At the end of the input, simply increment the count.
:type value: int # Time - O(n) for constructor when n is number of sentences. O(n log n) to input first char then O(n).
:rtype: bool # Space - O(n)
"""
if self.isFull(): from collections import defaultdict
return False
self.q[self.tail] = value class AutocompleteSystem(object):

def __init__(self, sentences, times):


""" if k < 80:
:type sentences: List[str] cumulative = [0]
:type times: List[int] for num in nums:
""" cumulative.append(cumulative[-1] + num)
self.partial = [] # previously seen chars of current sentence result = float('-inf')
self.matches = [] # matching sentences in decreasing frequency order for length in range(k, min(n + 1, 2 * k)):
max_sum = max([cumulative[length + i] - cumulative[i] for i in range(n - length + 1)])
self.counts = defaultdict(int) # map from sentence to its frequency result = max(result, max_sum / float(length))
for sentence, count in zip(sentences, times): return result
self.counts[sentence] = count
def has_average(x):
def input(self, c):
""" subarray_sum = 0
:type c: str for i in range(k):
:rtype: List[str] subarray_sum += nums[i] - x
""" if subarray_sum >= 0:
if c == "#": return True
sentence = "".join(self.partial)
self.counts[sentence] += 1 prefix_sum, min_prefix = 0, 0
self.partial = [] # reset partial and matches for i in range(k, n):
self.matches = [] subarray_sum += nums[i] - x
return [] prefix_sum += nums[i - k] - x
min_prefix = min(min_prefix, prefix_sum)
if not self.partial: # first char of sentence if subarray_sum - min_prefix >= 0:
self.matches = [(-count, sentence) for sentence, count in self.counts.items() if sentence[0] == c] return True
self.matches.sort()
self.matches = [sentence for _, sentence in self.matches] # drop the counts return False
else:
i = len(self.partial) # filter matches for c left, right = min(nums), max(nums)
self.matches = [sentence for sentence in self.matches if len(sentence) > i and sentence[i] == c] while right - left > 1e-5:
mid = (left + right) / 2.0
self.partial.append(c) if has_average(mid):
return self.matches[:3] left = mid
else:
right = mid

# python_1_to_1000/643_Maximum_Average_Subarray_I.py return left

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/645_Set_Mismatch.py

# https://leetcode.com/problems/maximum-average-subarray-i/ _author_ = 'jake'


# Given an array consisting of n integers, find the contiguous subarray of given length k that has the maximum _project_ = 'leetcode'
# average value. And you need to output the maximum average value.
# https://leetcode.com/problems/set-mismatch/
# Maintain a window with the sum of k elements. Slide the sindow along nums, updating the sum and max_average. # The set S originally contains numbers from 1 to n. But unfortunately, one of the numbers in the set got duplicated
# Time - O(n) # to another number in the set, which results in repetition of one number and loss of another number.
# Space - O(1) # Given an array nums representing the data status of this set after the error. Your task is to firstly find the
# number occurs twice and then find the number that is missing. Return them in the form of an array.
class Solution(object):
def findMaxAverage(self, nums, k): # Iterate over nums. When num is seen, set the num at index of abs(num) - 1 to negative. If the num at that index is
""" # already negative, it is the duplicate. Then find the index i that is not negative, which means i + 1 is missing.
:type nums: List[int] # Time - O(n)
:type k: int # Space - O(1)
:rtype: float
""" class Solution(object):
window_sum = sum(nums[:k]) # assumes len(nums) >= k def findErrorNums(self, nums):
max_average = window_sum / float(k) """
:type nums: List[int]
for i in range(len(nums) - k): :rtype: List[int]
window_sum += nums[i + k] - nums[i] """
max_average = max(max_average, window_sum / float(k)) for num in nums:
if nums[abs(num) - 1] < 0:
return max_average duplicate = abs(num)
else:
nums[abs(num) - 1] *= -1
# python_1_to_1000/644_Maximum_Average_Subarray_II.py - h
for i, num in enumerate(nums):
_author_ = 'jake' if num > 0:
_project_ = 'leetcode' missing = i + 1
break
# https://leetcode.com/problems/maximum-average-subarray-ii/
# Given an array consisting of n integers, find the contiguous subarray whose length is greater than or equal to k that return [duplicate, missing]
# has the maximum average value. And you need to output the maximum average value.

# 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

# python_1_to_1000/647_Palindromic_Substrings.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/dota2-senate/
# In the world of Dota2, there are two parties: the Radiant and the Dire.
# https://leetcode.com/problems/palindromic-substrings/ # The Dota2 senate consists of senators coming from two parties. Now the senate wants to make a decision about a
# Given a string, your task is to count how many palindromic substrings in this string. The substrings with different # change in the Dota2 game. The voting for this change is a round-based procedure.
# start indexes or end indexes are counted as different substrings even they consist of same characters. # In each round, each senator can exercise one of the two rights:
# Ban one senator's right: A senator can make another senator lose all his rights in this and all the following rounds.
# For each char or neighbouring pair of chars, extend outwards as long as left and right match. # Announce the victory: If this senator found the senators who still have rights to vote are all from the same party,
# Time - O(n**2) # he can announce the victory and make the decision about the change in the game.
# Space - O(1) # Given a string representing each senator's party belonging. The character 'R' and 'D' represent the Radiant party
# and the Dire party respectively. Then if there are n senators, the size of the given string will be n.
class Solution(object): # The round-based procedure starts from the first senator to the last senator in the given order. This procedure will
def countSubstrings(self, s): # last until the end of voting. All the senators who have lost their rights will be skipped during the procedure.
""" # Suppose every senator is smart enough and will play the best strategy for his own party, you need to predict which
:type s: str # party will finally announce the victory and make the change in the Dota2 game. The output should be Radiant or Dire.
:rtype: int
""" # Create a queue of senator for each part by index. Compare the indices of the first senator from each party. The first
count = 0 # will ban the rights of the second, so first is added to the back of the queue for this part and second is rejected.
# Time - O(n), total number of senators since one senator is removed in each step.
for i in range(2 * len(s) + 1): # Space - O(n)

left = right = i // 2 from collections import deque


if i % 2 == 1:
right += 1 class Solution(object):
def predictPartyVictory(self, senate):
while left >= 0 and right < len(s) and s[left] == s[right]: """
count += 1 :type senate: str
left -= 1 :rtype: str
right += 1 """
n = len(senate)
return count d, r = deque(), deque() # indices of remaining senators for each party
for i, c in enumerate(senate):
if c == "D":
# python_1_to_1000/648_Replace_Words.py - m d.append(i)
else:
_author_ = 'jake' r.append(i)
_project_ = 'leetcode'
while d and r:
# https://leetcode.com/problems/replace-words/ d_senator = d.popleft()
# In English, we have a concept called root, which can be followed by some other words to form another longer word - r_senator = r.popleft()
# let's call this word successor. For example, the root an, followed by other, which can form another word another. if d_senator < r_senator:
# Now, given a dictionary consisting of many roots and a sentence. You need to replace all the successor in the d.append(d_senator + n)
# sentence with the root forming it. If a successor has many roots can form it, replace it with the root with the else:
# shortest length.. You need to output the sentence after the replacement. r.append(r_senator + n)

# 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)

class Solution(object): # python_1_to_1000/654_Maximim_Binary_Tree.py - m


def maxA(self, N):
""" _author_ = 'jake'
:type N: int _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/maximum-binary-tree/
def helper(n): # Given an integer array with no duplicates. A maximum tree building on this array is defined as follow:
if n in memo: # The root is the maximum number in the array.
return memo[n] # The left subtree is the maximum tree constructed from left part subarray divided by the maximum number.
# The right subtree is the maximum tree constructed from right part subarray divided by the maximum number.
max_A = n # press 'A' n times # Construct the maximum tree by the given array and output the root node of this tree.
for i in range(max(n - 5, 0), n - 3): # i + 1 print 'A' to make a base list
max_A = max(max_A, helper(i) * (n - i - 1)) # then n - (i + 1) copies of the base list # For each array, find the maximum and set to root, then recurse for left and right subtrees.
# Time - O(n**2)
memo[n] = max_A # Space - O(n)
return max_A
class Solution(object):
memo = {} def constructMaximumBinaryTree(self, nums):
return helper(N) """
:type nums: List[int]
:rtype: TreeNode
# python_1_to_1000/652_Find_Duplicate_Subtrees.py - m """

_author_ = 'jake' def helper(i, j): # construct subtree from nums[i:j + 1]


_project_ = 'leetcode' if i > j:
return None
# https://leetcode.com/problems/find-duplicate-subtrees/
# Given a binary tree, return all duplicate subtrees. For each kind of duplicate subtrees, you only need to return max_num = float("-inf")
# the root node of any one of them. for k in range(i, j + 1):
# Two trees are duplicate if they have the same structure with same node values. if nums[k] > max_num:
max_num = nums[k]
# Preorder traversal. Create a string representation of each subtree and map that string to a list of root nodes. max_index = k
# Time - O(n**2)
# Space - O(n) root = TreeNode(max_num)
root.left = helper(i, max_index - 1)
from collections import defaultdict root.right = helper(max_index + 1, j)

class Solution(object): return root


def findDuplicateSubtrees(self, root):
""" return helper(0, len(nums) - 1)
:type root: TreeNode
:rtype: List[TreeNode]
""" # python_1_to_1000/655_Print_Binary_Tree.py - m
def serialize(node):
if not node: _author_ = 'jake'
return "#" _project_ = 'leetcode'
serial = str(node.val) + "," + serialize(node.left) + "," + serialize(node.right)
subtrees[serial].append(node) # https://leetcode.com/problems/print-binary-tree/
return serial # Print a binary tree in an m*n 2D string array following these rules:
# The row number m should be equal to the height of the given binary tree.
subtrees = defaultdict(list) # key is serialised subtree, value is list of subtree nodes # The column number n should always be an odd number.
serialize(root) # ignore return value # The root node's value (in string format) should be put in the exactly middle of the first row it can be put.
return [nodes[0] for serial, nodes in subtrees.items() if len(nodes) > 1] # The column and the row where the root node belongs will separate the rest space into two parts (left-bottom part
# and right-bottom part). You should print the left subtree in the left-bottom part and print the right subtree in
# the right-bottom part. The left-bottom part and the right-bottom part should have the same size. Even if one
# python_1_to_1000/653_Two_Sum_IV_-_Input_is_a_BST.py # subtree is none while the other is not, you don't need to print anything for the none subtree but still need to
# leave the space as large as that for the other subtree. However, if two subtrees are none, then you don't need # Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot makes a circle,
# to leave space for both of them. # which means it moves back to the original place.
# Each unused space should contain an empty string "". # The move sequence is represented by a string. And each move is represent by a character. The valid robot moves are:
# Print the subtrees following the same rules. # R (Right), L (Left), U (Up) and D (down). The output should be true or false.

# 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)

class Solution(object): class Solution(object):


def printTree(self, root): def judgeCircle(self, moves):
""" """
:type root: TreeNode :type moves: str
:rtype: List[List[str]] :rtype: bool
""" """
return moves.count("U") == moves.count("D") and moves.count("L") == moves.count("R")
def height(node):
if not node:
return 0 # python_1_to_1000/658_Find_K_Closest_Elements.py - m
return 1 + max(height(node.left), height(node.right))
_author_ = 'jake'
rows = height(root) _project_ = 'leetcode'
cols = 2 ** rows - 1
# https://leetcode.com/problems/find-k-closest-elements/
result = [["" for _ in range(cols)] for _ in range(rows)] # Given a sorted array, two integers k and x, find the k closest elements to x in the array. The result should also be
# sorted in ascending order. If there is a tie, the smaller elements are always preferred.
def place(node, r, c):
if not node: # Binary search for value closest to x, then expand outwards.
return # Time - O(log n + k)
result[r][c] = str(node.val) # Space - O(1)
shift = 2 ** (rows - r - 2) # next column shift as a function of r
place(node.left, r + 1, c - shift) class Solution(object):
place(node.right, r + 1, c + shift) def findClosestElements(self, arr, k, x):
"""
place(root, 0, cols // 2) :type arr: List[int]
return result :type k: int
:type x: int
:rtype: List[int]
# python_1_to_1000/656_Coin_Path.py - h """
left, right = 0, len(arr) - 1 # region of search for x (inclusive)
_author_ = 'jake'
_project_ = 'leetcode' while left <= right:
mid = (left + right) // 2
# https://leetcode.com/problems/coin-path/ if x == arr[mid]:
# Given an array A (index starts at 1) consisting of N integers: A1, A2, ..., AN and an integer B. The integer B left, right = mid, mid
# denotes that from any place (suppose the index is i) in the array A, you can jump to any one of the place in the break
# array A indexed i+1, i+2, …, i+B if this place can be jumped to. Also, if you step on the index i, you have to elif x > arr[mid]:
# pay Ai coins. If Ai is -1, it means you can’t jump to the place indexed i in the array. left = mid + 1
# Now, you start from the place indexed 1 in the array A, and your aim is to reach the place indexed N using the else:
# minimum coins. You need to return the path of indexes (starting from 1 to N) in the array you should take to get right = mid - 1
# to the place indexed N using minimum coins.
# If there are multiple paths with the same cost, return the lexicographically smallest such path. else: # find which of left and right is closer to x
# If it's not possible to reach the place indexed N then you need to return an empty array. if right == len(arr) or abs(arr[left] - x) <= abs(arr[right] - x):
right = left
# Dynamic programming. List contains the least coins to reach every index and it's path. Intialize the cost as else:
# infinity and empty path apart from the first index. For all reachable indices of A, update their cost with the left = right
# the cost from i if better.
# Time - O(nB) while right - left + 1 < k: # while result length less than k
# Space - O(n) if right + 1 == len(arr) or abs(arr[left - 1] - x) <= abs(arr[right + 1] - x): # add arr[left]
left -= 1
class Solution(object): else: # add arr[right]
def cheapestJump(self, A, B): right += 1
"""
:type A: List[int] return arr[left:right + 1]
:type B: int
:rtype: List[int]
""" # python_1_to_1000/659_Split_Array_into_Consecutive_Subsequences.py - m
cheapest = [[float("inf"), []] for _ in range(len(A))] # [cost, path] to reach each index of A
cheapest[0] = [A[0], [1]] _author_ = 'jake'
_project_ = 'leetcode'
for i, cost in enumerate(A[:-1]): # do not jump from last index
# https://leetcode.com/problems/split-array-into-consecutive-subsequences/
if cost == -1: # cannot jump from i # You are given an integer array sorted in ascending order (may contain duplicates), you need to split them into
continue # several subsequences, where each subsequences consist of at least 3 consecutive integers. Return whether you can
# make such a split.
for j in range(i + 1, min(i + B + 1, len(A))):
# Count each num. For each num, reduce count and extend a sequence ending with num - 1 if possible. Otherwise use num
if A[j] == -1: # cannot jump to j # and num + 1 and num + 2 to create a new sequence. Otherwise num cannot be used.
continue # Time - O(n)
new_cost = cheapest[i][0] + A[j] # Space - O(n)
new_path = cheapest[i][1] + [j + 1] # extend path
cheapest[j] = min(cheapest[j], [new_cost, new_path]) # lowest cost then lowest lexicographic path from collections import Counter, defaultdict

return cheapest[-1][1] class Solution(object):


def isPossible(self, nums):
"""
# python_1_to_1000/657_Judge_Route_Circle.py :type nums: List[int]
:rtype: bool
_author_ = 'jake' """
_project_ = 'leetcode' freq = Counter(nums)
sequences = defaultdict(int) # map from num to number of sequences ending with num
# https://leetcode.com/problems/judge-route-circle/

for num in nums: _author_ = 'jake'


_project_ = 'leetcode'
if freq[num] == 0: # num already used to extend other sequences
continue # https://leetcode.com/problems/maximum-width-of-binary-tree/
freq[num] -= 1 # Given a binary tree, write a function to get the maximum width of the given tree. The width of a tree is the maximum
# width among all levels. The binary tree has the same structure as a full binary tree, but some nodes are null.
if sequences[num - 1] != 0: # extend an existing sequence # The width of one level is defined as the length between the end-nodes (the leftmost and right most non-null nodes in
sequences[num - 1] -= 1 # the level, where the null nodes between the end-nodes are also counted into the length calculation.
sequences[num] += 1
# For each level, create a list of all non-null nodes at the next level along with their indices. Indices are relative
elif freq[num + 1] > 0 and freq[num + 2] > 0: # create a new sequence # to a complete binary tree i.e. left most node has index 0 and right most 2**depth - 1. Width is separation between
freq[num + 1] -= 1 # first and last nodes at each level.
freq[num + 2] -= 1 # Time - O(n)
sequences[num + 2] += 1 # Space - O(n)

else: # cannot use num class Solution(object):


return False def widthOfBinaryTree(self, root):
"""
return True :type root: TreeNode
:rtype: int
"""
if not root:
# python_1_to_1000/660_Remove_9.py - h return 0

_author_ = 'jake' max_width = 1


_project_ = 'leetcode' nodes = [(root, 0)] # list of nodes per level and their indices

# https://leetcode.com/problems/remove-9/ while True:


# Start from integer 1, remove any integer that contains 9 such as 9, 19, 29... new_nodes = []
# So now, you will have a new integer sequence: 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, ...
# Given a positive integer n, you need to return the n-th integer after removing. Note that 1 will be the first integer. for node, i in nodes:
if node.left:
# All remaining numbers without 9 are the base 9 numbers. Convert to base 9 by repeatedly dividing by 9, reverse result. new_nodes.append((node.left, i * 2))
# Time - O(log n) if node.right:
# Space - O(1) new_nodes.append((node.right, i * 2 + 1))

class Solution(object): if not new_nodes:


def newInteger(self, n): break
""" nodes = new_nodes
:type n: int max_width = max(max_width, 1 + nodes[-1][1] - nodes[0][1])
:rtype: int
""" return max_width
result = []

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

class Solution(object): class Solution(object):


def imageSmoother(self, M): def checkEqualTree(self, root):
""" """
:type M: List[List[int]] :type root: TreeNode
:rtype: List[List[int]] :rtype: bool
""" """
rows, cols = len(M), len(M[0]) def make_sum(node):
smoothed = [[0 for _ in range(cols)] for _ in range(rows)] if not node:
return 0
for r in range(rows): node.val += make_sum(node.left) + make_sum(node.right)
for c in range(cols): return node.val

nbors, total = 0, 0 tree_sum = make_sum(root)


for dr in (-1, 0, 1): if tree_sum % 2 == 1: # no partition possible
for dc in (-1, 0, 1): return False

if r + dr < 0 or r + dr >= rows or c + dc < 0 or c + dc >= cols: def find_split(node):


continue if not node:
total += M[r + dr][c + dc] return False
nbors += 1
if node.left and node.left.val == tree_sum // 2:
smoothed[r][c] = total // nbors # round down return True
if node.right and node.right.val == tree_sum // 2:
return smoothed return True
return find_split(node.left) or find_split(node.right)

# python_1_to_1000/662_Maximum_Width_of_Binary_Tree.py - m return find_split(root)


# python_1_to_1000/664_Strange_Printer.py - h
# python_1_to_1000/666_Path_Sum_IV.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/strange-printer/
# There is a strange printer with the following two special requirements: # https://leetcode.com/problems/path-sum-iv/
# The printer can only print a sequence of the same character each time. # If the depth of a tree is smaller than 5, then this tree can be represented by a list of three-digits integers.
# At each turn, the printer can print new characters starting from and ending at any places, and will cover the # For each integer in this list:
# original existing characters. # The hundreds digit represents the depth D of this node, 1 <= D <= 4.
# Given a string consists of lower English letters only, your job is to count the minimum number of turns the printer # The tens digit represents the position P of this node in the level it belongs to, 1 <= P <= 8. The position is the
# needed in order to print it. # same as that in a full binary tree.
# The units digit represents the value V of this node, 0 <= V <= 9.
# First remove repeated characters since they will always be printed together. # Given a list of ascending three-digits integers representing a binary with the depth smaller than 5. You need to
# To print s[i:j + 1] we find s[i] then iterate along the substring. When we find a s[k] == s[i] then s[i:k] can # return the sum of all paths from the root towards the leaves.
# be printed in the same time as s[i:k + 1] because we can print a string of s[i] and then the other characters in the
# same time in either case. So we can split the subproblems at every char that is the same as the starting char and # Create a mapping from each node's location to its value. Location is a tuple (depth, pos) where pos is indexed
# take the minimum prints of all those split points. # from zero. Then recursively explore the tree from the root with depth-first search. If node has no children then
# Time - O(n**3), iterate over every of the n**2 substrings # it is a leaf so return partial sum (including own value). Else return sums of paths via left and right subtrees.
# Space - O(n**2) # Time - O(n)
# Space - O(n)
class Solution(object):
def strangePrinter(self, s): class Solution(object):
""" def pathSum(self, nums):
:type s: str """
:rtype: int :type nums: List[int]
""" :rtype: int
s = "".join([a for a, b in zip(s, "#" + s) if a != b]) # remove repeated chars """
memo = {} mapping = {} # key is (depth, pos) of node, value is val

def helper(i, j): for num in nums:


location, val = divmod(num, 10)
if j - i + 1 <= 1: # length <= 1, return length depth, pos = divmod(location, 10)
return j - i + 1 mapping[(depth, pos - 1)] = val

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

for k in range(i + 1, j + 1): depth, pos = location


if s[k] == s[i]: # all chars that match first new_partial = partial + mapping[location]
min_prints = min(min_prints, helper(i, k - 1) + helper(k + 1, j)) left = (depth + 1, 2 * pos)
right = (depth + 1, 2 * pos + 1)
memo[(i, j)] = min_prints
return min_prints if left not in mapping and right not in mapping: # leaf node
return new_partial
return helper(0, len(s) - 1) return sum_paths((depth + 1, 2 * pos), new_partial) + sum_paths((depth + 1, 2 * pos + 1), new_partial)

return sum_paths((1, 0), 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

return result + list(range(k + 2, n + 1))

# 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'

_author_ = 'jake' # https://leetcode.com/problems/maximum-swap/


_project_ = 'leetcode' # Given a non-negative integer, you could swap two digits at most once to get the maximum valued number.
# Return the maximum valued number you could get.
# https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/
# Nearly every one have used the Multiplication Table. But could you find out the k-th smallest number quickly from # Iterate backwards from the least to the most significant digit. When we have already seen a greater digit than the
# the multiplication table? # current digit they could be swapped and increase the value. Track the first occurrence of greatest digit seen.
# Given the height m and the length n of a m * n Multiplication Table, and a positive integer k, you need to return # If the current digit is lower, we have a new candidate for swapping. If it is higher, we have a new max_seen.
# the k-th smallest number in this table. # The last candidates found result in the greatest increase because they increase the most significant digit possible.
# Time - O(log n)
# Binary search the range of possible answers, initially [1, m * n]. helper function determines whether there are at # Space - O(1)
# least k numbers in the multiplication table that are less than or equal to guess.
# Time - O(min(m, n) log(mn) class Solution(object):
# Space - O(1) def maximumSwap(self, num):
"""
class Solution(object): :type num: int
def findKthNumber(self, m, n, k): :rtype: int
""" """
:type m: int s = [int(c) for c in str(num)] # convert to list of digits
:type n: int
:type k: int max_seen, max_seen_i = -1, -1 # max digit seen (from back) and its index
:rtype: int demote, promote = -1, -1 # indices of best pair to swap
"""
if m > n: # ensure m is smaller for i in range(len(s) - 1, -1, -1): # iterate from least significant digit
m, n = n, m digit = s[i]
if max_seen > digit: # greater digit later in num so swap will increase value
def helper(guess): # return True if there are at least k numbers in table <= guess demote, promote = i, max_seen_i
count = 0 elif digit > max_seen: # update max_seen on first occurrence of greater digit
for i in range(1, m + 1): max_seen, max_seen_i = digit, i
temp = guess // i
if temp > n: # faster than count += min(n, guess // i) if demote == -1: # nothing can be swapped
count += n return num
else:
count += temp s[demote], s[promote] = s[promote], s[demote]
if count >= k: # stop iterating if count already too large result = 0
return True for digit in s:
result = result * 10 + digit
return False return result

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")

class Solution(object): def helper(node):


def trimBST(self, root, L, R):
""" if not node:
:type root: TreeNode return
:type L: int
:type R: int if node.val == min_val:
:rtype: TreeNode helper(node.left)
""" helper(node.right)
if not root: else: # node.val > min_val
return None self.second_min = min(node.val, self.second_min)

if root.val > R: helper(root)


return self.trimBST(root.left, L, R)
if root.val < L: return -1 if self.second_min == float("inf") else self.second_min
return self.trimBST(root.right, L, R)

root.left = self.trimBST(root.left, L, R) # python_1_to_1000/672_Bulb_Switcher_II.py - m


root.right = self.trimBST(root.right, L, R)
return root _author_ = 'jake'
_project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/bulb-switcher-ii/
# There is a room with n lights which are turned on initially and 4 buttons on the wall. After performing exactly m # https://leetcode.com/problems/longest-continuous-increasing-subsequence/
# unknown operations towards buttons, you need to return how many different kinds of status of the n lights could be. # Given an unsorted array of integers, find the length of longest continuous increasing subsequence (subarray).
# Suppose n lights are labeled as number [1, 2, 3 ..., n], function of these 4 buttons are given below:
# Flip all the lights. # Dynamic programming. Find longest CIS ending at each num. If non-increasing, reset current sequence length.
# Flip lights with even numbers. # Time - O(n)
# Flip lights with odd numbers. # Space - O(1)
# Flip lights with (3k + 1) numbers, k = 0, 1, 2, ...
class Solution(object):
# In the general case of large m and n, we can apply amy of the 3 operations - even, odd, 3k + 1. This gives 2**3 = 8 def findLengthOfLCIS(self, nums):
# possible states. Additional m or n do not lead to any more states. Smaller cases are considered individually. """
# Time - O(1) :type nums: List[int]
# Space - O(1) :rtype: int
"""
class Solution(object): longest, current = 0, 0
def flipLights(self, n, m):
""" for i, num in enumerate(nums):
:type n: int
:type m: int if i == 0 or num <= nums[i - 1]:
:rtype: int current = 0
"""
if n == 0: current += 1
return 0 # no lights longest = max(longest, current)
if m == 0:
return 1 # no switches return longest

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/implement-magic-dictionary/ def insert(self, key, val):


# Implement a magic directory with buildDict, and search methods. """
# For the method buildDict, you'll be given a list of non-repetitive words to build a dictionary. :type key: str
# For the method search, you'll be given a word, and judge whether if you modify exactly one character into another :type val: int
# character in this word, the modified word is in the dictionary you just built. :rtype: void
"""
# Create a trie where each node is a mapping from a letter to the next node (which is itself a mapping). Terminal if key in self.words: # update words and update val to change in val
# nodes at the end of words are signified by a mapping to '#'. Search works by depth first search on trie. self.words[key], val = val, val - self.words[key]
# Track the index of the next char to match in word and number of mistmatches seen so far. For each char, move down else:
# the trie to all children incrementing the mismatches if then node is different from the char of the word. Terminate self.words[key] = val # insert into words
# at either the end fo the word or too many mismatches are found.
# Time - O(n) to buildDict where n is the total number of chars in all words in dictionary. O(m) to search where m is for i in range(len(key)):
# the length of the word since there are a finite number (25) of mismatches at every node. prefix = key[:i + 1]
# Space - O(n) self.dict[prefix] += val # update dict for all prefixes

class MagicDictionary(object): def sum(self, prefix):


"""
def __init__(self): :type prefix: str
""" :rtype: int
Initialize your data structure here. """
""" return self.dict[prefix]
self.root = {} # key is char, value is dictionary

def buildDict(self, dict): # python_1_to_1000/678_Valid_Parenthesis_String.py - m


"""
Build a dictionary through a list of words _author_ = 'jake'
:type dict: List[str] _project_ = 'leetcode'
:rtype: void
""" # https://leetcode.com/problems/valid-parenthesis-string/
for word in dict: # Given a string containing only three types of characters: '(', ')' and '*', write a function to check whether this
node = self.root # string is valid. We define the validity of a string by these rules:
# 1. Any left parenthesis '(' must have a corresponding right parenthesis ')'.
for c in word: # 2. Any right parenthesis ')' must have a corresponding left parenthesis '('.
if c not in node: # 3. Left parenthesis '(' must go before the corresponding right parenthesis ')'.
node[c] = {} # 4. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string.
node = node[c] # 5. An empty string is also valid.
node["#"] = None # signifies end of a word
# Track the range of possible open brackets when iterating over s. If "(" is seen, both bounds of range increase. If
def search(self, word): # ")" is seen both bounds decrease subject to the lower bound not becoming negative. If "*" is seen, upper bound
""" # increase and lower bound decreases, subject to zero. Upper bound can never be less than zero. Lower bound must be
Returns if there is any word in the trie that equals to the given word after modifying exactly one character # zero at end of s.
:type word: str # Time - O(n)
:rtype: bool # Space - O(1)
"""
def helper(i, mismatches, node): # index of next char to match, nb mismatches class Solution(object):
def checkValidString(self, s):
if mismatches == 2: # too many mismatches """
return False :type s: str
:rtype: bool
if i == len(word): # end fo word, True if terminal node and 1 mismatch """
return "#" in node and mismatches == 1 min_open, max_open = 0, 0

for c in node.keys(): for c in s:


if c == "#":
continue if c == "(":
if helper(i + 1, mismatches + (c != word[i]), node[c]): min_open += 1
return True max_open += 1
elif c == ")":
return False min_open = max(0, min_open - 1)
max_open -= 1
return helper(0, 0, self.root) else:
min_open = max(0, min_open - 1)
max_open += 1

# python_1_to_1000/677_Map_Sum_Pairs.py - m if max_open < 0:


return False
_author_ = 'jake'
_project_ = 'leetcode' return min_open == 0

# 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)

# https://leetcode.com/problems/24-game/ class Solution(object):


# You have 4 cards each containing a number from 1 to 9. You need to judge whether they could operated def nextClosestTime(self, time):
# through *, /, +, -, (, ) to get the value of 24. """
:type time: str
# For any input list, iterate through every pair of numbers and combine them in all 6 possible ways. There are 6 ways :rtype: str
# because addition and multiplication are commutative but subtraction and division are not. Form a new shorter list """
# from the result of the operation oin the pair and remaining unused numbers from the original list and recurse. result = [c for c in time]
# The base case is a list with one element. Numerical precision implies this may not be exactly 24 but the minimum digits = set(int(c) for c in time[:2] + time[3:]) # set of digits in time
# number that can eb formed is 1 / (9 * 9 * 9) and sets a bound on the tolerance. min_digit = min(digits)
# Time - O(1) since here are a finite number of combinations. max_digits = {0 : 2, 3 : 5, 4 : 9} # max possible digit at each index
# Space - O(1)
def increase(i):
class Solution(object): if i == 1: # max digit depends on time[0]
def judgePoint24(self, nums): if time[0] == "2":
""" max_digit = 3
:type nums: List[int] else:
:rtype: bool max_digit = 9
""" else:
n = len(nums) max_digit = max_digits[i]
if n == 1:
return abs(nums[0] - 24) < 0.001 larger_digits = [d for d in digits if int(time[i]) < d <= max_digit]
return min(larger_digits) if larger_digits else -1
for i in range(n - 1):
for j in range(i + 1, n): for i in [4, 3, 1, 0]: # iterate backwards, ignoring ":"
remainder = nums[:i] + nums[i + 1:j] + nums[j + 1:] increaseed = increase(i)
if increaseed != -1:
if self.judgePoint24(remainder + [nums[i] + nums[j]]): result[i] = str(increaseed)
return True break
if self.judgePoint24(remainder + [nums[i] - nums[j]]): else:
return True result[i] = str(min_digit)
if self.judgePoint24(remainder + [nums[j] - nums[i]]):
return True return "".join(result)
if self.judgePoint24(remainder + [nums[i] * nums[j]]):
return True
if nums[j] != 0 and self.judgePoint24(remainder + [float(nums[i]) / float(nums[j])]):
return True # python_1_to_1000/682_Baseball_Game.py
if nums[i] != 0 and self.judgePoint24(remainder + [float(nums[j]) / float(nums[i])]):
return True _author_ = 'jake'
_project_ = 'leetcode'
return False
# https://leetcode.com/problems/baseball-game/
# You're now a baseball game point recorder.
# python_1_to_1000/680_Valid_Palindrome_II.py # Given a list of strings, each string can be one of the 4 following types:
# Integer (one round's score): Directly represents the number of points you get in this round.
_author_ = 'jake' # "+" (one round's score): The points you get in this round are the sum of the last two valid round's points.
_project_ = 'leetcode' # "D" (one round's score): The points you get in this round are the doubled data of the last valid round's points.
# "C" (an operation, which isn't a round's score): The last valid round's points were invalid and should be removed.
# https://leetcode.com/problems/valid-palindrome-ii/ # Each round's operation is permanent and could have an impact on the round before and the round after.
# Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome. # You need to return the sum of the points you could get in all the rounds.

# 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:

while i < n // 2: if op == "+": # assumes there are at least 2 previous socres


points.append(points[-1] + points[-2])
if s[i] != s[n - 1 - i]: elif op == "D": # assumes at least one previous score
del_front = s[i + 1:n - i] points.append(2 * points[-1])
del_back = s[i:n - 1 - i] elif op == "C": # remove previous
return del_front == del_front[::-1] or del_back == del_back[::-1] points.pop()
else:
i += 1 points.append(int(op))

return True return sum(points)

# 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 a, b in edges: class Solution(object):


def repeatedStringMatch(self, A, B):
parent_a, parent_b = find_parent(a), find_parent(b) """
if parent_a == parent_b: :type A: str
return [a, b] :type B: str
:rtype: int
parents[parent_a] = parent_b # union join """
if set(B) - set(A): # early return
return -1
# python_1_to_1000/685_Redundant_Connection_II.py - h
div, mod = divmod(len(B), len(A))
_author_ = 'jake'
if mod != 0: c1 = N - 1 - c1
div += 1 return [r1, c1]

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):

return -1 new_probs = [[0 for _ in range(M)] for _ in range(M)]

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

# python_1_to_1000/691_Stickers_to_Spell_Word.py - h _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/binary-number-with-alternating-bits/
# Given a positive integer, check whether it has alternating bits: namely, if two adjacent bits will always
# https://leetcode.com/problems/stickers-to-spell-word/ # have different values.
# We are given N different types of stickers. Each sticker has a lowercase English word on it.
# You would like to spell out the given target string by cutting individual letters from your collection of stickers # Repeatedly divide by 2 where remainder is bit value.
# and rearranging them. # Time - O(log n)
# You can use each sticker more than once if you want, and you have infinite quantities of each sticker. # Space - O(1)
# What is the minimum number of stickers that you need to spell out the target? If the task is impossible, return -1.
class Solution(object):
# Remove chars from each sticker that are not in target and create mapping from char to set of stickers containing def hasAlternatingBits(self, n):
# that char. Return -1 if every char of target is not contained in at least one sticker. """
# Maintain a heap of candidate solutions. Pop item from heap with lowest used stickers, breaking ties by lowest :type n: int
# remaining target length. For each sticker that contains the first remaining letter of target, remove all usable :rtype: bool
# chars from target and add remaining target back to heap. """
# Space - O(n * k**2) where n is number of sickers and k is length of target. If target is a string of the same char n, bit = divmod(n, 2) # get first bit, avoids special case in while loop
# repeated and every sticker is that char, then every sticker will be used for every char of target.
# Time - O(nk log(nk) * k * s**2) every item in heap created by taking every char of sticker, testing for char in while n:
# target, then remving from sticker.
if n % 2 == bit: # next bit is same as current bit
import heapq return False
from collections import defaultdict
n, bit = divmod(n, 2)
class Solution(object):
def minStickers(self, stickers, target): return True
"""
:type stickers: List[str]
:type target: str # python_1_to_1000/694_Number_of_Distinct_Islands.py - m
:rtype: int
""" _author_ = 'jake'
target_set, remaining_target = set(target), set(target) _project_ = 'leetcode'
char_to_word = defaultdict(set) # map char to set of words, where each word is a tuple of cleaned chars
# https://leetcode.com/problems/number-of-distinct-islands/
for sticker in stickers: # Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected
cleaned = tuple(x for x in sticker if x in target_set) # remove chars that are not in target # 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.
sticker_set = set(cleaned) # Count the number of distinct islands. An island is considered to be the same as another if and only if one island
for c in sticker_set: # can be translated (and not rotated or reflected) to equal the other.
char_to_word[c].add(cleaned)
remaining_target -= sticker_set # For each non-empty cell, breadth-first search for all adjacent non-empty cells. BFS by creating a queue of cells
# with positions relative to first cell, setting each cell to empty as it is found. Return tuple of relative positions
if remaining_target: # which are counted in a set.
return -1 # Time - O(mn)
# Space - O(mn)
heap = [(0, len(target), list(target))] # using a list for target allows remove
class Solution(object):
def numDistinctIslands(self, grid):
""" class Solution(object):
:type grid: List[List[int]] def countBinarySubstrings(self, s):
:rtype: int """
""" :type s: str
if not grid or not grid[0]: :rtype: int
return 0 """
seq, prev_seq = 1, 0 # lengths of the current and previous sequences
rows, cols = len(grid), len(grid[0]) count = 0

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

return tuple(queue) _author_ = 'jake'


_project_ = 'leetcode'
islands = set()
for r in range(rows): # https://leetcode.com/problems/degree-of-an-array/
for c in range(cols): # Given a non-empty array of non-negative integers nums, the degree of this array is defined as the maximum frequency
if grid[r][c] == 0: # of any one of its elements.
continue # Your task is to find the smallest possible length of a (contiguous) subarray of nums that has the same degree as nums.
islands.add(BFS(r, c))
# Count the frequency of each num and record its first and last index. Then find the num or nums with the largest count.
return len(islands) # Finally, find the shortest distance between first and last indices of each maximum count num.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/695_Max_Area_of_Island.py - m
from collections import defaultdict
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def findShortestSubArray(self, nums):
# https://leetcode.com/problems/max-area-of-island/ """
# Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected :type nums: List[int]
# 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. :rtype: int
# Find the maximum area of an island in the given 2D array. (If there is no island, the maximum area is 0.) """
counts, limits = defaultdict(int), {}
# Iterate over grid. If cell == 1 then perform depth-first search, setting cells to zero so they are not revisited.
# Time - O(mn) for i, num in enumerate(nums):
# Space - O(1), modifies input grid
counts[num] += 1
class Solution(object):
def maxAreaOfIsland(self, grid): if num not in limits:
""" limits[num] = [i, i] # first and last indices are both i
:type grid: List[List[int]] else:
:rtype: int limits[num][-1] = i # new last index of i
"""
rows, cols = len(grid), len(grid[0]) max_count, max_nums = 0, [] # list of nums with max_count
neighbours = [(1, 0), (-1, 0), (0, 1), (0, -1)] for num, count in counts.items():
max_area = 0
if count == max_count:
def island_area(r, c): max_nums.append(num) # new num with same max_count
elif count > max_count:
grid[r][c] = 0 max_nums = [num] # new unique max
area = 1 max_count = count

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)

return area return shortest

for row in range(rows):


for col in range(cols): # python_1_to_1000/698_Partion_to_K_Equal_Sum_Subsets.py - m
if grid[row][col] == 1: # check only occupied cells
max_area = max(max_area, island_area(row, col)) _author_ = 'jake'
_project_ = 'leetcode'
return max_area
# https://leetcode.com/problems/partition-to-k-equal-sum-subsets/
# Given an array of integers nums and a positive integer k, find whether it's possible to divide this array into k
# python_1_to_1000/696_Count_Binary_Substrings.py # non-empty subsets whose sums are all equal.

_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

def dfs(subsets, last, partial):


# python_1_to_1000/700_Search_in_a_Binary_Search_Tree.py
if subsets == 1: # base case, can always create one subset
return True _author_ = 'jake'
_project_ = 'leetcode'
if partial == target: # start a new subset
return dfs(subsets - 1, 0, 0) # https://leetcode.com/problems/search-in-a-binary-search-tree/
# Given the root node of a binary search tree (BST) and a value.
for i in range(last, len(nums)): # from last num onwards # You need to find the node in the BST that the node's value equals the given value.
# Return the subtree rooted with that node. If such node doesn't exist, you should return None.
if not used[i] and partial + nums[i] <= target:
used[i] = True # At each node, return if node has target val else recurse right or left depending whether val is greater or less than
if dfs(subsets, i + 1, partial + nums[i]): # only search smaller nums # node.val.
return True # Time - O(n)
used[i] = False # Space - O(n)

return False class Solution(object):


def searchBST(self, root, val):
return dfs(k, 0, 0) """
:type root: TreeNode
:type val: int
class Solution2(object): :rtype: TreeNode
def canPartitionKSubsets(self, nums, k): """
total = sum(nums) if not root: # val is not in tree
nums.sort(reverse = True) return None
target = total // k
if total % k != 0 or nums[0] > target: if root.val == val:
return False return root

partition = [0 for _ in range(k)] if val > root.val:


return self.searchBST(root.right, val)
def helper(i): # test whether nums[i] can be added to some partition return self.searchBST(root.left, val)
if i == len(nums):
return True
# python_1_to_1000/701_Insert_into_a_Binary_Search_Tree.py - m
for j in range(len(partition)):
if partition[j] + nums[i] <= target: _author_ = 'jake'
partition[j] += nums[i] _project_ = 'leetcode'
if helper(i + 1):
return True # https://leetcode.com/problems/insert-into-a-binary-search-tree/
partition[j] -= nums[i] # Given the root node of a binary search tree (BST) and a value to be inserted into the tree, insert the value into
if partition[j] == 0: # do not try other empty buckets # the BST. Return the root node of the BST after the insertion.
break # It is guaranteed that the new value does not exist in the original BST.
# Note that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion.
return False # You can return any of them.

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)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def insertIntoBST(self, root, val):
"""
# https://leetcode.com/problems/falling-squares/ :type root: TreeNode
# On an infinite number line (x-axis), we drop given squares in the order they are given. :type val: int
# The i-th square dropped (positions[i] = (left, side_length)) is a square with the left-most point being :rtype: TreeNode
# positions[i][0] and sidelength positions[i][1]. """
# The square is dropped with the bottom edge parallel to the number line, and from a higher height than all currently new_node = TreeNode(val)
# landed squares. We wait for each square to stick before dropping the next. if not root:
# The squares are infinitely sticky on their bottom edge, and will remain fixed to any positive length surface they return new_node
# touch (either the number line or another square). Squares dropped adjacent to each other will not stick together
# prematurely. node = root
# Return a list ans of heights. Each height ans[i] represents the current highest height of any square we have
# dropped, after dropping squares represented by positions[0], positions[1], ..., positions[i]. while True:

# 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

val = reader.get(mid) return -1


if target == val:
return mid
if target > val: # python_1_to_1000/705_Design_HashSet.py
left = mid + 1
else: _author_ = 'jake'
right = mid - 1 _project_ = 'leetcode'

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)]

import heapq def hash_function(self, key):


return key % self.size # could use builtin hash() for other objects
class KthLargest(object):
def add(self, key):
def __init__(self, k, nums): """
""" :type key: int
:type k: int :rtype: void
:type nums: List[int] """
""" if not self.contains(key): # do not add if key already present
heapq.heapify(nums) self.hashset[self.hash_function(key)].append(key)
while len(nums) > k:
heapq.heappop(nums) def remove(self, key):
self.k = k """
self.nums = nums :type key: int
:rtype: void
def add(self, val): """
""" if self.contains(key): # do not remove if key not present
:type val: int self.hashset[self.hash_function(key)].remove(key)
:rtype: int
""" def contains(self, key):
if len(self.nums) == self.k and val <= self.nums[0]: # heap full and val does not chahnge kth largest """
return self.nums[0] Returns true if this set contains the specified element
:type key: int
heapq.heappush(self.nums, val) :rtype: bool
if len(self.nums) > self.k: """
heapq.heappop(self.nums) return key in self.hashset[self.hash_function(key)] # check inner list
return self.nums[0]

# python_1_to_1000/706_Design_HashMap.py

# python_1_to_1000/704_Binary_Search.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/design-hashmap/
# Design a HashMap without using any built-in hash table libraries.

# To be specific, your design should include these functions: self.list = []


# put(key, value) : Insert a (key, value) pair into the HashMap. If the value already exists, update the value.
# get(key): Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key. def get(self, index):
# remove(key) : Remove the mapping for the value key if this map contains the mapping for the key. """
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
# Use a list of size 10000 becasue there are at most 10000 additions and so a reasonable number of collisions. :type index: int
# Eech bucket of the list stores a list of [key, value] pairs where the key hashes to the bucket index. :rtype: int
# Time - O(1) average case """
# Space - O(n) if index >= len(self.list):
return -1
class MyHashMap(object): return self.list[index]

def __init__(self): def addAtHead(self, val):


""" """
Initialize your data structure here. Add a node of value val before the first element of the linked list.
""" After the insertion, the new node will be the first node of the linked list.
self.size = 10000 :type val: int
self.hashmap = [[] for _ in range(self.size)] :rtype: void
"""
def put(self, key, value): self.list = [val] + self.list
"""
value will always be non-negative. def addAtTail(self, val):
:type key: int """
:type value: int Append a node of value val to the last element of the linked list.
:rtype: void :type val: int
""" :rtype: void
bucket, index = self.key_index(key) """
if index == -1: self.list.append(val)
self.hashmap[bucket].append([key, value])
else: def addAtIndex(self, index, val):
self.hashmap[bucket][index][1] = value """
Add a node of value val before the index-th node in the linked list.
def get(self, key): If index equals to the length of linked list, the node will be appended to the end of linked list.
""" If index is greater than the length, the node will not be inserted.
Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key :type index: int
:type key: int :type val: int
:rtype: int :rtype: void
""" """
bucket, index = self.key_index(key) if index > len(self.list):
return -1 if index == -1 else self.hashmap[bucket][index][1] return
self.list.insert(index, val)
def remove(self, key):
""" def deleteAtIndex(self, index):
Removes the mapping of the specified value key if this map contains a mapping for the key """
:type key: int Delete the index-th node in the linked list, if the index is valid.
:rtype: void :type index: int
""" :rtype: void
bucket, index = self.key_index(key) """
if index != -1: if index >= len(self.list):
del self.hashmap[bucket][index] return
del self.list[index]
def hash_function(self, key):
return key % self.size
# python_1_to_1000/708_Insert_into_a_Cyclic_Sorted_List.py - m
def key_index(self, key): # return the bucket that a key belongs to and its index if present else -1
bucket = self.hash_function(key) _author_ = 'jake'
pairs = self.hashmap[bucket] _project_ = 'leetcode'
for i in range(len(pairs)):
if pairs[i][0] == key: # https://leetcode.com/problems/insert-into-a-cyclic-sorted-list/
return (bucket, i) # Given a node from a cyclic linked list which is sorted in ascending order, write a function to insert a value into
return (bucket, -1) # the list such that it remains a cyclic sorted list. The given node can be a reference to any single node in the list,
# and may not be necessarily the smallest value in the cyclic list.
# If there are multiple suitable places for insertion, you may choose any place to insert the new value.
# python_1_to_1000/707_Design_Linked_List.py - m # After the insertion, the cyclic list should remain sorted.
# If the list is empty (i.e., given node is null), you should create a new single cyclic list and return the reference
_author_ = 'jake' # to that single node. Otherwise, you should return the original given node.
_project_ = 'leetcode'
# Iterate along the list handling 3 cases,
# https://leetcode.com/problems/design-linked-list/ # 1) Increasing node values - insert if insertVal is between (inclusive) node and node.next
# Design your implementation of the linked list. You can choose to use the singly linked list or the doubly linked list. # 2) Decreasing node values - insert if insertVal is >= node.val or <= node.next.val, i.e. beyond the range
# A node in a singly linked list should have two attributes: val and next. val is the value of the current node, and # 3) Same node values - insert if revisiting start, since all nodes have the same value
# next is a pointer/reference to the next node. If you want to use the doubly linked list, you will need one more # Time - O(n)
# attribute prev to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed. # Space - O(1)
# Implement these functions in your linked list class:
# get(index) : Get the value of the index-th node in the linked list. If the index is invalid, return -1. class Solution(object):
# addAtHead(val) : Add a node of value val before the first element of the linked list. def insert(self, head, insertVal):
# After the insertion, the new node will be the first node of the linked list. """
# addAtTail(val) : Append a node of value val to the last element of the linked list. :type head: Node
# addAtIndex(index, val) : Add a node of value val before the index-th node in the linked list. :type insertVal: int
# If index equals to the length of linked list, the node will be appended to the end of linked list. :rtype: Node
# If index is greater than the length, the node will not be inserted. """
# deleteAtIndex(index) : Delete the index-th node in the linked list, if the index is valid. if not head: # list is empty, return node referencing itself
new_node = Node(insertVal, None)
# Use a list. Alternatively define a Node class which allows addAtHead in O(1) time but O(n) get method. new_node.next = new_node
# Time - init O(1), get O(1), addAtHead O(n), addAtTail(1), addAtIndex(n), deleteAtIndex(n) return new_node
# Space - O(n)
def insert_after(node):
class MyLinkedList(object): node.next = Node(insertVal, node.next)

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

rows, cols = len(grid), len(grid[0])


# python_1_to_1000/709_To_Lower_Case.py
def BFS(base_r, base_c):
_author_ = 'jake'
_project_ = 'leetcode' grid[base_r][base_c] = 0 # set base cell as visited
queue = [(base_r, base_c)]
# https://leetcode.com/problems/to-lower-case/ for r, c in queue: # queue is extended during iteration
# Implement function ToLowerCase() that has a string parameter str, and returns the same string in lowercase.
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
# For each upper case character, convert to lower case by adding the ASCII code difference between lower and new_r, new_c = r + dr, c + dc
# upper cases.
# Time - O(n) if 0 <= new_r < rows and 0 <= new_c < cols and grid[new_r][new_c] == 1:
# Space - O(n) grid[new_r][new_c] = 0
queue.append((new_r, new_c))
class Solution(object):
def toLowerCase(self, str): canonical = [] # create a standard representation of the island
"""
:type str: str for _ in range(4): # make 8 shapes by rotation and rotation + reflection
:rtype: str queue = [(c, -r) for r, c in queue] # clockwise 90 degree rotation
""" min_r, min_c = min([r for r, _ in queue]), min([c for _, c in queue])
diff = ord("a") - ord("A") canonical = max(canonical, sorted([(r - min_r, c - min_c) for r, c in queue]))

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'

from random import randint # https://leetcode.com/problems/minimum-ascii-delete-sum-for-two-strings/


# Given two strings s1, s2, find the lowest ASCII sum of deleted characters to make two strings equal.
class Solution(object):
# Dynamic programming, similar to edit distance. Find the cost of equalising each prefix of s1 and prefix of s2.
def __init__(self, N, blacklist): # If either prefix is empty then all characters of the other prefix must be deleted. If the final chars of prefixes are
""" # equal then cost is same as for both prefixes without final chars. Else minumum cost of deleting a char from either
:type N: int # prefix.
:type blacklist: List[int] # Time - O(mn)
""" # Space - O(n)
self.white = N - len(blacklist) # number of non-black numbers
blacklist = set(blacklist) class Solution(object):
self.white_to_move = [i for i in range(self.white, N) if i not in blacklist] def minimumDeleteSum(self, s1, s2):
self.mapping = {b : self.white_to_move.pop() for b in blacklist if b < self.white} """
:type s1: str
def pick(self): :type s2: str
""" :rtype: int
:rtype: int """
""" dp = [0] # for empty prefix of s1
rand = randint(0, self.white - 1) for c in s2: # cost is all chars in prefix of s2
return self.mapping[rand] if rand in self.mapping else rand dp.append(dp[-1] + ord(c))

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)

def push(self, x):


# python_1_to_1000/715_Range_Module.py - h """
:type x: int
_author_ = 'jake' :rtype: void
_project_ = 'leetcode' """
self.stack.append((x, max(x, self.stack[-1][1])))
# https://leetcode.com/problems/range-module/
# A Range Module is a module that tracks ranges of numbers. Your task is to design and implement the following def pop(self):
# interfaces in an efficient manner. """
# addRange(int left, int right) Adds the half-open interval [left, right), tracking every real number in that :rtype: int
# interval. Adding an interval that partially overlaps with currently tracked numbers should add any numbers in """
# the interval [left, right) that are not already tracked. x, _ = self.stack.pop()
# queryRange(int left, int right) Returns true if and only if every real number in the interval [left, right) is return x
# currently being tracked.
# removeRange(int left, int right) Stops tracking every real number currently being tracked in the interval def top(self):
# [left, right). """
:rtype: int
# Maintain a list of points and whether all values from a point to the next are in a range. Binary search to find """
# the insertion point of a new range. Query by checking all points between left and right are in range. return self.stack[-1][0]
# Time - O(n) to add and remove, O(log n) to query
def peekMax(self): return low - 1
"""
:rtype: int
"""
return self.stack[-1][1] # python_1_to_1000/719_Find_K-th_Smallest_Pair_Distance.py - h

def popMax(self): _author_ = 'jake'


""" _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/find-k-th-smallest-pair-distance/
temp = [] # Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pair (A, B) is
x, target = self.stack.pop() # defined as the absolute difference between A and B.

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]

class Solution(object): while left < right:


def isOneBitCharacter(self, bits):
""" mid = (left + right) // 2
:type bits: List[int]
:rtype: bool if k_pair_distances(mid): # at least k pairs with difference of mid, search mid and lower
""" right = mid
i = 0 else:
while i < len(bits) - 1: left = mid + 1 # less than k pairs with distance mid, search above mid

if bits[i] == 1: return left


i += 1
i += 1

return i == len(bits) - 1
# python_1_to_1000/720_Longest_Word_in_Dictionary.py - m

# python_1_to_1000/718_Maximum_Length_of_Repeated_Subarray.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/longest-word-in-dictionary/
# Given a list of strings words representing an English Dictionary, find the longest word in words that can be built
# https://leetcode.com/problems/maximum-length-of-repeated-subarray/ # one character at a time by other words in words. If there is more than one possible answer, return the longest word
# Given two integer arrays A and B, return the maximum length of an subarray that appears in both arrays. # with the smallest lexicographical order.
# If there is no answer, return the empty string.
# Binary search for the largest length of a mutual subarray in A and B.
# Time - O(log(min(m, n)) * (m + n) * min(m, n)) # Map lengths of words to sets of words with the same length.
# Space - O(m**2) # For each word longer than the current candidates (initially only the empty string is a candidate), add word to
# next_candidates if its prefix without final letter is already a candidate.
class Solution(object): # Alternatively, for each word better than the longest word already found, check all prefixes in set of dictionary.
""" # Time - O(nk) for n words of maximum length k
:type A: List[int] # Space - O(nk)
:type B: List[int]
:rtype: int from collections import defaultdict
"""
def findLength(self, A, B): class Solution(object):
def longestWord(self, words):
def mutual_subarray(length): """
# make all subarrays of length in A :type words: List[str]
subarrays = set(tuple(A[i:i + length]) :rtype: str
for i in range(len(A) - length + 1)) """
# check if any of same length are also in B length_to_words = defaultdict(set)
return any(tuple(B[j:j + length]) in subarrays
for j in range(len(B) - length + 1)) for word in words: # map word lengths to set of words
length_to_words[len(word)].add(word)
low, high = 0, min(len(A), len(B)) + 1
candidates = {""} # initial candidate is the empty string
while low < high: # search for smallest length with no mutual subarray length = 0 # length of current candidates

mid = (low + high) // 2 while True:

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

for c in range(cols): for _ in range(k):


new_col = [0 for _ in range(rows)]
new_r = rows - 1 required = part_length # required length of this part
for r in range(rows - 1, -1, -1): # from bottom upwards if odd_parts > 0:
if not to_crush[r][c]: odd_parts -= 1
new_col[new_r] = board[r][c] # add to new_col if not crushed required += 1
new_r -= 1 # decrement new_r
if new_r != -1: # column has changed so update board result.append(node)
for r in range(rows): for _ in range(required):
board[r][c] = new_col[r] prev, node = node, node.next
if prev: # break link to next part
prev.next = None

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

# https://leetcode.com/problems/find-pivot-index/ _author_ = 'jake'


# Given an array of integers nums, write a method that returns the "pivot" index of this array. _project_ = 'leetcode'
# We define the pivot index as the index where the sum of the numbers to the left of the index is equal to the sum of
# the numbers to the right of the index. # https://leetcode.com/problems/number-of-atoms/
# If no such index exists, we should return -1. If there are multiple pivot indexes, you should return the left-most # Given a chemical formula (given as a string), return the count of each atom.
# pivot index. # An atomic element always starts with an uppercase character, then zero or more lowercase letters,
# representing the name.
# Iterate over nums, maintaining sums of left and right sides relative to pivot. Remove num from right, then check # 1 or more digits representing the count of that element may follow if the count is greater than 1. If the count
# whether sides have equal sums, then add num to left. # is 1, no digits will follow. For example, H2O and H2O2 are possible, but H1O2 is impossible.
# Time - O(n) # Two formulas concatenated together produce another formula. For example, H2O2He3Mg4 is also a formula.
# Space - O(1) # A formula placed in parentheses, and a count (optionally added) is also a formula. For example, (H2O2)
# and (H2O2)3 are formulas.
class Solution(object): # Given a formula, output the count of all elements as a string in the following form: the first name
def pivotIndex(self, nums): # (in sorted order), followed by its count (if that count is more than 1), followed by the second name
""" # (in sorted order), followed by its count (if that count is more than 1), and so on.
:type nums: List[int]
:rtype: int # Iterate over formula. If start of a new element, add previous element to counts. If bracket, find counts from
""" # within bracket and multiply by number after bracket.
left, right = 0, sum(nums) # sums of left and right arrays relative to pivot # Time - O(n)
# Space - O(n)
for i, num in enumerate(nums):
from collections import defaultdict
right -= num
class Solution(object):
if left == right: def countOfAtoms(self, formula):
return i """
:type formula: str
left += num # doing this last handles i == 0 better than adding previous before check :rtype: str
"""
return -1
def count_atoms(start):
counts = defaultdict(int)
# python_1_to_1000/725_Split_Linked_List_in_Parts.py - m element = None
element_count = 0
_author_ = 'jake' i = start
_project_ = 'leetcode'
while i < len(formula):
# https://leetcode.com/problems/split-linked-list-in-parts/ c = formula[i]
# Given a (singly) linked list with head node root, write a function to split the linked list into k consecutive
# linked list "parts". if "A" <= c <= "Z": # start new atom
# The length of each part should be as equal as possible: no two parts should have a size differing by more than 1. if element: # add previous atom to counts
# This may lead to some parts being null. counts[element] += element_count if element_count != 0 else 1
# The parts should be in order of occurrence in the input list, and parts occurring earlier should always have a element_count = 0
# size greater than or equal parts occurring later. element = c
# Return a List of ListNode's representing the linked list parts that are formed.
# Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ] elif "a" <= c <= "z": # add to name of current atom
element += c
# Count length and calculate part lengths. Each part is previous root, count required nodes then break link to
# next part. elif "0" <= c <= "9": # increase count of current atom
# Time - O(n) element_count = int(c) + (element_count * 10 if element_count != 0 else 0)
# Space - O(1)
elif c == "(":
# Definition for singly-linked list. bracket_count, i = count_atoms(i + 1) # get atom counts until closing bracket
class ListNode(object): bracket_multiplier = 0
def __init__(self, x): while i + 1 < len(formula) and "0" <= formula[i + 1] <= "9": # multiplier of bracket
self.val = x bracket_multiplier = bracket_multiplier * 10 + int(formula[i + 1])
self.next = None i += 1
for el, num in bracket_count.items():
class Solution(object): counts[el] += num * (bracket_multiplier if bracket_multiplier > 0 else 1)
def splitListToParts(self, root, k):
""" else: # closing bracket
:type root: ListNode if element: # add final element to counts
:type k: int counts[element] += element_count if element_count != 0 else 1
:rtype: List[ListNode] return [counts, i]
"""
node, count = root, 0 i += 1
while node: # find length of linked list
count += 1 return [counts, i]
node = node.next

formula = "(" + formula + ")"


counts = count_atoms(0)[0] return [num for num in range(left, right + 1) if is_self_dividing(num)]
return "".join([atom + (str(count) if count > 1 else "") for atom, count in sorted(counts.items())])

# 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))

for i, c in enumerate(T[1:], 1): # iterate over T if end > self.bookings[i][0]:


return False
new_matches = [] if start < self.bookings[i - 1][1]:
return False
for s_start, s_last in matches: # for each window
s_next = next_in_s[s_last][ord(c) - ord("a")] # find the next index in S matching c self.bookings.insert(i, (start, end))
if s_next != -1: return True
new_matches.append([s_start, s_next]) # update matches if c is found

if not new_matches: # python_1_to_1000/730_Count_Different_Palindromic_Subsequences.py - h


return ""
matches = new_matches _author_ = 'jake'
_project_ = 'leetcode'
# return the shortest window
start, end = min(matches, key = lambda i, j: j - i) # https://leetcode.com/problems/count-different-palindromic-subsequences/
return S[start:end + 1] # Given a string S, find the number of different non-empty palindromic subsequences in S, and return that number
# modulo 10^9 + 7.
# A subsequence of a string S is obtained by deleting 0 or more characters from S.
# python_1_to_1000/728_Self_Dividing_Numbers.py # A sequence is palindromic if it is equal to the sequence reversed.
# Two sequences A_1, A_2, ... and B_1, B_2, ... are different if there is some i for which A_i != B_i.
_author_ = 'jake'
_project_ = 'leetcode' # Top-down dynamic programming. Precompute tables of the first of each char before and after each index (inclusive).
# Calculate the solution as the number of unique character + for each character x the number of palindromes of the
# https://leetcode.com/problems/self-dividing-numbers/ # form x_x where _ is any other palindrome. Memoise results.
# A self-dividing number is a number that is divisible by every digit it contains. # Time - O(n**2)
# For example, 128 is a self-dividing number because 128 % 1 == 0, 128 % 2 == 0, and 128 % 8 == 0. # Space - O(n**2)
# Also, a self-dividing number is not allowed to contain the digit zero.
# Given a lower and upper number bound, output a list of every possible self dividing number, including the bounds. class Solution(object):
def countPalindromicSubsequences(self, S):
# Test each numbers. Repeatedly divide by 10 ro extract each digit, rejecting if original number is not divisible by """
# digit or digit is zero. :type S: str
# Time - O(n log k) where there are n numbers in range and k is the maximum number :rtype: int
# Space - O(n log n) """
NUM_LETTERS, MOD = 4, 10 ** 9 + 7
class Solution(object): S = [ord(c) - ord("a") for c in S] # convert chars to integers
def selfDividingNumbers(self, left, right): memo = {}
"""
:type left: int last_indices = [-1 for _ in range(NUM_LETTERS)]
:type right: int prev_index_letter = [None for _ in
:rtype: List[int] range(len(S))] # prev_index_letter[i][j] is the previous occurrence of
""" letter j
for i in range(len(S)): # at or before index i
def is_self_dividing(num): last_indices[S[i]] = i
prev_index_letter[i] = last_indices[:]
copy = num # make a copy since original num is also required
last_indices = [-1 for _ in range(NUM_LETTERS)]
while copy > 0: next_index_letter = [None for _ in range(len(S))] # next_index_letter[i][j] is the next occurrence of letter j
for i in range(len(S) - 1, -1, -1): # at or after index i
copy, digit = divmod(copy, 10) last_indices[S[i]] = i
if digit == 0 or num % digit != 0: next_index_letter[i] = last_indices[:]
return False
def helper(i, j): # solution for S[i:j + 1]
return True
if (i, j) in memo:
return memo[(i, j)] def __init__(self):
self.bookings = [[float("-inf"), 0], [float("inf"), 0]] # sorted list of [x, nb overlaps]
count = 1 # empty string plus single characters self.max_booking = 0 # maximum number of overlaps

for letter in range(4): def book(self, start, end):


next_index = next_index_letter[i][letter] # first occurrence of letter after or including index i """
prev_index = prev_index_letter[j][letter] # next occurrence of letter before or including index j :type start: int
:type end: int
if i <= next_index <= j: # single character palindromes :rtype: int
count += 1 """
i = bisect.bisect_left(self.bookings, [start, -1]) # find insertion index of start
if next_index != -1 and prev_index != -1 and prev_index > next_index: # string contains x_x
count += helper(next_index + 1, prev_index - 1) if self.bookings[i][0] != start: # insert if start is new x value
count = self.bookings[i - 1][1]
count %= MOD self.bookings.insert(i, [start, count + 1])
memo[(i, j)] = count self.max_booking = max(self.max_booking, count + 1)
return count i += 1

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

_author_ = 'jake' if self.bookings[i][0] != end: # insert if end is new x value


_project_ = 'leetcode' count = self.bookings[i - 1][1]
self.bookings.insert(i, [end, count - 1])
# https://leetcode.com/problems/my-calendar-ii/
# Implement a MyCalendarTwo class to store your events. A new event can be added if adding the event will not return self.max_booking
# cause a triple booking.
# Your class will have one method, book(int start, int end). Formally, this represents a booking on the half open
# interval [start, end), the range of real numbers x such that start <= x < end.
# A triple booking happens when three events have some non-empty intersection (ie., there is some time that is common
# to all 3 events.)
# For each call to the method MyCalendar.book, return true if the event can be added to the calendar successfully # python_1_to_1000/733_Flood_Fill.py
# without causing a triple booking. Otherwise, return false and do not add the event to the calendar.
# Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end) _author_ = 'jake'
_project_ = 'leetcode'
# Create unsorted lists of double bookings and events. For a new booking, return False if overlap with and double
# booking. Else check for overlap with each existing interval and if so, append overlap to doubles. # https://leetcode.com/problems/flood-fill/
# List of doubles may contain overlaps but no triple booking is permitted. # An image is represented by a 2-D array of integers, each integer representing the pixel value of the image
# Time - O(n**2) # (from 0 to 65535).
# Space - O(n) # Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value
# newColor, "flood fill" the image.
class MyCalendarTwo(object): # To perform a "flood fill", consider the starting pixel, plus any pixels connected 4-directionally to the starting
# pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with
def __init__(self): # the same color as the starting pixel), etc. Replace the color of all of the aforementioned pixels with the newColor.
self.doubles = [] # intervals with double bookings # At the end, return the modified image.
self.intervals = [] # all intervals
# Depth-first search. Find startColor or sr, sc. If this is the same as newColor, return image unchanged (or else
def book(self, start, end): # the while loop may not terminate). Stack contains pixels to be explored. Pop the next unexplored cell and if a
""" # valid cell of startColor then change its colour and add neighbours to the stack.
:type start: int # Time - O(mn)
:type end: int # Space - O(mn)
:rtype: bool
""" class Solution(object):
for i, j in self.doubles: # check overlap with existing double bookings def floodFill(self, image, sr, sc, newColor):
if start < j and end > i: """
return False :type image: List[List[int]]
:type sr: int
for i, j in self.intervals: # check overlap with existing bookings :type sc: int
if start < j and end > i: :type newColor: int
self.doubles.append((max(start, i), min(end, j))) :rtype: List[List[int]]
"""
self.intervals.append((start, end)) # add to list of all events rows, cols = len(image), len(image[0])

return True startColor = image[sr][sc]


if startColor == newColor:
return image

# python_1_to_1000/732_My_Calendar_III.py - h stack = [(sr, sc)]

_author_ = 'jake' while stack:


_project_ = 'leetcode'
r, c = stack.pop()
# https://leetcode.com/problems/my-calendar-iii/
# Implement a MyCalendarThree class to store your events. A new event can always be added. if r < 0 or r >= rows or c < 0 or c >= cols:
# Your class will have one method, book(int start, int end). Formally, this represents a booking on the half open continue
# interval [start, end), the range of real numbers x such that start <= x < end. if image[r][c] != startColor:
# A K-booking happens when K events have some non-empty intersection (ie., there is some time that is common to all continue
# K events.)
# For each call to the method MyCalendar.book, return an integer K representing the largest integer such that there image[r][c] = newColor
# exists a K-booking in the calendar. for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
# Your class will be called like this: MyCalendarThree cal = new MyCalendarThree(); MyCalendarThree.book(start, end) stack.append((r + dr, c + dc))

# 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

for asteroid in asteroids: elif operator == "add":


left, next_i = helper(start + 1)
while stack and stack[-1] > 0 > asteroid: # collision right, next_i = helper(next_i)
result = (left + right, next_i)
if stack[-1] == -asteroid: # destroy both
stack.pop() elif operator == "mult":
break left, next_i = helper(start + 1)
elif stack[-1] > -asteroid: # destroy asteroid right, next_i = helper(next_i)
break result = (left * right, next_i)
else: # destroy top of stack
stack.pop() elif operator == "let":
next_i = start + 1
else: # no collision between asteroid and top of stack while continue_let(next_i):
stack.append(asteroid) variable = tokens[next_i]
expression, next_i = helper(next_i + 1)
return stack scopes[-1][variable] = expression
result = helper(next_i)

# python_1_to_1000/736_Parse_Lisp_Expression.py - h else: # operator is variable


result = (scopes[-1][operator], start + 1)
# digits x and y satisfy x <= y.)
while closing_brackets > 0: # remove old scopes
closing_brackets -= 1 # Convert input to a list of integer digits. Iterate over digits. If next digit is lower than previous then move back
scopes.pop() # along digits looking for a digit that can be decreased whilst maintaining monotone increasing overall. When found,
# decrease that digit and set all subsequent digits to 9 (max possible).
return result # Time - O(n)
# Space - O(n)
# Determines whether we should continue parsing pairs of var/expression for let operator
def continue_let(i): # test for variable without closing bracket class Solution(object):
return "a" <= tokens[i][0] <= "z" and tokens[i][-1] != ")" def monotoneIncreasingDigits(self, N):
"""
return helper(0)[0] :type N: int
:rtype: int
"""
s = [int(c) for c in str(N)] # make list of digits
# python_1_to_1000/737_Sentence_Similarity_II.py - m
i = 0
_author_ = 'jake' while i + 1 < len(s):
_project_ = 'leetcode'
if s[i + 1] < s[i]: # next digit is decreasing
# https://leetcode.com/problems/sentence-similarity-ii/
# Given two sentences words1, words2 (each represented as an array of strings), and a list of similar word pairs pairs, while i > 0 and s[i] - 1 < s[i - 1]: # move back until s[i] can be decremented
# determine if two sentences are similar. i -= 1
# For example, words1 = ["great", "acting", "skills"] and words2 = ["fine", "drama", "talent"] are similar, if the
# similar word pairs are pairs = [["great", "good"], ["fine", "good"], ["acting","drama"], ["skills","talent"]]. s[i] -= 1 # decrement
# Note that the similarity relation is transitive. For example, if "great" and "good" are similar, and "fine" and s[i + 1:] = [9] * (len(s) - i - 1) # all else set to 9
# "good" are similar, then "great" and "fine" are similar.
# Similarity is also symmetric. For example, "great" and "fine" being similar is the same as "fine" and "great" result = 0
# being similar. for val in s:
# Also, a word is always similar with itself. For example, the sentences words1 = ["great"], words2 = ["great"], result = result * 10 + val
# pairs = [] are similar, even though there are no specified similar word pairs. return result
# Finally, sentences can only be similar if they have the same number of words. So a sentence like words1 = ["great"]
# can never be similar to words2 = ["doubleplus","good"]. else:
i += 1
# Union-find. Create tree linking each word to its parent. Find parents of new words by moving up tree, collapsing
# links from parent to grandparent. If either word is not in tree then make its parent the parent of the other word. return N # N is monotone increasing
# Time - O((n + p) log p ), len(words1) = n and len(pairs) = w2. p log p to create mapping + n log p to check.
# Space - O(n)
# python_1_to_1000/739_Daily_Temperatures.py - m
class Solution(object):
def areSentencesSimilarTwo(self, words1, words2, pairs): _author_ = 'jake'
""" _project_ = 'leetcode'
:type words1: List[str]
:type words2: List[str] # https://leetcode.com/problems/daily-temperatures/
:type pairs: List[List[str]] # Given a list of daily temperatures, produce a list that, for each day in the input, tells you how many days you
:rtype: bool # would have to wait until a warmer temperature. If there is no future day for which this is possible, put 0 instead.
""" # For example, given the list temperatures = [73, 74, 75, 71, 69, 72, 76, 73], your output should be
def find(word): # [1, 1, 4, 2, 1, 1, 0, 0]
if word not in mapping:
return None # Stack contains previous temperatures that do not have a higher temperature, hence is descending. Iterate over
while mapping[word] != word: # temperatures, popping off all lower temperatures and updating their results. Then add new temperature and its
mapping[word] = mapping[mapping[word]] # collapse link from parent to grandparent # index to stack.
word = mapping[word] # move up # Time - O(n)
return word # Space - O(n)

if len(words1) != len(words2): # early return class Solution(object):


return False def dailyTemperatures(self, temperatures):
mapping = {} # map word to its parent, which maybe itself """
:type temperatures: List[int]
for w1, w2 in pairs: :rtype: List[int]
p1, p2 = find(w1), find(w2) """
if p1: result = [0 for _ in range(len(temperatures))]
if p2:
mapping[p1] = p2 # may already be equal stack = []
else:
mapping[w2] = p1 # insert mapping for w1 for i, temp in enumerate(temperatures):
else:
if p2: while stack and stack[-1][0] < temp: # pop and set result for all lower previous temperatures
mapping[w1] = p2 # insert mapping for w2 _, prev_i = stack.pop()
else: result[prev_i] = i - prev_i
mapping[w1] = mapping[w2] = w1 # new pair separated from other mappings
stack.append((temp, i))
for w1, w2 in zip(words1, words2):
return result
if w1 == w2:
continue
# python_1_to_1000/740_Delete_and_Earn.py - m
p1, p2 = find(w1), find(w2)
if not p1 or not p2 or p1 != p2: # no or different parents _author_ = 'jake'
return False _project_ = 'leetcode'

return True # https://leetcode.com/problems/delete-and-earn/


# Given an array nums of integers, you can perform operations on the array.
# In each operation, you pick any nums[i] and delete it to earn nums[i] points.
# After, you must delete every element equal to nums[i] - 1 or nums[i] + 1.
# python_1_to_1000/738_Monotone_Increasing_Digits.py - m # You start with 0 points. Return the maximum number of points you can earn by applying such operations.

_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)

# Space - O(n) _author_ = 'jake'


_project_ = 'leetcode'
from collections import Counter
# https://leetcode.com/problems/closest-leaf-in-a-binary-tree/
class Solution(object): # Given a binary tree where every node has a unique value, and a target key k, find the value of the nearest leaf node
def deleteAndEarn(self, nums): # to target k in the tree. Here, nearest to a leaf means the least number of edges travelled on the binary tree to
""" # reach any leaf of the tree. Also, a node is called a leaf if it has no children.
:type nums: List[int] # There exists some node in the given binary tree for which node.val == k.
:rtype: int
""" # Bottom-up recursion through the tree to find the closest leaf to every node when moving downwards to subtrees.
freq = Counter(nums) # The recurse through the tree again, updating closest leaves for cases that best path is via parent.
pairs = [(num, count) for num, count in freq.items()] # Time - O(n)
pairs.sort() # Space - O(n)

used, not_used = 0, 0 class Solution(object):


def findClosestLeaf(self, root, k):
for i, (num, count) in enumerate(pairs): """
:type root: TreeNode
if i == 0 or pairs[i - 1][0] != num - 1: # no previous noum or not num - 1 :type k: int
not_used = max(used, not_used) # choose max :rtype: int
used = num * count + not_used # add point from this num """
else: nearest_leaves = {0: (float("inf"), 0)} # key is node.val, value is (distance to leaf, leaf.val)
used, not_used = num * count + not_used, max(used, not_used)
def closest_down(node): # create mapping for closes leaf node via subtrees
return max(used, not_used)
if not node:
return (float("inf"), 0)

# python_1_to_1000/741_Cherry_Pickup.py - h if not node.left and not node.right: # node is a leaf


result = (0, node.val)
_author_ = 'jake' else:
_project_ = 'leetcode' left_dist, left_nearest = closest_down(node.left)
right_dist, right_nearest = closest_down(node.right)
# https://leetcode.com/problems/cherry-pickup/ if left_dist <= right_dist: # closest leaf is via left subtree
# In a N x N grid representing a field of cherries, each cell is one of three possible integers. result = (left_dist + 1, left_nearest)
# 0 means the cell is empty, so you can pass through; else:
# 1 means the cell contains a cherry, that you can pick up and pass through; result = (right_dist + 1, right_nearest)
# -1 means the cell contains a thorn that blocks your way.
# Your task is to collect maximum number of cherries possible by following the rules below: nearest_leaves[node.val] = result
# Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid path cells return result
# (cells with value 0 or 1);
# After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells; def closest(node, parent_val): # update the mapping for nodes with closer leaves via parents
# When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0);
# If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected. if not node:
return
# Instead of one person traversing there and back, consider two persons traversing simultaneously.
# The column of the second person is fixed by the position of the first person (which determines the number of steps if 1 + nearest_leaves[parent_val][0] < nearest_leaves[node.val][0]: # closer leaf via parent
# taken) and the row of the second person, since both have taken the same number of steps. nearest_leaves[node.val] = (1 + nearest_leaves[parent_val][0], nearest_leaves[parent_val][1])
# Top-down dynamic programming with 3 degrees of freedom. There are 4 cases of each person moving down or across.
# Time - O(n**3) closest(node.left, node.val)
# Space - O(n**3) closest(node.right, node.val)

class Solution(object): closest_down(root)


def cherryPickup(self, grid): closest(root, 0)
""" return nearest_leaves[k][1]
:type grid: List[List[int]]
:rtype: int
""" # python_1_to_1000/743_Network_Delay_Time.py - m
n = len(grid)
memo = {} _author_ = 'jake'
_project_ = 'leetcode'
def helper(r1, c1, r2):
# https://leetcode.com/problems/network-delay-time/
c2 = r1 + c1 - r2 # There are N network nodes, labelled 1 to N.
# Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is the source node, v is the
if r1 == n or c1 == n or r2 == n or c2 == n: # out of bounds # target node, and w is the time it takes for a signal to travel from source to target.
return float("-inf") # Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal?
if grid[r1][c1] == -1 or grid[r2][c2] == -1: # either person is on a thorn # If it is impossible, return -1.
return float("-inf")
# Initialise the best time to reach each node as infinity apart from 0 for node K. Create a set of all nodes, find the
if r1 == n - 1 and c1 == n - 1: # both paths at end cell # node in the set with the smallest time to reach and remove it from the set, since this time cannot be improved by
return grid[n - 1][n - 1] # going via another node with a greater time to reach. Update the times to reach all neighbours. Repeat removing
# closest node until all nodes have been tested or closest node cannot bee reached by other nodes.
if (r1, c1, r2) in memo: # Time - O(n**2 + e) where n is nb nodes and e is nb edges
return memo[(r1, c1, r2)] # Space - O(n + e)

result = grid[r1][c1] # cherry from first person class Solution(object):


if r2 != r1 or c2 != c1: # if people not in same position def networkDelayTime(self, times, N, K):
result += grid[r2][c2] # add cherry from second person """
:type times: List[List[int]]
result += max(helper(r1 + 1, c1, r2 + 1), helper(r1, c1 + 1, r2), :type N: int
helper(r1 + 1, c1, r2), helper(r1, c1 + 1, r2 + 1)) :type K: int
:rtype: int
memo[(r1, c1, r2)] = result """
return result best_times = [float("inf") for _ in range(N + 1)] # best time for signal to reach any node
best_times[K] = 0
return max(0, helper(0, 0, 0)) # convert -inf (no solution) to zero
network = [[] for _ in range(N + 1)] # map nodes to list of (nbor, time)
for u, v, w in times:
network[u].append((v, w))

# python_1_to_1000/742_Closest_Leaf_in_a_Binary_Tree.py - m nodes = {n for n in range(1, N + 1)} # set of all nodes to be tested


while nodes: node = node[1][ord(c) - ord("a")]
node[0].add(word)
best_time = float("inf")
for node in nodes: # find the remaining node with smallest time for weight, word in enumerate(words):
if best_times[node] < best_time: self.weights[word] = weight
best_time = best_times[node] insert(word, True)
next_node = node insert(word, False)

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) """

return max(best_times[1:]) # ignore best_times[0] def find_words(word, forwards):


if forwards:
node = self.prefix_root
# python_1_to_1000/744_Find_Smallest_Letter_Greater_Than_Target.py iterate_word = word
else:
_author_ = 'jake' node = self.suffix_root
_project_ = 'leetcode' iterate_word = word[::-1]

# https://leetcode.com/problems/find-smallest-letter-greater-than-target/ for c in iterate_word:


# Given a list of sorted characters letters containing only lowercase letters, and given a target letter target, node = node[1][ord(c) - ord("a")]
# find the smallest element in the list that is larger than the given target. if not node:
# Letters also wrap around. For example, if the target is target = 'z' and letters = ['a', 'b'], the answer is 'a'. return -1 # early return if cannot match whole prefix or suffix
return node[0]
# Binary search for the next greater letter.
# Time - O(log n) prefix_matches = find_words(prefix, True)
# Space - O(1) suffix_matches = find_words(suffix, False)
if prefix_matches == -1 or suffix_matches == -1:
class Solution(object): return -1
def nextGreatestLetter(self, letters, target):
""" matches = prefix_matches & suffix_matches
:type letters: List[str] weight = -1
:type target: str for match in matches:
:rtype: str weight = max(weight, self.weights[match])
""" return weight
left, right = 0, len(letters) # initial search space is first letter to beyond last letter (inclusive)

while left < right: # stop if left == right # python_1_to_1000/746_Min_Cost_Climbing_Stairs.py

mid = (left + right) // 2 _author_ = 'jake'


_project_ = 'leetcode'
if target >= letters[mid]: # search RHS excluding mid
left = mid + 1 # https://leetcode.com/problems/min-cost-climbing-stairs/
else: # mid could be next greater letter # On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed).
right = mid # Once you pay the cost, you can either climb one or two steps. You need to find minimum cost to reach the top of
# the floor, and you can either start from the step with index 0, or the step with index 1.
letters.append(letters[0]) # handle wrap around
return letters[left] # Dynamic programming. Track the cost of reaching each step and the previous step. The cost of reaching any step is
# the cost of that step plus the lower cost of reaching the precious 2 steps.
# Time - O(n)
# python_1_to_1000/745_Prefix_and_Suffix_Search.py - h # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def minCostClimbingStairs(self, cost):
"""
# https://leetcode.com/problems/prefix-and-suffix-search/ :type cost: List[int]
# Given many words, words[i] has weight i. :rtype: int
# Design a class WordFilter that supports one function, WordFilter.f(String prefix, String suffix). """
# It will return the word with given prefix and suffix with maximum weight. If no word exists, return -1. prev, step = cost[:2]

# 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)]]

for i, num in enumerate(nums[1:], 1):


for dr, dc in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
if num >= nums[first_i]: r1, c1 = r + dr, c + dc
first_i, second = i, nums[first_i] # update first_i and second if r1 < 0 or r1 >= rows or c1 < 0 or c1 >= cols:
elif num > second: continue
second = num if grid[r1][c1] == 2: # ignore, already contained
continue
return first_i if nums[first_i] >= 2 * second else -1 # check if first is at least twice second if grid[r1][c1] == 0: # add to nbors and increase wall count
nbors.add((r1, c1))
walls[0] += 1
# python_1_to_1000/748_Shortest_Completing_Word.py else:
get_nbors(r1, c1) # recurse
_author_ = 'jake'
_project_ = 'leetcode' def contain_region(r, c): # set all cells in a region to 2 to indicate contained
if r < 0 or r >= rows or c < 0 or c >= cols:
# https://leetcode.com/problems/shortest-completing-word/ return
# Find the minimum length word from a given dictionary words, which has all the letters from the string licensePlate. if grid[r][c] != 1:
# Such a word is said to complete the given string licensePlate return
# Here, for letters we ignore case. For example, "P" on the licensePlate still matches "p" on the word. grid[r][c] = 2
# It is guaranteed an answer exists. If there are multiple answers, return the one that occurs first in the array. for dr, dc in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
# The license plate might have the same letter occurring multiple times. For example, given a licensePlate of "PP", contain_region(r + dr, c + dc)
# the word "pair" does not complete the licensePlate, but the word "supper" does.
while True:
# Count frequency fo each letter in licensePlate. Sort words in ascending order of length. For each word, count the regions = []
# frequency of each letter. If every letter in licensePlate has the same number or more copies in a word then return visited = set()
# that word. Although sorting has worse time complexity, it is practically faster for the test cases than scanning the
# unsorted words. for r in range(rows):
# Time - O(kn log n) to sort for n log n comparisons, each taking O(k) for n strings of length k. for c in range(cols):
# Space - O(kn) # for each viral region, find its neighbouring empty cells and walls required
if (r, c) not in visited and grid[r][c] == 1:
from collections import Counter nbors, walls = set(), [0]
get_nbors(r, c)
class Solution(object): regions.append([(r, c), set(nbors), walls[0]])
def shortestCompletingWord(self, licensePlate, words):
""" regions.sort(key = lambda x: -len(x[1])) # sort by most neighbours
:type licensePlate: str
:type words: List[str] if not regions or len(regions[0][1]) == 0: # all contained or fully infected
:rtype: str return used_walls
"""
letters = [c.lower() for c in licensePlate if c > "9"] # remove digits and space used_walls += regions[0][2] # contain first region
freq = Counter(letters) contain_region(regions[0][0][0], regions[0][0][1])

words.sort(key=lambda x: len(x)) for _, expansion, _ in regions[1:]: # infect neighbours of other regions


for r, c in expansion:
for word in words: grid[r][c] = 1

if len(word) < len(letters): # ignore words that are too short


continue

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)

results.append(num_to_ip(ip_num) + "/" + str(mask)) class Solution(object):


ip_num += 1 << (32 - mask) """
n -= 1 << (32 - mask) :type n: int
:type k: int
return results :rtype: str
"""
def crackSafe(self, n, k):
# python_1_to_1000/752_Open_the_Lock.py - m
seen = set()
_author_ = 'jake' digits = [str(i) for i in range(k)]
_project_ = 'leetcode' result = []

# https://leetcode.com/problems/open-the-lock/ def dfs(node):


# You have a lock in front of you with 4 circular wheels. for x in digits:
# Each wheel has 10 slots: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'. pattern = node + x
# The wheels can rotate freely and wrap around: for example we can turn '9' to be '0', or '0' to be '9'. if pattern not in seen:
# Each move consists of turning one wheel one slot. seen.add(pattern)
# The lock initially starts at '0000', a string representing the state of the 4 wheels. dfs(pattern[1:])
# You are given a list of deadends dead ends, meaning if the lock displays any of these codes, the wheels of the lock result.append(x)
# will stop turning and you will be unable to open it.
# Given a target representing the value of the wheels that will unlock the lock, return the minimum total number of dfs("0" * (n - 1))
# turns required to open the lock, or -1 if it is impossible. return "".join(result) + "0" * (n - 1)

# 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:

target += steps + 1 # take one more step


if target % 2 == 0: class Solution(object):
return steps + 1 def pyramidTransition(self, bottom, allowed):
"""
return steps + 2 # take one more step, must now be an even distance from target :type bottom: str
:type allowed: List[str]
:rtype: bool
"""
# python_1_to_1000/755_Pour_Water.py - m triangles = defaultdict(list)
for triple in allowed:
_author_ = 'jake' triangles[triple[:-1]].append(triple[-1])
_project_ = 'leetcode'
def helper(prev, current): # inputs are the previous row and the (partial) current row
# https://leetcode.com/problems/pour-water/
# We are given an elevation map, heights[i] representing the height of the terrain at that index. The width at each if len(prev) == 1: # finished pyramid
# index is 1. After V units of water fall at index K, how much water is at each index? return True
# Water first drops at index K and rests on top of the highest terrain or water at that index. Then, it flows n = len(current)
# according to the following rules: if n == len(prev) - 1: # start a new row
# If the droplet would eventually fall by moving left, then move left. return helper(current, "")
# Otherwise, if the droplet would eventually fall by moving right, then move right.
# Otherwise, rise at it's current position. colours = triangles[prev[n:n + 2]] # allowed next blocks
# Here, "eventually fall" means that the droplet will eventually be at a lower level if it moves in that direction. if not colours:
# Also, "level" means the height of the terrain plus any water in that column. return False
# We can assume there's infinitely high terrain on the two sides out of bounds of the array. Also, there could not be
# partial water being spread out evenly on more than 1 grid block - each unit of water has to be in exactly one block. for colour in colours:
if helper(prev, current + colour):
# For each drop, move left until the next index is higher, recording the lowest index. If the drop has fallen, update return True
# heights. Else follow the same procedure on the right. If the drop has not fallen on the right, put it at index K. return False
# Time - O(Vn) where len(heights) == n
# Space - O(n) return helper(bottom, "")

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

return heights[1:-1] return len(intersection)

# python_1_to_1000/756_Pyramid_Transition_Matrix.py - m # python_1_to_1000/758_Bold_Words_in_String.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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 ""

class Solution(object): balance, start = 0, 0


def employeeFreeTime(self, schedule): for i, c in enumerate(S):
"""
:type schedule: List[List[Interval]] balance += 1 if c == "1" else -1
:rtype: List[Interval] if balance == 0:
""" specials.append("1" + self.makeLargestSpecial(S[start + 1:i]) + "0")
employees = len(schedule) start = i + 1
next_start_times = [(schedule[i][0].start, 0, i) for i in range(employees)]
heapq.heapify(next_start_times) # heap of (start time, interval index, employee) specials.sort(reverse = True)
last_end_time = next_start_times[0][0] # time when last meeting ended return "".join(specials)
result = []

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/763_Partition_Labels.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/couples-holding-hands/
# N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum number of swaps so
# https://leetcode.com/problems/partition-labels/ # that every couple is sitting side by side. A swap consists of choosing any two people, then they stand up and
# A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that # switch seats.
# each letter appears in at most one part, and return a list of integers representing the size of these parts. # The people and seats are represented by an integer from 0 to 2N-1, the couples are numbered in order, the first
# couple being (0, 1), the second couple being (2, 3), and so on with the last couple being (2N-2, 2N-1).
# Map each character to its last index in S. Iterate over S, for each character update the end of the partition to be # The couples' initial seating is given by row[i] being the value of the person who is initially sitting in i-th seat.
# the later of current end and last appearance of the character. If we reach the end of the partition, add it to
# result and start new partition at next index. # Create an undirected graph where nodes are seats (holding 2 people) and edges are links to the seats of the partners
# Time - O(n) # of the people on the seat. Each node has 2 undirected edges. Walk the graph until a cycle of length k is found. It
# Space - O(n) # then takes k - 1 swaps so put couples together.
# Time - O(n)
class Solution(object): # Space - O(n)
def partitionLabels(self, S):
""" class Solution(object):
:type S: str def minSwapsCouples(self, row):
:rtype: List[int] """
""" :type row: List[int]
last = {c: i for i, c in enumerate(S)} :rtype: int
result = [] """
n = len(row) // 2 # number of couples
start, end = 0, 0 # current partition
for i, c in enumerate(S): couple_to_location = [[] for _ in range(n)] # map a couple index to current seating indices of the couple
for i, person in enumerate(row): # where seats hold 2 people together
end = max(end, last[c]) couple_to_location[person // 2].append(i // 2)
if i == end: # last appearance of all charcters in partition
result.append(end - start + 1) print(couple_to_location)
start = i + 1 # start new partition. end will be updated on next iteration. adjacency = [[] for _ in range(n)] # map seat index to the seat indices of the partners of the
for a, b in couple_to_location: # 2 people at that seat index
return result adjacency[a].append(b)
adjacency[b].append(a)

# 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):

# https://leetcode.com/problems/largest-plus-sign/ if not adjacency[start]:


# In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except those cells in the given list mines which continue
# are 0. What is the largest axis-aligned plus sign of 1s contained in the grid?
# Return the order of the plus sign. If there is none, return 0. swaps -= 1 # found a cycle
# An "axis-aligned plus sign of 1s of order k" has some center grid[x][y] = 1 along with 4 arms of length k-1 going up, a = start # starting seat index
# down, left, and right, and made of 1s. This is demonstrated in the diagrams below. Note that there could be 0s or 1s b = adjacency[start].pop() # seat index of a partner
# beyond the arms of the plus sign, only the relevant area of the plus sign is checked for 1s.
while b != start:
# Iterate over the array by row in both directions and by column in both directions (4 times in total). adjacency[b].remove(a) # remove link in other direction
# In each direction, find the longest sequence of cells without a mine. Result for each cell is the the shortest a, b = b, adjacency[b].pop() # move to next seat
# distance in any of the 4 directions.
# Time - O(N**2) return swaps
# Space - O(N**2)

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

return plus _author_ = 'jake'


_project_ = 'leetcode'

# 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)

while heap: if partition_max < min_right[i]:


partitions += 1
neg_count, letter = heapq.heappop(heap) partition_max = None

if not result or result[-1] != letter: return partitions


add_letter(letter, neg_count)
continue
# python_1_to_1000/770_Basic_Calculator_IV.py - h
if not heap: # no other letters on heap
return "" _author_ = 'jake'
_project_ = 'leetcode'
neg_count2, letter2 = heapq.heappop(heap) # use next most frequent letter
add_letter(letter2, neg_count2) # https://leetcode.com/problems/basic-calculator-iv/
heapq.heappush(heap, (neg_count, letter)) # add back most frequent with same count # Given an expression such as expression = "e + 8 - a + 5" and an evaluation map such as {"e": 1}
# (given in terms of evalvars = ["e"] and evalints = [1]), return a list of tokens representing the simplified
return "".join(result) # expression, such as ["-1*a","14"]
# An expression alternates chunks and symbols, with a space separating each chunk and symbol.
# A chunk is either an expression in parentheses, a variable, or a non-negative integer.
# python_1_to_1000/768_Max_Chunks_To_Make_Sorted_II.py - h # A variable is a string of lowercase letters (not including digits.) Note that variables can be multiple letters,
# and note that variables never have a leading coefficient or unary operator like "2x" or "-x".
_author_ = 'jake' # Expressions are evaluated in the usual order: brackets first, then multiplication, then addition and subtraction.
_project_ = 'leetcode' # For example, expression = "1 + 2 * 3" has an answer of ["7"].
# The format of the output is as follows:
# https://leetcode.com/problems/max-chunks-to-make-sorted-ii/ # For each term of free variables with non-zero coefficient, we write the free variables within a term in sorted
# Given an array arr of integers (not necessarily distinct), we split the array into some number of "chunks" # order lexicographically. For example, we would never write a term like "b*a*c", only "a*b*c".
# (partitions), and individually sort each chunk. After concatenating them, the result equals the sorted array. # Terms have degree equal to the number of free variables being multiplied, counting multiplicity.
# What is the most number of chunks we could have made? # (For example, "a*a*b*c" has degree 4.) We write the largest degree terms of our answer first, breaking ties by
# lexicographic order ignoring the leading coefficient of the term.
# Iterate from right to left, finding the minimum value to the right of each number. Then iterate from left to right # The leading coefficient of the term is placed directly to the left with an asterisk separating it from the variables
# tracking the maximum number in each partition. If the maximum is smaller or the same as all numbers to the right, # (if they exist.) A leading coefficient of 1 is still printed.
# the partition can be sorted and the whole list will be sorted. # An example of a well formatted answer is ["-2*a*a*a", "3*a*a*b", "3*b*b", "4*a", "5*c", "-6"]
# Time - O(n) # Terms (including constant terms) with coefficient 0 are not included.
# Space - O(n) # For example, an expression of "0" has an output of [].

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): """

partition_max = num if partition_max is None else max(partition_max, num) class CounterMul(Counter):

if partition_max <= min_right[i]: def __add__(self, other):


partitions += 1 self.update(other)
partition_max = None return self

return partitions def __sub__(self, other):

self.subtract(other) while i < len(s):


return self c = s[i]

def __mul__(self, other): if c in operators:


product = CounterMul() parsed.append(c)
for x in self: elif "0" <= c <= "9":
for y in other: if parsed and isinstance(parsed[-1], int): # part of previous integer
xy = tuple(sorted(x + y)) parsed[-1] = parsed[-1] * 10 + int(c)
product[xy] += self[x] * other[y] else: # start a new integer
return product parsed.append(int(c))
elif c == "(":
vals = dict(zip(evalvars, evalints)) # mapping of variables to values sublist, i = parse(i + 1)
parsed.append(sublist)
def make_counter(token): elif c == ")":
return parsed, i # parsed sub-string and index to restart from
token = str(vals.get(token, token)) # get mapping or return same token
i += 1 # ignores blank spaces
if token.isalpha():
return CounterMul({(token,): 1}) # map token to count of one return parsed, len(s)
return CounterMul({(): int(token)}) # map empty tuple to integer

# 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)

# https://leetcode.com/problems/jewels-and-stones/ parsed_s, _ = parse(0)


# You're given strings J representing the types of stones that are jewels, and S representing the stones you have. return calculate(parsed_s)
# Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels.
# The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive,
# so "a" is considered a different type of stone from "A".
# python_1_to_1000/773_Sliding_Puzzle.py - h
# Check if each stone is in jewels. Generator saves creating a list.
# Time - O(m + n) _author_ = 'jake'
# Space - O(m) _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/sliding-puzzle/


def numJewelsInStones(self, J, S): # On a 2x3 board, there are 5 tiles represented by the integers 1 through 5, and an empty square represented by 0.
""" # A move consists of choosing 0 and a 4-directionally adjacent number and swapping it.
:type J: str # The state of the board is solved if and only if the board is [[1,2,3],[4,5,0]].
:type S: str # Given a puzzle board, return the least number of moves required so that the state of the board is solved.
:rtype: int # If it is impossible for the state of the board to be solved, return -1.
"""
return sum(1 for s in S if s in set(J)) # Breadth-first search. Expand queue from board by moving to all board positions after making a swap.
# Alternatively, A* search with heap and heuristic of manhattan distance between each tile and its target location.
# Time - O(mn * mn!) since there are mn! possible boards
# python_1_to_1000/772_Basic_Calculator_III.py - h # Space - O(mn * mn!)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def slidingPuzzle(self, board):
"""
# https://leetcode.com/problems/basic-calculator-iii/ :type board: List[List[int]]
# Implement a basic calculator to evaluate a simple expression string. :rtype: int
# The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers """
# and empty spaces . nbors = [[1, 3], [0, 2, 4], [1, 5], [0, 4], [1, 3, 5], [2, 4]] # indices of neighbouring cells in linear board
# The expression string contains only non-negative integers, +, -, *, / operators , open ( and closing parentheses )
# and empty spaces. The integer division should truncate toward zero. def next_boards(b): # return list of next possible boards
# You may assume that the given expression is always valid.
i = b.index(0)
# Firstly, parse string to a list of integers, operators and sub-lists. Evaluate parsed list by creating a list of next_bds = []
# integers to be summed by using divide and multiply with the next and previous integers.
# Recursively calculate sub-lists. for nbor in nbors[i]:
# Time - O(n) b_copy = b[:] # make a copy
# Space - O(n) b_copy[i], b_copy[nbor] = b_copy[nbor], b_copy[i] # swap zero with neighbour
next_bds.append(b_copy)
class Solution(object): return next_bds
def calculate(self, s):
""" queue = [board[0] + board[1]] # convert board to linear board
:type s: str steps = 0
:rtype: int seen = set() # visited linear boards, as tuples
"""
operators = {"+", "-", "*", "/"} while queue:

def parse(i): # parse s from index i new_queue = []

parsed = [] for bd in queue:


if bd == [1, 2, 3, 4, 5, 0]:
return steps return False
seen.add(tuple(bd)) max_before_prev = max(max_before_prev, A[i - 1])
new_queue += [nb for nb in next_boards(bd) if tuple(nb) not in seen]
return True
steps += 1
queue = new_queue

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]

return remaining >= 0 return splitter(root)

max_d, min_d = distances[0], 0 # initial range for binary search


# python_1_to_1000/777_Swap_Adjacent_in_LR_String.py - m
while max_d - min_d > 10 ** -6:
_author_ = 'jake'
mid = (max_d + min_d) / 2.0 _project_ = 'leetcode'
if can_minmax_dist(mid):
max_d = mid # try smaller distances # https://leetcode.com/problems/swap-adjacent-in-lr-string/
else: # In a string composed of 'L', 'R', and 'X' characters, like "RXXLRXRXL", a move consists of either replacing one
min_d = mid # try larger distances # occurrence of "XL" with "LX", or replacing one occurrence of "RX" with "XR".
# Given the starting string start and the ending string end, return True if and only if there exists a sequence of
return max_d # moves to transform one string to the other.

# "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

class Solution(object): if c1 == "L":


def isIdealPermutation(self, A): left += 1
""" elif c1 == "R":
:type A: List[int] right += 1
:rtype: bool
""" if c2 == "L":
max_before_prev = -1 left -= 1
elif c2 == "R":
for i in range(1, len(A)): right -= 1

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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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)

import heapq class Solution(object):


def reachingPoints(self, sx, sy, tx, ty):
class Solution(object): """
def swimInWater(self, grid): :type sx: int
""" :type sy: int
:type grid: List[List[int]] :type tx: int
:rtype: int :type ty: int
""" :rtype: bool
N = len(grid) """
shifts = ((0, 1), (0, -1), (1, 0), (-1, 0)) while tx > sx and ty > sy:
frontier = [(grid[0][0], 0, 0)] # cells not explored but on edge of explored region tx, ty = tx % ty, ty % tx # either tx % ty ==
visited = {(0, 0)} # frontier and explored cells
if tx == sx and (ty - sy) % sx == 0:
max_water = 0 return True
return ty == sy and (tx - sx) % sy == 0
while True:

water, r, c = heapq.heappop(frontier) # lowest cell that is reachable # python_1_to_1000/781_Rabbits_in_Forest.py - m

max_water = max(max_water, water) _author_ = 'jake'


_project_ = 'leetcode'
if r == c == N - 1: # reached target
return max_water # https://leetcode.com/problems/rabbits-in-forest/
# In a forest, each rabbit has some color. Some subset of rabbits (possibly all of them) tell you how many other
for dr, dc in shifts: # rabbits have the same color as them. Those answers are placed in an array.
# Return the minimum number of rabbits that could be in the forest.
if r + dr < 0 or r + dr >= N or c + dc < 0 or c + dc >= N:
continue # Maintain a mapping for each colour (an integer) to the number of as yet unseen rabbits with that colour. If a rabbit
if (r + dr, c + dc) in visited: # has as many other rabbits as another rabbit already seen, then decrement the unseen count. Else increase the total
continue # count for the new colour by the rabbit plus all others.
visited.add((r + dr, c + dc)) # Time - O(n)
heapq.heappush(frontier, (grid[r + dr][c + dc], r + dr, c + dc)) # Space - O(n)

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)

p1, p2 = list(patterns) permutations = new_permutations

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()

self.min_diff = min(self.min_diff, node.val - self.prev) for nbor in graph[v]:


self.prev = node.val
if colours[nbor] is None:
inorder(node.right) colours[nbor] = not colours[v] # set to opposite colour of v
queue.append(nbor)
inorder(root)
return self.min_diff elif colours[nbor] == colours[v]: # inconsistency, cannot create bipartite graph
return False

# python_1_to_1000/784_Letter_Case_Permutation.py - m return True

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/786_K-th_Smallest_Prime_Fraction.py - m

# https://leetcode.com/problems/letter-case-permutation/ _author_ = 'jake'


# Given a string S, we can transform every letter individually to be lowercase or uppercase to create another string. _project_ = 'leetcode'
# Return a list of all possible strings we could create.
# https://leetcode.com/problems/k-th-smallest-prime-fraction/
# Start with empty list as the only result. For each char in S, if char is a digit append it ot each existing result. # A sorted list A contains 1, plus some number of primes.
# Else append the upper and lower case of char to each existing result. # Then, for every p < q in the list, we consider the fraction p/q.
# Time - O(n * 2**n), since 2**n possible results of length n # What is the K-th smallest fraction considered? Return your answer as an array of ints,
# Space - O(n * 2**n) # where answer[0] = p and answer[1] = q.

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

# the solution range < 10**-9.


# For each numerator in turn, test greater denominators to find the first fraction < mid. Next numerator starts with return -1 # destination cannot be reached
# previous denominator.
# Time - O(n ln k) where n is number of primes and k is max prime
# Space - O(1)
# python_1_to_1000/788_Rotated_Digits.py - m
class Solution(object):
def kthSmallestPrimeFraction(self, A, K): _author_ = 'jake'
""" _project_ = 'leetcode'
:type A: List[int]
:type K: int # https://leetcode.com/problems/rotated-digits/
:rtype: List[int] # X is a good number if after rotating each digit individually by 180 degrees, we get a valid number that is different
""" # from X. Each digit must be rotated - we cannot choose to leave it alone.
def count_smaller_fractions(x): # return number for fractions < x and largest such fraction # A number is valid if each digit remains a digit after rotation. 0, 1, and 8 rotate to themselves; 2 and 5 rotate to
# each other; 6 and 9 rotate to each other, the rest of the numbers do not rotate to any other number.
count, denominator, largest = 0, 1, [0, 1] # Now given a positive number N, how many numbers X from 1 to N are good?

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"}

mid = (low + high) / 2 for i in range(1, N + 1):


count, largest = count_smaller_fractions(mid)
if count < K: # insufficient fractions below mid, search larger candidates digits = set(str(i))
low = mid if not bad.intersection(digits) and opposites.intersection(digits):
else: # sufficient fractions below mid, search smaller candidates count += 1
result = largest # update largest fraction where count == K
high = mid return count

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

for _ in range(N): # python_1_to_1000/793_Preimage_Size_of_Factorial_Zeroes_Function.py - h

next_tilings = (tilings + prev_tilings + prev_one_extra) % MOD _author_ = 'jake'


next_one_extra = (2 * tilings + one_extra) % MOD _project_ = 'leetcode'

tilings, prev_tilings = next_tilings, tilings # https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/


one_extra, prev_one_extra = next_one_extra, one_extra # Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... * x, and by convention, 0! = 1.)
# For example, f(3) = 0 because 3! = 6 has no zeroes at the end, while f(11) = 2 because 11! = 39916800 has 2 zeroes
return tilings # at the end. Given K, find how many non-negative integers x have the property that f(x) = K.

# 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)

# https://leetcode.com/problems/custom-sort-string/ class Solution(object):


# S and T are strings composed of lowercase letters. In S, no letter occurs more than once. def preimageSizeFZF(self, K):
# S was sorted in some custom order previously. We want to permute the characters of T so that they match the order """
# that S was sorted. More specifically, if x occurs before y in S, then x should occur before y in the returned string. :type K: int
# Return any permutation of T (as a string) that satisfies this property. :rtype: int
"""
# Count the frequencies of all letters in T. For each letter in S, add to the result the number of copies of the letter def factorial_zeros(n): # find the number of trailing zeros in n!, as per problem 172
# in T. Finally add all copies of lteers in T that are not in S. factor = 5
# Time - O(m + n) result = 0
# Space - O(m) while factor <= n:
result += n // factor
from collections import Counter factor *= 5
return result
class Solution(object):
def customSortString(self, S, T): left, right = 0, 10 * K # solution is approximately 5 * K
"""
:type S: str while left < right: # loop until only one candidate remains
:type T: str
:rtype: str mid = (left + right) // 2
""" mid_zeros = factorial_zeros(mid)
result = [] if mid_zeros < K: # check strictly greater integers
t_count = Counter(T) left = mid + 1
else: # mid remains in range
for c in S: right = mid
result += [c] * t_count[c] # do not create strings with c * t_count[c]
del t_count[c] return 5 if factorial_zeros(right) == K else 0

for c, count in t_count.items():


result += [c] * count
return "".join(result) # python_1_to_1000/794_Valid_Tic-Tac-Toe_State.py - m

_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:

if board[0][j] == board[1][j] == board[2][j] == char: # columns lines :type B: str


lines[i] += 1 :rtype: bool
"""
for c in row: # counts if len(A) != len(B):
if c == char: return False
counts[i] += 1
return A in B + B
if board[0][0] == board[1][1] == board[2][2] == char: # diagonal
lines[i] += 1
# python_1_to_1000/797_All_Paths_From_Source_to_Target.py - m
if board[2][0] == board[1][1] == board[0][2] == char: # diagonal
lines[i] += 1 _author_ = 'jake'
_project_ = 'leetcode'
if lines[0] and lines[1]: # cannot both win
return False # https://leetcode.com/problems/all-paths-from-source-to-target/
# Given a directed, acyclic graph of N nodes. Find all possible paths from node 0 to node N-1
if lines[0] and counts[0] != counts[1]: # O wins, same number of each # and return them in any order.
return False # The graph is given as follows: the nodes are 0, 1, ..., graph.length - 1. graph[i] is a list of all nodes j for
# which the edge (i, j) exists.
if lines[1] and counts[1] != counts[0] + 1: # X wins, one more X
return False # Breadth-first search. For each partial path, extend to all neighbours of the last node. If the last node is the
# destination add a copy of path to results, else add to new partial paths.
if counts[1] - counts[0] > 1 or counts[1] - counts[0] < 0: # no winner # Time - O(n**2 * n**n) max path of length n, upper limit of n**n paths
return False # Space - O(n * n**n)

return True class Solution(object):


def allPathsSourceTarget(self, graph):
"""
# python_1_to_1000/795_Number_of_Subarrays_with_Bounded_Maximum.py - m :type graph: List[List[int]]
:rtype: List[List[int]]
_author_ = 'jake' """
_project_ = 'leetcode' paths, results = [[0]], [] # initial partial path of [0]

# https://leetcode.com/problems/number-of-subarrays-with-bounded-maximum/ while paths:


# We are given an array A of positive integers, and two positive integers L and R (L <= R).
# Return the number of (contiguous, non-empty) subarrays such that the value of the maximum array element in that new_paths = []
# subarray is at least L and at most R.
for path in paths:
# Dynamic programming. Find the number of solutions ending with each element of A. If the element is greater than R for next_node in graph[path[-1]]:
# then there are no solutions and we record the index of the latest element greater than R. If the element is less than destination = results if next_node == len(graph) - 1 else new_paths
# L then every solution ending with the previous element can be extended. If the element is between L and R inclusive destination.append(path[:] + [next_node])
# then every subarray starting after the last element greater than R is a solution.
# Time - O(n) paths = new_paths
# Space - O(1)
return results
class Solution(object):
def numSubarrayBoundedMax(self, A, L, R):
"""
:type A: List[int] # python_1_to_1000/798_Smallest_Rotation_with_Highest_Score.py - h
:type L: int
:type R: int _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
subarrays, total = 0, 0 # subarrays ending at current index, grand total # https://leetcode.com/problems/smallest-rotation-with-highest-score/
last_above_max = -1 # index of last element > R # Given an array A, we may rotate it by a non-negative integer K so that the array becomes
# A[K], A[K+1], A{K+2], ... A[A.length - 1], A[0], A[1], ..., A[K-1].
for i, num in enumerate(A): # Afterward, any entries that are less than or equal to their index are worth 1 point.
# Over all possible rotations, return the rotation index K that corresponds to the highest score we could receive.
if num > R: # If there are multiple answers, return the smallest such index K.
subarrays = 0
last_above_max = i # For each element of A, find the interval of rotation that cause the element to score a point. Increment rotations at
# index where first rotation occurs and at index after last rotation.
elif num < L: # all subarrays ending at previous index cn be extended # Iterate over rotations calculating a running sum of the number of open intervals and find the max.
total += subarrays # Time - O(n)
# Space - O(n)
else: # count subarrays ending with i and starting after last_above_max
subarrays = i - last_above_max class Solution(object):
total += subarrays def bestRotation(self, A):
"""
return total :type A: List[int]
:rtype: int
"""
n = len(A)
# python_1_to_1000/796_Rotate_String.py rotations = [0 for _ in range(n)]

_author_ = 'jake' for i, num in enumerate(A):


_project_ = 'leetcode'
min_rot = (i + 1) % n # rotate element to end of array
# https://leetcode.com/problems/rotate-string/ max_rot = (n - num + i + 1) % n # rotate past index of num
# We are given two strings, A and B. A shift of A consists of taking string A and moving the leftmost character to the
# rightmost position. For example, if A = 'abcde', then it will be 'bcdea' after one shift on A. rotations[min_rot] += 1
# Return True if and only if A can become B after some number of shifts on A. rotations[max_rot] -= 1
if min_rot > max_rot: # indices of rotation wrap around zero
# Rotation preserves length so if lengths differ there is no solution. If lengths are the same, there must be a copy of rotations[0] += 1
# A which is a substring of the concatenation of 2 copies of B.
# Alternatively, KMP algorithm performs substring search in O(n). score, max_score, best_rotation = 0, 0, 0
# Time - O(n**2) where n == len(A) == len(B)
# Space - O(n) for i, r in enumerate(rotations):
score += r
class Solution(object): if score > max_score:
def rotateString(self, A, B): max_score = score
""" best_rotation = i
:type A: str
return best_rotation _project_ = 'leetcode'

# 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)

glasses = new_glasses prev_no_swap, prev_swap = no_swap, swap

return min(glasses[query_glass], 1) return min(prev_no_swap, prev_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 = []

# python_1_to_1000/803_Bricks_Falling_When_Hit.py - h for c in word:


transformation.append(codes[ord(c) - ord("a")])
_author_ = 'jake'
_project_ = 'leetcode' morse.add("".join(transformation))

# https://leetcode.com/problems/bricks-falling-when-hit/ return len(morse)


# We have a grid of 1s and 0s; the 1s in a cell represent bricks. A brick will not drop if and only if it is directly
# connected to the top of the grid, or at least one of its (4-way) adjacent bricks will not drop.
# We will do some erasures sequentially. Each time we want to do the erasure at the location (i, j),
# the brick (if it exists) on that location will disappear, and then some other bricks may drop because of that erasure. # python_1_to_1000/805_Split_Array_With_Same_Average.py - h
# Return an array representing the number of bricks that will drop after each erasure in sequence.
_author_ = 'jake'
# Add all hits to grid, differentiating between those that hit a brick and those that are empty. Depth-first from the _project_ = 'leetcode'
# top row to flag all bricks that are still attached. Add back each brick in reverse order. If a brick added back has a
# neighbour that is attached, attach it and all connected bricks that are not already attached. # https://leetcode.com/problems/split-array-with-same-average/
# Time - O(mn) # In a given integer array A, we must move every element of A to either list B or list C.
# Space - O(mn) # B and C initially start empty.
# Return true if and only if after such a move, it is possible that the average value of B is equal to the average
class Solution(object): # value of C, and B and C are both non-empty.
def hitBricks(self, grid, hits):
""" # For the averages of B and C to be equal, they must both be the average of A.
:type grid: List[List[int]] # For each length of B from 1 to half of the length of A, find the required sum of B. If this is an integer, attempt to
:type hits: List[List[int]] # find numbers in A to make B with the required length and sum with helper function n_sum_target.
:rtype: List[int] # Time - O(n * 2**n) since O(n) lengths of B, for which each element of A may or may not be included
""" # Space - O(2**n)
rows, cols = len(grid), len(grid[0])
nbors = ((1, 0), (0, 1), (-1, 0), (0, -1)) class Solution(object):
def splitArraySameAverage(self, A):
for r, c in hits: # set to zero if a brick was hit, else set to -1 """
grid[r][c] -= 1 :type A: List[int]
:rtype: bool
def dfs(row, col): """
if row < 0 or row >= rows or col < 0 or col >= cols: def n_sum_target(n, tgt, j): # helper fn, can we find n numbers in A[j:] that sum to tgt?
return 0
if grid[row][col] != 1: if (n, tgt, j) in invalid: # already know this is impossible
return 0 return False
grid[row][col] = 2 if n == 0: # if no more numbers can be chosen,
return 1 + sum(dfs(row + dr, col + dc) for dr, dc in nbors) return tgt == 0 # then True if and only if we have exactly reached the target

for c in range(cols): for i in range(j, len(C)):


dfs(0, c)
if C[i] > tgt: # remaining numbers are at least as large because C is sorted
def connected(r, c): break
if r == 0: if n_sum_target(n - 1, tgt - C[i], i + 1): # recurse having used num in B
return True return True
return any(0 <= (r + dr) < rows and 0 <= (c + dc) < cols \
and grid[r + dr][c + dc] == 2 for dr, dc in nbors) invalid.add((n, tgt, j))
return False
result = []
for r, c in reversed(hits): n, sum_A = len(A), sum(A)
grid[r][c] += 1 invalid = set() # memoize failed attempts
if grid[r][c] == 1 and connected(r, c): C = sorted(A) # C initially contains all of A
result.append(dfs(r, c) - 1) # ignore erased brick
else: for len_B in range(1, (n // 2) + 1): # try all possible lengths of B
result.append(0)
target = sum_A * len_B / float(n)
return result[::-1] if target != int(target): # target must be an integer
continue

if n_sum_target(len_B, target, 0):


return True
# python_1_to_1000/804_Unique_Morse_Code_Words.py
return False
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/806_Number_of_Lines_To_Write_String.py
# https://leetcode.com/problems/unique-morse-code-words/
# International Morse Code defines a standard encoding where each letter is mapped to a series of dots and dashes, _author_ = 'jake'
# as follows: "a" maps to ".-", "b" maps to "-...", "c" maps to "-.-.", and so on. _project_ = 'leetcode'
# Now, given a list of words, each word can be written as a concatenation of the Morse code of each letter.
# For example, "cab" can be written as "-.-.-....-", (which is the concatenation "-.-." + "-..." + ".-"). # https://leetcode.com/problems/number-of-lines-to-write-string/
# We'll call such a concatenation, the transformation of a word. # We are to write the letters of a given string S, from left to right into lines.
# Return the number of different transformations among all words we have. # Each line has maximum width 100 units, and if writing a letter would cause the width of the line to exceed 100 units,
# it is written on the next line. We are given an array widths, an array where widths[0] is the width of 'a',
# Create the transformation of each word as a list of the transformations of each letter. # widths[1] is the width of 'b', ..., and widths[25] is the width of 'z'.
# Create a set of all transformations. # Now answer two questions: how many lines have at least one character from S,
# Time - O(n) # and what is the width used by the last such line? Return your answer as an integer list of length 2.
# Space - O(n)
# Track the current line number and its width. Start with zero lines of length 100 to handle empty S.
class Solution(object): # For each char in S, add it to the current line if there is room, else start another line.
def uniqueMorseRepresentations(self, words): # Time - O(n)
""" # Space - O(1)
:type words: List[str]
:rtype: int class Solution(object):
""" def numberOfLines(self, widths, S):
codes = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", """
"---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."] :type widths: List[int]
morse = set() :type S: str
:rtype: List[int]
for word in words: """
line, width = 0, 100 # line number and width
def helper(A, B):
for c in S:
if A <= 0 and B <= 0: # base case, both A and Bempty together
c_length = widths[ord(c) - ord("a")] return 0.5
if A <= 0: # base case, only A empty
if width + c_length > 100: # cannot fit c on this line, start a new line return 1
line += 1 if B <= 0: # base case, only B empty
width = 0 return 0

width += c_length if (A, B) in memo:


return memo[(A, B)]
return [line, width]
result = 0.25 * (helper(A - 4, B) + helper(A - 3, B - 1) + helper(A - 2, B - 2) + helper(A - 1, B - 3))
memo[(A, B)] = result
# python_1_to_1000/807_Max_Increase_to_Keep_City_Skyline.py - m return result

_author_ = 'jake' portions = math.ceil(N / float(25))


_project_ = 'leetcode' if N > 4800: #
return 1
# https://leetcode.com/problems/max-increase-to-keep-city-skyline/ return helper(portions, portions)
# In a 2 dimensional array grid, each value grid[i][j] represents the height of a building located there.
# We are allowed to increase the height of any number of buildings, by any amount (the amounts can be different for
# different buildings). Height 0 is considered to be a building as well. # python_1_to_1000/809_Expressive_Words.py - m
# At the end, the "skyline" when viewed from all four directions of the grid, i.e. top, bottom, left, and right,
# must be the same as the skyline of the original grid. A city's skyline is the outer contour of the rectangles formed _author_ = 'jake'
# by all the buildings when viewed from a distance. _project_ = 'leetcode'
# What is the maximum total sum that the height of the buildings can be increased?
# https://leetcode.com/problems/expressive-words/
# Find the maximum height in each row an each columns. For each cell in the grid, the building can be increased to the # Sometimes people repeat letters to represent extra feeling, such as "hello" -> "heeellooo", "hi" -> "hiiii".
# lower of the row and column maximum heights. # Here, we have groups, of adjacent letters that are all the same character, and adjacent characters to the group
# Time - O(mn) # are different. A group is extended if that group is length 3 or more, so "e" and "o" would be extended in the
# Space - O(m + n) # first example, and "i" would be extended in the second example.
# As another example, the groups of "abbcccaaaa" would be "a", "bb", "ccc", and "aaaa"; and "ccc" and "aaaa" are the
class Solution(object): # extended groups of that string.
def maxIncreaseKeepingSkyline(self, grid): # For some given string S, a query word is stretchy if it can be made to be equal to S by extending some groups.
""" # Formally, we are allowed to repeatedly choose a group (as defined above) of characters c, and add some number of the
:type grid: List[List[int]] # same character c to it so that the length of the group is 3 or more.
:rtype: int # Note that we cannot extend a group of size one like "h" to a group of size two like "hh" - all extensions must leave
""" # the group extended - ie., at least 3 characters long.
rows, cols = len(grid), len(grid[0]) # Given a list of query words, return the number of words that are stretchy.
row_sky = [0 for _ in range(rows)] # max heights by row
col_sky = [0 for _ in range(cols)] # max heights by col # Helper function get_groups returns the characters in a word and their group counts, in order.
# Compare the groups of S with groups of a word. All characters must match and each group cannot be larger in word and
for r in range(rows): # groups cannot be extended to be of length 2.
for c in range(cols): # Time - O(n) total length of all words and S.
row_sky[r] = max(row_sky[r], grid[r][c]) # Space - O(s + t) where s = len(s) and t is the max length of any word.
col_sky[c] = max(col_sky[c], grid[r][c])
from collections import namedtuple
increase = 0
class Solution(object):
for r in range(rows): def expressiveWords(self, S, words):
for c in range(cols): """
increase += min(row_sky[r], col_sky[c]) - grid[r][c] :type S: str
:type words: List[str]
return increase :rtype: int
"""
Groups = namedtuple("groups", ["chars", "counts"]) # lists of chars and their counts
# python_1_to_1000/808_Soup_Servings.py - m
def get_groups(word): # make Groups for word
_author_ = 'jake'
_project_ = 'leetcode' groups = Groups(chars = [], counts = [])
count = 1
# https://leetcode.com/problems/soup-servings/
# There are two types of soup: type A and type B. Initially we have N ml of each type of soup. for i, c in enumerate(word):
# There are four kinds of operations:
# Serve 100 ml of soup A and 0 ml of soup B if i == len(word) - 1 or c != word[i + 1]:
# Serve 75 ml of soup A and 25 ml of soup B groups.chars.append(c)
# Serve 50 ml of soup A and 50 ml of soup B groups.counts.append(count)
# Serve 25 ml of soup A and 75 ml of soup B count = 1
# When we serve some soup, we give it to someone and we no longer have it. else:
# Each turn, we will choose from the four operations with equal probability 0.25. count += 1
# If the remaining volume of soup is not enough to complete the operation, we will serve as much as we can. return groups
# We stop once we no longer have some quantity of both types of soup.
# Note that we do not have the operation where all 100 ml's of soup B are used first. result = 0
# Return the probability that soup A will be empty first, plus half the probability that A and B become empty at S_groups = get_groups(S)
# the same time.
# Answers within 10^-6 of the true value will be accepted as correct. for word in words:

# 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 = {}

return result """


:type points: List[List[int]]
:rtype: float
"""
n = len(points)
# python_1_to_1000/810_Chalkboard_XOR_Game.py - h largest = 0

_author_ = 'jake' for i in range(n - 2):


_project_ = 'leetcode' for j in range(i + 1, n - 1):
for k in range(j + 1, n):
# https://leetcode.com/problems/chalkboard-xor-game/ x1, y1 = points[i]
# We are given non-negative integers nums[i] which are written on a chalkboard. x2, y2 = points[j]
# Alice and Bob take turns erasing exactly one number from the chalkboard, with Alice starting first. x3, y3 = points[k]
# If erasing a number causes the bitwise XOR of all the elements of the chalkboard to become 0, then that player loses.
# Also, we'll say the bitwise XOR of one element is that element itself, and the bitwise XOR of no elements is 0. area = 0.5 * abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))
# Also, if any player starts their turn with the bitwise XOR of all the elements of the chalkboard equal to 0, largest = max(largest, area)
# then that player wins.
# Return True if and only if Alice wins the game, assuming both players play optimally. return largest

# 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)

# python_1_to_1000/811_Subdomain_Visit_Count.py - m class Solution(object):


def largestSumOfAverages(self, A, K):
_author_ = 'jake' """
_project_ = 'leetcode' :type A: List[int]
:type K: int
# https://leetcode.com/problems/subdomain-visit-count/ :rtype: float
# A website domain like "discuss.leetcode.com" consists of various subdomains. """
# At the top level, we have "com", at the next level, we have "leetcode.com", and at the lowest level, memo = {}
# "discuss.leetcode.com". When we visit a domain like "discuss.leetcode.com", we will also visit the parent
# domains "leetcode.com" and "com" implicitly. def helper(i, k): # max average for A[:i] partitioned into k subarrays
# Now, call a "count-paired domain" to be a count (representing the number of visits this domain received), followed
# by a space, followed by the address. An example of a count-paired domain might be "9001 discuss.leetcode.com". if (i, k) in memo:
# We are given a list cpdomains of count-paired domains. We would like a list of count-paired domains, return memo[(i, k)]
# (in the same format as the input, and in any order), that explicitly counts the number of visits to each subdomain.
if k == 1:
# Split each cp domain into a count and list of domains. For each list of domains, form all domains (max 3) as suffixes memo[(i, k)] = sum(A[:i]) / float(i)
# of the list. Increment counts of all domains. Return list of formatted counts and domains. return memo[(i, k)]
# Time - O(n), since
# Space - O(n) best = 0
for j in range(k - 1, i): # retains A[:j] for the k - 1 subarrays and calculate average of suffix
from collections import defaultdict best = max(best, helper(j, k - 1) + sum(A[j:i]) / float(i - j))

class Solution(object): memo[(i, k)] = best


def subdomainVisits(self, cpdomains): return best
"""
:type cpdomains: List[str] return helper(len(A), K)
:rtype: List[str]
"""
counts = defaultdict(int) # map a domain to its count # python_1_to_1000/814_Binary_Tree_Pruning.py - m

for cpdomain in cpdomains: _author_ = 'jake'


_project_ = 'leetcode'
count, domains = cpdomain.split(" ") # split count from domain
domains = domains.split(".") # split domain to components # https://leetcode.com/problems/binary-tree-pruning/
# We are given the head node root of a binary tree, where additionally every node's value is either a 0 or a 1.
for i in range(len(domains)): # Return the same tree where every subtree (of the given tree) not containing a 1 has been removed.
domain = ".".join(domains[i:]) # build each suffix of domains # Recall that the subtree of a node X is X, plus every node that is a descendant of X.
counts[domain] += int(count) # increment count
# Recursive helper function returns boolean whether tree has a node with val == 1 and also removes subtrees not
return [str(count) + " " + domain for domain, count in counts.items()] # format result # containing 1.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/812_Largest_Triangle_Area.py
class Solution(object):
_author_ = 'jake' def pruneTree(self, root):
_project_ = 'leetcode' """
:type root: TreeNode
# https://leetcode.com/problems/largest-triangle-area/ :rtype: TreeNode
# You have a list of points in the plane. Return the area of the largest triangle that can be formed by any """
# 3 of the points. def contains_one(node):

# 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

class Solution(object): if not left_one: # remove subtrees without 1s


def largestTriangleArea(self, points): node.left = None
if not right_one:
node.right = None class Solution(object):
def ambiguousCoordinates(self, S):
return node.val == 1 or left_one or right_one # 1 in node or subtrees """
:type S: str
return root if contains_one(root) else None # handle tree with no 1s :rtype: List[str]
"""

# python_1_to_1000/815_Bus_Routes.py - h def insert_decimal(s): # return list of possible representations of a number

_author_ = 'jake' if s == "0": # special case of leading and trailing zero


_project_ = 'leetcode' return [s]
if s[0] == "0" and s[-1] == "0": # cannot have both leading and trailing zeros
# https://leetcode.com/problems/bus-routes/ return []
# We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. if s[0] == "0": # cannot have multiple leading zeros before decimal point
# For example if routes[0] = [1, 5, 7], this means that the first bus (0-th indexed) travels in the return ["0." + s[1:]]
# sequence 1->5->7->1->5->7->1->... forever. if s[-1] == "0": # cannot have any trailing zeros after decimal point
# We start at bus stop S (initially not on a bus), and we want to go to bus stop T. return [s]
# Travelling by buses only, what is the least number of buses we must take to reach our destination?
# Return -1 if it is not possible. return [s[:i] + "." + s[i:] for i in range(1, len(s))] + [s]

# Bidirectional breadth-first search. S = S[1:-1] # remove brackets


# Create mapping from each stop to all routes that the stop is on. Maintain front and back frontiers of stops that result = []
# can be reached. Expand the smaller frontier in each round with all stops that have not been visited and are on the
# same route as a stop in the current frontier. Terminate when frontiers intersect or one is empty. for i in range(1, len(S)): # insert comma after index i
# Time - O(n), number of stops
# Space - O(n) left = insert_decimal(S[:i])
right = insert_decimal(S[i:])
from collections import defaultdict result += ["(" + ", ".join([l, r]) + ")" for l in left for r in right]

class Solution(object): return result


def numBusesToDestination(self, routes, S, T):
"""
:type routes: List[List[int]]
:type S: int # python_1_to_1000/817_Linked_List_Components.py - m
:type T: int
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
routes = [set(route) for route in routes] # convert routes so set for faster merging later
stop_to_routes = defaultdict(set) # map each stop to set of routes it is on # https://leetcode.com/problems/linked-list-components/
# We are given head, the head node of a linked list containing unique integer values.
for route, stops in enumerate(routes): # We are also given the list G, a subset of the values in the linked list.
for stop in stops: # Return the number of connected components in G, where two values are connected if they appear consecutively in
stop_to_routes[stop].add(route) # the linked list.

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?

front = new_front - visited # remove all visited while head:

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

_author_ = 'jake' head = head.next


_project_ = 'leetcode'
return count
# https://leetcode.com/problems/ambiguous-coordinates/
# We had some 2-dimensional coordinates, like "(1, 3)" or "(2, 0.5)".
# Then, we removed all commas, decimal points, and spaces, and ended up with the string S. # python_1_to_1000/818_Race_Car.py - h
# Return a list of strings representing all possibilities for what our original coordinates could have been.
# Our original representation never had extraneous zeroes, so we never started with numbers like "00", "0.0", "0.00", _author_ = 'jake'
# "1.0", "001", "00.01", or any other number that can be represented with less digits. _project_ = 'leetcode'
# Also, a decimal point within a number never occurs without at least one digit occuring before it, so we never
# started with numbers like ".1". # https://leetcode.com/problems/race-car/
# The final answer list can be returned in any order. # Your car starts at position 0 and speed +1 on an infinite number line. (Your car can go into negative positions.)
# Also note that all coordinates in the final answer have exactly one space between them (occurring after the comma. # Your car drives automatically according to a sequence of instructions A (accelerate) and R (reverse).
# When you get an instruction "A", your car does the following: position += speed, speed *= 2.
# Split the coordinates into two non-zero pieces where the comma will be inserted. For each piece, calculate a list of # When you get an instruction "R", your car does the following: if your speed is positive then speed = -1,
# all possible numbers with a digit. # otherwise speed = 1. (Your position stays the same.)
# If number has leading and trailing zeros zero it can only be zero. # For example, after commands "AAR", your car goes to positions 0->1->3->3, and your speed goes to 1->2->4->-1.
# If a number has a leading zero, it must have a decimal point after the zero. # Now for some target position, say the length of the shortest sequence of instructions to get there.
# If a number has a trailing zero, it cannot have a decimal point.
# Else insert the decimal point in all possible places. # After k steps of acceleration, we have travelled 2 ** k - 1 distance. Find k such that distance >= target,
# Create all possible combinations of the left and right pieces. # this is the number of bits used in target.
# Time - O(n**4), O(n**3) possible coordinates # If this distance reaches the target exactly, we cannot do better. Else we either go past the target, reverse and
# Space - O(n**4) # recurse for the remaining distance having already moved k + 1 steps, or reverse after k - 1 steps then accelerate

# 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'

if dist in min_steps: # https://leetcode.com/problems/shortest-distance-to-a-character/


return min_steps[dist] # Given a string S and a character C, return an array of integers representing the shortest distance from the
# character C in the string.
k = dist.bit_length() # S string length is in [1, 10000].
if 2 ** k - 1 == dist: # k steps reaches target exactly # C is a single character, and guaranteed to be in string S.
return k # All letters in S and C are lowercase.

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)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def flipgame(self, fronts, backs):
"""
# https://leetcode.com/problems/short-encoding-of-words/ :type fronts: List[int]
# Given a list of words, we may encode it by writing a reference string S and a list of indexes A. :type backs: List[int]
# For example, we can write words ["time", "me", "bell"], as S = "time#bell#" and indexes = [0, 2, 5]. :rtype: int
# Then for each index, we will recover the word by reading from the reference string from that index until we """
# reach a "#" character. duplicates = {f for f, b in zip(fronts, backs) if f == b}
# What is the length of the shortest reference string S possible that encodes the given words? result = float("inf")

# 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)

for left in A[:i]: return requests


right, remainder = divmod(num, left)
if right <= 1:
break # python_1_to_1000/826_Most_Profit_Assigning_Work.py - m
if remainder == 0 and right in num_to_trees:
num_to_trees[num] += num_to_trees[left] * num_to_trees[right] _author_ = 'jake'
_project_ = 'leetcode'
return sum(num_to_trees.values()) % MOD
# https://leetcode.com/problems/most-profit-assigning-work/
# We have jobs: difficulty[i] is the difficulty of the ith job, and profit[i] is the profit of the ith job.
# python_1_to_1000/824_Goat_Latin.py # Now we have some workers. worker[i] is the ability of the ith worker, which means that this worker can only complete
# a job with difficulty at most worker[i].
_author_ = 'jake' # Every worker can be assigned at most one job, but one job can be completed multiple times.
_project_ = 'leetcode' # For example, if 3 people attempt the same job that pays $1, then the total profit will be $3.
# If a worker cannot complete any job, his profit is $0.
# https://leetcode.com/problems/goat-latin/ # What is the most profit we can make?
# A sentence S is composed of words separated by spaces. Each word consists of lowercase and uppercase letters only.
# We would like to convert the sentence to "Goat Latin" (a made-up language similar to Pig Latin.) # Zip the difficulties and profits together then sort to create a list of tuples with ascending difficulty.
# The rules of Goat Latin are as follows: # Sort the workers then iterate over workers. For each worker step through the list of jobs, updating best_profit for
# If a word begins with a vowel (a, e, i, o, or u), append "ma" to the end of the word. # all jobs that this worker can do.
# For example, the word 'apple' becomes 'applema'. # Time - O(mlogm + nlogn) where len(difficulty) == m and len(worker) = n
# If a word begins with a consonant (i.e. not a vowel), remove the first letter and append it to the end, then add "ma". # Space - O(m)
# For example, the word "goat" becomes "oatgma".
# Add one letter 'a' to the end of each word per its word index in the sentence, starting with 1. class Solution(object):
# For example, the first word gets "a" added to the end, the second word gets "aa" added to the end and so on. def maxProfitAssignment(self, difficulty, profit, worker):
# Return the final sentence representing the conversion from S to Goat Latin. """
:type difficulty: List[int]
# Split by spaces. If a word does not start with a vowel, move first letter to end of word. Append word with "ma" and :type profit: List[int]
# "a" according to index. :type worker: List[int]
# Time - O(n) :rtype: int
# Space - O(n) """
max_profits = list(zip(difficulty, profit))
class Solution(object): max_profits.sort()
def toGoatLatin(self, S): max_profits.append((float("inf"), 0))
"""
:type S: str total_profit = 0
:rtype: str best_profit = 0
""" i = 0
S = S.split()
vowels = {"a", "e", "i", "o", "u"} worker.sort()
for diff in worker:
for i, word in enumerate(S):
while max_profits[i][0] <= diff: # all jobs worker can do
if word[0].lower() not in vowels: best_profit = max(best_profit, max_profits[i][1]) # update best_profit
S[i] = S[i][1:] + S[i][0] i += 1
total_profit += best_profit
S[i] += "ma" + "a" * (i + 1)
return total_profit
return " ".join(S)

# 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)

# Space - O(mn) # Time - O(sqrt(n))


# Space - O(1)
from collections import defaultdict
class Solution(object):
class Solution(object): def consecutiveNumbersSum(self, N):
def largestIsland(self, grid): """
""" :type N: int
:type grid: List[List[int]] :rtype: int
:rtype: int """
""" k = 1 # start from sequences of length 1
rows, cols = len(grid), len(grid[0]) temp = N - ((k + 1) * k) // 2 # RHS of equation
nbors = ((0, 1), (1, 0), (-1, 0), (0, -1)) result = 0

def island(r, c): while temp >= 0:


if r < 0 or r >= rows or c < 0 or c >= cols: # outside grid
return 0 if temp % k == 0: # RHS is divisible by k, solution found
if grid[r][c] == 2: # already explored result += 1
return 0 k += 1
if grid[r][c] == 0: # neighbour temp = N - ((k + 1) * k) // 2
edge.add((r, c))
return 0 return result
grid[r][c] = 2 # set to visited
return 1 + sum(island(r + dr, c + dc) for dr, dc in nbors)

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

for r in range(rows): _author_ = 'jake'


for c in range(cols): _project_ = 'leetcode'
edge = set()
area = island(r, c) # https://leetcode.com/problems/positions-of-large-groups/
if area != 0: # In a string S of lowercase letters, these letters form consecutive groups of the same character.
for cell in edge: # For example, a string like S = "abbxxxxzyy" has the groups "a", "bb", "xxxx", "z" and "yy".
cell_to_areas[cell] += area # Call a group large if it has 3 or more characters. Find the starting and ending positions of every large group.
# The final answer should be in lexicographic order.
if not cell_to_areas: # grid empty or full
return 1 if grid[0][0] == 0 else rows * cols # Iterate over S. When the next char is different from the previous char, add to the result if the group length >= 3.
return 1 + max(areas for areas in cell_to_areas.values()) # Time - O(n)
# Space - O(n)

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

class Solution(object): _author_ = 'jake'


def uniqueLetterString(self, S): _project_ = 'leetcode'
"""
:type S: str # https://leetcode.com/problems/masking-personal-information/
:rtype: int # We are given a personal information string S, which may represent either an email address or a phone number.
""" # We would like to mask this personal information according to the following rules:
unique = 0 # 1. Email address:
indices = [[-1] for _ in range(26)] # We define a name to be a string of length ≥ 2 consisting of only lowercase letters a-z or uppercase letters A-Z.
# An email address starts with a name, followed by the symbol '@', followed by a name, followed by the dot '.'
for i, c in enumerate(S): # and followed by a name.
indices[ord(c) - ord("A")].append(i) # All email addresses are guaranteed to be valid and in the format of "[email protected]".
# To mask an email, all names must be converted to lowercase and all letters between the first and last letter of the
for index_list in indices: # first name must be replaced by 5 asterisks '*'.
# 2. Phone number:
index_list.append(len(S)) # A phone number is a string consisting of only the digits 0-9 or the characters from the set {'+', '-', '(', ')', ' '}.
for i in range(1, len(index_list) - 1): # You may assume a phone number contains 10 to 13 digits.
unique += (index_list[i] - index_list[i - 1]) * (index_list[i + 1] - index_list[i]) # The last 10 digits make up the local number, while the digits before those make up the country code.
# Note that the country code is optional. We want to expose only the last 4 digits and mask all other digits.
return unique % (10 ** 9 + 7) # The local number should be formatted and masked as "***-***-1111", where 1 represents the exposed digits.
# To mask a phone number with country code like "+111 111 111 1111", we write it in the form "+***-***-***-1111".
# The '+' sign and the first '-' sign before the local number should only exist if there is a country code.
# python_1_to_1000/829_Consecutive_Numbers_Sum.py - h # For example, a 12 digit phone number mask should start with "+**-".
# Note that extraneous characters like "(", ")", " ", as well as extra dashes or plus signs not part of the above
_author_ = 'jake' # formatting scheme should be removed.
_project_ = 'leetcode' # Return the correct "mask" of the information provided.

# 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)

# python_1_to_1000/832_Flipping_an_Image.py from collections import defaultdict

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def sumOfDistancesInTree(self, N, edges):
"""
# https://leetcode.com/problems/flipping-an-image/ :type N: int
# Given a binary matrix A, we want to flip the image horizontally, then invert it, and return the resulting image. :type edges: List[List[int]]
# To flip an image horizontally means that each row of the image is reversed. :rtype: List[int]
# For example, flipping [1, 1, 0] horizontally results in [0, 1, 1]. """
# To invert an image means that each 0 is replaced by 1, and each 1 is replaced by 0. neighbours = defaultdict(set) # map node to set of neighbours
# For example, inverting [0, 1, 1] results in [1, 0, 0]. for a, b in edges:
neighbours[a].add(b)
# Reverse each row set each value to 1 - value so 0 becomes 1 and 1 becomes 0. neighbours[b].add(a)
# Time - O(mn)
# Space - O(mn) subtree_counts = [1] * N # number of nodes in subtree with node i as roor
distances = [0] * N
class Solution(object):
def flipAndInvertImage(self, A): def subtree_distances(node, parent):
""" for child in neighbours[node]:
:type A: List[List[int]] if child != parent: # graph is undirected, do not go back to parent
:rtype: List[List[int]] subtree_distances(child, node)
""" subtree_counts[node] += subtree_counts[child]
result = [] distances[node] += distances[child] + subtree_counts[child] # each node in subtree is 1 unit further

for row in A: def update_distances(node, parent):


result.append([1 - val for val in reversed(row)]) for child in neighbours[node]:
if child != parent:
return result distances[child] = distances[node] - subtree_counts[child] + (N - subtree_counts[child])
update_distances(child, node)

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)

class Solution(object): class Solution(object):


def findReplaceString(self, S, indexes, sources, targets): def largestOverlap(self, A, B):
""" """
:type S: str :type A: List[List[int]]
:type indexes: List[int] :type B: List[List[int]]
:type sources: List[str] :rtype: int
:type targets: List[str] """
:rtype: str def image_to_bits(image): # convert each row to an integer
""" bits = []
replaced = [c for c in S] # convert to list for row in image:
num = 0
for i, src, tgt in zip(indexes, sources, targets): for i, bit in enumerate(reversed(row)):
if bit == 1:
n = len(src) num += (bit << i)
if S[i:i + n] == src: bits.append(num)
replaced[i] = tgt return bits
replaced[i + 1:i + n] = [""] * (n - 1)
A_bits, B_bits = image_to_bits(A), image_to_bits(B)
return "".join(replaced) rows, cols = len(A), len(A[0])
max_overlap = 0

_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

for i in range(1, N + 1): from collections import defaultdict

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)

# python_1_to_1000/838_Push_Dominoes.py - m if N < 2 * W: # if few long words

_author_ = 'jake' for i, w1 in enumerate(A):


for j in range(i + 1, len(A)): for r in range(rows - 2):
w2 = A[j] for c in range(cols - 2):
if len([True for c1, c2 in zip(w1, w2) if ord(c1) - ord(c2) != 0]) == 2: magic += is_magic(r, c)
word_swap[w1].add(w2)
word_swap[w2].add(w1) return magic
else:
A_set = set(A)
# python_1_to_1000/841_Keys_and_Rooms.py - m
def get_neighbours(a):
if word_swap: _author_ = 'jake'
return word_swap[a] _project_ = 'leetcode'
neighbours = set()
for i in range(W - 1): # https://leetcode.com/problems/keys-and-rooms/
for j in range(i + 1, W): # There are N rooms and you start in room 0. Each room has a distinct number in 0, 1, 2, ..., N-1, and each room may
if a[i] != a[j]: # have some keys to access the next room.
neighbour = a[:i] + a[j] + a[i + 1:j] + a[i] + a[j + 1:] # Formally, each room i has a list of keys rooms[i], and each key rooms[i][j] is an integer in [0, 1, ..., N-1]
if neighbour in A_set: # where N = rooms.length. A key rooms[i][j] = v opens the room with number v.
neighbours.add(neighbour) # Initially, all the rooms start locked (except for room 0).
# You can walk back and forth between rooms freely.
return neighbours # Return true if and only if you can enter every room.

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)

rows, cols = len(grid), len(grid[0]) return fib


magic = 0
for len1 in range(1, (len(S) + 1) // 2):

# 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)

if s_i == -1 and t_i == -1: # both strings ended


# python_1_to_1000/843_Guess_the_Word.py - h return True
if s_i == -1 or t_i == -1: # one string ended
_author_ = 'jake' return False
_project_ = 'leetcode' if S[s_i] != T[t_i]: # chars do not match
return False
# https://leetcode.com/problems/guess-the-word/
# This problem is an interactive problem new to the LeetCode platform. s_i -= 1 # move to next chars
# We are given a word list of unique words, each word is 6 letters long, and one word in this list is chosen as secret. t_i -= 1
# You may call master.guess(word) to guess a word.
# The guessed word should have type string and must be from the original list with 6 lowercase letters.
# This function returns an integer type, representing the number of exact matches (value and position) of your guess # python_1_to_1000/845_Longest_Mountain_in_Array.py - m
# to the secret word. Also, if your guess is not in the given wordlist, it will return -1 instead.
# For each test case, you have 10 guesses to guess the word. At the end of any number of calls, if you have made 10 _author_ = 'jake'
# or less calls to master.guess and at least one of these guesses was the secret, you pass the testcase. _project_ = 'leetcode'
# Besides the example test case below, there will be 5 additional test cases, each with 100 words in the word list.
# The letters of each word in those testcases were chosen independently at random from 'a' to 'z', # https://leetcode.com/problems/longest-mountain-in-array/
# such that every word in the given word lists is unique. # Let's call any (contiguous) subarray B (of A) a mountain if the following properties hold:
# B.length >= 3
# Repeatedly choose a word to guess and eliminate all words that do not have the same number of matches as the # There exists some 0 < i < B.length - 1 such that B[0] < B[1] < ... B[i-1] < B[i] > B[i+1] > ... > B[B.length - 1]
# chosen word. Words are chosen so they have maximum overlap (same chars in same positions) with other words. # (Note that B could be any subarray of A, including the entire array A.)
# This reduces candidate list more than choosing a random word which may not overlap with any other words and so # Given an array A of integers, return the length of the longest mountain.
# does not allow any other words to be eliminated. # Return 0 if there is no mountain.
# Time - O(n)
# Space - O(n) # Iterate over A, comparing successive difference between points. Track the last valley where a mountain starts and
# the peak of the last mountain.
class Solution(object): # Time - O(n)
def findSecretWord(self, wordlist, master): # Space - O(1)
"""
:type wordlist: List[Str] class Solution(object):
:type master: Master def longestMountain(self, A):
:rtype: None """
""" :type A: List[int]
def pair_matches(a, b): # count the number of matching characters :rtype: int
return sum(c1 == c2 for c1, c2 in zip(a, b)) """
valley, peak = 0, 0
def most_overlap_word(): prev = 0 # previous difference: 0 == same, +1 == up, -1 == down
counts = [collections.defaultdict(int) for _ in range(6)] # counts[i] maps chars to count of words with longest = 0
char at index i
for word in candidates: for i in range(1, len(A)):
for i, c in enumerate(word):
counts[i][c] += 1 # all words with same chars in same positions if A[i] == A[i - 1]: # if same, reset valley and peak to this index
valley, peak = i, i
return max(candidates, key=lambda x:sum(counts[i][c] for i, c in enumerate(x))) prev = 0

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

end, length = heapq.heappop(partials) # num == partials[0][0] + 1, extend straight # python_1_to_1000/849_Maximize_Distance_to_Closest_Person.py - m


if length != W - 1:
heapq.heappush(partials, (num, length + 1)) _author_ = 'jake'
_project_ = 'leetcode'
return not partials
# https://leetcode.com/problems/maximize-distance-to-closest-person/
# In a row of seats, 1 represents a person sitting in that seat, and 0 represents that the seat is empty.
# There is at least one empty seat, and at least one person sitting.
# python_1_to_1000/847_Shortest_Path_Visiting_All_Nodes.py - h # Alex wants to sit in the seat such that the distance between him and the closest person to him is maximized.
# Return that maximum distance to closest person.
_author_ = 'jake'
_project_ = 'leetcode' # Iterate over seats, maintaining a list of empty seats as tuples of (index of empty seat, distance to seat on left).
# If a seat is occupied, update max_distance for each empty seat with the minimum of the distances to its left and
# https://leetcode.com/problems/shortest-path-visiting-all-nodes/ # right occupied seats. Else add to the list of empty seats if max_distance could be improved.
# An undirected, connected graph of N nodes (labeled 0, 1, 2, ..., N-1) is given as graph. # Time - O(n)
# graph.length = N, and j != i is in the list graph[i] exactly once, if and only if nodes i and j are connected. # Space - O(1)
# Return the length of the shortest path that visits every node.
# You may start and stop at any node, you may revisit nodes multiple times, and you may reuse edges. class Solution(object):
def maxDistToClosest(self, seats):
# Breadth-first search. States consist of (visited, node) where node is the most recent node and visited is an """
# integer with a bit set for every node visited. Expand frontier by visiting all neighbours of each node of each :type seats: List[int]
# state. Only consider states not visited already. :rtype: int
# Time - O(n * 2**n) the number of possible states, since 2**n possible values for visited and n values for node """
# Space - O(n * 2**n) empty_seats = []
max_distance = 0
class Solution(object): last_seat = float("-inf")
def shortestPathLength(self, graph):
""" for i, seat in enumerate(seats):
:type graph: List[List[int]]
:rtype: int if seat == 1: # occupied, update max_distance for all empty_seats
""" while empty_seats:
if len(graph) == 0 or len(graph[0]) == 0: seat_i, left_distance = empty_seats.pop()
return 0 max_distance = max(max_distance, min(left_distance, i - seat_i))
last_seat = i
n = len(graph)
frontier = {(1 << node, node) for node in range(n)} # set the bit for each node elif i - last_seat > max_distance: # add to empty_seats if max_distance can be improved
visited = set(frontier) empty_seats.append((i, i - last_seat))
distance = 0
while empty_seats: # remaining seats have no occupied seat on right
while True: seat_i, left_distance = empty_seats.pop()
max_distance = max(max_distance, left_distance)
new_frontier = set()
return max_distance
for bit_nodes, node in frontier:

if bit_nodes == 2 ** n - 1: # all nodes visited # python_1_to_1000/850_Rectangle_Area_II.py - h


return distance
_author_ = 'jake'
for nbor in graph[node]: _project_ = 'leetcode'

new_bit_nodes = bit_nodes | 1 << nbor # set bit for nbor # https://leetcode.com/problems/rectangle-area-ii/


if (new_bit_nodes, nbor) not in visited: # We are given a list of (axis-aligned) rectangles. Each rectangle[i] = [x1, y1, x2, y2], where (x1, y1) are the
new_frontier.add((new_bit_nodes, nbor)) # coordinates of the bottom-left corner, and (x2, y2) are the coordinates of the top-right corner of the ith rectangle.
# Find the total area covered by all rectangles in the plane.
visited |= new_frontier # update visited # Since the answer may be too large, return it modulo 10^9 + 7.
distance += 1
frontier = new_frontier # Create a sorted list of opening and closing edges along the x direction. For each edge in the x direction, add the

# 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

area = 0 _author_ = 'jake'


alive = set() # all rectangle indices currently alive at this value of x _project_ = 'leetcode'
y_coverage = 0 # the length covered by rectangle in y direction
x_prev = 0 # https://leetcode.com/problems/peak-index-in-a-mountain-array/
# Let's call an array A a mountain if the following properties hold:
for x, start, i in x_events: # A.length >= 3
# There exists some 0 < i < A.length - 1 such that A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]
area += (x - x_prev) * y_coverage # update the area as the distance since previous x * y length covered # Given an array that is definitely a mountain, return any i such that
x_prev = x # A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1].

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'

_author_ = 'jake' # https://leetcode.com/problems/car-fleet/


_project_ = 'leetcode' # N cars are going to the same destination along a one lane road. The destination is target miles away.
# Each car i has a constant speed speed[i] (in miles per hour), and initial position position[i] miles towards the
# https://leetcode.com/problems/loud-and-rich/ # target along the road.
# In a group of N people (labelled 0, 1, 2, ..., N-1), each person has different amounts of money, # A car can never pass another car ahead of it, but it can catch up to it, and drive bumper to bumper at the same speed.
# and different levels of quietness. # The distance between these two cars is ignored - they are assumed to have the same position.
# For convenience, we'll call the person with label x, simply "person x". # A car fleet is some non-empty set of cars driving at the same position and same speed.
# We'll say that richer[i] = [x, y] if person x definitely has more money than person y. # Note that a single car is also a car fleet.
# Note that richer may only be a subset of valid observations. # If a car catches up to a car fleet right at the destination point, it will still be considered as one car fleet.
# Also, we'll say quiet[x] = q if person x has quietness q. # How many car fleets will arrive at the destination?
# Now, return answer, where answer[x] = y if y is the least quiet person (that is, the person y with the smallest
# value of quiet[y]), among all people who definitely have equal to or more money than person x. # Sort the cars in decreasing order of position. Iterate over the cars. If a car arrives after the previous car it
# forms a new fleet.
# Create graph mapping people to richer people. For each person, depth-first search the graph, first updating the # Time - O(n log n)
# results of all richer people, then if any richer people have a quieter result, update the result of the person. # Space - O(n)
# Time - O(m + n), number of richer relationships + number of people
# Space - O(m + n) class Solution(object):
def carFleet(self, target, position, speed):
class Solution(object): """
def loudAndRich(self, richer, quiet): :type target: int
""" :type position: List[int]
:type richer: List[List[int]] :type speed: List[int]
:type quiet: List[int] :rtype: int
:rtype: List[int] """
""" fleets = 0
n = len(quiet) previous = -1 # time of arrival of previous car at target
richer_than = [set() for _ in range(n)] # map person to richer people
cars = zip(position, speed)
for a, b in richer: cars.sort(reverse = True) # greatest distance first
richer_than[b].add(a)
for pos, spd in cars:
result = [None] * n
time = (target - pos) / float(spd) # time of arrival at target
def update_results(person): if time > previous:
fleets += 1
if result[person] is not None: # already found result previous = time # new later time of arrival
if not self.seats: # empty room, use seat zero
return fleets self.seats.append(0)
return 0

# 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

_author_ = 'jake' for i in range(len(self.seats) - 1): # each pair of occupied seats


_project_ = 'leetcode' dist = (self.seats[i + 1] - self.seats[i]) // 2 # best case distance
if dist > max_dist: # improved best case
# https://leetcode.com/problems/k-similar-strings/ max_dist = dist
# Strings A and B are K-similar (for some non-negative integer K) if we can swap the positions of two letters in A index = self.seats[i] + dist
# exactly K times so that the resulting string equals B.
# Given two anagrams A and B, return the smallest K for which A and B are K-similar. if self.N - 1 - self.seats[-1] > max_dist: # put in last seat if further distance
index = self.N - 1
# Breadth-first search. For each word in the frontier, find the index of the first letter out of place and swap it with
# all letters which should be in that place. Memoize visited words. bisect.insort(self.seats, index) # insert seat in order
# Time - O(n * n!) since n! possible words of length n if letters are unique return index
# Space - O(n * n!)
def leave(self, p):
class Solution(object): """
def kSimilarity(self, A, B): :type p: int
""" :rtype: void
:type A: str """
:type B: str self.seats.remove(p)
:rtype: int
"""
visited = set() # python_1_to_1000/856_Score_of_Parentheses.py - m
k = 0
frontier = {A} _author_ = 'jake'
_project_ = 'leetcode'
while True:
# https://leetcode.com/problems/score-of-parentheses/
if B in frontier: # Given a balanced parentheses string S, compute the score of the string based on the following rule:
return k # () has score 1
# AB has score A + B, where A and B are balanced parentheses strings.
new_frontier = set() # (A) has score 2 * A, where A is a balanced parentheses string.

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

_author_ = 'jake' left, right = helper(node.left), helper(node.right)


_project_ = 'leetcode' if left == -1 and right == -1: # target is in neither subtree
return -1
# https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/ distance_to_target = 1 + max(left, right) # target is in a subtree
# Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K.
# If there is no non-empty subarray with sum at least K, return -1. if K - distance_to_target == 0: # add this node to results
nodes_at_distance(node, 0)
# Calculate the prefix sums of the array. Maintain an queue of prefix sums that have not been used in order of elif K - distance_to_target > 0: # find nodes on other_side that are K from target
# increasing index. other_side = node.left if left == -1 else node.right
# For each new prefix sum, update the result using the smallest indices in the queue, as long as the subarray nodes_at_distance(other_side, K - distance_to_target - 1)
# sum is >= K. The last value used creates the shortest subarray, so all earlier values can be discarded. The last
# value can be also discarded because all later prefix sums will make longer subarrays. return distance_to_target
# Remove from the right of the queue all greater prefixes, since they would make longer subarrays.
# Time - O(n) helper(root)
# Space - O(n) return results

from collections import deque


# python_1_to_1000/864_Shortest_Path_to_Get_All_Keys.py - h
class Solution(object):
def shortestSubarray(self, A, K): _author_ = 'jake'
""" _project_ = 'leetcode'
:type A: List[int]
:type K: int # https://leetcode.com/problems/shortest-path-to-get-all-keys/
:rtype: int # We are given a 2-dimensional grid. "." is an empty cell, "#" is a wall, "@" is the starting point,
""" # ("a", "b", ...) are keys, and ("A", "B", ...) are locks.
n = len(A) # We start at the starting point, and one move consists of walking one space in one of the 4 cardinal directions.
# We cannot walk outside the grid, or walk into a wall. If we walk over a key, we pick it up.
prefix_sums = [0] * (n + 1) # We can't walk over a lock unless we have the corresponding key.
for i in range(n): # For some 1 <= K <= 6, there is exactly one lowercase and one uppercase letter of the first K letters of the
prefix_sums[i + 1] = prefix_sums[i] + A[i] # English alphabet in the grid.
# This means that there is exactly one key for each lock, and one lock for each key; and also that the letters used
queue = deque() # to represent the keys and locks were chosen in the same order as the English alphabet.
result = n + 1 # Return the lowest number of moves to acquire all keys. If it's impossible, return -1.

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'

_author_ = 'jake' # https://leetcode.com/problems/transpose-matrix/


_project_ = 'leetcode' # Given a matrix A, return the transpose of A.
# The transpose of a matrix is the matrix flipped over it's main diagonal,
# https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/ # switching the row and column indices of the matrix.
# Given a binary tree rooted at root, the depth of each node is the shortest distance to the root.
# A node is deepest if it has the largest depth possible among any node in the entire tree. # Explode A into rows, which are zipped together with the ith element of each row (i.e. column i) being combined in
# The subtree of a node is that node, plus the set of all descendants of that node. # each tuple of the result.
# Return the node with the largest depth such that it contains all the deepest nodes in its subtree. # Time - O(mn)
# Space - O(mn)
# Helper function returns the depth of the deepest node and the deepest node that is a parent of all deepest nodes.
# Recursively explore left and right subtrees. If the deepest depths are equal, the current nodeis the deepest parent class Solution(object):
# of those deepest nodes. Else return the node from the deeper side. def transpose(self, A):
# Time - O(n) """
# Space - O(n) :type A: List[List[int]]
:rtype: List[List[int]]
from collections import namedtuple """
return zip(*A)
class Solution(object):
def subtreeWithAllDeepest(self, root):
""" # python_1_to_1000/868_Binary_Gap.py
:type root: TreeNode
:rtype: TreeNode _author_ = 'jake'
""" _project_ = 'leetcode'
Result = namedtuple("Result", ["node", "depth"]) # object returned by helper function
# https://leetcode.com/problems/binary-gap/
def helper(node): # Given a positive integer N, find and return the longest distance between two consecutive 1's in the
# binary representation of N.
if not node: # If there aren't two consecutive 1's, return 0.
return Result(None, -1)
# Check each bit (from least significant to most significant). Track the index of the previous set bit and the
left_result, right_result = helper(node.left), helper(node.right) # maximum distance so far.
# Time - O(log n)
depth_diff = left_result.depth - right_result.depth # Space - O(1)

if depth_diff == 0: class Solution(object):


return Result(node, left_result.depth + 1) def binaryGap(self, N):
"""
if depth_diff > 0: :type N: int
return Result(left_result.node, left_result.depth + 1) :rtype: int
return Result(right_result.node, right_result.depth + 1) """
previous, max_gap = None, 0 # index of previous 1
return helper(root).node i = 0 # current index in binary representation

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))

return result return all(l1 == l2 for l1, l2 in leaves)

# python_1_to_1000/871_Minimum_Number_of_Refueling_Stops.py - h # python_1_to_1000/873_Length_of_Longest_Fibonacci_Subsequence.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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

for distance, station_fuel in stations: max_length = max(max_length, length)

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 command in commands:


if command == -2: # python_1_to_1000/877_Stone_Game.py - m
orientation = (orientation - 1) % 4 # turn left
elif command == -1: _author_ = 'jake'
orientation = (orientation + 1) % 4 # turn right _project_ = 'leetcode'
else:
for _ in range(command): # https://leetcode.com/problems/stone-game/
next_position = (position[0] + directions[orientation][0], # Alex and Lee play a game with piles of stones.
position[1] + directions[orientation][1]) # There are an even number of piles arranged in a row, and each pile has a positive integer number of stones piles[i].
if next_position in obstacles: # stop moving if obstacle # The objective of the game is to end with the most stones. The total number of stones is odd, so there are no ties.
break # Alex and Lee take turns, with Alex starting first.
position = next_position # Each turn, a player takes the entire pile of stones from either the beginning or the end of the row.
max_sqr_distance = max(max_sqr_distance, position[0] ** 2 + position[1] ** 2) # This continues until there are no more piles left, at which point the person with the most stones wins.
# Assuming Alex and Lee play optimally, return True if and only if Alex wins the game.
return max_sqr_distance
# Alex can initially take the first pile (an even index) or the last pile (an odd index). If Alex takes an even index
# pile then Lee must take an odd index pile, and Alex can take an even index pile next. If Alex take an odd index pile
# initially, Lee must take an even index pile and Alex can take an odd index pile next.
# Thus Alex can take all even or all odd index piles. Since the sum of even piles and odd piles are not equal
# python_1_to_1000/875_Koko_Eating_Bananas.py - m # (because the total sum is odd), Alex can always take more stones in total.
# Time - O(1)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/koko-eating-bananas/ def stoneGame(self, piles):
# Koko loves to eat bananas. There are N piles of bananas, the i-th pile has piles[i] bananas. """
# The guards have gone and will come back in H hours. :type piles: List[int]
# Koko can decide her bananas-per-hour eating speed of K. Each hour, she chooses some pile of bananas, :rtype: bool
# and eats K bananas from that pile. """
# If the pile has less than K bananas, she eats all of them instead, and won't eat any more bananas during this hour. return True
# Koko likes to eat slowly, but still wants to finish eating all the bananas before the guards come back.
# Return the minimum integer K such that she can eat all the bananas within H hours.
# python_1_to_1000/878_Nth_Magical_Number.py - h
# Binary search the range of possible speeds. Maximum possible rate is to eat the largest pile in an hour.
# Minimum possible rate is to eat bananas constantly, so the sum of all bananas in the total time. _author_ = 'jake'
# Chech the middle rate between maximum and minimum and adjust the search range until one integer remains. _project_ = 'leetcode'
# The time to eat any pile is the size of the pile / rate, rounded up to the nearest integer.
# Time - O(n log n) # https://leetcode.com/problems/nth-magical-number/
# Space - O(1) # A positive integer is magical if it is divisible by either A or B.
# Return the N-th magical number. Since the answer may be very large, return it modulo 10^9 + 7.
class Solution(object):
def minEatingSpeed(self, piles, H): # Binary search the range of all possible solutions. Given a guess x, the number of magical numbers <= x is
""" # x // A + x // B - x // lcm(A, B), i.e. all the integers divisible by A + all the integers divisible by B - all the
:type piles: List[int] # integers divisible by both A and B (to avoid double-counting).
:type H: int # Time - O(1)
:rtype: int # Space - O(1)
"""
bananas, max_pile = sum(piles), max(piles) class Solution(object):
min_rate = (bananas + H - 1) // H # equivalent to ceil(bananas / H) def nthMagicalNumber(self, N, A, B):
max_rate = max_pile """
:type N: int
while min_rate < max_rate: :type A: int
:type B: int
rate = (min_rate + max_rate) // 2 :rtype: int
"""
low, high = 1, 10 ** 14 if "0" <= c <= "9": # multiply the length of the decoded string
length *= int(c)
def gcd(a, b): else: # increment the length of the decoded string
a, b = b, a % b length += 1
if b == 0: if length >= K:
return a break
return gcd(a, b)
for i in range(index, -1, -1): # iterate backwards along S
lcm = A * B // gcd(A, B) c = S[i]
if "0" <= c <= "9":
while low < high: length //= int(c)
K %= length
mid = (low + high) // 2 else:
num = (mid // A) + (mid // B) - (mid // lcm) # guess the result if K == length or K == 0: # K == 0 results from modulo
if num < N: # result must be greater than low return c
low = mid + 1 length -= 1
elif num >= N: # result is at most high
high = mid
# python_1_to_1000/881_Boats_to_Save_People.py - m
return low % (10 ** 9 + 7)
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/879_Profitable_Schemes.py - h
# https://leetcode.com/problems/boats-to-save-people/
_author_ = 'jake' # The i-th person has weight people[i], and each boat can carry a maximum weight of limit.
_project_ = 'leetcode' # Each boat carries at most 2 people at the same time, provided the sum of the weight of those people is at most limit.
# Return the minimum number of boats to carry every given person.
# https://leetcode.com/problems/profitable-schemes/ # It is guaranteed each person can be carried by a boat.
# There are G people in a gang, and a list of various crimes they could commit.
# The i-th crime generates a profit[i] and requires group[i] gang members to participate. # Sort the people in weight order. Maintain 2 pointers to the lightest and heaviest people not yet allocated to a boat.
# If a gang member participates in one crime, that member can't participate in another crime. # Add the heaviest person to a boat. If the lightest person can join them without going over the weight limit, then add
# Let's call a profitable scheme any subset of these crimes that generates at least P profit, # the lightest person. When the heaviest person is added to a boat, if the lightest person cannot join them then there
# and the total number of gang members participating in that subset of crimes is at most G. # is no other person that can join them and the heaviest person must be alone.
# How many schemes can be chosen? Since the answer may be very large, return it modulo 10^9 + 7. # Time - O(n log n)
# Space - O(1)
# Dynamic programming. For each job (with a profit and required gang), update a matrix of the number of schemes with
# each profit <= P and each gang <= G. Update the schemes for gang sizes at least as large as the job_gang, and for all class Solution(object):
# profits where schemes with profits > P are included in the profits == P cells. Return all schemes with profit at def numRescueBoats(self, people, limit):
# least P for any gang size in the matrix. """
# Time - O(NGP) :type people: List[int]
# Space - O(GP) :type limit: int
:rtype: int
class Solution(object): """
def profitableSchemes(self, G, P, group, profit): boats = 0
""" people.sort()
:type G: int light, heavy = 0, len(people) - 1
:type P: int
:type group: List[int] while light <= heavy:
:type profit: List[int]
:rtype: int boats += 1 # add heaviest to a new boat
"""
MOD = 10 ** 9 + 7 if people[light] + people[heavy] <= limit: # capacity for lightest and heaviest
light += 1
schemes = [[0] * (G + 1) for _ in range(P + 1)] # schemes[i][j] is nb schemes for profit i and gang j
schemes[0][0] = 1 heavy -= 1

for job_profit, job_gang in zip(profit, group): return boats

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

""" :type B: str


adjacency = defaultdict(set) # map node to set of (nbor, number of nodes on edge) :rtype: List[str]
subdivisions = {} # map an edge to (number of nodes on edge, visited nodes) """
counts = Counter(A.split(" ")) + Counter(B.split(" "))
for a, b, intermediate in edges: return [word for word, count in counts.items() if count == 1]
subdivisions[(a, b)] = [intermediate, 0]
subdivisions[(b, a)] = [intermediate, 0]
adjacency[a].add((b, intermediate)) # python_1_to_1000/885_Spiral_Matrix_III.py - m
adjacency[b].add((a, intermediate))
_author_ = 'jake'
queue = [(0, 0)] # (steps taken, node) _project_ = 'leetcode'
visited = set()
# https://leetcode.com/problems/spiral-matrix-iii/
while queue and len(visited) < N: # On a 2 dimensional grid with R rows and C columns, we start at (r0, c0) facing east.
steps, node = heapq.heappop(queue) # Here, the north-west corner of the grid is at the first row and column, and the south-east corner of the
if node in visited: # already visited with lower or same steps # grid is at the last row and column.
continue # Now, we walk in a clockwise spiral shape to visit every position in this grid.
visited.add(node) # Whenever we would move outside the boundary of the grid, we continue our walk outside the grid
# (but may return to the grid boundary later.)
for nbor, distance in adjacency[node]: # visit as many nodes as possible along this edge # Eventually, we reach all R * C spaces of the grid.
subdivisions[(node, nbor)][1] = min(distance, M - steps) # Return a list of coordinates representing the positions of the grid in the order they were visited.

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

from collections import Counter class Solution(object):


def possibleBipartition(self, N, dislikes):
class Solution(object): """
def uncommonFromSentences(self, A, B): :type N: int
""" :type dislikes: List[List[int]]
:type A: str :rtype: bool
""" # required difference.
dislike = defaultdict(set) # map each person to the set of people they dislike # Time - O(m + n)
for a, b in dislikes: # Space - O(n)
dislike[a].add(b)
dislike[b].add(a) class Solution(object):
def fairCandySwap(self, A, B):
this, other = set(), set() # 2 groups of people """
:type A: List[int]
for i in range(1, N + 1): :type B: List[int]
:rtype: List[int]
if i in this or i in other: # already placed this person in a group """
continue A_candy, B_candy = sum(A), sum(B)
to_add = {i} difference = (A_candy - B_candy) // 2 # difference of sizes of bars that must be exchanged

while to_add: B_set = set(B)


for a in A:
this |= to_add # put to_add in this if a - difference in B_set:
return [a, a - difference]
disliked = set() # people disliked by the people in to_add
for num in to_add: return []
disliked |= dislike[num]
if disliked & this: # somebody dislikes somebody else in this group
return False # python_1_to_1000/889_Construct_Binary_Tree_from_Preorder_and_Postorder_Traversal.py - m

disliked -= other # remove people already in other _author_ = 'jake'


to_add = disliked _project_ = 'leetcode'
this, other = other, this
# https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/
return True # Return any binary tree that matches the given preorder and postorder traversals.
# Values in the traversals pre and post are distinct positive integers.

# 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

while floors[K] < N: _author_ = 'jake'


_project_ = 'leetcode'
for eggs in range(K, 0, -1):
floors[eggs] += 1 + floors[eggs - 1] # https://leetcode.com/problems/find-and-replace-pattern/
drops += 1 # You have a list of words and a pattern, and you want to know which words in words matches the pattern.
# A word matches the pattern if there exists a permutation of letters p so that after replacing every letter x in
return drops # the pattern with p(x), we get the desired word.
# Recall that a permutation of letters is a bijection from letters to letters: every letter maps to another letter,
# and no two letters map to the same letter.
# python_1_to_1000/888_Fair_Candy_Swap.py # Return a list of the words in words that match the given pattern.
# You may return the answer in any order.
_author_ = 'jake'
_project_ = 'leetcode' # Each word and the pattern are converted to their canonical representations, which can then be compared.
# In a canonical representation, characters are mapped to integers in order of their appearance in the string.
# https://leetcode.com/problems/fair-candy-swap/ # The first character is mapped to 0, as are all subsequent appearances of that character. The second unique character
# Alice and Bob have candy bars of different sizes: A[i] is the size of the i-th bar of candy that Alice has, # is mapped to 1, etc.
# and B[j] is the size of the j-th bar of candy that Bob has. # Time - O(n) total length of all words and pattern
# Since they are friends, they would like to exchange one candy bar each so that after the exchange, # Space - O(n)
# they both have the same total amount of candy.
# The total amount of candy a person has is the sum of the sizes of candy bars they have. from collections import defaultdict
# Return an integer array ans where ans[0] is the size of the candy bar that Alice must exchange, and ans[1] is the
# size of the candy bar that Bob must exchange. class Solution(object):
# If there are multiple answers, you may return any one of them. It is guaranteed an answer exists. def findAndReplacePattern(self, words, pattern):
"""
# The difference of the sizes of the bars that they must swap is half of the difference of their total candy, since :type words: List[str]
# exchanging such bars will make the difference zero. For each bar in A, check if there is bar in B with the :type pattern: str

:rtype: List[str] area -= min(grid[row + 1][col], height)


""" if col != n - 1:
def canonical(s): # return a canonical representation of a string area -= min(grid[row][col + 1], height)
result = [] # list of integers
mapping = {} # map char to value return area
value = 0 # next value (equal to number of unique chars seen)

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)

# https://leetcode.com/problems/surface-area-of-3d-shapes/ class Solution(object):


# On a N * N grid, we place some 1 * 1 * 1 cubes. def allPossibleFBT(self, N):
# Each value v = grid[i][j] represents a tower of v cubes placed on top of grid cell (i, j). """
# Return the total surface area of the resulting shapes. :type N: int
:rtype: List[TreeNode]
# For each cell, add the area of top, bottom and all sides. Then subtract the side areas that are covered by """
# neighbours. memo = {}
# Time - O(mn)
# Space - O(1) def helper(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 = []

for row in range(n): for left_size in range(1, n, 2):


for col in range(n):
right_size = n - 1 - left_size
if grid[row][col] == 0: # ignore if no height left_subtrees = helper(left_size)
continue right_subtrees = helper(right_size)

height = grid[row][col] for left_subtree in left_subtrees:


area += 4 * height + 2 for right_subtree in right_subtrees:
root = TreeNode(0)
if row != 0: root.left = left_subtree
area -= min(grid[row - 1][col], height) root.right = right_subtree
if col != 0: result.append(root)
area -= min(grid[row][col - 1], height)
if row != n - 1: memo[n] = result
return result # Space - O(n)

return helper(N) class Solution(object):


def increasingBST(self, root, tail=None): # tail is appended after converting tree from root
"""
# python_1_to_1000/895_Maximum_Frequency_Stack.py - m :type root: TreeNode
:rtype: TreeNode
_author_ = 'jake' """
_project_ = 'leetcode' if root is None:
return tail
# https://leetcode.com/problems/maximum-frequency-stack/
# Implement FreqStack, a class which simulates the operation of a stack-like data structure. copy_root = TreeNode(root.val) # make a duplicate, so root.left and root.right are retained
# FreqStack has two functions: copy_root.right = self.increasingBST(root.right, tail)
# push(int x), which pushes an integer x onto the stack. return self.increasingBST(root.left, copy_root)
# pop(), which removes and returns the most frequent element in the stack.
# If there is a tie for most frequent element, the element closest to the top of the stack is removed and returned.
# python_1_to_1000/898_Bitwise_ORs_of_Subarrays.py - m
# Maintain a dictionary counting the number of each element in the stack and a stack_of_stacks. stack_of_stacks
# contains stacks of elements grouped by their counts. push() an element to the stack according to its count. _author_ = 'jake'
# pop() an element from the top stack_of_stacks. _project_ = 'leetcode'
# Time - O(1) for all methods
# Space - O(n) # https://leetcode.com/problems/bitwise-ors-of-subarrays/
# We have an array A of non-negative integers.
from collections import defaultdict # For every (contiguous) subarray B = [A[i], A[i+1], ..., A[j]] (with i <= j), we take the bitwise OR of all the
# elements in B, obtaining a result A[i] | A[i+1] | ... | A[j].
class FreqStack(object): # Return the number of possible results.
# Results that occur more than once are only counted once in the final answer.
def __init__(self):
self.counter = defaultdict(int) # count of each element in stack # Create sets of all numbers that can be created by OR and all numbers that can be created using the subarray ending
self.stack_of_stacks = [] # stack_of_stacks[i] is stack of elelemts with count of i + 1 # at the current index. For each index i, the results for the subarray ending at i are the OR of all previous results
# and A[i], and A[i] alone. Update all the results with the results from each index.
def push(self, x): # Time - O(n) since the length of subarray_or is at most 30 (the number of bits in any num) because each longer
""" # subarray ending at a given index covers al least all the bits covered by a shorter subarray.
:type x: int # Space - O(n)
:rtype: void
""" class Solution(object):
self.counter[x] += 1 def subarrayBitwiseORs(self, A):
count = self.counter[x] """
:type A: List[int]
if count > len(self.stack_of_stacks): # new stack :rtype: int
self.stack_of_stacks.append([]) """
self.stack_of_stacks[count - 1].append(x) all_or, subarray_or = set(), set()

def pop(self): for num in A:


""" new_or = {num | x for x in subarray_or}
:rtype: int new_or.add(num)
"""
num = self.stack_of_stacks[-1].pop() # pop from highest count stack all_or |= new_or
self.counter[num] -= 1 subarray_or = new_or

if not self.stack_of_stacks[-1]: # remove empty highest stack return len(all_or)


self.stack_of_stacks.pop()

return num
# python_1_to_1000/899_Orderly_Queue.py - h

# python_1_to_1000/896_Monotonic_Array.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/orderly-queue/
# A string S of lowercase letters is given. Then, we may make any number of moves.
# https://leetcode.com/problems/monotonic-array/ # In each move, we choose one of the first K letters (starting from the left), remove it,
# An array is monotonic if it is either monotone increasing or monotone decreasing. # and place it at the end of the string.
# An array A is monotone increasing if for all i <= j, A[i] <= A[j]. # Return the lexicographically smallest string we could have after any number of moves.
# An array A is monotone decreasing if for all i <= j, A[i] >= A[j].
# Return true if and only if the given array A is monotonic. # If K == 1, we can cycle through the string appending any number of the first characters to the end. In this case, try
# all possible numbers of characters moved.
# Iterate an check all A[i] >= A[i + 1] or A[i] <= A[i + 1] # Otherwise if K >= 2 then we can always swap the first 2 characters by moving the second before the first.
# Time - O(n) # Since we can perform any number of swaps, we
# Space - O(1) # Time - O(n**2)
# Space - O(n)
class Solution(object):
def isMonotonic(self, A): class Solution(object):
""" def orderlyQueue(self, S, K):
:type A: List[int] """
:rtype: bool :type S: str
""" :type K: int
return all(A[i] <= A[i + 1] for i in range(len(A) - 1)) or all(A[i] >= A[i + 1] for i in range(len(A) - 1)) :rtype: str
"""
if K > 1:
# python_1_to_1000/897_Increasing_Order_Search_Tree.py return "".join(sorted(S))

_author_ = 'jake' return min(S[i:] + S[:i] for i in range(len(S)))


_project_ = 'leetcode'

# 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

if self.i >= self.length:


return -1 # python_1_to_1000/903_Valid_Permutations_for_DI_Sequence.py - h

self.encoding[self.i] -= n # use some elements _author_ = 'jake'


return self.encoding[self.i + 1] _project_ = 'leetcode'

# 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:

def next(self, price): if move == "D":


""" dp = dp[1:] # move down from all last numbers apart from smallest
:type price: int for i in range(len(dp) - 2, -1, -1):
:rtype: int dp[i] += dp[i + 1] # add all solutions with higher ranked last number
""" else:
result = 1 # today's price has a span of 1 dp = dp[:-1] # move up from all last numbers apart from smallest
for i in range(1, len(dp)):
while self.stack and price >= self.stack[-1][0]: dp[i] += dp[i - 1] # add all solutions with lower ranked last number
_, count = self.stack.pop()
result += count return dp[0] % (10 ** 9 + 7)

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 fruit == other[0]: num = int(new_pal)


other[2] = i
other, prev = prev, other if num > R_sqrt: # greater than maximum possible palindrome
result = max(result, i + 1 - min(prev[1], other[1])) return result

elif prev[0] is None: if L_sqrt <= num and is_palindrome(num ** 2): # superpalindrome
prev = [fruit, i, i] result += 1

elif other[0] is None: prev_palis, palis = palis, new_palis


other, prev = prev, [fruit, i, i]
result = max(result, i + 1 - other[1])
# python_1_to_1000/907_Sum_of_Subarray_Minimums.py - m
else:
other = [prev[0], other[2] + 1, prev[2]] _author_ = 'jake'
prev = [fruit, i, i] _project_ = 'leetcode'

return result # https://leetcode.com/problems/sum-of-subarray-minimums/


# Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A.
# Since the answer may be large, return the answer modulo 10^9 + 7.

# 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)

_author_ = 'jake' return result % (10 ** 9 + 7)


_project_ = 'leetcode'

# 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):

""" # and minimum if lower than the current result.


:type A: List[int] # Time - O(n log n)
:type K: int # Space - O(n)
:rtype: int
""" class Solution:
range = max(A) - min(A) def smallestRangeII(self, A, K):
return max(0, range - 2 * K) """
:type A: List[int]
:type K: int
# python_1_to_1000/909_Snakes_and_Ladders.py - m :rtype: int
"""
_author_ = 'jake' A = sorted(A)
_project_ = 'leetcode' result = A[-1] - A[0] # move all elemnts in same direction

# 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

moves = 0 class TopVotedCandidate:


visited = set() # indices (before any snake or ladder)
queue = {1} # board moves are indexed from 1 def __init__(self, persons, times):
"""
while queue: :type persons: List[int]
:type times: List[int]
new_queue = set() """
self.times = times
for i in queue: self.leader = [] # leader[i] is the leading candidate at times[i]
counts = defaultdict(int) # cumulative count of votes for each candidate
if i in visited or i >= len(linear): # ignore positions seen already or too far max_count = 0 # number of votes for the leading candidate
continue
visited.add(i) for person, time in zip(persons, times):

if linear[i] != -1: # snake or ladder counts[person] += 1


i = linear[i]
if i == len(linear) - 1: if counts[person] > max_count: # new unique leader
return moves max_count += 1
leaders = [person]
for step in range(1, 7): # take 1 to 6 steps elif counts[person] == max_count: # join other leaders
new_queue.add(i + step) leaders.append(person)

moves += 1 self.leader.append(leaders[-1]) # most recent if tied


visited |= queue
queue = new_queue def q(self, t):
"""
return -1 :type t: int
:rtype: int
"""
i = bisect.bisect_left(self.times, t)
# python_1_to_1000/910_Smallest_Range_II.py - m
if i == len(self.times) or self.times[i] > t:
_author_ = 'jake' return self.leader[i - 1]
_project_ = 'leetcode'
return self.leader[i]
# https://leetcode.com/problems/smallest-range-ii/
# Given an array A of integers, for each integer A[i] we need to choose either x = -K or x = K,
# and add x to A[i] (only once). # python_1_to_1000/912_Sort_an_Array.py - m
# After this process, we have some array B.
# Return the smallest possible difference between the maximum value of B and the minimum value of B. _author_ = 'jake'
_project_ = 'leetcode'
# Sort the array (its starting order is irrelevant). For each split point i, the smaller elements A[i] and to the left
# are increased by K. The larger elements A[i + 1] and to the right are decreased by K. Find the minimum of the left # https://leetcode.com/problems/sort-an-array/
# and right sides, and the maximum of the left and right sides. Update the result with the difference of the maximum # Given an array of integers nums, sort the array in ascending order.
queue.append((i2, j2, prev_turn, turn))
# Use the in-built sorting function.
# Time - O(n log n) return state_winner[1, 2, MOUSE]
# Space - O(n)

class Solution(object): # python_1_to_1000/914_X_of_a_Kind_in_a_Deck_of_Cards.py


def sortArray(self, nums):
""" _author_ = 'jake'
:type nums: List[int] _project_ = 'leetcode'
:rtype: List[int]
""" # https://leetcode.com/problems/x-of-a-kind-in-a-deck-of-cards/
return sorted(nums) # In a deck of cards, each card has an integer written on it.
# Return true if and only if you can choose X >= 2 such that it is possible to split the entire deck into
# 1 or more groups of cards, where:
# Each group has exactly X cards.
# python_1_to_1000/913_Cat_and_Mouse.py - h # All the cards in each group have the same integer.

_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

from collections import defaultdict, deque _author_ = 'jake'


_project_ = 'leetcode'
class Solution(object):
def catMouseGame(self, graph): # https://leetcode.com/problems/partition-array-into-disjoint-intervals/
""" # Given an array A, partition it into two (contiguous) subarrays left and right so that:
:type graph: List[List[int]] # Every element in left is less than or equal to every element in right.
:rtype: int # left and right are non-empty.
""" # left has the smallest possible size.
DRAW, MOUSE, CAT = 0, 1, 2 # Return the length of left after such a partitioning. It is guaranteed that such a partitioning exists.
n = len(graph)
# Iterate along array tracking the maximum number in left partition, its index and the overall maximum number.
def parents(mouse, cat, turn): # find predecessor states # If the next number is less than the maximum in the left partition, it must extend the left partition. When the left
if turn == CAT: # partition is extended, its maximum becomes the overall maximum.
return [(new_mouse, cat, 3 - turn) for new_mouse in graph[mouse]] # Time - O(n)
return [(mouse, new_cat, 3 - turn) for new_cat in graph[cat] if new_cat != 0] # Space - O(1)

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

while queue: return last_left + 1

i, j, turn, winner = queue.popleft() # get state with known winner


# python_1_to_1000/916_Word_Subsets.py - m
for i2, j2, prev_turn in parents(i, j, turn): # for all predecessor states without known winners
if state_winner[i2, j2, prev_turn] is DRAW: _author_ = 'jake'
_project_ = 'leetcode'
if prev_turn == winner: # can move to a winning state
state_winner[i2, j2, prev_turn] = winner # https://leetcode.com/problems/word-subsets/
queue.append((i2, j2, prev_turn, winner)) # We are given two arrays A and B of words. Each word is a string of lowercase letters.
# Now, say that word b is a subset of word a if every letter in b occurs in a, including multiplicity.
else: # reduce count of unknown winner predecessor states # For example, "wrr" is a subset of "warrior", but is not a subset of "world".
degree[i2, j2, prev_turn] -= 1 # Now say a word a from A is universal if for every b in B, b is a subset of a.
if degree[i2, j2, prev_turn] == 0: # predecessor always leads to loss # Return a list of all universal words in A. You can return the words in any order.
state_winner[i2, j2, prev_turn] = turn

# 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

for b in B: overall_max = max(overall_max, max_ending_here)


freq = Counter(b) overall_min = min(overall_min, min_ending_here)
for letter, count in freq.items():
required[letter] = max(required[letter], count) return max(overall_max, sum(A) - overall_min)

results = []
for a in A: # python_1_to_1000/919_Complete_Binary_Tree_Inserter.py - m

freq = Counter(a) _author_ = 'jake'


if all(freq[letter] >= count for letter, count in required.items()): _project_ = 'leetcode'
results.append(a)
# https://leetcode.com/problems/complete-binary-tree-inserter/
return results # A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled,
# and all nodes are as far left as possible.
# Write a data structure CBTInserter that is initialized with a complete binary tree and supports the following:
# CBTInserter(TreeNode root) initializes the data structure on a given tree with head node root;
# python_1_to_1000/917_Reverse_Only_Letters.py # CBTInserter.insert(int v) will insert a TreeNode into the tree with value node.val = v so that the tree remains
# complete, and returns the value of the parent of the inserted TreeNode;
_author_ = 'jake' # CBTInserter.get_root() will return the head node of the tree.
_project_ = 'leetcode'
# Create a list of nodes of the tree from each row in order. Insert a new node by appending it to the list. Node's
# https://leetcode.com/problems/reverse-only-letters/ # parent has index (i - 1) // 2 - 1 where i is node index (indices start from zero). Link parent to node according
# Given a string S, return the "reversed" string where all characters that are not a letter stay in the same place, # to parity of node index.
# and all letters reverse their positions. # Time - O(n) for init, O(1) for insert and get_root
# Space - O(n)
# Convert to list. 2 pointers start from left and right. Move each pointer inwards until they both reach letters.
# Swap the letters and move the pointers another step each. Stop when pointers overlap. class CBTInserter:
# Time - O(n)
# Space - O(n) def __init__(self, root):
"""
import string :type root: TreeNode
"""
class Solution: self.nodelist = [root]
def reverseOnlyLetters(self, S):
""" for node in self.nodelist: # list is extended by children during iteration
:type S: str if node.left:
:rtype: str self.nodelist.append(node.left)
""" if node.right:
letters = set(string.ascii_lowercase + string.ascii_uppercase) self.nodelist.append(node.right)

S = [c for c in S] def insert(self, v):


left, right = 0, len(S) - 1 """
:type v: int
while left < right: :rtype: int
"""
while left < right and S[left] not in letters: node = TreeNode(v) # add new node to list
left += 1 self.nodelist.append(node)
while left < right and S[right] not in letters: n = len(self.nodelist)
right -= 1
parent = self.nodelist[(n // 2) - 1]
S[left], S[right] = S[right], S[left] if n % 2 == 0:
left += 1 parent.left = node
right -= 1 else:
parent.right = node
return "".join(S)
return parent.val

# python_1_to_1000/918_Maximim_Sum_Circular_Subarray.py - m def get_root(self):


"""
_author_ = 'jake' :rtype: TreeNode
_project_ = 'leetcode' """
return self.nodelist[0] # tree structure is maintained so just return root
# https://leetcode.com/problems/maximum-sum-circular-subarray/
# Given a circular array C of integers represented by A, find the maximum possible sum of a non-empty subarray of C.
# Here, a circular array means the end of the array connects to the beginning of the array. # python_1_to_1000/920_Number_of_Music_Playlists.py - h
# Formally, C[i] = A[i] when 0 <= i < A.length, and C[i+A.length] = C[i] when i >= 0.
# Also, a subarray may only include each element of the fixed buffer A at most once. _author_ = 'jake'
# Formally, for a subarray C[i], C[i+1], ..., C[j], there does not exist i <= k1, k2 <= j with _project_ = 'leetcode'
# k1 % A.length = k2 % A.length.
# https://leetcode.com/problems/number-of-music-playlists/
# Iterate over A, finding the max and min sum subarrays that end at each index. # Your music player contains N different songs and she wants to listen to L (not necessarily different)
# The result either does not use the circularity of A, in which case it is the maximum sum subarray within A. # songs during your trip. You create a playlist so that:
# Or the result is the sum of A minus the minimum sun subarray within A. # Every song is played at least once
# Time - O(n) # A song can only be played again only if K other songs have been played
# Space - O(1) # Return the number of possible playlists. As the answer can be very large, return it modulo 10^9 + 7.

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)

# python_1_to_1000/921_Minimum_Add_to_Make_Parentheses_Valid.py - m class Solution:


def threeSumMulti(self, A, target):
_author_ = 'jake' """
_project_ = 'leetcode' :type A: List[int]
:type target: int
# https://leetcode.com/problems/inimum-add-to-make-parentheses-valid/ :rtype: int
# Given a string S of '(' and ')' parentheses, we add the minimum number of parentheses ( '(' or ')', """
# and in any positions ) so that the resulting parentheses string is valid. counts = [0] * 101
# Formally, a parentheses string is valid if and only if: for num in A:
# It is the empty string, or counts[num] += 1
# It can be written as AB (A concatenated with B), where A and B are valid strings, or
# It can be written as (A), where A is a valid string. result = 0
# Given a parentheses string, return the minimum number of parentheses we must add to make the resulting string valid.
for small, small_count in enumerate(counts):
# Track net balance of open minus closed brackets. Add an opening bracket whenever the balance is negative, because if small_count == 0:
# there cannot be more closed than open brackets. At the end, add closing brackets for all open brackets. continue
# Time - O(n)
# Space - O(1) for med, med_count in enumerate(counts[small:], small):
if med_count == 0:
class Solution: continue
def minAddToMakeValid(self, S):
""" other = target - small - med
:type S: str if other < 0 or other > 100 or counts[other] == 0:
:rtype: int continue
""" other_count = counts[other]
additions = 0 # number of brackets added
net_open = 0 # balance of opening brackets minus closing brackets if small == med == other:
result += small_count * (small_count - 1) * (small_count - 2) // 6
for c in S: elif small == med: # exactly 2 numbers are the same
result += small_count * (small_count - 1) * other_count // 2
net_open += 1 if c == "(" else -1 # update the net_open balance elif other > med: # add if in order (med is always > small)
result += small_count * med_count * other_count
if net_open == -1: # more closing than opening, add an opening bracket
additions += 1 return result % (10 ** 9 + 7)
net_open = 0

return additions + net_open # close all remaining open brackets # python_1_to_1000/924_Minimize_Malware_Spread.py - h

_author_ = 'jake'
# python_1_to_1000/922_Sort_Array_By_Parity_II.py _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/minimize-malware-spread/


_project_ = 'leetcode' # In a network of nodes, each node i is directly connected to another node j if and only if graph[i][j] = 1.
# Some nodes initial are initially infected by malware.
# https://leetcode.com/problems/sort-array-by-parity-ii/ # Whenever two nodes are directly connected and at least one of those two nodes is infected by malware,
# Given an array A of non-negative integers, half of the integers in A are odd, and half of the integers are even. # both nodes will be infected by malware.
# Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is even. # This spread of malware will continue until no more nodes can be infected in this manner.
# You may return any answer array that satisfies this condition. # Suppose M(initial) is the final number of nodes infected with malware in the entire network,
# after the spread of malware stops.
# Iterate over even indices, tracking the next odd index to be checked. If the value at an even index is not even, # We will remove one node from the initial list.
# find the next odd index that is not odd and swap values. # Return the node that if removed, would minimize M(initial).
# Time - O(n) # If multiple nodes could be removed to minimize M(initial), return such a node with the smallest index.
# Space - O(n) # Note that if a node was removed from the initial list of infected nodes, it may still be infected later as
# a result of the malware spread.
class Solution:
def sortArrayByParityII(self, A): # For each node, find all connected nodes. If there is only one initially infected node in the connected group, if it
""" # was not infected it would improve overall the infection by the count of the group.
:type A: List[int] # Find the group of each node, ignoring nodes that already have groups.
:rtype: List[int] # If every group has more than one initially infected node, return the node with the lowest index since removing

# any node cannot reduce the ultimate infection.


# Time - O(n) each node is visited and tested for membership of initial # To make monotone increasing, there is one point in S where all chars on the left are 0 and all on the right are 1.
# Space - O(n) # Count the zeros. Initial case is to flip all zeros to ones.
# For each char, if zero then decrement the number of zeros to be flipped (since the zero is then on the left).
class Solution: # If one, then increment the number of ones to be flipped.
def minMalwareSpread(self, graph, initial): # Time - O(n)
""" # Space - O(1)
:type graph: List[List[int]]
:type initial: List[int] class Solution:
:rtype: int def minFlipsMonoIncr(self, S):
""" """
best_reduction = 0 # the best reduction of infected nodes :type S: str
best_node = min(initial) # the node that improves the infection, by default the lowest index :rtype: int
initial = set(initial) # convert to set """
zeros, ones = S.count("0"), 0
def connected(node): # recursively update group with all connected nodes result = zeros
if node in group:
return for c in S:
group.add(node)
[connected(nbor) for nbor, linked in enumerate(graph[node]) if linked == 1] # loop if c == "0":
zeros -= 1
visited = set() # all nodes that are part of a group else:
for node in range(len(graph)): ones += 1

if node in visited: result = min(result, zeros + ones)


continue
return result
group = set()
connected(node)
overlap = initial & group # set of all nodes in the group that are initially infected # python_1_to_1000/927_Three_Equal_Parts.py - h

if len(overlap) == 1 and len(group) > best_reduction: _author_ = 'jake'


best_reduction = len(group) _project_ = 'leetcode'
best_node = overlap.pop()
# https://leetcode.com/problems/three-equal-parts/
visited |= group # Given an array A of 0s and 1s, divide the array into 3 non-empty parts such that all of these parts represent the
# same binary value.
return best_node # If it is possible, return any [i, j] with i+1 < j, such that:
# A[0], A[1], ..., A[i] is the first part;
# A[i+1], A[i+2], ..., A[j-1] is the second part, and
# python_1_to_1000/925_Long_Pressed_Name.py # A[j], A[j+1], ..., A[A.length - 1] is the third part.
# All three parts have equal binary value.
_author_ = 'jake' # If it is not possible, return [-1, -1].
_project_ = 'leetcode' # Note that the entire part is used when considering what binary value it represents.
# For example, [1,1,0] represents 6 in decimal, not 3.
# https://leetcode.com/problems/long-pressed-name/ # Also, leading zeros are allowed, so [0,1,1] and [1,1] represent the same value.
# Your friend is typing his name into a keyboard.
# Sometimes, when typing a character c, the key might get long pressed, and the character will be typed 1 or more times. # The number of set bits must be divisible by 3. Find the start and end indices containing one_count // 3 set bits.
# You examine the typed characters of the keyboard. # Check that the second and third parts with the first bit set and the same length as the first part are identical.
# Return True if it is possible that it was your friends name, with some characters (possibly none) being long pressed. # Find the trailing zeros from the third part and extend the ends of the first and second parts accordingly.
# Check that the parts do not overlap. There may be additional leading zeros.
# For each char of name, count the run of identical chars. Count the run of the same char in typed. If there are more # Time - O(n)
# chars in name, it was not long pressed. Ensure all chars of typed have been accounted for. # Space - O(1)
# Time - O(m + n)
# Space - O(1) class Solution:
def threeEqualParts(self, A):
class Solution: """
def isLongPressedName(self, name, typed): :type A: List[int]
""" :rtype: List[int]
:type name: str """
:type typed: str one_count = sum(A)
:rtype: bool if one_count == 0: # all zeros, split anywhere
""" return [0, 2]
typed_i, name_i = 0, 0 # indices of next char to check in each string
ones_per_part, remainder = divmod(one_count, 3)
while name_i < len(name): if remainder != 0: # cannot divide set bits into 3 equal groups
return [-1, -1]
c, c_count = name[name_i], 1 # the char and the its count
name_i += 1 first_start = 0
while name_i < len(name) and name[name_i] == c: # count identical chars in name while A[first_start] == 0: # find first set bit
name_i += 1 first_start += 1
c_count += 1
first_end = first_start
while typed_i < len(typed) and typed[typed_i] == c: # count identical chars in typed count = 1
typed_i += 1 while count < ones_per_part: # find ones_per_part-th set bit
c_count -= 1 first_end += 1
count += A[first_end]
if c_count > 0: # more in name than typed length = first_end - first_start + 1
return False
second_start = first_end + 1
return typed_i == len(typed) # must use all of typed while A[second_start] == 0: # first set bit of second part
second_start += 1

# python_1_to_1000/926_Flip_String_to_Monotone_Increasing.py - m if A[first_start:first_end + 1] != A[second_start:second_start + length]:


return [-1, -1] # first and second part set bit patterns must be same
_author_ = 'jake'
_project_ = 'leetcode' third_start = second_start + length
while A[third_start] == 0:
# https://leetcode.com/problems/flip-string-to-monotone-increasing/ third_start += 1
# A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0),
# followed by some number of '1's (also possibly 0.) if A[first_start:first_end + 1] != A[third_start:third_start + length]:
# We are given a string S of '0's and '1's, and we may flip any '0' to a '1' or a '1' to a '0'. return [-1, -1]
# Return the minimum number of flips to make S monotone increasing.
trailing_zeros = len(A) - third_start - length # extend 1st and 2nd parts by trailing_zeros from 3rd part # It is possible to use both of these rules at the same time.
first_end += trailing_zeros # Given a list of emails, we send one email to each address in the list.
second_end = second_start + length - 1 + trailing_zeros # How many different addresses actually receive mails?

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()

# https://leetcode.com/problems/minimize-malware-spread-ii/ for email in emails:


# In a network of nodes, each node i is directly connected to another node j if and only if graph[i][j] = 1.
# Some nodes initial are initially infected by malware. local, domain = email.split("@")
# Whenever two nodes are directly connected and at least one of those two nodes is infected by malware,
# both nodes will be infected by malware. plus = local.index("+")
# This spread of malware will continue until no more nodes can be infected in this manner. if plus != -1:
# Suppose M(initial) is the final number of nodes infected with malware in the entire network, local = local[:plus]
# after the spread of malware stops.
# We will remove one node from the initial list, completely removing it and any connections from this node local = local.replace(".", "")
# to any other node.
# Return the node that if removed, would minimize M(initial). unique.add(local + domain)
# If multiple nodes could be removed to minimize M(initial), return such a node with the smallest index.
return len(unique)
# Convert the graph to an adjacency list structure, mapping each node to its neighbours.
# For each initial node, visit all possible nodes by depth-first search. The allows us to count the number of nodes
# initially infected. # python_1_to_1000/930_Binary_Subarrays_With_Sum.py - m
# The remove each initial node in turn and count the nodes that can be infected from the remaining initial nodes.
# Time - O(n**3), where n is the number of nodes since O(n**2) to explore the graph and O(n) initial nodes. _author_ = 'jake'
# Space - O(n**2) _project_ = 'leetcode'

class Solution: # https://leetcode.com/problems/binary-subarrays-with-sum/


def minMalwareSpread(self, graph, initial): # In an array A of 0s and 1s, how many non-empty subarrays have sum S?
"""
:type graph: List[List[int]] # Iterate along A, counting the number of each prefix sum of A.
:type initial: List[int] # For every prefix subarray, we can make a subarray of sum S with every other prefix subarray of sum running - S.
:rtype: int # Time - O(n)
""" # Space - O(n)
neighbours = {} # map node to list of neighbours
for i, row in enumerate(graph): from collections import defaultdict
neighbours[i] = [j for j, val in enumerate(row) if val == 1 and j != i]
class Solution:
def infected(): # return number of infected nodes, starting from initial def numSubarraysWithSum(self, A, S):
for node in initial: """
connected(node) :type A: List[int]
return len(visited) :type S: int
:rtype: int
def connected(node): # visit all connected nodes recursively """
if node in visited: result = 0
return running = 0 # prefix sum
visited.add(node) partials = defaultdict(int, {0: 1}) # map prefix sum to its count
for nbor in neighbours[node]:
connected(nbor) for i, a in enumerate(A):
running += a
visited = set() result += partials[running - S]
initial_infected = infected() partials[running] += 1 # increment the count with this prefix sum

best_gain = 0 # best reduction in infection, achieved by removing best_node return result


best_node = None

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

visited = {removed} # do not visit removed _author_ = 'jake'


infected() _project_ = 'leetcode'
gain = initial_infected - len(visited) + 1 # add one for removed node
if gain > best_gain: # https://leetcode.com/problems/minimum-falling-path-sum/
best_gain = gain # Given a square array of integers A, we want the minimum sum of a falling path through A.
best_node = removed # A falling path starts at any element in the first row, and chooses one element from each row.
# The next row's choice must be in a column that is different from the previous row's column by at most one.
return best_node
# Dynamic programming. For each row from the bottom upwards, find the minimum falling path sum from each cell.
# The minimum from any cell is the value of that cell plus the minimum of the results from the 3 cells in the row below.
# python_1_to_1000/929_Unique_Email_Addresses.py # Time - O(n**2)
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' class Solution:
def minFallingPathSum(self, A):
# https://leetcode.com/problems/unique-email-addresses/ """
# Every email consists of a local name and a domain name, separated by the @ sign. :type A: List[List[int]]
# For example, in [email protected], alice is the local name, and leetcode.com is the domain name. :rtype: int
# Besides lowercase letters, these emails may contain '.'s or '+'s. """
# If you add periods ('.') between some characters in the local name part of an email address, mail sent there will n = len(A)
# be forwarded to the same address without dots in the local name. row_minima = [0] * n
# For example, "[email protected]" and "[email protected]" forward to the same email address.
# Note that this rule does not apply for domain names. for r in range(n - 1, -1, -1): # from bottom row upwards
# If you add a plus ('+') in the local name, everything after the first plus sign will be ignored.
# This allows certain emails to be filtered, for example [email protected] will be forwarded to [email protected]. new_row_minima = list(A[r]) # initilaise minimum path sums with the value of each cell
# Again, this rule does not apply for domain names.

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:

# https://leetcode.com/problems/number-of-recent-calls/ new_perimeter = set()


# Write a class RecentCounter to count recent requests. for r, c in perimeter:
# It has only one method: ping(int t), where t represents some time in milliseconds. for r1, c1 in neighbours(r, c):
# Return the number of pings that have been made from 3000 milliseconds ago until now. if (r1, c1) in visited:
# Any ping with time in [t - 3000, t] will count, including the current ping. continue
# It is guaranteed that every call to ping uses a strictly larger value of t than before. if A[r1][c1] == 1: # other island found
return steps
# Add each time to a queue. new_perimeter.add((r1, c1))
# Remove all previous times that are longer than 3000ms ago and return the length of the queue.
# Time - O(n) worst case for ping, O(1) on average. visited |= new_perimeter
# Space - O(n) perimeter = new_perimeter
steps += 1
from collections import deque

class RecentCounter:
# python_1_to_1000/935_Knight_Dialer.py - m
def __init__(self):
self.times = deque() _author_ = 'jake'
self.WINDOW = 3000 _project_ = 'leetcode'

def ping(self, t): # https://leetcode.com/problems/knight-dialer/


""" # A chess knight can move 2 squares horizontal/vertical and one square vertical/horizontal.
:type t: int # This time, we place our chess knight on any numbered key of a phone pad (indicated above),
:rtype: int # and the knight makes N-1 hops. Each hop must be from one key to another numbered key.
""" # Each time it lands on a key (including the initial placement of the knight),
self.times.append(t) # it presses the number of that key, pressing N digits total.
while t - self.times[0] > self.WINDOW: # How many distinct numbers can you dial in this manner?
self.times.popleft() # Since the answer may be large, output the answer modulo 10^9 + 7.

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)

# https://leetcode.com/problems/stamping-the-sequence/ class Solution:


# You want to form a target string of lowercase letters. def reorderLogFiles(self, logs):
# At the beginning, your sequence is target.length '?' marks. You also have a stamp of lowercase letters. """
# On each turn, you may place the stamp over the sequence, and replace every letter in the sequence with the :type logs: List[str]
# corresponding letter from the stamp. You can make up to 10 * target.length turns. :rtype: List[str]
# For example, if the initial sequence is "?????", and your stamp is "abc", """
# then you may make "abc??", "?abc?", "??abc" in the first turn. letters, numbers = [], []
# Note that the stamp must be fully contained in the boundaries of the sequence in order to stamp. digits = {str(i) for i in range(10)}
# If the sequence is possible to stamp, then return an array of the index of the left-most letter being stamped
# at each turn. If the sequence is not possible to stamp, return an empty array. for log in logs:
# For example, if the sequence is "ababc", and the stamp is "abc", then we could return the answer [0, 2], space = log.find(" ")
# corresponding to the moves "?????" -> "abc??" -> "ababc". first = log[space + 1]
# Also, if the sequence is possible to stamp, it is guaranteed it is possible to stamp within 10 * target.length moves. if first in digits:
# Any answers specifying more than this number of moves will not be accepted. numbers.append(log)
else:
# From given indices i of target and j of stamp, recursively attempt to build a solution. letters.append((log[space + 1:] + log[:space], log))
# Base cases are too many stamps and having the reached end of the target.
# If at the end of the stamp, we can have put an earlier stamp which now shows only its suffix (may be the whole stamp). letters.sort() # sort by log with identifier at end to break ties
# If stamp and target chars match, we can continue with next chars of stamp and target, or try to start a new stamp.
# Memoize results. return [log for _, log in letters] + numbers
# Time - O(mn) since there are mn possible states and building results is O(1) due to max length of 10.
# Space - O(mn)
# python_1_to_1000/938_Range_Sum_of_BST.py
class Solution:
def movesToStamp(self, stamp, target): _author_ = 'jake'
""" _project_ = 'leetcode'
:type stamp: str
:type target: str # https://leetcode.com/problems/range-sum-of-bst/
:rtype: List[int] # Given the root node of a binary search tree, return the sum of values of all nodes with value between
""" # L and R (inclusive).
memo = {} # The binary search tree is guaranteed to have unique values.

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

elif target[i] != stamp[j]: # cannot continue current stamp if node.val > R:


result = [] return helper(node.left)
if node.val < L:
else: return helper(node.right)
temp = helper(i + 1, j + 1, results) # continue current stamp
if temp: return node.val + helper(node.left) + helper(node.right)
result = temp
else: # start a new stamp return helper(root)

# python_1_to_1000/941_Valid_Mountain_Array.py

# python_1_to_1000/939_Minimum_Area_Rectangle.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/valid-mountain-array/
# Given an array A of integers, return true if and only if it is a valid mountain array.
# https://leetcode.com/problems/minimum-area-rectangle/ # Recall that A is a mountain array if and only if:
# Given a set of points in the xy-plane, determine the minimum area of a rectangle formed from these points, # A.length >= 3
# with sides parallel to the x and y axes. # There exists some i with 0 < i < A.length - 1 such that:
# If there isn't any rectangle, return 0. # A[0] < A[1] < ... A[i-1] < A[i]
# A[i] > A[i+1] > ... > A[B.length - 1]
# Create a map of all the column values at each row value.
# If there are more columns than rows, then we swap this map so it is from each column value to a list of row values. # Increment left pointer as long as array is increasing. Decrement right pointer as long as array is decreasing.
# Sort the row values. For each row, sort the column values. For each pair of columns in that row, if the column # Pointers must meet and not be at ends.
# pair has appeared in a previous row then we have a rectangle. # Time - O(n)
# Update the mapping with each column pair to it's most recent row. # Space - O(1)
# Time - O(max(m, n) * min(m, n) ** 2) since we swap to ensure the inner loop over pairs is over the shorter list
# Space - O(mn) class Solution:
def validMountainArray(self, A):
from collections import defaultdict """
:type A: List[int]
class Solution: :rtype: bool
def minAreaRect(self, points): """
""" n = len(A)
:type points: List[List[int]] left, right = 0, n - 1
:rtype: int
""" while left + 1 < n - 1 and A[left + 1] > A[left]:
rows, cols = set(), set() # sets of unque row and column values left += 1
for r, c in points: while right - 1 > 0 and A[right - 1] > A[right]:
rows.add(r) right -= 1
cols.add(c)
return 0 < left == right < n - 1
row_to_cols = defaultdict(list) # map from a row to the list of columns
if len(rows) > len(cols):
for r, c in points: # python_1_to_1000/942_DI_String_Match.py
row_to_cols[r].append(c)
else: # swap map to be from column to list of rows _author_ = 'jake'
for r, c in points: _project_ = 'leetcode'
row_to_cols[c].append(r)
# https://leetcode.com/problems/di-string-match/
result = float("inf") # Given a string S that only contains "I" (increase) or "D" (decrease), let N = S.length.
# Return any permutation A of [0, 1, ..., N] such that for all i = 0, ..., N-1:
col_pair_to_row = {} # map from pair of column values to a row # If S[i] == "I", then A[i] < A[i+1]
# If S[i] == "D", then A[i] > A[i+1]
for r in sorted(row_to_cols):
# Iterate over S, tracking the next lowest and highest unused numbers.
columns = sorted(row_to_cols[r]) # When the char is "I", append to the result the lowest unused number, since all future numbers are increasing.
# When the char is "D", append to the result the highest unused number, since all future numbers are decreasing.
for i, c1 in enumerate(columns[:-1]): # Time - O(n)
for c2 in columns[i + 1:]: # Space - O(n)

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)

_author_ = 'jake' for c in S:


_project_ = 'leetcode'
if c == "I":
# https://leetcode.com/problems/distinct-subsequences-ii/ result.append(low)
# Given a string S, count the number of distinct, non-empty subsequences of S. low += 1
# Since the result may be large, return the answer modulo 10^9 + 7. else:
result.append(high)
# Create a mapping from each char to the count of subsequences that have been extended by the char. high -= 1
# For each char, we can extend all existing subsequences apart from those previously extended by the same char.
# Also update the mapping for the number of subsequences that have been extended by the char. return result + [low] # append the last unused number
# Time - O(n)
# Space - O(1)
# python_1_to_1000/943_Find_the_Shortest_Superstring.py - h
from collections import defaultdict
_author_ = 'jake'
class Solution: _project_ = 'leetcode'
def distinctSubseqII(self, S):
""" # https://leetcode.com/problems/find-the-shortest-superstring/
:type S: str # Given an array A of strings, find any smallest string that contains each string in A as a substring.
:rtype: int # We may assume that no string in A is substring of another string in A.
"""
total = 1 # start with the empty subsequence # For each pair of words (in both orders) find the overlap.
extended = defaultdict(int) # map char to number of subsequences before last using this char # For each of the 2**n sets of words, for each word in the set as the last word used in the resulting string,
# find the most total overlap with any other word in the set as the previous word in the string.
for c in S: # Time - O(n**2 (2**n + k)) where k is max string length
total, extended[c] = 2 * total - extended[c], total # Space - O(n (2**n + k)) where the nk is for the final result

total -= 1 # remove empty subsequence class Solution:


return total % (10 ** 9 + 7) def shortestSuperstring(self, A):
"""
:type A: List[str]
:rtype: str
"""
N = len(A) _author_ = 'jake'
_project_ = 'leetcode'
overlaps = [[0] * N for _ in range(N)] # overlaps[i][j] is nb chars overlapping between x and y
# https://leetcode.com/problems/minimum-increment-to-make-array-unique/
for i, x in enumerate(A): # Given an array of integers A, a move consists of choosing any A[i], and incrementing it by 1.
for j, y in enumerate(A): # Return the least number of moves to make every value in A unique.
if i != j:
for ans in range(min(len(x), len(y)), 0, -1): # Iterate over the sorted numbers. If a number is more than that last number used, it does not need incrementing.
if x.endswith(y[:ans]): # Else increment it to last_used + 1. In both cases update last_used.
overlaps[i][j] = ans # Time - O(n log n)
break # Space - O(n)

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

_author_ = 'jake' for num in pushed:


_project_ = 'leetcode'
stack.append(num)
# https://leetcode.com/problems/delete-columns-to-make-sorted/ while stack and stack[-1] == popped[i]:
# We are given an array A of N lowercase letter strings, all of the same length. i += 1
# Now, we may choose any set of deletion indices, and for each string, we delete all the characters in those indices. stack.pop()
# 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"], return i == len(popped) # stack is empty if i == popped()
# and the remaining columns of A are ["b","v"], ["e","y"], and ["f","z"].
# Formally, the c-th column is [A[0][c], A[1][c], ..., A[A.length-1][c]].
# Suppose we chose a set of deletion indices D such that after deletions, # python_1_to_1000/947_Most_Stones_Removed_with_Same_Row_or_Column.py - m
# each remaining column in A is in non-decreasing sorted order.
# Return the minimum possible value of D.length. _author_ = 'jake'
_project_ = 'leetcode'
# Rotate the array to iterate over columns. Check if each column is sorted.
# Time - O(m n log n) # https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/
# Space - O(mn) # On a 2D plane, we place stones at some integer coordinate points. Each coordinate point may have at most one stone.
# Now, a move consists of removing a stone that shares a column or row with another stone on the grid.
class Solution: # What is the largest possible number of moves we can make?
def minDeletionSize(self, A):
""" # Any connected component of the graph (points are connected by a common row or column) can be reduced to a single
:type A: List[str] # point by repeatedly pruning.
:rtype: int # Use union-find tree to identify rows and columns that are connected. Remove all stones apart from one per
""" # connected component.
deletions = 0 # Time - O(n log n)
# Space - O(n)
for col in zip(*A): # pass each string as a positional argument to zip
class Solution:
if list(col) != sorted(col): def removeStones(self, stones):
deletions += 1 """
:type stones: List[List[int]]
return deletions :rtype: int
"""
parents = {} # map row or column to its parent
# python_1_to_1000/945_Minimum_Increment_to_Make_Array_Unique.py - m

def find(x): for time in permutations(A):


while x != parents[x]:
x = parents[x] hours = time[0] * 10 + time[1]
return x if hours >= 24:
continue
def union(x, y):
parents.setdefault(x, x) # sets parents[x] to x if not in dictionary minutes = time[2] * 10 + time[3]
parents.setdefault(y, y) if minutes >= 60:
parents[find(x)] = find(y) continue

for i, j in stones: total_minutes = hours * 60 + minutes


union(i, ~j) # ~j == -j - 1, so columns are distinct from rows if total_minutes > best_minutes:
best_minutes = total_minutes
return len(stones) - len({find(x) for x in parents}) best = time

if best_minutes == -1:
# python_1_to_1000/948_Bag_of_Tokens.py - m return ""

_author_ = 'jake' best = [str(x) for x in best]


_project_ = 'leetcode' return "".join(best[:2]) + ":" + "".join(best[2:])

# 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)

return (self.flipEquiv(root1.left, root2.left) and self.flipEquiv(root1.right, root2.right)) \ class Solution(object):


or (self.flipEquiv(root1.left, root2.right) and self.flipEquiv(root1.right, root2.left)) def isAlienSorted(self, words, order):
"""
:type words: List[str]
# python_1_to_1000/952_Largest_Component_Size_by_Common_Factor.py - h :type order: str
:rtype: bool
_author_ = 'jake' """
_project_ = 'leetcode' indices = {c: i for i, c in enumerate(order)}
prev = []
# https://leetcode.com/problems/largest-component-size-by-common-factor/
# Given a non-empty array of unique positive integers A, consider the following graph: for word in words:
# There are A.length nodes, labelled A[0] to A[A.length - 1]; mapping = [indices[c] for c in word]
# There is an edge between A[i] and A[j] if and only if A[i] and A[j] share a common factor greater than 1. if mapping < prev:
# Return the size of the largest connected component in the graph. return False
prev = mapping
# Union-find to connect the indices of elements of A with common prime factors.
# For each element of A, find the set of prime factors. For each prime factor, if not seen before then map the factor return True
# to the index in A of the element. Else union the index of the element with the index already mapped to the factor
# and update the size of the connected component.
# Time - O(n k**0.5 log*(n k**0.5)) since there are O(k**0.5) factors for each element # python_1_to_1000/954_Array_of_Doubled_Pairs.py - m
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def largestComponentSize(self, A):
""" # https://leetcode.com/problems/array-of-doubled-pairs/
:type A: List[int] # Given an array of integers A with even length, return true if and only if it is possible to reorder it
:rtype: int # such that A[2 * i + 1] = 2 * A[2 * i] for every 0 <= i < len(A) / 2.
"""
# Solution requires that numbers are paired as (num, num * 2), hence each element of the input must be the lower
def prime_factors(x): # calculate set of prime factors of x # or higher member of such a pair. Construct pairs from lowest absolute element first.
factors = set() # Count occurrences of each number. For each unique number starting with the smallest absolute value, if the count of
# num * 2 is less than the count of num then we cannot construct the required list of pairs. Otherwise reduce the
while x % 2 == 0: # remove factors of 2, so next loop uses step of 2 # remaining count of num * 2.
factors.add(2) # Time - O(n)
x //= 2 # Space - O(n)

for i in range(3, int(x ** 0.5) + 1, 2): from collections import Counter


while x % i == 0:
factors.add(i) class Solution(object):
x //= i def canReorderDoubled(self, A):
"""
if x > 2: # x is originally prime :type A: List[int]
factors.add(x) :rtype: bool
"""
return factors counts = Counter(A)

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]

def union(x, y): return True


x, y = find(x), find(y)
if x == y:
return # python_1_to_1000/955_Delete_Columns_to_Make_Sorted_II.py - m
parents[x] = y # all children of x are moved to y
sizes[y] += sizes[x] _author_ = 'jake'
sizes[x] = 0 _project_ = 'leetcode'

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)

for row in rows_to_check: state_to_day = {}

char = A[row][col] def next_state(state):


prev_char = A[row - 1][col] return tuple([0] + [int(not (state[i - 1] ^ state[i + 1])) for i in range(1, 7)] + [0])

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)

return cols_deleted return list(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)

new_diffs = defaultdict(int, diffs) queue.append(node.left)


queue.append(node.right)
for diff, used_len in diffs.items():

new_diffs[diff + rod] = max(used_len + rod, new_diffs[diff + rod]) # python_1_to_1000/959_Regions_Cut_By_Slashes.py - m


new_diffs[abs(diff - rod)] = max(used_len + rod, new_diffs[abs(diff - rod)])
_author_ = 'jake'
diffs = new_diffs _project_ = 'leetcode'

return diffs[0] // 2 # https://leetcode.com/problems/regions-cut-by-slashes/


# In a N x N grid composed of 1 x 1 squares, each 1 x 1 square consists of a /, \, or blank space.
# These characters divide the square into contiguous regions.
# python_1_to_1000/957_Prison_Cells_After_N_Days.py - m # (Note that backslash characters are escaped, so a \ is represented as "\\".)
# Return the number of regions.
_author_ = 'jake'
_project_ = 'leetcode' # Create graph where each cell of grid has 4 nodes, one for each edge.
# Connect edge nodes to neighbouring cells and make connections within a cell's edge nodes according to the slash.
# https://leetcode.com/problems/prison-cells-after-n-days/ # Connections are undirected, hence only one direction of a connection is required.
# There are 8 prison cells in a row, and each cell is either occupied or vacant. # Union-find each pair of nodes connected by an edge and count the number of ultimate parents.
# Each day, whether the cell is occupied or vacant changes according to the following rules: # Time - O(n**2 log*n)
# If a cell has two adjacent neighbors that are both occupied or both vacant, then the cell becomes occupied. # Space - O(n**2)
# Otherwise, it becomes vacant.
# Note that because the prison is a row, the first and the last cells in the row can't have two adjacent neighbors. class Solution(object):
# We describe the current state of the prison in the following way: cells[i] == 1 if the i-th cell is occupied, def regionsBySlashes(self, grid):
# else cells[i] == 0. """
# Given the initial state of the prison, return the state of the prison after N days and N such changes. :type grid: List[str]
:rtype: int
# For 8 cells, the ends are vacant after the first day so there are at most 2**6 = 64 possible states. """
# After at most 64 days there will be a cycle in the pattern of cells. Evolve the cells until a repeated state is n= len(grid)
# found. Subtract as many cycles as possible from the remaining days, then evolve to the final state. UP, RIGHT, DOWN, LEFT = 0, 1, 2, 3
# Time - O(1)
# Space - O(1) parents = {} # map cell (r, c, dirn) to its parent

class Solution(object): def find(node): # return ultimate parent of a node


def prisonAfterNDays(self, cells, N): parents.setdefault(node, node)
""" while parents[node] != node:
:type cells: List[int] parents[node] = parents[parents[node]] # collapse links
:type N: int node = parents[node]
:rtype: List[int] return node
"""
day = 0 def union(node1, node2): # union ultimate parents
state = tuple(cells) # state can be a dict key parent1, parent2 = find(node1), find(node2)
parents[parent2] = parent1
# python_1_to_1000/962_Maximum_Width_Ramp.py - m
for r in range(n):
for c in range(n): _author_ = 'jake'
if r != n - 1: # connect to cell below _project_ = 'leetcode'
union((r, c, DOWN), (r + 1, c, UP))
if c != n - 1: # connect to cell to right # https://leetcode.com/problems/maximum-width-ramp/
union((r, c, RIGHT), (r, c + 1, LEFT)) # Given an array A of integers, a ramp is a tuple (i, j) for which i < j and A[i] <= A[j].
# The width of such a ramp is j - i.
if grid[r][c] == "/": # connect pairs of edge nodes within cell if slash # Find the maximum width of a ramp in A. If one doesn't exist, return 0.
union((r, c, UP), (r, c, LEFT))
union((r, c, DOWN), (r, c, RIGHT)) # If a later element of A is greater than or equal to an earlier element then the earlier element makes a wider ramp.
elif grid[r][c] == "\\": # Hence we find the indices of strictly decreasing elements of A, which are candidates for the left edges of ramps.
union((r, c, UP), (r, c, RIGHT)) # Then iterate over A again from the last index to the first, considering each element as the right edge of a ramp.
union((r, c, DOWN), (r, c, LEFT)) # When an element is greater than the top of stack, update max_ramp and pop off top of stack since lower index
else: # connect all edge nodes # elements of A cannot make wider ramps.
union((r, c, UP), (r, c, LEFT)) # Time - O(n)
union((r, c, UP), (r, c, DOWN)) # Space - O(n)
union((r, c, UP), (r, c, RIGHT))
class Solution(object):
return len({find(node) for node in parents.keys()}) # number of ultimate parents def maxWidthRamp(self, A):
"""
:type A: List[int]
:rtype: int
# python_1_to_1000/960_Delete_Columns_to_Make_Sorted_III.py - h """
max_ramp = 0
_author_ = 'jake' stack = [] # stack of indices in decreasing value order, left edges of ramps
_project_ = 'leetcode'
for i, num in enumerate(A):
# https://leetcode.com/problems/delete-columns-to-make-sorted-iii/ if not stack or num < A[stack[-1]]:
# We are given an array A of N lowercase letter strings, all of the same length. stack.append(i)
# Now, we may choose any set of deletion indices, and for each string, we delete all the characters in those indices.
# For example, if we have an array A = ["babca","bbazb"] and deletion indices {0, 1, 4}, for i in range(len(A) - 1, -1, -1): # iterate backwards
# then the final array after deletions is ["bc","az"]. while stack and A[i] >= A[stack[-1]]:
# Suppose we chose a set of deletion indices D such that after deletions, the final array has every element (row) max_ramp = max(max_ramp, i - stack.pop())
# in lexicographic order.
# For clarity, A[0] is in lexicographic order (ie. A[0][0] <= A[0][1] <= ... <= A[0][A[0].length - 1]), A[1] is in return max_ramp
# lexicographic order (ie. A[1][0] <= A[1][1] <= ... <= A[1][A[1].length - 1]), and so on.
# Return the minimum possible value of D.length.
# python_1_to_1000/963_Minimum_Area_Rectangle_II.py - m
# Find the maximum length subsequence containing columns which are already sorted.
# Dynamic programming recording the max_subsequence ending at each index. _author_ = 'jake'
# For each ending index, for each other index, update the max_subsequence if the ending and other columns are sorted. _project_ = 'leetcode'
# Update is the max of current max_subsequence and 1 + max_subsequence ending at other index.
# Time - O(n**2 m) # https://leetcode.com/problems/minimum-area-rectangle-ii/
# Space - O(n) # Given a set of points in the xy-plane, determine the minimum area of any rectangle formed from these points,
# with sides not necessarily parallel to the x and y axes.
class Solution(object): # If there isn't any rectangle, return 0.
def minDeletionSize(self, A):
""" # Convert points to complex numbers for easier vector operations.
:type A: List[str] # Sort points so directions of vectors are aligned (else opposite directions are double counted).
:rtype: int # Map each vector between a pair to a list of mid-points of that vector.
""" # For each vector, if the vector between any pair of mid-points is perpendicular to the vector then a rectangle can
rows, cols = len(A), len(A[0]) # be formed.
max_subsequence = [1] * cols # Time - O(n**2)
# Space - O(n**2)
for col_end in range(1, cols):
for col in range(col_end): from collections import defaultdict
if all(A[r][col] <= A[r][col_end] for r in range(rows)): from itertools import combinations
max_subsequence[col_end] = max(max_subsequence[col_end],
max_subsequence[col] + 1) class Solution(object):
def minAreaFreeRect(self, points):
return cols - max(max_subsequence) """
:type points: List[List[int]]
:rtype: float
"""
# python_1_to_1000/961_N-Repeated_Element_in_Size_2N_Array.py min_area = float("inf")

_author_ = 'jake' points = [complex(*p) for p in sorted(points)]


_project_ = 'leetcode' line_to_mid = defaultdict(list)

# https://leetcode.com/problems/n-repeated-element-in-size-2n-array/ for p1, p2 in combinations(points, 2):


# In a array A of size 2N, there are N+1 unique elements, and exactly one of these elements is repeated N times. line_to_mid[p2 - p1].append((p1 + p2) / 2)
# Return the element repeated N times.
for line1, mid_points in line_to_mid.items():
# Iterate over A, adding elements to set. Return when duplicated element is found. for mid1, mid2 in combinations(mid_points, 2):
# Time - O(n)
# Space - O(n) line2 = mid2 - mid1
if line1.real * line2.real + line1.imag * line2.imag == 0:
class Solution(object): min_area = min(min_area, abs(line1) * abs(line2))
def repeatedNTimes(self, A):
""" return min_area if min_area != float("inf") else 0
:type A: List[int]
:rtype: int
""" # python_1_to_1000/964_Least_Operators_to_Express_Number.py - h
seen = set()
_author_ = 'jake'
for num in A: _project_ = 'leetcode'
if num in seen:
return num # https://leetcode.com/problems/least-operators-to-express-number
seen.add(num) # Given a single positive integer x, we will write an expression of the form x (op1) x (op2) x (op3) x ... where each
# operator op1, op2, etc. is either addition, subtraction, multiplication, or division (+, -, *, or /).
# For example, with x = 3, we might write 3 * 3 / 3 + 3 - 3 which is a value of 3.

# When writing such an expression, we adhere to the following conventions: #


# The division operator (/) returns rational numbers. # When the query exactly matches a word in the wordlist (case-sensitive), you should return the same word back.
# There are no parentheses placed anywhere. # When the query matches a word up to capitlization, you should return the first such match in the wordlist.
# We use the usual order of operations: multiplication and division happens before addition and subtraction. # When the query matches a word up to vowel errors, you should return the first such match in the wordlist.
# It's not allowed to use the unary negation operator (-). # If the query has no matches in the wordlist, you should return the empty string.
# For example, "x - x" is a valid expression as it only uses subtraction, but "-x + x" is not because it uses negation. # Given some queries, return a list of words answer, where answer[i] is the correct word for query = queries[i].
# Write an expression with the least number of operators such that the expression equals the given target.
# Return the least number of operators used. # Create a set of the words for O(1) lookup. Map the lower case of each word to the first such word.
# Map the lower case with vowels replaced by underscore to the first such word.
# Build the target as a number in base x, starting from the least significant digit. # Look up each word in the set and both mappings, returning the first hit.
# For each digit, we can either make the digit as a sum of ones (each one being made from x / x), or make the next # Time - O(m + n)
# power of x minus the digit. # Space - O(m + n)
# Apart from the first digit, subsequent digits are made as a power multiplied by the digits and possibly with an
# additional factor of power and the previous neg result. from re import sub
# Time - O(log n)
# Space - O(1) class Solution:
def spellchecker(self, wordlist, queries):
class Solution(object): """
def leastOpsExpressTarget(self, x, target): :type wordlist: List[str]
""" :type queries: List[str]
:type x: int :rtype: List[str]
:type target: int """
:rtype: int
""" def replace_vowels(word):
pos = neg = powers = 0 return sub('[aeiou]', '_', word)

while target: wordsset = set(wordlist)


target, remainder = divmod(target, x) # remainder is the next digit to be built in base x
lower_words, vowel_words = {}, {}
if powers == 0: for word in wordlist:
pos, neg = remainder * 2, (x - remainder) * 2 # make digit or x - digit lower_words.setdefault(word.lower(), word) # do not overwrite if key already exists
else: for word in lower_words.keys():
pos, neg = min(remainder * powers + pos, (remainder + 1) * powers + neg), \ replaced = replace_vowels(word)
min((x - remainder) * powers + pos, (x - remainder - 1) * powers + neg) vowel_words.setdefault(replaced, lower_words[word])

powers += 1 def check(word):


if word in wordsset:
return min(pos, powers + neg) - 1 # add the final power to neg, subtract 1 since no final operator return word

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)

# https://leetcode.com/problems/binary-tree-cameras/ class Solution(object):


# Given a binary tree, we install cameras on the nodes of the tree. def powerfulIntegers(self, x, y, bound):
# Each camera at a node can monitor its parent, itself, and its immediate children. """
# Calculate the minimum number of cameras needed to monitor all nodes of the tree. :type x: int
:type y: int
# Bottom-up recursion. Helper function returns the number of cameras to cover a subtree, apart from potentially not :type bound: int
# covering the root. Maintain a set of nodes that are covered. :rtype: List[int]
# After processing child subtrees, if either child is not covered then there must be a camera at the node and hence """
# its parent is also covered. result = set()
# Time - O(n)
# Space - O(n) def make_power_list(val):
power_list = [1]
class Solution(object): if val != 1: # val == 1 means list of only 1
def minCameraCover(self, root): while power_list[-1] <= bound:
""" power_list.append(power_list[-1] * val)
:type root: TreeNode power_list.pop() # last value is too large
:rtype: int return power_list
"""
covered = {None} # empty leaves are always covered x_list, y_list = make_power_list(x), make_power_list(y)

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

return result _author_ = 'jake'


_project_ = 'leetcode'
cameras = helper(root, None)
return cameras if root in covered else cameras + 1 # potentially add camera at root # https://leetcode.com/problems/flip-binary-tree-to-match-preorder-traversal/
# Given a binary tree with N nodes, each node has a different value from {1, ..., N}.
# A node in this binary tree can be flipped by swapping the left child and the right child of that node.
# Consider the sequence of N values reported by a preorder traversal starting from the root.
# python_1_to_1000/969_Pancake_Sorting.py - m # Call such a sequence of N values the voyage of the tree.
# Recall that a preorder traversal of a node means we report the current node's value, then preorder-traverse the
_author_ = 'jake' # left child, then preorder-traverse the right child.
_project_ = 'leetcode' # Our goal is to flip the least number of nodes so that the voyage of the tree matches the voyage we are given.
# If we can do so, then return a list of the values of all nodes flipped. You may return the answer in any order.
# https://leetcode.com/problems/pancake-sorting/ # If we cannot do so, then return the list [-1].
# Given an array A, we can perform a pancake flip: We choose some positive integer k <= A.length,
# then reverse the order of the first k elements of A. # Recursive helper function returns whether subtree can be flipped to match voyage and increments index of next
# We want to perform zero or more pancake flips (doing them one after another in succession) to sort the array A. # element of voyage to be tested. Note that voyage is the same length as the number of nodes in the tree.
# Return the k-values corresponding to a sequence of pancake flips that sort A. # After checking the root against voyage, if there is a left child that doesn't match the next element of voyage
# Any valid answer that sorts the array within 10 * A.length flips will be judged as correct. # then there must be a flip. If no left child, the next element of voyage must match the right child (if any).
# Time - O(n)
# For each number descending from the largest, find the index of the number. Flip the list up to and including that # Space - O(n)
# number to move it to the beginning. Then flip the list up to the end of the already sorted part, to add the
# number to the sorted part. The two flips combine to shift A[:i + 1] next to the already sort part and move the class Solution(object):
# reversed A[i + 1:unsorted] to the beginning. def flipMatchVoyage(self, root, voyage):
# Time - O(n**2) """
# Space - O(n) :type root: TreeNode
:type voyage: List[int]
class Solution: :rtype: List[int]
def pancakeSort(self, A): """
""" flipped = []
:type A: List[int] self.i = 0 # index of next node in voyage
:rtype: List[int]
""" def preorder(node): # returns False if voyage cannot be matched by traversal
flips = [] if not node:
return True
for unsorted in range(len(A), 0, -1): # each unsorted number in decresing order
if voyage[self.i] != node.val: # must match root
i = A.index(unsorted) return False
if i == unsorted - 1: # already in correct position self.i += 1
continue
if node.left:
A = A[unsorted - 1:i:-1] + A[:i + 1] + A[unsorted:]
flips += [i + 1, unsorted] if node.left.val != voyage[self.i]:
flipped.append(node.val)
return flips node.left, node.right = node.right, node.left
if not preorder(node.left): # recurse with left subtree
return False

# python_1_to_1000/970_Powerful_Integers.py - m return preorder(node.right)

_author_ = 'jake' return flipped if preorder(root) else [-1]


_project_ = 'leetcode'

# 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'

_project_ = 'leetcode' def subarraysDivByK(self, A, K):


"""
# https://leetcode.com/problems/equal-rational-numbers/ :type A: List[int]
# Given two strings S and T, each of which represents a non-negative rational number, :type K: int
# return True if and only if they represent the same number. :rtype: int
# The strings may use parentheses to denote the repeating part of the rational number. """
# In general a rational number can be represented using up to three parts: an integer part, a non-repeating part, result = 0
# and a repeating part. running_sum = 0
# The number will be represented in one of the following three ways: prefix_sums = defaultdict(int)
# <IntegerPart> (e.g. 0, 12, 123) prefix_sums[0] = 1
# <IntegerPart><.><NonRepeatingPart> (e.g. 0.5, 1., 2.12, 2.0001)
# <IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)> (e.g. 0.1(6), 0.9(9), 0.00(1212)) for num in A:
# The repeating portion of a decimal expansion is conventionally denoted within a pair of round brackets. For example: running_sum = (running_sum + num) % K
# 1 / 6 = 0.16666666... = 0.1(6) = 0.1666(6) = 0.166(66) result += prefix_sums[running_sum]
# Both 0.1(6) or 0.1666(6) or 0.166(66) are correct representations of 1 / 6. prefix_sums[running_sum] += 1

# 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

from fractions import Fraction _author_ = 'jake'


_project_ = 'leetcode'
class Solution:
def isRationalEqual(self, S, T): # https://leetcode.com/problems/odd-even-jump/
""" # You are given an integer array A. From some starting index, you can make a series of jumps.
:type S: str # The (1st, 3rd, 5th, ...) jumps in the series are called odd numbered jumps, and the (2nd, 4th, 6th, ...) jumps in
:type T: str # the series are called even numbered jumps.
:rtype: bool #
""" # You may from index i jump forward to index j (with i < j) in the following way:
def to_numeric(s): # During odd numbered jumps (ie. jumps 1, 3, 5, ...), you jump to the index j such that A[i] <= A[j] and A[j] is the
# smallest possible value. If there are multiple such indexes j, you can only jump to the smallest such index j.
if not ("(") in s: # no repeating part # During even numbered jumps (ie. jumps 2, 4, 6, ...), you jump to the index j such that A[i] >= A[j] and A[j] is the
return Fraction(s) # largest possible value. If there are multiple such indexes j, you can only jump to the smallest such index j.
# (It may be the case that for some index i, there are no legal jumps.)
non_repeat, repeat = s.split("(") # A starting index is good if, starting from that index, you can reach the end of the array (index A.length - 1) by
repeat = repeat[:-1] # remove closing brace # jumping some number of times (possibly 0 or more than once.)
# Return the number of good starting indexes.
_, non_repeat_decimal = non_repeat.split(".")
# Create lists of the next smaller and the next larger element from each element of the array.
fract = Fraction(int(repeat), (10 ** len(repeat) - 1) * (10 ** len(non_repeat_decimal))) # Lists are made by sorting the indices of A in ascending and descending order of the values. Indices are popped from
# a stack when a next smaller or larger element is found.
return Fraction(non_repeat) + fract # Then iterate backwards over A, when an index has a next larger element, we can make an odd jump to the next larger
# element and reach the end if we can make an even jump from there.
return to_numeric(S) == to_numeric(T) # Time - O(n log n)
# Space - O(n)

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

class Solution: result = max(result, up, down)


def largestPerimeter(self, A): up, down = down, up # swap so next iteration considers opposite move
"""
:type A: List[int] return result + 1 if result != 0 else 0 # add 1 for final element only if any sequence found
:rtype: int
"""
A.sort(reverse=True)
# python_1_to_1000/979_Distribute_Coins_in_Binary_Tree.py - m
for i, side in enumerate(A[:-2]):
if side < A[i + 1] + A[i + 2]: _author_ = 'jake'
return side + A[i + 1] + A[i + 2] _project_ = 'leetcode'

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

return result[::-1] # reverse to decreasing order


# python_1_to_1000/980_Unique_Paths_III.py - h

_author_ = 'jake'
# python_1_to_1000/978_Longest_Turbulent_Subarray.py - m _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/unique-paths-iii/


_project_ = 'leetcode' # On a 2-dimensional grid, there are 4 types of squares:
# 1 represents the starting square. There is exactly one starting square.
# https://leetcode.com/problems/longest-turbulent-subarray/ # 2 represents the ending square. There is exactly one ending square.
# A subarray A[i], A[i+1], ..., A[j] of A is said to be turbulent if and only if: # 0 represents empty squares we can walk over.
# For i <= k < j, A[k] > A[k+1] when k is odd, and A[k] < A[k+1] when k is even; # -1 represents obstacles that we cannot walk over.
# OR, for i <= k < j, A[k] > A[k+1] when k is even, and A[k] < A[k+1] when k is odd. # Return the number of 4-directional walks from the starting square to the ending square,
# In other words, the subarray is turbulent if the comparison sign flips between each adjacent pair of elements # that walk over every non-obstacle square exactly once.
# in the subarray.
# Return the length of a maximum size turbulent subarray of A. # Create a set of cells to visit and identify the start and end cells.
# From the start, recursively visit all unvisited neighbours, removing the neighbour from unvisited before recusing
# Track the longest subarrays where the last move is up and the last move is down. # and adding it back after returning.
# For each difference between elements of the array, extend either the up, the down or neither sequence. # Bases cases are end reached with all cells visited or it is impossible to do so.
# Swap the up and down counts after every iteration, so the next iteration is opposite. # Time - O(4**mn)
# Time - O(n) # Space - O(mn)
# Space - O(1)
class Solution:
class Solution: def uniquePathsIII(self, grid):
def maxTurbulenceSize(self, A): """
""" :type grid: List[List[int]]
:type A: List[int] :rtype: int
:rtype: int """
""" rows, cols = len(grid), len(grid[0])
if len(A) == 1: # special case of single element unvisited = set()
return 1
for r in range(rows):
result = 0 for c in range(cols):
down, up = 0, 0 # longest sequences where last move is up and down if grid[r][c] == 1:
start = (r, c)
for i in range(1, len(A)): elif grid[r][c] == 2:
end = (r, c)
if A[i] > A[i - 1]: # extend up sequence, no down sequence unvisited.add((r, c))
up += 1 elif grid[r][c] == 0:
down = 0 unvisited.add((r, c))
elif A[i] < A[i - 1]: # extend down sequence, no up sequence
down += 1 def make_paths(r, c):

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':

from collections import defaultdict PASSES = [1, 7, 30] # days covered


import bisect
@lru_cache(None)
class TimeMap: def get_min_cost(i): # min cost from days[i] onwards

def __init__(self): if i >= len(days):


""" return 0
Initialize your data structure here.
""" min_cost = float("inf")
self.key_to_values = defaultdict(list) j = i
self.key_to_times = defaultdict(list) for length, cost in zip(PASSES, costs):
while j < len(days) and days[j] < days[i] + length: # find next uncovered travel day by this pass
def set(self, key: 'str', value: 'str', timestamp: 'int') -> 'None': j += 1
self.key_to_values[key].append(value) min_cost = min(min_cost, cost + get_min_cost(j))
self.key_to_times[key].append(timestamp)
return min_cost
def get(self, key: 'str', timestamp: 'int') -> 'str':
i = bisect.bisect_right(self.key_to_times[key], timestamp) return get_min_cost(0)
if i == 0:
return ""
return self.key_to_values[key][i - 1]
# python_1_to_1000/984_String_Without_AAA_or_BBB.py - m

_author_ = 'jake'
# python_1_to_1000/982_Triples_with_Bitwise_AND_Equal_To_Zero.py - h _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/string-without-aaa-or-bbb/


_project_ = 'leetcode' # Given two integers A and B, return any string S such that:
# S has length A + B and contains exactly A 'a' letters, and exactly B 'b' letters;
# https://leetcode.com/problems/triples-with-bitwise-and-equal-to-zero/ # The substring 'aaa' does not occur in S;
# Given an array of integers A, find the number of triples of indices (i, j, k) such that: # The substring 'bbb' does not occur in S.
# 0 <= i < A.length
# 0 <= j < A.length # If A and B are not equal, create as many groups of "xxy" as possible where x is the letter with the greater count.
# 0 <= k < A.length # Each group reduces the count difference by 1. Then add as many pairs of "ab" as possible, followed by any
# A[i] & A[j] & A[k] == 0, where & represents the bitwise-AND operator. # remaining single letters.
# Time - O(a + b)
# Count the numbers of ways to form the AND for all pairs. # Space - O(a + b)
# For each number, if the AND with any AND of a pair is zero then add the count of all pairs to the result.
# Time - O(n**2) since the number of pairs is limited by the 2**16 for 16 bit elements of A. Calculation of pairs takes class Solution:
# O(n**2) but the calculation of result takes O(n). def strWithout3a3b(self, a, b):
# Space - O(n**2) """
:type A: int
from collections import defaultdict :type B: int
:rtype: str
class Solution: """
def countTriplets(self, A): result = []
""" diff = a - b
:type A: List[int] if diff > 0:
:rtype: int groups = min(diff, b)
""" result = ["aab"] * groups # equalize the difference as much as possible
pairs = defaultdict(int) a -= 2 * groups # update remaining required letters
b -= groups
for num1 in A: elif diff < 0:
for num2 in A: groups = min(-diff, a)
pairs[num1 & num2] += 1 result = ["bba"] * groups
b -= 2 * groups
result = 0 a -= groups
result.append(Interval(s=last_start, e=first_end))
pairs = min(a, b)
result += ["ab"] * pairs if A[i].end < B[j].end: # move past interval that ends first
a -= pairs i += 1
b -= pairs else:
j += 1
result += ["a"] * a + ["b"] * b # at most one of "a" or "b"
return result
return "".join(result)

# 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]])

_author_ = 'jake' return result


_project_ = 'leetcode'

# 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 ""

while i < len(A) and j < len(B): node_char = chr(node.val + ord("a"))

last_start = max(A[i].start, B[j].start) left, right = helper(node.left), helper(node.right)


first_end = min(A[i].end, B[j].end)
if last_start <= first_end: # no overlap if max start is after first end if not left or not right:

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.

# https://leetcode.com/problems/add-to-array-form-of-integer/ # If X > Y then we never multiply, just repeatedly subtract 1.


# For a non-negative integer X, the array-form of X is an array of its digits in left to right order. # Otherwise reduce Y to X. Division reduces Y and addition increases Y.
# For example, if X = 1231, then the array form is [1,2,3,1]. # Greedily divide whenever possible, since it is optimal to divide a smaller number before adding, rather than add
# Given the array-form A of a non-negative integer X, return the array-form of the integer X+K. # then divide a larger number.
# Time - O(log Y)
# Treat K as the carry. Add carry to the least significant digit then divide by 10 to get the new carry, with the # Space - O(1)
# remainder being the new digit.
# Time - O(max(log K, n)) where n is the length of A class Solution(object):
# Space - O(max(log K, n)) def brokenCalc(self, X, Y):
"""
class Solution(object): :type X: int
def addToArrayForm(self, A, K): :type Y: int
""" :rtype: int
:type A: List[int] """
:type K: int operations = 0
:rtype: List[int]
""" while Y > X:
for i in range(len(A) - 1, -1, -1): # iterate from least significant digit operations += 1
A[i] += K if Y % 2 == 0:
K, A[i] = divmod(A[i], 10) Y //= 2
else:
return [int(c) for c in str(K)] + A if K else A # append remaining carry if any Y += 1

return X - Y + operations

# python_1_to_1000/990_Satisfiability_of_Equality_Equations.py - m

_author_ = 'jake' # python_1_to_1000/992_Subarrays_with_K_Different_Integers.py - h


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/satisfiability-of-equality-equations/ _project_ = 'leetcode'
# Given an array equations of strings that represent relationships between variables, each string equations[i] has
# length 4 and takes one of two different forms: "a==b" or "a!=b". # https://leetcode.com/problems/subarrays-with-k-different-integers/
# Here, a and b are lowercase letters (not necessarily different) that represent one-letter variable names. # Given an array A of positive integers, call a (contiguous, not necessarily distinct) subarray of A good if the
# Return true if and only if it is possible to assign integers to variable names to satisfy all the given equations. # number of different integers in that subarray is exactly K.
# For example, [1,2,3,1,2] has 3 different integers: 1, 2, and 3.
# Create an undirected graph mapping each variable to the list of variables it is equal to. # Return the number of good subarrays of A.
# Mark all connected variables as belonging to the same group.
# Return false if any pair of not equal variables belong to the same group. # For each ending index of a subarray, find the starting index such that all subarrays contains at most K distinct
# Alternatively, union-find. # elements. The difference between the at_most_k(K) and at_most_k(K - 1) is the number of subarrays with exactly K.
# Time - O(n) # A counter tracks the numbers in the sliding window, adding each element and decrementing the required distinct if
# Space - O(n) # the new element is not already in the window. Then while there are too many distinct elements, move the start index
# forward and remove elements from the window. Result is incremented by all subarrays of length <= end - start + 1.
class Solution(object): # Time - O(n)
def equationsPossible(self, equations): # Space - O(n)
"""
:type equations: List[str] from collections import Counter
:rtype: bool
""" class Solution(object):
graph = [[] for _ in range(26)] # map of variable to equal variables def subarraysWithKDistinct(self, A, K):
not_equal = [] # tuples of not equal variables """
:type A: List[int]
for eqn in equations: :type K: int
first, op, second = eqn[0], eqn[1], eqn[3] :rtype: int
first, second = ord(first) - ord("a"), ord(second) - ord("a") # convert letter variables to integers """
def at_most_k(distinct):
if op == "=":
graph[first].append(second) count = Counter()
graph[second].append(first) subarrays = 0
else: start = 0
not_equal.append((first, second))
for end, num in enumerate(A):
groups = [None] * 26 # group index of equal variables
if count[num] == 0:
def dfs(node, group): distinct -= 1
if groups[node] is None: count[num] += 1
groups[node] = group
for nbor in graph[node]: while distinct < 0: # too many distinct elements
dfs(nbor, group) count[A[start]] -= 1
if count[A[start]] == 0:
for i in range(26): # if not already set, set connected variable group index distinct += 1
dfs(i, i) start += 1 # move start of window forwards

for first, second in not_equal: subarrays += end - start + 1


if groups[first] == groups[second]:
return False return subarrays

return True return at_most_k(K) - at_most_k(K - 1)


for r, c in rotten:
# python_1_to_1000/993_Cousins_in_Binary_Tree.py for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]: # check all neighbours
if (r + dr, c + dc) in fresh:
_author_ = 'jake' new_rotten.add((r + dr, c + dc))
_project_ = 'leetcode'
if not new_rotten:
# https://leetcode.com/problems/cousins-in-binary-tree/ return -1
# In a binary tree, the root node is at depth 0, and children of each depth k node are at depth k+1. rotten = new_rotten
# Two nodes of a binary tree are cousins if they have the same depth, but have different parents. fresh -= new_rotten
# We are given the root of a binary tree with unique values, and the values x and y of two different nodes in the tree.
# Return true if and only if the nodes corresponding to the values x and y are cousins. return mins

# 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)

x_node = val_to_node.get(x, None) from collections import deque


y_node = val_to_node.get(y, None)
if x_node is not None and y_node is not None: class Solution(object):
return node_to_parent[x_node] != node_to_parent[y_node] def minKBitFlips(self, A, K):
if x_node is not None or y_node is not None: """
return False :type A: List[int]
:type K: int
new_val_to_node = {} :rtype: int
for node in val_to_node.values(): """
if node.left: flips = 0
node_to_parent[node.left] = node flip_i = deque() # sliding window of indices of flips
new_val_to_node[node.left.val] = node.left
if node.right: for i in range(len(A)):
node_to_parent[node.right] = node
new_val_to_node[node.right.val] = node.right while flip_i and flip_i[0] + K <= i: # remove flips that do not affect A[i]
val_to_node = new_val_to_node flip_i.popleft()

if (A[i] + len(flip_i)) % 2 == 0: # A[i] must be flipped


if i > len(A) - K:
# python_1_to_1000/994_Rotting_Oranges.py - m return -1 # cannot flip last K elements
flips += 1
_author_ = 'jake' flip_i.append(i)
_project_ = 'leetcode'
return flips
# https://leetcode.com/problems/rotting-oranges/
# In a given grid, each cell can have one of three values:
# the value 0 representing an empty cell;
# the value 1 representing a fresh orange; # python_1_to_1000/996_Number_of_Squareful_Arrays.py - h
# the value 2 representing a rotten orange.
# Every minute, any fresh orange that is adjacent (4-directionally) to a rotten orange becomes rotten. _author_ = 'jake'
# Return the minimum number of minutes that must elapse until no cell has a fresh orange. _project_ = 'leetcode'
# If this is impossible, return -1 instead.
# https://leetcode.com/problems/number-of-squareful-arrays/
# Breadth-first search. Create sets of coordinates of fresh and rotted oranges. While there are still some fresh, # Given an array A of non-negative integers, the array is squareful if for every pair of adjacent elements,
# for each rotten orange, add any fresh neighbours to the set to be updated and add the rotten orange to the set of # their sum is a perfect square.
# already checked oranges. # Return the number of permutations of A that are squareful.
# For each minute, if there are no new rotten oranges and some fresh then not all oranges can be rotten. # Two permutations A1 and A2 differ if and only if there is some index i such that A1[i] != A2[i].
# Else remove the checked oranges from rotten and convert newly rotted oranges from fresh to rotten.
# Time - O(mn) # Create a mapping from each number to all numbers that sum to a square.
# Space - O(mn) # Start the permutation with any element. For each next element that can sum to a square, if the count of that element
# is not zero, use the element and recurse. Add the element back to the count when backtracking.
class Solution(object): # Time - O(n**n)
def orangesRotting(self, grid): # Space - O(n)
"""
:type grid: List[List[int]] from collections import defaultdict, Counter
:rtype: int
""" class Solution(object):
rows, cols = len(grid), len(grid[0]) def numSquarefulPerms(self, A):
fresh, rotten = set(), set() """
:type A: List[int]
for r in range(rows): :rtype: int
for c in range(cols): """
if grid[r][c] == 1: freq = Counter(A) # counts of each element of A
fresh.add((r, c)) pairs = defaultdict(set) # map element to the set of elements that sum to a square
if grid[r][c] == 2: unique = list(freq.keys())
rotten.add((r, c)) pairs[None] = unique # any element can start an empty permutation

mins = 0 for i, num1 in enumerate(unique): # create pairs mapping


while fresh: for num2 in unique[i:]:
mins += 1 if int((num1 + num2) ** 0.5) ** 2 == num1 + num2:
new_rotten = set() pairs[num1].add(num2)
pairs[num2].add(num1)

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

return helper(None, 0) # python_1_to_1000/999_Available_Captures_for_Rook.py

_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

@functools.lru_cache(None) class Solution(object):


def helper(i, j): # merge stones[i:j + 1] def commonChars(self, A):
"""
if j - i + 1 < K: # cannot merge length less than K :type A: List[str]
return 0 :rtype: List[str]
"""
res = min(helper(i, mid) + helper(mid + 1, j) for mid in range(i, j, K - 1)) counts = Counter(A[0])
if (j - i) % (K - 1) == 0:
res += prefix_sum[j + 1] - prefix_sum[i] for word in A[1:]:
return res word_count = Counter(word)
for c in counts:
return helper(0, n - 1) counts[c] = min(counts[c], word_count[c])

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

return len(A) - i _author_ = 'jake'


_project_ = 'leetcode'

# 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:

class Solution(object): mid_capacity = (min_capacity + max_capacity) // 2


def bitwiseComplement(self, N): if can_ship(mid_capacity):
""" max_capacity = mid_capacity # above mid_capacity is not the lowest possible capacity
:type N: int else:
:rtype: int min_capacity = mid_capacity + 1 # range of capacities is above mid_capacity
"""
if N == 0: # special case because 0 has bit_length of 1 return min_capacity
return 1
return (2**N.bit_length() - 1) - N

# python_1001_to_2000/1012_Numbers_With_Repeated_Digits.py - h

# python_1001_to_2000/1010_Pairs_of_Songs_With_Total_Durations_Divisible_by_60.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/numbers-with-repeated-digits/
# Given a positive integer N, return the number of positive integers less than or equal to N that have at
# https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/ # least 1 repeated digit.
# In a list of songs, the i-th song has a duration of time[i] seconds.
# Return the number of pairs of songs for which their total duration in seconds is divisible by 60. # Count the numbers with repeated digits and subtract from N.
# Formally, we want the number of indices i < j with (time[i] + time[j]) % 60 == 0. # Sum the counts with repeated digit for each power of 10 of length less than N+1.
# Then fix each digit in turn from the most significant and count the non-repeated numbers with fixed prefixes.
# Count the number of songs with each (time modulo 60). For the songs with modulo time 0 and 30, we can form a pair of # Time - O(log n)
# each song and each other song with the same time. # Space - O(log n)
# For other times, we can form pairs of songs with time t and time 60 - t.
# Time - O(n) class Solution(object):
# Space - O(1) def numDupDigitsAtMostN(self, N):
"""
from collections import defaultdict :type N: int
:rtype: int
class Solution(object): """
def numPairsDivisibleBy60(self, time): digits = [int(c) for c in str(N + 1)] # convert N+1 to a list of digits
""" n = len(digits) # length of N+1
:type time: List[int] not_dup = 0 # count of numbers without repeated digits
:rtype: int
""" # returns the number of permutations of length digits out of num_digits
mod_count = defaultdict(int) def permutations(num_digits, length):
if length == 0:
for t in time: return 1
mod_count[t % 60] += 1 # all perms of shorter length, extended by any unused digit
return permutations(num_digits, length - 1) * (num_digits - length + 1)
pairs = mod_count[0] * (mod_count[0] - 1) // 2
pairs += mod_count[30] * (mod_count[30] - 1) // 2 for i in range(1, n): # count not_dup for powers of 10 less than N
for t in range(1, 30): # do not count to 60 to avoid double-counting # 9 possible leading digits (not zero) then permutations of the other 9 digits (including zero)
pairs += mod_count[t] * mod_count[60 - t] not_dup += 9 * permutations(9, i - 1)

return pairs seen = set() # previously fixed digits


for i, max_digit in enumerate(digits): # max_digit is the most significant unfixed digit of N+1
for digit in range(0 if i else 1, max_digit): # possible range of leading unfixed digit
if digit not in seen: # cannot use if digit has been fixed earlier
# python_1001_to_2000/1011_Capacity_To_Ship_Packages_Within_D_Days.py - m not_dup += permutations(9 - i, n - i - 1) # perms of unused digit for shorter length
if max_digit in seen: # all future numbers will contain repeated max_digit
_author_ = 'jake' break
_project_ = 'leetcode' seen.add(max_digit) # fix this digit

# https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/ return N - not_dup


# A conveyor belt has packages that must be shipped from one port to another within D days.
# The i-th package on the conveyor belt has a weight of weights[i].
# Each day, we load the ship with packages on the conveyor belt (in the order given by weights).
# We may not load more weight than the maximum weight capacity of the ship. # python_1001_to_2000/1013_Partition_Array_Into_Three_Parts_With_Equal_Sum.py
# Return the least weight capacity of the ship that will result in all the packages being shipped within D days.
_author_ = 'jake'
# Binary search the range of possible capacities. Lowest possible capacity is the max weight of any item. _project_ = 'leetcode'
# Greatest possible capacity is the sum of all items, which can be shipped in one day.
# Time - O(n log nm) for n weights of max weight m # https://leetcode.com/problems/partition-array-into-three-parts-with-equal-sum/
# Space - O(1) # Given an array A of integers, return true if and only if we can partition the array into three non-empty parts
# with equal sums.
class Solution(object): # Formally, we can partition the array if we can find indexes i+1 < j with (A[0] + A[1] + ... + A[i] ==
def shipWithinDays(self, weights, D): # A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + A[A.length - 1])
"""
:type weights: List[int] # Check if the total is divisible by 3. If so, iterate along the array counting the subarrays with sum of one third
:type D: int # of the total sum.
:rtype: int # Time - O(n)
""" # Space - O(1)
def can_ship(capacity): # determine whether weights can be shipped given a capacity
days = D class Solution(object):
load = 0 def canThreePartsEqualSum(self, A):
"""
for weight in weights: :type A: List[int]
if weight + load > capacity: # use a new ship :rtype: bool
days -= 1 """
load = 0 partition, remainder = divmod(sum(A), 3)
load += weight if remainder != 0:
if days == 0: # all days have been used and some weight remains return False
return False

subarray = 0 # sum of subarray # https://leetcode.com/problems/binary-string-with-substrings-representing-1-to-n/


partitions = 0 # number of partitions found # Given a binary string S (a string consisting only of '0' and '1's) and a positive integer N,
# return true if and only if for every integer X from 1 to N, the binary representation of X is a substring of S.
for num in A:
subarray += num # Brute force check of all numbers from N to 1. Check numbers in descending order because failure is more likely for
if subarray == partition: # large numbers than smaller numbers and if there is no solution we will return False sooner.
partitions += 1 # The concatenation of the binary strings of all integers from 1 to N is of length O(N log N). If S is significantly
subarray = 0 # reset the subarray sum # shorter than this number then it is unlikely to be able to include all bit strings (despite the fact that some bit
# strings will overlap).
return partitions >= 3 # ok if more than 3 partitions # Time - O(n log n)
# Space - O(log n)

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)

_author_ = 'jake' return result


_project_ = 'leetcode'
result += enclave(r, c)
# python_1001_to_2000/1019_Next_Greater_Node_In_Linked_List.py - m
return result
_author_ = 'jake'
_project_ = 'leetcode'

# 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()

# python_1001_to_2000/1020_Number_of_Enclaves.py - m return "".join(result)

_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

for r in range(rows): # python_1001_to_2000/1023_Camelcase_Matching.py - m


for c in range(cols):
self.edge = False # reset flag for each cell _author_ = 'jake'

_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))]

for i in range(1, len(A)):


for j in range(i):
# python_1001_to_2000/1025_Divisor_Game.py diff = A[i] - A[j] # difference between successive elements of the subsequence
sequences[i][diff] = max(sequences[j][diff] + 1, sequences[i][diff]) # https://leetcode.com/problems/matrix-cells-in-distance-order/
# We are given a matrix with R rows and C columns has cells with integer coordinates (r, c),
return max(max(mapping.values()) for mapping in sequences[1:]) + 1 # where 0 <= r < R and 0 <= c < C.
# Additionally, we are given a cell in that matrix with coordinates (r0, c0).
# Return the coordinates of all cells in the matrix,
# sorted by their distance from (r0, c0) from smallest distance to largest distance.
# python_1001_to_2000/1028_Recover_a_Tree_From_Preorder_Traversal.py - h # Here, the distance between two cells (r1, c1) and (r2, c2) is the Manhattan distance, |r1 - r2| + |c1 - c2|.
# You may return the answer in any order that satisfies this condition.
_author_ = 'jake'
_project_ = 'leetcode' # List all cells and sort by Manhattan distance from (r0, c0).
# Alternatively, breadth-first search maintaining a queue and ignoring cells outside matrix or already found.
# https://leetcode.com/problems/recover-a-tree-from-preorder-traversal/ # Time - O(mn log mn)
# We run a preorder depth first search on the root of a binary tree. # Space - O(mn)
# At each node in this traversal, we output D dashes (where D is the depth of this node),
# then we output the value of this node. class Solution(object):
# If the depth of a node is D, the depth of its immediate child is D+1. The depth of the root node is 0. def allCellsDistOrder(self, R, C, r0, c0):
# If a node has only one child, that child is guaranteed to be the left child. """
# Given the output S of this traversal, recover the tree and return its root. :type R: int
:type C: int
# Recursive helper function takes the required depth for a node to be added (initially zero for the root). :type r0: int
# The depth of the current node is found from the count of "-" and None is returned if this does not match the :type c0: int
# required depth. :rtype: List[List[int]]
# If the depth is as required, the index in S is moved past the "-" and a node is created with the parsed value. """
# Add the left and right subtrees by recursing at the next greater depth. result = []
# Time - O(n) for r in range(R):
# Space - O(n) for c in range(C):
result.append((r, c))
class Solution(object):
def recoverFromPreorder(self, S): return sorted(result, key=lambda x: abs(x[0] - r0) + abs(x[1] - c0))
"""
:type S: str
:rtype: TreeNode class Solution2(object):
""" def allCellsDistOrder(self, R, C, r0, c0):
self.i = 0 # index of next char of S queue = deque()
queue.append((r0, c0))
def helper(required_depth): # return subtree if root is at required_depth result = []
visited = set()
depth = 0
while self.i + depth < len(S) and S[self.i + depth] == "-": while queue:
depth += 1
r, c = queue.popleft()
if depth != required_depth: if r < 0 or r >= R or c < 0 or c >= C:
return None # self.i is not incremented if depth is not as required continue
if (r, c) in visited:
self.i += depth # increment self.i continue
val = 0
while self.i < len(S) and S[self.i] != "-": result.append((r, c))
val = val * 10 + int(S[self.i]) visited.add((r, c))
self.i += 1
node = TreeNode(val) for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
queue.append((r + dr, c + dc))
node.left = helper(required_depth + 1)
node.right = helper(required_depth + 1) return result

return node

return helper(0) # python_1001_to_2000/1031_Maximum_Sum_of_Two_Non-Overlapping_Subarrays.py - m

_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

return False # end of queries reached without matching a word

# python_1001_to_2000/1035_Uncrossed_Lines.py - m

# python_1001_to_2000/1033_Moving_Stones_Until_Consecutive.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/uncrossed-lines/
# We write the integers of A and B (in the order they are given) on two separate horizontal lines.
# https://leetcode.com/problems/moving-stones-until-consecutive/ # Now, we may draw a straight line connecting two numbers A[i] and B[j] as long as A[i] == B[j],
# Three stones are on a number line at positions a, b, and c. # and the line we draw does not intersect any other connecting (non-horizontal) line.
# Each turn, you pick up a stone at an endpoint (ie., either the lowest or highest position stone), # Return the maximum number of connecting lines we can draw in this way.
# and move it to an unoccupied position between those endpoints.
# Formally, let's say the stones are currently at positions x, y, z with x < y < z. # Dynamic programming. For each i element of the first list, find the maximum uncrossed lines we can draw for each
# You pick up the stone at either position x or position z, and move that stone to an integer position k, # element j of the second list.
# with x < k < z and k != y. # To get the result for i, j we can add 1 to the result for i - 1, j - 1 of the elements match, or ignore either i or j
# The game ends when you cannot make any more moves, ie. the stones are in consecutive positions. # and take the result for i, j - 1 or i - 1, j.
# When the game ends, what is the minimum and maximum number of moves that you could have made? # Time - O(mn)
# Return the answer as an length 2 array: answer = [minimum_moves, maximum_moves] # Space - O(min(m, n)

# 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)

for i, c in enumerate(cols): class Solution(object):


if i != 0 and cols[i - 1] != c - 1: # not consecutive, add a gap of a single col def bstToGst(self, root):
new_col += 1 """
col_to_compressed[c] = new_col :type root: TreeNode
new_col += 1 :rtype: TreeNode
"""
# map the original inputs to their compressed values self.running = 0
blocked = {(row_to_compressed[r], col_to_compressed[c]) for r, c in blocked}
source = (row_to_compressed[source[0]], col_to_compressed[source[1]]) def inorder(node):
target = (row_to_compressed[target[0]], col_to_compressed[target[1]]) if not node:
return
# set an extra row or col if we are not at the edege of the original grid inorder(node.right)
if new_row != 10 ** 6 + 1: self.running += node.val
new_row += 1 node.val = self.running
if new_col != 10 ** 6 + 1: inorder(node.left)
new_col += 1
inorder(root)
# breadth first search return root
frontier, back, visited = {source, }, {target, }, set()
while frontier and back:

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)

from functools import lru_cache class Solution(object):


def isRobotBounded(self, instructions):
class Solution(object): """
def minScoreTriangulation(self, A): :type instructions: str
""" :rtype: bool
:type A: List[int] """
:rtype: int r, c = 0, 0
""" dr, dc = 1, 0
@lru_cache(None)
def helper(i, j): for instruction in instructions:
if j - i <= 1: if instruction == "G":
return 0 r += dr
return min(helper(i, k) + A[i] * A[k] * A[j] + helper(k, j) for k in range(i + 1, j)) c += dc
elif instruction == "L":
return helper(0, len(A) - 1) dr, dc = -dc, dr
else:
dr, dc = dc, -dr

# python_1001_to_2000/1040_Moving_Stones_Until_Consecutive_II.py - m return (dr, dc) != (1, 0) or (r, c) == (0, 0)

_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):

for stone in stones: if flowers[garden]:


window.append(stone) continue
while stone - window[0] >= n: # remove stones before start of window possible_flowers = {1, 2, 3, 4} - {flowers[nbor] for nbor in edges[garden]}
window.popleft() flowers[garden] = possible_flowers.pop()

moves = n - len(window) # move all stones into window return flowers[1:]


if moves == 1 and window[0] != stone - n + 1: # additional move if only first position of window is empty
moves = 2
min_moves = min(min_moves, moves)
# python_1001_to_2000/1043_Partition_Array_for_Maximum_Sum.py - m
return [min_moves, max_moves]
_author_ = 'jake'
_project_ = 'leetcode'

# 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)

return -stones[0] if stones else 0

# python_1001_to_2000/1044_Longest_Duplicate_Substring.py - h

_author_ = 'jake' # python_1001_to_2000/1047_Remove_All_Adjacent_Duplicates_In_String.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/longest-duplicate-substring/ _project_ = 'leetcode'
# Given a string S, consider all duplicated substrings: (contiguous) substrings of S that occur 2 or more times.
# The occurrences may overlap. # https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/
# Return any duplicated substring that has the longest possible length. # Given a string S of lowercase letters, a duplicate removal consists of choosing two adjacent and equal letters,
# If S does not have a duplicated substring, the answer is "". # and removing them.
# We repeatedly make duplicate removals on S until we no longer can.
# Binary search for the length of the longest repeated substring. # Return the final string after all such duplicate removals have been made. It is guaranteed the answer is unique.
# For a given length guess, a repeated substring is found by taking the rolling hash of substrings of length guess.
# Rolling hash is calculated as C0 + C1 * MULTIPLIER + C2 * MULTIPLIER**2 + ... for characters C0, C1, ... # Iterate over s. When a char matches the previous retained char, discard the both. Else retain the char.
# Hash is also modulo MOD. Calculation of next hash as substring slides over S is O(1). # Time - O(n)
# Time - O(n log n) # Space - O(n)
# Space - O(n)
class Solution(object):
class Solution(object): def removeDuplicates(self, S):
def longestDupSubstring(self, S): """
""" :type S: str
:type S: str :rtype: str
:rtype: str """
""" result = []
MOD = 2 ** 63 - 1 for c in S:
MULTIPLIER = 26 if result and result[-1] == c:
s = [ord(c) - ord("a") for c in S] # convert char to integer result.pop()
else:
def test(guess): # return index or None if no repeat result.append(c)
hash_value = 0
for i in range(guess): return "".join(result)
hash_value = (hash_value * MULTIPLIER + s[i]) % MOD

val = (MULTIPLIER ** guess) % MOD


seen = {hash_value} # python_1001_to_2000/1048_Longest_String_Chain.py - m

for i in range(guess, len(S)): _author_ = 'jake'


hash_value = (hash_value * MULTIPLIER + s[i] - s[i - guess] * val) % MOD _project_ = 'leetcode'
if hash_value in seen:
return i - guess + 1 # start index of duplicate # https://leetcode.com/problems/longest-string-chain/
seen.add(hash_value) # Given a list of words, each word consists of English lowercase letters.
# Let's say word1 is a predecessor of word2 if and only if we can add exactly one letter anywhere in word1 to make
result, low, high = 0, 0, len(S) # it equal to word2. For example, "abc" is a predecessor of "abac".
while low < high: # A word chain is a sequence of words [word_1, word_2, ..., word_k] with k >= 1, where word_1 is a predecessor
mid = (low + high + 1) // 2 # if high - low == 1, choose high # of word_2, word_2 is a predecessor of word_3, and so on.
index = test(mid) # Return the longest possible length of a word chain with words chosen from the given list of words.
if index: # longest duplicate length is mid or greater
low = mid # Sort the words in increasing order of length. For each word, make all shorter words by removing one char.
result = index # If a shorter word is valid, we can extend its chain by adding this word.
else: # longest duplicate length is less than mid # Save the best result from all shorter words.
high = mid - 1 # Time - O(n k**2) for n words of maximum length k
# Space - O(n)
return S[result:result + low]
from collections import defaultdict

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)

_author_ = 'jake' else:


_project_ = 'leetcode' base_satisfied += customers[i]

# https://leetcode.com/problems/last-stone-weight-ii/ if i - X >= 0 and grumpy[i - X] == 1:


# We have a collection of rocks, each rock has a positive integer weight. window -= customers[i - X] # remove customers from window
# Each turn, we choose any two rocks and smash them together.
# Suppose the stones have weights x and y with x <= y. The result of this smash is: best_window = max(best_window, window)
# If x == y, both stones are totally destroyed;
# If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x. return base_satisfied + best_window
# At the end, there is at most 1 stone left.
# Return the smallest possible weight of this stone (the weight is 0 if there are no stones left.)

# 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

for i in range(len(customers)): return result


if grumpy[i] == 1:
window += customers[i] # add additional customers to window
# https://leetcode.com/problems/campus-bikes/
# python_1001_to_2000/1055_Shortest_Way_to_Form_String.py - m # On a campus represented as a 2D grid, there are N workers and M bikes,
# with N <= M. Each worker and bike is a 2D coordinate on this grid.
_author_ = 'jake' # Our goal is to assign a bike to each worker.
_project_ = 'leetcode' # Among the available bikes and workers, we choose the (worker, bike) pair with the shortest Manhattan distance
# between each other, and assign the bike to that worker.
# https://leetcode.com/problems/shortest-way-to-form-string/ # If there are multiple (worker, bike) pairs with the same shortest Manhattan distance, we choose the pair with the
# From any string, we can form a subsequence of that string by deleting some number of characters # smallest worker index; if there are multiple ways to do that, we choose the pair with the smallest bike index.
# (possibly no deletions). # We repeat this process until there are no available workers.
# Given two strings source and target, return the minimum number of subsequences of source such that # The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|.
# their concatenation equals target. # Return a vector ans of length N, where ans[i] is the index of the bike that the i-th worker is assigned to.
# If the task is impossible, return -1.
# For each worker, create a sorted list of distances to each bike.
# Create mapping from each source char to the indices in source of that char. # The elements of the list are tuples (distance, worker, bike).
# Iterate over target, searching for the next index in source of each char. Return -1 if not found. # For each worker, add the tuple with the shortest distance to the heap.
# Search is by binary search of the list of indices in source of char. # Until each worker has a bike, pop the smallest distance from the heap.
# If the next index in source requires wrapping around to the start of source, increment result count. # If this bike is not used, update the result for this worker,
# Time - O(n log m) for source of length m and target of length n. # else add the next closest tuple for this worker to the heap.
# Space - O(m) # Time - O(mn log mn) for m workers and n bikes.
# Space - O(mn)
from collections import defaultdict
import bisect import heapq

class Solution(object): class Solution(object):


def shortestWay(self, source, target): def assignBikes(self, workers, bikes):
""" """
:type source: str :type workers: List[List[int]]
:type target: str :type bikes: List[List[int]]
:rtype: int :rtype: List[int]
""" """
char_indices = defaultdict(list) distances = [] # distances[worker] is list of [distance, worker, bike] for each bike
for i, c in enumerate(source): for i, (x, y) in enumerate(workers):
char_indices[c].append(i) distances.append([])
for j, (x_b, y_b) in enumerate(bikes):
result = 0 distance = abs(x - x_b) + abs(y - y_b)
i = 0 # next index of source to check distances[-1].append([distance, i, j])
distances[-1].sort(reverse=True) # reverse so we pop the smallest distance first
for c in target:
if c not in char_indices: # cannot make target if char not in source result = [None] * len(workers)
return -1 used_bikes = set()
queue = [distances[i].pop() for i in range(len(workers))] # smallest distance for each worker
j = bisect.bisect_left(char_indices[c], i) # index in char_indices[c] that is >= i heapq.heapify(queue)
if j == len(char_indices[c]): # wrap around to beginning of source
result += 1 while len(used_bikes) < len(workers):
j = 0 _, worker, bike = heapq.heappop(queue)
i = char_indices[c][j] + 1 # next index in source if bike not in used_bikes:
result[worker] = bike
return result if i == 0 else result + 1 # add 1 for partial source used_bikes.add(bike)
else:
heapq.heappush(queue, distances[worker].pop()) # bike used, add next closest bike

# python_1001_to_2000/1056_Confusing_Number.py return result

_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'

result += sum(remainders[i:]) # round down the rest of remainders # https://leetcode.com/problems/lexicographically-smallest-equivalent-string/


return "{:.3f}".format(result / 1000) # Given strings A and B of the same length, we say A[i] and B[i] are equivalent characters.
# For example, if A = "abc" and B = "cde", then we have 'a' == 'c', 'b' == 'd', 'c' == 'e'.
# Equivalent characters follow the usual rules of any equivalence relation:
# Reflexivity: 'a' == 'a'
# python_1001_to_2000/1059_All_Paths_from_Source_Lead_to_Destination.py - m # Symmetry: 'a' == 'b' implies 'b' == 'a'
# Transitivity: 'a' == 'b' and 'b' == 'c' implies 'a' == 'c'
_author_ = 'jake' # For example, given the equivalency information from A and B above, S = "eed", "acd", and "aab" are equivalent strings,
_project_ = 'leetcode' # and "aab" is the lexicographically smallest equivalent string of S.
# Return the lexicographically smallest equivalent string of S by using the equivalency information from A and B.
# https://leetcode.com/problems/all-paths-from-source-lead-to-destination/
# Given the edges of a directed graph, and two nodes source and destination of this graph, # Create a mapping from each char to its direct equivalents.
# determine whether or not all paths starting from source eventually end at destination, that is: # For each char of S, explore the map of all equivalents and set the minimum equivalent of all chars visited.
# At least one path exists from the source node to the destination node # Memoize the minimum equivalents.
# If a path exists from the source node to a node with no outgoing edges, then that node is equal to destination. # Time - O(n)
# The number of possible paths from source to destination is a finite number. # Space - O(n)
# Return true if and only if all roads from source lead to destination.
from collections import defaultdict
# Build a map from each node to the set of nodes connected by an edge.
# From the source node, recursively explore all neighbours adding them to the visited set and testing whether all class Solution(object):
# paths lead to the destination. Remove nodes from visited set when returning from recursion. def smallestEquivalentString(self, A, B, S):
# Time - O(m + n), nodes + edges """
# Space - O(m + n) :type A: str
:type B: str
from collections import defaultdict :type S: str
:rtype: str
class Solution(object): """
def leadsToDestination(self, n, edges, source, destination): equivalents = defaultdict(set) # map char to its directly connected equivalents
""" for a, b in zip(A, B):
:type n: int equivalents[a].add(b)
:type edges: List[List[int]] equivalents[b].add(a)
:type source: int
:type destination: int minimum = {} # map char to its minimum equivalent
:rtype: bool
""" def get_minimum(char): # return the minimum equivalent
visited = set() if char in minimum:
edge_dict = defaultdict(set) return minimum[char]
for start, end in edges:
edge_dict[start].add(end) result = char
visited = set()
def can_reach_dest(node): queue = {char}
if node == destination and len(edge_dict[node]) == 0: # destination reached and no neighbours
return True while queue:
if node == destination or len(edge_dict[node]) == 0: # destination has neighbours or terminal node c = queue.pop()
return False # that is not destination if c in visited:
continue
if node in visited: visited.add(c)
return False result = min(result, c)
visited.add(node) queue |= equivalents[c] # add all equivalents to the queue
result = all(can_reach_dest(nbor) for nbor in edge_dict[node])
visited.remove(node) for v in visited: # minimum equivalent for all visited is set to result
return result minimum[v] = result
return result
return can_reach_dest(source)
return "".join(get_minimum(c) for c in S)

# 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

class Solution2(object): # python_1001_to_2000/1065_Index_Pairs_of_a_String.py


def longestRepeatingSubstring(self, S):
n = len(S) _author_ = 'jake'
result = 0 _project_ = 'leetcode'

for offset in range(1, n): # compare S[:-i] to S[i:] # https://leetcode.com/problems/index-pairs-of-a-string/


if result >= n - offset: # Given a text string and words (a list of strings), return all index pairs [i, j]
break # so that the substring text[i]...text[j] is in the list of words.

sequence = 0 # Repeatedly find each word in text until it is not found.


for i in range(n - offset): # Start each find from the character after the previous find.
if S[i] == S[i + offset]: # Time - O(mn log mn) for m words in text of length n
sequence += 1 # Space - O(mn)
result = max(result, sequence)
else: class Solution(object):
sequence = 0 def indexPairs(self, text, words):
"""
return result :type text: str
:type words: List[str]
:rtype: List[List[int]]
"""
# python_1001_to_2000/1063_Number_of_Valid_Subarrays.py - h result = []
for word in words:
_author_ = 'jake' i = -1
_project_ = 'leetcode' while True:
i = text.find(word, i + 1)
# https://leetcode.com/problems/number-of-valid-subarrays/ if i == -1:
# Given an array A of integers, return the number of non-empty continuous subarrays that satisfy the following: break
# The leftmost element of the subarray is not larger than other elements in the subarray. result.append([i, i + len(word) - 1])

# Maintain a stack of leftmost elements in increasing order. return sorted(result)


# Iterate along nums, popping from the stack all leftmost elements that are greater than the current element.
# Add the current element and increment the result by the count of leftmost elements on the stack.
# Time - O(n)
# Space - O(n) # python_1001_to_2000/1066_Campus_Bikes_II.py - m

class Solution(object): _author_ = 'jake'


def validSubarrays(self, nums): _project_ = 'leetcode'
"""
:type nums: List[int] # https://leetcode.com/problems/campus-bikes-ii/
:rtype: int # On a campus represented as a 2D grid, there are N workers and M bikes, with N <= M.
""" # Each worker and bike is a 2D coordinate on this grid.
result = 0 # We assign one unique bike to each worker so that the sum of the Manhattan distances between each worker
stack = [] # leftmost elements # and their assigned bike is minimized.
# The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|.
for num in nums: # Return the minimum possible sum of Manhattan distances between each worker and their assigned bike.

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

# python_1001_to_2000/1064_Fixed_Point.py class Solution(object):


def assignBikes(self, workers, bikes):
_author_ = 'jake' """
_project_ = 'leetcode' :type workers: List[List[int]]
:type bikes: List[List[int]]
# https://leetcode.com/problems/fixed-point/ :rtype: int
# Given an array A of distinct integers sorted in ascending order, """
# return the smallest index i that satisfies A[i] == i. Return -1 if no such i exists. distance = []
for worker in workers:
# Binary search the indices of the array. distance.append([])
# If a A[i] is greater than i then the fixed point must be to the left, so decrease right to i - 1. for bike in bikes:
# If a A[i] is leff than i then the fixed point must be to the right, so increase left to i + 1. distance[-1].append(abs(worker[0] - bike[0]) + abs(worker[1] - bike[1]))
# Time - O(log n)
# Space - O(1) heap = [(0, 0, 0)] # heap of (total distance, used bike flags, workers with bikes)
heapq.heapify(heap)
class Solution(object): seen = set()
def fixedPoint(self, A):
""" while True:
:type A: List[int] dist, used, count = heapq.heappop(heap)

if count == len(workers): _author_ = 'jake'


return dist _project_ = 'leetcode'
if used in seen:
continue # https://leetcode.com/problems/flip-columns-for-maximum-number-of-equal-rows/
seen.add(used) # Given a matrix consisting of 0s and 1s, we may choose any number of columns in the matrix
# and flip every cell in that column.
for i in range(len(bikes)): # Flipping a cell changes the value of that cell from 0 to 1 or from 1 to 0.
if not used & (1 << i): # Return the maximum number of rows that have all values equal after some number of flips.
heapq.heappush(heap, (dist + distance[count][i], used | (1 << i), count + 1))
# For 2 rows to have all cells the same after some column flips, they must have either the same pattern of
# 0 and 1 or the opposite pattern.
# For each row, if the first column is not zero flip all values of that row by taking XOR with first value.
# python_1001_to_2000/1067_Digit_Count_in_Range.py - h # Convert the row to a tuple and count the number of each tuple.
# The largest tuple count is the most rows that can be all equal.
_author_ = 'jake' # Time - O(mn)
_project_ = 'leetcode' # Space - O(mn)

# https://leetcode.com/problems/digit-count-in-range/ from collections import defaultdict


# Given an integer d between 0 and 9, and two positive integers low and high as lower and upper bounds, respectively.
# Return the number of times that d occurs as a digit in all integers between low and high, class Solution(object):
# including the bounds low and high. def maxEqualRowsAfterFlips(self, matrix):
"""
# Helper function count_digits(n) recursively counts d in all integers less than n. :type matrix: List[List[int]]
# Separate n into prefix (dividing by 0) and units (modulo 0). :rtype: int
# The 4 components to the count are: """
# - fix prefix count d in units, provided d < units. row_counter = defaultdict(int)
# - count of d in fixed prefix, followed by all units < d. for row in matrix:
# - any int < prefix, followed by fixed d (not 0 prefix and 0 units). row_counter[tuple(x ^ row[0] for x in row)] += 1
# - result from prefix, followed by any digit 0 to 9.
# Time - O(log n) return max(row_counter.values())
# Space - O(log n)

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

while b != 0: while result[-1] == 0 and len(result) > 1: # remove leading zeros


a, b = b, a % b result.pop()
return result[::-1] # put most significant digit first
candidate = str1[:a]
return candidate if str1 == candidate * (len(str1) // a) and str2 == candidate * (len(str2) // a) else ""

# python_1001_to_2000/1074_Number_of_Submatrices_That_Sum_to_Target.py - h

# python_1001_to_2000/1072_Flip_Columns_For_Maximum_Number_of_Equal_Rows.py - m _author_ = 'jake'


_project_ = 'leetcode'
# https://leetcode.com/problems/number-of-submatrices-that-sum-to-target/ # Count the number of tiles of each type.
# Given a matrix, and a target, return the number of non-empty submatrices that sum to target. # Depth-first search for all possible sequences.
# A submatrix x1, y1, x2, y2 is the set of all cells matrix[x][y] with x1 <= x <= x2 and y1 <= y <= y2. # Use each tile with a non-zero count and increment the number of sequences.
# Two submatrices (x1, y1, x2, y2) and (x1', y1', x2', y2') are different if they have some different coordinate # Decrement the count of the used tile, then recurse. Increment the count back after recursion.
# for example, if x1 != x1'. # Return when all tiles are used.
# Time - O(n!)
# Calculate the cumulative sums along each row. # Space - O(n!)
# For each pair of columns, calculate the sumbmatrix sum between those columns from row 0 to each row.
# Check if any other submatrix sum can be subtracted from the current sum to reach target. from collections import Counter
# Time - O(m**2 * n)
# Space - O(mn) class Solution(object):
def numTilePossibilities(self, tiles):
from collections import defaultdict """
:type tiles: str
class Solution(object): :rtype: int
def numSubmatrixSumTarget(self, matrix, target): """
""" self.total = 0
:type matrix: List[List[int]] freq = Counter(tiles)
:type target: int
:rtype: int def helper(remaining):
"""
rows, cols = len(matrix), len(matrix[0]) if remaining == 0:
if rows < cols: # swap rows and cols if more cols return
matrix = zip(*matrix[::-1])
rows, cols = cols, rows for tile, count in freq.items():
if count != 0:
cumulative_rows = [] # sum along each row freq[tile] -= 1
for row in range(rows): self.total += 1
cumulative_rows.append([matrix[row][0]]) helper(remaining - 1)
for col in range(1, cols): freq[tile] += 1
cumulative_rows[-1].append(matrix[row][col] + cumulative_rows[-1][-1])
helper(len(tiles))
result = 0 return self.total

for col_start in range(cols):


for col_end in range(col_start, cols): # each pair of columns
seen = defaultdict(int, {0: 1}) # count submatrix sums between there columns # python_1001_to_2000/1080_Insufficient_Nodes_in_Root_to_Leaf_Paths.py - m
submatrix = 0
for row in range(rows): _author_ = 'jake'
submatrix += cumulative_rows[row][col_end] # add new row upto sol_end _project_ = 'leetcode'
if col_start != 0:
submatrix -= cumulative_rows[row][col_start - 1] # subtract row before col_start # https://leetcode.com/problems/insufficient-nodes-in-root-to-leaf-paths/
# Given the root of a binary tree, consider all root to leaf paths: paths from the root to any leaf.
if submatrix - target in seen: # A leaf is a node with no children.
result += seen[submatrix - target] # A node is insufficient if every such root to leaf path intersecting this node has sum strictly less than limit.
seen[submatrix] += 1 # Delete all insufficient nodes simultaneously, and return the root of the resulting binary tree.

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

class Solution(object): if root.left:


def findOcurrences(self, text, first, second): root.left = self.sufficientSubset(root.left, limit - root.val)
""" if root.right:
:type text: str root.right = self.sufficientSubset(root.right, limit - root.val)
:type first: str
:type second: str return root if root.right or root.left else None
:rtype: List[str]
"""
result = []
s = text.split() # python_1001_to_2000/1081_Smallest_Subsequence_of_Distinct_Characters.py - m

for i in range(2, len(s)): _author_ = 'jake'


if s[i - 2] == first and s[i - 1] == second: _project_ = 'leetcode'
result.append(s[i])
# https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/
return result # Return the lexicographically smallest subsequence of text that contains all the distinct characters
# of text exactly once.

# Map each char to its last index in text.


# python_1001_to_2000/1079_Letter_Tile_Possibilities.py - m # Iterate over text. For each char, if it's in the text then ignore it.
# While the char is lexicographically after the top of stack and top of stack char also occurs later in text,
_author_ = 'jake' # then pop top of stack. Append char to stack and convert to string before returning.
_project_ = 'leetcode' # Time - O(n)
# Space - O(1) since alphabet size is limited.
# https://leetcode.com/problems/letter-tile-possibilities/
# You have a set of tiles, where each tile has one letter tiles[i] printed on it. class Solution(object):
# Return the number of possible non-empty sequences of letters you can make. def smallestSubsequence(self, text):

""" # Each letter in the word has 1 or more options.


:type text: str # If there is one option, the letter is represented as is.
:rtype: str # If there is more than one option, then curly braces delimit the options.
""" # For example, "{a,b,c}" represents options ["a", "b", "c"].
last_index = {c: i for i, c in enumerate(text)} # For example, "{a,b,c}d{e,f}" represents the list ["ade", "adf", "bde", "bdf", "cde", "cdf"].
stack = [] # Return all words that can be formed in this manner, in lexicographical order.

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

class Solution(object): results = []


def sumOfDigits(self, A): def expand(group, partial):
""" if group == len(groups):
:type A: List[int] results.append(partial)
:rtype: int return
""" for c in groups[group]:
minimum = min(A) expand(group + 1, partial + c)
digit_sum = 0
while minimum: expand(0, "")
digit_sum += minimum % 10 return results
minimum //= 10
return int(digit_sum % 2 == 0)

# python_1001_to_2000/1088_Confusing_Number_II.py - h

# python_1001_to_2000/1086_High_Five.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/confusing-number-ii/
# We can rotate digits by 180 degrees to form new digits.
# https://leetcode.com/problems/high-five/ # When 0, 1, 6, 8, 9 are rotated 180 degrees, they become 0, 1, 9, 8, 6 respectively.
# Given a list of scores of different students, return the average score of each student's top five scores # When 2, 3, 4, 5 and 7 are rotated 180 degrees, they become invalid.
# in the order of each student's id. # A confusing number is a number that when rotated 180 degrees becomes a different number with each digit valid.
# Each entry items[i] has items[i][0] the student's id, and items[i][1] the student's score. # Note that the rotated number can be greater than the original number.
# The average score is calculated using integer division. # Given a positive integer N, return the number of confusing numbers between 1 and N inclusive.

# 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

# https://leetcode.com/problems/brace-expansion/ _author_ = 'jake'


# A string S represents a list of words. _project_ = 'leetcode'
# Adjacent cells C_i and C_{i+1} are connected 8-directionally (ie., they are different and share an edge or corner)
# https://leetcode.com/problems/duplicate-zeros/ # C_1 is at location (0, 0) (ie. has value grid[0][0])
# Given a fixed length array arr of integers, duplicate each occurrence of zero, # C_k is at location (N-1, N-1) (ie. has value grid[N-1][N-1])
# shifting the remaining elements to the right. # If C_i is located at (r, c), then grid[r][c] is empty (ie. grid[r][c] == 0).
# Note that elements beyond the length of the original array are not written. # Return the length of the shortest such clear path from top-left to bottom-right.
# Do the above modifications to the input array in place, do not return anything from your function. # If such a path does not exist, return -1.

# 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)

class Solution(object): class Solution(object):


def duplicateZeros(self, arr): def shortestPathBinaryMatrix(self, grid):
""" """
:type arr: List[int] :type grid: List[List[int]]
:rtype: None Do not return anything, modify arr in-place instead. :rtype: int
""" """
length = 0 # length of arr after duplicating zeros n = len(grid)
for i, num in enumerate(arr): if grid[0][0] == 1 or grid[n - 1][n - 1] == 1: # front and back frontiers only contain empty cells
length += 2 if num == 0 else 1 return -1
if length >= len(arr): front, back = {(0, 0)}, {(n - 1, n - 1)}
break visited = set()
path = 0
next_fill = len(arr) - 1
if length > len(arr): # only one of the duplicate zero fits in arr while front and back:
arr[-1] = 0 path += 1
i -= 1 if front & back: # frontiers intersect
next_fill -= 1 return path
if len(front) > len(back):
for j in range(i, -1, -1): front, back = back, front
arr[next_fill] = arr[j] new_front = set()
next_fill -= 1
if arr[j] == 0: for r, c in front:
arr[next_fill] = arr[j] for dr in (-1, 0, 1):
next_fill -= 1 for dc in (-1, 0, 1): # dr == dc == 0 is visited
if r + dr < 0 or r + dr >= n:
continue
if c + dc < 0 or c + dc >= n:
# python_1001_to_2000/1090_Largest_Values_From_Labels.py - m continue
if grid[r + dr][c + dc] == 1:
_author_ = 'jake' continue
_project_ = 'leetcode' new_front.add((r + dr, c + dc))

# https://leetcode.com/problems/largest-values-from-labels/ visited |= front


# We have a set of items: the i-th item has value values[i] and label labels[i]. new_front -= visited
# Then, we choose a subset S of these items, such that: front = new_front
# |S| <= num_wanted
# For every label L, the number of items in S with label L is <= use_limit. return -1
# Return the largest possible sum of the subset S.

# Sort tuples of (value, label) in descending order.


# Greedily add each value to the result, provided do not add more than use_limit of each item. # python_1001_to_2000/1092_Shortest_Common_Supersequence.py - h
# Track the remaining allowed number of each label in a dictionary.
# Return when we have added num_wanted values. _author_ = 'jake'
# Time - O(n log n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/shortest-common-supersequence/
class Solution(object): # Given two strings str1 and str2, return the shortest string that has both str1 and str2 as subsequences.
def largestValsFromLabels(self, values, labels, num_wanted, use_limit): # If multiple answers exist, you may return any of them.
""" # A string S is a subsequence of string T if deleting some number of characters from T
:type values: List[int] # (possibly 0, and the characters are chosen anywhere from T) results in the string S.
:type labels: List[int]
:type num_wanted: int # Find the longest common supersequence by dynamic programming.
:type use_limit: int # For each pair of prefixes str1[:i] and str2 [:j], extend the result for i - 1, j - 1 if end chars are the same.
:rtype: int # Else take the larger result of i - 1, j and i, j - 1.
""" # Make the shortest common supersequence by iterating over the LCS.
result, used = 0, 0 # Add all chars of str1 to the result until we match a char in LCS. Do the same for str2, then add the matching char.
remaining = {} # map label to remaining number we can choose # Time - O(mn * min(m, n)) since there are O(mn) entries in the lcs matrix and each takes min(m, n) to build.
# Space - O(mn)
for value, label in sorted(zip(values, labels), reverse=True):
remain = remaining.get(label, use_limit) # default use_limit if not found class Solution(object):
if remain > 0: def shortestCommonSupersequence(self, str1, str2):
result += value """
remaining[label] = remain - 1 :type str1: str
used += 1 :type str2: str
if used == num_wanted: :rtype: str
break """
m, n = len(str1), len(str2)
return result lcs = [["" for _ in range(n + 1)] for _ in range(m + 1)]
for i in range(m):
for j in range(n):
if str1[i] == str2[j]:
# python_1001_to_2000/1091_Shortest_Path_in_Binary_Matrix.py - m lcs[i + 1][j + 1] = lcs[i][j] + str1[i]
else:
_author_ = 'jake' lcs[i + 1][j + 1] = max(lcs[i + 1][j], lcs[i][j + 1], key=len)
_project_ = 'leetcode'
result = []
# https://leetcode.com/problems/shortest-path-in-binary-matrix/ i, j = 0, 0
# In an N by N square grid, each cell is either empty (0) or blocked (1). for c in lcs[-1][-1]:
# A clear path from top-left to bottom-right has length k if and only if it is composed of while str1[i] != c:
# cells C_1, C_2, ..., C_k such that: result.append(str1[i])

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.

# Iterate along count, updating the count of samples_seen.


# Find the index or indices of the median element(s). # python_1001_to_2000/1095_Find_in_Mountain_Array.py - h
# If 2 median elements, find their sum.
# Time - O(n) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/find-in-mountain-array/


def sampleStats(self, count): # You may recall that an array A is a mountain array if and only if:
""" # A.length >= 3
:type count: List[int] # There exists some i with 0 < i < A.length - 1 such that:
:rtype: List[float] # A[0] < A[1] < ... A[i-1] < A[i]
""" # A[i] > A[i+1] > ... > A[A.length - 1]
minimum = None # Given a mountain array mountainArr, return the minimum index such that mountainArr.get(index) == target.
sample_count = sum(count) # If such an index doesn't exist, return -1.
sum_samples, samples_seen = 0, 0 # You can't access the mountain array directly. You may only access the array using a MountainArray interface:
mode, mode_count = 0, 0 # MountainArray.get(k) returns the element of the array at index k (0-indexed).
# MountainArray.length() returns the length of the array.
median_sum = 0 # Submissions making more than 100 calls to MountainArray.get will be judged Wrong Answer.
median_indices = [sample_count // 2] # Also, any solutions that attempt to circumvent the judge will result in disqualification.
if sample_count % 2 == 0:
median_indices.append(median_indices[-1] - 1) # Find the peak of the mountain by binary search.
# Binary search the left side of the peak, and if the target is not found then search the right side.
for num, freq in enumerate(count): # Time - O(log n)
if freq == 0: # Space - O(1)
continue
class Solution(object):
if minimum is None: def findInMountainArray(self, target, mountain_arr):
minimum = num """
maximum = num :type target: integer
:type mountain_arr: MountainArray
samples_seen += freq :rtype: integer
sum_samples += freq * num """
n = mountain_arr.length()
if freq > mode_count: left, right = 0, n - 1
mode_count = freq
mode = num while left < right:
mid = (left + right) // 2
while median_indices and samples_seen > median_indices[-1]: val = mountain_arr.get(mid)
median_sum += num next_val = mountain_arr.get(mid + 1)
median_indices.pop() if next_val < val: # slope down
right = mid
mean = sum_samples / float(sample_count) else: # slope up
median = median_sum / float(2 if sample_count % 2 == 0 else 1) left = mid + 1
return [minimum, maximum, mean, median, mode]
mountain = left

left, right = 0, mountain


# python_1001_to_2000/1094_Car_Pooling.py - m while left <= right:
mid = (left + right) // 2
_author_ = 'jake' val = mountain_arr.get(mid)
_project_ = 'leetcode' if val == target:
return mid
# https://leetcode.com/problems/car-pooling/ if val > target:
# You are driving a vehicle that has capacity empty seats initially available for passengers. right = mid - 1
# The vehicle only drives east (ie. it cannot turn around and drive west.) else:
# Given a list of trips, trip[i] = [num_passengers, start_location, end_location] left = mid + 1
# contains information about the i-th trip: the number of passengers that must be picked up,
# and the locations to pick them up and drop them off. left, right = mountain, n - 1
# The locations are given as the number of kilometers due east from your vehicle's initial location. while left <= right:
# Return true if and only if it is possible to pick up and drop off all passengers for all the given trips. mid = (left + right) // 2
val = mountain_arr.get(mid)
# Sort by ascending start location. if val == target:
# Iterate over trips, removing from heap all passengers dropped off before the current start location. return mid
# Reduce capacity by the picked up passengers and check if car is too full. if val > target:
# Else add the end location and number of passengers to the dropoff heap. left = mid + 1
# Time - O(n log n) else:
# Space - O(n) right = mid - 1
result = -1
return -1 A.sort()
left, right = 0, len(A) - 1
while left < right:
if A[left] + A[right] < K:
# python_1001_to_2000/1096_Brace_Expansion_II.py - m result = max(result, A[left] + A[right])
left += 1
_author_ = 'jake' else:
_project_ = 'leetcode' right -= 1
return result
# https://leetcode.com/problems/brace-expansion-ii/
# Under a grammar given below, strings can represent a set of lowercase words.
# Let's use R(expr) to denote the set of words the expression represents.
# Grammar can best be understood through simple examples: # python_1001_to_2000/1100_Find_K-Length_Substrings_With_No_Repeated_Characters.py - m
# Single letters represent a singleton set containing that word.
# R("a") = {"a"} _author_ = 'jake'
# R("w") = {"w"} _project_ = 'leetcode'
# When we take a comma delimited list of 2 or more expressions, we take the union of possibilities.
# R("{a,b,c}") = {"a","b","c"} # https://leetcode.com/problems/find-k-length-substrings-with-no-repeated-characters/
# R("{{a,b},{b,c}}") = {"a","b","c"} (notice the final set only contains each word at most once) # Given a string S, return the number of substrings of length K with no repeated characters.
# When we concatenate two expressions, we take the set of possible concatenations between two words
# where the first word comes from the first expression and the second word comes from the second expression. # Maintain a sliding window of length K over S.
# R("{a,b}{c,d}") = {"ac","ad","bc","bd"} # Count the instances of all chars in the window.
# R("a{b,c}{d,e}f{g,h}") = {"abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", "acefg", "acefh"} # Increment the count for each new char and decrement for chars leaving the window.
# Formally, the 3 rules for our grammar: # Maintain a count of repeated chars, to avoid checking all chars for every iteration.
# For every lowercase letter x, we have R(x) = {x} # Time - O(n)
# For expressions e_1, e_2, ... , e_k with k >= 2, we have R({e_1,e_2,...}) = R(e_1) ∪ R(e_2) ∪ ... # Space - O(1) for fixed size alphabet.
# For expressions e_1 and e_2, we have R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)},
# where + denotes concatenation, and × denotes the cartesian product. from collections import defaultdict
# Given an expression representing a set of words under the given grammar,
# return the sorted list of words that the expression represents. class Solution(object):
def numKLenSubstrNoRepeats(self, S, K):
# Maintain a stack of sets of words, commas and opening braces. """
# Add opening braces and commas to the stack. Add words in their own set. :type S: str
# When there is a closing brace, combine all comma-separated sets into a single set and pop off opening bracket. :type K: int
# When 2 sets are at the top of the stack, remove them and append a new set of all the concatenations. :rtype: int
# Time - O(n**2 * 2**n), as per space with additional time to construct each intermediate result. """
# Space - O(n 2**n), consider pairs e.g.(a,b)(c,d)(e,f) .... leading to an exponential number of results. if K > 26 or K > len(S): # must have repeats if more than alphabet size
return 0
class Solution(object):
def braceExpansionII(self, exp): counts = defaultdict(int)
""" repeated, result = 0, 0
:type expression: str
:rtype: List[str] for i, c in enumerate(S):
""" counts[c] += 1
stack = [] if counts[c] == 2: # new repeated char
repeated += 1
for c in exp: if i >= K:
if c == "{" or c == ",": counts[S[i - K]] -= 1
stack.append(c) if counts[S[i - K]] == 1:
elif c == "}": repeated -= 1
while stack[-2] == ",": # combine all sets to a single set
stack[-3] |= stack[-1] if i >= K - 1: # from i = K - 1 onwards
stack.pop() # remove combined set and comma result += repeated == 0 # increment result if no repeated
stack.pop()
del stack[-2] # remove the opening bracket return result
else:
stack.append(set(c)) # push char in its own set

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'

return list(sorted(stack[-1])) # https://leetcode.com/problems/the-earliest-moment-when-everyone-become-friends/


# In a social group, there are N people, with unique integer ids from 0 to N-1.
# We have a list of logs, where each logs[i] = [timestamp, id_A, id_B] contains a non-negative integer timestamp,
# and the ids of two different people.
# python_1001_to_2000/1099_Two_Sum_Less_Than_K.py # Each log represents the time in which two different people became friends.
# Friendship is symmetric: if A is friends with B, then B is friends with A.
_author_ = 'jake' # Let's say that person A is acquainted with person B if A is friends with B,
_project_ = 'leetcode' # or A is a friend of someone acquainted with B.
# Return the earliest time for which every person became acquainted with every other person.
# https://leetcode.com/problems/two-sum-less-than-k/ # Return -1 if there is no such earliest time.
# Given an array A of integers and integer K,
# return the maximum S such that there exists i < j with A[i] + A[j] = S and S < K. # Sort by time. Union-find groups of friends.
# If no i, j exist satisfying this equation, return -1. # Intially each person is in their own group.
# For each pair of new friends, find their group leaders and if not the same leader then join the groups.
# Sort and start 2 pointers at both ends of A. # Keep count of the number of groups.
# If the sum of values at the pointers is less than K, update the best result and increment the left pointer so the # Time - O(n**2)
# sum of values increases. # Space - O(n)
# If the sum of values at the pointers is greater than or equal to K, decrement the right pointer so the sum of values
# decreases. class Solution(object):
# Time - O(n log n) def earliestAcq(self, logs, N):
# Space - O(n) """
:type logs: List[List[int]]
class Solution(object): :type N: int
def twoSumLessThanK(self, A, K): :rtype: int
""" """
:type A: List[int] logs.sort() # sort by ascending time
:type K: int friend = {i: i for i in range(N)} # map person to a friend
:rtype: int groups = N
"""

def leader(i): # find exemplar amongst a group of friends """


while friend[i] != i: people_served = int(((1 + 8 * candies) ** 0.5 - 1) / 2) # people who get their full portion
i = friend[i] cycles = people_served // num_people # complete cycles of num_people
return i
result = [0] * num_people
for time, A, B in logs: if cycles != 0:
a, b = leader(A), leader(B) base = num_people * (cycles - 1) * cycles // 2 # same for every person
if a != b: for i in range(num_people):
friend[a] = b # join the groups and decrement the group count result[i] += base + cycles * (i + 1) # for each cycle, add index + 1
groups -= 1
if groups == 1: # everybody is friends last_candies = cycles * num_people
return time candies -= sum(result)
for i in range(num_people): # incomplete final cycle
return -1 if candies <= 0:
break
result[i] += min(candies, last_candies + i + 1)
candies -= last_candies + i + 1
# python_1001_to_2000/1102_Path_With_Maximum_Minimum_Value.py - m
return result
_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1104_Path_In_Zigzag_Labelled_Binary_Tree.py - m
# https://leetcode.com/problems/path-with-maximum-minimum-value/
# Given a matrix of integers A with R rows and C columns, _author_ = 'jake'
# find the maximum score of a path starting at [0,0] and ending at [R-1,C-1]. _project_ = 'leetcode'
# The score of a path is the minimum value in that path.
# For example, the value of the path 8 → 4 → 5 → 9 is 4. # https://leetcode.com/problems/path-in-zigzag-labelled-binary-tree/
# A path moves some number of times from one visited cell to any neighbouring unvisited cell in one of # In an infinite binary tree where every node has two children, the nodes are labelled in row order.
# the 4 cardinal directions (north, east, west, south). # In the odd numbered rows (ie., the first, third, fifth,...), the labelling is left to right,
# while in the even numbered rows (second, fourth, sixth,...), the labelling is right to left.
# Maintain heap of (-score, row, column).
# Each cell is popped the heap and visited when it has its largest score. # We can mive up the tree to each parent by dividing by 2.
# Add all neighbours within the grid bounds to the heap. # But because alternate rows are reversed, this will give the correect answer for every other row.
# Starting from [R-1, C-1] is faster than starting from [0, 0] because equal score ties are broken by lower row, # So find the position of the label if the row of the label is reversed and move up the tree alternately using
# which is closer to [0, 0]. # the original and reversed labels.
# Time - O(mn log mn) # Time - O(log n)
# Space - O(mn) # Space - O(log n)

import heapq class Solution(object):


def pathInZigZagTree(self, label):
class Solution(object): """
def maximumMinimumPath(self, A): :type label: int
""" :rtype: List[int]
:type A: List[List[int]] """
:rtype: int power_of_2 = 1
""" while power_of_2 <= label:
rows, cols = len(A), len(A[0]) power_of_2 *= 2
heap = [(-A[rows - 1][cols - 1], rows - 1, cols - 1)]
a = label
while True: b = power_of_2 - label - 1 + power_of_2 // 2 # equivalent label in reversed row
neg_max, r, c = heapq.heappop(heap)
if A[r][c] == - 1: # -1 signifies visited result = []
continue while a != 1: # until root
A[r][c] = -1 result.append(a)
if r == c == 0: a //= 2 # up to parents
return -neg_max b //= 2
for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)): a, b = b, a # alternate reversed and not
if r + dr < 0 or r + dr >= rows or c + dc < 0 or c + dc >= cols:
continue result.append(1)
heapq.heappush(heap, (max(-A[r + dr][c + dc], neg_max), r + dr, c + dc)) return result[::-1] # start from root

# python_1001_to_2000/1103_Distribute_Candies_to_People.py # python_1001_to_2000/1105_Filling_Bookcase_Shelves.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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

for i in range(len(books)): # python_1001_to_2000/1109_Corporate_Flight_Bookings.py - m


width = shelf_width # last shelf has no books initially
shelf_height = 0 _author_ = 'jake'
results.append(float("inf")) _project_ = 'leetcode'
j = i # index of next book to be moved to last shelf
# https://leetcode.com/problems/corporate-flight-bookings/
while j >= 0 and width >= books[j][0]: # There are n flights, and they are labeled from 1 to n.
shelf_height = max(shelf_height, books[j][1]) # We have a list of flight bookings.
width -= books[j][0] # A booking [i, j, k] means that we booked k seats from flights labeled i to j inclusive.
results[-1] = min(results[-1], shelf_height + results[j]) # Return an array answer of length n, representing the number of seats booked on each flight in order of their label.
j -= 1
# Create the result with the changes of seats,
return results[-1] # i.e. increment result[start - 1] by seats and decrement result[end] by seats.
# Then update the result by iterating and summing the cumulative changes.
# Time - O(m + n), number of bookings + number of flights
# Space - O(n)

# python_1001_to_2000/1106_Parsing_A_Boolean_Expression.py - h class Solution(object):


def corpFlightBookings(self, bookings, n):
_author_ = 'jake' """
_project_ = 'leetcode' :type bookings: List[List[int]]
:type n: int
# https://leetcode.com/problems/parsing-a-boolean-expression/ :rtype: List[int]
# Return the result of evaluating a given boolean expression, represented as a string. """
# An expression can either be: result = [0] * (n + 1)
# "t", evaluating to True; for start, end, seats in bookings:
# "f", evaluating to False; result[start - 1] += seats
# "!(expr)", evaluating to the logical NOT of the inner expression expr; result[end] -= seats
# "&(expr1,expr2,...)", evaluating to the logical AND of 2 or more inner expressions expr1, expr2, ...;
# "|(expr1,expr2,...)", evaluating to the logical OR of 2 or more inner expressions expr1, expr2, ... seats = 0
for i, change in enumerate(result):
# Iterate over the expression. seats += change
# Add opening braces, booleans and operators to the stack, ignore commas. result[i] = seats
# For closing braces, pop all booleans off and add to a set.
# Apply the operator to the set and push the result back onto the stack. return result[:-1] # remove any change after final flight
# Time - O(n)
# Space - O(n)

class Solution(object): # python_1001_to_2000/1110_Delete_Nodes_And_Return_Forest.py - m


def parseBoolExpr(self, expression):
""" _author_ = 'jake'
:type expression: str _project_ = 'leetcode'
:rtype: bool
""" # https://leetcode.com/problems/delete-nodes-and-return-forest/
stack = [] # Given the root of a binary tree, each node in the tree has a distinct value.
# After deleting all nodes with a value in to_delete, we are left with a forest (a disjoint union of trees).
for c in expression: # Return the roots of the trees in the remaining forest. You may return the result in any order.
if c == "t":
stack.append(True) # Recursive helper function returns a node if it is not deleted, else None.
elif c == "f": # If a node has no parent and is not deleted, add it to the result list.
stack.append(False) # Set the left and right subtrees by recursion.
elif c == ")":
booleans = set() # Time - O(n)
while stack[-1] != "(": # Space - O(n)
booleans.add(stack.pop())
stack.pop() # discard opening bracket class Solution(object):
operator = stack.pop() def delNodes(self, root, to_delete):
if operator == "&": """
stack.append(all(booleans)) :type root: TreeNode
elif operator == "|": :type to_delete: List[int]
stack.append(any(booleans)) :rtype: List[TreeNode]
else: """
stack.append(not booleans.pop()) to_delete = set(to_delete) # convert to set for O(1) lookup
elif c != ",": result = []
stack.append(c)
def helper(node, has_parent):
return stack[-1] if not node:
return None
delete = node.val in to_delete
if not has_parent and not delete:
# python_1001_to_2000/1108_Defanging_an_IP_Address.py result.append(node)
node.left = helper(node.left, not delete)
_author_ = 'jake' node.right = helper(node.right, not delete)
_project_ = 'leetcode' return None if delete else node

# https://leetcode.com/problems/defanging-an-ip-address/ helper(root, False)


# Given a valid (IPv4) IP address, return a defanged version of that IP address. return result
# A defanged IP address replaces every period "." with "[.]".

# 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

for c in seq: def helper(node):


if c == ")": # decrement before c if not node:
depth -= 1 return 0, 0
result.append(depth % 2) left_nodes, left_sum = helper(node.left)
if c == "(": # increment after c right_nodes, right_sum = helper(node.right)
depth += 1 total_nodes = 1 + left_nodes + right_nodes
total_sum = node.val + left_sum + right_sum
return result self.result = max(self.result, total_sum / float(total_nodes))
return total_nodes, total_sum

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.

class Solution(object): # There are at most n // K subsequences for an array of length n.


def numberOfDays(self, Y, M): # If any element occurs more frequently than the most number of subsequences then we cannot make that many increasing
""" # subsequences, because the element must be duplicated in at least one subsequence.
:type Y: int # Else we can always take elements to make increasing subsequences.
:type M: int # Time - O(n)
:rtype: int # Space - O(n)
"""
if M == 2: # February from collections import Counter
if Y % 4 != 0: # not a leap year if not divisible by 4
return 28 class Solution(object):
if Y % 400 == 0: # leap year if divisible by 400 def canDivideIntoSubsequences(self, nums, K):
return 29 """
if Y % 100 == 0: # not a leap year if not divisible by 100 but not 400, e.g. 1900 :type nums: List[int]
return 28 :type K: int
return 29 :rtype: bool
"""
if M in [4, 6, 9, 11]: # not February return max(Counter(nums).values()) <= len(nums) // K
return 30
return 31

# python_1001_to_2000/1122_Relative_Sort_Array.py

# python_1001_to_2000/1119_Remove_Vowels_from_a_String.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/relative-sort-array/
# Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all elements in arr2 are also in arr1.
# https://leetcode.com/problems/remove-vowels-from-a-string/ # Sort the elements of arr1 such that the relative ordering of items in arr1 are the same as in arr2.
# Given a string S, remove the vowels 'a', 'e', 'i', 'o', and 'u' from it, and return the new string. # Elements that don't appear in arr2 should be placed at the end of arr1 in ascending order.

# 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

# python_1001_to_2000/1123_Lowest_Common_Ancestor_of_Deepest_Leaves.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/smallest-sufficient-team/
# In a project, you have a list of required skills req_skills, and a list of people.
# https://leetcode.com/problems/lowest-common-ancestor-of-deepest-leaves/ # The i-th person people[i] contains a list of skills that person has.
# Given a rooted binary tree, return the lowest common ancestor of its deepest leaves. # Consider a sufficient team: a set of people such that for every required skill in req_skills,
# Recall that: # there is at least one person in the team who has that skill.
# The node of a binary tree is a leaf if and only if it has no children # We can represent these teams by the index of each person:
# The depth of the root of the tree is 0, and if the depth of a node is d, the depth of each of its children is d+1. # for example, team = [0, 1, 3] represents the people with skills people[0], people[1], and people[3].
# The lowest common ancestor of a set S of nodes is the node A with the largest depth, # Return any sufficient team of the smallest possible size, represented by the index of each person.
# such that every node in S is in the subtree with root A. # You may return the answer in any order. It is guaranteed an answer exists.

# 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)

class Solution(object): class Solution(object):


def lcaDeepestLeaves(self, root): def smallestSufficientTeam(self, req_skills, people):
""" """
:type root: TreeNode :type req_skills: List[str]
:rtype: TreeNode :type people: List[List[str]]
""" :rtype: List[int]
def helper(node): """
if not node: skill_to_int = {skill: i for i, skill in enumerate(req_skills)}
return None, 0 people_skills = [0] * len(people) # skills per person represented as an int
for i, person in enumerate(people):
left_lca, left_depth = helper(node.left) for skill in person:
right_lca, right_depth = helper(node.right) people_skills[i] |= 1 << skill_to_int[skill]
if left_depth == right_depth:
return node, left_depth + 1 self.has_skills = 0 # current skills, represented as an int
self.smallest_team = list(range(len(req_skills) + 1))
if left_depth > right_depth: team = [] # current team
return left_lca, left_depth + 1
return right_lca, right_depth + 1 def helper(next_skill):
if len(team) >= len(self.smallest_team): # early return is cannot improve on result
result, _ = helper(root) return
return result if next_skill == len(req_skills):
self.smallest_team = team[:]
return

# python_1001_to_2000/1124_Longest_Well-Performing_Interval.py - m if self.has_skills & (1 << next_skill):


helper(next_skill + 1)
_author_ = 'jake' else:
_project_ = 'leetcode' for i, person_skills in enumerate(people_skills):
if person_skills & (1 << next_skill):
# https://leetcode.com/problems/longest-well-performing-interval/ copy_skills = self.has_skills # save so can be reset after recursion
# We are given hours, a list of the number of hours worked per day for a given employee. self.has_skills |= person_skills
# A day is considered to be a tiring day if and only if the number of hours worked is (strictly) greater than 8. team.append(i)
# A well-performing interval is an interval of days for which the number of tiring days is strictly larger helper(next_skill + 1)
# than the number of non-tiring days. team.pop() # revert team and skills before next person
# Return the length of the longest well-performing interval. self.has_skills = copy_skills

# 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

# Breadth-first search the graph of (node, next colour). _author_ = 'jake'


# Expand all neighbours of frontier, ignoring (node, colour) seen before. _project_ = 'leetcode'
# Update result on first instance of visiting a node.
# Time - O(m + n) # https://leetcode.com/problems/maximum-of-absolute-value-expression/
# Space - O(m + n) # Given two arrays of integers with equal lengths, return the maximum value of:
# |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
from collections import defaultdict # where the maximum is taken over all 0 <= i, j < arr1.length.

class Solution(object): # Each of arr1[i], arr2[i] and i can be positive or negative.


def shortestAlternatingPaths(self, n, red_edges, blue_edges): # So there are 2**3 == 8 ways to combine those three values.
""" # Some combinations are the negative of other, so there are actually 4 ways ignoring sign.
:type n: int # Calculate the 4 ways, then return the maximum of the greatest range of each way.
:type red_edges: List[List[int]] # Time - O(n)
:type blue_edges: List[List[int]] # Space - O(n)
:rtype: List[int]
""" class Solution(object):
red, blue = defaultdict(list), defaultdict(list) # convert edges to maps from node to neighbours def maxAbsValExpr(self, arr1, arr2):
for start, end in red_edges: """
red[start].append(end) :type arr1: List[int]
for start, end in blue_edges: :type arr2: List[int]
blue[start].append(end) :rtype: int
"""
result = [-1] * n # default to -1 temp1, temp2, temp3, temp4 = [], [], [], []
frontier = [(0, True), (0, False)] # list of (node, is_red) to explore for i, (a1, a2) in enumerate(zip(arr1, arr2)):
steps = 0 temp1.append(a1 + a2 + i)
visited = set() temp2.append(a1 + a2 - i)
temp3.append(a1 - a2 + i)
while frontier: temp4.append(a1 - a2 - i)
new_frontier = []
for node, is_red in frontier: return max(max(temp) - min(temp) for temp in [temp1, temp2, temp3, temp4])
if (node, is_red) in visited: # visited this node, colour combination already
continue
visited.add((node, is_red))
if result[node] == -1: # first visit to this node # python_1001_to_2000/1133_Largest_Unique_Number.py
result[node] = steps
_author_ = 'jake'
nbors = red[node] if is_red else blue[node] _project_ = 'leetcode'
new_frontier += [(nbor, not is_red) for nbor in nbors]
# https://leetcode.com/problems/largest-unique-number/
frontier = new_frontier # Given an array of integers A, return the largest integer that only occurs once.
steps += 1 # If no integer occurs once, return -1.

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)

# python_1001_to_2000/1130_Minimum_Cost_Tree_From_Leaf_Values.py - m from collections import Counter

_author_ = 'jake' class Solution(object):


def largestUniqueNumber(self, A): connected.add(nbor)
""" result += cost
:type A: List[int] for edge in edges[nbor]:
:rtype: int if edge[1] not in connected: # only add if not already connected
""" heapq.heappush(connections, edge)
freq = Counter(A)
unique = [key for key, val in freq.items() if val == 1] return result
if not unique: # no number has a count of 1
return -1
return max(unique)
# python_1001_to_2000/1136_Parallel_Courses.py - m

_author_ = 'jake'
# python_1001_to_2000/1134_Armstrong_Number.py _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/parallel-courses/


_project_ = 'leetcode' # There are N courses, labelled from 1 to N.
# We are given relations[i] = [X, Y], representing a prerequisite relationship between course X and course Y:
# https://leetcode.com/problems/armstrong-number/ # course X has to be studied before course Y.
# The k-digit number N is an Armstrong number if and only if the k-th power of each digit sums to N. # In one semester you can study any number of courses as long as you have studied all the prerequisites
# Given a positive integer N, return true if and only if it is an Armstrong number. # for the course you are studying.
# Return the minimum number of semesters needed to study all courses.
# Remove digits by dividing by 10. Add each digit ** length to the result. # If there is no way to study all the courses, return -1.
# Compare result to original number.
# Time - O(log n) # Map each course to the list of next courses, and to a count of its prerequisites.
# Space - O(log n) # Repeatedly take all courses with no prerequisites and decreases the prerequisite counts of all courses that they
# are prerequisites for. Update the courses that now have all their prerequisites taken.
class Solution(object): # Time - O(m + n)
def isArmstrong(self, N): # Space - O(m + n)
"""
:type N: int from collections import defaultdict
:rtype: bool
""" class Solution(object):
digits = len(str(N)) def minimumSemesters(self, N, relations):
result, n = 0, N """
:type N: int
while n > 0: :type relations: List[List[int]]
n, digit = divmod(n, 10) :rtype: int
result += digit ** digits """
course_to_next = defaultdict(list) # map course to list of next courses
return result == N prerequisite_count = defaultdict(int) # map course to count of prerequisites
for pre, post in relations:
course_to_next[pre].append(post)
prerequisite_count[post] += 1
# python_1001_to_2000/1135_Connecting_Cities_With_Minimum_Cost.py - m
# initilaize list of courses with no prerequisites
_author_ = 'jake' no_preresquisites = [course for course in range(1, N + 1) if prerequisite_count[course] == 0]
_project_ = 'leetcode' taken, semesters = 0, 0 # counts of courses take and semesters

# https://leetcode.com/problems/connecting-cities-with-minimum-cost/ while no_preresquisites: # some course has no prerequisites


# There are N cities numbered from 1 to N. new_no_preresquisites = []
# You are given connections, where each connections[i] = [city1, city2, cost] for course in no_preresquisites:
# represents the cost to connect city1 and city2 together. for next_course in course_to_next[course]:
# A connection is bidirectional: connecting city1 and city2 is the same as connecting city2 and city1. prerequisite_count[next_course] -= 1 # take course, so decrease prerequisites of next
# Return the minimum cost so that for every pair of cities, there exists a path of connections (possibly of length 1) if prerequisite_count[next_course] == 0:
# that connects those two cities together. new_no_preresquisites.append(next_course)
# The cost is the sum of the connection costs used. If the task is impossible, return -1.
semesters += 1
# Convert connections to map from a city to a list of neighbours connected by an edge. taken += len(no_preresquisites)
# Start from any city, city 1 is chosen arbitrarily. if taken == N:
# Add all edges from the starting city to the heap in the form (cost, neighbour). return semesters
# Repeatedly pop off the neighbour with the lowest cost. no_preresquisites = new_no_preresquisites
# If neighbour is not already connected, update the total cost and add its unconnected neighbours to the heap.
# Time - O(n log n) for n connections. return -1
# Space - O(n)

from collections import defaultdict


import heapq # python_1001_to_2000/1137_N-th_Tribonacci_Number.py

class Solution(object): _author_ = 'jake'


def minimumCost(self, N, connections): _project_ = 'leetcode'
"""
:type N: int # https://leetcode.com/problems/n-th-tribonacci-number/
:type connections: List[List[int]] # The Tribonacci sequence Tn is defined as follows:
:rtype: int # T0 = 0, T1 = 1, T2 = 1, and Tn+3 = Tn + Tn+1 + Tn+2 for n >= 0.
""" # Given n, return the value of Tn.
edges = defaultdict(list)
for a, b, cost in connections: # Repeatedly make the next elements of the sequence from the sum of the last 3 elements.
edges[a].append((cost, b)) # Alternatively, use a queue and retain only 3 elements to resuce space to O(1).
edges[b].append((cost, a)) # Time - O(n)
# Space - O(n)
connected = {1} # set of connected cities
connections = list(edges[1]) # unexplored edges from connected cities class Solution(object):
heapq.heapify(connections) def tribonacci(self, n):
result = 0 """
:type n: int
while len(connected) < N: :rtype: int
if not connections: """
return -1 nums = [0, 1, 1]
while len(nums) <= n:
cost, nbor = heapq.heappop(connections) # cheapest cost nums.append(sum(nums[-3:]))
if nbor in connected:
continue return nums[n]

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)

result = [] class Solution(object):


row, col = 0, 0 def stoneGameII(self, piles):
for char in target: """
r, c = location(char) :type piles: List[int]
if c < col: :rtype: int
result += ["L"] * (col - c) """
if r < row: n = len(piles)
result += ["U"] * (row - r) for i in range(n - 2, -1, -1):
if c > col: piles[i] += piles[i + 1] # convert to cumulative sum from end
result += ["R"] * (c - col) memo = {}
if r > row:
result += ["D"] * (r - row) def helper(i, M):
if i + 2 * M >= n: # take all remaining piles
row, col = r, c return piles[i]
result.append("!") if (i, M) in memo:
return memo[(i, M)]
return "".join(result)
best = 0
for x in range(1, 2 * M + 1): # try all valid values of x
best = max(best, piles[i] - helper(i + x, max(M, x)))
# python_1001_to_2000/1139_Largest_1-Bordered_Square.py - m
memo[(i, M)] = best
_author_ = 'jake' return best
_project_ = 'leetcode'
return helper(0, 1)
# https://leetcode.com/problems/largest-1-bordered-square/
# Given a 2D grid of 0s and 1s, return the number of elements in the largest square subgrid that has all 1s
# on its border, or 0 if such a subgrid doesn't exist in the grid.
# python_1001_to_2000/1143_Longest_Common_Subsequence.py - m
# Iterate along each row, counting the continuous sequence of ones.
# For each side length from the sequence down to the current best side length + 1, _author_ = 'jake'
# check if the other 3 edges of the square are all ones. _project_ = 'leetcode'
# Return early or continue if the current best cannot be improved.
# Time - O(mn * (m + n)) since for each cell of the grid, explore up to side lengths of the grid. # https://leetcode.com/problems/longest-common-subsequence/
# Space - O(1) # Given two strings text1 and text2, return the length of their longest common subsequence.
# A subsequence of a string is a new string generated from the original string with some characters (can be none)
class Solution(object): # deleted without changing the relative order of the remaining characters.
def largest1BorderedSquare(self, grid): # Eg, "ace" is a subsequence of "abcde" while "aec" is not.
""" # A common subsequence of two strings is a subsequence that is common to both strings.
:type grid: List[List[int]] # If there is no common subsequence, return 0.
:rtype: int
""" # Dynamic programming.
rows, cols = len(grid), len(grid[0]) # For each prefix of text1, find the lcs with each prefix of text2.
best = 0 # If the end characters of each prefix are equal, we can extend the lcs of the prefixes without the end characters.
# Else we take the longest lcs ignoring the last character from one prefix.
for row in range(rows): # Time - O(mn)
sequence = 0 # Space - O(n)
for col in range(cols):
if best >= rows - row: # insufficient rows to make a bigger square class Solution(object):
return best * best def longestCommonSubsequence(self, text1, text2):
"""
if grid[row][col] == 1: :type text1: str
:type text2: str :type x: int
:rtype: int :rtype: bool
""" """
m, n = len(text1), len(text2) self.left, self.right = 0, 0
lcs = [0 for _ in range(n + 1)]
def count(node):
for c1 in text1: # for prefix of text1 up to and including c1 if not node:
new_lcs = [0] return 0
for j, c2 in enumerate(text2): # for prefix of text2 up to and including c2
if c1 == c2: if node.val == x: # count child subtrees
new_lcs.append(1 + lcs[j]) self.left = count(node.left)
else: self.right = count(node.right)
new_lcs.append(max(new_lcs[-1], lcs[j + 1])) return 0
lcs = new_lcs
return 1 + count(node.left) + count(node.right)
return lcs[-1]
parent = count(root)
results = sorted([parent, self.left, self.right])

return results[-1] > sum(results[:2]) + 1


# python_1001_to_2000/1144_Decrease_Elements_To_Make_Array_Zigzag.py - m

_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1146_Snapshot_Array.py - m

# https://leetcode.com/problems/decrease-elements-to-make-array-zigzag/ _author_ = 'jake'


# Given an array nums of integers, a move consists of choosing any element and decreasing it by 1. _project_ = 'leetcode'
# An array A is a zigzag array if either:
# Every even-indexed element is greater than adjacent elements, ie. A[0] > A[1] < A[2] > A[3] < A[4] > ... # https://leetcode.com/problems/snapshot-array/
# OR, every odd-indexed element is greater than adjacent elements, ie. A[0] < A[1] > A[2] < A[3] > A[4] < ... # Implement a SnapshotArray that supports the following interface:
# Return the minimum number of moves to transform the given array nums into a zigzag array. #
# SnapshotArray(int length) initializes an array-like data structure with the given length.
# Iterate over array, calculating the cost of making each element lower than its lowest neighbour. # Initially, each element equals 0.
# Add the cost to the total cost of even or odd indices. # void set(index, val) sets the element at the given index to be equal to val.
# Return the minimum total cost. # int snap() takes a snapshot of the array and returns the snap_id: the total number of times we called snap() minus 1.
# Time - O(n) # int get(index, snap_id) returns the value at the given index, at the time we took the snapshot with the given snap_id
# Space - O(n)
# For each index of the array, store the historical values as [snap_id, value].
class Solution(object): # When setting a value, append a new [snap_id, value] if the value and id has changed.
def movesToMakeZigzag(self, nums): # Binary search the history to find a value at a previous snap.
""" # Time - O(n) for __init__ when n is the array length.
:type nums: List[int] # O(1) for set and snap. O(m) for get for m snap operations.
:rtype: int # Space - O(mn)
"""
nums = [float('inf')] + nums + [float('inf')] import bisect
even_low, odd_low = 0, 0 # moves to make the even and odd indices low
class SnapshotArray(object):
for i in range(1, len(nums) - 1):
# decrease nums[i] to 1 less than the lowest neighbour def __init__(self, length):
cost = max(0, nums[i] - min(nums[i - 1], nums[i + 1]) + 1) """
if i % 2 == 0: :type length: int
even_low += cost """
else: self.history = [[[-1, 0]] for _ in range(length)]
odd_low += cost self.id = 0 # next snap id

return min(even_low, odd_low) def set(self, index, val):


"""
:type index: int
:type val: int
# python_1001_to_2000/1145_Binary_Tree_Coloring_Game.py - m :rtype: None
"""
_author_ = 'jake' if val == self.history[index][-1][1]: # do nothing if value unchanged
_project_ = 'leetcode' return
if self.history[index][-1][0] == self.id: # update value only if id is unchanged
# https://leetcode.com/problems/binary-tree-coloring-game/ self.history[index][-1][1] = val
# Two players play a turn based game on a binary tree. return
# We are given the root of this binary tree, and the number of nodes n in the tree.
# n is odd, and each node has a distinct value from 1 to n. self.history[index].append([self.id, val])
# Initially, the first player names a value x with 1 <= x <= n,
# and the second player names a value y with 1 <= y <= n and y != x. def snap(self):
# The first player colors the node with value x red, and the second player colors the node with value y blue. """
# Then, the players take turns starting with the first player. :rtype: int
# In each turn, that player chooses any node of their color (red if player 1, blue if player 2) """
# and colors an uncolored neighbor of the chosen node (either the left child, right child, or parent of the node.) self.id += 1
# If (and only if) a player cannot choose such a node in this way, they must pass their turn. return self.id - 1
# If both players pass their turn, the game ends, and the winner is the player that colored more nodes.
# You are the second player. def get(self, index, snap_id):
# If it is possible to choose such a y to ensure you win the game, return true. """
# If it is not possible, return false. :type index: int
:type snap_id: int
# Count the nodes from the root excluding those after the red node. :rtype: int
# Also count the left and right subtrees of the red node. """
# The second player should colour the parent, left child or right child of the red node. # binary search for inf value to always return the index after the snap_id
# If the most nodes controlled from any of those locations is greater than the nodes in the other locations + the i = bisect.bisect_left(self.history[index], [snap_id, float("inf")])
# initial red node, then the second player can win. return self.history[index][i - 1][1]
# Time - O(n)
# Space - O(n)

class Solution(object): # python_1001_to_2000/1147_Longest_Chunked_Palindrome_Decomposition.py - m


def btreeGameWinningMove(self, root, n, x):
""" _author_ = 'jake'
:type root: TreeNode _project_ = 'leetcode'
:type n: int

# https://leetcode.com/problems/longest-chunked-palindrome-decomposition/ ones = sum(data)


# Return the largest possible k such that there exists a_1, a_2, ..., a_k such that: window_sum = sum(data[:ones]) # initial sliding window
# Each a_i is a non-empty string; result = ones - window_sum # count of ones to move inside window
# Their concatenation a_1 + a_2 + ... + a_k is equal to text;
# For all 1 <= i <= k, a_i = a_{k+1 - i}. for i in range(len(data) - ones):
window_sum -= data[i]
# Find a prefix of text that matches a suffix, then remove the prefix and the suffix and repeat. window_sum += data[i + ones]
# Continue until all the text is used or we are half way through and the middle is not a palindrome. result = min(result, ones - window_sum)
# Time - O(n**2)
# Space - O(n) return result

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

# Count the number of ones. class Solution(object):


# Iterate along the data with a sliding window of length of the number of ones. def canConvert(self, str1, str2):
# At each index, update the number of ones in the window. """
# Update the result with the number of ones outside the window, that would have to move to group the ones together. :type str1: str
# Time - O(n) :type str2: str
# Space - O(1) :rtype: bool
"""
class Solution(object): if len(set(str2)) == 26 and str1 != str2:
def minSwaps(self, data): return False
"""
:type data: List[int] char1_indices = defaultdict(list)
:rtype: int for i, c in enumerate(str1):
""" char1_indices[c].append(i)
for c, indices in char1_indices.items(): from collections import defaultdict
if len({str2[i] for i in indices}) != 1:
return False class Solution(object):
def maxRepOpt1(self, text):
return True """
:type text: str
:rtype: int
"""
# python_1001_to_2000/1154_Day_of_the_Year.py char_substrings = defaultdict(list) # map char to list of [start, end] substrings
for i, c in enumerate(text):
_author_ = 'jake' if i == 0 or c != text[i - 1]:
_project_ = 'leetcode' char_substrings[c].append([i, i])
else:
# https://leetcode.com/problems/day-of-the-year/ char_substrings[c][-1][1] = i
# Given a string date representing a Gregorian calendar date formatted as YYYY-MM-DD,
# return the day number of the year. result = 0
for substrings in char_substrings.values():
# Find the number of day in the whole months completed, assuming not a leap year. for i, (start, end) in enumerate(substrings):
# Add 29th February if in March or later and a leap year. length = end - start + 1
# Time - O(n) # add 1 to length if there is at least one other substring
# Space - O(n) result = max(length + int(len(substrings) >= 2), result)

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]

year, month, day = [int(x) for x in date.split("-")]


result = cumulative_days[month - 1] + day # python_1001_to_2000/1157_Online_Majority_Element_In_Subarray.py - h

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

class Solution(object): class MajorityChecker(object):


def numRollsToTarget(self, d, f, target):
""" def __init__(self, arr):
:type d: int """
:type f: int :type arr: List[int]
:type target: int """
:rtype: int self.val_to_indices = defaultdict(list)
""" for i, val in enumerate(arr):
MOD = 10 ** 9 + 7 self.val_to_indices[val].append(i)
dp = [[0 for _ in range(target + 1)] for _ in range(d + 1)]
dp[0][0] = 1 # 1 way to make 0 with 0 dice self.vals = sorted(self.val_to_indices.keys(), key=lambda x: len(self.val_to_indices[x]), reverse=True)

for die in range(1, d + 1): def query(self, left, right, threshold):


for total in range(die, target + 1): # make each possible score """
dp[die][total] = sum(dp[die - 1][max(total - f, 0):total]) % MOD :type left: int
:type right: int
return dp[-1][-1] :type threshold: int
:rtype: int
"""
for val in self.vals:
# python_1001_to_2000/1156_Swap_For_Longest_Repeated_Character_Substring.py - m if len(self.val_to_indices[val]) < threshold:
break
_author_ = 'jake' left_i = bisect.bisect_left(self.val_to_indices[val], left)
_project_ = 'leetcode' right_i = bisect.bisect_right(self.val_to_indices[val], right)
if right_i - left_i >= threshold:
# https://leetcode.com/problems/swap-for-longest-repeated-character-substring/ return val
# Given a string text, we are allowed to swap two of the characters in the string.
# Find the length of the longest substring with repeated characters. return -1

# 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

# python_1001_to_2000/1161_Maximum_Level_Sum_of_a_Binary_Tree.py - m return distance

_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)

# https://leetcode.com/problems/as-far-from-land-as-possible/ candidates = char_indices[max(char_indices.keys())]


# Given an N x N grid containing only values 0 and 1, where 0 represents water and 1 represents land, length += 1
# find a water cell such that its distance to the nearest land cell is maximized and return the distance.
# The distance used in this problem is the Manhattan distance: return s[candidates.pop() - length:] # suffix of s
# the distance between two cells (x0, y0) and (x1, y1) is |x0 - x1| + |y0 - y1|.
# If no land or water exists in the grid, return -1.

# Breadth-first search. # python_1001_to_2000/1165_Single-Row_Keyboard.py


# Maintain a count of frontier cells to explore, initially all the land cells.
# Maintain a count of cells reached, initially all the land cells. _author_ = 'jake'
# For each cell of the frontier, add all neighbours to visited count and to new frontier. Set value to 1 to avoid _project_ = 'leetcode'
# repeated visits to the same cell.
# Stop when the whole grid has been counted. # https://leetcode.com/problems/single-row-keyboard/
# Time - O(mn) # There is a special keyboard with all keys in a single row.
# Space - O(mn) # Given a string keyboard of length 26 indicating the layout of the keyboard (indexed from 0 to 25),
# initially your finger is at index 0.
class Solution(object): # To type a character, you have to move your finger to the index of the desired character.
# The time taken to move your finger from index i to index j is |i - j|.
# You want to type a string word. Write a function to calculate how much time it takes to type it with one finger.
# python_1001_to_2000/1167_Minimum_Cost_to_Connect_Sticks.py - m
# Map each char of keyboard to its index.
# For each char of word, find the distance from the current index to that char. _author_ = 'jake'
# The update the total distance moved and index. _project_ = 'leetcode'
# Time - O(n)
# Space - O(1) # https://leetcode.com/problems/minimum-cost-to-connect-sticks/
# You have some sticks with positive integer lengths.
class Solution(object): # You can connect any two sticks of lengths X and Y into one stick by paying a cost of X + Y.
def calculateTime(self, keyboard, word): # You perform this action until there is one stick remaining.
""" # Return the minimum cost of connecting all the given sticks into one stick in this way.
:type keyboard: str
:type word: str # Since the cost is proportional to the lengths of sticks connected, we want to connect the shortest sticks.
:rtype: int # Maintain a heap and repeatedly connect the shortest 2 sticks, putting the connected stick back on the heap.
""" # Time - O(n log n)
char_to_index = {c : i for i, c in enumerate(keyboard)} # Space - O(n)

result, index = 0, 0 import heapq


for c in word:
next_index = char_to_index[c] class Solution(object):
result += abs(next_index - index) def connectSticks(self, sticks):
index = next_index """
:type sticks: List[int]
return result :rtype: int
"""
cost = 0
heapq.heapify(sticks)
# python_1001_to_2000/1166_Design_File_System.py - m
while len(sticks) > 1:
_author_ = 'jake' x, y = heapq.heappop(sticks), heapq.heappop(sticks)
_project_ = 'leetcode' cost += x + y
heapq.heappush(sticks, x + y)
# https://leetcode.com/problems/design-file-system/
# You are asked to design a file system which provides two functions: return cost
# createPath(path, value): Creates a new path and associates a value to it if possible and returns True.
# Returns False if the path already exists or its parent path doesn't exist.
# get(path): Returns the value associated with a path or returns -1 if the path doesn't exist.
# The format of a path is one or more concatenated strings of the form: # python_1001_to_2000/1168_Optimize_Water_Distribution_in_a_Village.py - h
# / followed by one or more lowercase English letters.
# For example, /leetcode and /leetcode/problems are valid paths while an empty string and / are not. _author_ = 'jake'
# Implement the two functions. _project_ = 'leetcode'

# Build a tree of folders in the file system. # https://leetcode.com/problems/optimize-water-distribution-in-a-village/


# Each node of the tree has a value and a map to child folders. # There are n houses in a village. We want to supply water for all the houses by building wells and laying pipes.
# To createPath, break the path into a list of folders and find the node of the penultimate folder. If the path is # For each house i, we can either build a well inside it directly with cost wells[i],
# valid, insert the value in a new child node. # or pipe in water from another well to it.
# To get, follow the folders down the tree, returning the final value if the path is valid. # The costs to lay pipes between houses are given by the array pipes,
# Time - O(n) for createPath and get where n is the number of previous createPath. # where each pipes[i] = [house1, house2, cost] represents the cost to connect house1 and house2 together using a pipe.
# Space - O(n) # Connections are bidirectional.
# Find the minimum total cost to supply water to all houses.
class Node(object):
def __init__(self, value): # Maintain a heap of accessible sources of water, by (cost, house).
self.children = {} # Initial heap consists of all wells. Repeatedly use the least cost from the heap to connect an unconnected house.
self.value = value # Add all pipes to neighbours to the heap. Repeat until all houses are connected.
# Time - O(m log(m + n)) for m pipes and n wells, since each pipe is added to heap of all pipes and wells.
class FileSystem(object): # Space - O(m + n)

def __init__(self): from collections import defaultdict


self.root = Node(None) import heapq

# 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

_author_ = 'jake' # python_1001_to_2000/1171_Remove_Zero_Sum_Consecutive_Nodes_from_Linked_List.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/invalid-transactions/ _project_ = 'leetcode'
# A transaction is possibly invalid if:
# the amount exceeds $1000, or; # https://leetcode.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list/
# if it occurs within (and including) 60 minutes of another transaction with the same name in a different city. # Given the head of a linked list,
# Each transaction string transactions[i] consists of comma separated values representing: # we repeatedly delete consecutive sequences of nodes that sum to 0 until there are no such sequences.
# the name, time (in minutes), amount, and city of the transaction. # After doing so, return the head of the final linked list. You may return any such answer.
# Given a list of transactions, return a list of transactions that are possibly invalid.
# You may return the answer in any order. # Iterate along the list, updating a running sum of node values.
# If we have running sum that has been seen before, connect the previous node with the running sum to the next node,
# Sort all transactions by ascending time. # thereby removing the zero sum sequence from the list.
# For user, maintain an ordered list of previous transactions. # Use an OrderedDict so we can pop all the eliminated nodes off the dictionary.
# For each transactions, add to result if cost > 1000. # Alternatively, when a zero sum sequence is found eliminate those nodes and start from the head again.
# Iterate backwards through the previous transactions for that user, while they are within 60 minutes. # So the dictionary does not have to be cleared.
# If a previous transaction is in a different city, add both current and previous to the invalid set. # Time - O(n)
# Time - O(n**2) since for each transaction we may iterate through all previous transactions. # Space - O(n)
# Space - O(n)
from collections import OrderedDict
from collections import defaultdict
class Solution(object):
class Solution(object): def removeZeroSumSublists(self, head):
def invalidTransactions(self, transactions): """
""" :type head: ListNode
:type transactions: List[str] :rtype: ListNode
:rtype: List[str] """
""" dummy = ListNode(0) # create a new dummy head, in case the head is removed
elements = [transaction.split(",") + [i] for i, transaction in enumerate(transactions)] dummy.next = head
elements.sort(key=lambda x: int(x[1])) # sort by ascending time node = dummy
running_sum = 0 # sum of all node vals seen
user_transactions = defaultdict(list) # map user to list of transactions ordered by time sum_to_node = OrderedDict() # map running_sum to ListNode
invalid = set() # remove duplicates by using set
while node:
for transaction in elements: running_sum += node.val
name, time, cost, city, i = transaction to_connect = sum_to_node.get(running_sum, node) # node to be connected to node.next
time = int(time)
while running_sum in sum_to_node: # remove eliminated nodes
if int(cost) > 1000: sum_to_node.popitem()
invalid.add(transactions[i]) sum_to_node[running_sum] = to_connect

j = len(user_transactions[name]) - 1 node = to_connect.next = node.next


while j >= 0 and time - user_transactions[name][j][0] <= 60: # while within 60 minutes
if user_transactions[name][j][1] != city: return dummy.next
invalid.add(transactions[i])
invalid.add(transactions[user_transactions[name][j][2]])
j -= 1
# python_1001_to_2000/1172_Dinner_Plate_Stacks.py - h
user_transactions[name].append([time, city, i]) # update previous transactions for this person
_author_ = 'jake'
return list(invalid) _project_ = 'leetcode'

# 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

def popAtStack(self, index): # python_1001_to_2000/1177_Can_Make_Palindrome_from_Substring.py - m


"""
:type index: int _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
if index >= len(self.stacks) or len(self.stacks[index]) == 0: # https://leetcode.com/problems/can-make-palindrome-from-substring/
return -1 # Given a string s, we make queries on substrings of s.
# For each query queries[i] = [left, right, k], we may rearrange the substring s[left], ..., s[right],
if index == len(self.stacks) - 1: # do not need incomplete_stacks for final stack # and then choose up to k of them to replace with any lowercase English letter.
return self.pop() # If the substring is possible to be a palindrome string after the operations above, the result of the query is true.
# Otherwise, the result is false.
heapq.heappush(self.incomplete_stacks, index) # Return an array answer[], where answer[i] is the result of the i-th query queries[i].
return self.stacks[index].pop() # Note that: Each letter is counted individually for replacement so if for example s[left..right] = "aaa",
# and k = 2, we can only replace two of the letters.
# Also, note that the initial string s is never modified by any query.

# 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")))

class Solution(object): result = []


def numPrimeArrangements(self, n): for left, right, k in queries:
""" left_odd_bits = char_odd_bits[left]
:type n: int right_odd_bits = char_odd_bits[right + 1]
:rtype: int odd_chars = bin(left_odd_bits ^ right_odd_bits).count("1") # XOR to count different bits in left and right
"""
primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] odd_chars -= (right - left + 1) % 2 # use an odd char for the middle if substring length is odd
prime_count = bisect.bisect_right(primes, n) odd_chars -= 2 * k # change each odd char to match another odd char
return (math.factorial(prime_count) * math.factorial(n - prime_count)) % (10 ** 9 + 7) result.append(odd_chars <= 0)

return result

# python_1001_to_2000/1176_Diet_Plan_Performance.py

_author_ = 'jake' # python_1001_to_2000/1178_Number_of_Valid_Words_for_Each_Puzzle.py - h


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/diet-plan-performance/ _project_ = 'leetcode'
# A dieter consumes calories[i] calories on the i-th day.
# Given an integer k, for every consecutive sequence of k days # https://leetcode.com/problems/number-of-valid-words-for-each-puzzle/
# (calories[i], calories[i+1], ..., calories[i+k-1] for all 0 <= i <= n-k), they look at T, # With respect to a given puzzle string, a word is valid if both the following conditions are satisfied:
# the total calories consumed during that sequence of k days (calories[i] + calories[i+1] + ... + calories[i+k-1]): # word contains the first letter of puzzle.
# If T < lower, they performed poorly on their diet and lose 1 point; # For each letter in word, that letter is in puzzle.
# If T > upper, they performed well on their diet and gain 1 point; # For example, if the puzzle is "abcdefg", then valid words are "faced", "cabbage", and "baggage";
# Otherwise, they performed normally and there is no change in points. # while invalid words are "beefed" (doesn't include "a") and "based" (includes "s" which isn't in the puzzle).
# Initially, the dieter has zero points. # Return an array answer, where answer[i] is the number of words in the given word list words that are valid
# Return the total number of points the dieter has after dieting for calories.length days. # with respect to the puzzle puzzles[i].
# Note that the total points can be negative.
# Convert each word to an integer, where a set bit indicates the presence of of a character.
# Sliding window of the calories consumed over k days. # Count the frequency of each such integer.
# For each day after the end of a window, update points then update window calories. # For each puzzle, form all combinations of integers from characters of the puzzle. Always include the first
# Time - O(n) # character + any number of other character. Add to the result the count of words with each combination.
# Space - O(1) # Time - O(mk + n * 2**p) for m words of length k, and n puzzles of length p.
# Space - O(mk + n)
class Solution(object):
def dietPlanPerformance(self, calories, k, lower, upper): from collections import Counter
""" from itertools import combinations
:type calories: List[int]
:type k: int class Solution(object):

def findNumOfValidWords(self, words, puzzles):


""" for i, split_phrase1 in enumerate(split_phrases):
:type words: List[str] for j, split_phrase2 in enumerate(split_phrases):
:type puzzles: List[str] if i != j and split_phrase1[-1] == split_phrase2[0]:
:rtype: List[int] joined = " ".join(split_phrase1 + split_phrase2[1:])
""" result.add(joined)
def word_to_int(s):
bits = 0 return sorted(result)
for c in s:
bits |= (1 << (ord(c) - ord("a")))
return bits
# python_1001_to_2000/1182_Shortest_Distance_to_Target_Color.py - m
word_bits_counter = Counter(word_to_int(w) for w in words)
_author_ = 'jake'
result = [] _project_ = 'leetcode'

for puzzle in puzzles: # https://leetcode.com/problems/shortest-distance-to-target-color/


first_char_bit = word_to_int(puzzle[0]) # this bit is always set # You are given an array colors, in which there are three colors: 1, 2 and 3.
other_char_bits = [word_to_int(c) for c in puzzle[1:]] # check all combinations of these bits # You are also given some queries.
valid = 0 # Each query consists of two integers i and c,
for k in range(7): # 0 to 6 other bits # return the shortest distance between the given index i and the target color c.
for combination in combinations(other_char_bits, k): # If there is no solution return -1.
valid += word_bits_counter[first_char_bit + sum(combination)]
result.append(valid) # For each element of the array, find the distance to the closest element of each color to the left.
# Then update the closest distance to each color for each index, with any closer indices on the right.
return result # For each query index, lookup the closest distance to the required color.
# Time - O(m + n) for array of length m and n queries.
# Space - O(m + n)

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

# https://leetcode.com/problems/maximum-subarray-sum-with-one-deletion/ _author_ = 'jake'


# Given an array of integers, _project_ = 'leetcode'
# return the maximum sum for a non-empty subarray (contiguous elements) with at most one element deletion.
# In other words, you want to choose a subarray and optionally delete one element from it so that there is still # https://leetcode.com/problems/maximum-number-of-balloons/
# at least one element left and the sum of the remaining elements is maximum possible. # Given a string text, you want to use the characters of text to form as many instances
# Note that the subarray needs to be non-empty after deleting one element. # of the word "balloon" as possible.
# You can use each character in text at most once. Return the maximum number of instances that can be formed.

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'

_author_ = 'jake' # https://leetcode.com/problems/critical-connections-in-a-network/


_project_ = 'leetcode' # There are n servers numbered from 0 to n-1 connected by undirected server-to-server connections forming a network
# where connections[i] = [a, b] represents a connection between servers a and b.
# https://leetcode.com/problems/reverse-substrings-between-each-pair-of-parentheses/ # Any server can reach any other server directly or indirectly through the network.
# You are given a string s that consists of lower case English letters and brackets. # A critical connection is a connection that, if removed, will make some server unable to reach some other server.
# Reverse the strings in each pair of matching parentheses, starting from the innermost one. # Return all critical connections in the network in any order.
# Your result should not contain any brackets.
# A connection is critical if and only if it is not in any cycle in the network.
# Iterate along s, maintaining a stack of text at each depth of open braces. # Convert the connections to an adjacency list for each node.
# For an opening brace, add the text since the previous brace to the current stack top and start a new stack level. # Create a set of all edges (as ordered pairs of nodes).
# For a closing brace, add the text since the previous brace to the current stack top, then pop the top, reverse it # Set the rank of a node as its depth when it is visited, or n when all paths have been fully explored.
# and add to the new stack top. # Depth-first search the graph.
# Time - O(n**2) # Helper function returns the rank of a node if node has already been seen, else the minimum rank of any node that
# Space - O(n) # can be reached.
# For each unvisited node, set rank to depth then recurse to neighbours apart from parent.
class Solution(object): # If any neighbour leads to a node with lower depth then we have seen that node on the current path and the edge
def reverseParentheses(self, s): # between nodes is in a cycle.
""" # Time - O(m + n) for m edges and n nodes
:type s: str # Space - O(m + n)
:rtype: str
""" from collections import defaultdict
stack = [""]
class Solution(object):
start = 0 def criticalConnections(self, n, connections):
for i, c in enumerate(s): """
if c == "(": # add substring to top of stack and start a new empty substring :type n: int
stack[-1] += s[start:i] :type connections: List[List[int]]
stack.append("") :rtype: List[List[int]]
start = i + 1 """
elif c == ")": node_to_nbors = defaultdict(list)
stack[-1] += s[start:i] for connection in connections:
stack[-1] += stack.pop()[::-1] node_to_nbors[connection[0]].append(connection[1])
start = i + 1 node_to_nbors[connection[1]].append(connection[0])

return stack[0] + s[start:] # add remaining text connections = {tuple(sorted(connection)) for connection in connections}
rank = [-float("inf")] * n

def helper(node, depth):


# python_1001_to_2000/1191_K-Concatenation_Maximum_Sum.py - m if rank[node] >= 0: # visiting (0 <= rank < n), or visited (rank == n)
return rank[node]
_author_ = 'jake'
_project_ = 'leetcode' rank[node] = depth # new node on current path
min_nbor_path_depth = n
# https://leetcode.com/problems/k-concatenation-maximum-sum/ for nbor in node_to_nbors[node]:
# Given an integer array arr and an integer k, modify the array by repeating it k times. if rank[nbor] == depth - 1: # don't go back to parent
# For example, if arr = [1, 2] and k = 3 then the modified array will be [1, 2, 1, 2, 1, 2]. continue
# Return the maximum sub-array sum in the modified array.
# Note that the length of the sub-array can be 0 and its sum in that case is 0. nbor_path_depth = helper(nbor, depth + 1)
# As the answer can be very large, return the answer modulo 10^9 + 7. if nbor_path_depth <= depth: # edge forms a cycle
connections.discard(tuple(sorted((node, nbor))))
# Iterate along the array, finding the maximum sum prefix and the maximum sum subarray. min_nbor_path_depth = min(min_nbor_path_depth, nbor_path_depth)
# Iterate along the array in reverse, finding the maximum sum suffix. rank[node] = n # node fully explored
# If k == 1, return the maximum sum subarray. return min_nbor_path_depth
# Else we can use the maximum sum subarray or the max prefix + max suffix.
# If the array sum is positive we can insert (k - 2) copies of the whole array between suffix and prefix. helper(0, 0) # start from any arbitrary node since connected graph
# Time - O(n) return list(connections)
# Space - O(1)

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'

return apples # https://leetcode.com/problems/minimum-time-to-build-blocks/


# You are given a list of blocks, where blocks[i] = t means that the i-th block needs t units of time to be built.
# A block can only be built by exactly one worker.
# A worker can either split into two workers (number of workers increases by one) or build a block then go home.
# python_1001_to_2000/1197_Minimum_Knight_Moves.py - m # Both decisions cost some time.
# The time cost of spliting one worker into two workers is given as an integer split.
_author_ = 'jake' # Note that if two workers split at the same time, they split in parallel so the cost would be split.
_project_ = 'leetcode' # Output the minimum time needed to build all blocks.
# Initially, there is only one worker.
# https://leetcode.com/problems/minimum-knight-moves/
# In an infinite chess board with coordinates from -infinity to +infinity, you have a knight at square [0, 0]. # Create a heap of the time to mine each block.
# A knight has 8 possible moves it can make. # Repeatedly pop off the smallest 2 blocks and combine them into a single block.
# Each move is two squares in a cardinal direction, then one square in an orthogonal direction. # Add the combined block back to the heap, with its time of split + max time to mine underlying blocks.
# Return the minimum number of steps needed to move the knight to the square [x, y]. # Continue until only one block remains.
# It is guaranteed the answer exists. # Time - O(n log n)
# Space - O(n)
# A-star search the board.
# Maintain a heap of positions, repeatedly expanding the position with the lowest possible result. import heapq
# Use a heuristic of the minimum possible moves to reach the target.
# If the distance in the smallest dimension (x or y) is less than twice the distance in the largest dimension, class Solution(object):
# then we can potentially reach target in (largest dimension + 1) // 2 steps. Else we need to add additional steps def minBuildTime(self, blocks, split):
# to reach the target in the smallest dimension. """
# Time - O(d**8) where d is the number of moves to reach the target. :type blocks: List[int]
# Space - O(d**8) :type split: int
:rtype: int
import heapq """
heapq.heapify(blocks)
class Solution(object):
def minKnightMoves(self, x, y): while len(blocks) > 1: # combine the smallest 2 blocks
""" heapq.heappop(blocks)
:type x: int heapq.heappush(blocks, split + heapq.heappop(blocks))
:type y: int
:rtype: int return blocks[0]
"""
def heuristic(cell):
dx, dy = abs(cell[0] - x), abs(cell[1] - y)
min_d, max_d = sorted([dx, dy]) # python_1001_to_2000/1200_Minimum_Absolute_Difference.py
max_moves = (max_d + 1) // 2
return max_moves + max(0, (min_d - max_moves + 1) // 2) _author_ = 'jake'
_project_ = 'leetcode'
queue = [[heuristic((0, 0)), 0, (0, 0)]] # [min total moves possible, moves so far, cell]
seen = set() # https://leetcode.com/problems/minimum-absolute-difference/
# Given an array of distinct integers arr, find all pairs of elements with the minimum absolute
while True: # difference of any two elements.
_, moves, cell = heapq.heappop(queue) # Return a list of pairs in ascending order(with respect to pairs), each pair [a, b] follows
if cell == (x, y): # a, b are from arr
return moves # a < b
# b - a equals to the minimum absolute difference of any two elements in arr
if cell in seen: # ignore cells already reached
continue # Sort the array and iterate along, calculating the difference between each pair.
seen.add(cell) # If the difference is less than the minimum distance, update the minimum and clear the previous results.
# Then if the difference is less than the minimum distance, append the pair to the results.
for dx, dy in [(2, 1), (2, -1), (-2, -1), (-2, 1), (1, 2), (-1, 2), (-1, -2), (1, -2)]: # 8 moves # Time - O(n log n)
new_cell = (cell[0] + dx, cell[1] + dy) # Space - O(n)
if new_cell not in seen:
heapq.heappush(queue, [heuristic(new_cell) + moves + 1, moves + 1, new_cell]) class Solution(object):
def minimumAbsDifference(self, arr):
"""
:type arr: List[int]
# python_1001_to_2000/1198_Find_Smallest_Common_Element_in_All_Rows.py - m :rtype: List[List[int]]
"""
_author_ = 'jake' arr.sort()
_project_ = 'leetcode' results = []
min_diff = float("inf")
# https://leetcode.com/problems/find-smallest-common-element-in-all-rows/
# Given a matrix mat where every row is sorted in increasing order, return the smallest common element in all rows. for i in range(1, len(arr)):
# If there is no common element, return -1. diff = arr[i] - arr[i - 1]
if diff < min_diff:
# Create a set of all elements from the first row. min_diff = diff

results = [] # clear previous results


def find(i):
if diff == min_diff: while parents[i] != i:
results.append([arr[i - 1], arr[i]]) parents[i] = parents[parents[i]] # collapse the grandparent to parent
i = parents[i]
return results return i

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/ugly-number-iii/ result = [None] * n


# Write a program to find the n-th ugly number. for children in parent_to_children.values(): # children indices are sorted
# Ugly numbers are positive integers which are divisible by a or b or c. chars = sorted(s[i] for i in children)
for child, char in zip(children, chars):
# Given a guess for the nth ugly number, we can count the ugly numbers <= guess. result[child] = char
# Count all the numbers divisible by a, b and c. Subtract the numbers divisible by the lowest common multiple of
# each pair from a, b and c. Add back numbers divisible by the lowest common multiple of a, b and c. return "".join(result)
# Binary search the range of possible results.
# Time - O(log n)
# Space - O(1)
# python_1001_to_2000/1203_Sort_Items_by_Groups_Respecting_Dependencies.py - h
class Solution(object):
def nthUglyNumber(self, n, a, b, c): _author_ = 'jake'
""" _project_ = 'leetcode'
:type n: int
:type a: int # https://leetcode.com/problems/sort-items-by-groups-respecting-dependencies/
:type b: int # There are n items each belonging to zero or one of m groups where group[i] is the group that the i-th item belongs
:type c: int # to and it's equal to -1 if the i-th item belongs to no group.
:rtype: int # The items and the groups are zero indexed.
""" # A group can have no item belonging to it.
def gcd(x, y): # x >= y # Return a sorted list of the items such that:
while y != 0: # The items that belong to the same group are next to each other in the sorted list.
x, y = y, x % y # There are some relations between these items where beforeItems[i] is a list containing all the items that
return x # should come before the i-th item in the sorted array (to the left of the i-th item).
# Return any solution if there is more than one solution and return an empty list if there is no solution.
def lcm(x, y):
return (x * y) // gcd(x, y) # Topologically sort the items in each group and topologically sort the groups.
# Topologically sort by repeatedly adding items with nothing before to the result. Then reducing the count of items
a, b, c = sorted([a, b, c]) # before any items the must go after the added item, and adding it to the set of items with nothing before if the
ab, ac, bc = lcm(b, a), lcm(c, a), lcm(c, b) # count is zero.
abc = lcm(bc, a) # Time - O(m + n) for m beforeItems and n items
# Space - O(m + n)
def ugly_less_or_equal(x): # count ugly <= x
result = (x // a) + (x // b) + (x // c) from collections import defaultdict
result -= (x // ab) + (x // ac) + (x // bc)
result += x // abc class Solution(object):
return result def sortItems(self, n, m, group, beforeItems):
"""
lower, upper = 1, 2 * 10 ** 9 :type n: int
:type m: int
while lower < upper: :type group: List[int]
mid = (lower + upper) // 2 :type beforeItems: List[List[int]]
if ugly_less_or_equal(mid) >= n: # mid or lower is potentially correct :rtype: List[int]
upper = mid """
else: # result must be above lower
lower = mid + 1 def top_sort(map_to_after, before_count):
no_before = {i for i, count in before_count.items() if count == 0} # items with nothing before
return lower result = []
while no_before:
i = no_before.pop()
result.append(i)
# python_1001_to_2000/1202_Smallest_String_With_Swaps.py - m for after in map_to_after[i]:
before_count[after] -= 1
_author_ = 'jake' if before_count[after] == 0:
_project_ = 'leetcode' no_before.add(after)

# https://leetcode.com/problems/smallest-string-with-swaps/ return result if len(result) == len(before_count) else []


# You are given a string s, and an array of pairs of indices in the string pairs where pairs[i] = [a, b]
# indicates 2 indices(0-indexed) of the string. for i in range(n):
# You can swap the characters at any pair of indices in the given pairs any number of times. if group[i] == -1: # make a new group for this item only
# Return the lexicographically smallest string that s can be changed to after using the swaps. group[i] = m
m += 1
# Union-find to connect the sets of connected indices.
# Then create a mapping of each ultimate parent to all children (including the parent itself). group_items = defaultdict(set)
# For each connected group, place the sorted the characters in the sorted indices. for item, gp in enumerate(group):
# Time - O(m log* m + n log n) for string length n and m pairs group_items[gp].add(item)
# Space - O(n)
between_groups_after = defaultdict(set) # group to set of groups before group
from collections import defaultdict groups_before_count = {gp: 0 for gp in range(m)} # group to count of groups before
ordered_groups = {} # map group to list of sorted items
class Solution(object):
def smallestStringWithSwaps(self, s, pairs): for gp, items in group_items.items():
""" within_group_after = defaultdict(set) # item to set of items after item
:type s: str items_before_count = {item: 0 for item in items} # item to count of items before
:type pairs: List[List[int]]
:rtype: str for item in items:
""" for before_item in beforeItems[item]:
n = len(s) if before_item in items:
parents = {i: i for i in range(n)} within_group_after[before_item].add(item)
items_before_count[item] += 1 # python_1001_to_2000/1209_Remove_All_Adjacent_Duplicates_in_String_II.py - m
else:
if group[item] not in between_groups_after[group[before_item]]: # do not double count _author_ = 'jake'
groups_before_count[group[item]] += 1 _project_ = 'leetcode'
between_groups_after[group[before_item]].add(group[item])
# https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/
ordered_items = top_sort(within_group_after, items_before_count) # Given a string s, a k duplicate removal consists of choosing k adjacent and equal letters from s
if not ordered_items: # and removing them causing the left and the right side of the deleted substring to concatenate together.
return [] # We repeatedly make k duplicate removals on s until we no longer can.
ordered_groups[gp] = ordered_items # Return the final string after all such duplicate removals have been made.
# It is guaranteed that the answer is unique.
group_ordering = top_sort(between_groups_after, groups_before_count)
if not group_ordering: # Maintain a stack of [char, count of identical chars in sequence].
return [] # Iterate over s, updating the count of the top of stack if it's the same as the current char.
# If k chars are in sequence, pop them off the stack.
result = [] # If the current char is different from the top of stack, add the new char to stack with count of 1.
for gp in group_ordering: # Time - O(n)
if gp in ordered_groups: # ignore group with no items # Space - O(n)
result += ordered_groups[gp]
return result class Solution(object):
def removeDuplicates(self, s, k):
"""
:type s: str
# python_1001_to_2000/1207_Unique_Number_of_Occurrences.py :type k: int
:rtype: str
_author_ = 'jake' """
_project_ = 'leetcode' stack = [] # stack of [char, sequence length]

# 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)

class Solution(object): class Solution(object):


def equalSubstring(self, s, t, maxCost): def minimumMoves(self, grid):
""" """
:type s: str :type grid: List[List[int]]
:type t: str :rtype: int
:type maxCost: int """
:rtype: int rows, cols = len(grid), len(grid[0])
""" moves = 0
start = 0 seen = set()
cost, result = 0, 0 frontier = {(0, 1, True)} # (row of head, col of head, is horizontal)

for i, (c1, c2) in enumerate(zip(s, t)): while frontier:


cost += abs(ord(c1) - ord(c2)) if (rows - 1, cols - 1, True) in frontier:
while cost > maxCost: return moves
cost -= abs(ord(s[start]) - ord(t[start]))
start += 1 new_frontier = set()
result = max(result, i - start + 1) for r, c, horizontal in frontier:
if (r, c, horizontal) in seen:
return result continue

if horizontal and c != cols - 1 and grid[r][c + 1] == 0:


new_frontier.add((r, c + 1, True))

if not horizontal and r != rows - 1 and grid[r + 1][c] == 0:


new_frontier.add((r + 1, c, False))
# python_1001_to_2000/1215_Stepping_Numbers.py - m
if horizontal and r != rows - 1 and grid[r + 1][c] == 0 and grid[r + 1][c - 1] == 0:
new_frontier.add((r + 1, c, True)) # down _author_ = 'jake'
new_frontier.add((r + 1, c - 1, False)) # clockwise rotation _project_ = 'leetcode'

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)]

def find(node): if s[start] == s[end]:


if not node: result = helper(start + 1, end - 1)
return False else:
if target - node.val in seen: result = 1 + min(helper(start + 1, end), helper(start, end - 1))
return True
return find(node.left) or find(node.right) memo[(start, end)] = result
return result
return find(root2)
return helper(0, len(s) - 1) <= k
# Time - O(m**2 * n**2)
# Space - O(mn)

# python_1001_to_2000/1217_Play_with_Chips.py class Solution(object):


def getMaximumGold(self, grid):
_author_ = 'jake' """
_project_ = 'leetcode' :type grid: List[List[int]]
:rtype: int
# https://leetcode.com/problems/play-with-chips/ """
# There are some chips, and the i-th chip is at position chips[i]. rows, cols = len(grid), len(grid[0])
# You can perform any of the two following types of moves any number of times (possibly zero) on any chip: neighbours = [[1, 0], [0, 1], [-1, 0], [0, -1]]
# Move the i-th chip by 2 units to the left or to the right with a cost of 0.
# Move the i-th chip by 1 unit to the left or to the right with a cost of 1. def helper(r, c):
# There can be two or more chips at the same position initially. if r < 0 or r >= rows or c < 0 or c >= cols:
# Return the minimum cost needed to move all the chips to the same position (any position). return 0
if grid[r][c] == 0:
# Count the number of chips at odd and even positions. return 0
# All chips within each group can be moved to the same position at no cost.
# Move the smaller group to the larger group, costing the size of the smaller group. gold = best = grid[r][c]
# Time - O(n) grid[r][c] = 0 # delete gold from visited cell
# Space - O(1) for dr, dc in neighbours:
best = max(best, gold + helper(r + dr, c + dc))
class Solution(object):
def minCostToMoveChips(self, chips): grid[r][c] = gold # reset the gold in this cell
""" return best
:type chips: List[int]
:rtype: int result = 0
""" for r in range(rows):
evens, odds = 0, 0 for c in range(cols):
for chip in chips: result = max(result, helper(r, c))
if chip % 2 == 0:
evens += 1 return result
else:
odds += 1

return min(evens, odds) # python_1001_to_2000/1220_Count_Vowels_Permutation.py - h

_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

return sum(counts.values()) % (10 ** 9 + 7)

# python_1001_to_2000/1219_Path_with_Maximum_Gold.py - m

_author_ = 'jake' # python_1001_to_2000/1221_Split_a_String_in_Balanced_Strings.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/path-with-maximum-gold/ _project_ = 'leetcode'
# In a gold mine grid of size m * n,
# each cell in this mine has an integer representing the amount of gold in that cell, 0 if it is empty. # https://leetcode.com/problems/split-a-string-in-balanced-strings/
# Return the maximum amount of gold you can collect under the conditions: # Balanced strings are those who have equal quantity of 'L' and 'R' characters.
# Every time you are located in a cell you will collect all the gold in that cell. # Given a balanced string s split it in the maximum amount of balanced strings.
# From your position you can walk one step to the left, right, up or down. # Return the maximum amount of splitted balanced strings.
# You can't visit the same cell more than once.
# Never visit a cell with 0 gold. # Keep a running net balance of "L" - "R" when iterating over s.
# You can start and stop collecting gold from any position in the grid that has some gold. # Update the result whenever the balance is zero.
# Time - O(n)
# For each starting position, perform depth-first search to find the maximum gold. # Space - O(1)
# DFS returns zero if a cell is out of the grid or has no gold.
# Else take the gold, set the gold in the cell to zero and recurse for all neighbours. class Solution(object):
# Return the best result from all 4 neighbours and reset the gold in the visited cell. def balancedStringSplit(self, s):

""" 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

return result _author_ = 'jake'


_project_ = 'leetcode'

# 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

while i < m and j < n: while left < right:


# earliest finish - latest start mid = (left + right + 1) // 2
latest_start = max(slots1[i][0], slots2[j][0]) if can_split(mid):
overlap = min(slots1[i][1], slots2[j][1]) - latest_start left = mid
if overlap >= duration: else:
return [latest_start, latest_start + duration] right = mid - 1

if slots1[i][0] <= slots2[j][0]: return left


i += 1
else:
j += 1
# python_1001_to_2000/1232_Check_If_It_Is_a_Straight_Line.py
return []
_author_ = 'jake'
_project_ = 'leetcode'

# 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.

# Time - O(n) class Solution(object):


# Space - O(1) def balancedString(self, s):
"""
class Solution(object): :type s: str
def checkStraightLine(self, coordinates): :rtype: int
""" """
:type coordinates: List[List[int]] balance = len(s) // 4
:rtype: bool excess = {}
""" for c, count in Counter(s).items():
if len(coordinates) < 3: # 1 or 2 points are always on a line. if count - balance > 0:
return True excess[c] = count - balance
if not excess:
x_diff = coordinates[1][0] - coordinates[0][0] # keep diffs since gradient is a float return 0
y_diff = coordinates[1][1] - coordinates[0][1]
start = 0
for x, y in coordinates[2:]: result = len(s)
dx = x - coordinates[0][0]
dy = y - coordinates[0][1] for end, c in enumerate(s):
if x_diff * dy != y_diff * dx: if c in excess:
return False excess[c] -= 1
while all(v <= 0 for v in excess.values()):
return True result = min(result, end - start + 1)
if s[start] in excess:
excess[s[start]] += 1
start += 1
# python_1001_to_2000/1233_Remove_Sub-Folders_from the_Filesystem.py - m
return result
_author_ = 'jake'
_project_ = 'leetcode'

# 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/replace-the-substring-for-balanced-string/ _author_ = 'jake'


# You are given a string containing only 4 kinds of characters 'Q', 'W', 'E' and 'R'. _project_ = 'leetcode'
# A string is said to be balanced if each of its characters appears n/4 times where n is the length of the string.
# Return the minimum length of the substring that can be replaced with any other string of the same # https://leetcode.com/problems/web-crawler/
# length to make the original string s balanced. # Given a url startUrl and an interface HtmlParser,
# Return 0 if the string is already balanced. # implement a web crawler to crawl all links that are under the same hostname as startUrl.
# Return all urls obtained by your web crawler in any order.
# For each char of s, count the excess chars above the balanced expectation (n / 4). # Your crawler should:
# Then iterate over s. # Start from the page: startUrl
# If a char has an excess count, decrement the excess count since it is now in the replacement substring. # Call HtmlParser.getUrls(url) to get all urls from a webpage of given url.
# If/while there are no excess chars, update the result, move the start of the subtring forwards and increment any # Do not crawl the same link twice.
# excess chars that are no longer in the substring. # Explore only the links that are under the same hostname as startUrl.
# Time - O(n), since to check all values of excess is O(1) because it has at most 26 elements.
# Space - O(1) # Find the hostname from startUrl.
# Depth-first search the web by checking is a url has not been seen and had the correct hostname.
from collections import Counter # If so, add it to the result and recurse for all links.
# Time - O(m + n) for m links and n urls.
# Space - O(m + n) # https://leetcode.com/problems/circular-permutation-in-binary-representation/
# Given 2 integers n and start. Your task is return any permutation p of (0,1,2.....,2^n -1) such that :
class Solution(object): # p[0] = start
def crawl(self, startUrl, htmlParser): # p[i] and p[i+1] differ by only one bit in their binary representation.
""" # p[0] and p[2^n -1] must also differ by only one bit in their binary representation.
:type startUrl: str
:type htmlParser: HtmlParser # Find a permutation starting from 0, then move the part from start to the front.
:rtype: List[str] # To find the permutation for n, start with the permutation for n - 1.
""" # Append to the n - 1 permutation the elements in reverse order with an additional first bit set.
PREFIX = "http://" # Time - O(2 ** n)
n = len(PREFIX) # Space - O(2 ** n)

def get_host_and_path(url): class Solution(object):


suffix = url[n:] def circularPermutation(self, n, start):
if "/" not in suffix: """
return [suffix, ""] :type n: int
return suffix.split("/", 1) :type start: int
:rtype: List[int]
start_host, _ = get_host_and_path(startUrl) """
results = set() def helper(i):
if i == 1:
def dfs(url): return [0, 1]
if url in results: temp = helper(i - 1)
return power = 2 ** (i - 1)
return temp + [power + t for t in temp[::-1]]
host, path = get_host_and_path(url)
if host != start_host: perms = helper(n)
return i = perms.index(start)
return perms[i:] + perms[:i]
results.add(url)
for next_url in htmlParser.getUrls(url):
dfs(next_url)
# python_1001_to_2000/1239_Maximum_Length_of_a_Concatenated_String_with_Unique_Characters.py - m
dfs(startUrl)
return list(results) _author_ = 'jake'
_project_ = 'leetcode'

# 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

_author_ = 'jake' # python_1001_to_2000/1245_Tree_Diameter.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/array-transformation/ _project_ = 'leetcode'
# Given an initial array arr, every day you produce a new array using the array of the previous day.
# On the i-th day, you do the following operations on the array of day i-1 to produce the array of day i: # https://leetcode.com/problems/tree-diameter/
# If an element is smaller than both its left neighbor and its right neighbor, then this element is incremented. # Given an undirected tree, return its diameter: the number of edges in a longest path in that tree.
# If an element is bigger than both its left neighbor and its right neighbor, then this element is decremented. # The tree is given as an array of edges where edges[i] = [u, v] is a bidirectional edge between nodes u and v.
# The first and last elements never change. # Each node has labels in the set {0, 1, ..., edges.length}.
# After some days, the array does not change. Return that final array.
# Repeatedly remove leaves (nodes with one neighbour) from the tree to find the centroid leaf or leaves.
# While the previous array was modified, decrement any peaks and increment any troughs. # For each leaf removed, add new leaves if the neighbour then has only one neighbour.
# If any element was changed, update the flag so we check again until nothing is changed. # Repeat until no leaves remain (even result) or a final pair of leaves (odd result).
# Time - O(mn) for max value m of n elements # Time - O(m + n)
# Space - O(n) # Space - O(m + n)

class Solution(object): from collections import defaultdict


def transformArray(self, arr):
""" class Solution(object):
:type arr: List[int] def treeDiameter(self, edges):
:rtype: List[int] """
""" :type edges: List[List[int]]
changed = True # flag, true so we enter the while loop at least once :rtype: int
"""
while changed: node_to_nbors = defaultdict(set)
new_arr = arr[:] for a, b in edges:
changed = False # reset node_to_nbors[a].add(b)
for i in range(1, len(arr) - 1): node_to_nbors[b].add(a)
if arr[i] < arr[i - 1] and arr[i] < arr[i + 1]:
new_arr[i] += 1 leaves = {node for node, nbors in node_to_nbors.items() if len(nbors) == 1}
changed = True
elif arr[i] > arr[i - 1] and arr[i] > arr[i + 1]: result = 0
new_arr[i] -= 1 while len(leaves) > 1:
changed = True new_leaves = set()
for leaf in leaves:
arr = new_arr nbor = node_to_nbors[leaf].pop()
if nbor in leaves: # node, nbor are final pair remaining
return arr result += 1
break

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)

for k in range(i, j - 1): # python_1001_to_2000/1249_Minimum_Remove_to_Make_Valid_Parentheses.py - m


if arr[j] == arr[k]:
# cost of dp(k + 1, j - 1) is the same as dp(k, j) _author_ = 'jake'
result = min(result, dp(i, k - 1) + dp(k + 1, j - 1)) _project_ = 'leetcode'

memo[(i, j)] = result # https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/


return result # Given a string s of '(' , ')' and lowercase English characters.
# Your task is to remove the minimum number of parentheses ( '(' or ')',
return dp(0, len(arr) - 1) # in any positions ) so that the resulting parentheses string is valid and return any valid string.
# Formally, a parentheses string is valid if and only if:
# It is the empty string, contains only lowercase characters, or
# It can be written as AB (A concatenated with B), where A and B are valid strings, or
# python_1001_to_2000/1247_Minimum_Swaps_to_Make_Strings_Equal.py - m # It can be written as (A), where A is a valid string.

_author_ = 'jake' # Iterate along s, adding opening brackets to a list.


_project_ = 'leetcode' # If we see a closing bracket without any opening bracket, it must be removed.
# If we see a closing bracket with unmatched opening brackets, discard the matching opening bracket.
# https://leetcode.com/problems/minimum-swaps-to-make-strings-equal/ # Finally, discard any unmatched opening brackets before reconstructing s without discarded indices.
# You are given two strings s1 and s2 of equal length consisting of letters "x" and "y" only. # Time - O(n)
# Your task is to make these two strings equal to each other. # Space - O(n)
# You can swap any two characters that belong to different strings, which means: swap s1[i] and s2[j].
# Return the minimum number of swaps required to make s1 and s2 equal, or return -1 if it is impossible to do so. class Solution(object):
def minRemoveToMakeValid(self, s):
# Iterate along the strings together, flagging when s1 contains an additional x or y compared to s2. """
# If we find an x in s1 and there is already an additional x, we can swap woth an additional y in s2. :type s: str
# Similarly if there is a y in s1 and already an additional y. :rtype: str
# Fail if only x or y has an excess at the end, else perfoma a final double swap. """
# Time - O(n) opening = [] # indices of opening brackets
# Space - O(1) removals = set() # indices of removed brackets

class Solution(object): for i, c in enumerate(s):


def minimumSwap(self, s1, s2): if c == "(":
""" opening.append(i)
:type s1: str elif c == ")":
:type s2: str if not opening: # no matching opening
:rtype: int removals.add(i)
""" else: # match with opening
s1_excess_x, s1_excess_y = False, False opening.pop()
result = 0
removals.update(opening) # add all open but not closed brackets
for c1, c2 in zip(s1, s2): return "".join(c for i, c in enumerate(s) if i not in removals)
if c1 == c2:
continue

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]

:rtype: bool for i, col in enumerate(colsum):


"""
def calc_gcd(a, b): if col == 2:
while a > 0: lower -= 1
a, b = b % a, a upper -= 1
return b upper_row[i] = lower_row[i] = 1
elif col == 1 and upper > lower: # set 1 in row with greatest required
gcd = nums[0] upper -= 1
upper_row[i] = 1
for num in nums: elif col == 1 and upper <= lower:
gcd = calc_gcd(num, gcd) lower -= 1
if gcd == 1: lower_row[i] = 1
return True
if upper < 0 or lower < 0:
return False return []

if upper > 0 or lower > 0:


return []
# python_1001_to_2000/1252_Cells_with_Odd_Values_in_a_Matrix.py return [upper_row, lower_row]

_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

for c, count in word_counts.items():


char_counts[c] -= count # decrement counts before recurse
use = word_scores[i] + helper(i + 1) # python_1001_to_2000/1258_Synonymous_Sentences.py - m
for c, count in word_counts.items():
char_counts[c] += count # increment counts after recurse _author_ = 'jake'
_project_ = 'leetcode'
return max(use, not_use)
# https://leetcode.com/problems/synonymous-sentences/
return helper(0) # Given a list of pairs of equivalent words synonyms and a sentence text,
# return all possible synonymous sentences sorted lexicographically.

# Group synonyms together with union-find.


# python_1001_to_2000/1256_Encode_Number.py - m # Each synonym is mapped to a parent. The ultimate parent is a group exemplar.
# For each pair of synonymous words, find their parents and join their parent's groups.
_author_ = 'jake' # Then map each ultimate parent to all synonyms.
_project_ = 'leetcode' # For each word in the text, extend each previous result with each synonym.
# Alternatively, breadth-first search the graph of synonyms.
# https://leetcode.com/problems/encode-number/ # Time - O(s log* m + n**2 * k**n) where s log* m is for s synonym pairs and m synonym words and
# Given a non-negative integer num, Return its encoding string. # n**2 * k**n is for n words in text each with k synonyms.
# The encoding is done by converting the integer to a string using a secret function # Space - O(s + n * k**n)
# that you should deduce from the following table:
# num encoding from collections import defaultdict
# 0 ""
# 1 "0" class Solution(object):
# 2 "1" def generateSentences(self, synonyms, text):
# 3 "00" """
# 4 "01" :type synonyms: List[List[str]]
# 5 "10" :type text: str
# 6 "11" :rtype: List[str]
# 7 "000" """
parents = {} # map node to parent (map to self if no parent)
# Encoding is the binary representation of num + 1 without the first digit.
# Time - O(log n) def find(s): # find ultimate parent (could also collapse)
# Space - O(log n) if s not in parents:
parents[s] = s
class Solution(object): while parents[s] != s:
def encode(self, num): s = parents[s]
""" return s
:type num: int
:rtype: str for a, b in synonyms: # join groups of ultimate parents
""" parents[find(a)] = find(b)
return bin(num + 1)[3:]
parent_to_synonyms = defaultdict(list) # map each parent to all synonyms
for word in parents:
parent_to_synonyms[find(word)].append(word)
# python_1001_to_2000/1257_Smallest_Common_Region.py - m
results = [[""]]
_author_ = 'jake'
_project_ = 'leetcode' for word in text.split():
new_results = []
# https://leetcode.com/problems/smallest-common-region/ synonyms = parent_to_synonyms.get(find(word), [word]) # default to word of no synonyms
# You are given some lists of regions where the first region of each list includes all other regions in that list. for synonym in synonyms:
# Naturally, if a region X contains another region Y then X is bigger than Y. for result in results:
# Also by definition a region X contains itself. new_results.append(result[:] + [synonym])
# Given two regions region1, region2, find out the smallest region that contains both of them. results = new_results
# If you are given regions r1, r2 and r3 such that r1 includes r3,
# it is guaranteed there is no r2 such that r2 includes r3. return [" ".join(result[1:]) for result in sorted(results)] # sort lexicographically
# It's guaranteed the smallest region exists.

# 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.

_author_ = 'jake' # Then lookup each value.


_project_ = 'leetcode' # Time - O(n) for __init__ and O(1) for find
# Space - O(n)
# https://leetcode.com/problems/handshakes-that-dont-cross/
# You are given an even number of people num_people that stand around a circle and class FindElements(object):
# each person shakes hands with someone else, so that there are num_people / 2 handshakes total. def __init__(self, root):
# Return the number of ways these handshakes could occur such that none of the handshakes cross. """
# Since this number could be very big, return the answer mod 10^9 + 7 :type root: TreeNode
"""
# Dynamic programming. self.elements = set()
# For each even number of people, choose one arbitrary person and handshake with each other person so there is an
# even number of people on both sides of the handshake pair. def helper(node, val): # explore tree from node with correct value val
# Sum the results for each other person, which is the product of the results for the two groups on both sides if not node:
# of the handshaking pair. return
# Time - O(n**2) self.elements.add(val)
# Space - O(n) helper(node.left, 2 * val + 1)
helper(node.right, 2 * val + 2)
class Solution(object):
def numberOfWays(self, num_people): helper(root, 0)
"""
:type num_people: int def find(self, target):
:rtype: int """
""" :type target: int
dp = [1] # dp[i] is the result for i // 2 people :rtype: bool
"""
for people in range(2, num_people + 1, 2): return target in self.elements
result = 0
for left in range(0, people - 1, 2): # number of people on the left of the handshake pair
result += dp[left // 2] * dp[(people - left - 2) // 2] # python_1001_to_2000/1262_Greatest_Sum_Divisible_by_Three.py - m
dp.append(result)
_author_ = 'jake'
return dp[-1] % (10 ** 9 + 7) _project_ = 'leetcode'

# 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.

_author_ = 'jake' # If the sum of elements is divisible by 3, return that sum.


_project_ = 'leetcode' # Else make sorted lists of the elements divisible by 1 and 2.
# If the remainder of the sum after dividing by 3 is 1, we can subtract the smallest element divisible by 1,
# https://leetcode.com/problems/shift-2d-grid/ # or subtract the 2 smallest elements divisible by 2.
# Given a 2D grid of size n * m and an integer k. You need to shift the grid k times. # If the remainder of the sum after dividing by 3 is 2, we can subtract the smallest element divisible by 2,
# In one shift operation: # or subtract the 2 smallest elements divisible by 1.
# Element at grid[i][j] becomes at grid[i][j + 1]. # Return the maximum candidate.
# Element at grid[i][m - 1] becomes at grid[i + 1][0]. # Time - O(n log n)
# Element at grid[n - 1][m - 1] becomes at grid[0][0]. # Space - O(n)
# Return the 2D grid after applying shift operation k times.
class Solution(object):
# Build a new array by iterating over the indices of the existing array. def maxSumDivThree(self, nums):
# Indices are from 0 to rows * cols - 1. """
# For each index, find the shifted index - k modulo the number of indices. :type nums: List[int]
# Convert that index to a row and column to find the value to append to the new array. :rtype: int
# Time - O(mn) """
# Space - O(mn) total = sum(nums)
rem = total % 3
class Solution(object):
def shiftGrid(self, grid, k): if rem == 0:
""" return total
:type grid: List[List[int]]
:type k: int rem_1 = [num for num in nums if num % 3 == 1]
:rtype: List[List[int]] rem_2 = [num for num in nums if num % 3 == 2]
""" rem_1.sort()
rows, cols = len(grid), len(grid[0]) rem_2.sort()
n = rows * cols
candidates = [0] # default 0
result = [[]] if rem == 1:
for i in range(n): # iterate over all indices of grid if rem_1:
if len(result[-1]) == cols: # make a new empty row candidates.append(total - rem_1[0])
result.append([]) if len(rem_2) >= 2:
prev = (i - k) % n # index of element to move here candidates.append(total - sum(rem_2[:2]))
r, c = divmod(prev, cols) # convert index in n to row and col elif rem == 2:
result[-1].append(grid[r][c]) if rem_2:
candidates.append(total - rem_2[0])
return result if len(rem_1) >= 2:
candidates.append(total - sum(rem_1[:2]))

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

# https://leetcode.com/problems/find-elements-in-a-contaminated-binary-tree/ _author_ = 'jake'


# Given a binary tree with the following rules: _project_ = 'leetcode'
# root.val == 0
# If treeNode.val == x and treeNode.left != null, then treeNode.left.val == 2 * x + 1 # https://leetcode.com/problems/minimum-moves-to-move-a-box-to-their-target-location/
# If treeNode.val == x and treeNode.right != null, then treeNode.right.val == 2 * x + 2 # Storekeeper is a game in which the player pushes boxes around in a warehouse trying to get them to target locations.
# Now the binary tree is contaminated, which means all treeNode.val have been changed to -1. # The game is represented by a grid of size n*m, where each element is a wall, floor, or a box.
# You need to first recover the binary tree and then implement the FindElements class: # Your task is move the box 'B' to the target position 'T' under the following rules:
# FindElements(TreeNode* root) Initializes the object with a canotaminated binary tree, you need to recover it first. # Player is represented by character 'S' and can move up, down, left, right in the grid if it is a floor (empty cell).
# bool find(int target) Return if the target value exists in the recovered binary tree. # Floor is represented by character '.' that means free cell to walk.
# Wall is represented by character '#' that means obstacle (impossible to walk there).
# Recursively explore the tree by depth-first search, adding all values to a set. # There is only one box 'B' and one target cell 'T' in the grid.
# The box can be moved to an adjacent free cell by standing next to the box and # which is O(n**2) time but O(1) space.
# then moving in the direction of the box. This is a push. # Alternatively, divide the list into intervals of length sqrt(n).
# The player cannot walk through the box. # Make a list of nodes at the start of each interval.
# Return the minimum number of pushes to move the box to the target. # For the start interval nodes in reverse, find all nodes to end interval then print in reverse.
# If there is no way to reach the target, return -1. # This is O(n) time and O(sqrt(n)) space.

# A-star search. class Solution(object):


# Maintain a heap of states where a state consists of box and person locations together. def printLinkedListInReverse(self, head):
# Heap is ordered by the number of moves so far to reach a state + heuristic estimate of remaining moves. """
# Heuristic (an under-estimate of the remaining moves required) is the Manhattan distance between box and target. :type head: ImmutableListNode
# Repeatedly pop the state with the lowest heuristic + previous moves off the heap. :rtype: None
# Attempt to move the person in all 4 directions. """
# If any direction moves the person to the box, check if the box can move to the next position in the grid. if not head.getNext():
# Time - O(log(mn) * m**2 * n**2) since there are m**2 * n**2 states. head.printValue()
# Space - O(m**2 * n**2) return

import heapq self.printLinkedListInReverse(head.getNext())


head.printValue()
class Solution(object):
def minPushBox(self, grid): class Solution2(object):
""" def printLinkedListInReverse(self, head):
:type grid: List[List[str]] node = head
:rtype: int length = 0
""" while node:
rows, cols = len(grid), len(grid[0]) length += 1
for r in range(rows): node = node.getNext()
for c in range(cols):
if grid[r][c] == "T": for i in range(length - 1, -1, -1): # get each value in reverse order
target = (r, c) node = head
if grid[r][c] == "B": for _ in range(i):
start_box = (r, c) node = node.getNext()
if grid[r][c] == "S": node.printValue()
start_person = (r, c)
class Solution3(object):
def heuristic(box): def printLinkedListInReverse(self, head):
return abs(target[0] - box[0]) + abs(target[1] - box[1]) node = head
length = 0
def out_bounds(location): # return whether the location is in the grid and not a wall while node:
r, c = location length += 1
if r < 0 or r >= rows: node = node.getNext()
return True
if c < 0 or c >= cols: interval = int(length ** 0.5)
return True
return grid[r][c] == "#" node = head
counter = 0
heap = [[heuristic(start_box), 0, start_person, start_box]] partition_nodes = [] # nodes at start of each interval
visited = set() while node:
if counter % interval == 0:
while heap: partition_nodes.append(node)
_, moves, person, box = heapq.heappop(heap) counter += 1
if box == target: node = node.getNext()
return moves
if (person, box) in visited: # do not visit same state again for i in range(len(partition_nodes) - 1, -1, -1):
continue node = partition_nodes[i]
visited.add((person, box)) interval_end = partition_nodes[i + 1] if i != len(partition_nodes) - 1 else None
interval_nodes = []
for dr, dc in [[0, 1], [1, 0], [-1, 0], [0, -1]]: while node != interval_end:
new_person = (person[0] + dr, person[1] + dc) interval_nodes.append(node)
if out_bounds(new_person): node = node.getNext()
continue
for print_node in interval_nodes[::-1]:
if new_person == box: print_node.printValue()
new_box = (box[0] + dr, box[1] + dc)
if out_bounds(new_box):
continue # python_1001_to_2000/1266_Minimum_Time_Visiting_All_Points.py
heapq.heappush(heap, [heuristic(new_box) + moves + 1, moves + 1, new_person, new_box])
else: _author_ = 'jake'
heapq.heappush(heap, [heuristic(box) + moves, moves, new_person, box]) # box remains same _project_ = 'leetcode'

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:]:

dx, dy = abs(x1 - x2), abs(y1 - y2) products.sort()


time += max(dx, dy) results = []
x1, y1 = x2, y2 # update current point
for length in range(1, len(searchWord) + 1):
return time prefix = searchWord[:length]
i = bisect.bisect_left(products, prefix)
results.append([p for p in products[i: i + 3] if p[:length] == prefix])

# python_1001_to_2000/1267_Count_Servers_that_Communicate.py - m return results

_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

for r in range(rows): return i_to_count[0] % (10 ** 9 + 7)


for c in range(cols):
if grid[r][c] == 1:
row_servers[r] += 1
cols_servers[c] += 1 # python_1001_to_2000/1271_Hexspeak.py
servers.add((r, c))
_author_ = 'jake'
return sum(1 for r, c in servers if row_servers[r] > 1 or cols_servers[c] > 1) _project_ = 'leetcode'

# 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

_author_ = 'jake' # python_1001_to_2000/1274_Number_of_Ships_in_a_Rectangle.py - h


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/remove-interval/ _project_ = 'leetcode'
# Given a sorted list of disjoint intervals, each interval intervals[i] = [a, b]
# represents the set of real numbers x such that a <= x < b. # https://leetcode.com/problems/number-of-ships-in-a-rectangle/
# We remove the intersections between any interval in intervals and the interval toBeRemoved. # This problem is an interactive problem.
# Return a sorted list of intervals after all such removals. # On the sea represented by a cartesian plane,
# each ship is located at an integer point, and each integer point may contain at most 1 ship.
# Iterate over intervals. # You have a function Sea.hasShips(topRight, bottomLeft) which takes two points as arguments
# If remove_start is after the interval end, there is no overlap so append the interval to the result. # and returns true if and only if there is at least one ship in the rectangle represented by the two points,
# If remove_end is before the interval start, there is no overlap and all other intervals will not overlap. # including on the boundary.
# Else if the start or end parts of the interval do not overlap, append them (possibly both) to the result. # Given two points, which are the top right and bottom left corners of a rectangle,
# Time - O(n) # return the number of ships present in that rectangle.
# Space - O(n) # It is guaranteed that there are at most 10 ships in that rectangle.
# Submissions making more than 400 calls to hasShips will be judged Wrong Answer.
class Solution(object): # Also, any solutions that attempt to circumvent the judge will result in disqualification.
def removeInterval(self, intervals, toBeRemoved):
""" # Split any rectangle with either non-zero side length containing a ship into 2 sections along the longest axis.
:type intervals: List[List[int]] # Repeat until rectangle is empty or is a single point with a ship.
:type toBeRemoved: List[int] # Time - O(mn), may split to each point of initial rectangle.
:rtype: List[List[int]] # Space - O(mn)
"""
remove_start, remove_end = toBeRemoved class Solution(object):
result = [] def countShips(self, sea, topRight, bottomLeft):
"""
for i, (start, end) in enumerate(intervals): :type sea: Sea
if remove_start >= end: :type topRight: Point
result.append([start, end]) :type bottomLeft: Point
elif remove_end <= start: # all remaining intervals will not overlap :rtype: integer
result += intervals[i:] """
break def counter(top_right, bottom_left):
else: if not sea.hasShips(top_right, bottom_left):
if remove_start > start: return 0 # no need to keep exploring
result.append([start, remove_start]) x_dist = top_right.x - bottom_left.x
if remove_end < end: y_dist = top_right.y - bottom_left.y
result.append([remove_end, end]) if x_dist == 0 and y_dist == 0: # rectangle is a point containing a ship
return 1
return result
if x_dist > y_dist: # split along x
x_mid = bottom_left.x + x_dist // 2
return counter(Point(x_mid, top_right.y), bottom_left) + counter(top_right,
# python_1001_to_2000/1273_Delete_Tree_Nodes.py - m Point(x_mid + 1, bottom_left.y))
else: # split along y
_author_ = 'jake' y_mid = bottom_left.y + y_dist // 2
_project_ = 'leetcode' return counter(Point(top_right.x, y_mid), bottom_left) + counter(top_right,
Point(bottom_left.x, y_mid + 1))
# https://leetcode.com/problems/delete-tree-nodes/
# A tree rooted at node 0 is given as follows: return counter(topRight, bottomLeft)
# The number of nodes is nodes;
# The value of the i-th node is value[i];
# The parent of the i-th node is parent[i].
# Remove every subtree whose sum of values of nodes is zero.
# After doing so, return the number of nodes remaining in the tree. # python_1001_to_2000/1275_Find_Winner_on_a_Tic_Tac_Toe_Game.py

# 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)]

up_diag, down_diag = 0, 0 # sums of moves along diagonals


_author_ = 'jake'
for r, c in moves: # add move to sums for each line _project_ = 'leetcode'
row_sums[r] += player
col_sums[c] += player # https://leetcode.com/problems/palindrome-partitioning-iii/
if r == c: # You are given a string s containing lowercase letters and an integer k. You need to :
up_diag += player # First, change some characters of s to other lowercase English letters.
if r + c == 2: # Then divide s into k non-empty disjoint substrings such that each substring is palindrome.
down_diag += player # Return the minimal number of characters that you need to change to divide the string.

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

jumbo = (tomatoSlices - 2 * cheeseSlices) // 2 return helper(0, k)


small = cheeseSlices - jumbo
return [jumbo, small]

# python_1001_to_2000/1281_Subtract_the_Product_and_Sum_of_Digits_of_an_Integer.py

# python_1001_to_2000/1277_Count_Square_Submatrices_with_All_Ones.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/subtract-the-product-and-sum-of-digits-of-an-integer/
# Given an integer number n, return the difference between the product of its digits and the sum of its digits.
# https://leetcode.com/problems/count-square-submatrices-with-all-ones/
# Given a m * n matrix of ones and zeros, return how many square submatrices have all ones. # Repeatedly remove each digit and update the product and total sum.
# Time - O(log n)
# Iterate ove the matrix apart from the first row and column. # Space - O(1)
# Update each cell to the maximum side square with this cell in the top right corner.
# The maximum side is 0 if the cell is 0, class Solution(object):
# else we can extend the smallest side square to the left, down or down and left by 1. def subtractProductAndSum(self, n):
# Sum the resulting matrix, since a cell with value x has square submatrices of side lengths 1, 2 ... x ending """
# with the cell in the top right corner. :type n: int
# Time - O(mn) :rtype: int
# Space - O(Tmn) """
product, total = 1, 0
class Solution(object):
def countSquares(self, matrix): while n > 0: # note n can be positive only
""" n, digit = divmod(n, 10)
:type matrix: List[List[int]] product *= digit
:rtype: int total += digit
"""
rows, cols = len(matrix), len(matrix[0]) return product - total

for r in range(1, rows):


for c in range(1, cols):
matrix[r][c] *= 1 + min(matrix[r - 1][c], matrix[r][c - 1], matrix[r - 1][c - 1]) # python_1001_to_2000/1282_Group_the_People_Given_the_Group_Size_They_Belong_To.py - m

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()

# python_1001_to_2000/1283_Find_the_Smallest_Divisor_Given_a_Threshold.py - m for state in frontier:


if all(not v for v in state): # found result
_author_ = 'jake' return steps
_project_ = 'leetcode'
if state in seen:
# https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/ continue
# Given an array of integers nums and an integer threshold, seen.add(state)
# we will choose a positive integer divisor and divide all the array by it and sum the result of the division.
# Find the smallest divisor such that the result mentioned above is less than or equal to threshold. for i in range(rows * cols):
# Each result of division is rounded to the nearest integer greater than or equal to that element. new_state = list(state)
# For example: 7/3 = 3 and 10/2 = 5. for nbor in linear_nbors[i]:
# It is guaranteed that there will be an answer. new_state[nbor] = not (new_state[nbor])
new_frontier.add((tuple(new_state)))
# Binary search for the divisor.
# The divisor is between 1 and max(num), inclusive. steps += 1
# Search this range by guessing the mid and checking if the sum of divided num is <= threshold. frontier = new_frontier
# If so, search the range from the guess and lower. Else search above the guess.
# Time - O(n log k) for n nums of max value k. return -1 # no result
# Space - O(1)

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 "".join(self.chars[i] for i in self.combination) import heapq

def hasNext(self): class Solution(object):


""" def minFallingPathSum(self, arr):
:rtype: bool """
""" :type arr: List[List[int]]
return self.combination != self.final :rtype: int
"""
n = len(arr)

# python_1001_to_2000/1287_Element_Appearing_More_Than_25%_In_Sorted_Array.py for row in range(1, n):


smallest, second = heapq.nsmallest(2, arr[row - 1])
_author_ = 'jake' for col in range(n):
_project_ = 'leetcode' arr[row][col] += second if arr[row - 1][col] == smallest else smallest

# https://leetcode.com/problems/element-appearing-more-than-25-in-sorted-array/ return min(arr[-1])


# Given an integer array sorted in non-decreasing order,
# there is exactly one integer in the array that occurs more than 25% of the time.
# Return that integer.
# python_1001_to_2000/1290_Convert_Binary_Number_in_a_Linked_List_to_Integer.py
# Count the frequency of each num, returning the num when any count is more than 25%.
# Alternatively, for each num at 25%, 50% and 75% of the array, binary search for its first and last occurences. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/convert-binary-number-in-a-linked-list-to-integer/
from collections import defaultdict # Given head which is a reference node to a singly-linked list.
# The value of each node in the linked list is either 0 or 1.
class Solution(object): # The linked list holds the binary representation of a number.
def findSpecialInteger(self, arr): # Return the decimal value of the number in the linked list.
"""
:type arr: List[int] # Iterate along the linked list.
:rtype: int # For each node, multiply the previous result by 2 (left bit shift) and add the bit from the current node.
""" # Time - O(n)
target = len(arr) // 4 + 1 # Space - O(n)
counts = defaultdict(int)
for num in arr: class Solution(object):
counts[num] += 1 def getDecimalValue(self, head):
if counts[num] == target: """
return num :type head: ListNode
:rtype: int
"""
result = 0
# python_1001_to_2000/1288_Remove_Covered_Intervals.py - m
while head:
_author_ = 'jake' result = result * 2 + head.val
_project_ = 'leetcode' head = head.next

# https://leetcode.com/problems/remove-covered-intervals/ return result


# Given a list of intervals, remove all intervals that are covered by another interval in the list.
# Interval [a,b) is covered by interval [c,d) if and only if c <= a and b <= d.
# After doing so, return the number of remaining intervals.
# python_1001_to_2000/1291_Sequential_Digits.py - m
# Sort the intervals and iterate over them.
# Maintain a stack of intervals that are not covered. _author_ = 'jake'
# For each new interval, if the to of stack interval ends before the interval ends it is not covered. _project_ = 'leetcode'
# Time - O(n log n)
# Space - O(n) # https://leetcode.com/problems/sequential-digits/
# An integer has sequential digits if and only if each digit in the number is one more than the previous digit.
class Solution(object): # Return a sorted list of all the integers in the range [low, high] inclusive that have sequential digits.
def removeCoveredIntervals(self, intervals):
""" # Starting from the digits from 1 to 9, extend each number by the next greater digit.
:type intervals: List[List[int]] # If a number is more than high, return the result since all later numbers are greater.
:rtype: int # If a number is greater than or equal to low, append it to the result.
""" # Time - O(log n)
stack = [] # Space - O(log n)
intervals.sort(key=lambda x:[x[0], -x[1]])
class Solution(object):
for interval in intervals: def sequentialDigits(self, low, high):
if not stack or stack[-1][1] < interval[1]: # keep if not covered """
stack.append(interval) :type low: int
:type high: int
return len(stack) :rtype: List[int]
"""
nums = list(range(1, 10))
result = []
# python_1001_to_2000/1289_Minimum_Falling_Path_Sum_II.py - h
while nums:
_author_ = 'jake' new_nums = []
_project_ = 'leetcode'
for num in nums:
# https://leetcode.com/problems/minimum-falling-path-sum-ii/ if num > high:
# Given a square grid of integers arr, break
# a falling path with non-zero shifts is a choice of exactly one element from each row of arr, if num >= low:
# such that no two elements chosen in adjacent rows are in the same column. result.append(num)
# Return the minimum sum of a falling path with non-zero shifts. last_digit = num % 10
if last_digit != 9: # extend with next greater digit
# For each row, only the smallest and second smallest paths are used. new_nums.append(num * 10 + last_digit + 1)
# Iterate over the rows, updating each element with the minimum sum path.
nums = new_nums return steps

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

# https://leetcode.com/problems/shortest-path-in-a-grid-with-obstacles-elimination/ class Solution(object):


# Given a m * n grid, where each cell is either 0 (empty) or 1 (obstacle). def isPossibleDivide(self, nums, k):
# In one step, you can move up, down, left or right from and to an empty cell. """
# Return the minimum number of steps to walk from the upper left corner (0, 0) to :type nums: List[int]
# the lower right corner (m-1, n-1) given that you can eliminate at most k obstacles. :type k: int
# If it is not possible to find such walk return -1. :rtype: bool
"""
# A-star search with heuristic of Manhattan distance. if len(nums) % k != 0: # check if nums can be divided into groups of k
# Repeatedly visit the state with the lowest heuristic + steps taken, ties broken by most remaining eliminations. return False
# Do not revisit the same cell with the same or fewer eliminations.
# Time - O(mnk log mnk) for grid of size mn each cell may be visited k times. counts = Counter(nums)
# Space - O(mnk)
for start_num in sorted(counts.keys()):
import heapq count = counts[start_num]
if count == 0: # num has already been used in other sequences
class Solution(object): continue
def shortestPath(self, grid, k):
""" for num in range(start_num, start_num + k):
:type grid: List[List[int]] if num not in counts or counts[num] < count:
:type k: int return False
:rtype: int counts[num] -= count # decrement so count nums are not reused
"""
rows, cols = len(grid), len(grid[0]) return True

def heuristic(r, c):


return abs(rows - 1 - r) + abs(cols - 1 - c)
# python_1001_to_2000/1297_Maximum_Number_of_Occurrences_of_a_Substring.py - m
queue = [(heuristic(0, 0), -k + grid[0][0], 0, 0, 0)] # h + steps, neg_elims, steps, r, c
_author_ = 'jake'
visited = {} # map cell to most eliminations remaining when cell visited _project_ = 'leetcode'

while queue: # https://leetcode.com/problems/maximum-number-of-occurrences-of-a-substring/


_, neg_elims, steps, r, c = heapq.heappop(queue) # Given a string s, return the maximum number of occurrences of any substring under the following rules:
# The number of unique characters in the substring must be less than or equal to maxLetters.
if neg_elims > 0: # too many eliminations used # The substring size must be between minSize and maxSize inclusive.
continue
if r == rows - 1 and c == cols - 1: # Ignore maxSize since there will be most substrings of length minSize.

# 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'

class Solution(object): # https://leetcode.com/problems/replace-elements-with-greatest-element-on-right-side/


def maxFreq(self, s, maxLetters, minSize, maxSize): # Given an array arr,
""" # replace every element in that array with the greatest element among the elements to its right,
:type s: str # and replace the last element with -1.
:type maxLetters: int # After doing so, return the array.
:type minSize: int
:type maxSize: int # Iterate over the array from right to left.
:rtype: int # Simultaneously update the greatest value seen and replace the value with the greatest.
""" # Time - O(n)
substrings = defaultdict(int) # map substring to its count in s # Space - O(n)
letters = defaultdict(int) # map letter to its count in sliding window
class Solution(object):
for end in range(len(s)): def replaceElements(self, arr):
letters[s[end]] += 1 # add letter to window count before checking substring """
start = end - minSize + 1 :type arr: List[int]
if start >= 0: :rtype: List[int]
if len(letters) <= maxLetters: # increment substring count if <= maxLetters in window """
substrings[s[start:end + 1]] += 1 greatest = -1
letters[s[start]] -= 1 # remove letter from window count after checking substring
if letters[s[start]] == 0: for i in range(len(arr) - 1, -1, -1):
del letters[s[start]] arr[i], greatest = greatest, max(greatest, arr[i])

return 0 if not substrings else max(substrings.values()) return arr

# 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

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# 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:

for open_box in open_boxes:


if status[open_box] == VISITED: # avoid re-vistiing # python_1001_to_2000/1301_Number_of_Paths_with_Max_Score.py - h
continue
status[open_box] = VISITED _author_ = 'jake'
_project_ = 'leetcode'
result += candies[open_box]
for key in keys[open_box]: # open when box is reached, no need to retain key # https://leetcode.com/problems/number-of-paths-with-max-score/
status[key] = OPEN # You are given a square board of characters.
closed_boxes.update(containedBoxes[open_box]) # You can move on the board starting at the bottom right square marked with the character 'S'.
# You need to reach the top left square marked with the character 'E'.
open_boxes = {box for box in closed_boxes if status[box] == OPEN} # The rest of the squares are labeled either with a numeric character 1, 2, ..., 9 or with an obstacle 'X'.
closed_boxes -= open_boxes # In one move you can go up, left or up-left (diagonally) only if there is no obstacle there.
# Return a list of two integers: the first integer is the maximum sum of numeric characters you can collect,
return result # and the second is the number of such paths that you can take to get that maximum sum, taken modulo 10^9 + 7.
# In case there is no path, return [0, 0].
# Recursive helper function finds result from any cell.
# Base cases of outside board and "X" return no paths. # https://leetcode.com/problems/find-n-unique-integers-sum-up-to-zero/
# Base case of "E" returns one path with maximum value zero. # Given an integer n, return any array containing n unique integers such that they add up to 0.
# Recurse for the 3 possible moves. If all moves have no paths, return no paths.
# Else find the max value and sum all paths with that value. # Use integers 1, 2, ... n // 2 and their negatives.
# Memoize to avoid repetition. # If n is odd, also append zero.
# Time - O(mn) # Time - O(n)
# Space - O(mn) # Space - O(n)

class Solution(object): class Solution(object):


def pathsWithMaxScore(self, board): def sumZero(self, n):
""" """
:type board: List[str] :type n: int
:rtype: List[int] :rtype: List[int]
""" """
MOD = 10 ** 9 + 7 ints = [i for i in range(1, (n // 2) + 1)]
rows, cols = len(board), len(board[0]) ints += [-i for i in ints]
visited = {} return ints if n % 2 == 0 else ints + [0]

def helper(r, c): # return [max_value, path_count] from board[r][c]


if r < 0 or c < 0 or board[r][c] == "X": # no paths
return [0, 0] # python_1001_to_2000/1305_All_Elements_in_Two_Binary_Search_Trees.py - m
if (r, c) in visited:
return visited[(r, c)] _author_ = 'jake'
if r == 0 and c == 0: # "E" end cell _project_ = 'leetcode'
return [0, 1]
# https://leetcode.com/problems/all-elements-in-two-binary-search-trees/
# 3 possible moves # Given two binary search trees root1 and root2.
up_max, up_paths = helper(r - 1, c) # Return a list containing all the integers from both trees sorted in ascending order.
left_max, left_paths = helper(r, c - 1)
up_left_max, up_left_paths = helper(r - 1, c - 1) # Perform inorder traversals on each tree to get the node in ascending value order.
max_value, max_count_paths = 0, 0 # Then iterate along the sorted lists to merge them.
# Alternatively, sort tree1 and tree2 instead of merging.
if up_paths + left_paths + up_left_paths > 0: # no max_count_paths if no paths for any move # Time - O(n)
max_value = max(up_max, left_max, up_left_max) # Space - O(n)
if up_max == max_value:
max_count_paths += up_paths class Solution(object):
if left_max == max_value: def getAllElements(self, root1, root2):
max_count_paths += left_paths """
if up_left_max == max_value: :type root1: TreeNode
max_count_paths += up_left_paths :type root2: TreeNode
max_value += int(board[r][c]) if r < rows - 1 or c < cols - 1 else 0 # handle "S" start cell :rtype: List[int]
"""
visited[(r, c)] = [max_value, max_count_paths] def inorder(node, ascending):
return [max_value, max_count_paths % MOD] if not node:
return
return helper(rows - 1, cols - 1) inorder(node.left, ascending)
ascending.append(node.val)
inorder(node.right, ascending)

# python_1001_to_2000/1302_Deepest_Leaves_Sum.py - m tree1, tree2 = [], []


inorder(root1, tree1)
_author_ = 'jake' inorder(root2, tree2)
_project_ = 'leetcode'
result = []
# https://leetcode.com/problems/deepest-leaves-sum/ i, j = 0, 0 # indices of next elements to merge
# Given a binary tree, return the sum of values of its deepest leaves. while i < len(tree1) and j < len(tree2): # until one list is exhausted
if tree1[i] <= tree2[j]:
# Breadth-first search. result.append(tree1[i])
# For each layer, sum all the node values and find all nodes in the next layer. i += 1
# Repeat until the layer is empty and return the sum of nodes in the previous layer. else:
# Time - O(n) result.append(tree2[j])
# Space - O(n) j += 1

class Solution(object): return result + tree1[i:] + tree2[j:] # append remaining nodes


def deepestLeavesSum(self, root):
"""
:type root: TreeNode
:rtype: int # python_1001_to_2000/1306_Jump_Game_III.py - m
"""
nodes = [root] _author_ = 'jake'
_project_ = 'leetcode'
while nodes:
level_sum = 0 # https://leetcode.com/problems/jump-game-iii/
new_nodes = [] # Given an array of non-negative integers arr, you are initially positioned at start index of the array.
# When you are at index i, you can jump to i + arr[i] or i - arr[i], check if you can reach to any index with value 0.
for node in nodes: # Notice that you can not jump outside of the array at any time.
level_sum += node.val
if node.left: # Recursive helper returns False if index is outside array and True if value is zero.
new_nodes.append(node.left) # Else recurse jumping by +/- arr[i].
if node.right: # Record visited indices to avois loops.
new_nodes.append(node.right) # Time - O(n)
# Space - O(n)
nodes = new_nodes
class Solution(object):
return level_sum def canReach(self, arr, start):
"""
:type arr: List[int]
:type start: int
# python_1001_to_2000/1304_Find_N_Unique_Integers_Sum_up_to_Zero.py :rtype: bool
"""
_author_ = 'jake' n = len(arr)
_project_ = 'leetcode' visited = set()

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(i + arr[i]) or helper(i - arr[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.

# Calculate cumulative XOR up to each element.


# For each query, take the difference between cumulative XOR of start and end + 1 indices.
# Time - O(m + n) for m queries and arr of length n
# Space - O(m + n)

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

You might also like