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

github_jakehoare_leetcode_4splits_100scale_with_difficulty

The document contains code snippets for various LeetCode problems, including Two Sum, Add Two Numbers, and Longest Palindromic Substring. Each problem description is followed by a Python class solution that outlines the approach, time complexity, and space complexity. The document serves as a reference for solving common algorithmic challenges in coding interviews.
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)
3 views

github_jakehoare_leetcode_4splits_100scale_with_difficulty

The document contains code snippets for various LeetCode problems, including Two Sum, Add Two Numbers, and Longest Palindromic Substring. Each problem description is followed by a Python class solution that outlines the approach, time complexity, and space complexity. The document serves as a reference for solving common algorithmic challenges in coding interviews.
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/ 221

carry += l1.

val
# python_1_to_1000/001_Two_Sum.py l1 = l1.next
if l2:
_author_ = 'jake' carry += l2.val
_project_ = 'leetcode' l2 = l2.next
prev.next = ListNode(carry % 10)
# https://leetcode.com/problems/two-sum/ prev = prev.next
# Given an array of integers, return indices of the two numbers carry //= 10
# such that they add up to a specific target.
# You may assume that each input would have exactly one solution. return result.next

# Maintain a mapping from each number to its index.


# Check if target - num has already been found. # python_1_to_1000/003_Longest_Substring_Without_Repeating_Characters.py - m
# Time - O(n)
# Space - O(n) for the dictionary _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def twoSum(self, nums, target): # https://leetcode.com/problems/longest-substring-without-repeating-characters/
""" # Given a string, find the length of the longest substring without repeating characters.
:type nums: List[int]
:type target: int # Maintain a sliding window, updating the start whenever we see a character repeated.
:rtype: List[int] # Time - O(n)
""" # Space - O(1), dictionary is limited by fixed size alphabet

num_to_index = {} # key is number, value is index in nums class Solution(object):


def lengthOfLongestSubstring(self, s):
for i, num in enumerate(nums): """
:type s: str
if target - num in num_to_index: :rtype: int
return [num_to_index[target - num], i] """
last_seen = {} # mapping from character to its last seen index in s
num_to_index[num] = i start = 0 # start index of current substring
longest = 0
return [] # no sum
for i, c in enumerate(s):

if c in last_seen and last_seen[c] >= start:


# python_1_to_1000/002_Add_Two_Numbers.py - m # start a new substring after the previous sighting of c
start = last_seen[c] + 1
_author_ = 'jake' else:
_project_ = 'leetcode' longest = max(longest, i - start + 1)

# https://leetcode.com/problems/add-two-numbers/ last_seen[c] = i # update the last sighting index


# You are given two linked lists representing two non-negative numbers.
# The digits are stored in reverse order and each of their nodes contain a single digit. return longest
# Add the two numbers and return it as a linked list.

# Iterate over lists. Add to result a node with the the sum of input nodes plus carry,
mod 10. # python_1_to_1000/004_Median_of_Two_Sorted_Arrays.py - h
# Time - O(max(m,n)) where m and n are input list lengths.
# Space - O(max(m,n)), output will be at most one digit more than longest input. _author_ = 'jake'
_project_ = 'leetcode'
# Definition for singly-linked list.
class ListNode(object): # https://leetcode.com/problems/median-of-two-sorted-arrays/
def __init__(self, x): # There are two sorted arrays nums1 and nums2 of size m and n respectively.
self.val = x # Find the median of the two sorted arrays. The overall run time complexity should be
self.next = None O(log (m+n)).

class Solution(object): # Find the middle element if sum of input list lengths is odd, or else the average of the
def addTwoNumbers(self, l1, l2): middle pair.
""" # get_kth_smallest recusively removes k//2 elements from one list.
:type l1: ListNode # Time - O(log(m+n)), half of the elements smaller than median are removed each recursive
:type l2: ListNode call.
:rtype: ListNode # Space - O(log(m+n)) for the recursive call stack.
"""
prev = result = ListNode(None) # dummy head class Solution(object):
carry = 0 def findMedianSortedArrays(self, A, B):
"""
while l1 or l2 or carry: :type A: List[int]
if l1:

:type B: List[int] # start with middle index that potentially creates longest palindrome
:rtype: float centres = [len(s) - 1]
""" for diff in range(1, len(s)): # build list of indices from long to short
def get_kth_smallest(a_start, b_start, k): centres.append(centres[0] + diff)
centres.append(centres[0] - diff)
if k <= 0 or k > len(A) - a_start + len(B) - b_start:
raise ValueError('k is out of the bounds of the input lists') for centre in centres:

# base cases if (min(centre + 1, 2 * len(s) - 1 - centre) <= len(longest)):


if a_start >= len(A): break # return if cannot make a longer palindrome
return B[b_start + k - 1]
if b_start >= len(B): if centre % 2 == 0:
return A[a_start + k - 1] left, right = (centre // 2) - 1, (centre // 2) + 1
if k == 1: else:
return min(A[a_start], B[b_start]) left, right = centre // 2, (centre // 2) + 1

# remove k//2 elements from one list while left >= 0 and right < len(s) and s[left] == s[right]:
# find the smallest of the k//2 - 1th element from both lists and recurse left -= 1
having reduced that list. right += 1
# k//2 - 1th element must exist in at least 1 list # left and right are now beyond the ends of the substring
mid_A, mid_B = float('inf'), float('inf')
if k // 2 - 1 < len(A) - a_start: if right - left - 1 > len(longest):
mid_A = A[a_start + k // 2 - 1] longest = s[left + 1:right]
if k // 2 - 1 < len(B) - b_start:
mid_B = B[b_start + k // 2 - 1] return longest

if mid_A < mid_B:


return get_kth_smallest(a_start + k // 2, b_start, k - k // 2)
return get_kth_smallest(a_start, b_start + k // 2, k - k // 2) # python_1_to_1000/006_ZigZag_Conversion.py - m

right = get_kth_smallest(0, 0, 1 + (len(A) + len(B)) // 2) _author_ = 'jake'


if (len(A) + len(B)) % 2 == 1: # odd total length _project_ = 'leetcode'
return right
# https://leetcode.com/problems/zigzag-conversion/
left = get_kth_smallest(0, 0, (len(A) + len(B)) // 2) # The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows
return (left + right) / 2.0 like this:
# P A H N
# A P L S I I G
# Y I R
# python_1_to_1000/005_Longest_Palindromic_Substring.py - m # And then read line by line: "PAHNAPLSIIGYIR"
# Write the code that will take a string and make this conversion given a number of rows.
_author_ = 'jake'
_project_ = 'leetcode' # Build a list of chars for each row by tracking the direction of movement up or down and
# reversing direction at end rows.
# https://leetcode.com/problems/longest-palindromic-substring/ # Time - O(n), use a list of chars and join instead of adding to immutable strings.
# Given a string S, find the longest palindromic substring in S. # Space - O(n)
# You may assume that the maximum length of S is 1000, and there exists one unique
longest palindromic substring. class Solution(object):
def convert(self, s, numRows):
# For each centre point of a character or between 2 characters, """
# expand the palindrome if the end characters are the same. :type s: str
# Return early by starting with the middle centre and ruling out later centres that could :type numRows: int
not have longer :rtype: str
# substring than the palindrome already found. """
# Time - O(n^2), 2n centres, each expanded upto n times if numRows == 1:
# Space - O(n) to store the result return s

# Note that Manacher's algorithm provides a O(n) time solution. zigzag = [[] for _ in range(numRows)]
row = 0
class Solution(object): direction = -1 # -1 for up, +1 for down
def longestPalindrome(self, s):
""" for c in s:
:type s: str zigzag[row].append(c)
:rtype: str if row == 0 or row == numRows-1: # change direction
""" direction = -direction
longest = "" row += direction

# create list of 2n-1 possible centres, each letter and between each pair return "".join([c for r in zigzag for c in r]) # flatten list of lists
# even indices represent letters, odd represent between letters
return 0

# python_1_to_1000/007_Reverse_Integer.py - m digits = {i for i in '0123456789'}


result = 0
_author_ = 'jake' for c in str: # record integer upto first non-digit
_project_ = 'leetcode' if c not in digits:
break
# https://leetcode.com/problems/reverse-integer/ result = result * 10 + int(c)
# Reverse digits of an integer.
# Example1: x = 123, return 321 if negative:
# Example2: x = -123, return -321 result = -result

# Repeatedly multiply previous result by 10 and add last digit. result = max(min(result, 2**31 - 1), -2**31) # keep within 4 byte signed
# Time - O(n) where n is the number of digits. integer bounds
# Space - O(n), same number of digits in output as input. return result

class Solution(object):
def reverse(self, x):
""" # python_1_to_1000/009_Palindrome_Number.py
:type x: int
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
negative = x < 0 # record if negative and change to positive
x = abs(x) # https://leetcode.com/problems/palindrome-number/
reversed = 0 # Determine whether an integer is a palindrome. Do this without extra space.

while x != 0: # Check equivalence of first and last characters, moving inwards.


reversed = reversed * 10 + x % 10 # Time - O(n)
x //= 10 # Space - O(1)

if reversed > 2**31 - 1: # required to pass leetcode test cases, not class Solution(object):
applicable for python def isPalindrome(self, x):
return 0 """
return reversed if not negative else -reversed :type x: int
:rtype: bool
"""
s = str(x)
left, right = 0, len(s)-1

# python_1_to_1000/008_String_to_Integer_(atoi).py - m while left < right:


if s[left] != s[right]:
_author_ = 'jake' return False
_project_ = 'leetcode' left += 1
right -=1
# https://leetcode.com/problems/string-to-integer-atoi/
# Implement atoi to convert a string to an integer. return True
# Notes: It is intended for this problem to be specified vaguely (ie, no given input
specs).
# You are responsible to gather all the input requirements up front. # python_1_to_1000/010_Regular_Expression_Matching.py - h

# Return the integer upto any non-digit. _author_ = 'jake'


# Time - O(n) _project_ = 'leetcode'
# Space - O(n), new str created by strip()
# https://leetcode.com/problems/regular-expression-matching/
# Implement regular expression matching with support for '.' and '*'.
class Solution(object): # '.' Matches any single character.
def myAtoi(self, str): # '*' Matches zero or more of the preceding element.
""" # The matching should cover the entire input string (not partial).
:type str: str
:rtype: int # Dynamic programming calculation of matrix of whether any prefix of s patches any prefix
""" of p.
str = str.strip() # remove padding spaces # Time - O(m*n) when m = len(p) and n = len(s)
# Space - O(m*n)
negative = False # remove leading + or -
if str and str[0] == '-': class Solution(object):
negative = True def isMatch(self, s, p):
if str and (str[0] == '+' or str[0] == '-'):
str = str[1:] # matched[i][j] is True if the first i chars of s (i.e. s[:i]) matches the first
if not str: j chars of p (i.e. p[:j])

matched = [[False for _ in range(len(p)+1)] for _ in range(len(s)+1)] # https://leetcode.com/problems/integer-to-roman/


matched[0][0] = True # no pattern (j=0) matches no string and not any non- # Given an integer, convert it to a roman numeral.
zero string # Input is guaranteed to be within the range from 1 to 3999.

for i in range(len(s)+1): # Repeatedly take of as many copies of each numeral as possible until num is less than
for j in range(1, len(p)+1): # the value of that numeral.
pattern = p[j-1] # Time - O(n) where n = len(str(num)), the longest roman equivalent is 8 where one digit
maps to 4 chars
if pattern == '.': # dot matches any last character of s # Space - O(n)
matched[i][j] = (i != 0 and matched[i-1][j-1])
class Solution(object):
elif pattern == '*': # either ignore last 2 chars of p, or ignore last def intToRoman(self, num):
char of s provided it """
star = p[j-2] # matches the star char :type num: int
matched[i][j] = matched[i][j-2] or (i > 0 and matched[i-1][j] and :rtype: str
(star == s[i-1] or star == '.')) """
mapping = [(1000, 'M'),
else: # pattern must match the last character of s (900, 'CM'),
matched[i][j] = (i != 0 and matched[i-1][j-1] and s[i-1] == pattern) (500, 'D'),
(400, 'CD'),
return matched[-1][-1] (100, 'C'),
(90, 'XC'),
(50, 'L'),
(40, 'XL'),
# python_1_to_1000/011_Container_With_Most_Water.py - m (10, 'X'),
(9, 'IX'),
_author_ = 'jake' (5, 'V'),
_project_ = 'leetcode' (4, 'IV'),
(1, 'I'),]
# https://leetcode.com/problems/container-with-most-water/
# Given n non-negative integers a1, a2, ..., an, where each represents a point at roman = []
coordinate (i, ai), for i, numeral in mapping:
# n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, while num >= i:
0). num -= i
# Find two lines, which together with x-axis forms a container, such that the container roman.append(numeral)
contains the most water.
return "".join(roman)
# Start with the widest separation of lines. To form a greater area, any lesser
separation must have a greater
# minimum boundary height.
# Time - O(n) # python_1_to_1000/013_Roman_to_Integer.py
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def maxArea(self, height):
""" # https://leetcode.com/problems/roman-to-integer/
:type height: List[int] # Given a roman numeral, convert it to an integer.
:rtype: int # Input is guaranteed to be within the range from 1 to 3999.
"""
left = 0 # Iterate along s, checking if the next 2 characters match any valid roman numeral.
right = len(height)-1 # If so, add the value of the numeral to the result. Otherwise the next single
max_area = (right - left) * min(height[right], height[left]) # character must match a numeral, which is added to the result.
# Time - O(n)
while left < right: # Space - O(1)
if height[left] < height[right]: # By moving in the lower boundary we have
the possibility class Solution(object):
left += 1 # of finding a larger area. def romanToInt(self, s):
else: """
right -= 1 :type s: str
max_area = max(max_area, (right - left) * min(height[right], height[left])) :rtype: int
"""
return max_area doubles = {'CM' : 900, 'CD' : 400, 'XC' : 90, 'XL' : 40, 'IX' :9, 'IV' : 4}
singles = {'M' : 1000, 'D' : 500, 'C' : 100, 'L' : 50, 'X' : 10, 'V' : 5, 'I' :
1}
# python_1_to_1000/012_Integer_to_Roman.py - m
integer = 0
_author_ = 'jake' i = 0
_project_ = 'leetcode' while i < len(s):
if i < len(s) - 1 and s[i:i + 2] in doubles:
integer += doubles[s[i:i + 2]] nums.sort()
i += 2
else: i = 0
integer += singles[s[i]] while i < len(nums):
i += 1 j = i + 1
k = len(nums) - 1
return integer
while j < k:

triple_sum = nums[i] + nums[j] + nums[k]


# python_1_to_1000/014_Longest_Common_Prefix.py
if triple_sum == 0: # record result and move both j and k to next new
_author_ = 'jake' numbers
_project_ = 'leetcode' results.append([nums[i], nums[j], nums[k]])
k -= 1
# https://leetcode.com/problems/longest-common-prefix/ while k > j and nums[k] == nums[k + 1]:
# Write a function to find the longest common prefix string amongst an array of strings. k -= 1
j += 1
# Sort strings and find longest prefix of first and last, which are the most different. while j < k and nums[j] == nums[j - 1]:
# Alternatively all strings could be inserted into a trie and we find the first node j += 1
# with more than one child.
# Time - O(k*n logn) where k is the length of the longest string and n is number of elif triple_sum > 0: # decrement k to next new number
strings. k -= 1
# Space - O(1) while k > j and nums[k] == nums[k + 1]:
k -= 1
class Solution(object): else: # increment j to next new number
def longestCommonPrefix(self, strs): j += 1
""" while j < k and nums[j] == nums[j - 1]:
:type strs: List[str] j += 1
:rtype: str
""" i += 1 # increment i to next new number
if not strs: while i < len(nums) - 2 and nums[i] == nums[i - 1]:
return '' i += 1

strs.sort() return results


first = strs[0]
last = strs[-1]

i = 0
while i < len(first) and i < len(last) and first[i] == last[i]: # python_1_to_1000/016_3Sum_Closest.py - m
i += 1
return first[:i] _author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/3sum-closest/
# python_1_to_1000/015_3Sum.py - m # Given an array nums of n integers, find three integers in nums such that the sum is
closest to a given number, target.
_author_ = 'jake' # Return the sum of the three integers. You may assume that each input would have exactly
_project_ = 'leetcode' one solution.

# https://leetcode.com/problems/3sum/ # Sort the array. For each staring index bidirectional search in the rest of the array.
# Given an array S of n integers, are there elements a, b, c in S such that a + b + c = # Time - O(n**2)
0? # Space - O(1)
# Find all unique triplets in the array which gives the sum of zero.
# Note: The solution set must not contain duplicate triplets. class Solution(object):
def threeSumClosest(self, nums, target):
# Sort the array. For each index i perform a bidirectional search on the higher values """
in the array. :type nums: List[int]
# Skip over duplicates. Increment i to the next new minimum number. :type target: int
# Time - O(n**2), for each i at least one of j and k moves every iteration. :rtype: int
# Space - O(n) """
nums.sort()
class Solution(object): closest = float('inf') # default if len(nums) < 3
def threeSum(self, nums):
""" for i in range(len(nums) - 2):
:type nums: List[int] j = i + 1
:rtype: List[List[int]] k = len(nums) - 1
"""
results = [] while j < k:

# Note: The solution set must not contain duplicate quadruplets.


triple = nums[i] + nums[j] + nums[k]
if triple == target: # early return, cannot do better # Recursively reduce to 2sum problem.
return target # Time - O(n^3), for each pair perform linear search on the rest of the array
if abs(triple - target) < abs(closest - target):
closest = triple class Solution(object):
ELEMENTS = 4 # parametrise the number of elements being summed
if triple - target > 0:
k -= 1 def fourSum(self, nums, target):
else: """
j += 1 :type nums: List[int]
:type target: int
return closest :rtype: List[List[int]]
"""
results = []
self.n_sum(sorted(nums), target, [], self.ELEMENTS, results)
# python_1_to_1000/017_Letter_Combinations_of_a_Phone_Number.py - m return results

_author_ = 'jake'
_project_ = 'leetcode' def n_sum(self, nums, target, partial, n, results): # generalise for
n-sum
# https://leetcode.com/problems/letter-combinations-of-a-phone-number/
# Given a digit string, return all possible letter combinations that the number could if len(nums) < n or target > nums[-1]*n or target < nums[0]*n: # early return if
represent. impossible
return
# For each digit add all possible letter mappings to each of the previous results.
# Alternatively can be solved recursively. if n == 2: # base case of linear bidirectional search for n
# Time - O(n * 4^n) == 2
# Space - O(n * 4^n), max 4 possible chars per digit so O(4^n) strings each of length n left = 0
right = len(nums)-1
class Solution(object): while left < right:
def letterCombinations(self, digits): if nums[left] + nums[right] == target:
""" results.append(partial + [nums[left], nums[right]])
:type digits: str left += 1
:rtype: List[str] right -= 1
""" while nums[right] == nums[right+1] and right > left: # move to
if not digits or '0' in digits or '1' in digits: next different number if target found
return [] right -=1
elif nums[left] + nums[right] < target:
results = [[]] left += 1
mapping = {'2' : ['a', 'b', 'c'], else:
'3' : ['d', 'e', 'f'], right -= 1
'4' : ['g', 'h', 'i'],
'5' : ['j', 'k', 'l'], else:
'6' : ['m', 'n', 'o'], for i in range(len(nums)-n+1): # for all possible first numbers
'7' : ['p', 'q', 'r', 's'], nums[i]
'8' : ['t', 'u', 'v'], if i == 0 or nums[i] != nums[i-1]: # if not duplicate
'9' : ['w', 'x', 'y' , 'z']} self.n_sum(nums[i+1:], target-nums[i], partial + [nums[i]], n-1,
results)
for digit in digits:
temp = []
for result in results:
for letter in mapping[digit]: # python_1_to_1000/019_Remove_Nth_Node_From_End_of_List.py - m
temp.append(result + [letter])
results = temp _author_ = 'jake'
_project_ = 'leetcode'
# convert lists of chars to strings
return ["".join(result) for result in results] # 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.

# python_1_to_1000/018_4Sum.py - m # Advance first pointer n steps then advance both pointers at same rate.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
# Definition for singly-linked list.
# https://leetcode.com/problems/4sum/ # class ListNode(object):
# Given an array nums of n integers, are there elements a, b, c, and d in nums such that # def __init__(self, x):
a + b + c + d = target? # self.val = x
# Find all unique quadruplets in the array which gives the sum of target. # self.next = None
# the list with remaining nodes.
class Solution(object): # Time - O(m+n)
def removeNthFromEnd(self, head, n): # Space - O(1)
"""
:type head: ListNode # Definition for singly-linked list.
:type n: int class ListNode(object):
:rtype: ListNode def __init__(self, x):
""" self.val = x
first, second = head, head self.next = None

for i in range(n): # move first n steps forwards class Solution(object):


first = first.next def mergeTwoLists(self, l1, l2):
if not first:
return head.next prev = dummy = ListNode(None) # new dummy head for the merged list

while first.next: # move both pointers until first is at end while l1 and l2: # link prev to the lowest node
first = first.next
second = second.next if l1.val < l2.val:
second.next = second.next.next # nth from end is second.next prev.next = l1
return head l1 = l1.next
else:
prev.next = l2
# python_1_to_1000/020_Valid_Parentheses.py l2 = l2.next

_author_ = 'jake' prev = prev.next


_project_ = 'leetcode'
prev.next = l1 or l2 # link prev to the list with remaining nodes
# https://leetcode.com/problems/valid-parentheses/ return dummy.next
# Given a string containing just the characters '(', ')', '{', '}', '[' and ']',
determine if the input string is valid.
# The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]"
and "([)]" are not.
# python_1_to_1000/022_Generate_Parentheses.py - m
# Maintain a stack of opening brackets. For each closing bracket pop the head of the
stack and check it matches. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/generate-parentheses/
class Solution(object): # Given n pairs of parentheses, write a function to generate all combinations of well-
def isValid(self, s): formed parentheses.
"""
:type s: str # Recursively add an opening left bracket if any remain, and a closing right bracket if
:rtype: bool more left brackets have been used.
""" # Time - O(2^n), each recursion can generate 2 recursive calls althougn in practive this
stack = [] is an upper bound
match = {'(' : ')', '[' : ']', '{' : '}'} # Space - O(2^n)

for c in s: class Solution(object):


if c in match: def generateParenthesis(self, n):
stack.append(c) """
else: :type n: int
if not stack or match[stack.pop()] != c: :rtype: List[str]
return False """
result = []
return not stack self.generate([], n, n, result)
return result

# Generates all parentheses given a starting prefix and remaining left and right
# python_1_to_1000/021_Merge_Two_Sorted_Lists.py brackets.
def generate(self, prefix, left, right, result):
_author_ = 'jake' if left == 0 and right == 0:
_project_ = 'leetcode' result.append("".join(prefix))
if left != 0:
# https://leetcode.com/problems/merge-two-sorted-lists/ self.generate(prefix + ['('], left-1, right, result)
# Merge two sorted linked lists and return it as a new list. The new list should be made if right > left:
by splicing together the nodes of the first two lists. self.generate(prefix + [')'], left, right-1, result)

# Whilst there are nodes in both lists, link to lowest head node and increment that list.
Finally link to

class ListNode(object):
# python_1_to_1000/023_Merge_k_Sorted_Lists.py - h def __init__(self, x):
self.val = x
_author_ = 'jake' self.next = None
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/merge-k-sorted-lists/ def swapPairs(self, head):
# Merge k sorted linked lists and return it as one sorted list. Analyze and describe its """
complexity. :type head: ListNode
:rtype: ListNode
# Maintain a min heap of tuples of (val, list index) for the next node in each list. """
# Also maintain a list of the next node to be merged for each list index. prev = dummy = ListNode(None)
# Time - O(n log k) for n total nodes, each of which is pushed and popped from heap in
log k time. while head and head.next:
# Space - O(k) for heap of k nodes next_head = head.next.next
prev.next = head.next
# Definition for singly-linked list. head.next.next = head
class ListNode(object): prev = head
def __init__(self, x): head = next_head
self.val = x
self.next = None prev.next = head
return dummy.next
import heapq

class Solution(object):
def mergeKLists(self, lists): # python_1_to_1000/025_Reverse_Nodes_in_k-Group.py - h
"""
:type lists: List[ListNode] _author_ = 'jake'
:rtype: ListNode _project_ = 'leetcode'
"""
prev = dummy = ListNode(None) # https://leetcode.com/problems/reverse-nodes-in-k-group/
next_nodes, heap = [], [] # Given a linked list, reverse the nodes of a linked list k at a time and return its
modified list.
for i, node in enumerate(lists): # If the number of nodes is not a multiple of k then left-out nodes in the end should
next_nodes.append(node) # next_nodes[i] is the next node to be merged remain as it is.
from lists[i] # You may not alter the values in the nodes, only nodes itself may be changed.
if node: # Only constant memory is allowed.
heap.append((node.val, i))
heapq.heapify(heap) # If there are at least k nodes, recursively reverse remainder and append reversed group
to reversed remainder.
while heap: # Time - O(n)
value, i = heapq.heappop(heap) # Space - O(1)
node = next_nodes[i]
prev.next = node # add node to merged list class Solution(object):
prev = prev.next def reverseKGroup(self, head, k):
if node.next: """
next_nodes[i] = node.next :type head: ListNode
heapq.heappush(heap, (node.next.val, i)) :type k: int
:rtype: ListNode
return dummy.next """
if k < 2:
return head

# python_1_to_1000/024_Swap_Nodes_in_Pairs.py - m node = head


for _ in range(k):
_author_ = 'jake' if not node:
_project_ = 'leetcode' return head # return head if there are not at least k nodes
node = node.next
# https://leetcode.com/problems/swap-nodes-in-pairs/ # else node is now head of second group
# 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. # reverse remainder after this group
# Your algorithm should use only constant space. You may not modify the values in the prev = self.reverseKGroup(node, k)
list, only nodes itself can be changed.
for _ in range(k): # reverse this group, adding in front of prev
# Store the previous node, swap and append in pairs. temp = head.next
# Time - O(n) head.next = prev
# Space - O(1) prev = head
head = temp
# Definition for singly-linked list.
return prev
# python_1_to_1000/028_Implement_strStr().py

# python_1_to_1000/026_Remove_Duplicates_from_Sorted_Array.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/implement-strstr/
# Implement strStr().
# https://leetcode.com/problems/remove-duplicates-from-sorted-array/ # Returns the index of the first occurrence of needle in haystack, or -1 if needle is not
# Given a sorted array, remove the duplicates in place such that each element appear only part of haystack.
once and return the new length.
# Do not allocate extra space for another array, you must do this in place with constant # For each pssible starting point in haystack, check characters match with needle and
memory. break if not.
# Alternatively KMP would improve expected time complexity.
# Maintain a pointer to the next index to be filled with a new number. Check every number # Time - O(n^2)
against the previous num # Space - O(1)
# (if any) and if different, move to the next_new index.
# Time - O(n) class Solution(object):
# Space - O(1) def strStr(self, haystack, needle):
"""
class Solution(object): :type haystack: str
def removeDuplicates(self, nums): :type needle: str
""" :rtype: int
:type nums: List[int] """
:rtype: int for i in range(len(haystack) - len(needle) + 1):
""" for j in range(len(needle)):
next_new = 0 # index where the next unique number is to be moved to if haystack[i + j] != needle[j]:
break
for i in range(len(nums)): else: # for/else reaches here if no break
if i == 0 or nums[i] != nums[i - 1]: return i
nums[next_new] = nums[i] return -1
next_new += 1

return next_new
# python_1_to_1000/029_Divide_Two_Integers.py - m

_author_ = 'jake'
# python_1_to_1000/027_Remove_Element.py _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/divide-two-integers/


_project_ = 'leetcode' # Divide two integers without using multiplication, division and mod operator.
# If overflow, return MAX_INT.
# https://leetcode.com/problems/remove-element/
# Given an array and a value, remove all instances of that value in place and return the # Repeatedly double the divisor until it would exceed the dividend. Then repeatedly
new length. halve the divisor, subtracting
# Do not allocate extra space for another array, you must do this in place with constant # it from the dividend whenever possible.
memory. # Time - O(log n)
# The order of elements can be changed. It doesn't matter what you leave beyond the new # Space - O(1)
length.
class Solution(object):
# Maintain pointer to next index to be used for any number not equal to val. def divide(self, dividend, divisor):
# Time - O(n) """
# Space - O(1) :type dividend: int
:type divisor: int
class Solution(object): :rtype: int
def removeElement(self, nums, val): """
""" if divisor == 0:
:type nums: List[int] return None
:type val: int diff_sign = (divisor < 0) ^ (dividend < 0)
:rtype: int dividend = abs(dividend)
""" divisor = abs(divisor)
next_free = 0
for i, num in enumerate(nums): result = 0
if num != val: max_divisor = divisor
nums[next_free] = num shift_count = 1
next_free += 1
return next_free while dividend >= (max_divisor << 1): # find divisor * 2^i where divisor *
2^(i+1) > dividend
max_divisor <<= 1

shift_count <<= 1 dictionary


freq[first_word] += 1
while shift_count >= 1: to_match += 1
if dividend >= max_divisor: # subtract max_divisor whenever possible
dividend -= max_divisor else: # no words matched
result += shift_count i += word_len
shift_count >>= 1
max_divisor >>= 1 return result

if diff_sign:
result = -result
return max(min(result, 2**31-1), -2**31) # required for leetcode # python_1_to_1000/031_Next_Permutation.py - m

_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/030_Substring_with_Concatenation_of_All_Words.py - h
# https://leetcode.com/problems/next-permutation/
_author_ = 'jake' # Implement next permutation, which rearranges numbers into the lexicographically next
_project_ = 'leetcode' greater permutation of numbers.
# If such arrangement is not possible, it must rearrange it as the lowest possible order
# https://leetcode.com/problems/substring-with-concatenation-of-all-words/ (ie, sorted in ascending order).
# You are given a string, s, and a list of words, words, that are all of the same length. # The replacement must be in-place, do not allocate extra memory.
# Find all starting indices of substring(s) in s that is a concatenation of each word in
words exactly once # Starting from the last number, move forward to find the first decrease nums[i].
# and without any intervening characters. # Find the smallest number bigger than nums[i], nums[j]. Swap nums[i] and nums[j].
# Reverse all from i+1 onwards, or whole array if no decrease found in first step.
# For each stripe, maintain a sliding window of matched words. # Time - O(n)
# Time - O(n) where n = len(s). word_len stripes, each of which we move the start or end # Space - O(1)
of the matched window
# forwards n / word_len times. class Solution(object):
# Space - O(len(words)*word_len) for dictionary def nextPermutation(self, nums):
"""
from collections import Counter :type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
class Solution(object): """
def findSubstring(self, s, words): if not nums or len(nums) == 1:
""" return
:type s: str
:type words: List[str] i = len(nums)-2 # starting at back, find the first decrease - increasing it
:rtype: List[int] will increment the permutation
""" while i >= 0 and nums[i] >= nums[i+1]:
result = [] i -= 1
word_len = len(words[0])
if i != -1: # if any decrease then find the smallest larger number to
for stripe in range(word_len): # each stripe starts at a different position in swap with
s, modulo word_len j = i+1
while j < len(nums) and nums[j] > nums[i]:
i = stripe # the next index in s that we want to match a j += 1
word j -= 1
to_match = len(words) # number of words still to be matched nums[i], nums[j] = nums[j], nums[i]
freq = Counter(words) # frequency of each words to be matched
# reverse all from i+1 onwards since they were decreasing and increasing
while i + to_match*word_len <= len(s): # remainder of s is long enough to minimises permutation
hold remaining unmatched words left = i+1
right = len(nums)-1
word = s[i:i+word_len] # next part of s attempting to be matched while left < right:
if word in freq: # match, decrement freq count nums[left], nums[right] = nums[right], nums[left]
freq[word] -= 1 left += 1
if freq[word] == 0: right -= 1
del freq[word]
to_match -= 1
i += word_len
if to_match == 0: # all matched # python_1_to_1000/032_Longest_Valid_Parentheses.py - h
result.append(i - word_len*len(words))
_author_ = 'jake'
elif to_match != len(words): # some words have been matched _project_ = 'leetcode'
nb_matches = len(words) - to_match
first_word = s[i - nb_matches*word_len:i - (nb_matches-1)*word_len] # https://leetcode.com/problems/longest-valid-parentheses/
freq.setdefault(first_word, 0) # put first word matched back in # Given a string containing just the characters '(' and ')', find the length of the
longest valid (well-formed) parentheses substring.
# For example is ")()())", where the longest valid parentheses substring is "()()", which if nums[left] <= nums[mid]: # LHS is sorted
has length = 4. if target >= nums[left] and target < nums[mid]: # target is on LHS
right = mid - 1
# Maintain a stack of indices in s of unmatched brackets. Pop an opening bracket when else:
matched with a closing bracket. left = mid + 1
# Push unmatched closing brackets and all opening brackets. Then find the longest gap else: # RHS is sorted
between indices on the stack. if target <= nums[right] and target > nums[mid]: # target is on RHS
# Time - O(n) left = mid + 1
# Space - O(n) else:
right = mid - 1
class Solution(object):
def longestValidParentheses(self, s): return -1
"""
:type s: str
:rtype: int
"""
stack = [] # indices of brackets that are not matched
# python_1_to_1000/034_Search_for_a_Range.py - m
for i, c in enumerate(s):
if c == ")" and stack and s[stack[-1]] == '(': _author_ = 'jake'
stack.pop() # close matches an open on the stack _project_ = 'leetcode'
else:
stack.append(i) # puch open brackets or unmatched close brackets # https://leetcode.com/problems/search-for-a-range
# Given a sorted array of integers, find the starting and ending position of a given
stack.append(len(s)) # last unmatched index after end of s target value.
max_length = stack[0] # first unmatched index before start of s # Your algorithm's runtime complexity must be in the order of O(log n).
# If the target is not found in the array, return [-1, -1].
for index in range(1, len(stack)): # find max gap between remaining unmatched
indices # Search for target +/- 0.5 (not integer so not found) and return the index above this.
max_length = max(max_length, stack[index] - stack[index-1] - 1) # If same index is returned for + and - 0.5 then target not found.
# Binary search could be implemented iteratively or use the bisect module.
return max_length # Time - O(log n)
# Space - O(1)

class Solution(object):
def searchRange(self, nums, target):
# python_1_to_1000/033_Search_in_Rotated_Sorted_Array.py - m """
:type nums: List[int]
_author_ = 'jake' :type target: int
_project_ = 'leetcode' :rtype: List[int]
"""
# https://leetcode.com/problems/search-in-rotated-sorted-array/ def binary(target, left, right):
# 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). if left > right:
# You are given a target value to search. If found in the array return its index, return left
otherwise return -1.
# You may assume no duplicate exists in the array. mid = (left + right) // 2
if target > nums[mid]:
# Binary search. If one side is sorted and target is in that region then rescurse on left = mid + 1
that side or else other side. else:
# Time - O(log n), half of the array is eliminated for every recursion. right = mid - 1
# Space - O(1)
return binary(target, left, right)
class Solution(object):
def search(self, nums, target): lower = binary(target - 0.5, 0, len(nums) - 1)
""" upper = binary(target + 0.5, 0, len(nums) - 1)
:type nums: List[int] return [-1, -1] if lower == upper else [lower, upper - 1]
:type target: int
:rtype: int
"""
left, right = 0, len(nums) - 1 # python_1_to_1000/035_Search_Insert_Position.py

while left <= right: _author_ = 'jake'


_project_ = 'leetcode'
mid = (left + right) // 2
# https://leetcode.com/problems/search-insert-position/
if nums[mid] == target: # Given a sorted array and a target value, return the index if the target is found.
return mid # If not, return the index where it would be if it were inserted in order.

# You may assume no duplicates in the array. rows[r].add(digit)


cols[c].add(digit)
# Iterative binary search until left > right or left or right move outside array. boxes[box].add(digit)
# Return left (the greater index), which would be the new index of inserted entry (could
be len(nums) but not -1). return True
# Time - O(log n)
# Space - O(1)
# python_1_to_1000/037_Sudoku_Solver.py - h
class Solution(object):
def searchInsert(self, nums, target): _author_ = 'jake'
""" _project_ = 'leetcode'
:type nums: List[int]
:type target: int # https://leetcode.com/problems/sudoku-solver/
:rtype: int # Write a program to solve a Sudoku puzzle by filling the empty cells.
""" # Empty cells are indicated by the character '.'.
left = 0 # You may assume that there will be only one unique solution.
right = len(nums)
# Convert unknown cells to a set of possible digits, initially {1..9}.
while left <= right and left < len(nums) and right >= 0: # Repeatedly use known cells to eliminate possibilities in unknown cells. Which creates
mid = (left + right) // 2 new known cells etc.
if target == nums[mid]: # If this does not result in a solution, recursively guess each cell from its range of
return mid possibilities.
if target < nums[mid]:
right = mid - 1 class Solution(object):
else: def solveSudoku(self, board):
left = mid + 1 """
:type board: List[List[str]]
return left :rtype: void Do not return anything, modify board in-place instead.
"""
self.size = 9
# python_1_to_1000/036_Valid_Sudoku.py - m self.board = board
self.new_digits = [] # new digits at start or digits found by reducing to
_author_ = 'jake' 1 possibility
_project_ = 'leetcode'
for r in range(self.size):
# https://leetcode.com/problems/valid-sudoku/ self.board[r] = [digit for digit in self.board[r]] # convert from
# Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. string to list of digits
# The Sudoku board could be partially filled, where empty cells are filled with the for c in range(self.size):
character '.'. if self.board[r][c] == '.':
self.board[r][c] = {str(i) for i in range(1, 10)} # convert dot to
# Create a set of digits seen in each row, column and box. False if any duplicates. set of possible digits
# Time - O(n^2) for board of side n else:
# Space - O(n) self.new_digits.append((r, c))

class Solution(object): while self.new_digits:


def isValidSudoku(self, board): for r, c in self.new_digits:
""" self.eliminate(r, c) # given a new digit in (r,c), eliminate that
:type board: List[List[str]] digit from row, col and box
:rtype: bool self.new_digits = []
""" self.find_new() # identify cells with only one possible digit
size = 9
digits = {str(i) for i in range(1,10)} self.solve_recursive()
rows = [set() for _ in range(size)]
cols = [set() for _ in range(size)]
boxes = [set() for _ in range(size)] def eliminate(self, row, col):
for i in range(self.size):
for r in range(size):
for c in range(size): if isinstance(self.board[i][col], set):
self.board[i][col].discard(self.board[row][col]) # discard does not
digit = board[r][c] cause error if element not present
if digit == '.': if isinstance(self.board[row][i], set):
continue self.board[row][i].discard(self.board[row][col])

if digit not in digits: for box_row in range(3*(row//3), 3 + 3*(row//3)):


return False for box_col in range(3*(col//3), 3 + 3*(col//3)):
if isinstance(self.board[box_row][box_col], set):
box = (size//3) * (r // (size//3)) + (c // (size//3)) self.board[box_row][box_col].discard(self.board[row][col])
if digit in rows[r] or digit in cols[c] or digit in boxes[box]:
return False def find_new(self):
for row in range(self.size): if not next or next[-1] != num:
for col in range(self.size): next += [1, num]
if isinstance(self.board[row][col], set) and len(self.board[row][col]) == else:
1: next[-2] += 1
self.board[row][col] = self.board[row][col].pop() sequence = next
self.new_digits.append((row,col))
return "".join(map(str, sequence))

def solve_recursive(self):

for r in range(self.size):
for c in range(self.size): # python_1_to_1000/039_Combination_Sum.py - m

if len(self.board[r][c]) == 1: _author_ = 'jake'


continue _project_ = 'leetcode'
for digit in self.board[r][c]: # loop over possible digits
if self.is_valid(r, c, digit): # will always be valid on first # https://leetcode.com/problems/combination-sum/
recursion # Given a set of candidate numbers (C) and a target number (T), find all unique
save_set = self.board[r][c] combinations in C where the candidate numbers sums to T.
self.board[r][c] = digit # The same repeated number may be chosen from C unlimited number of times.
if self.solve_recursive(): # All numbers (including target) will be positive integers.
return True # The solution set must not contain duplicate combinations.
self.board[r][c] = save_set # revert back
return False # Subtract each candidate from target as many times as possible whilst remainder is non-
return True negative. Recurse
# each time, moving on to the next candidate.
# Time - approx f^n where f is target/average_candidate and n is the number of candidates
def is_valid(self, row, col, digit): # checks whether board is valid after adding with this nb recursions
digit in row, col
for i in range(self.size): # row and column class Solution(object):
if self.board[row][i] == digit or self.board[i][col] == digit: def combinationSum(self, candidates, target):
return False """
:type candidates: List[int]
n = self.size // 3 :type target: int
for r in range(n*(row//n), n + n*(row//n)): # box :rtype: List[List[int]]
for c in range(n*(col//n), n + n*(col//n)): """
if self.board[r][c] == digit: result = []
return False self.helper(candidates, 0, target, [], result)
return True return result

def helper(self, nums, next, target, partial, result):


if target == 0:
# python_1_to_1000/038_Count_and_Say.py - m result.append(partial)
return
_author_ = 'jake' if next == len(nums):
_project_ = 'leetcode' return

# https://leetcode.com/problems/count-and-say/ i = 0
# The count-and-say sequence is the sequence of integers beginning as follows: while target - i * nums[next] >= 0:
# 1, 11, 21, 1211, 111221, ... self.helper(nums, next + 1, target - i * nums[next], partial + [nums[next]] *
# 21 is read off as "one 2, then one 1" or 1211. i, result)
# Given an integer n, generate the nth sequence. i += 1

# 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. # python_1_to_1000/040_Combination_Sum_II.py - m
# Time - O(2^n), the sequence at worst doubles each step
# Space - O(2^n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def countAndSay(self, n): # https://leetcode.com/problems/combination-sum-ii/
""" # Given a collection of candidate numbers (C) and a target number (T), find all unique
:type n: int combinations in C where the candidate numbers sums to T.
:rtype: str # Each number in C may only be used once in the combination.
""" # All numbers (including target) will be positive integers.
sequence = [1] # The solution set must not contain duplicate combinations.
for _ in range(n-1):
next = [] # Count the frequency of each number in candidates. For each number subtract all
for num in sequence: possible numbers of copies up to

# the count and without exceeding target and recurse for the next number. Alternative # If an element of nums is a positive integer that could appear in nums (1 to len(nums)
iterative version below. inclusive) and is not in
# Time - O((f+1)^n) where f is the max frequency of any number and n is the number of # correct place (nums[i] = i+1) then swap.
distinct numbers # Time - O(n)
# Space - O(1)
from collections import Counter
class Solution(object):
class Solution(object): def firstMissingPositive(self, nums):
def combinationSum2(self, candidates, target): """
""" :type nums: List[int]
:type candidates: List[int] :rtype: int
:type target: int """
:rtype: List[List[int]] i = 0
""" while i < len(nums):
results = []
freq = list(Counter(candidates).items()) while nums[i] > 0 and nums[i] <= len(nums) and nums[nums[i]-1] != nums[i]:
self.combos(freq, 0, target, [], results) temp = nums[nums[i]-1]
return results nums[nums[i]-1] = nums[i]
nums[i] = temp
def combos(self, freq, next, target, partial, results):
if target == 0: i += 1
results.append(partial)
return for i, num in enumerate(nums):
if next == len(freq): if nums[i] != i+1:
return return i+1
return len(nums)+1
for i in range(freq[next][1]+1):
if i * freq[next][0] > target:
break
self.combos(freq, next+1, target-i*freq[next][0], partial + [freq[next] # python_1_to_1000/042_Trapping_Rain_Water.py - h
[0]]*i, results)
_author_ = 'jake'
_project_ = 'leetcode'
# Iterative version of same procedure.
class Solution_Iterative(object): # https://leetcode.com/problems/trapping-rain-water/
def combinationSum2(self, candidates, target): # Given n non-negative integers representing an elevation map where the width of each bar
results = [] is 1,
partials = [[]] # compute how much water it is able to trap after raining.
freq = list(Counter(candidates).items())
# Calculate the highest elevation to the right and to the left of every bar. Min of
for candidate, count in freq: these is the max depth of water.
# Subtract the bar height from the max possible depth and floor at zero.
new_partials = [] # Time - O(n)
for partial in partials: # Space - O(n)

partial_sum = sum(partial) class Solution(object):


for i in range(count + 1): def trap(self, height):
if partial_sum + candidate*i < target:
new_partials.append(partial + [candidate]*i) highest_right = [0] * len(height)
elif partial_sum + candidate*i == target: for i in range(len(height)-2, -1, -1):
results.append(partial + [candidate]*i) highest_right[i] = max(highest_right[i+1], height[i+1])
if partial_sum + candidate*i >= target:
break 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
partials = new_partials at 1
highest_left[i] = max(highest_left[i-1], height[i-1])
return results depth += max(0, min(highest_left[i], highest_right[i]) - height[i])

return depth
# python_1_to_1000/041_First_Missing_Positive.py - h

_author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/first-missing-positive/
# Given an unsorted integer array, find the first missing positive integer. # python_1_to_1000/043_Multiply_Strings.py - m
# e.g. given [1,2,0] return 3, and [3,4,-1,1] return 2.
# Your algorithm should run in O(n) time and uses constant space _author_ = 'jake'
_project_ = 'leetcode'
repeatedly backtrack
# https://leetcode.com/problems/multiply-strings/ # Space - O(1)
# Given two numbers represented as strings, return multiplication of the numbers as a
string. class Solution(object):
# The numbers can be arbitrarily large and are non-negative. def isMatch(self, s, p):
# Converting the input string to integer is NOT allowed.
# You should NOT use internal library such as BigInteger. i, j = 0, 0 # next indices to be matched in s and p
star = -1 # last index in p of *
# Create a list of each digit in the result, starting wiht the least significant digit.
# Reverse input digit order. nums1[i] * nums2[j] is added to result[i+j+1] and while i < len(s):
result[i+j]
# Alternatively: return str(int(num1) * int(num2)) # if beyond end of pattern or pattern is unmatched letter
# Time - O(m * n) where inputs are of lengths m and n if j >= len(p) or (p[j] not in {'*' , '?'} and p[j] != s[i]):
# Space - O(max(m,n)) if star == -1: # no flexibility if no star
return False
class Solution(object): j = star + 1 # reset p to character after star
def multiply(self, num1, num2): star_i += 1 # reset s to charcater after star_i, i.e. use * to
""" match one char from s
:type num1: str i = star_i
:type num2: str
:rtype: str elif p[j] == '*': # record * index in p and next index to be matched in
""" s
num1, num2 = num1[::-1], num2[::-1] # easier to work with lowest digits star = j
first star_i = i
result = [0] * (len(num1) + len(num2)) j += 1

else: # chars match or ?, increment both


for i in range(len(num1)): i += 1
j += 1
int1 = ord(num1[i]) - ord('0')
while j < len(p): # any remaining characters in p can only be *
for j in range(len(num2)): if p[j] != '*':
return False
int2 = ord(num2[j]) - ord('0') j += 1
return True
tens, units = divmod(int1 * int2, 10)

result[i + j] += units # add units and handle carry of units


if result[i + j] > 9:
result[i + j + 1] += result[i + j] // 10 # python_1_to_1000/045_Jump_Game_II.py - m
result[i + j] %= 10
_author_ = 'jake'
result[i + j + 1] += tens # add tens and handle carry of tens _project_ = 'leetcode'
if result[i + j + 1] > 9:
result[i + j + 2] += result[i + j + 1] // 10 # https://leetcode.com/problems/jump-game-ii/
result[i + j + 1] %= 10 # Given an array of non-negative integers, you are initially positioned at the first
index of the array.
while len(result) > 1 and result[-1] == 0: # remove trailing zeros # Each element in the array represents your maximum jump length at that position.
result.pop() # Your goal is to reach the last index in the minimum number of jumps.
return "".join(map(str, result[::-1])) # reverse and convert to string # 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.)
# You can assume that you can always reach the last index.

# For each index in currently accessible range, update the max_index that can be reached
# python_1_to_1000/044_Wildcard_Matching.py - m in one more step.
# Iterate to next range, from end of previous range to max_index.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/wildcard-matching/ class Solution(object):


# Implement wildcard pattern matching with support for '?' and '*'. def jump(self, nums):
# '?' Matches any single character. """
# '*' Matches any sequence of characters (including the empty sequence). :type nums: List[int]
# The matching should cover the entire input string (not partial). :rtype: int
"""
# Record index in p of star and index in s at that time. Try to match without star, if if len(nums) == 1:
fails back up and use * return 0
# to match one more character from s.
# Time - O(m * n), * at beginning of p could match many chars in s before failing and start, end = 0, 0 # indices in nums of current range

max_index = 0
steps = 1

while True: # will always terminate since last index is accessible


for i in range(start, end+1):
max_index = max(max_index, i + nums[i])
if max_index >= len(nums)-1: # python_1_to_1000/047_Permutations_II.py - m
return steps
steps += 1 _author_ = 'jake'
start, end = end + 1, max_index _project_ = 'leetcode'

# https://leetcode.com/problems/permutations-ii/
# Given a collection of numbers that might contain duplicates, return all possible unique
permutations.
# python_1_to_1000/046_Permutations.py - m
# Count occurences of each unique number. Recursively append each number if still has a
_author_ = 'jake' positive count.
_project_ = 'leetcode' # Time - O(n^2 * n!), as 046_Permutations if all numbers are unique
# Space - O(n * n!)
# https://leetcode.com/problems/permutations/
# Given a collection of distinct numbers, return all possible permutations. from collections import Counter

# For each number, insert it at all possible places in all existing permutations. class Solution(object):
# Alternatively recursively swap every index with every greater index (and itself). def permuteUnique(self, nums):
# Time - O(n^2 * n!). n! results, each of with has n elements added, each addition """
taking O(n) time for list slicing :type nums: List[int]
# Space - O(n *n!) :rtype: List[List[int]]
"""
class Solution(object): freq = Counter(nums)
def permute(self, nums): permutations = []
""" self.permute_helper(len(nums), [], freq, permutations)
:type nums: List[int] return permutations
:rtype: List[List[int]]
""" def permute_helper(self, to_add, partial, freq, permutations):
permutations = [[]] if to_add == 0:
permutations.append(partial)
for num in nums:
new_permutations = [] for item in freq:
for perm in permutations: if freq[item] > 0:
for i in range(len(perm) + 1): freq[item] -= 1
new_permutations.append(perm[:i] + [num] + perm[i:]) self.permute_helper(to_add-1, partial + [item], freq, permutations)
permutations = new_permutations freq[item] += 1

return permutations

class Solution2(object): # python_1_to_1000/048_Rotate_Image.py - m


def permute(self, nums):
""" _author_ = 'jake'
:type nums: List[int] _project_ = 'leetcode'
:rtype: List[List[int]]
""" # https://leetcode.com/problems/rotate-image/
return self.permute_helper(nums, 0) # You are given an n x n 2D matrix representing an image.
# Rotate the image by 90 degrees (clockwise).
def permute_helper(self, nums, index):
# Number of layer to rotate is n//2. For each item along the top side of each layer,
permutations = [] save as temp and
# move in the item from the next side, repeating until temp is put into the last side.
if index >= len(nums): # Alternatively - matrix[:] = list(map(list, zip(*matrix[::-1]))). Reverse the order of
permutations.append(nums[:]) # make a new copy to freeze nums row, unpack,
# zip and convert back to lists.
for i in range(index, len(nums)): # Time - O(n^2)
nums[i], nums[index] = nums[index], nums[i] # swap with all indices >= # Space - O(1)
index
permutations += self.permute_helper(nums, index + 1) class Solution(object):
nums[i], nums[index] = nums[index], nums[i] # swap back def rotate(self, matrix):
"""
return permutations :type matrix: List[List[int]]
:rtype: void Do not return anything, modify matrix in-place instead.
""" return 1/pos_result if neg else pos_result
n = len(matrix)
layers = n//2 def pos_pow(self, x, n):
if n == 0:
for layer in range(layers): return 1
for i in range(layer, n - layer - 1):
temp = matrix[layer][i] temp = self.pos_pow(x, n//2)
matrix[layer][i] = matrix[n - 1 - i][layer] temp *= temp
matrix[n - 1 - i][layer] = matrix[n - 1 - layer][n - 1- i]
matrix[n - 1 - layer][n - 1 - i] = matrix[i][n - 1 - layer] return temp if n % 2 == 0 else temp * x
matrix[i][n - 1 - layer] = temp

# python_1_to_1000/051_N-Queens.py - h
# python_1_to_1000/049_Group_Anagrams.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/n-queens/
# https://leetcode.com/problems/anagrams/ # The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that
# Given an array of strings, group anagrams together. no two queens attack each other.
# Given an integer n, return all distinct solutions to the n-queens puzzle.
# Sort the letters in each word. Use sorted words as dictionary keys, values are # Each solution contains a distinct board configuration of the n-queens' placement,
unsorted words. # where 'Q' and '.' both indicate a queen and an empty space respectively.
# Anagrams have equivalent sorted words.
# Time - O(k log k * n) for n words of length k # For each column, place a queen in each possible row that does not conflict with an
# Space - O(k * n) existing queen.
# Time - O(n^2 * n!), n possible rows for first col, n-1 for second ... etc. each result
from collections import defaultdict size n^2
# Space - O(n^2 * n!)
class Solution(object):
def groupAnagrams(self, strs): class Solution(object):
""" def solveNQueens(self, n):
:type strs: List[str] """
:rtype: List[List[str]] :type n: int
""" :rtype: List[List[str]]
sorted_words = defaultdict(list) """
partials = [[]] # solutions up to current row
for word in strs: for col in range(n):
letter_list = [c for c in word] new_partials = []
letter_list.sort() for partial in partials:
sorted_word = "".join(letter_list) for row in range(n):
sorted_words[sorted_word].append(word) if not self.conflict(partial, row):
new_partials.append(partial + [row])
return list(sorted_words.values()) partials = new_partials

results = []
# python_1_to_1000/050_Power_Function.py - m for partial in partials: # convert result to strings
result = [['.'] * n for _ in range(n)]
_author_ = 'jake' for col, row in enumerate(partial):
_project_ = 'leetcode' result[row][col] = 'Q'
for row in range(n):
# https://leetcode.com/problems/powx-n/ result[row] = ''.join(result[row])
# Implement pow(x, n). results.append(result)

# Recursively calculate (pow(x, n//2))^2 if n is even or with additional factor of x if n return results
is odd.
# Time - O(log n) def conflict(self, partial, new_row):
# Space - O(log n) for col, row in enumerate(partial):
if new_row == row: # same row
class Solution(object): return True
def myPow(self, x, n): col_diff = len(partial) - col
""" if abs(new_row - row) == col_diff: # same diagonal
:type x: float return True
:type n: int
:rtype: float return False
"""
neg = n < 0
pos_result = self.pos_pow(x, abs(n))

# python_1_to_1000/052_N-Queens_II.py - h max_ending_here = num


overall_max = max(overall_max, max_ending_here)
_author_ = 'jake'
_project_ = 'leetcode' return overall_max

# https://leetcode.com/problems/n-queens-ii/
# Follow up for N-Queens problem. # python_1_to_1000/054_Spiral_Matrix.py - m
# Now, instead outputting board configurations, return the total number of distinct
solutions. _author_ = 'jake'
_project_ = 'leetcode'
# As for N-Queens except just count solutions instead of converting to boards.
# Time - O(n!) # https://leetcode.com/problems/spiral-matrix/
# Space - O(n!) # Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix
in spiral order.
class Solution(object):
def totalNQueens(self, n): # Use row_leg and col_leg to traxk the max number of moves before turning. Decrease
""" row_leg and col_leg then turning.
:type n: int # Time - O(m * n)
:rtype: List[List[str]] # Space - O(1)
"""
partials = [[]] class Solution(object):
for col in range(n): def spiralOrder(self, matrix):
new_partials = [] """
for partial in partials: :type matrix: List[List[int]]
for row in range(n): :rtype: List[int]
if not self.conflict(partial, row): """
new_partials.append(partial + [row]) if not matrix or not matrix[0]:
partials = new_partials return []

return len(partials) spiral = []


row, col = 0, -1
def conflict(self, partial, new_row): d_row, d_col = 0, 1 # movement direction
for col, row in enumerate(partial): row_leg, col_leg = len(matrix[0]), len(matrix)-1 # steps before change of
if new_row == row: direction
return True leg_count = 0 # count of steps in current
col_diff = len(partial) - col direction
if row + col_diff == new_row or row - col_diff == new_row:
return True for _ in range(len(matrix[0]) * len(matrix)):
return False
row += d_row
col += d_col
# python_1_to_1000/053_Maximum_Subarray.py - m spiral.append(matrix[row][col])
leg_count += 1
_author_ = 'jake'
_project_ = 'leetcode' # change direction
if (d_col != 0 and leg_count == row_leg) or (d_row != 0 and leg_count ==
# https://leetcode.com/problems/maximum-subarray/ col_leg):
# Find the contiguous subarray within an array (containing at least one number) which has if d_col != 0:
the largest sum. row_leg -= 1
else:
# For each num calculate the max subarray sum ending with that num as either num alone col_leg -= 1
(if previous sum was -ve) or d_row, d_col = d_col, -d_row
# num + previous sum (if previous sum was +ve) leg_count = 0
# Time - O(n)
# Space - O(1) return spiral

class Solution(object):
def maxSubArray(self, nums):
""" # python_1_to_1000/055_Jump_Game.py - m
:type nums: List[int]
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
overall_max = float('-inf')
max_ending_here = 0 # https://leetcode.com/problems/jump-game/
# Given an array of non-negative integers, you are initially positioned at the first
for num in nums: index of the array.
if max_ending_here > 0: # Each element in the array represents your maximum jump length at that position.
max_ending_here += num # Determine if you are able to reach the last index.
else:
# Record the maximum index that can be reached. Initially this is index 0. # Time - O(n)
# Iterate through nums, returning False an index cannot be reached. # Space - O(1)
# Else update the maximum index with the current index + its value (the maximum jump).
# Time - O(n) class Solution(object):
# Space - O(1) def insert(self, intervals, newInterval):
"""
class Solution(object): :type intervals: List[List[int]]
def canJump(self, nums): :type newInterval: List[int]
""" :rtype: List[List[int]]
:type nums: List[int] """
:rtype: bool left, right = 0, len(intervals) - 1
""" while left < len(intervals) and intervals[left][1] < newInterval[0]:
max_index = 0 left += 1

for i, num in enumerate(nums): while right >= 0 and intervals[right][0] > newInterval[1]:
if i > max_index: right -= 1
return False
max_index = max(max_index, i + num) if left <= right:
newInterval[0] = min(newInterval[0], intervals[left][0])
return True newInterval[1] = max(newInterval[1], intervals[right][1])

return intervals[:left] + [newInterval] + intervals[right + 1:]

# python_1_to_1000/056_Merge_Intervals.py - m

_author_ = 'jake' # python_1_to_1000/058_Length_of_Last_Word.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/merge-intervals/ _project_ = 'leetcode'
# Given a collection of intervals, merge all overlapping intervals.
# https://leetcode.com/problems/length-of-last-word/
# Sort intervals by start points. If interval starts before previous interval ends then # Given a string s consists of upper/lower-case alphabets and empty space characters ' ',
merge, else add to result. # return the length of last word in the string.
# Time - O(n log n) # If the last word does not exist, return 0.
# Space - O(1) # Note: A word is defined as a character sequence consists of non-space characters only.

class Solution(object): # Start at last character and decrement i.


def merge(self, intervals): # Set variable end when non-blank is seen.
""" # Return at next non-blank.
:type intervals: List[Interval] # Time - O(n)
:rtype: List[Interval] # Space - O(1)
"""
intervals.sort(key=lambda x : x[0]) class Solution(object):
merged = [] def lengthOfLastWord(self, s):
"""
for interval in intervals: :type s: str
if not merged or merged[-1][1] < interval[0]: :rtype: int
merged.append(interval) """
else: i = len(s) - 1
merged[-1][1] = max(merged[-1][1], interval[1]) end = -1
return merged
while i >= 0:
if s[i] == ' ' and end != -1:
return end - i
# python_1_to_1000/057_Insert_Intervals.py - m if s[i] != ' ' and end == -1:
end = i
_author_ = 'jake' i -= 1
_project_ = 'leetcode' return end + 1 if end != -1 else 0

# https://leetcode.com/problems/insert-interval/
# Given a set of non-overlapping intervals, insert a new interval into the intervals
(merge if necessary). # python_1_to_1000/059_Spiral_Matrix_II.py - m
# You may assume that the intervals were initially sorted according to their start times.
_author_ = 'jake'
# Find all intervals strictly to the left and to the right of new interval. If any _project_ = 'leetcode'
intervals in between they
# overlap with newInterval. If any overlap, update start of newInterval with start of # https://leetcode.com/problems/spiral-matrix-ii/
first overlap and # Given an integer n, generate a square matrix filled with elements from 1 to n**2 in
# update end with end of last overlap. spiral order.

n -= 1
# Change direction clockwise when edge of matrix or non-zero cell is reached.
# Time - O(n**2) return "".join(result)
# Space - O(n**2)

class Solution(object):
def generateMatrix(self, n): # python_1_to_1000/061_Rotate_List.py - m
"""
:type n: int _author_ = 'jake'
:rtype: List[List[int]] _project_ = 'leetcode'
"""
spiral = [[0 for _ in range(n)] for _ in range(n)] # https://leetcode.com/problems/rotate-list/
row, col = 0, 0 # Given a list, rotate the list to the right by k places, where k is non-negative.
d_r, d_c = 0, 1
# Count length of list, reset k to k % length (avoids repeated cycles). Connect tail of
count = 1 list with head and then
while count <= n*n: # break k%length steps before the old tail.
spiral[row][col] = count # Time - O(n), n is length of list
count += 1 # Space - O(1)
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: # Definition for singly-linked list.
d_r, d_c = d_c, -d_r class ListNode(object):
row += d_r def __init__(self, x):
col += d_c self.val = x
self.next = None
return spiral
class Solution(object):
def rotateRight(self, head, k):
"""
# python_1_to_1000/060_Permutation_Sequence.py - h :type head: ListNode
:type k: int
_author_ = 'jake' :rtype: ListNode
_project_ = 'leetcode' """
if not head:
# https://leetcode.com/problems/permutation-sequence/ return
# The set [1,2,3,…,n] contains a total of n! unique permutations.
# By listing and labeling all of the permutations in order, we get the following sequence count = 1
(ie, for n = 3): node = head
# "123", "132", "213", "231", "312", "321"
# Given n and k, return the kth permutation sequence. while node.next:
node = node.next
# Find each digit according to the ratio between k and the total number of possible count += 1
permutations. node.next = head # connect tail to head
# Time - O(n**2) since each iteration adds one digit and O9n) for del from list
# Space - O(n) to store chars list to_move = count - (k % count) #nb steps to move node before breaking
while to_move > 0:
from math import factorial node = node.next
to_move -= 1
class Solution(object): head = node.next # new head
def getPermutation(self, n, k): node.next = None
"""
:type n: int return head
:type k: int
:rtype: str
""" # python_1_to_1000/062_Unique_Paths.py - m
chars = [str(i) for i in range(1, n+1)] # the symbols that will be permuted
permutations = factorial(n) # total number of permutations for _author_ = 'jake'
this n _project_ = 'leetcode'
k -= 1 # change indexing to 0
result = [] # https://leetcode.com/problems/unique-paths/
# A robot is located at the top-left corner of a m x n grid.
while chars: # The robot can only move either down or right at any point in time.
digit = n * k // permutations # get the first digit (range is 0 to # The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in
n-1) the diagram below).
result.append(chars[digit]) # map from digit to a symbol # How many possible unique paths are there?
del chars[digit] # remove that symbol
permutations //= n # repeat for next digit with # Dynamic programming, nb paths = paths from above cell + paths from right cell
decreased permutations, n and k # Alternatively, catalan number.
k -= digit * permutations # Time - O(m * n)
# Space - O(n), just keep last row instead of entire grid

class Solution(object): # python_1_to_1000/064_Minimum_Path_Sum.py - m


def uniquePaths(self, m, n):
""" _author_ = 'jake'
:type m: int cols _project_ = 'leetcode'
:type n: int rows
:rtype: int # https://leetcode.com/problems/minimum-path-sum/
""" # Given a m x n grid filled with non-negative numbers, find a path from top left to
if m == 0 or n == 0: bottom right which minimizes
return 0 # the sum of all numbers along its path.
# Note: You can only move either down or right at any point in time.
row_paths = [1 for _ in range(n)] # first row, one path to each column
# Dynamic programming, min path to a cell = cell value + min(min paths to cells above and
for row in range(m-1): left)
new_row_paths = [1] # one path to first col of each row # Time - O(m * n)
for col in range(1, n): # Space - O(n)
new_row_paths.append(new_row_paths[-1] + row_paths[col])
row_paths = new_row_paths class Solution(object):
def minPathSum(self, grid):
return row_paths[-1] """
:type grid: List[List[int]]
:rtype: int
"""
# python_1_to_1000/063_Unique_Paths_II.py - m m = len(grid)
n = len(grid[0])
_author_ = 'jake'
_project_ = 'leetcode' min_path = [float('inf') for _ in range(n + 1)]
min_path[1] = 0
# https://leetcode.com/problems/unique-paths-ii/
# Follow up for "Unique Paths": for row in range(1, m + 1):
# Now consider if some obstacles are added to the grids. How many unique paths would new_min_path = [float('inf') for _ in range(n + 1)]
there be? for col in range(1, n + 1):
# An obstacle and empty space is marked as 1 and 0 respectively in the grid. new_min_path[col] = grid[row - 1][col - 1] + min(min_path[col],
new_min_path[col - 1])
# Dynamic programming. Nb paths is 0 if obstacle, else paths from above + paths from min_path = new_min_path
left.
# Time - O(m * n) return min_path[-1]
# Space - O(n)

class Solution(object): # python_1_to_1000/065_Valid_Number.py - h


def uniquePathsWithObstacles(self, obstacleGrid):
""" _author_ = 'jake'
:type obstacleGrid: List[List[int]] _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/valid-number/
m = len(obstacleGrid) # Validate if a given string is numeric.
n = len(obstacleGrid[0]) # Note: It is intended for the problem statement to be ambiguous. You should gather all
requirements up front before implementing one.
if not m or not n:
return 0 # Test if integer or float or scientific. Allow for first character signs.
if obstacleGrid[0][0] or obstacleGrid[-1][-1]: # Time - O(n)
return 0 # Space - O(n)

row_paths = [0 for _ in range(n+1)] class Solution(object):


row_paths[1] = 1 def isNumber(self, s):
self.digits = {str(i) for i in range(10)}
for row in range(1, m+1): s = [c for c in s.strip().lower()]
new_row_paths = [0] if not s:
for col in range(1, n+1): return False
if obstacleGrid[row-1][col-1]: return self.is_int(s, True) or self.is_float(s) or self.is_sci(s)
new_row_paths.append(0)
else:
new_row_paths.append(new_row_paths[-1] + row_paths[col]) def is_int(self, s, signed):
row_paths = new_row_paths if len(s) == 0:
return False
return row_paths[-1] if s[0] == '-' and signed:
s = s[1:]
elif s[0] == '+' and signed:

s = s[1:] return digits[:i] + [digits[i]+1] + digits[i+1:]


if len(s) == 0:
return False

for c in s: # python_1_to_1000/067_Add_Binary.py
if c not in self.digits:
return False _author_ = 'jake'
return True _project_ = 'leetcode'

# https://leetcode.com/problems/add-binary/
def is_float(self, s): # Given two binary strings, return their sum (also a binary string).
try:
dot = s.index('.') # Starting with least significant digits, add digits. Reverse result string.
before = s[:dot] # Time - O(max(m, n))
after = s[dot+1:] # Space - O(1)

if before and before[0] in '+-': class Solution(object):


before = before[1:] def addBinary(self, a, b):
if before and not self.is_int(before, False): """
return False :type a: str
if after and not self.is_int(after, False): :type b: str
return False :rtype: str
return before or after """
except: result = []
return False carry = 0
i = len(a)-1
j = len(b)-1
def is_sci(self, s):
try: while carry or i >= 0 or j >= 0:
e = s.index('e')
before = s[:e] total = carry
after = s[e+1:] if i >= 0:
total += int(a[i])
if not before or not after: i -= 1
return False if j >= 0:
if not self.is_int(before, True) and not self.is_float(before): total += int(b[j])
return False j -= 1
return self.is_int(after, True) result.append(str(total % 2))
except: carry = total // 2
return False
return "".join(result[::-1])

# python_1_to_1000/066_Plus_One.py

_author_ = 'jake' # python_1_to_1000/068_Text_Justification.py - h


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/plus-one/ _project_ = 'leetcode'
# Given a non-negative number represented as an array of digits, plus one to the number.
# The digits are stored such that the most significant digit is at the head of the list. # https://leetcode.com/problems/text-justification/
# Given an array of words and a length L, format the text such that each line has exactly
# Starting from least significant digit, replace with zeros until we find the first non L characters and is fully (left and right) justified.
9, which is incremented. # Pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that
# Time - O(n) each line has exactly L characters.
# Space - O(1) # 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
class Solution(object): on the left will be assigned more spaces than the slots on the right.
def plusOne(self, digits): # For the last line of text, it should be left justified and no extra space is inserted
""" between words.
:type digits: List[int] # Each word is guaranteed not to exceed L in length.
:rtype: List[int]
""" # Fill lines with words and single spaces until full. Then justify by distributing
i = len(digits)-1 remaining spaces
while i >= 0 and digits[i] == 9: # Time - O(maxWidth * nb_lines)
digits[i] = 0 # Space - O(maxWidth * nb_lines)
i -= 1
class Solution(object):
if i == -1: def fullJustify(self, words, maxWidth):
return [1] + digits """
:type words: List[str] """
:type maxWidth: int guess = x
:rtype: List[str] while guess * guess > x:
""" guess = (guess + x // guess) // 2
line_chars = 0 # number of chars on current line (without spaces) return guess
line_words = [] # list of words on current line
justified = [] # output, list of justified strings

for word in words:


# python_1_to_1000/070_Climbing_Stairs.py
if line_chars + len(line_words) + len(word) <= maxWidth: # add word to
current line _author_ = 'jake'
line_words.append(word) _project_ = 'leetcode'
line_chars += len(word)
# https://leetcode.com/problems/climbing-stairs/
else: # word cannot be added to current # You are climbing a stair case. It takes n steps to reach to the top.
line # Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to
gaps = len(line_words) - 1 # nb gaps between words the top?
spaces = maxWidth - line_chars # nb of spaces to make line maxWidth
line = [line_words[0]] # list of words and spaces # Dynamic programming. Base cases of no ways for n <= 0, 1 way for n == 1 and 2 ways for
if gaps == 0: # pad end if single word n == 2.
line.append(" " * spaces) # For each additional step, the number of ways is taking one step from the previous step
+ taking two steps from the
for line_word in line_words[1:]: # distribute spaces between other # step before that. Result is a Fibonacci sequence.
words # Time - O(n)
space = spaces//gaps # Space - O(1)
if spaces % gaps != 0: # round up if uneven division of
spaces class Solution(object):
space += 1 def climbStairs(self, n):
line.append(" " * space) # add space """
spaces -= space # reduce remaining spaces and gaps :type n: int
gaps -= 1 :rtype: int
line.append(line_word) """
if n <= 0:
justified.append("".join(line)) return 0
if n <= 2:
line_words = [word] # add word to next line. return n
line_chars = len(word)
stairs, prev = 2, 1 # 2 ways to reach second step, one way to reach first
final_line = " ".join(line_words) # pad final line with spaces for _ in range(3, n + 1):
final_line += " " * (maxWidth - len(final_line)) stairs, prev = stairs + prev, stairs
justified.append(final_line)
return stairs
return justified

# python_1_to_1000/071_Simplify_Path.py - m
# python_1_to_1000/069_Sqrt(x).py
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/simplify-path/
# https://leetcode.com/problems/sqrtx/ # Given an absolute path for a file (Unix-style), simplify it.
# Implement int sqrt(int x).
# Compute and return the square root of x. # Create result stack. Go up a level if '..'. Stay at same level if '.'.
# Time - O(n)
# Newton method. Initial guess of x. Iteratively update guess to be average of previous # Space - O(n)
guess and x // guess.
# Since guess is too high, x // guess is too low. class Solution(object):
# Terminate when guess^2 <= x. def simplifyPath(self, path):
# Time - O((log x)^3) - log x from nb iterations, log x from multiple and log x from """
divide :type path: str
# Space - O(1) :rtype: str
"""
class Solution(object): path_list = path.split('/') # does not treat consecutive delimiters as one if
def mySqrt(self, x): delimiter specified
""" result = []
:type x: int
:rtype: int for item in path_list:

if item == '..': # go up one level if possible # Record whether first row and forst col contains zero. Then use first for and first col
if result: to flag whether body of
result.pop() # matrix contains a zero in that row or col.
elif item and item != '.': # add item to path # Time - O(m * n)
result.append(item) # Space - O(1)
# else ignore '.' and ''
class Solution(object):
return '/' + '/'.join(result) def setZeroes(self, matrix):
"""
:type matrix: List[List[int]]
# python_1_to_1000/072_Edit_Distance.py - m :rtype: void Do not return anything, modify matrix in-place instead.
"""
_author_ = 'jake' if not matrix or not matrix[0]:
_project_ = 'leetcode' return 0

# https://leetcode.com/problems/edit-distance/ rows = len(matrix)


# Given two words word1 and word2, find the minimum number of steps required to convert cols = len(matrix[0])
word1 to word2.
# You have the following 3 operations permitted on a word (each 1 step): first_row_zero = any([True for c in range(cols) if matrix[0][c] == 0])
# a) Insert a character first_col_zero = any([True for r in range(rows) if matrix[r][0] == 0])
# b) Delete a character
# c) Replace a character for r in range(1, rows):
for c in range(1, cols):
# Dynamic programming. Base case if either string is empty, return unmatched length of if matrix[r][c] == 0:
other string. matrix[r][0] = 0
# If last characters matched then same cost as matching other characters. Else best case matrix[0][c] = 0
of insert, delete or replace.
# Time - O(m * n) for r in range(1, rows):
# Space - O(m * n) if matrix[r][0] == 0:
for c in range(1, cols):
class Solution(object): matrix[r][c] = 0
def minDistance(self, word1, word2):
""" for c in range(1, cols):
:type word1: str if matrix[0][c] == 0:
:type word2: str for r in range(1, rows):
:rtype: int matrix[r][c] = 0
"""
if first_row_zero:
def edit_distance(i, j): matrix[0] = [0] * cols
if i < 0 or j < 0: if first_col_zero:
return i + 1 + j + 1 for r in range(rows):
matrix[r][0] = 0
if (i, j) in memo:
return memo[(i, j)]

if word1[i] == word2[j]: # python_1_to_1000/074_Search_a_2D_Matrix.py - m


result = edit_distance(i - 1, j - 1)
else: _author_ = 'jake'
result = 1 + min(edit_distance(i - 1, j), _project_ = 'leetcode'
edit_distance(i, j - 1),
edit_distance(i - 1, j - 1)) # https://leetcode.com/problems/search-a-2d-matrix/
# Write an efficient algorithm that searches for a value in an m x n matrix. This matrix
memo[(i, j)] = result has the following properties:
return result # Integers in each row are sorted from left to right.
# The first integer of each row is greater than the last integer of the previous row.
memo = {}
return edit_distance(len(word1) - 1, len(word2) - 1) # Treat the 2-d matrix as a 1-d list of length rows * cols. Binary search indices from 0
to rows * cols - 1.
# Time - O(log m + log n)
# Space - O(1)
# python_1_to_1000/073_Set_Matrix_Zeroes.py - m
class Solution(object):
_author_ = 'jake' def searchMatrix(self, matrix, target):
_project_ = 'leetcode' """
:type matrix: List[List[int]]
# https://leetcode.com/problems/set-matrix-zeroes/ :type target: int
# Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in :rtype: bool
place. """
if not matrix or not matrix[0]:
return False # https://leetcode.com/problems/minimum-window-substring/
# Given a string S and a string T, find the minimum window in S which will contain all
rows, cols = len(matrix), len(matrix[0]) the characters in T in complexity O(n).
low, high = 0, rows * cols - 1 # If there is no such window in S that covers all characters in T, return the empty
string "".
while high >= low: # If there are multiple such windows, you are guaranteed that there will always be only
one unique minimum window in S.
mid = (high + low) // 2
value = matrix[mid // cols][mid % cols] # convert mid to a row and column # Slide end of window forwards when not all letters in t are matched with window. Slide
start of window when all
if target == value: # letters are matched. Maintain the required count of each letter (can be negative if
return True excess) and overall to_match.
if target > value: # Time - O(n)
low = mid + 1 # Space - O(1)
else:
high = mid - 1 from collections import Counter

return False class Solution(object):


def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
# python_1_to_1000/075_Sort_Colors.py - m """
freq = Counter(t)
_author_ = 'jake' best_start, best_end = 0, float('inf')
_project_ = 'leetcode' start, end = 0, -1 # first and last indices of window in s
to_match = len(t)
# https://leetcode.com/problems/sort-colors/
# Given an array with n objects colored red, white or blue, sort them so that objects of while end < len(s)-1 or to_match == 0: # can extend end or all matched so
the same color are adjacent, will increase start
# 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 if to_match != 0: # not all matched, extend end
respectively. end += 1
if s[end] in freq: # reduce count, can be negative
# Overwrite each index with blue. If index was red or white, add a new white and freq[s[end]] -= 1
increment white pointer. If index if freq[s[end]] >= 0: # reduce to_match if count not negative
# was red, add a new red and increment red pointer. to_match -= 1
# Time - O(n)
# Space - O(1) else: # all matched, check if new min window, increment
start
class Solution(object): if end - start < best_end - best_start:
def sortColors(self, nums): best_end = end
""" best_start = start
:type nums: List[int] if s[start] in freq: # add start letter back to count
:rtype: void Do not return anything, modify nums in-place instead. freq[s[start]] += 1
""" if freq[s[start]] > 0:
next_red, next_white = 0, 0 to_match += 1 # increment to_match if positive count
start += 1
for i in range(len(nums)):
if best_end == float('inf'):
colour = nums[i] return ''
nums[i] = 2 return s[best_start:best_end+1]

if colour < 2:
nums[next_white] = 1
next_white += 1 # python_1_to_1000/077_Combinations.py - m

if colour == 0: _author_ = 'jake'


nums[next_red] = 0 _project_ = 'leetcode'
next_red += 1
# https://leetcode.com/problems/combinations/
# Given two integers n and k, return all possible combinations of k numbers out of 1 ...
n.
# python_1_to_1000/076_Maximum_Window_Substring.py - h
# Recursively ignore the last number and choose k form n-1, or use the last number and
_author_ = 'jake' combine with k-1 from n-1.
_project_ = 'leetcode' # Time - O(k * n! / (k! * (n-k)!)), nCk combinations each of length k
# Space - O(k * n! / (k! * (n-k)!))

# or vertically neighboring. The same letter cell may not be used more than once.
class Solution(object):
def combine(self, n, k): # For each starting position, depth first search moving in all 4 directions and marking
""" visited cells.
:type n: int # Time - O(m * n * s), for each starting board position, try upto s characters
:type k: int # Space - O(1)
:rtype: List[List[int]]
""" class Solution(object):
if k == 0: # or if k == 1 return [[i] for i in range(1,n+1)] def exist(self, board, word):
return [[]] """
if n < k: # or if k == n return [[i for i in range(1,n+1)]] :type board: List[List[str]]
return [] :type word: str
:rtype: bool
without_last = self.combine(n-1, k) """
if not board or not board[0]:
with_last = [[n] + combo for combo in self.combine(n-1, k-1)] return False
rows, cols = len(board), len(board[0])
return with_last + without_last
for r in range(rows):
for c in range(cols):
if self.can_find(word, 0, board, r, c):
return True
# python_1_to_1000/078_Subsets.py - m return False

_author_ = 'jake'
_project_ = 'leetcode' def can_find(self, word, i, board, r, c):

# https://leetcode.com/problems/subsets/ if i >= len(word): # nothing more of word to find


# Given a set of distinct integers, nums, return all possible subsets. return True
# The solution set must not contain duplicate subsets. if r < 0 or r >= len(board) or c < 0 or c >= len(board[0]): # outside board
return False
# Each bit of binary number form 0 to 2**n - 1 represents whether or not an entry in nums if word[i] != board[r][c]: # no match letter
is in that set. return False
# Alternatively, copy partial subsets both with and without each item.
# Time - O(n * 2**n), 2**n subsets each of length n. board[r][c] = '*' # set this position so cannot be used again
# Space - O(n * 2**n)
if (self.can_find(word, i+1, board, r+1, c) or self.can_find(word, i+1, board, r-
class Solution(object): 1, c) or
def subsets(self, nums): self.can_find(word, i+1, board, r, c+1) or self.can_find(word, i+1,
""" board, r, c-1)):
:type nums: List[int] return True
:rtype: List[List[int]]
""" board[r][c] = word[i] # if False, reset position to letter
nb_subsets = 2**len(nums) return False
all_subsets = []

for subset_nb in range(nb_subsets):


# python_1_to_1000/080_Remove_Duplicates_from_Sorted_Array_II.py - m
subset = []
for num in nums: _author_ = 'jake'
if subset_nb % 2 == 1: _project_ = 'leetcode'
subset.append(num)
subset_nb //= 2 # https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/
# Follow up for "Remove Duplicates":
all_subsets.append(subset) # What if duplicates are allowed at most twice?
# For example, given sorted array nums = [1,1,1,2,2,3],
return all_subsets # Your function should return length = 5, with the first five elements of nums being 1,
1, 2, 2 and 3.

# Maintain a pointer to the next index to contain a result. If a new number does not
# python_1_to_1000/079_Word_Search.py - m have 2 copies already
# in result then add it.
_author_ = 'jake' # Time - O(2)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/word-search/ class Solution(object):


# Given a 2D board and a word, find if the word exists in the grid. def removeDuplicates(self, nums):
# The word can be constructed from letters of sequentially adjacent cell, where """
"adjacent" cells are those horizontally :type nums: List[int]
:rtype: int if nums[right] == nums[mid] and nums[mid] != nums[left]: # RHS is flat and
""" does not include target
next = 2 # next index to be filled with result return self.binary(nums, left, mid-1, target) # so check LHS

for index in range(2, len(nums)): if self.binary(nums, left, mid-1, target): # both sides flat, if not fount
on one side check the other
if nums[index] != nums[next-2]: # result does not contain 2 copies of return True
this num return self.binary(nums, mid+1, right, target)
nums[next] = nums[index]
next += 1

return min(next, len(nums))


# python_1_to_1000/082_Remove_Duplicates_from_Sorted_List_II.py - m

# python_1_to_1000/081_Search_in_Rotated_Sorted_Array_II.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
# Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only
# https://leetcode.com/problems/search-in-rotated-sorted-array-ii/ distinct numbers from the original list.
# Follow up for "Search in Rotated Sorted Array":
# What if duplicates are allowed? # If node is duplicated, move past all nodes of same value. Else add node to final list.
# Would this affect the run-time complexity? How and why? # Time - O(n)
# Write a function to determine if a given target is in the array. # Space - O(1)

# When splitting the array at mid, one side contains the rotation point. The other side # Definition for singly-linked list.
must be increasing or flat. class ListNode(object):
# Rotation point side cannot be increasing, only flat or decreasing. def __init__(self, x):
# Therefor if we find an increasing side we know whether to recurse on that side or the self.val = x
other. self.next = None
# Then if either side is not flat we know it is not sorted adn the other side is, so
recurse there. class Solution(object):
# If both sides are flat we must check them both. def deleteDuplicates(self, head):
# Time - O(n) """
# Space - O(n) :type head: ListNode
:rtype: ListNode
class Solution(object): """
def search(self, nums, target): pseudo = prev = ListNode(None)
""" pseudo.next = head
:type nums: List[int] node = head
:type target: int
:rtype: bool while node:
"""
return self.binary(nums, 0, len(nums)-1, target) if node.next and node.val == node.next.val: # node begins a sequence of
duplicates
def binary(self, nums, left, right, target): duplicate_value = node.val
node = node.next
if left > right: while node and node.val == duplicate_value: # skip over all duplicates
return False node = node.next
prev.next = None # list ends until non-
mid = (left + right) // 2 duplicate found
if nums[mid] == target:
return True else: # node is not duplicated
prev.next = node # add to resulting list
if nums[left] < nums[mid]: # LHS is sorted prev = node
if target < nums[mid] and target >= nums[left]: # check target in range node = node.next
of both ends
return self.binary(nums, left, mid-1, target) # target cannot be on RHS return pseudo.next
return self.binary(nums, mid+1, right, target) # target cannot be on LHS

if nums[mid] < nums[right]: # RHS is sorted


if target > nums[mid] and target <= nums[right]: # check target in range # python_1_to_1000/083_Remove_Duplicates_from_Sorted_List.py
of both ends
return self.binary(nums, mid+1, right, target) # target cannot be on LHS _author_ = 'jake'
return self.binary(nums, left, mid-1, target) # target cannot be on RHS _project_ = 'leetcode'

if nums[left] == nums[mid] and nums[mid] != nums[right]: # LHS is flat and # https://leetcode.com/problems/remove-duplicates-from-sorted-list/


does not include target # Given a sorted linked list, delete all duplicates such that each element appear only
return self.binary(nums, mid+1, right, target) # so check RHS once.

# If next node is same as node, link node to node.next.next. Else move to next node. return max_area
# Time - O(n)
# Space - O(1)

# Definition for singly-linked list.


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

class Solution(object): # https://leetcode.com/problems/maximal-rectangle/


def deleteDuplicates(self, head): # Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing
""" only 1's and return its area.
:type head: ListNode
:rtype: ListNode # For each row build a 'histogram' of the number of 1s above and including each column.
""" Then proceed as for problem 084
node = head # and pop a column off the stack whenever its 2 boundaries are lower.
# Time - O(m*n)
while node and node.next: # Space - O(n)
if node.val == node.next.val:
node.next = node.next.next class Solution(object):
else: def maximalRectangle(self, matrix):
node = node.next """
:type matrix: List[List[str]]
return head :rtype: int
"""
if not matrix or not matrix[0]:
return 0
# python_1_to_1000/084_Largest_Rectangle_in_Histogram.py - h
rows = len(matrix)
_author_ = 'jake' cols = len(matrix[0])
_project_ = 'leetcode'
max_area = 0
# https://leetcode.com/problems/largest-rectangle-in-histogram/ heights = [0] * cols
# Given n non-negative integers representing the histogram's bar height where the width
of each bar is 1, for row in range(rows):
# find the area of largest rectangle in the histogram.
heights = [heights[i]+1 if matrix[row][i]=='1' else 0 for i in range(cols)]
# For each bar, find the largest rectangle including that bar as the lowest bar. heights.append(0)
# An index is popped from the stack when a lower bar to the right is found. stack = [0]
# We calculate the largest area with the bar at the popped index as the height (lowest
bar in rectangle). for col in range(1, len(heights)):
# Width is determined by the closest lower bar to the left and right. while stack and heights[col] < heights[stack[-1]]:
# Time - O(n) height = heights[stack.pop()]
# Space - O(n) if not stack:
width = col
class Solution(object): else:
def largestRectangleArea(self, heights): width = col - stack[-1] - 1
""" max_area = max(max_area, height * width)
:type heights: List[int]
:rtype: int stack.append(col)
"""
max_area = 0 return max_area
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
# python_1_to_1000/086_Partition_List.py - m
for i, bar in enumerate(heights[1:], 1):
_author_ = 'jake'
while heights[stack[-1]] > bar: # pop taller off stack _project_ = 'leetcode'

height = heights[stack.pop()] # form rectangle with popped bar # https://leetcode.com/problems/partition-list/


determining height # Given a linked list and a value x, partition it such that all nodes less than x come
width = i - stack[-1] - 1 # i and stack[-1] - 1 are the first lower before nodes greater than or equal to x.
bars on left and right # You should preserve the original relative order of the nodes in each of the two
max_area = max(max_area, height * width) partitions.

stack.append(i) # Create new pseudo heads for lists of nodes lesser and greater than x.
# Time - O(n) if s1 == s2:
# Space - O(1) return True

# Definition for singly-linked list. for partition in range(1, len(s1)):


class ListNode(object):
def __init__(self, x): s1_l = s1[:partition] # partition number of chars from left
self.val = x s1_r = s1[partition:] # last (len(s1) - partition) chars
self.next = None s2_l = s2[:partition]
s2_r = s2[partition:]
class Solution(object): s2_l_swap = s2[:-partition] # (len(s2) - partition) chars from left
def partition(self, head, x): s2_r_swap = s2[-partition:] # last partition chars
"""
:type head: ListNode if (self.isScramble(s1_l, s2_l) and self.isScramble(s1_r, s2_r)) or \
:type x: int (self.isScramble(s1_l, s2_r_swap) and self.isScramble(s1_r,
:rtype: ListNode s2_l_swap)):
""" return True
lesser_head = lesser = ListNode(None)
greater_head = greater = ListNode(None) return False

node = head
while node:
if node.val < x: # python_1_to_1000/088_Merge_Sorted_Array.py
lesser.next = node
lesser = node _author_ = 'jake'
else: # node.val >= x _project_ = 'leetcode'
greater.next = node
greater = node # https://leetcode.com/problems/merge-sorted-array/
node = node.next # Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted
array.
greater.next = None # if last node not greater then break link to # You may assume that nums1 has enough space (size that is greater or equal to m + n) to
last node hold additional elements from nums2.
lesser.next = greater_head.next # join lists # The number of elements initialized in nums1 and nums2 are m and n respectively.
return lesser_head.next
# Start from end of nums1. Move largest elements from each array.
# Time - O(m + n)
# python_1_to_1000/087_Scramble_String.py - h # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def merge(self, nums1, m, nums2, n):
"""
# https://leetcode.com/problems/scramble-string/ :type nums1: List[int]
# Given a string s1, we may represent it as a binary tree by partitioning it to two non- :type m: int
empty substrings recursively. :type nums2: List[int]
# To scramble the string, we may choose any non-leaf node and swap its two children. :type n: int
# Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string :rtype: void Do not return anything, modify nums1 in-place instead.
of s1. """
i, j, k = m - 1, n - 1, m + n - 1
# Base cases of strings containing different characters or same string. Else for all
partition points, lest and right while i >= 0 and j >= 0:
# sides are scrambled versions, before or after swapping. if nums1[i] > nums2[j]:
# Time - exponential since 4n recursive calls for string of length n. nums1[k] = nums1[i]
i -= 1
from collections import Counter else:
nums1[k] = nums2[j]
class Solution(object): j -= 1
def isScramble(self, s1, s2): k -= 1
"""
:type s1: str if i < 0: # Nothing to move if only nums1 remain, else move rest of nums2
:type s2: str nums1[:k+1] = nums2[:j+1]
:rtype: bool
"""
count1 = Counter(s1) # python_1_to_1000/089_Gray_Code.py - m
for c in s2:
if c not in count1: _author_ = 'jake'
return False _project_ = 'leetcode'
count1[c] -= 1
if count1[c] < 0: # https://leetcode.com/problems/gray-code/
return False # The gray code is a binary numeral system where two successive values differ in only one
bit.

# Given a non-negative integer n representing the total number of bits in the code, print _project_ = 'leetcode'
the sequence of gray code.
# A gray code sequence must begin with 0. For example, given n = 2, return [0,1,3,2]. Its # https://leetcode.com/problems/decode-ways/
gray code sequence is: # A message containing letters from A-Z is being encoded to numbers using the following
# 00 - 0, 01 - 1, 11 - 3, 10 - 2 mapping:
# 'A' -> 1, 'B' -> 2, ..., 'Z' -> 26
# Grey sequence of n + 1 is formed starting with sequence for n, then appending the # Given an encoded message containing digits, determine the total number of ways to
reverse of that sequence with decode it.
# the extra bit set.
# GC(0) = [0], GC(1) = [0,1], GC(2) = [0,1,3,2], GC(3) = [0,1,3,2,6,7,5,4] # Dynamic programming. Calc ways for prefix of length i from prefixes of lengths i-1 and
# Time - O(2**n) i-2.
# Space - O(2**n) # Time - O(n)
# Space - O(n), could be O(1) by keeping only last 2 values of nb_ways
class Solution(object):
def grayCode(self, n): class Solution(object):
""" def numDecodings(self, s):
:type n: int """
:rtype: List[int] :type s: str
""" :rtype: int
gray = [0] """
if not s:
for i in range(n): return 0
gray += [x + 2 ** i for x in reversed(gray)]
nb_ways = [0] * (len(s)+1) # nb_ways[i] is number of ways to decode prefix
return gray of length i
nb_ways[0] = 1 # required else '10' will be 0
if s[0] != '0':
nb_ways[1] = 1

# python_1_to_1000/090_Subsets_II.py - m for i in range(1, len(s)):

_author_ = 'jake' if s[i] != '0': # last char is not '0'


_project_ = 'leetcode' nb_ways[i+1] += nb_ways[i] # use all ways to decode without this
char
# https://leetcode.com/problems/subsets-ii/ if 10 <= int(s[i-1:i+1]) <= 26: # last 2 form int between 10 and 26
# Given a collection of integers that might contain duplicates, nums, return all possible nb_ways[i+1] += nb_ways[i-1] # use all ways to decode without last 2
subsets. chars
# Note: The solution set must not contain duplicate subsets.
return nb_ways[-1]
# Count the frequency of times each num in nums. Starting with the empty subset, for
each num append it to all
# subsets every possible number of times (between 0 and its frequency in nums,
inclusive). # python_1_to_1000/092_Reverse_Linked_List_II.py - m
# Time - O(n * 2**n), worst case when nums are all ujnique
# Space - O(n * 2**n) _author_ = 'jake'
_project_ = 'leetcode'
from collections import Counter
# https://leetcode.com/problems/reverse-linked-list-ii/
class Solution(object): # Reverse a linked list from position m to n. Do it in-place and in one-pass.
def subsetsWithDup(self, nums): # m, n satisfy the following condition: 1 ≤ m ≤ n ≤ length of list.
"""
:type nums: List[int] # Find tail of non-reversed section, reverse nodes between m and n, link back between
:rtype: List[List[int]] non-reversed sections.
""" # Time - O(n)
num_count = Counter(nums) # Space - O(1)
results = [[]]
# Definition for singly-linked list.
for num in num_count: class ListNode(object):
results += [partial+[num]*i for i in range(1,num_count[num]+1) for partial in def __init__(self, x):
results] self.val = x
self.next = None
return results
class Solution(object):
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
# python_1_to_1000/091_Decode_Ways.py - m :type m: int
:type n: int
_author_ = 'jake' :rtype: ListNode
""" if 3 * (NB_SECTIONS - 1) >= remaining - 3 >= NB_SECTIONS - 1 and 100 <=
pseudo = ListNode(None) # create a new pseudo head int(s[used:used + 3]) <= 255:
pseudo.next = head new_results.append(result + [s[used:used + 3]])
node = pseudo if 3 * (NB_SECTIONS - 1) >= remaining - 2 >= NB_SECTIONS - 1 and 10 <=
n -= m # n = nb nodes to be reversed - 1 int(s[used:used + 2]):
new_results.append(result + [s[used:used + 2]])
while m > 1: # find the tail of the first non-reversed section if 3 * (NB_SECTIONS - 1) >= remaining - 1 >= NB_SECTIONS - 1:
node = node.next new_results.append(result + [s[used]])
m -= 1
NB_SECTIONS -= 1
reversed_head = None results = new_results
next_reverse = node.next
return ['.'.join(result) for result in results]
while n >= 0: # add next_reverse in front of reversed_head
tail = next_reverse.next
next_reverse.next = reversed_head
reversed_head = next_reverse
next_reverse = tail # python_1_to_1000/094_Binary_Tree_Inorder_Traversal.py
n -= 1
_author_ = 'jake'
node.next.next = tail # link tail of reversed section to second non- _project_ = 'leetcode'
reversed section
node.next = reversed_head # link tail of the first non-reversed section to # https://leetcode.com/problems/binary-tree-inorder-traversal/
reversed section # Given a binary tree, return the inorder traversal of its nodes' values.
# Note: Recursive solution is trivial, could you do it iteratively?
return pseudo.next
# From root, go as far left as possible pushing all nodes onto stack. While nodes on
stack, pop a node and add it to
# python_1_to_1000/093_Restore_IP_Addresses.py - m # the result. Its left child (if any) has already been visited because it was added to
the stack later so popped
_author_ = 'jake' # earlier. If the node has a right child, add that child and all its left branch to the
_project_ = 'leetcode' stack.
# Time - O(n)
# https://leetcode.com/problems/restore-ip-addresses/ # Space - O(n)
# Given a string containing only digits, restore it by returning all possible valid IP
address combinations. # Definition for a binary tree node.
# E.g. given "25525511135", return ["255.255.11.135", "255.255.111.35"]. (Order does not # class TreeNode(object):
matter) # def __init__(self, x):
# self.val = x
# For each of the 4 sections of an IP address, use 3 chars if between 100 and 255, 2 if > # self.left = None
10 and always use 1 char - # self.right = None
# provided that the remaining chars are not too few or too many to make an IP address.
# an IP address class Solution(object):
# Time - O(1), max of 4**3 possibilities for any s def inorderTraversal(self, root):
# Space - O(1) """
:type root: TreeNode
class Solution(object): :rtype: List[int]
def restoreIpAddresses(self, s): """
""" stack, result = [], []
:type s: str
:rtype: List[str] while root: # make top of stack the smallest value
""" stack.append(root)
NB_SECTIONS = 4 root = root.left
if 3 * NB_SECTIONS < len(s) < NB_SECTIONS: # cannot make any IPs
return [] while stack:

results = [[]] node = stack.pop()


result.append(node.val)
while NB_SECTIONS > 0:
if node.right:
new_results = [] node = node.right
while node:
for result in results: stack.append(node)
node = node.left
used = sum((len(section) for section in result)) # number of used
characters in this partial result return result
remaining = len(s) - used # number of remaining
chars in s
# python_1_to_1000/095_Unique_Binary_Search_Trees_II.py - m

self.val = x
_author_ = 'jake' self.left = None
_project_ = 'leetcode' self.right = None

# https://leetcode.com/problems/unique-binary-search-trees-ii/ class Solution(object):


# Given an integer n, generate all structurally unique BST's (binary search trees) that def numTrees(self, n):
store values 1...n. """
:type n: int
# Any number i from 1 to n is the root. Numbers less than i form the left subtree, :rtype: int
numbers greater from the right. """
# Time - O(n**2 * Catalan(n)) where Catalan(n) = 2n! / (n+1)!n! memo = [-1] * (n+1) # memo[i] is number of ways for i nodes
# Space - O(n * Catalan(n)) return self.helper(n, memo)

# Definition for a binary tree node. def helper(self, n, memo):


class TreeNode(object): if n <= 1:
def __init__(self, x): return 1 # 1 tree for n==0 (empty tree) and 1 tree for n==1
self.val = x
self.left = None if memo[n] != -1:
self.right = None return memo[n]

class Solution(object): count = 0


def generateTrees(self, n): for i in range(1, n+1): # take each number 1...n as root
""" # all numbers < i form left subtree, all > i form right subtree
:type n: int # multiply possibilities
:rtype: List[TreeNode] count += self.helper(i-1, memo) * self.helper(n-i, memo)
""" memo[n] = count
if n <= 0: return count
return []
return self.generate(1, n)

def generate(self, left, right): # python_1_to_1000/097_Interleaving_String.py - m

if left > right: _author_ = 'jake'


return [None] _project_ = 'leetcode'

results = [] # https://leetcode.com/problems/interleaving-string/
for i in range(left, right+1): # Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

left_trees = self.generate(left, i-1) # If the next char of s1 or s2 matches s3, recurse on the remainder.
right_trees = self.generate(i+1, right) # Time - O(m * n), every prefix of s1 * every prefix of s2
for l in left_trees: # Space - O(m * n)
for r in right_trees:
root = TreeNode(i) class Solution(object):
root.left = l def isInterleave(self, s1, s2, s3):
root.right = r """
results.append(root) :type s1: str
:type s2: str
return results :type s3: str
:rtype: bool
"""
if len(s1) + len(s2) != len(s3): # early return
# python_1_to_1000/096_Unique_Binary_Search_Trees.py - m return False
return self.helper(s1, s2, s3, 0, 0, {})
_author_ = 'jake'
_project_ = 'leetcode'
def helper(self, s1, s2, s3, i, j, memo): # i, j are indices of next char to be
# https://leetcode.com/problems/unique-binary-search-trees/ matched in s1, s2
# Given an integer n, count all structurally unique BST's (binary search trees) that
store values 1...n. if i >= len(s1) or j >= len(s2): # base case, one string already matched
return s1[i:] + s2[j:] == s3[i+j:]
# Dynamic programming. Base case of 1 for n = 0 or 1. For each of n possible root
nodes, multiply the if (i, j) in memo:
# possible left subtrees with the right subtrees. return memo[(i, j)]
# Time - O(n**2)
# Space - O(n) result = False
if s1[i] == s3[i+j] and self.helper(s1, s2, s3, i+1, j, memo):
# Definition for a binary tree node. result = True
class TreeNode(object): elif s2[j] == s3[i+j] and self.helper(s1, s2, s3, i, j+1, memo):
def __init__(self, x): result = True
return self.valid(node.left, lower, node.val) and self.valid(node.right,
memo[(i, j)] = result node.val, upper)
return result

# python_1_to_1000/099_Recover_Binary_Search_Tree.py - m
# python_1_to_1000/098_Validate_Binary_Search_Tree.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/recover-binary-search-tree/
# https://leetcode.com/problems/validate-binary-search-tree/ # The values of 2 nodes of a binary search tree (BST) are swapped by mistake.
# Given a binary tree, determine if it is a valid binary search tree (BST). # Recover the tree without changing its structure.
# Assume a BST is defined as follows:
# The left subtree of a node contains only nodes with keys less than the node's key. # Perform an inorder traversal tracking the previous node. The first time a non-
# The right subtree of a node contains only nodes with keys greater than the node's key. increasing node value is found,
# Both the left and right subtrees must also be binary search trees. # store the previous node. The second time a non-increasing node value is found, store
the node.
# Perform an inorder traversal and check that each node is greater than the previous. # E.g. for 1,2,3,8,5,6,7,4,9 we store 8 and 4.
Does not work if equal nodes # Time - O(n)
# are allowed. # Space - O(n), recursion depth worst case, log n if balanced
# Alternatively track the upper and lower bounds possible for each node, depending on
parents. # Definition for a binary tree node.
# Time - O(n) class TreeNode(object):
# Space - O(n), or log n if balanced 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 def recoverTree(self, root):
self.right = None """
:type root: TreeNode
class Solution(object): :rtype: void Do not return anything, modify root in-place instead.
def isValidBST(self, root): """
""" self.swapped1 = None
:type root: TreeNode self.swapped2 = None
:rtype: bool self.prev = TreeNode(float('-inf'))
""" self.inorder(root)
self.correct = True self.swapped1.val, self.swapped2.val = self.swapped2.val, self.swapped1.val
self.prev = float('-inf')
self.inorder(root)
return self.correct def inorder(self, node):
if not node:
def inorder(self, node): return
if not node or not self.correct: # return if already found out of order
return self.inorder(node.left)

self.inorder(node.left) if node.val <= self.prev.val:


if not self.swapped1:
if node.val <= self.prev: self.swapped1 = self.prev
self.correct = False if self.swapped1:
return # halt exploration self.swapped2 = node
self.prev = node.val
self.prev = node
self.inorder(node.right)
self.inorder(node.right)

class Solution2(object):
def isValidBST(self, root):
return self.valid(root, float('-inf'), float('inf')) # python_1_to_1000/100_Same_Tree.py

def valid(self, node, lower, upper): # node.val must be above lower and below _author_ = 'jake'
upper _project_ = 'leetcode'
if not node:
return True # https://leetcode.com/problems/same-tree/
if node.val <= lower or node.val >= upper: # can be amended if equal values are # Given two binary trees, write a function to check if they are equal or not.
allowed # Two binary trees are considered equal if they are structurally identical and the nodes
return False have the same value.

# Traverse both trees, checking nodes exist in same places and values are same. Could if not left_node or not right_node:
preorder, inorder or postorder. return False
# Time - O(min(m, n))
# Space - O(min(m, n)), or log is balanced if left_node.val != right_node.val:
return False
# Definition for a binary tree node.
class TreeNode(object): return self.is_mirror(right_node.right, left_node.left) and \
def __init__(self, x): self.is_mirror(left_node.right, right_node.left)
self.val = x
self.left = None
self.right = None # python_1_to_1000/102_Binary_Tree_Level_Order_Traversal.py - m

class Solution(object): _author_ = 'jake'


def isSameTree(self, p, q): _project_ = 'leetcode'
"""
:type p: TreeNode # https://leetcode.com/problems/binary-tree-level-order-traversal/
:type q: TreeNode # Given a binary tree, return the level order traversal of its nodes' values. (ie, from
:rtype: bool left to right, level by level).
"""
if not p and not q: # Create a list of all non-null nodes from the nodes in the level above.
return True # Time - O(n)
if not p or not q: # Space - O(n)
return False
# Definition for a binary tree node.
if p.val != q.val: # class TreeNode(object):
return False # def __init__(self, x):
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) # self.val = x
# self.left = None
# self.right = None

class Solution(object):
def levelOrder(self, root):
# python_1_to_1000/101_Symmetric_Tree.py """
:type root: TreeNode
_author_ = 'jake' :rtype: List[List[int]]
_project_ = 'leetcode' """
result = []
# https://leetcode.com/problems/symmetric-tree/ if not root:
# Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its return result
center).
level_nodes = [root]
# Check if left and right subtrees are both present or not, then if root values are
equal. Then recurse on their while level_nodes:
# subtrees being mirrors - left/left of right/right and left/right of right/left
# Time - O(n) new_level_nodes = []
# Space - O(n) result.append([])

# Definition for a binary tree node. for node in level_nodes:


# class TreeNode(object): result[-1].append(node.val)
# def __init__(self, x): if node.left:
# self.val = x new_level_nodes.append(node.left)
# self.left = None if node.right:
# self.right = None new_level_nodes.append(node.right)

class Solution(object): level_nodes = new_level_nodes


def isSymmetric(self, root):
""" return result
:type root: TreeNode
:rtype: bool
"""
if not root: # python_1_to_1000/103_Binary_Tree_Zigzag_Level_Order_Traversal.py - m
return True
return self.is_mirror(root.left, root.right) _author_ = 'jake'
_project_ = 'leetcode'
def is_mirror(self, left_node, right_node):
# https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/
if not left_node and not right_node: # Given a binary tree, return the zigzag level order traversal of its nodes' values.
return True # (ie, from left to right, then right to left for the next level and alternate between).
def maxDepth(self, root):
# Alternately append new nodes from left to right and right to left. """
# Time - O(n) :type root: TreeNode
# Space - O(n) :rtype: int
"""
# Definition for a binary tree node. if not root:
# class TreeNode(object): return 0
# def __init__(self, x): return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
# self.val = x
# self.left = None
# self.right = None # python_1_to_1000/105_Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.py - m

class Solution(object): _author_ = 'jake'


def zigzagLevelOrder(self, root): _project_ = 'leetcode'
"""
:type root: TreeNode # https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-
:rtype: List[List[int]] traversal/
""" # Given preorder and inorder traversal of a tree, construct the binary tree.
if not root: # You may assume that duplicates do not exist in the tree.
return []
traversal = [] # Build until we reach stop value, initially None. Take first preorder as root then
recurse left until inorder is
level = [root] # root value. Then discard inorder and recurse right until final stop.
forward = True # Time - O(n)
# Space - O(n)
while level:
from collections import deque
new_level = []
if forward: # Definition for a binary tree node.
traversal.append([n.val for n in level]) class TreeNode(object):
else: def __init__(self, x):
traversal.append([n.val for n in level[::-1]]) self.val = x
self.left = None
for node in level: self.right = None
if node.left:
new_level.append(node.left) class Solution(object):
if node.right: def buildTree(self, preorder, inorder):
new_level.append(node.right) """
:type preorder: List[int]
level = new_level :type inorder: List[int]
forward = not forward :rtype: TreeNode
"""
return traversal def build(stop):

if not inorder or inorder[-1] == stop:


return None

# python_1_to_1000/104_Maximum_Depth_of_Binary_Tree.py root_val = preorder.pop()


root = TreeNode(root_val)
_author_ = 'jake' root.left = build(root_val) # build left subtree until inorder reaches
_project_ = 'leetcode' root_val
inorder.pop() # then discard root_val
# https://leetcode.com/problems/maximum-depth-of-binary-tree/ root.right = build(stop) # build right subtree until inorder reaches
# Given a binary tree, find its maximum depth. original stop
# The maximum depth is the number of nodes along the longest path from the root node down
to the farthest leaf node. return root

# Base case of zer for null node, else 1 + max of left and right subtrees. preorder.reverse() # reverse so we can pop in O(1) time
# Time - O(n) inorder.reverse()
# Space - O(n) return build(None)

# Definition for a binary tree node.


# class TreeNode(object): # python_1_to_1000/106_Construct_Binary_Tree_from_Postorder_and_Inorder_Traversal.py - m
# def __init__(self, x):
# self.val = x _author_ = 'jake'
# self.left = None _project_ = 'leetcode'
# self.right = None
# https://leetcode.com/problems/construct-binary-tree-from-postorder-and-inorder-
class Solution(object): traversal/

# Given inorder and postorder traversal of a tree, construct the binary tree.
# You may assume that duplicates do not exist in the tree. if not node:
return
# Construct in postorder. Last element of postorder is root. Partition preorder about
this element. if len(traversal) == depth:
# Build the right subtree first until postorder[0] is not in inorder. traversal.append([])
# Time - O(n)
# Space - O(n) self.inorder(node.left, depth+1, traversal)

# Definition for a binary tree node. traversal[depth].append(node.val)


class TreeNode(object):
def __init__(self, x): self.inorder(node.right, depth+1, traversal)
self.val = x
self.left = None
self.right = None

class Solution(object): # python_1_to_1000/108_Convert_Sorted_Array_to_Binary_Search_Tree.py


def buildTree(self, inorder, postorder):
""" _author_ = 'jake'
:type inorder: List[int] _project_ = 'leetcode'
:type postorder: List[int]
:rtype: TreeNode # 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
if not inorder: # no inorder signifies null tree even if postorder is not balanced BST.
null
return None # Mid element is root, recursively form left and right subtrees.
# Time - O(n)
inorder_index = inorder.index(postorder.pop()) # Space - O(n)
root = TreeNode(inorder[inorder_index])
# Definition for a binary tree node.
root.right = self.buildTree(inorder[inorder_index+1:], postorder) # right first class TreeNode(object):
root.left = self.buildTree(inorder[:inorder_index], postorder) def __init__(self, x):
self.val = x
return root self.left = None
self.right = None

# python_1_to_1000/107_Binary_Tree_Level_Order_Traversal_II.py - m class Solution(object):


def sortedArrayToBST(self, nums):
_author_ = 'jake' """
_project_ = 'leetcode' :type nums: List[int]
:rtype: TreeNode
# 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. return self.convert(nums, 0, len(nums)-1)
# I.e. from left to right, level by level from leaf to root.
def convert(self, nums, left, right):
# Perform an inorder traversal, tracking depth and appending node values to corresponding if left > right:
sub-list. Reverse return None
# result before returning. mid = (left + right) // 2
# Time - O(n) root = TreeNode(nums[mid])
# Space - O(n) root.left = self.convert(nums, left, mid-1)
root.right = self.convert(nums, mid+1, right)
# Definition for a binary tree node. return root
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None # python_1_to_1000/109_Convert_Sorted_List_to_Binary_Search_Tree.py - m
self.right = None
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def levelOrderBottom(self, root):
"""
:type root: TreeNode # https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/
:rtype: List[List[int]] # Given a singly linked list where elements are sorted in ascending order, convert it to
""" a height balanced BST.
traversal = []
self.inorder(root, 0, traversal) # Count the length of the list. Form left subtree from nodes before mid. Mid node forms
return traversal[::-1] root, then right subtree
# from nodes after mid. When a new tree node is made, advance the linked list pointer.
def inorder(self, node, depth, traversal): Bottom-up approach.
# Time - O(n) # A tree is not balance if either left or right subtree is not balanced, or the
# Space - O(n) difference in left and right subtree
# depths is greater than 1.
# Definition for singly-linked list. # Time - O(n), visit all nodes
class ListNode(object): # Space - O(n)
def __init__(self, x):
self.val = x class Solution(object):
self.next = None def isBalanced(self, root):
"""
# Definition for a binary tree node. :type root: TreeNode
class TreeNode(object): :rtype: bool
def __init__(self, x): """
self.val = x def balanced(node):
self.left = None
self.right = None if not node:
return 0

class Solution(object): left_depth = balanced(node.left)


def sortedListToBST(self, head): right_depth = balanced(node.right)
"""
:type head: ListNode if left_depth == -1 or right_depth == -1:
:rtype: TreeNode return -1
""" if abs(left_depth - right_depth) > 1:
count = 0 return -1
node = head
while node: return 1 + max(left_depth, right_depth)
count += 1
node = node.next return balanced(root) != -1
return self.list_to_bst([head], 0, count - 1) # [head] is mutable list of next
list node to be converted

def list_to_bst(self, node_as_list, start, end): # convert linked-list nodes from


start to end (inclusive) # python_1_to_1000/111_Minimum_Depth_of_Binary_Tree.py

if start > end: _author_ = 'jake'


return None _project_ = 'leetcode'

mid = (start + end) // 2 # https://leetcode.com/problems/minimum-depth-of-binary-tree/


# Given a binary tree, find its minimum depth.
left_subtree = self.list_to_bst(node_as_list, start, mid - 1) # will update # The minimum depth is the number of nodes along the shortest path from the root node
contents of node_as_list to down to the nearest leaf node.
# become the mid
node of linked list # If either subtrees is not present, return 1 + minDepth of existing subtree. If both
root = TreeNode(node_as_list[0].val) (or neither) subtrees, return
root.left = left_subtree # 1 + min of subtree minDepths
node_as_list[0] = node_as_list[0].next # update entry to next node of # Time - O(n)
linked-list # Space - O(n)

root.right = self.list_to_bst(node_as_list, mid + 1, end) # Definition for a binary tree node.


class TreeNode(object):
return root def __init__(self, x):
self.val = x
self.left = None
self.right = None

# python_1_to_1000/110_Balanced_Binary_Tree.py class Solution(object):


def minDepth(self, root):
_author_ = 'jake' """
_project_ = 'leetcode' :type root: TreeNode
:rtype: int
# https://leetcode.com/problems/balanced-binary-tree/ """
# Given a binary tree, determine if it is height-balanced. if not root:
# A height-balanced binary tree is defined as a binary tree in which the depth of the two return 0
subtrees of every node
# never differ by more than 1. l = self.minDepth(root.left)
r = self.minDepth(root.right)
# Helper function balanced returns the depth of the root if the tree is balance or else
-1 if not balanced. if not l or not r:

return 1 + l + r class Solution(object):


def pathSum(self, root, sum):
return 1 + min(l, r) """
:type root: TreeNode
:type sum: int
:rtype: List[List[int]]
# python_1_to_1000/112_Path_Sum.py """
paths = []
_author_ = 'jake' self.preorder(root, sum, [], paths)
_project_ = 'leetcode' return paths

# https://leetcode.com/problems/path-sum/ def preorder(self, node, target, partial, paths):


# Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that
adding up if not node:
# all the values along the path equals the given sum. return

# Base cases of False if no node and True if leaf node with correct sum. Else subtract target -= node.val
node value and check if partial.append(node.val)
# True in either subtree. if target == 0 and not node.left and not node.right:
# Time - O(n) paths.append(partial[:])
# Space - O(n)
self.preorder(node.left, target, partial, paths)
# Definition for a binary tree node. self.preorder(node.right, target, partial, paths)
class TreeNode(object):
def __init__(self, x): partial.pop()
self.val = x
self.left = None
self.right = None # python_1_to_1000/114_Flatten_Binary_Tree_to_Linked_List.py - m

class Solution(object): _author_ = 'jake'


def hasPathSum(self, root, sum): _project_ = 'leetcode'
"""
:type root: TreeNode # https://leetcode.com/problems/flatten-binary-tree-to-linked-list/
:type sum: int # Given a binary tree, flatten it to a linked list in-place.
:rtype: bool # Each node only has a right child. Left subtree is flattened before right.
"""
if not root: # Records the root of the previous subtree flattened as an instance field.
return False # 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.
sum -= root.val # Then removes the link from the root to the old left subtree, and sets the
if sum == 0 and not root.left and not root.right: # leaf node # root.right to the root of the left subtree (now flattened).
return True # Time - O(n)
# Space - O(n)
return self.hasPathSum(root.left, sum) or self.hasPathSum(root.right, sum)
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
# python_1_to_1000/113_Path_Sum_II.py - m self.val = x
self.left = None
_author_ = 'jake' self.right = None
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/path-sum-ii/
# Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals def __init__(self): # instance field self.prev to track previous node
the given sum. self.prev = None

# Maintain a partial path, appending latest node and decrementing target. When path has def flatten(self, root):
been explored, pop node off """
# partial path. Base cases are no node and leaf with remaining target of zero. :type root: TreeNode
# Time - O(n log n), balanced tree has n/2 leaves and height log n :rtype: None Do not return anything, modify root in-place instead.
# Space - O(n log n), every path of balanced tree has correct sum """
if not root:
# Definition for a binary tree node. return
class TreeNode(object):
def __init__(self, x): self.flatten(root.right)
self.val = x self.flatten(root.left)
self.left = None
self.right = None root.left = None
root.right = self.prev
self.prev = root # You may assume that it is a perfect binary tree (ie, all leaves are at the same level,
and every parent has two children).

# Breadth first search by level.


# python_1_to_1000/115_Distinct_Subsequences.py - h # Time - O(n)
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' # Definition for binary tree with next pointer.
class TreeLinkNode(object):
# https://leetcode.com/problems/distinct-subsequences/ def __init__(self, x):
# Given a string S and a string T, count the number of distinct subsequences of T in S. self.val = x
# A subsequence of a string is a new string which is formed from the original string by self.left = None
deleting some (can be none) self.right = None
# of the characters without disturbing the relative positions of the remaining self.next = None
characters.
class Solution(object):
# Dynamic programming. For all prefixes of S and T calculate the number of sequences. def connect(self, root):
Base case is that the prefix """
# of T is the empty string, which is one subsequence of every prefix of S. :type root: TreeLinkNode
# The number of times T[:r] is a subsequence of S[:c] is the number of times T[:r] is a :rtype: nothing
subsequence of S[:c - 1], plus """
# if the last chars of T[:r] and S[:c] match then every T[:r - 1] subsequence of S[:c] level = [root]
can also be extended.
# empty string is a subsequence of any string. while level and level[0]: # if first item is None then all are None because
# Time - O(m * n) where m = len(S) and n = len(T) perfect, so terminate
# Space - O(m)
next_level = []
prev = None
class Solution(object):
def numDistinct(self, s, t): for node in level: # set next right pointer
""" if prev:
:type s: str prev.next = node
:type t: str prev = node
:rtype: int
""" next_level.append(node.left) # add nodes to next level list, do not
prev_subsequences = [1 for _ in range(len(s) + 1)] # empty string is always check if None
one subsequence of any string next_level.append(node.right)

for r in range(1, len(t) + 1): # first r characters of T, level = next_level


i.e. T[:r]

subsequences = [0 for _ in range(len(s) + 1)] # python_1_to_1000/117_Populating_Next_Right_Pointers_in_Each_Node_II.py - m

for c in range(r, len(s) + 1): # first c chars of S. If c _author_ = 'jake'


< r then no possibilities _project_ = 'leetcode'

subsequences[c] = subsequences[c - 1] # all T[:r] subsequences of # https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/


S[:c - 1] are also # Follow up for problem "Populating Next Right Pointers in Each Node".
# subsequences of S[:c] # What if the given tree could be any binary tree? Would your previous solution still
if s[c - 1] == t[r - 1]: # last chars match, add work?
T[:r-1] subsequences of S[:c-1]
subsequences[c] += prev_subsequences[c - 1] # Breadth first search by level. Only append non-null nodes to level list.
# Time - O(n)
prev_subsequences = subsequences # Space - O(n)

return prev_subsequences[-1] # Definition for binary tree with next pointer.


class TreeLinkNode(object):
def __init__(self, x):
self.val = x
self.left = None
# python_1_to_1000/116_Populating_Next_Right_Pointers_in_Each_Node.py - m self.right = None
self.next = None
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def connect(self, root):
# https://leetcode.com/problems/populating-next-right-pointers-in-each-node/ """
# Given a binary tree, populate each next pointer to point to its next right node. :type root: TreeLinkNode
# If there is no next right node, the next pointer should be set to NULL. :rtype: nothing
# You may only use constant extra space. """

if not root: :type rowIndex: int


return :rtype: List[int]
level = [root] """
row = [1]
while level: for i in range(rowIndex):
next_level = [] row = [1] + [row[i]+row[i+1] for i in range(len(row)-1)] + [1]
prev = None return row
for node in level:
if prev:
prev.next = node # python_1_to_1000/120_Triangle.py - m
prev = node
if node.left: _author_ = 'jake'
next_level.append(node.left) _project_ = 'leetcode'
if node.right:
next_level.append(node.right) # https://leetcode.com/problems/triangle/
# Given a triangle, find the minimum path sum from top to bottom. Each step you may move
level = next_level to adjacent numbers on the row below.

# Bottom-ip dynamic programming. Min path is value of that element + min of the 2 paths
to elements below.
# python_1_to_1000/118_Pascal's_Triangle.py # Time - O(n**2) for triangle height n since all elements visited
# Space - O(1), modifies input data
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def minimumTotal(self, triangle):
# https://leetcode.com/problems/pascals-triangle/ """
# Given numRows, generate the first numRows of Pascal's triangle. :type triangle: List[List[int]]
:rtype: int
# Next row is sum of consecutive pairs of items from previous row. """
# Time - O(n**2) for row in range(len(triangle)-2, -1, -1):
# Space - O(n**2)
for col in range(len(triangle[row])):
class Solution(object): triangle[row][col] += min(triangle[row+1][col], triangle[row+1][col+1])
def generate(self, numRows):
""" return triangle[0][0]
:type numRows: int
:rtype: List[List[int]]
""" # python_1_to_1000/121_Best_Time_to_Buy_and_Sell_Stock.py
if numRows == 0:
return [] _author_ = 'jake'
_project_ = 'leetcode'
pascal = [[1]]
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
for i in range(1, numRows): # 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
pascal.append([1]) one share of the stock),
for num1, num2 in zip(pascal[-2][:-1], pascal[-2][1:]): # design an algorithm to find the maximum profit.
pascal[-1].append(num1 + num2)
pascal[-1].append(1) # Record the max cash after buying stock at any point previously (which is negative), and
the max cash after selling
return pascal # as the cash after boying + sale proceeds.
# Time - O(n)
# Space - O(1)

# python_1_to_1000/119_Pascal's_Triangle_II.py class Solution(object):


def maxProfit(self, prices):
_author_ = 'jake' """
_project_ = 'leetcode' :type prices: List[int]
:rtype: int
# https://leetcode.com/problems/pascals-triangle-ii/ """
# Given an index k, return the kth row of the Pascal's triangle. buy = float('-inf') # maximum cash balance after buying a stock
sell = 0 # maximum cash balance after buying and selling a stock
# Next row is sum of consecutive pairs of previous row.
# Time - O(n**2) for price in prices:
# Space - O(n) buy = max(-price, buy) # max of buying earlier or now
sell = max(price + buy, sell) # max of selling earlier or now
class Solution(object):
def getRow(self, rowIndex): return sell
"""
# Given a binary tree, find the maximum path sum.
# For this problem, a path is defined as any sequence of nodes from some starting node to
# python_1_to_1000/122_Best_Time_to_Buy_and_Sell_Stock_II.py - m any node in
# the tree along the parent-child connections.
_author_ = 'jake' # The path must contain at least one node and does not need to go through the root.
_project_ = 'leetcode'
# Recursive helper function calculates max path downwards from and including any node and
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ max path via a node or via
# Say you have an array for which the ith element is the price of a given stock on day i. # any node below.
# Design an algorithm to find the maximum profit. You may complete as many transactions # Time - O(n)
as you like # Space - O(1)
# (ie, buy one and sell one share of the stock multiple times). However, you may not
engage in multiple # Definition for a binary tree node.
# transactions at the same time (ie, you must sell the stock before you buy again). # class TreeNode(object):
# def __init__(self, x):
# Sum all price increases. # self.val = x
# Time - O(n) # self.left = None
# Space - O(n), could be O(1) without creating a new list # self.right = None

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


def maxProfit(self, prices): def maxPathSum(self, root):
""" """
:type prices: List[int] :type root: TreeNode
:rtype: int :rtype: int
""" """
return sum([max(prices[i]-prices[i-1], 0) for i in range(1,len(prices))]) return self.helper(root)[0]

def helper(self, node): # returns tuple of (via, down) where via is max path sum
via (and including) this node
# python_1_to_1000/123_Best_Time_to_Buy_and_Sell_Stock_III.py - h # or via any node below, down is max path sum downwards
from this node
_author_ = 'jake' if not node:
_project_ = 'leetcode' return float('-inf'), 0 # -inf for via if no node since path must have at
least one node
# 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. left_via, left_down = self.helper(node.left)
# Design an algorithm to find the maximum profit. You may complete at most two right_via, right_down = self.helper(node.right)
transactions.
# You may not engage in multiple transactions at the same time (ie, you must sell the # either use this node and go down left and/or right if positive, or best of left
stock before you buy again). and right via.
via = max(node.val + max(0, left_down) + max(0, right_down), left_via, right_via)
# As per problem 121 with an additional buy and sell. # use this node and go down max of right or left if positive.
# Time - O(n) down = node.val + max(0, left_down, right_down)
# Space - O(1)
return via, down
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
""" # python_1_to_1000/125_Valid_Palindrome.py
buy1, buy2 = float('-inf'), float('-inf')
sell1, sell2 = 0, 0 _author_ = 'jake'
_project_ = 'leetcode'
for price in prices:
buy1 = max(buy1, -price) # https://leetcode.com/problems/valid-palindrome/
sell1 = max(sell1, price + buy1) # Given a string, determine if it is a palindrome, considering only alphanumeric
buy2 = max(buy2, sell1 - price) characters and ignoring cases.
sell2 = max(sell2, price + buy2)
# Convert to lower case and remove non-alphanumeric characters.
return sell2 # Time - O(n)
# Space - O(n)

# python_1_to_1000/124_Binary_Tree_Maximum_Path_Sum.py - h import string

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def isPalindrome(self, s):
"""
# https://leetcode.com/problems/binary-tree-maximum-path-sum/ :type s: str

:rtype: bool
""" next_left = defaultdict(set)
allowed = set(string.ascii_lowercase + string.digits) for word in left:
s = [c for c in s.lower() if c in allowed] for char in string.ascii_lowercase:
for i in range(len(beginWord)):
i, j = 0, len(s)-1 n = word[:i] + char + word[i + 1:] # replace every position with
while i < j: every char
if s[i] != s[j]: if n in wordList and n not in left_parents: # valid word not been
return False used
i += 1 next_left[n].add(word)
j -= 1
return True left_parents.update(next_left)
left = set(next_left.keys())

if swapped: # swap back


left, right = right, left
# python_1_to_1000/126_Word_Ladder_II.py - h left_parents, right_parents = right_parents, left_parents

_author_ = 'jake' ladders = [[word] for word in left & right] # start from central intersection
_project_ = 'leetcode' while ladders and ladders[0][0] not in beginWord: # extend ladders left to
start
# https://leetcode.com/problems/word-ladder-ii/ ladders = [[p] + l for l in ladders for p in left_parents[l[0]]]
# Given two words (beginWord and endWord), and a dictionary's word list, find all while ladders and ladders[0][-1] != endWord: # extend ladders right to end
shortest transformation sequence(s) ladders = [l + [p] for l in ladders for p in right_parents[l[-1]]]
# from beginWord to endWord, such that:
# Only one letter can be changed at a time return ladders
# Each transformed word must exist in the word list. Note that beginWord is not a
transformed word.
# Note: # python_1_to_1000/127_Word_Ladder.py - h
# Return an empty list if there is no such transformation sequence.
# All words have the same length. _author_ = 'jake'
# All words contain only lowercase alphabetic characters. _project_ = 'leetcode'
# You may assume no duplicates in the word list.
# You may assume beginWord and endWord are non-empty and are not the same. # https://leetcode.com/problems/word-ladder/
# Given two words (beginWord and endWord), and a dictionary's word list, find the length
# Bidirectional breadth first search. Frontiers of valid neighbouring words are gradually of shortest transformation
expanded. Swap to use the # sequence from beginWord to endWord, such that:
# smaller frontier in each round, stop when either frontier is empty (return empty list) # Only one letter can be changed at a time.
or an intersection is found. # Each transformed word must exist in the word list. Note that beginWord is not a
# Build ladders to srat using left parents and to end using right parents. transformed word.
# Time - O(b^(d/2)) where b is branching factor and d is depth between start and end # Note:
# Return 0 if there is no such transformation sequence.
from collections import defaultdict # All words have the same length.
import string # All words contain only lowercase alphabetic characters.
# You may assume no duplicates in the word list.
class Solution(object):
def findLadders(self, beginWord, endWord, wordList): # 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
:type beginWord: str BFS with branching
:type endWord: str # factor b and depth d
:type wordList: List[str] # Space - O(n*k) for graph
:rtype: List[List[str]]
""" from collections import defaultdict
if endWord not in wordList:
return [] class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
wordList = set(wordList) # convert to set for O(1) lookup """
left, right = {beginWord}, {endWord} # frontiers at both ends :type beginWord: str
left_parents, right_parents = defaultdict(set), defaultdict(set) # map word to :type endWord: str
its parent :type wordList: List[str]
swapped = False # have the frontiers been swapped? :rtype: int
"""
while left and right and not (left & right): # while both frontiers and no length = 1
intersection visited = set()
if endWord not in wordList:
if len(right) < len(left): # swap to expand smaller frontier return 0
left, right = right, left
left_parents, right_parents = right_parents, left_parents graph = defaultdict(set)
swapped = not swapped for word in wordList: # build a mapping of words reachable by
changing one letter
for i in range(len(word)):
wildcard = word[:i] + '_' + word[i + 1:]
graph[wildcard].add(word)

front, back = {beginWord}, {endWord} # frontiers in both directions # python_1_to_1000/129_Sum_Root_to_Leaf_Numbers.py - m

while front: _author_ = 'jake'


_project_ = 'leetcode'
if front & back: # intersection between frontiers
return length # https://leetcode.com/problems/sum-root-to-leaf-numbers/
# Given a binary tree containing digits from 0-9 only, each root-to-leaf path could
new_front = set() represent a number.
for word in front: # An example is the root-to-leaf path 1->2->3 which represents the number 123.
# Find the total sum of all root-to-leaf numbers.
visited.add(word) # add word to set of those already
removed from frontiers # Recursively find the sum of all paths from a node to all leaves having already seen
path value of partial.
for i in range(len(word)): # add reachable words to frontier # Time - O(n)
next_words = graph[word[:i] + '_' + word[i + 1:]] # Space - O(n)
next_words -= visited # apart from if already removed from a
frontier # Definition for a binary tree node.
new_front |= next_words class TreeNode(object):
def __init__(self, x):
length += 1 self.val = x
front = new_front self.left = None
self.right = None
if len(back) < len(front): # expand the smaller frontier next
front, back = back, front class Solution(object):
def sumNumbers(self, root):
return 0 """
:type root: TreeNode
:rtype: int
"""
return self.helper(root, 0)
# python_1_to_1000/128_Longest_Consecutive_Sequence.py - m
def helper(self, node, partial):
_author_ = 'jake'
_project_ = 'leetcode' if not node: # no path to leaves
return 0
# https://leetcode.com/problems/longest-consecutive-sequence/
# Given an unsorted array of integers, find the length of the longest consecutive partial = 10 * partial + node.val # incorporate this node.val
elements sequence.
if not node.left and not node.right: # base case, leaf
# Test if each number starts a new sequence, if it does then count that sequence. return partial
# Time - O(n), visits each number at most twice
# Space - O(n) return self.helper(node.left, partial) + self.helper(node.right, partial)

class Solution(object):
def longestConsecutive(self, nums): # python_1_to_1000/130_Surrounded_Regions.py - m
"""
:type nums: List[int] _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
numset = set(nums) # no ordering, O(1) lookup # https://leetcode.com/problems/surrounded-regions/
longest = 0 # Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded
by 'X'.
for num in numset: # A region is captured by flipping all 'O's into 'X's in that surrounded region.

if num-1 in numset: # not the start of a sequence # All edge cells containing 'O' and their adjoining 'O' cannot be surrounded.
continue Temporarily flag these cells, by depth-
# first search. Then convert all unflagged 'O' (that can be surrounded) to 'X'.
seq = 0 # Time - O(m * n)
while num in numset: # move along this sequence # Space - O(m * n)
seq += 1
num += 1 class Solution(object):
longest = max(longest, seq) def solve(self, board):
"""
return longest :type board: List[List[str]]

:rtype: void Do not return anything, modify board in-place instead.


""" _author_ = 'jake'
if not board or not board[0]: _project_ = 'leetcode'
return
# https://leetcode.com/problems/palindrome-partitioning-ii/
rows, cols = len(board), len(board[0]) # Given a string s, partition s such that every substring of the partition is a
palindrome.
to_expand = [] # stack of cells to be checked # Return the minimum cuts needed for a palindrome partitioning of s.

for row in range(rows): # add all edge cells to stack # Initialise worst case for each prefix as length of prefix - 1. For each character
to_expand += [(row, 0), (row, cols - 1)] expand outwards both odd and even
for col in range(1, cols-1): # length palindromes. Whenever a palindrome is found, update min_cuts for that
to_expand += [(0, col), (rows - 1, col)] palindrome plus the left prefix.
# Time - O(n**2)
while to_expand: # if cell contains 'O', change to temporary 'T' and # Space - O(n)
add neighbours to stack
row, col = to_expand.pop() class Solution(object):
if 0 <= row < rows and 0 <= col < cols and board[row][col] == 'O': def minCut(self, s):
board[row][col] = 'T' """
for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]: :type s: str
to_expand.append((row + dr, col + dc)) :rtype: int
"""
for row in range(rows): # change all 'T' back to 'O' and all 'O' to 'X' min_cuts = [i-1 for i in range(len(s)+1)] # min_cuts[i] is min cuts for
for col in range(cols): prefix s[:i] of length i
if board[row][col] == 'O':
board[row][col] = 'X' for i in range(len(s)): # for each character as centre of
elif board[row][col] == 'T': palindrome
board[row][col] = 'O'
left, right = i, i # expand to find all odd-length
palindromes
# python_1_to_1000/131_Palindrome_Partitioning.py - m 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])
_author_ = 'jake' left -= 1
_project_ = 'leetcode' right += 1

# https://leetcode.com/problems/palindrome-partitioning/ left, right = i, i+1 # expand to find all even-length


# Given a string s, partition s such that every substring of the partition is a palindromes
palindrome. while left >= 0 and right < len(s) and s[left] == s[right]:
# Return all possible palindrome partitioning of s. min_cuts[right + 1] = min(min_cuts[right + 1], 1 + min_cuts[left])
left -= 1
# If any prefix of s is a palindrome, then recursively partition the suffix into right += 1
palindromes.
# Time - O(2**n), for string of length n there we can partition or not after each letter return min_cuts[-1]
# Space - O(2**n)

class Solution(object):
def partition(self, s): # python_1_to_1000/133_Clone_Graph.py - m
"""
:type s: str _author_ = 'jake'
:rtype: List[List[str]] _project_ = 'leetcode'
"""
partitons = [] # https://leetcode.com/problems/clone-graph/
self.find_partitions(s, [], partitons) # Clone an undirected graph. Each node in the graph contains a label and a list of its
return partitons neighbors

# When a new node is discovered it is copied, added to mapping and to_clone. Main while
def find_partitions(self, s, partial, partitions): loop makes directed edges
if not s: # to neighbors.
partitions.append(partial) # Time - O(m + n), edges + nodes
# Space - O(m + n)
for i in range(1, len(s)+1):
prefix = s[:i] # Definition for a undirected graph node
if prefix == prefix[::-1]: class UndirectedGraphNode(object):
self.find_partitions(s[i:], partial + [s[:i]], partitions) def __init__(self, x):
self.label = x
self.neighbors = []

class Solution(object):
# python_1_to_1000/132_Palindrome_Partitioning_II.py - h def cloneGraph(self, node):
"""
:type node: UndirectedGraphNode return -1 if total < 0 else start
:rtype: UndirectedGraphNode
"""
if not node: # python_1_to_1000/135_Candy.py - h
return
cloned_start = UndirectedGraphNode(node.label) _author_ = 'jake'
to_clone = [node] # list (or set) of original nodes _project_ = 'leetcode'
node_mapping = {node : cloned_start} # original to cloned nodes
# https://leetcode.com/problems/candy/
while to_clone: # There are N children standing in a line. Each child is assigned a rating value.
# You are giving candies to these children subjected to the following requirements:
node = to_clone.pop() # node is in mapping but does not have # Each child must have at least one candy.
links to neighbors # Children with a higher rating get more candies than their neighbors.
clone_node = node_mapping[node] # What is the minimum candies you must give?

for neighbor in node.neighbors: # Find how many candies are required due to children on left and then on right.
if neighbor not in node_mapping: # create copies of neighbors if not # Result for each child is the higher of those values.
already existing # Time - O(n)
clone_neightbor = UndirectedGraphNode(neighbor.label) # Space - O(n)
node_mapping[neighbor] = clone_neightbor
to_clone.append(neighbor) class Solution(object):
else: def candy(self, ratings):
clone_neightbor = node_mapping[neighbor] """
:type ratings: List[int]
clone_node.neighbors.append(clone_neightbor) # directed edges from :rtype: int
clone_node """
left = [1 for _ in range(len(ratings))] # default to 1 per child
return cloned_start right = [1 for _ in range(len(ratings))]

for i in range(1, len(ratings)): # increase above previous child if


greater rating
# python_1_to_1000/134_Gas_Station.py - m if ratings[i] > ratings[i-1]:
left[i] = left[i-1] + 1
_author_ = 'jake'
_project_ = 'leetcode' candies = left[-1] # rightmost child not included in loop below
for i in range(len(ratings)-2, -1, -1):
# https://leetcode.com/problems/gas-station/ if ratings[i] > ratings[i+1]: # increase if greater rating
# There are N gas stations along a circular route, where the amount of gas at station i right[i] = right[i+1] + 1
is gas[i]. candies += max(left[i], right[i]) # child gets higher of candies due to
# You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from left and right
station i to its next
# station (i+1). You begin the journey with an empty tank at one of the gas stations. return candies
# Return the starting gas station's index if you can travel around the circuit once,
otherwise return -1.
# python_1_to_1000/136_Single_Number.py
# If total gas >= total cost then a circuit is possible.
# Iterate round the circuit, updating current tank balance and total. If current tank is _author_ = 'jake'
negative, cannot start at _project_ = 'leetcode'
# that station so update start to next possible station.
# Time - O(n) # https://leetcode.com/problems/single-number/
# Space - O(1) # Given an array of integers, every element appears twice except for one. Find that
single one.
class Solution(object):
def canCompleteCircuit(self, gas, cost): # Any number xor with itself is zero.
""" # Time - O(n)
:type gas: List[int] # Space - O(1)
:type cost: List[int]
:rtype: int class Solution(object):
""" def singleNumber(self, nums):
start, tank, total = 0, 0, 0 """
:type nums: List[int]
for station in range(len(gas)): :rtype: int
balance = gas[station] - cost[station] """
tank += balance xor = 0
total += balance for num in nums:
if tank < 0: xor ^= num
start = station + 1 return xor
tank = 0

copy.next = next
# python_1_to_1000/137_Single_Number_II.py - m node = next

_author_ = 'jake' node = head


_project_ = 'leetcode' while node:
if node.random:
# https://leetcode.com/problems/single-number-ii/ node.next.random = node.random.next
# Given an array of integers, every element appears three times except for one. Find that node = node.next.next
single one.
pseudo = prev = RandomListNode(0)
# If a bit is set in num, but not set in ones or twos then that bit is then set in ones. node = head
# If a bit is set in num, set in ones but not in twos then that bit is then set in twos while node:
and not ones. prev.next = node.next
# If a bit is set in num, but not set in ones or twos then that bit is then set in ones. node.next = node.next.next
# Time - O(n) node = node.next
# Space - O(1) prev = prev.next

class Solution(object): return pseudo.next


def singleNumber(self, nums):
"""
:type nums: List[int] # python_1_to_1000/139_Word_Break.py - m
:rtype: int
""" _author_ = 'jake'
ones, twos = 0, 0 _project_ = 'leetcode'

for num in nums: # https://leetcode.com/problems/word-break/


ones = (ones ^ num) & ~twos # xor of all nums that have appeared once # Given a string s and a dictionary of words dict, determine if s can be segmented into a
only # space-separated sequence of one or more dictionary words.
twos = (twos ^ num) & ~ones # xor of all nums that have appeared twice
only # Dynamic programming. A prefix can be made from words in dictionary if it can be split
into a shorter prefix
return ones # that can be made and another word in dictionary.
# Time - O(n**3), there are O(n**2) substrings s[j:i], each taking O(n) to create
# Space - O(n)

# python_1_to_1000/138_Copy_List_with_Random_Pointer.py class Solution(object):


def wordBreak(self, s, wordDict):
_author_ = 'jake' """
_project_ = 'leetcode' :type s: str
:type wordDict: Set[str]
# https://leetcode.com/problems/copy-list-with-random-pointer/ :rtype: bool
# A linked list is given such that each node contains an additional random pointer which """
could point to any node in the list or null. can_make = [False] * (len(s)+1) # can_make[i] is True if can make prefix
# Return a deep copy of the list. of length i
can_make[0] = True
# Duplicate every node and insert copy in list after original node. Link copied nodes to
random pointers, which for i in range(1, len(s)+1): # prefix length
# follow random pointers of original nodes. Separate out original and copied lists. for j in range(i-1, -1, -1): # j is existing prefix, start with
# Time - O(n) longest + shortest new word
# Space - O(1) if can_make[j] and s[j:i] in wordDict:
can_make[i] = True
# Definition for singly-linked list with a random pointer. break
class RandomListNode(object):
def __init__(self, x): return can_make[-1]
self.label = x
self.next = None
self.random = None
# python_1_to_1000/140_Word_Break_II.py - h
class Solution(object):
def copyRandomList(self, head): _author_ = 'jake'
""" _project_ = 'leetcode'
:type head: RandomListNode
:rtype: RandomListNode # https://leetcode.com/problems/word-break-ii/
""" # Given a string s and a dictionary of words dict, add spaces in s to construct a
node = head sentence where each word is a valid dictionary word.
while node: # Return all such possible sentences.
next = node.next
copy = RandomListNode(node.label) # Test if word can be broken as per problem 139. For all prefixes of s in the
node.next = copy dictionary, recurse on the suffix.
# Time - O(n**3 * 2**(n-1)) self.val = x
# Space - O(n * 2**(n-1)), 2**(n-1) possible partitions of string of length n (every self.next = None
combination of gaps between words)
# each partiton is of length n. Memo for shorter suffixes does not impact big O. class Solution(object):
def hasCycle(self, head):
class Solution(object): """
:type head: ListNode
def canBreak(self, s, wordDict): :rtype: bool
can_make = [False] * (len(s)+1) # can_make[i] is True if can make prefix """
of length i fast, slow = head, head
can_make[0] = True while fast and fast.next:
for i in range(1, len(s)+1): # prefix length slow = slow.next
for j in range(i-1, -1, -1): # j is existing prefix, start with fast = fast.next.next
longest + shortest new word if fast == slow:
if can_make[j] and s[j:i] in wordDict: return True
can_make[i] = True return False
break
return can_make[-1]

# python_1_to_1000/142_Linked_List_Cycle_II.py - m
def wordBreak(self, s, wordDict):
""" _author_ = 'jake'
:type s: str _project_ = 'leetcode'
:type wordDict: Set[str]
:rtype: List[str] # https://leetcode.com/problems/linked-list-cycle-ii/
""" # Given a linked list, return the node where the cycle begins. If there is no cycle,
if not self.canBreak(s, wordDict): return null.
return []
result_lists = self.break_word(s, 0, wordDict, {}) # If there are k nodes before a cycle of c nodes, when slow reaches start of loop, fast
return [" ".join(result) for result in result_lists] # convert back to strings is k % c into loop.
# When fast reaches slow, both are c - k % c into the loop. Restart fast at head and
move both 1 step at a time.
def break_word(self, s, left, wordDict, memo): # break from s[left] onwards # After k steps, both are at start of loop.
# Time - O(n)
if left >= len(s): # base case # Space - O(1)
return [[]]
if left in memo: # Definition for singly-linked list.
return memo[left] class ListNode(object):
def __init__(self, x):
results = [] self.val = x
for i in range(left+1, len(s)+1): # try all possible prefixes self.next = None
prefix = s[left:i]
suffix_breaks = self.break_word(s, i, wordDict, memo) class Solution(object):
if suffix_breaks and prefix in wordDict: def detectCycle(self, head):
for suffix_break in suffix_breaks: """
results.append([prefix] + suffix_break) :type head: ListNode
:rtype: ListNode
memo[left] = results[:] """
return results fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
# python_1_to_1000/141_Linked_List_Cycle.py if fast == slow:

_author_ = 'jake' fast = head


_project_ = 'leetcode' while fast != slow:
fast = fast.next
# https://leetcode.com/problems/linked-list-cycle/ slow = slow.next
# Given a linked list, determine if it has a cycle in it. return slow

# Increment fast pointer by 2 nodes and slow pointer by 1 node per time step. If loop, return None
fast will catch up with slow
# else fast will reach end.
# Time - O(n)
# Space - O(1) # python_1_to_1000/143_Reorder_List.py - m

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


class ListNode(object): _project_ = 'leetcode'
def __init__(self, x):

# https://leetcode.com/problems/reorder-list/ """
# Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… if not root:
# Do this in-place without altering the nodes' values. return []

# Find the mid point, reverse list after mid point, then interleave the 2 sides. preorder = []
# Time - O(n) stack = [root]
# Space - O(1)
while stack:
# Definition for singly-linked list. node = stack.pop()
class ListNode(object): preorder.append(node.val)
def __init__(self, x): if node.right:
self.val = x stack.append(node.right) # push right first so left is popped first
self.next = None if node.left:
stack.append(node.left)
class Solution(object):
def reorderList(self, head): return preorder
"""
:type head: ListNode
:rtype: void Do not return anything, modify head in-place instead. class Solution2(object):
""" def preorderTraversal(self, root):
if not head: result = []
return None self.preorder(root, result)
return result
# set slow to mid for odd length lists, first of second half for even
fast, slow = head, head def preorder(self, node, result):
while fast and fast.next: if not node:
fast = fast.next.next return
slow = slow.next result.append(node.val)
self.preorder(node.left, result)
# reverse nodes after slow (slow has pointers from both sides) self.preorder(node.right, result)
prev, node = None, slow
while node:
prev, node.next, node = node, prev, node.next
# python_1_to_1000/145_Binary_Tree_Postorder_Traversal.py
first, second = head, prev # heads of the normal and reversed lists
while second.next: _author_ = 'jake'
first.next, first = second, first.next # insert second after first _project_ = 'leetcode'
second.next, second = first, second.next # insert first after second
# https://leetcode.com/problems/binary-tree-postorder-traversal/
# Given a binary tree, return the postorder traversal of its nodes' values.

# Maintain a stack of nodes discovered and to be visited. Nodes are added to front of
# python_1_to_1000/144_Binary_Tree_Preorder_Traversal.py result (or the end of a list
# which is reversed before returning result).
_author_ = 'jake' # Add left children to stack before right so right subtrees are visited before left.
_project_ = 'leetcode' # Alternatively, recurse left, recurse right then visit node.
# Time - O(n)
# https://leetcode.com/problems/binary-tree-preorder-traversal/ # Space - O(n)
# Given a binary tree, return the preorder traversal of its nodes' values.
# Definition for a binary tree node.
# Maintain a stack of nodes discovered and to be visited. Add right children to stack class TreeNode(object):
before left so left subtrees def __init__(self, x):
# are visited before right. self.val = x
# Alternatively, visit node, recurse left then recurse right. self.left = None
# Time - O(n) self.right = None
# Space - O(n)
from collections import deque
# Definition for a binary tree node.
class TreeNode(object): class Solution(object):
def __init__(self, x): def postorderTraversal(self, root):
self.val = x """
self.left = None :type root: TreeNode
self.right = None :rtype: List[int]
"""
class Solution(object): if not root:
def preorderTraversal(self, root): return []
"""
:type root: TreeNode result = deque() # deque instead of list so we can append at front
:rtype: List[int] stack = [root]
node.next.prev = self.head
while stack: self.head.next = self.head.next.next
node = stack.pop() key = node.key
result.appendleft(node.val) del node
return key
if node.left:
stack.append(node.left) def update(self, node):
if node.right: node.prev.next = node.next # take out from existing position
stack.append(node.right) node.next.prev = node.prev
self.insert(node) # put back at tail
return list(result)

class Solution2(object): class LRUCache(object):


def postorderTraversal(self, root):
result = [] def __init__(self, capacity):
self.postorder(root, result) """
return result :type capacity: int
"""
def postorder(self, node, result): self.capacity = capacity
if not node: self.queue = DLL()
return self.mapping = {}
self.postorder(node.left, result)
self.postorder(node.right, result)
result.append(node.val) def get(self, key):
"""
:rtype: int
"""
if key not in self.mapping:
# python_1_to_1000/146_LRU_Cache.py - m return -1
node = self.mapping[key]
_author_ = 'jake' self.queue.update(node)
_project_ = 'leetcode' return node.val

# https://leetcode.com/problems/lru-cache/
# Design and implement a data structure for Least Recently Used cache. It should support def set(self, key, value):
the following operations: """
# get(key) - Get the value (will always be positive) of the key if the key exists in the :type key: int
cache, otherwise return -1. :type value: int
# set(key, value) - Set or insert the value if the key is not already present. When the :rtype: nothing
cache reached its capacity, """
# it should invalidate the least recently used item before inserting a new item. if key in self.mapping: # update value and move node to tail
node = self.mapping[key]
# Dictionary stores keys with values of nodes. Nodes form double linked list containing node.val = value
key, value pairs. DLL is in self.queue.update(node)
# order of use with least recent at head and most recent at tail. return
# Time - O(1) to set and get
# Space - O(n) node = Node(key, value) # else new key
self.mapping[key] = node
class Node: self.queue.insert(node)
def __init__(self, key, val):
self.key = key if self.capacity == 0: # cache is full, eject oldest
self.val = val removed_key = self.queue.remove_at_head()
self.prev = None del self.mapping[removed_key]
self.next = None else: # decrement capacity
self.capacity -= 1
class DLL:
def __init__(self):
self.head = Node(None, None) # least recently used, remove at head
self.tail = Node(None, None) # most recently used, add and update at tail # python_1_to_1000/147_Insertion_Sort_List.py - m
self.head.next = self.tail
self.tail.prev = self.head _author_ = 'jake'
_project_ = 'leetcode'
def insert(self, node):
node.prev, self.tail.prev.next = self.tail.prev, node # https://leetcode.com/problems/insertion-sort-list/
node.next, self.tail.prev = self.tail, node # Sort a linked list using insertion sort.

def remove_at_head(self): # Maintain a sorted part of the list. For each next node, find its correct location by
node = self.head.next iterating along sorted section.

# Time - O(n**2) fast, slow, prev = head, head, None


# Space - O(1) while fast and fast.next:
prev, slow, fast = slow, slow.next, fast.next.next
# Definition for singly-linked list.
class ListNode(object): prev.next = None
def __init__(self, x): one = self.sortList(head)
self.val = x two = self.sortList(slow)
self.next = None
return self.merge(one, two)
class Solution(object):
def insertionSortList(self, head):
""" def merge(self, one, two):
:type head: ListNode
:rtype: ListNode dummy = merged = ListNode(None)
"""
sorted_tail = dummy = ListNode(float('-inf')) # sorted_tail is last node of while one and two:
sorted section
dummy.next = head if one.val <= two.val:
merged.next = one
while sorted_tail.next: one = one.next
else:
node = sorted_tail.next merged.next = two
two = two.next
if node.val >= sorted_tail.val: # node already in correct place merged = merged.next
sorted_tail = sorted_tail.next
continue merged.next = one or two # add remaining list

sorted_tail.next = sorted_tail.next.next # cut out node return dummy.next

insertion = dummy
while insertion.next.val <= node.val: # python_1_to_1000/149_Max_Points_on_a_Line.py - h
insertion = insertion.next
_author_ = 'jake'
node.next = insertion.next # put node after insertion _project_ = 'leetcode'
insertion.next = node
# https://leetcode.com/problems/max-points-on-a-line/
return dummy.next # Given n points on a 2D plane, find the maximum number of points that lie on the same
straight line.

# For each point, calculate the gradient of the line to all other points and store in
dictionary. Python accepts
# python_1_to_1000/148_Sort_List.py - m # floats as dictionary keys and floating point accuracy is not an issue for sufficiently
small x and y.
_author_ = 'jake' # Infinite slopes are stored with key of 'inf'. If both x and y are the same, both
_project_ = 'leetcode' points lie on all lines with the
# first point. Calculate the max number of points on a line with each base point in turn,
# https://leetcode.com/problems/sort-list/ only considering other points
# Sort a linked list in O(n log n) time using constant space complexity. # that have not already been the base point.
# Time - O(n**2)
# Base case is empty list or single node. Else recursively split list in half, sort # Space - O(n)
halves and merge.
# Time - O(n log n) # Definition for a point.
# Space - O(n) class Point(object):
def __init__(self, a=0, b=0):
# Definition for singly-linked list. self.x = a
class ListNode(object): self.y = b
def __init__(self, x):
self.val = x from collections import defaultdict
self.next = None
class Solution(object):
class Solution(object): def maxPoints(self, points):
def sortList(self, head): """
""" :type points: List[Point]
:type head: ListNode :rtype: int
:rtype: ListNode """
""" if len(points) <= 2:
if not head or not head.next: return len(points)
return head
overall_max = 2
for i, point in enumerate(points): # for each point _author_ = 'jake'
_project_ = 'leetcode'
gradients = defaultdict(int) # key is gradient, value is nb lines
involving point with this gradient # https://leetcode.com/problems/reverse-words-in-a-string/
max_points = 1 # point is on every line # Given an input string, reverse the string word by word.

for point_2 in points[i+1:]: # check all # Parse int a list of words by spaces, reverse word list and recombine with spaces.
# Time - O(n)
if point.x == point_2.x: # Space - O(n)
if point.y == point_2.y: # same point, on all lines
max_points += 1 class Solution(object):
else: # infinite gradient def reverseWords(self, s):
gradients['inf'] += 1 """
:type s: str
else: :rtype: str
gradient = (point_2.y - point.y) / float(point_2.x - point.x) """
gradients[gradient] += 1 words = s.split()
return " ".join(words[::-1])
if gradients:
max_points += max(gradients.values())
overall_max = max(overall_max, max_points) # python_1_to_1000/152_Maximum_Product_Subarray.py - m

return overall_max _author_ = 'jake'


_project_ = 'leetcode'

# https://leetcode.com/problems/maximum-product-subarray/
# Find the contiguous subarray within an array (containing at least one number) which has
# python_1_to_1000/150_Evaluate_Reverse_Polish_Notation.py - m the largest product.

_author_ = 'jake' # Calculate the most positive and most negative subarray products ending at each element.
_project_ = 'leetcode' # Either the element alone or multiplied by previous most positive or most negative.
# Time - O(n)
# https://leetcode.com/problems/evaluate-reverse-polish-notation/ # Space - O(1)
# Evaluate the value of an arithmetic expression in Reverse Polish Notation.
# Valid operators are +, -, *, /. Each operand may be an integer or another expression. class Solution(object):
def maxProduct(self, nums):
# Push numbers onto stack. Apply operators to top 2 members of stack and push back """
result. :type nums: List[int]
# Faster but less concise without using eval(). :rtype: int
# Time - O(n) """
# Space - O(n) largest_product = float('-inf')
most_neg, most_pos = 1, 1
class Solution(object):
def evalRPN(self, tokens): for num in nums:
""" most_pos, most_neg = max(num, most_pos * num, most_neg * num), min(num,
:type tokens: List[str] most_pos * num, most_neg * num)
:rtype: int largest_product = max(largest_product, most_pos, most_neg)
"""
ops = {'+', '-', '/', '*'} return largest_product
stack = []

for token in tokens:


# python_1_to_1000/153_Find_Minimum_in_Rotated_Sorted_Array.py - m
if token in ops:
right = stack.pop() _author_ = 'jake'
left = stack.pop() _project_ = 'leetcode'
if token == '/':
stack.append(int(left / float(right))) # round down # https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
else: # Suppose a sorted array is rotated at some pivot unknown to you beforehand.
stack.append((eval(str(left) + token + str(right)))) # (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
else: # Find the minimum element.
stack.append(int(token)) # You may assume no duplicate exists in the array.

return stack[-1] # If right element is less than mid element, min mist be to right of mid. Else min mist
be mid or left.
# Time - O(log n)
# Space - O(1)
# python_1_to_1000/151_Reverse_Words_in_a_String.py - m

class Solution(object): _project_ = 'leetcode'


def findMin(self, nums):
""" # https://leetcode.com/problems/min-stack/
:type nums: List[int] # Design a stack that supports push, pop, top, and retrieving the minimum element in
:rtype: int constant time.
""" # push(x) -- Push element x onto stack.
left = 0 # pop() -- Removes the element on top of the stack.
right = len(nums)-1 # top() -- Get the top element.
# getMin() -- Retrieve the minimum element in the stack.
while left < right:
# Main stack has all items, mins stack has items less than or equal to previous min.
if nums[left] <= nums[right]: # not rotated, left is min # Note : no error handling for empty stack required
break # Time - O(1)
# Space - O(n)
mid = (left + right) // 2
if nums[right] < nums[mid]: # min must be on right of mid class MinStack(object):
left = mid + 1
else: # nums[right] > nums[mid] def __init__(self):
right = mid # min must be mid or on left """
# nums[right] != nums[mid] because loop terminated if left == right and if initialize your data structure here.
right == left + 1 then """
# mid == left and since nums are unique num[left] != nums[right] self.main = []
self.mins = []
return nums[left]
def push(self, x):
"""
# python_1_to_1000/154_Find_Minimum_in_Rotated_Sorted_Array_II.py - h :type x: int
:rtype: void
_author_ = 'jake' """
_project_ = 'leetcode' self.main.append(x)
if not self.mins or x <= self.mins[-1]:
# https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/ self.mins.append(x)
# Follow up for "153 Find Minimum in Rotated Sorted Array": What if duplicates are
allowed? def pop(self):
"""
# As per problem 153 except if nums[left] == nums[right] == nums[mid] must search both :rtype: void
left and right. """
# Time - O(n) item = self.main.pop()
# Space - O(1) if item == self.mins[-1]:
self.mins.pop()
class Solution(object):
def findMin(self, nums): def top(self):
""" """
:type nums: List[int] :rtype: int
:rtype: int """
""" return self.main[-1]
left, right = 0, len(nums)-1
def getMin(self):
while left < right: """
:rtype: int
if nums[left] < nums[right]: # already sorted """
break return self.mins[-1]

mid = (left + right) // 2


# python_1_to_1000/156_Binary_Tree_Upside_Down.py - m
if nums[right] < nums[mid]:
left = mid + 1 # discontinuity on RHS of mid _author_ = 'jake'
elif nums[right] > nums[mid] or nums[left] > nums[mid]: _project_ = 'leetcode'
right = mid # discontinuity is mid or LHS
else: # nums[right] == nums[mid] == nums[left] # https://leetcode.com/problems/binary-tree-upside-down/
left += 1 # Given a binary tree where all the right nodes are either leaf nodes with a sibling (a
right -= 1 left node that shares the
# same parent node) or empty, flip it upside down and turn it into a tree where the
return nums[left] original right nodes turned
# into left leaf nodes. Return the new root.

# python_1_to_1000/155_Min_Stack.py - m # Base case for recursion is a leaf node or None. Recursively process left subtree, find
rightmost path, add previous
_author_ = 'jake' # right on left and previous root on right.
# Time - O(n) # python_1_to_1000/158_Read_N_Characters_Given_Read4_II_-_Call_multiple_times.py - h
# Space - O(1)
_author_ = 'jake'
# Definition for a binary tree node. _project_ = 'leetcode'
# class TreeNode(object):
# def __init__(self, x): # https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/
# self.val = x # The API: int read4(char *buf) reads 4 characters at a time from a file.
# self.left = None # The return value is the actual number of characters read.
# self.right = None # By using the read4 API, implement the function int read(char *buf, int n) that reads n
characters from the file.
class Solution(object): # The read function may be called multiple times.
def upsideDownBinaryTree(self, root):
""" # Use a double-linked list to store any characters read by read4 but not required. Use
:type root: TreeNode those characters first
:rtype: TreeNode # on the next call of read().
""" # Time - O(n)
if not root or not root.left: # if no left then no right, leaf # Space - O(n)
return root
# The read4 API is already defined for you.
new_root = self.upsideDownBinaryTree(root.left) # recurse left # @param buf, a list of characters
node = new_root # @return an integer
while node.right: # traverse as far right as possible def read4(buf):
node = node.right pass

node.left = root.right from collections import deque


node.right = root
root.left = None class Solution(object):
root.right = None def __init__(self):
self.leftover = deque() # store chars read by read4 but not added previous
return new_root buf

def read(self, buf, n):


# python_1_to_1000/157_Read_N_Characters_Given_Read4.py """
:type buf: Destination buffer (List[str])
_author_ = 'jake' :type n: Maximum number of characters to read (int)
_project_ = 'leetcode' :rtype: The number of characters read (int)
"""
# https://leetcode.com/problems/read-n-characters-given-read4/ total_chars, added_chars, read_chars = 0, 4, 0
# The API: int read4(char *buf) reads 4 characters at a time from a file.
# The return value is the actual number of characters read. Eg, it returns 3 if only 3 while self.leftover and total_chars < n: # add leftover chars to buf
characters are left in the file. buf[total_chars] = self.leftover.popleft()
# By using the read4 API, implement the function int read(char *buf, int n) that reads n total_chars += 1
characters from the file.
while added_chars == 4 and total_chars < n: # add blocks of 4 chars up to eof
# Read up to 4 chars into buf4 and copy to buf (which is modified in-place). buf4 = [""] * 4 # temporary buffer
# Time - O(n) read_chars = read4(buf4)
# Space - O(n) added_chars = min(read_chars, n - total_chars)
buf[total_chars:total_chars+added_chars] = buf4
# The read4 API is already defined for you. total_chars += added_chars
# @param buf, a list of characters
# @return an integer while read_chars > added_chars: # save extra chars
def read4(buf): self.leftover.append(buf4[added_chars])
pass added_chars += 1

class Solution: return total_chars


def read(self, buf, n):

total_chars, last_chars = 0, 4 # python_1_to_1000/159_Longest Substring_with_At_Most_Two_Distinct_Characters.py - m

while last_chars == 4 and total_chars < n: _author_ = 'jake'


_project_ = 'leetcode'
buf4 = [""] * 4 # temporary buffer
last_chars = min(read4(buf4), n - total_chars) # https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/
buf[total_chars:total_chars+last_chars] = buf4 # Given a string, find the length of the longest substring T that contains at most 2
total_chars += last_chars distinct characters.

return total_chars # Maintain a window of the longest substring. If a 3rd char is found, reset the window
start to after the first
# seen char.

# Time - O(n) if not headA or not headB:


# Space - O(1) return None

class Solution(object): savedA, savedB = headA, headB


def lengthOfLongestSubstringTwoDistinct(self, s):
""" while headA != headB:
:type s: str headA = savedB if not headA else headA.next
:rtype: int headB = savedA if not headB else headB.next
"""
start, max_substring = 0, 0 gc.collect() # required to pass leetocde strict memory usage
last_seen = {} # key is char, value is last index of char return headA

for i, c in enumerate(s):
class Solution2(object):
if c in last_seen or len(last_seen) < 2: # extend substring with same def getIntersectionNode(self, headA, headB):
start """
max_substring = max(max_substring, i - start + 1) :type head1, head1: ListNode
:rtype: ListNode
else: # c not in current substring and 2 chars seen """
for seen in last_seen: if not headA or not headB:
if seen != s[i-1]: # find the char that is not the return None
previous char
start = last_seen[seen] + 1 # move start to after this char savedA, savedB = headA, headB
del last_seen[seen] len_diff = 0
break
while headA.next:
last_seen[c] = i len_diff += 1
headA = headA.next
return max_substring while headB.next:
len_diff -= 1
headB = headB.next

if headA != headB: # no intersection


# python_1_to_1000/160_Intersection_of_Two_Linked_Lists.py return

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


_project_ = 'leetcode'
while len_diff != 0: # traverse longer list for length difference
# https://leetcode.com/problems/intersection-of-two-linked-lists/ if len_diff > 0:
# Write a program to find the node at which the intersection of two singly linked lists headA = headA.next
begins. len_diff -= 1
# If the two linked lists have no intersection at all, return null. else:
# The linked lists must retain their original structure after the function returns. headB = headB.next
# You may assume there are no cycles anywhere in the entire linked structure. len_diff += 1

# Traverse both lists, when reach end switch to start of other list. If lists have l1 while headA != headB:
and l2 nodes before intersect headA = headA.next
# and k nodes after then both traversals intersect after l1 + l2 + k nodes. If no headB = headB.next
intersection, k = 0 and both pointers
# meet at None. gc.collect()
# Alternatively, count lengths and traverse longer list for length difference before return headA
traversing both in step.
# Time - O(n)
# Space - O(1) # python_1_to_1000/161_One_Edit_Distance.py - m

import gc # used to manually clear the memory _author_ = 'jake'


_project_ = 'leetcode'
# Definition for singly-linked list.
class ListNode(object): # https://leetcode.com/problems/one-edit-distance/
def __init__(self, x): # Given two strings s and t, determine if they are both one edit distance apart.
self.val = x
self.next = None # If same lengths find the one different char (replacement edit) and test all else are
same.
class Solution(object): # If length diff of 1, find the extra char in longer and check all else is the same.
def getIntersectionNode(self, headA, headB): # Time - O(n)
""" # Space - O(1)
:type head1, head1: ListNode
:rtype: ListNode class Solution(object):
""" def isOneEditDistance(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool # python_1_to_1000/163_Missing_Ranges.py
"""
diff = len(s) - len(t) _author_ = 'jake'
if abs(diff) > 1: # early break _project_ = 'leetcode'
return False
# https://leetcode.com/problems/missing-ranges/
edit = False # Given a sorted integer array where elements are in the inclusive range [lower, upper],
if diff == 0: # one replacement return its missing ranges.
for c_s, c_t in zip(s, t): # For example, given [0, 1, 3, 50, 75], lower = 0 and upper = 99, return ["2", "4->49",
if c_s != c_t: "51->74", "76->99"].
if edit: # already seen a replacement
return False # Track the last number seen. If num == last_seen+2 then last_seen+1 is the start and
edit = True end of a missing range.
return edit # False if no replacement # If num > last_seen+2 then inclusive range last_seen+1 to num-1 is missing. Update
last_seen. Do nothing if
else: # abs(diff) == 1 # num is last_seen or last_seen+1 since nothing is missing.
long, short = s, t # Time - O(n)
if diff < 0: # Space - O(n)
long, short = short, long
i = 0 # find the mismatch class Solution(object):
while i < len(short) and long[i] == short[i]: def findMissingRanges(self, nums, lower, upper):
i += 1 """
return long[i+1:] == short[i:] # remainders must be same :type nums: List[int]
:type lower: int
:type upper: int
# python_1_to_1000/162_Find_Peak_Element.py - m :rtype: List[str]
"""
_author_ = 'jake' last_seen = lower-1
_project_ = 'leetcode' nums.append(upper+1)
missing = []
# https://leetcode.com/problems/find-peak-element/
# A peak element is an element that is greater than its neighbors. for num in nums:
# Given an input array where num[i] ≠ num[i+1], find a peak element and return its index. if num == last_seen + 2:
# The array may contain multiple peaks, in that case return the index to any one of the missing.append(str(last_seen+1))
peaks is fine. elif num > last_seen + 2:
# You may imagine that num[-1] = num[n] = -∞. missing.append(str(last_seen+1) + '->' + str(num-1))
last_seen = num
# If array has 3 or more elements, return mid if it is a peak else recurse on the side
with a higher element. return missing
# If array has < 3 elements, return index of greater.
# Time - O(log n)
# Space - O(1)
# python_1_to_1000/164_Maximum_Gap.py - m
class Solution(object):
def findPeakElement(self, nums): _author_ = 'jake'
""" _project_ = 'leetcode'
:type nums: List[int]
:rtype: int # https://leetcode.com/problems/maximum-gap/
""" # Given an unsorted array, find the maximum difference between the successive elements in
left, right = 0, len(nums)-1 its sorted form.
# Return 0 if the array contains less than 2 elements.
while left < right - 1: # at least 3 elements # You may assume all elements in the array are non-negative integers and fit in the 32-
bit signed integer range.
mid = (left + right) // 2
# Bucket sort. By pigeon-hole principle we ensure at least one bucket is empty or numbers
if nums[mid] >= nums[mid+1] and nums[mid] >= nums[mid-1]: are equally separated
return mid # by the same distance.
if nums[mid+1] > nums[mid]: # RHS is higher (LHS could be also but # Time - O(n)
arbitrarily choose RHS) # Space - O(n)
left = mid + 1
else: # LHS must be higher if RHS is not class Solution(object):
right = mid - 1 def maximumGap(self, nums):
"""
if nums[left] >= nums[right]: :type nums: List[int]
return left :rtype: int
return right """

if len(nums) < 2: return 1


return 0 if i1 < i2:
return -1
lower = min(nums)
difference = max(nums) - lower return 0 # all version components are same
gaps = len(nums) - 1 # number of spaces between sorted nums
if difference == 0: # all nums are same
return 0 # python_1_to_1000/166_Fraction_to_Recurring_Decimal.py - m

width = difference // gaps # range of integers // number of gaps _author_ = 'jake'


if width == 0: _project_ = 'leetcode'
width = 1
# https://leetcode.com/problems/fraction-to-recurring-decimal/
nb_buckets = 1 + difference // width # ensure max(nums) goes in final bucket # Given two integers representing the numerator and denominator of a fraction, return the
fraction in string format.
buckets = [[None, None] for _ in range(nb_buckets)] # max and min of each bucket # If the fractional part is repeating, enclose the repeating part in parentheses.

for num in nums: # Find the initial integer part then repeatedly multiply by 10, divide by denominator and
bucket = (num - lower) // width calculate remainder. If
buckets[bucket][0] = min(buckets[bucket][0], num) if buckets[bucket][0] != # same remainder repeats there is a cycle.
None else num
buckets[bucket][1] = max(buckets[bucket][1], num) if buckets[bucket][1] != class Solution(object):
None else num def fractionToDecimal(self, numerator, denominator):
"""
last_used_bucket = 0 :type numerator: int
max_gap = difference // gaps # default case of no empty buckets :type denominator: int
for i in range(nb_buckets - 1): :rtype: str
if not buckets[i][0] and buckets[i + 1][0]: """
max_gap = max(max_gap, buckets[i + 1][0] - buckets[last_used_bucket][1]) if denominator == 0:
elif buckets[i][0]: return None
last_used_bucket = i decimal = [] # store result as a list
if numerator * denominator < 0: # negative sign
return max_gap decimal.append('-')

output, remainder = divmod(abs(numerator), abs(denominator)) # divide and


modulo combined
# python_1_to_1000/165_Compare_Version_Numbers.py - m decimal.append(str(output))
if remainder == 0:
_author_ = 'jake' return "".join(decimal)
_project_ = 'leetcode'
decimal.append('.')
# https://leetcode.com/problems/compare-version-numbers/ seen = {} # key is remainder, value is index in decimal
# Compare two version numbers version1 and version2.
# If version1 > version2 return 1, if version1 < version2 return -1, otherwise return 0. while remainder != 0:
# You may assume that the version strings are non-empty and contain only digits and the . if remainder in seen:
character. return "".join(decimal[:seen[remainder]] + ['('] +
# The . character does not represent a decimal point and is used to separate number decimal[seen[remainder]:] + [')'])
sequences. seen[remainder] = len(decimal)
output, remainder = divmod(remainder*10, abs(denominator))
# Split by '.' and pad shorter list with [0]. Then compare each section. decimal.append(str(output))
# Time - O(n)
# Space - O(n) return "".join(decimal)

import itertools

class Solution(object):
def compareVersion(self, version1, version2): # python_1_to_1000/167_Two_Sum_II_-_Input_array_is_sorted.py - m
"""
:type version1: str _author_ = 'jake'
:type version2: str _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/
v1 = [int(v) for v in version1.split('.')] # split by "." and # Given an array of integers that is already sorted in ascending order, find an ordered
convert to int pair of indices of two numbers
v2 = [int(v) for v in version2.split('.')] # such that they add up to a specific target number.
# Please note that your returned answers (both index1 and index2) are not zero-based.
for i1, i2 in itertools.zip_longest(v1, v2, fillvalue=0): # pad shorter with # You may assume that each input would have exactly one solution.
zeros
if i1 > i2: # Start pointers at both ends of array. Increment left if sum is too low or decrement
right if sum is too high. # When the count is zero, the next element becomes the candidate. When an element is the
# Time - O(n) same as the candidate,
# Space - O(1) # increment the count, else decrement the count.
# Time - O(n)
class Solution(object): # Space - O(1)
def twoSum(self, numbers, target):
""" class Solution(object):
:type numbers: List[int] def majorityElement(self, nums):
:type target: int """
:rtype: List[int] :type nums: List[int]
""" :rtype: int
left, right = 0, len(numbers)-1 """
count, candidate = 0, None
while True:
for i, num in enumerate(nums):
pair_sum = numbers[left] + numbers[right]
if pair_sum == target: if count == 0:
return [left+1, right+1] candidate = num

if pair_sum < target: if candidate == num:


left += 1 count += 1
else: else:
right -= 1 count -= 1

return candidate
# python_1_to_1000/168_Excel_Sheet_Column_Title.py

_author_ = 'jake' # python_1_to_1000/170_Two_Sum_III_-_Data_structure_design.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/excel-sheet-column-title/ _project_ = 'leetcode'
# Given a positive integer, return its corresponding column title as appear in an Excel
sheet. # https://leetcode.com/problems/two-sum-iii-data-structure-design/
# For example:, 1 -> A, 2 -> B, 3 -> C, ..., 26 -> Z, 27 -> AA # Design and implement a TwoSum class. It should support the following operations: add
and find.
# Generate characters starting with least significant by calculating remainder of # add - Add the number to an internal data structure.
division by 26. # find - Find if there exists any pair of numbers which sum is equal to the value.
# Time - O(log n)
# Space - O(log n) # Use a dictionary to store each number and whether it has been added multiple times. To
find, for each num in
from collections import deque # dictionary look for the difference between target value and that num, or for the num to
be duplicated if it
class Solution(object): # is half of the target value.
def convertToTitle(self, n): # Time - O(1) to add, O(n) to find
""" # Space - O(n)
:type n: int
:rtype: str class TwoSum(object):
"""
column = deque() # faster than list for appendleft() def __init__(self):
while n > 0: """
n, output = divmod(n-1, 26) initialize your data structure here
column.appendleft(output) """
self.nums = {} # key is num, value is True if num is duplicated else False
return "".join([chr(i+ord('A')) for i in column])
def add(self, number):
"""
Add the number to an internal data structure.
:rtype: nothing
# python_1_to_1000/169_Majority_Element.py """
self.nums[number] = number in self.nums # False for first occurence, True for
_author_ = 'jake' multiple occurrences
_project_ = 'leetcode'
def find(self, value):
# https://leetcode.com/problems/majority-element/ """
# Given an array of size n, find the majority element. The majority element appears more Find if there exists any pair of numbers which sum is equal to the value.
than [n/2] times. :type value: int
# You may assume that the array is non-empty and the majority element always exist in the :rtype: bool
array. """
for num in self.nums:

if value == 2 * num: # need num to be duplicated # python_1_to_1000/173_Binary_Search_Tree_Iterator.py - m


if self.nums[num]:
return True _author_ = 'jake'
else: # look for difference _project_ = 'leetcode'
if value - num in self.nums:
return True # https://leetcode.com/problems/binary-search-tree-iterator/
return False # 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.
# next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is
the height of the tree.
# python_1_to_1000/171_Excel_Sheet_Column_Number.py
# Iterative inorder traversal. Go left to smallest node, pushing all nodes onto stack.
_author_ = 'jake' After popping a node,
_project_ = 'leetcode' # add to stack all nodes on path to its inorder successor by moving to right child then
as far left as possible.
# https://leetcode.com/problems/excel-sheet-column-number/ # Time - O(n) worst case and O(1) average for __init__() and next().
# Given a column title as appear in an Excel sheet, return its corresponding column # Space - O(n) worst case, log n if balanced.
number.
# Definition for a binary tree node
# For each char, multiply previous result by 26 and add value of char class TreeNode(object):
# Time - O(n) def __init__(self, x):
# Space - O(n) self.val = x
self.left = None
class Solution(object): self.right = None
def titleToNumber(self, s):
""" class BSTIterator(object):
:type s: str def __init__(self, root):
:rtype: int """
""" :type root: TreeNode
result = 0 """
for c in s: self.stack = []
result = result*26 + ord(c) - ord('A') + 1 while root:
return result self.stack.append(root)
root = root.left

# python_1_to_1000/172_Factorial_Trailing_Zeros.py - m def hasNext(self):


"""
_author_ = 'jake' :rtype: bool
_project_ = 'leetcode' """
return True if self.stack else False
# https://leetcode.com/problems/factorial-trailing-zeroes/
# Given an integer n, return the number of trailing zeroes in n!. def next(self):
"""
# Every trailing zero is created by a factor of 5 (since there are many more factors of 2 :rtype: int
that together make """
# trailing zeroes). Count the numbers in 1..n that are divisible by 5, then those node = self.stack.pop()
divisible by 25 which have a result = node.val
# second factor of 5, then 125 etc ... if node.right:
# Time - O(log n) node = node.right
# Space - O(1) while node:
self.stack.append(node)
class Solution(object): node = node.left
def trailingZeroes(self, n): return result
"""
:type n: int
:rtype: int # python_1_to_1000/174_Dungeon_Game.py - h
"""
zeroes = 0 _author_ = 'jake'
power_of_5 = 5 _project_ = 'leetcode'

while power_of_5 <= n: # https://leetcode.com/problems/dungeon-game/


zeroes += n // power_of_5 # The demons had captured the princess (P) and imprisoned her in the bottom-right corner
power_of_5 *= 5 of a dungeon.
# The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was
return zeroes 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
# to 0 or below, he dies immediately. nums = list(map(str, nums)) # convert to strings
# Some of the rooms are guarded by demons, so the knight loses health (negative integers) nums.sort(key=functools.cmp_to_key(comparator))
upon entering these rooms;
# other rooms are either empty (0's) or contain magic orbs that increase the knight's return str(int("".join(nums))) # remove excess leading zeroes
health (positive integers).
# 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 # python_1_to_1000/186_Reverse_Words_in_a_String_II.py - m
rescue the princess.
_author_ = 'jake'
# Dynamic programming. Min health to reach end from any room is health lost/gained in _project_ = 'leetcode'
that room + min required
# after moving down or right, floored at 1 since health cannot be zero. # https://leetcode.com/problems/reverse-words-in-a-string-ii/
# Time - O(n * m) # Given an input string, reverse the string word by word. A word is defined as a sequence
# Space - O(n + m) of non-space characters.
# The input string does not contain leading or trailing spaces and the words are always
class Solution(object): separated by a single space.
def calculateMinimumHP(self, dungeon):
""" # Revese entire string then reverse each word individually.
:type dungeon: List[List[int]] # Alternatively use built-in reverse() and reversed() functions.
:rtype: int # Time - O(n)
""" # Space - O(1)
rows, cols = len(dungeon), len(dungeon[0])
class Solution:
for r in range(rows - 1): # add new final column and row of infinity # @param s, a list of 1 length strings, e.g., s = ['h','e','l','l','o']
dungeon[r].append(float('inf')) # @return nothing
dungeon.append([float('inf') for _ in range(cols + 1)]) def reverseWords(self, s):

dungeon[rows - 1].append(1) # final room requires min health of 1 self.reverse(s, 0, len(s)-1)

for r in range(rows - 1, -1, -1): s.append(' ') # temporary space to signify end of last word
for c in range(cols - 1, -1, -1): start = 0
dungeon[r][c] = max(1, -dungeon[r][c] + min(dungeon[r+1][c], dungeon[r] for i in range(len(s)):
[c+1])) if s[i] == ' ':
self.reverse(s, start, i-1) # reverse word from start to i-1
return dungeon[0][0] start = i+1 # start of next word
s.pop()

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


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

# https://leetcode.com/problems/largest-number/
# Given a list of non negative integers, arrange them such that they form the largest class Solution2:
number. def reverseWords(self, s):
# For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330. s.reverse()
# Note: The result may be very large, so you need to return a string instead of an s.append(' ')
integer. start = 0
for i in range(len(s)):
# Comparator sorts by checking which order of concatenation gives the larger result. if s[i] == ' ':
# Time - O(n log n) s[start:i] = reversed(s[start:i])
# Space - O(n) start = i+1
s.pop()
import functools

class Solution: # python_1_to_1000/187_Repeated_DNA_Sequences.py - m


# @param {integer[]} nums
# @return {string} _author_ = 'jake'
def largestNumber(self, nums): _project_ = 'leetcode'

def comparator(x, y): # inputs are string representations of non-negative ints # https://leetcode.com/problems/repeated-dna-sequences/
if x+y > y+x: # no need to convert to int because x+y and y+x are same # All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for
length example: "ACGAATTCCG".
return -1 # so lexicographic string sort behaves like numeric sort # When studying DNA, it is sometimes useful to identify repeated sequences within the
else: DNA.
return 1 # Write a function to find all the 10-letter-long sequences (substrings) that occur more
than once in a DNA molecule.

return max(sells)
# Store all substrings of length 10 in a set, if substring is duplicated add to result
set.
# Time - O(n)
# Space - O(n) # python_1_to_1000/189_Rotate_Array.py - m

class Solution(object): _author_ = 'jake'


def findRepeatedDnaSequences(self, s): _project_ = 'leetcode'
"""
:type s: str # https://leetcode.com/problems/rotate-array/
:rtype: List[str] # Rotate an array of n elements to the right by k steps.
"""
substrings, repeated = set(), set() # Reverse entire array, then reverse left k elements and right n-k elements.
TARGET = 10 # Alternatively, split after n-k elements and swap slices.
# Time - O(n)
for i in range(len(s)-TARGET+1): # Space - O(1)

substring = s[i:i+TARGET] class Solution(object):


if substring in substrings: def rotate(self, nums, k):
repeated.add(substring) """
else: :type nums: List[int]
substrings.add(substring) :type k: int
:rtype: void Do not return anything, modify nums in-place instead.
return list(repeated) # convert set to list """
k %= len(nums)
nums.reverse()
# python_1_to_1000/188_Best_Time_to_Buy_and_Sell_Stock_IV.py - h nums[:k] = reversed(nums[:k])
nums[k:] = reversed(nums[k:])
_author_ = 'jake'
_project_ = 'leetcode' class Solution2(object):
def rotate(self, nums, k):
# https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/ n = len(nums)
# Say you have an array for which the ith element is the price of a given stock on day i. k %= n
# Design an algorithm to find the maximum profit. You may complete at most k nums[:] = nums[n-k:] + nums[:n-k]
transactions.
# You may not engage in multiple transactions at the same time (ie, you must sell the
stock before you buy again). # python_1_to_1000/190_Reverse_Bits.py

# Dynamic programming. Max profit after i buys = cost + max after i-1 transactions. _author_ = 'jake'
# Max profit after i sells = sale price + max after i-1 transactions and additional buy. _project_ = 'leetcode'
# Time - O(n * k)
# Space - O(n * k) # https://leetcode.com/problems/reverse-bits/
# Reverse bits of a given 32 bits unsigned integer.
class Solution(object): # For example, given input 43261596 (represented in binary as
def maxProfit(self, k, prices): 00000010100101000001111010011100),
""" # return 964176192 (represented in binary as 00111001011110000010100101000000).
:type k: int
:type prices: List[int] # Convert to string of binary. Reverse and convert base 2 string back to int.
:rtype: int # Alternatively, if bit i is set than add 2**(31-i) to the result.
""" # Time - O(log n)
if k >= len(prices) // 2: # can transact as often as required to get max # Space - O(log n)
profit
return sum([max(0, prices[i] - prices[i-1]) for i in range(1, len(prices))]) class Solution:
# @param n, an integer
# buys[i] is the max profit after i-1 buy/sell transactions and another buy # @return an integer
# sells[i] is the max profit after i buy/sell transactions def reverseBits(self, n):
buys, sells = [float('-inf') for _ in range(k + 1)], [0 for _ in range(k + 1)] binary = bin(n)
binary = binary[2:] # remove header '0b'
for price in prices: reversed_binary = binary[::-1] + ''.join(['0' for _ in range(32 - len(binary))])
for i in range(1, len(buys)): return int(reversed_binary, 2) # convert from base 2

buys[i] = max(buys[i], sells[i-1] - price) # add -price to previous best


after i-1 transactions class Solution2:
if buys[i] == buys[i-1]: # additional transaction has # @param n, an integer
not increased profit # @return an integer
break def reverseBits(self, n):
sells[i] = max(sells[i], buys[i] + price) # add +price to max after i-1
transactions and another buy reversed, bit = 0, 31
while n != 0: # python_1_to_1000/199_Binary_Tree_Right_Side_View.py - m
if n % 2 == 1: # last bit is set
reversed += 2**bit _author_ = 'jake'
bit -= 1 _project_ = 'leetcode'
n //= 2
# https://leetcode.com/problems/binary-tree-right-side-view/
return reversed # 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.

# python_1_to_1000/191_Number_of_1_Bits.py # BFS layer by layer. Add to result last value found in a layer.
# Alternatively, recursively pre-order traverse tracking depth and updating result for
_author_ = 'jake' each node.
_project_ = 'leetcode' # Time - O(n)
# Space - O(n)
# https://leetcode.com/problems/number-of-1-bits/
# Write a function that takes an unsigned integer and returns the number of ’1' bits # Definition for a binary tree node.
(known as the Hamming weight). class TreeNode(object):
def __init__(self, x):
# Convert to string and count '1' chars. self.val = x
# Time - O(log n) self.left = None
# Space - O(log n) self.right = None

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


def hammingWeight(self, n): def rightSideView(self, root):
""" """
:type n: int :type root: TreeNode
:rtype: int :rtype: List[int]
""" """
return sum(c == "1" for c in bin(n)[2:]) if not root:
return []

# python_1_to_1000/198_House_Robber.py - m right_view = []
layer = [root]
_author_ = 'jake'
_project_ = 'leetcode' while layer:

# https://leetcode.com/problems/house-robber/ right_view.append(layer[-1].val)
# You are a professional robber planning to rob houses along a street. Each house has a next_layer = []
certain amount of money stashed,
# the only constraint stopping you from robbing each of them is that adjacent houses have for node in layer:
security system connected and if node.left:
# it will automatically contact the police if two adjacent houses were broken into on the next_layer.append(node.left)
same night. if node.right:
# Given a list of non-negative integers representing the amount of money of each house, next_layer.append(node.right)
determine the maximum amount
# of money you can rob tonight without alerting the police. layer = next_layer

# Either do not rob current house and take max from all previous houses, or rob current return right_view
house, skip previous and
# take max of all others.
# Time - O(n) class Solution2(object):
# Space - O(1) def rightSideView(self, root):
right_side = []
class Solution(object): self.recursive(root, 0, right_side)
def rob(self, nums): return right_side
"""
:type nums: List[int] def recursive(self, node, depth, right_side):
:rtype: int
""" if not node:
if not nums: return
return 0
loot, prev = nums[0], 0 # max from robbing this and previous adjacent houses if depth >= len(right_side): # update right_side with this node
right_side.append(node.val)
for num in nums[1:]: else:
loot, prev = max(num + prev, loot), loot right_side[depth] = node.val

return loot self.recursive(node.left, depth+1, right_side) # recurse left before right


self.recursive(node.right, depth+1, right_side)

def rangeBitwiseAnd(self, m, n):


# python_1_to_1000/200_Number_of_Islands.py - m """
:type m: int
_author_ = 'jake' :type n: int
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/number-of-islands/ if m == 0:
# Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. return 0
# An island is surrounded by water and is formed by connecting adjacent lands result = 0
horizontally or vertically.
# You may assume all four edges of the grid are all surrounded by water. bit = int(log(n, 2)) # highest bit that is set in n

# If cell is '1' then set to '0' and recurse for all adjacent cells. while bit >= 0 and ((m & (1 << bit)) == (n & (1 << bit))):
# Time - O(m * n) if (m & (1 << bit)): # if this bit is set
# Space - O(1) result += 2**bit
bit -= 1
class Solution(object):
def numIslands(self, grid): return result
"""
:type grid: List[List[str]]
:rtype: int # python_1_to_1000/202_Happy_Number.py
"""
if not grid: _author_ = 'jake'
return 0 _project_ = 'leetcode'

rows, cols = len(grid), len(grid[0]) # https://leetcode.com/problems/happy-number/


islands = 0 # Write an algorithm to determine if a number is "happy".
for r in range(rows): # A happy number is a number defined by the following process: Starting with any positive
for c in range(cols): integer,
if grid[r][c] == '1': # replace the number by the sum of the squares of its digits, and repeat the process
islands += 1 until the number equals 1
self.set_island(r, c, grid) # (where it will stay), or it loops endlessly in a cycle which does not include 1. Those
numbers for which this
return islands # process ends in 1 are happy numbers.

def set_island(self, row, col, grid): # Fast and slow pointers increment to the next sum of square digits. If in a cycle
if row < 0 or row >= len(grid) or col < 0 or col >= len(grid[0]): pointers will converge at
return # a value other than 1, if no cycle pointers will both be 1.
if grid[row][col] != '1': # Alternatively, if n == 4 then we are in a cycle. See
return https://en.wikipedia.org/wiki/Happy_number
grid[row][col] = '0' # Time - O(log n)
self.set_island(row+1, col, grid) # Space - O(1)
self.set_island(row-1, col, grid)
self.set_island(row, col+1, grid) class Solution(object):
self.set_island(row, col-1, grid) def isHappy(self, n):
"""
:type n: int
:rtype: bool
# python_1_to_1000/201_Bitiwse_AND_of_Numbers_Range.py - m """
if n == 1:
_author_ = 'jake' return True, 1
_project_ = 'leetcode' slow = sum([int(c)*int(c) for c in str(n)])
fast = sum([int(c)*int(c) for c in str(slow)])
# https://leetcode.com/problems/bitwise-and-of-numbers-range/
# Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all while fast != slow:
numbers in this range, inclusive. slow = sum([int(c)*int(c) for c in str(slow)])
fast = sum([int(c)*int(c) for c in str(fast)])
# Starting from the most significant bit that is set in n, compare each bit in n to the fast = sum([int(c)*int(c) for c in str(fast)])
equivalent bit in m.
# If both bits are the same, set the same bit in the result to its value in m and n. return slow == 1
# Stop when a bit is set differently in m and n.
# When any bit is different, all less significant bits must take on both values of 0 and class Solution2(object):
1 in the range. def isHappy(self, n):
# Time - O(log n) """
# Space - O(1) :type n: int
:rtype: bool
from math import log """
while True:
class Solution(object): if n == 1:
return True
if n == 4: sieve[i*i:n:i] = [False] * len(sieve[i*i:n:i]) # list comprehension
return False faster than loop
n = sum([int(c)*int(c) for c in str(n)]) # start at i*i since i*
(i-1) already eliminated
return sum(sieve)

# python_1_to_1000/203_Remove_Linked_List_Elements.py
# python_1_to_1000/205_Isomorphic_Strings.py
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/remove-linked-list-elements/
# Remove all elements from a linked list of integers that have value val. # https://leetcode.com/problems/isomorphic-strings/
# Given two strings s and t, determine if they are isomorphic.
# Iterate along list, cutting out nodes with val. # Two strings are isomorphic if the characters in s can be replaced to get t.
# Time - O(n) # All occurrences of a character must be replaced with another character while preserving
# Space - O(1) the order of characters.
# No two characters may map to the same character but a character may map to itself.
# Definition for singly-linked list.
class ListNode(object): # Store a mapping from chars of s to chars of t. If a char in s is already in mapping
def __init__(self, x): then check that the char in t
self.val = x # is same as previously observed. Check also that a new mapping of char in s is not to a
self.next = None char in t already mapped.
# Time - O(n)
class Solution(object): # Space - O(n)
def removeElements(self, head, val):
""" class Solution(object):
:type head: ListNode def isIsomorphic(self, s, t):
:type val: int """
:rtype: ListNode :type s: str
""" :type t: str
dummy = prev = ListNode(None) # dummy in case head is deleted :rtype: bool
dummy.next = head """
if len(s) != len(t):
while head: return False

if head.val == val: s_to_t = {}


prev.next, head.next, head = head.next, None, head.next t_mapped = set()
else:
prev, head = head, head.next for cs, ct in zip(s, t):

return dummy.next if cs in s_to_t:


if s_to_t[cs] != ct:
return False
# python_1_to_1000/204_Count_Primes.py - m elif ct in t_mapped:
return False
_author_ = 'jake' s_to_t[cs] = ct
_project_ = 'leetcode' t_mapped.add(ct)

# https://leetcode.com/problems/count-primes/ return True


# Count the number of prime numbers less than a non-negative number, n.

# Sieve numbers. Assume all are prime and eliminate those with factors.
# Time - O(n***3/2) # python_1_to_1000/206_Reverse_Linked_List.py
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def countPrimes(self, n):
""" # https://leetcode.com/problems/reverse-linked-list/
:type n: int # Reverse a singly linked list.
:rtype: int
""" # Iterative resvers. Alternatively, use recursion.
sieve = [False, False] + [True for _ in range(n-2)] # 0 and 1 are not prime # Time - O(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) # Definition for singly-linked list.
class ListNode(object):
if sieve[i]: # i is prime def __init__(self, x):

self.val = x
self.next = None
# python_1_to_1000/208_Implement_Trie_(Prefix_Tree).py - m
class Solution(object):
def reverseList(self, head): _author_ = 'jake'
""" _project_ = 'leetcode'
:type head: ListNode
:rtype: ListNode # https://leetcode.com/problems/implement-trie-prefix-tree/
""" # Implement a trie with insert, search, and startsWith methods.
reversed = None # You may assume that all inputs are consist of lowercase letters a-z
while head:
next = head.next # Node stores dictionary mapping letters to child nodes. Array would use fixed space
head.next = reversed regardless of actual nb children.
reversed = head # Note that node does not explicitly store letter.
head = next # Time - O(n) to create where n is total length of all words, O(k) to search where k is
return reversed length of word.
# Space - O(n)

# python_1_to_1000/207_Course_Schedule.py - m class TrieNode(object):


def __init__(self):
_author_ = 'jake' """
_project_ = 'leetcode' Initialize your data structure here.
"""
# https://leetcode.com/problems/course-schedule/ self.children = {} # mapping from letter to child TrieNodes
# There are a total of n courses you have to take, labeled from 0 to n - 1. self.terminal = False # flag indicates whole word
# 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] class Trie(object):
# Given the total number of courses and a list of prerequisite pairs, is it possible for
you to finish all courses? def __init__(self):
self.root = TrieNode()
# Topological sort. Find nodes with no dependencies. Remove outgoing edges from each self.root.terminal = True # empty string is a whole word
such node. Repeat until
# no node has no dependencies. def insert(self, word):
# Time - O(m + n), edges + nodes """
# Space - O(m + n) Inserts a word into the trie.
:type word: str
from collections import defaultdict :rtype: void
"""
class Solution(object): node = self.root
def canFinish(self, numCourses, prerequisites): for c in word:
""" if c not in node.children: # create a node if it does not exist
:type numCourses: int node.children[c] = TrieNode()
:type prerequisites: List[List[int]] node = node.children[c]
:rtype: bool node.terminal = True # set to True at end of word
"""
nb_prerequisites = defaultdict(int) # key is course, value is number of def search(self, word):
prerequisite courses """
prereq_list = defaultdict(list) # key is a course, value is list of Returns if the word is in the trie.
courses that depend on course :type word: str
:rtype: bool
for after, before in prerequisites: """
nb_prerequisites[after] += 1 node = self.root
prereq_list[before].append(after) for c in word:
if c in node.children:
can_take = set(i for i in range(numCourses)) - set(nb_prerequisites.keys()) node = node.children[c]
else:
while can_take: return False
return node.terminal # only True if terminal
course = can_take.pop() # take any course with no
prerequisites def startsWith(self, prefix):
numCourses -= 1 # decrement count of remaining """
courses to be taken Returns if there is any word in the trie
for dependent in prereq_list[course]: that starts with the given prefix.
nb_prerequisites[dependent] -= 1 # decrement count of dependencies :type prefix: str
if nb_prerequisites[dependent] == 0: # no more prerequisites :rtype: bool
can_take.add(dependent) """
node = self.root
return numCourses == 0 for c in prefix:
if c in node.children:
node = node.children[c] """
else: :type numCourses: int
return False :type prerequisites: List[List[int]]
return True :rtype: List[int]
"""
order = []
# python_1_to_1000/209_Minimum_Size_Subarray_Sum.py - m nb_prerequisites = defaultdict(int) # key is course, value is number of
prerequisite courses
_author_ = 'jake' prereq_list = defaultdict(list) # key is a course, value is list of
_project_ = 'leetcode' courses that depend on course

# https://leetcode.com/problems/minimum-size-subarray-sum/ for after, before in prerequisites:


# Given an array of n positive integers and a positive integer s, find the minimal length nb_prerequisites[after] += 1
of a prereq_list[before].append(after)
# subarray of which the sum ≥ s. If there isn't one, return 0 instead.
can_take = set(i for i in range(numCourses)) - set(nb_prerequisites.keys())
# Maintain a sliding window and increase the end by 1 element at every step. Whenever
the subarray sum is >= s then while can_take:
# update min_length and increment the starting index until the subarray sum < s.
# Time - O(n) course = can_take.pop() # take any course with no
# Space - O(1) prerequisites
order.append(course)
class Solution(object): for dependent in prereq_list[course]:
def minSubArrayLen(self, s, nums): nb_prerequisites[dependent] -= 1 # decrement count of dependencies
""" if nb_prerequisites[dependent] == 0: # no more prerequisites
:type s: int can_take.add(dependent)
:type nums: List[int]
:rtype: int return order if len(order) == numCourses else []
"""
subarray_sum, min_length, start = 0, len(nums) + 1, 0 # min_length len(nums)+1
indicates no subarray sum >= s # python_1_to_1000/211_Add_and_Search_Word_-_Data_structure_design.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/add-and-search-word-data-structure-design/
while subarray_sum >= s: # decrease window # Design a data structure that supports the following two operations:
min_length = min(min_length, i - start + 1) # void addWord(word)
subarray_sum -= nums[start] # bool search(word)
start += 1 # search(word) can search a literal word or a regular expression string containing only
letters a-z or '.' (one letter).
return 0 if min_length > len(nums) else min_length
# Store of a list of words by length. Check search word against list of words of same
length by checking each char
# python_1_to_1000/210_Course_Schedule_II.py - m # and ignoring '.'.
# Alternatively use a trie to store words and when search char is '.' then search all
_author_ = 'jake' children.
_project_ = 'leetcode' # Time - O(1) to addWord, O(n * k_ search where there are n strings of length k
# Space - O(t), total number of chars in all strings
# https://leetcode.com/problems/course-schedule-ii/
# There are a total of n courses you have to take, labeled from 0 to n - 1. from collections import defaultdict
# Some courses may have prerequisites, for example to take course 0 you have to first
take course 1, class WordDictionary(object):
# which is expressed as a pair: [0,1]. Given the total number of courses and a list of def __init__(self):
prerequisite pairs, """
# return the ordering of courses you should take to finish all courses. There may be initialize your data structure here.
multiple correct orders, """
# you just need to return one of them. If it is impossible to finish all courses, return self.words = defaultdict(list)
an empty array.
def addWord(self, word):
# As per problem 207, find courses with no prerequisites and remove dependencies on such """
courses. Adds a word into the data structure.
# Time - O(m + n) :type word: str
# Space - O(m + n) :rtype: void
"""
from collections import defaultdict self.words[len(word)].append(word)

class Solution(object): def search(self, word):


def findOrder(self, numCourses, prerequisites): """

Returns if the word is in the data structure. A word could letter = board[r][c]
contain the dot character '.' to represent any one letter. if letter not in node.children:
:type word: str return
:rtype: bool
""" node = node.children[letter]
for w in self.words[len(word)]: if node.word:
for i, c in enumerate(w): found.append(node.word)
if word[i] != '.' and word[i] != c: node.word = None # avoid duplication of results
break
else: board[r][c] = '*' # temporarily flag this cell as being used
return True self.search(board, node, r+1, c, found)
return False self.search(board, node, r-1, c, found)
self.search(board, node, r, c+1, found)
self.search(board, node, r, c-1, found)
board[r][c] = letter # replace cell contents

# python_1_to_1000/212_Word_Search_II.py - h

_author_ = 'jake' # python_1_to_1000/213_House_Robber_II.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/word-search-ii/ _project_ = 'leetcode'
# Given a 2D board and a list of words from the dictionary, find all words in the board.
# Each word must be constructed from letters of sequentially adjacent cell, where # https://leetcode.com/problems/house-robber-ii/
"adjacent" cells are those # This is an extension of 198 House Robber.
# horizontally or vertically neighboring. The same letter cell may not be used more than # After robbing those houses on that street, the thief has found himself a new place for
once in a word. his thievery so that he
# will not get too much attention. This time, all houses at this place are arranged in a
# Build a trie of the words to be found. For each starting cell of the board, if cell circle. That means the first
contains same letter as a child # house is the neighbor of the last one. Meanwhile, the security system for these houses
# of the trie node then update node to child and recurse on 4 surrounding cells. Add remain the same as for
complete words to found list. # those in the previous street.
# Overwrite letters used in each dfs with '*' char (not used in words) during recursion # Given a list of non-negative integers representing the amount of money of each house,
then replace before return. determine the maximum
# Time - O(m * n * t) where board is m by n and t is total number of chars in all words # amount of money you can rob tonight without alerting the police.
# Space - O(t) for trie
# As per 198 except consider the greater of 2 cases - allow robbing the first house but
class Node: no the last, allow robbing the
def __init__(self): # last house but not the first.
self.children = {} # map letter to child node # Time - O(n)
self.word = None # Space - O(1)

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


def findWords(self, board, words): def rob(self, nums):
""" """
:type board: List[List[str]] :type nums: List[int]
:type words: List[str] :rtype: int
:rtype: List[str] """
""" if len(nums) < 2:
root = Node() return sum(nums) # 1 house has no neighbours
for word in words: # build a trie
node = root loot, prev = 0, 0
for c in word: for num in nums[1:]: # do not rob first house
if c not in node.children: loot, prev = max(num + prev, loot), loot
node.children[c] = Node()
node = node.children[c] nums[-1] = 0 # do not rob last house
node.word = word # node is end of complete word loot2, prev = 0, 0
for num in nums:
found = [] loot2, prev = max(num + prev, loot2), loot2
for r in range(len(board)):
for c in range(len(board[0])): return max(loot, loot2)
self.search(board, root, r, c, found)
return found
# python_1_to_1000/214_Shortest_Palindrome.py - h
def search(self, board, node, r, c, found): # depth first search of board
_author_ = 'jake'
if r < 0 or r >= len(board) or c < 0 or c >= len(board[0]): _project_ = 'leetcode'
return
# https://leetcode.com/problems/shortest-palindrome/
# Given a string S, you are allowed to convert it to a palindrome by adding characters in while True:
front of it. index = self.partition(nums, left, right) # all entries < index are <=
# Find and return the shortest palindrome you can find by performing this transformation. nums[index]
if index == k:
# Least number of characters added implies finding the longest prefix palindrome. Use return nums[index]
KMP failure function if index > k:
# algorithm to find the longest prefix of s that is also a suffix of s[::-1]. right = index-1
# Time - O(n) else:
# Space - O(n) left = index+1

class Solution(object):
def shortestPalindrome(self, s): def partition(self, nums, left, right):
"""
:type s: str rand_index = random.randint(left, right)
:rtype: str rand_entry = nums[rand_index]
""" nums[rand_index], nums[right] = nums[right], nums[rand_index] # swap rand_index
longest_prefix_suffix = self.kmp_table(s + '*' + s[::-1]) to right
return s[:longest_prefix_suffix:-1] + s
next_lower = left # the next index there an entry <= rand_entry will be
stored
def kmp_table(self, word): for i in range(left, right):
failure = [-1] + [0 for _ in range(len(word)-1)] if nums[i] <= rand_entry: # no action if > rand_entry
pos = 2 # the next index of failure table to be computed nums[next_lower], nums[i] = nums[i], nums[next_lower]
candidate = 0 next_lower += 1

while pos < len(word): nums[next_lower], nums[right] = nums[right], nums[next_lower] # swap rand_entry
back to be next_lower
if word[pos-1] == word[candidate]: # prefix/suffix of word[:i] extends the return next_lower
previous prefix/suffix by 1 char
failure[pos] = candidate + 1
candidate += 1
pos += 1 # python_1_to_1000/216_Combination_Sum_III.py - m
elif candidate > 0: # no extension, update candidate to
earlier prefix/suffix _author_ = 'jake'
candidate = failure[candidate] _project_ = 'leetcode'
failure[pos] = 0
else: # candidate == 0 # https://leetcode.com/problems/combination-sum-iii/
failure[pos] = 0 # Find all possible combinations of k numbers that add up to a number n, given that only
pos += 1 numbers from 1 to 9 can
# be used and each combination should be a unique set of numbers.
return failure[-1]
# Recursively add to partial solution all numbers greater than the previous number.
# Time - O(1), finite digits 1 to 9 implies fixed bound
# python_1_to_1000/215_Kth_Largest_in_an_Array.py - m # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def combinationSum3(self, k, n):
"""
# https://leetcode.com/problems/kth-largest-element-in-an-array/ :type k: int
# Find the kth largest element in an unsorted array. Note that it is the kth largest :type n: int
element in :rtype: List[List[int]]
# the sorted order, not the kth distinct element. """
results = []
# Quick select. Partition array about random element. Narrow search region to one side self.cs3([], n, results, k)
of partition. return results
# Time - O(n), recurse on half (random) of array
# Space - O(1) def cs3(self, partial, target, results, k):

import random if len(partial) == k and target == 0: # result found


results.append(partial)
class Solution(object):
def findKthLargest(self, nums, k): if len(partial) >= k or target <= 0: # cannot make sum of n with k elements
""" return
:type nums: List[int]
:type k: int last_used = 0 if not partial else partial[-1]
:rtype: int for i in range(last_used+1, 10): # add all greater digits than last_used
""" self.cs3(partial + [i], target-i, results, k)
k = len(nums) - k # find index k when sorted ascendingly
left, right = 0, len(nums)-1

edges.sort()
# python_1_to_1000/217_Contains_Duplicate.py
for x, neg_h, r in edges:
_author_ = 'jake'
_project_ = 'leetcode' while current[0][1] <= x: # discard right edges that are left or equal
to new edge
# https://leetcode.com/problems/contains-duplicate/ heapq.heappop(current) # dummy right edge at infinity ensures heap
# Given an array of integers, find if the array contains any duplicates. Your function will never be empty
should return true if any value
# appears at least twice in the array, and it should return false if every element is if neg_h != 0: # implies left edge (since h will not be
distinct. zero), push right edge
heapq.heappush(current, (neg_h, r))
# If every number is unique then the set length is the same as the list length. If this
is not true, then there is if skyline[-1][1] != -current[0][0]: # previous skyline different from
# some duplicate. highest alive building
# Time - O(n) skyline.append([x, -current[0][0]]) # add point (x, highest 'alive'
# Space - O(n) bldg) to result

class Solution(object): return skyline[1:]


def containsDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: bool
""" # python_1_to_1000/219_Contains_Duplicate_II.py
return len(set(nums)) != len(nums)
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/218_The_Skyline_Problem.py - h
# https://leetcode.com/problems/contains-duplicate-ii/
_author_ = 'jake' # Given an array of integers and an integer k, find out whether there are two distinct
_project_ = 'leetcode' 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.
# https://leetcode.com/problems/the-skyline-problem/
# A city's skyline is the outer contour of the silhouette formed by all the buildings in # Create a set of nums in a sliding window of length k. Iterate over nums, removing the
that city when viewed from num at the back of the window,
# a distance. Now suppose you are given the locations and height of all the buildings as # checking if the new num is already in the window, or else adding it.
a cityscape photo. # Time - O(n)
# Write a program to output the skyline formed by these buildings collectively. # Space - O(k)
# The geometric information of each building is represented by a triplet of integers [Li,
Ri, Hi], where Li and Ri class Solution(object):
# are the x coordinates of the left and right edge of the ith building, respectively, and def containsNearbyDuplicate(self, nums, k):
Hi is its height. """
# It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may :type nums: List[int]
assume all buildings are :type k: 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, window = set() # elements in window must be unique or else solution already
right edge) whenever we found
# 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 for i, num in enumerate(nums):
# edge to the heap, record the highest building. Heap top has the highest 'alive' if i > k:
building after each edge. window.remove(nums[i - k - 1])
# Time - O(n * logn), each building is inserted and removed from heap if num in window:
# Space - O(n) return True
window.add(num)
import heapq
return False
class Solution(object):
def getSkyline(self, buildings):
"""
:type buildings: List[List[int]] # python_1_to_1000/220_Contains_Duplicate_III.py - h
:rtype: List[List[int]]
""" _author_ = 'jake'
skyline = [(0, 0)] # resulting list of points, dummy first point _project_ = 'leetcode'
current = [(0, float('inf'))] # heap of 'alive' buildings by height, then by
right edge # https://leetcode.com/problems/contains-duplicate-iii/
# Given an array of integers, find out whether there are two distinct indices i and j in
edges = [(l, -h, r) for l, r, h in buildings] # left edges the array such that the
edges += [(r, 0, None) for _, r, _ in buildings] # right edges # difference between nums[i] and nums[j] is at most t and the difference between i and j
is at most k. bottom right

# Map each num to a bucket of width t+1 so collision in bucket implies numbers are within for r in range(rows):
t. Also check
# higher and lower buckets. Remove numbers from sliding window if more than k indices new_square_sides = [int(matrix[r][0])] + [0 for _ in range(cols-1)]
earlier.
# Time - O(n) for c in range(1, cols):
# Space - O(n) if matrix[r][c] == '1':
new_square_sides[c] = 1 + min(new_square_sides[c-1], square_sides[c],
class Solution(object): square_sides[c-1])
def containsNearbyAlmostDuplicate(self, nums, k, t):
""" max_side = max(max_side, max(new_square_sides))
:type nums: List[int] square_sides = new_square_sides
:type k: int
:type t: int return max_side**2
:rtype: bool
"""
if k <= 0 or t < 0: # cannot have distinct integers if no index separation # python_1_to_1000/222_Count_Complete_Tree_Nodes.py
return False # numerical separation must be positive
buckets = {} # map from a bucket to num in that bucket _author_ = 'jake'
_project_ = 'leetcode'
for i, num in enumerate(nums):
bucket = num // (t + 1) # bucket width t+1, collision implies difference # https://leetcode.com/problems/count-complete-tree-nodes/
<= t. handles t == 0 # Given a complete binary tree, count the number of nodes.
if bucket in buckets: # In a complete binary tree every level, except possibly the last, is completely filled,
return True and all nodes in the last
if bucket+1 in buckets and abs(num - buckets[bucket+1]) <= t: # # level are as far left as possible. It can have between 1 and 2h nodes inclusive at the
neighbouring buckets last level h.
return True
if bucket-1 in buckets and abs(num - buckets[bucket-1]) <= t: # Find depth of left most path in left and right subtrees. If equal then left subtree is
return True complete, if different
# then right subtree is complete.
buckets[bucket] = num # add to bucket # Alternatively, find depth of left path and right path, if equal return 2**depth -1. If
if i - k >= 0: # remove from start of window not recurse on subtrees,
old_bucket = nums[i - k] // (t + 1) # retaining know left path depth of left subtree and right path depth of right subtree.
del buckets[old_bucket] # Time - O((log n)**2), height is log n since complete. Recurse either left or right at
each layer.
return False # Space - O(1)

# Definition for a binary tree node.


# python_1_to_1000/221_Maximal_Square.py - m class TreeNode(object):
def __init__(self, x):
_author_ = 'jake' self.val = x
_project_ = 'leetcode' self.left = None
self.right = None
# https://leetcode.com/problems/maximal-square/
# Given a 2D binary matrix filled with 0's and 1's, find the largest square containing class Solution(object):
only 1's and return its area. def countNodes(self, root):
"""
# For each cell find the largest square with that cell at the bottom right by dynamic :type root: TreeNode
programming. :rtype: int
# If cell == '1' then it extends the squares with bottom right cells to the left, above """
and above-left. Take the min if not root:
# of these 3 squares that are extended. return 0
# Time - O(m * n)
# Space - O(n) left_subtree = self.left_depth(root.left)
right_subtree = self.left_depth(root.right)
class Solution(object):
def maximalSquare(self, matrix): if left_subtree == right_subtree:
""" return 2**left_subtree + self.countNodes(root.right) # 1 (root) +
:type matrix: List[List[str]] 2**left_subtree - 1 (left subtree)
:rtype: int else:
""" return 2**right_subtree + self.countNodes(root.left)
if not matrix or not matrix[0]:
return 0
def left_depth(self, node):
rows, cols = len(matrix), len(matrix[0]) depth = 0
max_side = 0 while node:
square_sides = [0] * cols # largest square side with cell in each col as node = node.left

depth += 1 digits = {str(i) for i in range(10)}


return depth expression = ['('] # wrap whole expression with brackets, easily identifies
end

# python_1_to_1000/223_Rectangle_Area.py - m for c in s: # pre-process string into list of operators, brackets and


ints
_author_ = 'jake' if c == ' ': # ignore blanks
_project_ = 'leetcode' continue
if c not in digits: # operator or bracket
# https://leetcode.com/problems/rectangle-area/ expression.append(c)
# Find the total area covered by two rectilinear rectangles in a 2D plane. elif isinstance(expression[-1], int): # extending integer
# Each rectangle is defined by its bottom left corner (A, B) or (E, F) and top right expression[-1] = expression[-1]*10 + int(c)
corner (C, D) or (G, H). else: # new integer
expression.append(int(c))
# Calculate the left and right edges of horizontal overlap. Take the difference to get
the x_overlap and similar for expression.append(')')
# y_overlap. Subtract the overlap area from the sum of the areas of the two rectangles. result, _ = self.evaluate(expression, 1)
# Time - O(1) return result
# Space - O(1)

class Solution(object): def evaluate(self, expression, i): # evaluate from index i onwards to closing
def computeArea(self, A, B, C, D, E, F, G, H): bracket
"""
:type A: int calc, operator = 0, '+'
:type B: int while expression[i] != ')':
:type C: int
:type D: int atom = expression[i]
:type E: int if atom == '+' or atom == '-': # store the operator
:type F: int operator = atom
:type G: int else: # open bracket or integer
:type H: int if isinstance(atom, int):
:rtype: int num = atom
""" else: # recurse on bracketed expression
x_lhs = max(A, E) num, i = self.evaluate(expression, i+1)
x_rhs = min(C, G)
x_overlap = max(x_rhs - x_lhs, 0) if operator == '+': # apply operator to num
calc += num
y_lhs = max(B, F) else:
y_rhs = min(D, H) calc -= num
y_overlap = max(y_rhs - y_lhs, 0) i += 1

rect1 = (C - A) * (D - B) return calc, i # return calculation and index of closing bracket


rect2 = (G - E) * (H - F)

return rect1 + rect2 - y_overlap * x_overlap # python_1_to_1000/225_Implement_Stack_Using_Queues.py

_author_ = 'jake'
# python_1_to_1000/224_Basic_Calculator.py - h _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/implement-stack-using-queues/


_project_ = 'leetcode' # Implement the following operations of a stack using queues.
# push(x) -- Push element x onto stack.
# https://leetcode.com/problems/basic-calculator/ # pop() -- Removes the element on top of the stack.
# Implement a basic calculator to evaluate a simple expression string. # top() -- Get the top element.
# The expression string may contain open ( and closing parentheses ), the plus + or minus # empty() -- Return whether the stack is empty.
sign -, non-negative # Notes:
# integers and empty spaces . You may assume that the given expression is always valid. # You must use only standard operations of a queue -- which means only push to back,
peek/pop from front, size,
# Preprocess string to identify integers. Recursively apply operator and bracket # and is empty operations are valid.
expression to previous result. # Depending on your language, queue may not be supported natively. You may simulate a
# Time - O(n) queue by using a list or
# Space - O(n) # deque (double-ended queue), as long as you use only standard operations of a queue.
# You may assume that all operations are valid (for example, no pop or top operations
class Solution(object): will be called on an empty stack).
def calculate(self, s):
""" # To insert, append to deque. To pop, move ell elements to new_queue until there is only
:type s: str one element and return that.
:rtype: int # To top, similar to pop except all elements are moved to new_queue. After pop or top,
""" set queue to new_queue.
# Time - O(1) for push and empty, O(n) for pop and top. """
# Space - O(n) :type root: TreeNode
:rtype: TreeNode
from collections import deque """
if not root:
class MyStack(object): return None

def __init__(self): root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)


"""
Initialize your data structure here. return root
"""
self.queue = deque()

def push(self, x): # python_1_to_1000/227_Basic_Calculator_II.py - m


"""
Push element x onto stack. _author_ = 'jake'
:type x: int _project_ = 'leetcode'
:rtype: void
""" # https://leetcode.com/problems/basic-calculator-ii/
self.queue.appendleft(x) # Implement a basic calculator to evaluate a simple expression string.
# The expression string contains only non-negative integers, +, -, *, / operators and
def pop(self): empty spaces.
""" # The integer division should truncate toward zero.
Removes the element on top of the stack and returns that element. # You may assume that the given expression is always valid.
:rtype: int
""" # Create a stack of partial results to be summed to get the full result. Iterate over s.
new_queue = deque() When c is a digit
while True: # increase the current integer num. When c is an operator or at end of string, apply the
x = self.queue.pop() previous operator
if not self.queue: # to num. For '*' and '/' this uses the previous integer on the stack.
self.queue = new_queue # Time - O(n)
return x # Space - O(n)
new_queue.appendleft(x)
class Solution(object):
def top(self): def calculate(self, s):
""" """
Get the top element. :type s: str
:rtype: int :rtype: int
""" """
new_queue = deque() stack = []
while self.queue: num = 0
x = self.queue.pop() op = '+'
new_queue.appendleft(x)
self.queue = new_queue for i, c in enumerate(s):
return x
if c.isdigit(): # build num
def empty(self): num = num*10 + int(c)
"""
Returns whether the stack is empty. if (not c.isdigit() and c != ' ') or i == len(s)-1: # c is an operator or
:rtype: bool end of string
""" if op == '+': # use previous operator op
return len(self.queue) == 0 stack.append(num)
elif op == '-':
stack.append(-num)
# python_1_to_1000/226_Invert_Binary_Tree.py elif op == '*':
stack.append(stack.pop() * num)
_author_ = 'jake' else: # op == '/'
_project_ = 'leetcode' left = stack.pop()
stack.append(left // num)
# https://leetcode.com/problems/invert-binary-tree/ if left // num < 0 and left % num != 0:
# Invert a binary tree. stack[-1] += 1 # # negative integre division result with
remainder rounds down by default
# Left substree is old right subtree inverted. Right subtree is old left subtree num = 0 # num has been used so reset
inverted. op = c
# Time - O(n)
# Space - O(n) return sum(stack)

class Solution(object):
def invertTree(self, root): # python_1_to_1000/228_Summary_Ranges.py

elif count2 == 0: # new cancidate


_author_ = 'jake' cand2 = num
_project_ = 'leetcode' count2 = 1
else: # 'remove' 3 different elements (cand1, cand2, num) from count
# https://leetcode.com/problems/summary-ranges/ count1 -= 1
# Given a sorted integer array without duplicates, return the summary of its ranges. count2 -= 1
# For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"].
# check if candidates are more than 1/3 of list length
# Create a list of pair [start, end] for each range. Extend previous range if new num is return [n for n in (cand1, cand2) if nums.count(n) > len(nums) // 3]
previous + 1, else
# start a new range.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/230_Kth_Smallest_Element_in_a_BST.py - m
class Solution(object):
def summaryRanges(self, nums): _author_ = 'jake'
""" _project_ = 'leetcode'
:type nums: List[int]
:rtype: List[str] # https://leetcode.com/problems/kth-smallest-element-in-a-bst/
""" # Given a binary search tree, write a function kthSmallest to find the kth smallest
summary = [] element in it.
for num in nums:
if not summary or num > summary[-1][1] + 1: # Iterative inorder traversal.
summary.append([num, num]) # Alternatively, recursive inorder traversal tracking remaining count with instance
else: variable.
summary[-1][1] = num # Time - O(n)
# Space - O(n)
result = [str(i) if i == j else str(i) + '->' + str(j) for i, j in summary]
return result # Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
# python_1_to_1000/229_Majority_Element_II.py - m self.val = x
self.left = None
_author_ = 'jake' self.right = None
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/majority-element-ii/ def kthSmallest(self, root, k):
# Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ """
times. :type root: TreeNode
# The algorithm should run in linear time and in O(1) space. :type k: int
:rtype: int
# There can be at most 2 elements that make up more than 1/3 of the input. Maintain 2 """
candidates, incrementing their stack = []
# counts as we find new instances. If an element is neither candidate then decrement while root:
count of both candidates. stack.append(root)
# If an element is more than 1/3 of an array then it will remain so when 3 different root = root.left
elements are removed.
# If a count reduces to zero then the next element is a new candidate. while stack:
# Finally check if candidates are actually > 1/3 of array. node = stack.pop()
# Time - O(n) k -= 1
# Space - O(1) if k == 0:
return node.val
class Solution(object): node = node.right
def majorityElement(self, nums): while node:
""" stack.append(node)
:type nums: List[int] node = node.left
:rtype: List[int]
""" class Solution2(object):
cand1, count1 = None, 0 def kthSmallest(self, root, k):
cand2, count2 = None, 0 self.k = k # instance variables
self.result = None
for num in nums: self.helper(root)
if num == cand1: # increment count of candidate return self.result
count1 += 1
elif num == cand2: # increment count of candidate def helper(self, node):
count2 += 1 if not node:
elif count1 == 0: # new cancidate return
cand1 = num self.helper(node.left)
count1 = 1 self.k -= 1
if self.k == 0:
self.result = node.val def pop(self):
return """
self.helper(node.right) Removes the element from in front of queue and returns that element.
:rtype: int
"""
if not self.reversed:
# python_1_to_1000/231_Power_of_Two.py while self.stack:
self.reversed.append(self.stack.pop())
_author_ = 'jake' return self.reversed.pop()
_project_ = 'leetcode'
def peek(self):
# https://leetcode.com/problems/power-of-two/ """
# Given an integer, write a function to determine if it is a power of two. Get the front element.
:rtype: int
# n must be positive. Powers of 2 have their most significant bit set and no other bits, """
so there are no set bits if self.reversed:
# in common between n and n - 1. return self.reversed[-1]
# Time - O(1) return self.top
# Space - O(1)
def empty(self):
class Solution: """
def isPowerOfTwo(self, n): Returns whether the queue is empty.
""" :rtype: bool
:type n: int """
:rtype: bool return not self.stack and not self.reversed
"""
return n > 0 and not n & (n - 1)
# python_1_to_1000/233_Number_of_Digit_One.py - h

# python_1_to_1000/232_Implement_Queue_using_Stacks.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/number-of-digit-one/
# Given an integer n, count the total number of digit 1 appearing in all non-negative
# https://leetcode.com/problems/implement-queue-using-stacks/ integers less than or equal to n.
# Implement the following operations of a queue using stacks.
# push(x) -- Push element x to the back of queue. # Calculate the number of 1s in each position, starting with units and moving forwards.
# pop() -- Removes the element from in front of queue. # In each position we consider the n+1 numbers from 0 to n inclusive.
# peek() -- Get the front element. # block_size is the cycle length before the pattern of 1s repeats.
# empty() -- Return whether the queue is empty. # Count the number of complete blocks in n+1, each such block having 1/10th of its size
# You may assume that all operations are valid (e.g., no pop or peek operations will be of 1s.
called on an empty queue). # Then add the partial blocks.

# One stack contains the iteams as they are added. Another stack is used to reverse the # Time - O(log n)
order during the pop operation. # Space - O(1)
# The top of the stack is recorded for O(1) peek.
# Time - O(1) for init, push, peek and empty. O(n) for pop. class Solution(object):
# Space - O(n) def countDigitOne(self, n):
"""
class MyQueue(object): :type n: int
:rtype: int
def __init__(self): """
""" if n <= 0:
Initialize your data structure here. return 0
""" ones = 0
self.stack = []
self.reversed = [] block_size = 10
self.top = None for _ in range(len(str(n))):

def push(self, x): blocks, rem = divmod(n + 1, block_size)


""" ones += blocks * block_size // 10 # nb blocks * nb ones in a block
Push element x to the back of queue. ones += min(block_size // 10, max(0, rem - block_size // 10)) # partial
:type x: int blocks
:rtype: void block_size *= 10
"""
if not self.stack: return ones
self.top = x
self.stack.append(x) print(Solution().countDigitOne(524))

def lowestCommonAncestor(self, root, p, q):


"""
:type root: TreeNode
# python_1_to_1000/234_Palindrome_Linked_List.py :type p: TreeNode
:type q: TreeNode
_author_ = 'jake' :rtype: TreeNode
_project_ = 'leetcode' """
if p.val > root.val and q.val > root.val:
# https://leetcode.com/problems/palindrome-linked-list/ return self.lowestCommonAncestor(root.right, p, q)
# Given a singly linked list, determine if it is a palindrome. if p.val < root.val and q.val < root.val:
return self.lowestCommonAncestor(root.left, p, q)
# Move a fast pointer and a slow pointer along the list. Slow pointer nodes are added to return root
reversed list.
# When no more fast move is possible, iterate along slow and back along reversed list
checking for val equality. # python_1_to_1000/236_Lowest_Common_Ancestor_of_a_Binary_Tree.py - m
# Time - O(n)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def isPalindrome(self, head): # https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/
""" # Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the
:type head: ListNode tree.
:rtype: bool # The lowest common ancestor is defined between two nodes v and w as the lowest node in T
""" that has both v
fast, slow = head, head # and w as descendants (where we allow a node to be a descendant of itself).
rev = None # head of the already-reversed part
# Recursive function return p or q if only one of those nodes is present, None if
while fast and fast.next: neither.
fast = fast.next.next # Find LCA of p and q in and right subtrees. If both return a value then p and q are in
next_slow = slow.next opposite subtrees and
slow.next = rev # root is LCA. Else return LCA of p and q in the subtree containing both of them.
rev = slow # Time - O(n)
slow = next_slow # Space - O(1)

# if fast is not null, slow is middle element of odd length list which is skipped # Definition for a binary tree node.
# if fast is null, slow is first element of 2nd half of even length list class TreeNode(object):
if fast: def __init__(self, x):
slow = slow.next self.val = x
self.left = None
while slow: self.right = None
if slow.val != rev.val:
return False class Solution(object):
slow = slow.next def lowestCommonAncestor(self, root, p, q):
rev = rev.next """
:type root: TreeNode
return True :type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
# python_1_to_1000/235_Lowest_Common_Ancestor_of_a_Binary_Search_Tree.py - m """

_author_ = 'jake' if not root or p == root or q == root: # base cases


_project_ = 'leetcode' return root

# https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ left_lca = self.lowestCommonAncestor(root.left, p, q)


# Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given right_lca = self.lowestCommonAncestor(root.right, p, q)
nodes in the BST.
# According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined if left_lca and right_lca:
between two nodes v and w as return root
# the lowest node in T that has both v and w as descendants (where we allow a node to be return left_lca or right_lca
a descendant of itself).”

# If both p and q are more than the node value then the common ancestor must be on the # python_1_to_1000/237_Delete_Node_in_a_Linked_List.py - m
right. Similarly on the left if
# p and q are lower. Else this is the common ancestor. Could also be iterative instead of _author_ = 'jake'
recursive. _project_ = 'leetcode'
# Time - O(n)
# Space - O(1) # https://leetcode.com/problems/delete-node-in-a-linked-list/
# Write a function to delete a node (except the tail) in a singly linked list, given only
class Solution(object): access to that node.
# Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with # Before adding a new index, pop from tail all indexes whose numbers are less than the
value 3, the linked list should new num since they can
# become 1 -> 2 -> 4 after calling your function. # never be the window max. Pop from head if that index is now outside the window. Head
has largest in window.
# Copy the value of the next node to the given node and connext the node to the next # Time - O(n)
after next. I.e. remove the next # Space - O(k)
# node after moving its value to the given node.
# Time - O(1) from collections import deque
# Space - O(1)
class Solution(object):
class Solution(object): def maxSlidingWindow(self, nums, k):
def deleteNode(self, node): """
""" :type nums: List[int]
:type node: ListNode :type k: int
:rtype: void Do not return anything, modify node in-place instead. :rtype: List[int]
""" """
node.val = node.next.val q = deque()
node.next = node.next.next max_window = []

for i, num in enumerate(nums):


# python_1_to_1000/238_Product_of_Array_Except_Self.py - m
while q and nums[q[-1]] < num: # pop smaller numbers from RHS
_author_ = 'jake' q.pop()
_project_ = 'leetcode'
q.append(i) # append this number at RHS
# https://leetcode.com/problems/product-of-array-except-self/
# Given an array of n integers where n > 1, nums, return an array output such that if q[0] <= i - k: # if LHS is outside window, remove it
output[i] is equal to the q.popleft()
# product of all the elements of nums except nums[i].
if i >= k - 1: # if window is at least k, add LHS to result
# Iterate from left to right, calculating the product of all numbers to the left. max_window.append(nums[q[0]])
# The iterate from right to left, multiplying each result by the product of all numbers
to the right. return max_window
# If any one value is zero then result is all zeros apart from that entry.
# Time - O(n)
# Space - O(1) # python_1_to_1000/240_Search_a_2D_Matrix_II.py - m

class Solution(object): _author_ = 'jake'


def productExceptSelf(self, nums): _project_ = 'leetcode'
"""
:type nums: List[int] # https://leetcode.com/problems/search-a-2d-matrix-ii/
:rtype: List[int] # Write an efficient algorithm that searches for a value in an m x n matrix. This matrix
""" has the following properties:
products = [1] # product of all to left of nums[0] is set to 1 # Integers in each row are sorted in ascending from left to right.
for i in range(1, len(nums)): # Integers in each column are sorted in ascending from top to bottom.
products.append(nums[i-1] * products[-1])
# Start at the top-right. If target is greater than this value then it cannot be in this
right_product = 1 row so increment row.
for i in range(len(nums)-1, -1, -1): # If target is less than this value then it cannot be in this column so decrement column.
products[i] *= right_product # Time - O(m + n)
right_product *= nums[i] # Space - O(1)

return products class Solution(object):


def searchMatrix(self, matrix, target):
"""
# python_1_to_1000/239_Sliding_Window_Maximum.py - h :type matrix: List[List[int]]
:type target: int
_author_ = 'jake' :rtype: bool
_project_ = 'leetcode' """
if not matrix or not matrix[0]:
# https://leetcode.com/problems/sliding-window-maximum/ return False
# Given an array nums, there is a sliding window of size k which is moving from the very
left of the array to the rows, cols = len(matrix), len(matrix[0])
# very right. You can only see the k numbers in the window. Each time the sliding window r, c = 0, cols-1
moves right by one position.
# Return a list of the max number in each window of the sliding window. while r < rows and c >= 0:

# Keep indices in double ended queue. New indices are added at head of queue (RHS) so if matrix[r][c] == target:
oldest are at tail (LHS). return True

if target > matrix[r][c]:


r += 1 # python_1_to_1000/242_Valid_Anagram.py
else:
c -= 1 _author_ = 'jake'
_project_ = 'leetcode'
return False
# https://leetcode.com/problems/valid-anagram/
# Given two strings s and t, write a function to determine if t is an anagram of s.
# python_1_to_1000/241_Different_Ways_to_Add_Parentheses.py - m # You may assume the string contains only lowercase alphabets.

_author_ = 'jake' # Strings s and t must contain the same number of each character.
_project_ = 'leetcode' # Time - O(m + n)
# Space - O(1)
# https://leetcode.com/problems/different-ways-to-add-parentheses/
# Given a string of numbers and operators, return all possible results from computing all from collections import Counter
the different
# possible ways to group numbers and operators. The valid operators are +, - and *. class Solution(object):
def isAnagram(self, s, t):
# Preprocess the string into a list of integers and string operators. Split the string """
by each operators and :type s: str
# recurse on the left and the right expressions. Combine the left and the right results :type t: str
in all possible ways. :rtype: bool
# Memoize the results to save duplication. """
return Counter(s) == Counter(t)
class Solution(object):
def diffWaysToCompute(self, input):
""" # python_1_to_1000/243_Shortest_Word_Distance.py
:type input: str
:rtype: List[int] _author_ = 'jake'
""" _project_ = 'leetcode'
start = 0 # start index of current integer
parsed = [] # https://leetcode.com/problems/shortest-word-distance/
# Given a list of words and two words word1 and word2, return the shortest distance
for i in range(len(input)): between these two words in the list.
if not input[i].isdigit(): # For example,
parsed.append(int(input[start:i])) # append integer # Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
parsed.append(input[i]) # append operator # Given word1 = “coding”, word2 = “practice”, return 3.
start = i+1 # Given word1 = "makes", word2 = "coding", return 1.
parsed.append(int(input[start:len(input)])) # You may assume that word1 does not equal to word2, and word1 and word2 are both in the
list.
return self.diff_ways(parsed, 0, len(parsed)-1, {})
# Iterate over list, updating the last seen indices whenever word matches word1 or word2.
Also update the shortest
def diff_ways(self, s, left, right, memo): # distance.
# Time - O(n)
if left == right: # case case of single integer # Space - O(1)
return [s[left]]
if (left, right) in memo: class Solution(object):
return memo[(left, right)] def shortestDistance(self, words, word1, word2):
"""
ways = [] :type words: List[str]
for i in range(left+1, right, 2): # partiton by each operator :type word1: str
:type word2: str
left_results = self.diff_ways(s, left, i-1, memo) :rtype: int
right_results = self.diff_ways(s, i+1, right, memo) """
shortest = len(words)
for l in left_results: i_1, i_2 = float("-inf"), float("-inf") # last seen indices of word1 and
for r in right_results: word2
if s[i] == '+':
ways.append(l+r) for i, word in enumerate(words):
elif s[i] == '-':
ways.append(l-r) if word == word1:
elif s[i] == '*': i_1 = i
ways.append(l*r) shortest = min(shortest, i_1 - i_2)
if word == word2:
memo[(left, right)] = ways i_2 = i
return ways shortest = min(shortest, i_2 - i_1)
return shortest # As per problem 243 except if word1 == word2 treat indices as queue of length 2.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/244_Shortest_Word_Distance_II.py - m
class Solution(object):
_author_ = 'jake' def shortestWordDistance(self, words, word1, word2):
_project_ = 'leetcode' """
:type words: List[str]
# https://leetcode.com/problems/shortest-word-distance-ii/ :type word1: str
# Design a class which receives a list of words in the constructor, and implements a :type word2: str
method that takes two words word1 :rtype: int
# and word2 and return the shortest distance between these two words in the list. """
Distance is the difference between last1, last2 = -1, -1 # last indices in words of word1 and word2
# the indices of the words in the list. same = word1 == word2 # only test once
# Your method will be called repeatedly many times with different parameters. distance = len(words)

# Dictionary stores and ordered list of the indices of each word in words. for i, word in enumerate(words):
# Iterate along the lists of indices of each word together, moving forwards the pointer if word == word1:
to the lower index. if same:
# Time - O(n) last1, last2 = last2, i # shift last2 to last1 and update last2
# Space - O(n) to i
else:
from collections import defaultdict last1 = i
elif word == word2:
class WordDistance(object): last2 = i
def __init__(self, words):
""" if last1 != -1 and last2 != -1:
initialize your data structure here. distance = min(distance, abs(last1 - last2))
:type words: List[str]
""" return distance
self.word_indices = defaultdict(list)
for i, word in enumerate(words):
self.word_indices[word].append(i) # python_1_to_1000/246_Strobogrammatic_Number.py

def shortest(self, word1, word2): _author_ = 'jake'


""" _project_ = 'leetcode'
Adds a word into the data structure.
:type word1: str # https://leetcode.com/problems/strobogrammatic-number/
:type word2: str # A strobogrammatic number is a number that looks the same when rotated 180 degrees
:rtype: int (looked at upside down).
""" # Write a function to determine if a number is strobogrammatic. The number is represented
i1 = self.word_indices[word1] # list of indices of word1 as a string.
i2 = self.word_indices[word2] # list of indices of word2 # For example, the numbers "69", "88", and "818" are all strobogrammatic.
distance = float('inf')
p1, p2 = 0, 0 # pointers to indices in the lists # Iterate over nums, matching digits at the front with rotated digits at the back.
# Time - O(n)
while p1 < len(i1) and p2 < len(i2): # break when either pointer exceeds its # Space - O(1)
list
class Solution(object):
distance = min(distance, abs(i1[p1] - i2[p2])) def isStrobogrammatic(self, num):
if i1[p1] < i2[p2]: # index of word1 is less than index of word2 """
p1 += 1 :type num: str
else: :rtype: bool
p2 += 1 """
strob = {'0':'0', '1':'1', '8':'8', '6':'9', '9':'6'} # map digit to its
return distance rotation

for left in range((len(num) + 1) // 2): # include middle


digit if odd length
# python_1_to_1000/245_Shortest_Word_Distance_III.py - m
right = len(num) - 1 - left
_author_ = 'jake' if num[left] not in strob or strob[num[left]] != num[right]:
_project_ = 'leetcode' return False

# https://leetcode.com/problems/shortest-word-distance-iii/ return True


# Given a list of words and two words word1 and word2, return the shortest distance
between these two words in the list.
# word1 and word2 may be the same and they represent two individual words in the list. # python_1_to_1000/247_Strobogrammatic_Number_II.py - m

_author_ = 'jake' strobo = {'0' : '0', '1' : '1', '8': '8', '6' : '9', '9' : '6'}
_project_ = 'leetcode'
if min_len == 1:
# https://leetcode.com/problems/strobogrammatic-number-ii/ strobo_count += len([i for i in other_list if low <= int(i) <= high])
# A strobogrammatic number is a number that looks the same when rotated 180 degrees
(looked at upside down). for i in range(2, max_len+1):
# Find all strobogrammatic numbers that are of length = n. live_list = [c + r + strobo[c] for r in live_list for c in strobo] # wrap c
and strobo[c] around previous numbers
# Base case of single strobogrammatic digits for odd n, empty string for even n.
# Create numbers of length i by adding pairs of strobogrammatic digits before and after if min_len < i < max_len: # add all numbers in list not beginning
all numbers of length i-2. with zero
# Remove results with leading zero unless single digit. strobo_count += len([True for result in live_list if result[0] != '0'])
# Time - O(5**(n//2)), each number of length n-2 is wrapped by 5 pairs to produce numbers elif i == min_len or i == max_len: # add numbers not beginning with zero and
of length n between low and high
# Space - O(5**(n//2)) strobo_count += len([True for result in live_list if result[0] != '0' and
low <= int(result) <= high])
import time
live_list, other_list = other_list, live_list # swap even and odd lists
class Solution(object):
def findStrobogrammatic(self, n): return strobo_count
"""
:type n: int
:rtype: List[str]
""" # python_1_to_1000/249_Group_Shifted_Strings.py - m
if n <= 0:
return [''] _author_ = 'jake'
_project_ = 'leetcode'
if n % 2 == 1:
results = ['0', '1', '8'] # https://leetcode.com/problems/group-shifted-strings/
else: # Given a string, we can "shift" each of its letter to its successive letter, for
results = [''] example: "abc" -> "bcd". We can
# keep "shifting" which forms the sequence: "abc" -> "bcd" -> ... -> "xyz"
strobo = {'0' : '0', '1' : '1', '8': '8', '6' : '9', '9' : '6'} # Given a list of strings which contains only lowercase alphabets, group all strings that
for i in range(n//2): belong to the same
results = [c + r + strobo[c] for r in results for c in strobo] # shifting sequence.

return [result for result in results if (result[0] != '0' or n == 1)] # For each string, shift so first character is "a". Map shifted string to list of all
unshifted strings.
# Time - O(n), total number of chars of all strings
# Space - O(n)
# python_1_to_1000/248_Strobogrammatic_Number_III.py - h
from collections import defaultdict
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def groupStrings(self, strings):
# https://leetcode.com/problems/strobogrammatic-number-iii/ """
# A strobogrammatic number is a number that looks the same when rotated 180 degrees :type strings: List[str]
(looked at upside down). :rtype: List[List[str]]
# Write a function to count the total strobogrammatic numbers that exist in the range of """
low <= num <= high. shifted = defaultdict(list)
# Because the range might be a large number, the low and high numbers are represented as
string. for s in strings:

# Build lists of numbers upto the length of high. Wrap pairs of strobogrammatic digits shift = ord(s[0]) - ord('a') # assumes s is not empty
around previous numbers. s_shifted = "".join([chr((ord(c) - ord('a') - shift) % 26 + ord('a')) for c
in s])
class Solution(object): shifted[s_shifted].append(s)
def strobogrammaticInRange(self, low, high):
""" return shifted.values()
:type low: str
:type high: str
:rtype: int
""" # python_1_to_1000/250_Count_Univalue_Subtrees.py - m
max_len, min_len = len(high), len(low)
low, high = int(low), int(high) _author_ = 'jake'
_project_ = 'leetcode'
live_list = [''] # base case for even length numbers
other_list = ['0', '1', '8'] # bas case for odd length numbers # https://leetcode.com/problems/count-univalue-subtrees/
strobo_count = 0 # Given a binary tree, count the number of uni-value subtrees.
# A Uni-value subtree means all nodes of the subtree have the same value. if root.right and root.right.val != root.val:
return False
# Bottom-up count univariate subtrees in left and right subtrees than add 1 if both return self.is_univariate(root.left) and self.is_univariate(root.right)
subtrees are univariate with the
# same value as the root.
# Alternatively define a function to test if the subtree rooted at that node is
univariate (which explores the subtree) # python_1_to_1000/251_Flatten_2D_Vector.py - m
# and preorder (or inorder/postorder) traverse the tree to test all nodes. O(n**2) time
but runs faster on the _author_ = 'jake'
# leetcode test cases. _project_ = 'leetcode'
# Time - O(n)
# Space - O(1) # https://leetcode.com/problems/flatten-2d-vector/
# Implement an iterator to flatten a 2d vector.
# Definition for a binary tree node.
class TreeNode(object): # Store pointer to the next valid sublist and item. To initialise and after every
def __init__(self, x): iteration move pointers to the next
self.val = x # valid item or beyond final sublist.
self.left = None # Time - O(1) for hasNext. init() and next() are O(m) where m is number of sublists
self.right = None # Space - O(n), total length of all sublists

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


def countUnivalSubtrees(self, root):
""" def __init__(self, vec2d):
:type root: TreeNode """
:rtype: int Initialize your data structure here.
""" :type vec2d: List[List[int]]
self.univariates = 0 """
self.is_univariate(root) self.vec2d = vec2d
return self.univariates self.list_nb, self.item_nb = 0, 0
# while empty sublist, move to next sublist until end of vec2d
# returns True if tree from root is univariate and increments count for all while self.list_nb < len(self.vec2d) and len(self.vec2d[self.list_nb]) == 0:
univariate subtrees self.list_nb += 1
def is_univariate(self, root):
def next(self):
if not root: """
return True :rtype: int
"""
left_uni = self.is_univariate(root.left) result = self.vec2d[self.list_nb][self.item_nb]
right_uni = self.is_univariate(root.right) if self.item_nb < len(self.vec2d[self.list_nb]) - 1:
self.item_nb += 1 # not end of sublist, increment item
if left_uni and right_uni: else: # end of sublist, reset item and find next non-empty
if (not root.left or root.left.val == root.val) and (not root.right or sublist or end of vec2d
root.right.val == root.val): self.item_nb = 0
self.univariates += 1 self.list_nb += 1
return True while self.list_nb < len(self.vec2d) and len(self.vec2d[self.list_nb]) == 0:
self.list_nb += 1
return False return result

def hasNext(self):
class Solution2(object): """
def countUnivalSubtrees(self, root): :rtype: bool
self.univariates = 0 """
self.preorder(root) return self.list_nb < len(self.vec2d) # list_nb pointer beyond end of vec2d
return self.univariates

def preorder(self, root):


if not root: # python_1_to_1000/252_Meeting_Rooms.py
return
if self.is_univariate(root): _author_ = 'jake'
self.univariates += 1 _project_ = 'leetcode'
self.preorder(root.left)
self.preorder(root.right) # https://leetcode.com/problems/meeting-rooms/
# Given an array of meeting time intervals consisting of start and end times [[s1,e1],
def is_univariate(self, root): [s2,e2],...] (si < ei),
if not root: # determine if a person could attend all meetings.
return True
if root.left and root.left.val != root.val: # Siort by increasing start time, then check for any meeting starting before previous
return False meeting finishes.

# Time - O(n log n)


# Space - O(1)
class Solution2(object):
class Solution(object): def minMeetingRooms(self, intervals):
def canAttendMeetings(self, intervals): overlaps = []
""" intervals.sort(key=lambda x: x.start)
:type intervals: List[Interval]
:rtype: bool for interval in intervals:
"""
intervals.sort(key=lambda x: x.start) if overlaps and interval.start >= overlaps[0]: # starts after earliest end
time so replace
for i, interval in enumerate(intervals[1:], 1): # skip first interval heapq.heapreplace(overlaps, interval.end)
else: # overlaps so push to heap
if interval.start < intervals[i - 1].end: heapq.heappush(overlaps, interval.end)
return False
return len(overlaps)
return True

# python_1_to_1000/254_Factor_Combinations.py - m
# python_1_to_1000/253_Meeting_Rooms_II.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/factor-combinations/
# https://leetcode.com/problems/meeting-rooms-ii/ # Numbers can be regarded as product of its factors. For example,
# Given an array of meeting time intervals consisting of start and end times [[s1,e1], # Write a function that takes an integer n and return all possible combinations of its
[s2,e2],...] (si < ei), factors.
# find the minimum number of conference rooms required.
# Recursive helper function returns all combinations of factors of n starting from trial
# Use a heap to store the end times of meetings that have not finished. For each new factor, where partial is the
meeting in start time order, # list of existing factors. Whenever trial is a factor add a new result and recurse
# push it onto heap, pop all meetings that have already ended and update max_rooms being without this factor.
used. # Alternatively, iterative version same except stack replaces recursive calls.
# Alternatively, use heap to store the end times of all meetings that need their own
rooms. If a new meeting does import time
# not overlap with the earliest ending existing meeting then replace existing with new
meeting. New meet will overlap class Solution(object):
# with all others on heap. def getFactors(self, n):
# Time - O(n log n) """
# Space - O(n) :type n: int
:rtype: List[List[int]]
# Definition for an interval. """
class Interval(object): return self.factorise(n, 2, [], [])
def __init__(self, s=0, e=0):
self.start = s def factorise(self, n, trial, partial, factors):
self.end = e
while trial * trial <= n: # if trial**2 > n then have already found all
import heapq factors

class Solution(object): if n % trial == 0: # trial is a factor


def minMeetingRooms(self, intervals): factors.append(partial + [n//trial, trial]) # append this result
""" self.factorise(n//trial, trial, partial + [trial], factors) # try and
:type intervals: List[Interval] factorise again with trial
:rtype: int trial += 1
"""
max_rooms = 0 return factors
rooms = [] # heap of end times of overlapping
meetings
intervals.sort(key=lambda x: x.start) # sort by start time class Solution2(object):
def getFactors(self, n):
for interval in intervals: stack = [(n, 2, [])] # tuples of number to factorise, trial factor, list
of previous factors
heapq.heappush(rooms, interval.end) factors = []
while rooms[0] <= interval.start: # pop all meetings that have ended before
this meeting starts while stack:
heapq.heappop(rooms) num, trial, partial = stack.pop()
max_rooms = max(max_rooms, len(rooms))
while trial * trial <= num: # as per recursive with push to stack
return max_rooms replacing function call
# Min cost of painting a house any colour is the cost of painting that house that colour
if num % trial == 0: + min of painting the previous
factors.append(partial + [num//trial, trial]) # house a different colour.
stack.append((num//trial, trial, partial + [trial])) # Time - O(n)
trial += 1 # Space - O(1)

return factors class Solution(object):


def minCost(self, costs):
"""
:type costs: List[List[int]]
:rtype: int
"""
if not costs:
return 0
# python_1_to_1000/255_Verify_Preorder_Sequence_in_Binary_Search_Tree.py - m
for i in range(1, len(costs)):
_author_ = 'jake' costs[i][0] += min(costs[i-1][1], costs[i-1][2])
_project_ = 'leetcode' costs[i][1] += min(costs[i-1][0], costs[i-1][2])
costs[i][2] += min(costs[i-1][0], costs[i-1][1])
# https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/
# Given an array of numbers, verify whether it is the correct preorder traversal sequence return min(costs[-1])
of a binary search tree.
# You may assume each number in the sequence is unique.
# python_1_to_1000/257_Binary_Tree_Paths.py
# Whilst the values are decreasing they are left children and we push them onto a stack.
When we see a higher value _author_ = 'jake'
# it must be a right child so pop off all smaller values, the last of which is the parent _project_ = 'leetcode'
of the current value.
# Anything smaller than the parent should have been traversed already so parent is the # https://leetcode.com/problems/binary-tree-paths/
minimum of future values. # Given a binary tree, return all root-to-leaf paths.
# Time - O(n)
# Space - O(n) # Recursive dfs. If leaf, add path to result. Else add node value to partial and recurse.
# Time - O(n**2)
class Solution(object): # Space - O(n)
def verifyPreorder(self, preorder):
""" class Solution(object):
:type preorder: List[int] def binaryTreePaths(self, root):
:rtype: bool """
""" :type root: TreeNode
stack = [float('inf')] # added so do not need to check is empty :rtype: List[str]
minimum = float('-inf') """

for value in preorder: def helper(node, partial): # partial is exiting path from root
if not node:
if value < minimum: return
return False partial.append(str(node.val))
if not node.left and not node.right:
while value > stack[-1]: paths.append("->".join(partial))
minimum = stack.pop() # will only ever increase return
stack.append(value) helper(node.left, partial[:])
helper(node.right, partial)
return True
paths = []
helper(root, [])
# python_1_to_1000/256_Paint_House.py - m return paths

_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/258_Add_Digits.py
# https://leetcode.com/problems/paint-house/
# There are a row of n houses, each house can be painted with one of the three colors: _author_ = 'jake'
red, blue or green. _project_ = 'leetcode'
# The cost of painting each house with a certain color is different. You have to paint
all the houses such that no # https://leetcode.com/problems/add-digits/
# two adjacent houses have the same color. # Given a non-negative integer num, repeatedly add all its digits until the result has
# The cost of painting each house with a certain color is represented by a n x 3 cost only one digit.
matrix.
# Find the minimum cost to paint all houses. All costs are positive integers. # Repeatedly sum digitss until < 10.
# Time - O(log n)

# Space - O(1) # Time - O(n)


# Space - O(1)
class Solution(object):
def addDigits(self, num): class Solution(object):
""" def singleNumber(self, nums):
:type num: int """
:rtype: int :type nums: List[int]
""" :rtype: List[int]
while num > 9: """
num = sum([int(c) for c in str(num)]) xor = 0
return num for num in nums:
xor = xor ^ num

# python_1_to_1000/259_3Sum_Smaller.py - m bit = 0
while not (1 << bit) & xor:
_author_ = 'jake' bit += 1
_project_ = 'leetcode'
bit_set_xor, bit_not_set_xor = 0, 0
# https://leetcode.com/problems/3sum-smaller/ for num in nums:
# Given an array of n integers nums and a target, find the number of index triplets i, j, if (1 << bit) & num:
k bit_set_xor = bit_set_xor ^ num
# with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target else:
bit_not_set_xor = bit_not_set_xor ^ num
# Sort the array. For each index i search nums[i+1, len(nums)]. Whenever a triple sums
to less than target we return [bit_set_xor, bit_not_set_xor]
# increment the count by right - left since for that value of the left pointer all values
to the left of nums[right]
# also form a triplet less than the target. # python_1_to_1000/261_Graph_Valid_Tree.py - m
# Time - O(n**2)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def threeSumSmaller(self, nums, target): # https://leetcode.com/problems/graph-valid-tree/
""" # Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a
:type nums: List[int] pair of nodes),
:type target: int # write a function to check whether these edges make up a valid tree.
:rtype: int
""" # Tree has the minimum number of edges to whilst still being connected. If not n-1 edges
count = 0 then must be loop and/or not
nums.sort() # connected so not a tree. If n-1 edges then graph is either a tree or (not connected
and loop).
for i in range(len(nums)-2): # Test for not connected by depth first search. From any starting node, remove node from
graph and recurse on all
left, right = i+1, len(nums)-1 # neighbours. If any node not removed then graph is not connected so not a tree.
while left < right: # Alternatively identify loops by keeping an array of the furthest node reachable from
if nums[i] + nums[left] + nums[right] < target: any starting node. Union-find
count += right - left # identifies connected regions.
left += 1 # Time - O(n + m), nodes + edges
else: # Space - O(n + m)
right -= 1
class Solution(object):
return count def validTree(self, n, edges):
"""
:type n: int
# python_1_to_1000/260_Single_number_III.py - m :type edges: List[List[int]]
:rtype: bool
_author_ = 'jake' """
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/single-number-iii/ def validTree(self, n, edges):
# Given an array of numbers nums, in which exactly two elements appear only once and all """
the other elements :type n: int
# appear exactly twice. Find the two elements that appear only once. :type edges: List[List[int]]
:rtype: bool
# 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
# singles and not the other. Find the first bit that is set, then find the xor of all def dfs(node): # recursively removes nbors from mapping
nums with that bit set nbors = adjacency.pop(node, [])
# and the xor of all nums without that bit set. for nbor in nbors:
dfs(nbor) if num <= 0:
return False
if len(edges) != n - 1: # eliminate if too many/few edges for n
nodes while num % 2 == 0:
return False num //= 2
while num % 3 == 0:
adjacency = {i: [] for i in range(n)} # list of neighbours for each num //= 3
node while num % 5 == 0:
for a, b in edges: num //= 5
adjacency[a].append(b)
adjacency[b].append(a) return num == 1

dfs(0)
return not adjacency
# python_1_to_1000/264_Ugly_Number_II.py - m

class Solution2(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
def find(node): numbers.
if parents[node] == -1: # Note that 1 is typically treated as an ugly number, and n does not exceed 1690.
return node
return find(parents[node]) # Create the sequence of ugly numbers and track the last index that has not been
multiplied by 2 to generate another
if len(edges) != n - 1: # number in the sequence as i_2. Similarly track i_3 and i_5. The next number is the
return False lowest new number that can be
# generated. Increment all indices that can generate thhe latest ugly number (since more
parents = [-1] * n than one of 2, 3 and 5 may be
# able to generate the last number.
for a, b in edges: # Time - O(n)
# Space - O(n)
a_parent = find(a)
b_parent = find(b) class Solution(object):
def nthUglyNumber(self, n):
if a_parent == b_parent: # already have same parent before this edge """
return False :type n: int
parents[a_parent] = b_parent :rtype: int
"""
return True 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

# python_1_to_1000/263_Ugly_Number.py while len(ugly) < n:

_author_ = 'jake' ugly.append(min(2 * ugly[i_2], 3 * ugly[i_3], 5 * ugly[i_5])) # append


_project_ = 'leetcode' smallest

# https://leetcode.com/problems/ugly-number/ if ugly[-1] == 2 * ugly[i_2]: # increment i_2 if latest ugly can be


# Write a program to check whether a given number is an ugly number. generated from 2 * ugly[i_2]
# Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For i_2 += 1
example, 6, 8 are ugly while 14 is if ugly[-1] == 3 * ugly[i_3]: # increment i_3 if latest ugly can be
# not ugly since it includes another prime factor 7. generated from 3 * ugly[i_3]
# 1 is typically treated as an ugly number. i_3 += 1
# Input is within the 32-bit signed integer range. if ugly[-1] == 5 * ugly[i_5]: # increment i_5 if latest ugly can be
generated from 5 * ugly[i_5]
# Reject if <= 0. Remove all factors of 2, 3, and 5 then check if remainder is 1. i_5 += 1
# Time - O(log n)
# Space - O(1) return ugly[-1]

class Solution(object):
def isUgly(self, num): # python_1_to_1000/265_Paint_House_II.py - h
"""
:type num: int _author_ = 'jake'
:rtype: bool _project_ = 'leetcode'
"""

# https://leetcode.com/problems/paint-house-ii/ :type s: str


# There are a row of n houses, each house can be painted with one of the k colors. :rtype: bool
# The cost of painting each house with a certain color is different. You have to paint """
all the houses such that freq = Counter(s)
# no two adjacent houses have the same color. odd = False # no odd has been seen

# For each house, calculate the min cost of painting that house each colour given min for letter, count in freq.items():
costs of painting upto the if count % 2 == 1:
# previous house each colour. if odd: # amother char has odd count
# Find the colour that minimises the cost of painting upto and including the previous return False
house. The min cost of painting odd = True
# the next house any colour apart from the previous min cost colour is the cost of the
previous min cost + new colour. return True
# 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/267_Palindrome_Permutation_II.py - m
# Time - O(nk)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def minCostII(self, costs): # https://leetcode.com/problems/palindrome-permutation-ii/
""" # Given a string s, return all the palindromic permutations (without duplicates) of it.
:type costs: List[List[int]] # Return an empty list if no palindromic permutation could be formed.
:rtype: int
""" # Firstly find the only char with an odd count, if there is any. If more than 1 odd
if not costs or not costs[0]: count char then return [].
return 0 # 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
for i in range(1, len(costs)): instance of any char with a
# non-zero count to partial list and decrementing the count of this char by 2. Track the
min_colours = [0, 1] # colours of previous house that give min and second number of remaining
min costs # chars to add such that when this is zero we have a resulting half-palindrome. Finally
if costs[i-1][0] > costs[i-1][1]: build full palindromes from
min_colours = [1, 0] # half and odd_char.
# Time - O(n * n!), n! permutations of length n
for colour in range(2, len(costs[0])): # Space - O(n * n!)
if costs[i-1][colour] <= costs[i-1][min_colours[0]]: # new min cost
min_colours[1], min_colours[0] = min_colours[0], colour from collections import Counter
elif costs[i-1][colour] < costs[i-1][min_colours[1]]: # new second min
cost class Solution(object):
min_colours[1] = colour def generatePalindromes(self, s):
"""
for colour in range(len(costs[0])): # colour == min_colours[0] is 1 if colour :type s: str
is the min_colours[0] :rtype: List[str]
costs[i][colour] += costs[i-1][min_colours[colour == min_colours[0]]] """
char_counts = Counter(s)
return min(costs[-1]) odd_char = "" # char with an odd count

for char, count in char_counts.items():


if count % 2 != 0:
if odd_char:
return [] # more than one odd count, cannot form
# python_1_to_1000/266_Palindrome_Permutation.py palindromes
odd_char = char
_author_ = 'jake' char_counts[odd_char] -= 1 # decrement counter
_project_ = 'leetcode'
palindromes = []
# https://leetcode.com/problems/palindrome-permutation/ self.build_palindromes(palindromes, [], char_counts, len(s)//2)
# Given a string, determine if a permutation of the string could form a palindrome. return ["".join(p + [odd_char] + p[::-1]) for p in palindromes]

# There can be at most one character with an odd count in a palindrome.


# Time - O(n) def build_palindromes(self, palindromes, partial, char_counts, remaining):
# Space - O(1)
if remaining == 0:
from collections import Counter palindromes.append(partial[:]) # copy of partial

class Solution(object): for c in char_counts.keys():


def canPermutePalindrome(self, s): if char_counts[c] == 0: # skip if count is zero
""" continue
seen = set(words[0]) # all chars found so far
char_counts[c] -= 2 # decrement count and add c to partial
list for i in range(1, len(words)):
partial.append(c) diff_to_prev = False
self.build_palindromes(palindromes, partial, char_counts, remaining-1)
partial.pop() # revert count and partial list for j, c in enumerate(words[i]):
char_counts[c] += 2 seen.add(c) # add every char of every word to seen

# 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]:
if c not in order[words[i-1][j]]: # have not seen this ordering
# python_1_to_1000/268_Missing_Number.py before
order[words[i-1][j]].add(c)
_author_ = 'jake' after[c] += 1
_project_ = 'leetcode' diff_to_prev = True

# https://leetcode.com/problems/missing-number/ if not diff_to_prev and len(words[i-1]) > len(words[i]): # no differences


# Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one and longer word first
that is missing from the array. return ""

# Subtract the sum from n*(n-1)/2 for c in seen: # all chars depend on at least zero previous chars
# Time - O(n) if c not in after:
# Space - O(1) after[c] = 0

class Solution(object): frontier = set() # frontier have no dependencies


def missingNumber(self, nums): for a in after:
""" if after[a] == 0:
:type nums: List[int] frontier.add(a)
:rtype: int
""" letters = []
return (((len(nums) + 1) * len(nums)) // 2) - sum(nums) while frontier:
b = frontier.pop() # add char from frontier to result
del after[b]
letters.append(b)
for a in order[b]: # decrement dependency count of those appearing after
# python_1_to_1000/269_Alien_Dictionary.py - h b
after[a] -= 1
_author_ = 'jake' if after[a] == 0:
_project_ = 'leetcode' frontier.add(a)

# https://leetcode.com/problems/alien-dictionary/ if after:
# There is a new alien language which uses the latin alphabet. However, the order among return ""
letters are unknown to you.
# You receive a list of words from the dictionary, where words are sorted return "".join(letters)
lexicographically by the rules of this
# 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/270_Closest_Binary_Search_Tree_Value.py
# The first difference in chars at the same position for consecutive words in the
dictionary gives an ordered pair _author_ = 'jake'
# of chars. Find a topologial ordering of the resulting directed graph by repeatedly _project_ = 'leetcode'
removing chars that have no
# earlier chars remaining. # https://leetcode.com/problems/closest-binary-search-tree-value/
# Time - O(n), total number of chars in all words # Given a non-empty binary search tree and a target value, find the value in the BST that
# Space - O(m**2), nb chars in alphabet - order can be set of all chars for each char is closest to the target.
# Given target value is a floating point.
from collections import defaultdict # You are guaranteed to have only one unique value in the BST that is closest to the
target.
class Solution(object):
def alienOrder(self, words): # If target is node val then return. Update closest if node val is closer. If target is
""" more than root val then
:type words: List[str] # no value in left subtree can be closer than node.val so move to right subtree. Vica
:rtype: str versa for left subtree.
""" # Time - O(n)
after = defaultdict(int) # key is char, value is nb times char depends on a # Space - O(1)
previous char
order = defaultdict(set) # key is char, value is set of chars appearing after class Solution(object):
char def closestValue(self, root, target):

""" j = s.find('*', i) # '*' must be present if any remaining test


:type root: TreeNode len_substring = int(s[i:j])
:type target: float decoding.append(s[j+1:j+1+len_substring])
:rtype: int i = j+1+len_substring
""" return decoding
closest = root.val

while root: # python_1_to_1000/272_Closest_Binary_Search_Tree_Value_II.py - h

if root.val == target: # early return since cannot improve _author_ = 'jake'


return root.val _project_ = 'leetcode'

if abs(root.val - target) < abs(closest - target): # https://leetcode.com/problems/closest-binary-search-tree-value-ii/


closest = root.val # Given a non-empty binary search tree and a target value, find k values in the BST that
are closest to the target.
if target < root.val: # You may assume k is always valid, that is: k ≤ total nodes.
root = root.left # You are guaranteed to have only one unique set of k values in the BST that are closest
else: to the target.
root = root.right
# Heap stores k closest values as tuples (- abs node diff from target, node value). Top
return closest of heap is furthest from
# target. If a node.val is closer than the furthest value in the heap then add it to the
heap and check left and
# right subtrees. If a node.val is further than the furthest value in the heap then the
# python_1_to_1000/271_Encode_and_Decode_Strings.py - m nodes of one subtree are all
# also further away.
_author_ = 'jake' # Alternatively, preorder traverse tree to create a sorted list. Find the pair of values
_project_ = 'leetcode' surrounding target and
# expand outwards always taking the closest to target. O(n + k) but always visits ever
# https://leetcode.com/problems/encode-and-decode-strings/ node.
# Design an algorithm to encode a list of strings to a string. # Time - O(n log k)
# The encoded string is then sent over the network and is decoded back to the original # Space - O(k)
list of strings.
# Definition for a binary tree node.
# Prepend each string with its lenght and a special char '*'. To decode, find the first class TreeNode(object):
'*', text before this is the def __init__(self, x):
# length of the substring. find() will always locate '*' after the length, never within self.val = x
a substring. self.left = None
# Alternatively, prepend each string by its length as a string, padding string length self.right = None
with zeros to be a fixed number
# of characters. import heapq
# Alternatively, separate strings by a rare character surrounded by spaces eg ' # '.
Whenever '#' appears in a string class Solution(object):
# duplicate it such that all even numbers of consecutive "#" are from original strings. def closestKValues(self, root, target, k):
# Time - O(n) """
# Space - O(n) :type root: TreeNode
:type target: float
class Codec: :type k: int
def encode(self, strs): :rtype: List[int]
"""Encodes a list of strings to a single string. """
:type strs: List[str] closest = [(float('-inf'), 0)] # add one item to avoid checking for empty
:rtype: str heap
""" self.find_closest(root, target, k, closest)
encoding = [] return [val for _, val in closest]
for s in strs:
len_s = str(len(s)) def find_closest(self, node, target, k, closest):
encoding.append(len_s) # length as string if not node:
encoding.append('*') # delimiter '*' return
encoding.append(s)
return "".join(encoding) if abs(node.val - target) < -closest[0][0]: # node.val is closer to target
than furthest in heap
def decode(self, s): heapq.heappush(closest, (-abs(node.val - target), node.val))
"""Decodes a single string to a list of strings. if len(closest) > k: # heap is over capacity
:type s: str heapq.heappop(closest)
:rtype: List[str] self.find_closest(node.left, target, k, closest)
""" self.find_closest(node.right, target, k, closest)
decoding = []
i = 0 elif target > node.val: # LHS nodes cannot be closer than node.val, which is
while i < len(s): itself not in k closest
self.find_closest(node.right, target, k, closest) _author_ = 'jake'
else: _project_ = 'leetcode'
self.find_closest(node.left, target, k, closest)
# https://leetcode.com/problems/h-index/
# Given an array of citations (each citation is a non-negative integer) of a researcher,
# python_1_to_1000/273_Integer_to_English_Words.py - h write a function to compute
# the researcher's h-index. According to the definition of h-index on Wikipedia: "A
_author_ = 'jake' scientist has index h if h of
_project_ = 'leetcode' # his/her N papers have at least h citations each, and the other N − h papers have no
more than h citations each."
# https://leetcode.com/problems/integer-to-english-words/ # If there are several possible values for h, the maximum one is taken as the h-index.
# Convert a non-negative integer to its english words representation.
# Given input is guaranteed to be less than 2**31 - 1. # Bucket sort the papers by number of citations, using one bucket for all papers with
len(citations) citations or
# Build the words from left to right in blocks of 3 digits. # more. Starting from the bucket with the papers with the most citations, add those
# Time - O(log n) papers to the cumulative sum
# Space - O(log n) # and until there are at least as many papers as citations.
# Time - O(n)
from collections import deque # Space - O(n)

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


def numberToWords(self, num): def hIndex(self, citations):
""" """
:type num: int :type citations: List[int]
:rtype: str :rtype: int
""" """
int_to_word = {1 : 'One', 2 : 'Two', 3 : 'Three', 4 : 'Four', 5 : 'Five', buckets = [0] * (len(citations)+1) # each bucket index represents a number
6 : 'Six', 7 : 'Seven', 8 : 'Eight', 9 : 'Nine', 10 : 'Ten', of citations
11 : 'Eleven', 12 : 'Twelve', 13 : 'Thirteen', 14 : 'Fourteen', for citation in citations: # buckets[i] is the number of papers
15 : 'Fifteen', 16 : 'Sixteen', 17 : 'Seventeen', 18 : 'Eighteen', cited i times
19: 'Nineteen', 20 : 'Twenty', 30 : 'Thirty', 40 : 'Forty', buckets[min(citation, len(citations))] += 1
50 : 'Fifty', 60 : 'Sixty', 70 : 'Seventy', 80 : 'Eighty', 90 :
'Ninety'} papers = 0 # count of papers with at least buckets
citations
digits_to_word = {3 : 'Thousand', 6 : 'Million', 9 : 'Billion', 12 : 'Trillion', for bucket in range(len(buckets)-1, -1, -1):
15 : 'Quadrillion', 18 : 'Quintillion', 21 : 'Sextillion', 24 : papers += buckets[bucket]
'Septillion', if papers >= bucket:
27 : 'Octillion', 30 : 'Nonillion'} return bucket

english = deque()
digits = 0 # python_1_to_1000/275_H-Index_II.py - m
if num == 0:
return "Zero" _author_ = 'jake'
_project_ = 'leetcode'
while num:
# https://leetcode.com/problems/h-index-ii/
num, section = divmod(num, 1000) # section is the block of 3 digits # Follow up for 274_H-Index: What if the citations array is sorted in ascending order?
hundreds, tens = divmod(section, 100)
# Binary search. If the number of citations of the paper at index mid is at least the
if section and digits > 0: count of papers with
english.appendleft(digits_to_word[digits]) # a smaller or equal number of citations then search on the left, else search right.
digits += 3 # Time - O(log n)
# Space - O(1)
if tens >= 20:
if tens%10: class Solution(object):
english.appendleft(int_to_word[tens%10]) def hIndex(self, citations):
english.appendleft(int_to_word[10*(tens//10)]) """
elif tens: :type citations: List[int]
english.appendleft(int_to_word[tens]) :rtype: int
"""
if hundreds: n = len(citations)
english.appendleft("Hundred") left, right = 0, n-1
english.appendleft(int_to_word[hundreds])
while left <= right:
return " ".join(english) mid = (left + right) // 2

if citations[mid] >= n-mid:


# python_1_to_1000/274_H-Index.py - m right = mid - 1
else:

left = mid + 1 # Time - O(n)


# Space - O(1)
return n-left
# The knows API is already defined for you.
# @param a, person a
# python_1_to_1000/276_Paint_Fence.py - m # @param b, person b
# @return a boolean, whether a knows b
_author_ = 'jake' def knows(a, b):
_project_ = 'leetcode' return

# https://leetcode.com/problems/paint-fence/ class Solution(object):


# There is a fence with n posts, each post can be painted with one of the k colors. def findCelebrity(self, n):
# You have to paint all the posts such that no more than two adjacent fence posts have """
the same color. :type n: int
# Return the total number of ways you can paint the fence. :rtype: int
# n and k are non-negative integers. """
candidate = 0
# Base cases of zero or one post are 0 or k respectively. For more than 1 post, track the for i in range(1, n):
number of ways when the last if knows(candidate, i):
# 2 posts are same and when they are different. Update same as previous different, since candidate = i
we add the next post as the
# same colour as previous. Update different as (k - 1) * (same + different) since any for i in range(n):
previous way of either same or if i == candidate:
# different can add a post that is not the same colour as the last post. continue
# Time - O(n) if not knows(i, candidate) or knows(candidate, i):
# Space - O(1) return -1
return candidate
class Solution(object):
def numWays(self, n, k):
"""
:type n: int # python_1_to_1000/278_First_Bad_Version.py
:type k: int
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
if n == 0:
return 0 # https://leetcode.com/problems/first-bad-version/
if n == 1: # You are a product manager and currently leading a team to develop a new product.
return k Unfortunately, the latest version
# of your product fails the quality check. Since each version is developed based on the
same, different = 0, k previous version, all the
# versions after a bad version are also bad.
for _ in range(n - 1): # Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one,
same, different = different, (same + different) * (k - 1) which causes all the
# following ones to be bad.
return same + different # You are given an API bool isBadVersion(version) which will return whether version is
bad. Implement a function to
# find the first bad version. You should minimize the number of calls to the API.
# python_1_to_1000/277_Find_the_Celebrity.py - m
# Binary search.
_author_ = 'jake' # Time - O(log n)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/find-the-celebrity/ class Solution(object):


# Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, def firstBadVersion(self, n):
there may exist one celebrity. """
# The definition of a celebrity is that all the other n - 1 people know him/her but :type n: int
he/she does not know any of them. :rtype: int
# Now you want to find out who the celebrity is or verify that there is not one. """
# The only thing you are allowed to do is to ask questions "Does A know B?". You need to left, right = 1, n # left, right are the lowest and highest possible
find out the celebrity (or first bad versions
# verify there is not one) by asking as few questions as possible (in the asymptotic
sense). while left < right:

# Find the only candidate by testing each person. If the candidate knows that person, mid = (left + right) // 2
the candidate is not a celebrity if isBadVersion(mid): # first bad version must be mid or before
# and the new candidate is the test person. If the candidate doesn't know that person, right = mid
then that person is not a else: # first bad version must be after mid
# celebrity. Note that there can be only one or zero celebrities. left = mid + 1
# Then verify whether the candidate if valid.
return left
# https://leetcode.com/problems/zigzag-iterator/
# Given two 1d vectors, implement an iterator to return their elements alternately.
# python_1_to_1000/279_Perfect_Squares.py - m
# Maintain a queue of tuples (next vector, index in next vector) containing the next
_author_ = 'jake' valid index and vector. After
_project_ = 'leetcode' # iterating, add vector to back of queue if any more items remain.
# Time - O(k) (nb of vectors) to initialise vectors and q, O91) for next() and hasNext()
# https://leetcode.com/problems/perfect-squares/ # Space - O(n), total number of items in all vectors
# Given a positive integer n, find the least number of perfect square numbers (e.g., 1,
4, 9, 16, ...) which sum to n. from collections import deque

# Dynamic programming. memo[i] is the minimum nb squares that sum to i. While n is not class ZigzagIterator(object):
already in memo, extend memo
# to be 1 + min of all previous memo results that are a perfect square number of indices def __init__(self, v1, v2):
away. """
# Time - O(n**1.5) Initialize your data structure here.
# Space - O(n) :type v1: List[int]
:type v2: List[int]
class Solution(object): """
self.vectors = [v for v in (v1, v2) if v] # list of non-empty
memo = [0, 1] # memo is persistent so that calls to numSquares() build on previous vectors
results self.q = deque((i, 0) for i in range(len(self.vectors))) # queue of (index in
vectors, index in vector)
def numSquares(self, n):
""" def next(self):
:type n: int """
:rtype: int :rtype: int
""" """
while len(self.memo) <= n: vector, index = self.q.popleft()
self.memo.append(1 + min(self.memo[-i*i] for i in range(1, if index < len(self.vectors[vector])-1:
int(len(self.memo)**0.5)+1))) self.q.append((vector, index+1)) # rejoin queue if not last item of
vector
return self.memo[n] return self.vectors[vector][index]

def hasNext(self):
"""
:rtype: bool
# python_1_to_1000/280_Wiggle_Sort.py - m """
return bool(self.q)
_author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/wiggle-sort/
# Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= # python_1_to_1000/282_Expression_Add_Operators.py - h
nums[2] <= nums[3]...
_author_ = 'jake'
# If index is odd and not greater than or equal to previous, then swap with previous. _project_ = 'leetcode'
# If index is even and greater than or equal to previous, then swap with previous (if
equal, swap has no effect). # https://leetcode.com/problems/expression-add-operators/
# Time - O(n) # Given a string that contains only digits 0-9 and a target value, return all
# Space - O(1) possibilities to insert binary operators
# +, -, or * between the digits so they evaluate to the target value.
class Solution(object):
def wiggleSort(self, nums): # Insert an operator (except before first digit) then for each partition of the remaining
""" digits treat the first part
:type nums: List[int] # as the next integer. Track the evaluation of the current expression and the result of
:rtype: void Do not return anything, modify nums in-place instead. appending '*1' to the
""" # expression and so multiplying the last part by 1.
for i in range(1, len(nums)): # Time - O(4**(n-1)), choice of 3 operators or none at each partition point.
if i%2 ^ (nums[i] >= nums[i-1]): # Space - O(n * 4**(n-1)), worst case input of all zeros
nums[i], nums[i-1] = nums[i-1], nums[i]
class Solution(object):
def addOperators(self, num, target):
"""
# python_1_to_1000/281_Zigzag_Iterator.py - m :type num: str
:type target: int
_author_ = 'jake' :rtype: List[str]
_project_ = 'leetcode' """

if not num: # python_1_to_1000/284_Peeking_Iterator.py - m


return []
_author_ = 'jake'
self.num, self.target, self.expressions = num, target, [] _project_ = 'leetcode'
self.helper("", 0, 0, 0)
return self.expressions # https://leetcode.com/problems/peeking-iterator/
# Given an Iterator class interface with methods: next() and hasNext(), design and
implement a PeekingIterator that
def helper(self, path, index, eval, multed): # supports the peek() operation -- i.e. returns the element that will be returned by the
next call to next().
if index == len(self.num) and self.target == eval:
self.expressions.append(path) # Store the next iterator result and return it when peeking.
# Time - O(1)
for i in range(index, len(self.num)): # use num[index:i+1] as next integer # Space - O(1)

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


break # no leading zeros unless single digit def __init__(self, iterator):
"""
cur_str = self.num[index:i+1] # insert operator then cur Initialize your data structure here.
cur_int = int(cur_str) :type iterator: Iterator
"""
if index == 0: # no operator if start of nums self.front = None
self.helper(path + cur_str, i + 1, cur_int, cur_int) self.it = iterator
else: if self.it.hasNext():
self.helper(path + "+" + cur_str, i + 1, eval + cur_int , cur_int) self.front = self.it.next()
self.helper(path + "-" + cur_str, i + 1, eval - cur_int, -cur_int)
self.helper(path + "*" + cur_str, i + 1, eval - multed + multed * def peek(self):
cur_int, multed * cur_int) """
Returns the next element in the iteration without advancing the iterator.
:rtype: int
"""
# python_1_to_1000/283_Move_Zeros.py return self.front # None if not iterator.hasNext()

_author_ = 'jake' def next(self):


_project_ = 'leetcode' """
:rtype: int
# https://leetcode.com/problems/move-zeroes/ """
# Given an array nums, write a function to move all 0's to the end of it while temp = self.front
maintaining the relative order of the self.front = None
# non-zero elements. For example, given nums = [0, 1, 0, 3, 12], after calling your if self.it.hasNext(): # replace front
function, nums should be self.front = self.it.next()
# [1, 3, 12, 0, 0]. return temp
# You must do this in-place without making a copy of the array.
def hasNext(self):
# Track the next index where a non-zero entry can be placed, initially zero. Iterate over """
nums, when a non-zero entry :rtype: bool
# is seen, copy it to nums[i] and increment i. No action if num == 0. After iteration, """
replace all entries from i return bool(self.front)
# onwards with zero.
# Time - O(n)
# Space - O(n)
# python_1_to_1000/285_Inorder_Successor_in_BST.py - m
class Solution(object):
def moveZeroes(self, nums): _author_ = 'jake'
""" _project_ = 'leetcode'
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead. # https://leetcode.com/problems/inorder-successor-in-bst/
""" # Given a binary search tree and a node in it, find the in-order successor of that node
i = 0 # next index to move a non-zero entry to in the BST.
# If the given node has no in-order successor in the tree, return None.
for num in nums:
if num != 0: # Iterate through tree, whenever we go left update the successor.
nums[i] = num # Alternatively recursively explore right subtree if target value >= node value since
i += 1 successor must then be on right.
# If target value < node value and successor is not in left subtree then node is the
nums[i:] = [0] * (len(nums) - i) successor.
# Time - O(n), height of tree so log n if balanced
# Space - O(1)
# Definition for a binary tree node. if not rooms or not rooms[0]:
class TreeNode(object): return
def __init__(self, x):
self.val = x INF = 2 ** 31 - 1
self.left = None rows, cols = len(rooms), len(rooms[0])
self.right = None frontier = deque([(r, c) for r in range(rows) for c in range(cols) if rooms[r][c]
== 0])
class Solution(object):
def inorderSuccessor(self, root, p): while frontier:
""" row, col = frontier.popleft()
:type root: TreeNode for i, j in [(row + 1, col), (row - 1, col), (row, col + 1), (row, col - 1)]:
:type p: TreeNode if i >= 0 and i < rows and j >= 0 and j < cols:
:rtype: TreeNode if rooms[i][j] == INF:
""" rooms[i][j] = rooms[row][col] + 1
succ = None frontier.append((i, j))

while root:
if p.val >= root.val: # python_1_to_1000/287_Find_the_Duplicate_Number.py - m
root = root.right
else: _author_ = 'jake'
succ = root _project_ = 'leetcode'
root = root.left
# https://leetcode.com/problems/find-the-duplicate-number/
return succ # Given an array nums containing n + 1 integers where each integer is between 1 and n
(inclusive),
class Solution2(object): # assume that there is only one duplicate number, find the duplicate one.
def inorderSuccessor(self, root, p): # You must not modify the array (assume the array is read only).
if not root: # There is only one duplicate number in the array, but it could be repeated more than
return None once.

if p.val >= root.val: # For each integer i in nums, nums[i] is also in nums. Since there are more slots in
return self.inorderSuccessor(root.right, p) nums than unique integers in
# the range [1 .. n] inclusive then some integer must be duplicated. By following a path
left_succ = self.inorderSuccessor(root.left, p) i, nums[i], nums[nums[i]], ...
# the path must eventually repeat. There is a cycle whereby nums[j] has already been
return root if not left_succ else left_succ visited. Find cycle as per
# problem 142_Linked_List_Cycle_II - advance fast and slow pointers until they meet then
reset one pointer to starting
# python_1_to_1000/286_Walls_and_Gates.py - m # position and advance together until meet again.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/walls-and-gates/ def findDuplicate(self, nums):
# You are given a m x n 2D grid initialized with these three possible values. """
# -1 - A wall or an obstacle. :type nums: List[int]
# 0 - A gate. :rtype: int
# INF - Infinity means an empty room. We use the value 2**31 - 1 = 2147483647 to """
represent INF. slow = nums[0]
# Fill each empty room with the distance to its nearest gate. If it is impossible to fast = nums[slow]
reach a gate, it should be filled with INF.
while fast != slow: # move slow pointer 1 step and fast 2 steps until collide
# Multidirectional BFS. Frontier initially contains all gates. For each room in frontier slow = nums[slow]
update any surrounding fast = nums[nums[fast]]
# rooms with infinite distance and add them to frontier. Expands in concentric circles
around gates. fast = 0 # restart fast from index zero and move both pointers one step at a
# DFS or BFS from each gate in turn can result in repeatedly updating rooms and greater time
time complexity. while fast != slow:
# Time - O(m * n), each cell visited once slow = nums[slow]
# Space - O(m * n) for queue fast = nums[fast]
return fast
from collections import deque

class Solution(object):
def wallsAndGates(self, rooms):
""" # python_1_to_1000/288_Unique_Word_Abbreviation.py - m
:type rooms: List[List[int]]
:rtype: void Do not return anything, modify rooms in-place instead. _author_ = 'jake'
""" _project_ = 'leetcode'

the second bit to signify


# https://leetcode.com/problems/unique-word-abbreviation/ # that in the next timestep the cell will be alive. Then update the fisrt bit to the
# An abbreviation of a word follows the form <first letter><number><last letter>. second bit.
# Assume you have a dictionary and given a word, find whether its abbreviation is unique # Time - O(m * n)
in the dictionary. # Space - O(1)
# A word's abbreviation is unique if no other word from the dictionary has the same
abbreviation. class Solution(object):
def gameOfLife(self, board):
# Create a set of words form dictionary to eliminate duplicates so the same word is not """
double counted. For each :type board: List[List[int]]
# unique word, create a mapping from its abbreviation to the count of words with the same :rtype: void Do not return anything, modify board in-place instead.
abbreviation. A word is """
# unique if it is in the dictionary and no other word has the same abbreviation, or no if not board or not board[0]:
other word has same abbreviation. return
# Time - O(n) for init() where n is the total number of letters in all words in the rows, cols = len(board), len(board[0])
dictionary. O(k) for isUnique()
# where k is the length of the word to be tested for uniqueness. for r in range(rows):
# Space - O(n) for c in range(cols):
nbors = self.count_neighbours(r, c, board)
from collections import defaultdict if nbors == 3 or (board[r][c] and nbors == 2):
board[r][c] += 2 # set second bit so signify next status is alive
class ValidWordAbbr(object):
for r in range(rows):
def __init__(self, dictionary): for c in range(cols):
""" board[r][c] >>= 1 # 2nd bit determines next status
:type dictionary: List[str]
"""
self.dictionary = set(dictionary) def count_neighbours(self, r, c, board):
self.freq = defaultdict(int)
for word in self.dictionary: count = 0
self.freq[self.abbreviate(word)] += 1 for row_offset in range(-1, 2):
for col_offset in range(-1, 2):
def isUnique(self, word):
""" if row_offset == col_offset == 0:
:type word: str continue
:rtype: bool 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
abbr = self.abbreviate(word) current status
if word in self.dictionary:
return self.freq[abbr] == 1 return count
else:
return abbr not in self.freq

def abbreviate(self, word): # python_1_to_1000/290_Word_Pattern.py


n = len(word)
if n < 3: _author_ = 'jake'
return word _project_ = 'leetcode'
return word[0] + str(n - 2) + word[-1]
# https://leetcode.com/problems/word-pattern/
# Given a pattern and a string str, find if str follows the same pattern.
# python_1_to_1000/289_Game_of_Life.py - m # Here follow means a full match, so that there is a bijection between a letter in
pattern and a non-empty word in str.
_author_ = 'jake' # You may assume pattern contains only lowercase letters and str contains lowercase
_project_ = 'leetcode' letters separated by a single space.

# https://leetcode.com/problems/game-of-life/ # Iterate over pairs of pattern chars and words, creating 2 mappings from pattern char to
# Given a board with m by n cells, each cell has an initial state live (1) or dead (0). word and word to pattern
# Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the # char. If a word or pattern char has been mapped differently already then return False.
following four rules:: # Time - O(m + n)
# Any live cell with fewer than two live neighbors dies, as if caused by under- # Space - O(m + n)
population.
# Any live cell with two or three live neighbors lives on to the next generation. class Solution(object):
# Any live cell with more than three live neighbors dies, as if by over-population.. def wordPattern(self, pattern, str):
# Any dead cell with exactly three live neighbors becomes a live cell, as if by """
reproduction. :type pattern: str
# Write a function to compute the next state (after one update) of the board given its :type str: str
current state. :rtype: bool
"""
# For each cell in current board count neighbours and if 3 or 2 and cell is alive, set str = str.split()
if len(str) != len(pattern): # early return if lengths do not match failed
return False s_used.discard(test_s)

p_to_s, s_to_p = {}, {} elif p in mapping and mapping[p] == test_s: # p already mapped to
test_s
for w, c in zip(str, pattern): if is_match(i + 1, end + 1):
return True
if c in p_to_s and p_to_s[c] != w:
return False return False
p_to_s[c] = w
mapping = {}
if w in s_to_p and s_to_p[w] != c: s_used = set()
return False return is_match(0, 0)
s_to_p[w] = c

return True # python_1_to_1000/292_Nim_Game.py

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

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


_project_ = 'leetcode' # You are playing the following Nim Game with your friend: There is a heap of stones on
the table, each time one of
# https://leetcode.com/problems/word-pattern-ii/ # you take turns to remove 1 to 3 stones. The one who removes the last stone will be the
# Given a pattern and a string str, find if str follows the same pattern. winner.
# Follow means a full match, such that there is a bijection between a letter in pattern # You will take the first turn to remove the stones.
and a non-empty substring in str. # Both of you are very clever and have optimal strategies for the game. Write a function
# Each letter in pattern maps to a substring of str e.g. pattern = "abab", str = to determine whether you can
"redblueredblue" should return true. # win the game given the number of stones in the heap.
# You may assume both pattern and str contain only lowercase letters.
# Can win if n is not divisible by 4, since then I can make it so n is divisible by 4 for
# For each character c in pattern, attempt to match this with test_s, a prefix of str. my opponent. On each
If neither c nor the prefix # subsequent turn I will always make it so n is divisible by 4 or take the last 1, 2 or 3
# have been used before, set this mapping and recurse. Delete mapping if recursion does stones.
not match remainders. # Time - O(1)
# If c is already mapped to prefix, recurse. Invalid mapping if either c or test_s are # Space - O(1)
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 canWinNim(self, n):
"""
class Solution(object): :type n: int
:rtype: bool
def wordPatternMatch(self, pattern, str): """
""" return n % 4 != 0
:type pattern: str
:type str: str
:rtype: bool # python_1_to_1000/293_Flip_Game.py
"""
m, n = len(pattern), len(str) _author_ = 'jake'
_project_ = 'leetcode'
def is_match(i, j):
# https://leetcode.com/problems/flip-game/
if i >= m and j >= n: # You are playing the following Flip Game with your friend: Given a string that contains
return True only these two characters:
if i >= m: # no pattern but some str remains # + and -, you and your friend take turns to flip two consecutive "++" into "--".
unmatched # The game ends when a person can no longer make a move and therefore the other person
return False will be the winner.
# Write a function to compute all possible states of the string after one valid move.
for end in range(j, n - (m - i) + 1): # leave at least 1 char in str for
each of remaining pattern # Iterate over s looking at pairs of chars and chaning any "++" to "--".
# Time - O(n**2)
p, test_s = pattern[i], str[j:end + 1] # try to match test_s with p # Space - O(n**2)
if p not in mapping and test_s not in s_used: # neither p nor test_s
are used class Solution(object):
mapping[p] = test_s def generatePossibleNextMoves(self, s):
s_used.add(test_s) """
if is_match(i + 1, end + 1): :type s: str
return True :rtype: List[str]
del mapping[p] # revert mapping and s_used since """

result = [] median and half the numbers above


# (or equal to) median. If the count of numners is odd, spare number is added to lower
for i in range(len(s) - 1): heap. New numbers are
if s[i:i + 2] == "++": # added to lower heap if less than or equal to its max value, else to higher heap. Then
result.append(s[:i] + "--" + s[i + 2:]) heaps are rebalanced to
# maintain the lower being at most 1 greater than higher.
return result # Time - O(log n) to addNum(), O(1) to findMedian()
# Space - O(n)

# python_1_to_1000/294_Flip_Game_II.py - m import heapq

_author_ = 'jake' class MedianFinder:


_project_ = 'leetcode' def __init__(self):
"""
# https://leetcode.com/problems/flip-game-ii/ Initialize your data structure here.
# You are playing the following Flip Game with your friend: Given a string that contains """
only these two characters: self.lower = [] # lower half of numbers, and the extra num if count is odd
# + and -, you and your friend take turns to flip two consecutive "++" into "--". The self.higher = [] # higher half of numbers
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 determine if the starting player can guarantee a win. """
Adds a num into the data structure.
# Find every '++' in s and if there is no winning strategy for opponent after converting :type num: int
it to '--' then this is a :rtype: void
# winning strategy. """
# Time - O(n * n!), if string contains only '+' then n - 1 choices for first pair to if not self.lower or num <= -self.lower[0]: # push onto appropriate heap
replace, (n - 1)(n - 3) heapq.heappush(self.lower, -num)
# for second pair .. each replacement takes O(n) else:
# Space - O(n * n!) heapq.heappush(self.higher, num)

class Solution(object): if len(self.higher) > len(self.lower): # rebalance if more than half on


def canWin(self, s): higher heap
""" heapq.heappush(self.lower, -heapq.heappop(self.higher))
:type s: str elif len(self.lower) > 1 + len(self.higher): # or more than half+1 on lower
:rtype: bool heapq.heappush(self.higher, -heapq.heappop(self.lower))
"""
def findMedian(self):
def helper(s): """
Returns the median of current data stream
if s in memo: :rtype: float
return memo[s] """
if len(self.lower) > len(self.higher):
for i in range(len(s) - 1): return float(-self.lower[0])
if s[i:i + 2] == '++' and not helper(s[:i] + '--' + s[i + 2:]): return (-self.lower[0] + self.higher[0]) / 2.0
memo[s] = True
return True

memo[s] = False # python_1_to_1000/296_Best_Meeting_Point.py - h


return False
_author_ = 'jake'
memo = {} _project_ = 'leetcode'
return helper(s)
# https://leetcode.com/problems/best-meeting-point/
# 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.
# python_1_to_1000/295_Find_Median_from_Data_Stream.py - h # Calculated the minimum travel using Manhattan Distance,

_author_ = 'jake' # Create sorted lists of row and column indices of people. Because dimensions are
_project_ = 'leetcode' independent for Manhattan distance,
# rows and cols can be optimised separately. Optimal meet is median of sorted indices
# https://leetcode.com/problems/find-median-from-data-stream/ (or anywhere between median pair
# Design a data structure that supports the following two operations: # if even number). To reach a meet between a pair of points takes distance of points
# void addNum(int num) - Add a integer number from the data stream to the data separation if meet is between
structure. # points, else greater distance if meet is not between points. Hence optimal meet is
# double findMedian() - Return the median of all elements so far. between the most pairs of
# If the size of the list is even, median is the mean of the two middle values. # points, which is the median.
# Time - O((m*n) + nlogn)
# Partition the numbers into 2 heaps containing half the numbers below (or equal to) # Space - O(m * n) if all cells contain people
"""
class Solution(object): nodes = []
def minTotalDistance(self, grid):
""" def preorder(node):
:type grid: List[List[int]] if not node:
:rtype: int nodes.append("null")
""" else:
rows, cols = [], [] nodes.append(str(node.val))
preorder(node.left)
for r in range(len(grid)): # collect rows in sorted order preorder(node.right)
for c in range(len(grid[0])):
if grid[r][c] == 1: preorder(root)
rows.append(r) return ",".join(nodes) # assumes TreeNode.val do not include comma
cols.append(c)
def deserialize(self, data):
cols.sort() # potentially better to collect cols in separate loop O(m*n) """Decodes your encoded data to tree.
rather than sort in O(n log n) :type data: str
dist = 0 :rtype: TreeNode
"""
left, right = 0, len(rows)-1 # increment distance by separation of outer pair node_list = deque(data.split(","))
of rows
while left < right: def rebuild():
dist += (rows[right] - rows[left])
left += 1 if not node_list:
right -= 1 return None

left, right = 0, len(cols)-1 # increment distance by separation of outer pair node = node_list.popleft()
of cols if node == "null":
while left < right: return None
dist += (cols[right] - cols[left])
left += 1 node = TreeNode(node)
right -= 1 node.left = rebuild()
node.right = rebuild()
return dist return node

return rebuild()
# python_1_to_1000/297_Serialize_and_Deserialize_Binary_Tree.py - h

_author_ = 'jake' # python_1_to_1000/298_Binary_Tree_Longest_Consecutive_Sequence.py - m


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/serialize-and-deserialize-binary-tree _project_ = 'leetcode'
# Serialization is the process of converting a data structure or object into a sequence
of bits so that it can be # https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/
# stored in a file or memory buffer, or transmitted across a network connection link to # Given a binary tree, find the length of the longest consecutive sequence path. The
be reconstructed later in the path refers to any sequence
# same or another computer environment. # of nodes from some starting node to any node in the tree along the parent-child
# Design an algorithm to serialize and deserialize a binary tree. There is no restriction connections. The longest consecutive
on how your # path must be from parent to child (cannot be the reverse).
# serialization/deserialization algorithm should work. You just need to ensure that a
binary tree can be serialized # Preorder traversal. If a node is 1 + previous value then increment sequence length,
# to a string and this string can be deserialized to the original tree structure. else start a new sequence.
# Time - O(n)
# Perform a preorder traversal, appending all visited nodes to a list and special # Space - O(1)
sentinel "null" For None. Recursing
# whenever we see a non-null node. Rebuild by creating a queue and taking the front # Definition for a binary tree node.
value. class TreeNode(object):
# Ignore if null, else rebuild the root with value, recurse right then left. def __init__(self, x):
# Time - O(n) self.val = x
# Space - O(n) self.left = None
self.right = None
from collections import deque
class Solution(object):
class Codec: def longestConsecutive(self, root):
"""
def serialize(self, root): :type root: TreeNode
"""Encodes a tree to a single string. :rtype: int
:type root: TreeNode """
:rtype: str self.longest = 0

self.consecutive(root, float('inf'), 0) for g, count in unmatched_guess.items():


return self.longest cows += min(unmatched_secret[g], count)

def consecutive(self, node, parent_val, sequence): return str(bulls) + "A" + str(cows) + "B"
if not node:
return
# python_1_to_1000/300_Longest_Increasing_Subsequence.py - m
if node.val == 1 + parent_val:
sequence += 1 _author_ = 'jake'
else: _project_ = 'leetcode'
sequence = 1
self.longest = max(self.longest, sequence) # https://leetcode.com/problems/longest-increasing-subsequence/
# Given an unsorted array of integers, find the length of longest increasing subsequence.
self.consecutive(node.left, node.val, sequence)
self.consecutive(node.right, node.val, sequence) # Maintain a list of the smallest final memeber of longest increasing subsequence of each
length. Binary search this
# list to find the sequence that each num can extend. This either creates a new longest
sequence, improves some other
# python_1_to_1000/299_Bulls_and_Cows.py - m # existing length sequence, or does nothing.
# Time - O(nlogn)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/bulls-and-cows/ def lengthOfLIS(self, nums):
# You are playing the following Bulls and Cows game with your friend: You write down a """
number and ask your friend to :type nums: List[int]
# guess what the number is. Each time your friend makes a guess, you provide a hint that :rtype: int
indicates how many digits in """
# said guess match your secret number exactly in both digit and position (called "bulls") LIS = [] # LIS[i] is the smallest number at the end of an increasing
and how many digits match subsequence of length i+1
# the secret number but locate in the wrong position (called "cows"). Your friend will
use successive guesses and for num in nums:
# hints to eventually derive the secret number. list_nb = self.binary_search(num, LIS)
# For example: Secret number: "1807" Friend's guess: "7810" if list_nb == len(LIS)-1: # num extends longest list
# Hint: 1 bull and 3 cows. (The bull is 8, the cows are 0, 1 and 7.) LIS.append(num)
# Write a function to return a hint according to the secret number and friend's guess, else: # num extends LIS[list_nb]
use A to indicate the bulls LIS[list_nb+1] = min(num, LIS[list_nb+1])
# and B to indicate the cows. In the above example, your function should return "1A3B".
# Please note that both secret number and friend's guess may contain duplicate digits. return len(LIS)
# You may assume that the secret number and your friend's guess only contain digits, and
their lengths are always equal.
def binary_search(self, num, LIS): # return the index in LIS of the smallest number
# Iterate over secret and guess together. If digits match increment bulls, else increment < num
counts of unmatched digits in left, right = 0, len(LIS)-1 # or -1 if no such number
# secret and guess. Then iterate over unmatched_guess digits, incrementing cows by the
lower of unmatched_secret while left <= right:
# and unmatched_guess counts for each digit.
# Time - O(n) mid = (left + right) // 2
# Space - O(1) if num <= LIS[mid]: # if num equals or is less than LIS[mid] then it
cannot extend mid sequence
from collections import defaultdict right = mid-1 # so look at all shorter sequences
else:
class Solution(object): left = mid+1
def getHint(self, secret, guess):
""" return right
:type secret: str
:type guess: str
:rtype: str # python_1_to_1000/301_Remove_Invalid_Parentheses.py - h
"""
bulls, cows = 0, 0 _author_ = 'jake'
unmatched_secret, unmatched_guess = defaultdict(int), defaultdict(int) _project_ = 'leetcode'

for s, g in zip(secret, guess): # https://leetcode.com/problems/remove-invalid-parentheses/


if s == g: # Remove the minimum number of invalid parentheses in order to make the input string
bulls += 1 valid. Return all possible results.
else: # The input string may contain letters other than the parentheses ( and ).
unmatched_secret[s] += 1
unmatched_guess[g] += 1 # When there are more closing than opening brackets, remove any previous closing bracket
at the last removed position
# or without a closing bracket before it (to avoid duplicate solutions) and recurse for if not image or not image[0] or image[x][y] != '1':
remainder of string. If return 0
# string is then valid, reverse string and switch opening and closing brackets to repeat
in other direction. # find lowest index of a row with any black cells
top_edge = self.find_edge(0, x, True, True, image)
class Solution(object):
def removeInvalidParentheses(self, s): # find lowest index of a row with any white cells
""" bottom_edge = self.find_edge(x+1, len(image), True, False, image)
:type s: str
:rtype: List[str] # find lowest index of a col with any black cells
""" left_edge = self.find_edge(0, y, False, True, image)
valid = []
self.remove(s, valid, 0, 0, ('(', ')')) # find lowest index of a col with any white cells
return valid right_edge = self.find_edge(y+1, len(image[0]), False, False, image)

return (right_edge - left_edge) * (bottom_edge - top_edge)


def remove(self, s, valid, start, removed, par):
net_open = 0
def find_edge(self, left, right, column, black, image):
for i in range(start, len(s)): while left < right:
net_open += ((s[i] == par[0]) - (s[i] == par[1])) mid = (left + right) // 2
if net_open >= 0: if black == self.any_black(mid, column, image):
continue right = mid
else:
# string is invalid so remove a closing bracket left = mid + 1
for j in range(removed, i+1): return left
if s[j] == par[1] and (j == removed or s[j - 1] != par[1]):
self.remove(s[:j] + s[j+1:], valid, i, j, par)
return def any_black(self, i, column, image):
if column: # if checking all columns, return True if any '1' in row i
reversed = s[::-1] return ('1' in image[i])
if par[0] == '(': # finished left to right else: # if checking all rows, return True if any '1' in column i
self.remove(reversed, valid, 0, 0, (')', '(')) return any(image[r][i] == '1' for r in range(len(image)))
else: # finished right to left
valid.append(reversed)

# python_1_to_1000/303_Range_Sum_Query_-_Immutable.py

_author_ = 'jake'
# python_1_to_1000/302_Smallest_Rectangle_Enclosing_Black_Pixels.py - h _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/range-sum-query-immutable/


_project_ = 'leetcode' # Given an integer array nums, find the sum of the elements between indices i and j (i ≤
j), inclusive.
# https://leetcode.com/problems/smallest-rectangle-enclosing-black-pixels/
# An image is represented by a binary matrix with 0 as a white pixel and 1 as a black # Store cumulative sums.
pixel. The black pixels are # Time - O(n) for __init__(), O(1) for sumRange()
# connected, i.e., there is only one black region. Pixels are connected horizontally and # Space - O(n)
vertically. Given the
# location (x, y) of one of the black pixels, return the area of the smallest (axis- class NumArray(object):
aligned) rectangle that encloses
# all black pixels. def __init__(self, nums):
"""
# If the black pixels are connected then every column and row in the enclosing rectangle :type nums: List[int]
contains a black pixel. We """
# search in each dimension separately for the first row/col with a black pixel and the self.cumul = [0]
first row/col after the (x,y) for num in nums:
# pixel without a black pixel. self.cumul.append(self.cumul[-1] + num)
# Time - O(mlogn + nlogm), binary search cols checking every row and vica versa
# Space - O(1) def sumRange(self, i, j):
"""
class Solution(object): :type i: int
def minArea(self, image, x, y): :type j: int
""" :rtype: int
:type image: List[List[str]] """
:type x: int return self.cumul[j + 1] - self.cumul[i]
:type y: int
:rtype: int
""" # python_1_to_1000/304_Range_Sum_Query_2D-Immutable.py - m

surrounded by water.
_author_ = 'jake'
_project_ = 'leetcode' # Union-find structure. parent stores the parent island, self if not attached to any
other land. Number of
# https://leetcode.com/problems/range-sum-query-2d-immutable/ # unique neighbour islands are counted by ascending to ultimate parents, updating links
# Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by to grandparents to compress
its upper left corner # paths and speed future lookups. All connected neighbours are combined by union.
# (row1, col1) and lower right corner (row2, col2) where row1 ≤ row2 and col1 ≤ col2. # Time - O(k log* k) where log* is iterated logarithm amd k is number of positions
# You may assume that the matrix does not change. There are many calls to sumRegion # Space - O(k)
function.
class Solution(object):
# Store cumulative sums to each cell as cell value + cumulative sum to previous row + def numIslands2(self, m, n, positions):
cumulative sum to previous col - """
# cumulative sum to previous row and col. :type m: int
# Time - O(m * n) to initialise, O(1) for sumRegion() :type n: int
# Space - O(1) :type positions: List[List[int]]
:rtype: List[int]
class NumMatrix(object): """
island_count = [0]
def __init__(self, matrix): parent = {} # key is (r,c), value is parent (r,c)
"""
:type matrix: List[List[int]] for r, c in positions:
"""
if not matrix or not matrix[0]: if (r, c) in parent: # ignore duplicate land
return island_count.append(island_count[-1])
continue
rows, cols = len(matrix), len(matrix[0])
for r in range(rows): nbors = set()
for c in range(cols):
if c != 0: for nbor in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]:
matrix[r][c] += matrix[r][c-1] if nbor in parent:
if r != 0: island = parent[nbor]
matrix[r][c] += matrix[r-1][c] while island != parent[island]:
if c != 0 and r != 0: parent[island] = parent[parent[island]] # path compression
matrix[r][c] -= matrix[r-1][c-1] island = parent[island]
nbors.add(island)
self.matrix = matrix
if not nbors:
def sumRegion(self, row1, col1, row2, col2): parent[(r, c)] = (r, c) # own parent
""" island_count.append(island_count[-1] + 1)
:type row1: int else:
:type col1: int this_island = nbors.pop()
:type row2: int for nbor in nbors:
:type col2: int parent[nbor] = this_island
:rtype: int parent[(r, c)] = this_island
""" island_count.append(island_count[-1] - len(nbors))
region = self.matrix[row2][col2]
if col1 != 0: return island_count[1:]
region -= self.matrix[row2][col1-1]
if row1 != 0:
region -= self.matrix[row1-1][col2]
if row1 !=0 and col1 != 0:
region += self.matrix[row1-1][col1-1] # python_1_to_1000/306_Additive_Number.py - m
return region
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/305_Number_of_Islands_II.py - h
# https://leetcode.com/problems/additive-number/
_author_ = 'jake' # Additive number is a string whose digits can form additive sequence. A valid additive
_project_ = 'leetcode' sequence should contain at
# least three numbers. Except for the first two numbers, each subsequent number in the
# https://leetcode.com/problems/number-of-islands-ii/ sequence must be the sum of
# A 2d grid map of m rows and n columns is initially filled with water. We may perform an # the preceding two.
addLand operation which
# turns the water at position (row, col) into a land. Given a list of positions to # Try all possible starting digit pairs with lengths such that the remainder has at least
operate, count the number of as many digits as the
# islands after each addLand operation. An island is surrounded by water and is formed by # longer of the 2 starting digits. Break out of loop if any number begins with 0 and has
connecting adjacent length > 1.
# lands horizontally or vertically. You may assume all four edges of the grid are all # 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) :type nums: List[int]
# Space - O(1) """
self.width = int(len(nums)**0.5) # width of each bin (apart from last)
class Solution(object): self.bin_sums = [] # sum of each bin
def isAdditiveNumber(self, num): self.nums = nums
"""
:type num: str for i, num in enumerate(nums):
:rtype: bool if i % self.width == 0: # start a new bin
""" self.bin_sums.append(num)
n = len(num) else: # add to last bin
if n < 3: self.bin_sums[-1] += num
return False

for second in range(1, 1 + (n - 1) // 2): # first digit of second integer def update(self, i, val):
if num[0] == "0" and second > 1: """
break :type i: int
third = second + 1 # first digit of third integer :type val: int
:rtype: void
while n - third >= max(second, third - second): """
if num[second] == "0" and third > second + 1: bin_i = i // self.width
break diff = val - self.nums[i]
self.bin_sums[bin_i] += diff # update bin_sums
n1, n2 = int(num[0:second]), int(num[second:third]) self.nums[i] = val # update nums
start = third
while True:
next_int = n1 + n2 def sumRange(self, i, j):
next_start = start + len(str(next_int)) """
if num[start] == "0" and next_start > start + 1: :type i: int
break :type j: int
if next_int != int(num[start:next_start]): :rtype: int
break """
if next_start == n: bin_i, bin_j = i // self.width, j // self.width
return True range_sum = sum(self.bin_sums[bin_i:bin_j]) # sum of whole bins
n1, n2, start = n2, next_int, next_start range_sum += sum(self.nums[bin_j*self.width:j+1]) # add partial last bin
range_sum -= sum(self.nums[bin_i*self.width:i]) # subtract partial first bin
third += 1 return range_sum

return False

# python_1_to_1000/308_Range_Sum_Query_2D-Mutable.py - h
# python_1_to_1000/307_Range_Sum_Query-Mutable.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/range-sum-query-2d-mutable/
# https://leetcode.com/problems/range-sum-query-mutable/ # Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by
# Given an integer array nums, find the sum of the elements between indices i and j (i ≤ its upper left corner
j), inclusive. # (row1, col1) and lower right corner (row2, col2).
# The update(i, val) function modifies nums by updating the element at index i to val. # You may assume the number of calls to update and sumRegion function is distributed
# You may assume the number of calls to update and sumRange function is distributed evenly.
evenly. # You may assume that row1 ≤ row2 and col1 ≤ col2.

# Break nums into bins, each of size approx n**0.5 and containing approx n**0.5 nums. # Store the cumulative sums for each row. To sumRegion, sum the difference between the
Calculate the sum of each bin. sum to the last and first col
# To sumRange(), sum the bins from and including i to and excluding j, then add the sum # over each row. To update, add the difference to the cumulative sum of that row for
of nums from the bin containing each later column.
# j and subtract the nums before i from the bin containing i. Update nums as well as # Time - O(mn) to initialise, O(n) to update, O(m) to sumRegion
bin_sums. # Space - O(1), modified im place
# Alternatively calculate the running cumulative sums within each bin and of each bin,
which makes O(n**0.5) to update class NumMatrix(object):
# and O(1) sumRange(). def __init__(self, matrix):
# Time - O(n) to initialise, O(1) to update, O(n**0.5) to sumRange(). """
# Space - O(n) :type matrix: List[List[int]]
"""
class NumArray(object): if not matrix or not matrix[0]:
return
def __init__(self, nums): rows, self.cols = len(matrix), len(matrix[0])

for r in range(rows): for i, price in enumerate(prices):


for c in range(1, self.cols): buy = max(buy, prev_sell-price)
matrix[r][c] += matrix[r][c - 1] prev_sell = sell
self.matrix = matrix sell = max(sell, buy+price)
print(buy, sell, prev_sell)
def update(self, row, col, val):
""" return sell
:type row: int
:type col: int
:type val: int
:rtype: void # python_1_to_1000/310_Minimum_Height_Trees.py - m
"""
prev = self.matrix[row][col] _author_ = 'jake'
if col != 0: _project_ = 'leetcode'
prev -= self.matrix[row][col - 1]
diff = val - prev # https://leetcode.com/problems/minimum-height-trees/
# For a undirected graph with tree characteristics, we can choose any node as the root.
for c in range(col, self.cols): # The result graph is then a rooted tree. Among all possible rooted trees, those with
self.matrix[row][c] += diff minimum height are called
# minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs
def sumRegion(self, row1, col1, row2, col2): and return a list of
""" # their root labels.
:type row1: int # The graph contains n nodes which are labeled from 0 to n - 1. You will be given the
:type col1: int number n and a list of
:type row2: int # undirected edges (each edge is a pair of labels). You can assume that no duplicate
:type col2: int edges will appear in edges.
:rtype: int
""" # In each iteration of the while loop, remove all leaves (nodes with 1 neighbour). This
sum_region = 0 prunes the tree from the
for r in range(row1, row2 + 1): # outwards resulting in either 1 or 2 nodes that are the maximum distance from any leaf.
sum_region += self.matrix[r][col2] # Time - O(n)
if col1 != 0: # Space - O(n)
sum_region -= self.matrix[r][col1 - 1]
return sum_region from collections import defaultdict

class Solution(object):
# python_1_to_1000/309_Best_Time_to_Buy_and_Sell_Stock_with_Cooldown.py - m def findMinHeightTrees(self, n, edges):
"""
_author_ = 'jake' :type n: int
_project_ = 'leetcode' :type edges: List[List[int]]
:rtype: List[int]
# 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. if n == 1:
# Design an algorithm to find the maximum profit. You may complete as many transactions return [0]
as you like connections = defaultdict(set) # key is node, value is set of neighbouring
# (ie, buy one and sell one share of the stock multiple times) with the following nodes
restrictions:
# You may not engage in multiple transactions at the same time (ie, you must sell the for a, b in edges:
stock before you buy again). connections[a].add(b)
# After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day) connections[b].add(a)

# Dynamic programming. Max cash if last transaction was a buy is either the max cash leaves = set(node for node in connections if len(connections[node]) == 1)
after an earlier last buy or
# the max cash after an earlier sell at least 2 days ago and buying now. The max cash while len(connections) > 2:
after selling on a given day is new_leaves = set()
# either the max cash after an earlier last sell or the max cash after an earlier buy and for leaf in leaves:
selling now. nbor = connections[leaf].pop()
# Max cash after selling = max profit since the stock is no longer held. connections[nbor].remove(leaf)
# Time - O(n) if len(connections[nbor]) == 1:
# Space - O(1) new_leaves.add(nbor)
del connections[leaf]
class Solution(object): leaves = new_leaves
def maxProfit(self, prices):
""" return list(connections.keys())
:type prices: List[int]
:rtype: int
""" # python_1_to_1000/311_Sparse_Matrix_Multiplication.py - m
buy, sell, prev_sell = float("-inf"), 0, 0
_author_ = 'jake'
_project_ = 'leetcode' for length in range(1, n + 1):

# https://leetcode.com/problems/sparse-matrix-multiplication/ for left in range(1, n + 2 - length): # consider subarrays from left to


# Given two sparse matrices A and B, return the result of AB. right inclusive
# You may assume that A's column number is equal to B's row number. right = left + length - 1

# When an element of A is non-zero update all elements of C using that element. Skip if for last in range(left, right + 1):
element of A is sero. this_coins = nums[left - 1] * nums[last] * nums[right + 1] # last
# Scales linearly with the density of A. balloon and neighbours
# Time - O(m*n*p) for A being (m by n) and B being (n by p) max_coins[length][left] = max(max_coins[length][left],
# Space - O(m*p) this_coins + max_coins[last - left][left] + max_coins[right -
last][last + 1])
class Solution(object):
def multiply(self, A, B): return max_coins[-1][1]
"""
:type A: List[List[int]]
:type B: List[List[int]]
:rtype: List[List[int]] # python_1_to_1000/313_Super_Ugly_Number.py - m
"""
rows_A, cols_A = len(A), len(A[0]) _author_ = 'jake'
cols_B = len(B[0]) # rows_B = cols_A _project_ = 'leetcode'

C = [[0 for _ in range(cols_B)] for _ in range(rows_A)] # https://leetcode.com/problems/super-ugly-number/


# Write a program to find the nth super ugly number. Super ugly numbers are positive
for r in range(rows_A): numbers whose all prime factors
for c in range(cols_A): # are in a given list of primes.
# 1 is a super ugly number for any given primes.
if A[r][c] != 0: # The given numbers in primes are in ascending order.
for i in range(cols_B):
C[r][i] += A[r][c] * B[c][i] # Each super ugly number is the product of a prime and a previous super ugly number.
Track the last super ugly number
return C # 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.
# python_1_to_1000/312_Burst _Balloons.py - h # Alternatively, use a heap to find min(candidates) in log k time if len(primes) is
large.
_author_ = 'jake' # Time - O(n * k) where k is the length of primes list.
_project_ = 'leetcode' # Space - O(n)

# https://leetcode.com/problems/burst-balloons/ class Solution(object):


# Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it def nthSuperUglyNumber(self, n, primes):
represented by array nums. """
# You are asked to burst all the balloons. If the you burst balloon i you will get :type n: int
nums[left] * nums[i] * nums[right] :type primes: List[int]
# coins. Here left and right are adjacent indices of i. After the burst, the left and :rtype: int
right then becomes adjacent. """
# Find the maximum coins you can collect by bursting the balloons wisely. super_ugly = [1]
# super_ugly[indices[i]] is the last super_ugly number to be multiplied by
# Dynamic programming. Calculate the max coins for subarrays of increasing lengths by primes[i] to generate candidates[i]
considering the max coins from indices = [0 for _ in range(len(primes))]
# all possible balloons to be burst last. Coins gained from bursting a balloon last = candidates = primes[:]
coins from that balloon *
# coins from balloon before the subarray * coins from balloon after the subarray + coins while len(super_ugly) < n:
from left subarray + coins
# from right subarray. ugly = min(candidates)
# Time - O(n**3) super_ugly.append(ugly)
# Space - O(n**2)
for i in range(len(candidates)): # update all candidates equal to ugly
class Solution(object): (avoids duplicates)
def maxCoins(self, nums): if ugly == candidates[i]:
""" indices[i] += 1
:type nums: List[int] candidates[i] = primes[i] * super_ugly[indices[i]]
:rtype: int
""" return super_ugly[-1]
n = len(nums)
nums = [1] + nums + [1]
max_coins = [[0 for _ in range(n + 2)] for _ in range(n + 1)] # row = length, # python_1_to_1000/314_Binary_Tree_Vertical_Order_Traversal.py - m
col = left

_author_ = 'jake' def helper(indices):


_project_ = 'leetcode' mid = len(indices) / 2
if mid == 0:
# https://leetcode.com/problems/binary-tree-vertical-order-traversal/ return indices
# Given a binary tree, return the vertical order traversal of its nodes' values. (from
top to bottom, column by column). left, right = helper(indices[:mid]), helper(indices[mid:])
# If two nodes are in the same row and column, the order should be from left to right.
for i in range(len(indices))[::-1]: # Rebuild indices from largest to
# Breadth first search tracking column number in a dictionary (since the range of columns smallest num.
is unknown). if not right or left and nums[left[-1]] > nums[right[-1]]:
# Time - O(n) indices[i] = left.pop()
# Space - O(n) smaller[indices[i]] += len(right) # All right are smaller than
largest left.
# Definition for a binary tree node. else:
# class TreeNode(object): indices[i] = right.pop()
# def __init__(self, x):
# self.val = x return indices
# self.left = None
# self.right = None
smaller = [0 for _ in range(len(nums))]
from collections import defaultdict helper([i for i in range(len(smaller))])
return smaller
class Solution(object):
def verticalOrder(self, root):
"""
:type root: TreeNode # python_1_to_1000/316_Remove_Duplicate_Letters.py - m
:rtype: List[List[int]]
""" _author_ = 'jake'
vertical = defaultdict(list) _project_ = 'leetcode'
frontier = [(root, 0)] # (node, column) pairs
# https://leetcode.com/problems/remove-duplicate-letters/
for node, col in frontier: # Given a string which contains only lowercase letters, remove duplicate letters so that
every letter appear once
if node: # and only once. You must make sure your result is the smallest in lexicographical order
vertical[col].append(node.val) among all possible results.
frontier += [(node.left, col-1), (node.right, col+1)]
# ok but not great to extend frontier whilst iterating over it # Find the first instance of the lexicographically first letter in the string. If the
suffix starting from this letter
return [vertical[col] for col in sorted(vertical)] # contains all of the letters in the string, then add this to the result and recurse on
the remainder of the string
# having removed all of this letter. If the suffix does not contain all letters, try the
lexicographically next letter.
# A letter is added to the result when the prefix does not contain all instances of any
other letter.
# Time - O(n * k) where k is the size of the alphabet
# Space - O(n)
# python_1_to_1000/315_Count_of_Smaller_Numbers_After_Self.py - h
class Solution(object):
_author_ = 'jake' def removeDuplicateLetters(self, s):
_project_ = 'leetcode' """
:type s: str
# https://leetcode.com/problems/count-of-smaller-numbers-after-self/ :rtype: str
# You are given an integer array nums and you have to return a new counts array. The """
counts array has the property s_set = sorted(set(s))
# where counts[i] is the number of smaller elements to the right of nums[i]. for c in s_set:
suffix = s[s.index(c):]
# Merge sort, counting the smaller elements to the right during merging. if len(set(suffix)) == len(s_set):
# Helper function sorts the original indices of the input. return c + self.removeDuplicateLetters(suffix.replace(c, ""))
# Merge in decreasing order, incrementing smallest when all right array are smaller than return ""
largest of left array.
# Time - O(n log n)
# Space - O(n)
# python_1_to_1000/317_Shortest_Distance_from_All_Buildings.py - h
class Solution(object):
def countSmaller(self, nums): _author_ = 'jake'
""" _project_ = 'leetcode'
:type nums: List[int]
:rtype: List[int] # 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. # Given a string array words, find the maximum value of length(word[i]) * length(word[j])
# You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or where the two words do not
2, where: # share common letters. You may assume that each word will contain only lower case
# Each 0 marks an empty land which you can pass by freely. letters.
# Each 1 marks a building which you cannot pass through. # If no such two words exist, return 0.
# 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 # Encode each word as an integer (up to (2^26)-1) with each set bit indicating the
-1. presence of a letter. Check all
# pairs of codes, if the logical AND of the codes is zero then they have no letters in
# For each house explore all of the grid that is reachable by previous houses with BFS. common.
Add the distance from the # Alternatively sort worst in decreasing length order and break code comparison when
# house to a copy of the grid. BFS is pruned by only considering cells reached by max_product can no longer be
earlier houses. # exceeded.
# Time - O(m * n * h) where h is the number of houses # Time - O(n**2)
# Space - O(m * n) # Space - O(n)

from copy import deepcopy class Solution(object):


def maxProduct(self, words):
class Solution(object): """
def shortestDistance(self, grid): :type words: List[str]
""" :rtype: int
:type grid: List[List[int]] """
:rtype: int codes = [] # set a bit for each letter present in word
""" for word in words:
rows, cols = len(grid), len(grid[0]) codes.append(sum(1 << (ord(c) - ord('a')) for c in set(word)))
house = 0 # number of the current house performing BFS
distances = deepcopy(grid) # sum of distances from all explored houses to max_product = 0
each point for i in range(len(codes)-1):
for j in range(i+1, len(codes)):
for row in range(rows): if not (codes[i] & codes[j]):
for col in range(cols): max_product = max(max_product, len(words[i]) * len(words[j]))
return max_product
if grid[row][col] != 1: # not a house
continue
q = [(row, col)] # frontier of all cells to be explored # python_1_to_1000/319_Bulb_Switcher.py - m
house_dist = 1
_author_ = 'jake'
while q: _project_ = 'leetcode'
new_q = []
for r, c in q: # https://leetcode.com/problems/bulb-switcher/
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]: # There are n bulbs that are initially off. You first turn on all the bulbs. Then, you
# if within grid and has been explored by all previous houses turn off every second bulb.
if 0 <= r + dr < rows and 0 <= c + dc < cols and grid[r + dr] # On the third round, you toggle every third bulb (turning on if it's off or turning off
[c + dc] == -house: if it's on). For the ith
grid[r + dr][c + dc] -= 1 # signify that # round, you toggle every i bulb. For the nth round, you only toggle the last bulb.
another house has reached here # Find how many bulbs are on after n rounds.
new_q.append((r + dr, c + dc)) # add to list to
explore # The ith bulb is toggled twice by every pair a, b where a*b == i. Thus every prime is
distances[r + dr][c + dc] += house_dist # add to toggled twice only, most
cumulative distances # 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.
house_dist += 1 # Time - O(1)
q = new_q # Space - O(1)

house += 1 class Solution(object):


def bulbSwitch(self, n):
# 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] :type n: int
[c] == -house] :rtype: int
return -1 if not reachable else min(reachable) """
return int(n**0.5)

# python_1_to_1000/318_Maximum_Product_of_Word_Lengths.py - m
# python_1_to_1000/320_Generalized_Abbreviation.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/maximum-product-of-word-lengths/

# https://leetcode.com/problems/generalized-abbreviation/ :rtype: List[int]


# Write a function to generate the generalized abbreviations of a word. """
# Example: Given word = "word", return the following list (order does not matter): max_number = 0
# ["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", for i in range(k + 1):
"1o2", "2r1", "3d", "w3", "4"] if i <= len(nums1) and k - i <= len(nums2):
max1 = self.max_single(nums1, i)
# For each letter, either abbreviate that letter by converting it to an integer and max2 = self.max_single(nums2, k - i)
possibly adding to the count of merged = self.merge(max1, max2)
# previously abbreviated letters, or do not abbreviate and leave the letter as it is. max_number = max(max_number, int("".join(map(str, merged))))
# Time - O(2**n) return [int(c) for c in str(max_number)]
# Space - O(n * 2**n)

class Solution(object): def max_single(self, nums, k):


def generateAbbreviations(self, word): stack, n = [], len(nums)
""" for i, num in enumerate(nums):
:type word: str # stack not empty and num is more than top of stack and stack + remaining
:rtype: List[str] nums are more than k
""" while stack and num > stack[-1] and (len(stack) + (n - i) > k):
abbreviations = [[]] stack.pop()
if len(stack) < k:
for c in word: stack.append(num)
new_abbreviations = [] return stack
for abbr in abbreviations:

# abbreviate c def merge(self, nums1, nums2):


if len(abbr) > 0 and isinstance(abbr[-1], int): i, j = 0, 0
new_abbreviations.append(abbr[:-1] + [abbr[-1] + 1]) merged = []
else:
new_abbreviations.append(abbr + [1]) while i < len(nums1) and j < len(nums2):

# do not abbreviate c if nums1[i] < nums2[j]:


new_abbreviations.append(abbr + [c]) use1 = False
elif nums1[i] > nums2[j]:
abbreviations = new_abbreviations use1 = True
else: # nums1[i] == nums2[j]
return ["".join(map(str, a)) for a in abbreviations] shift = 1
while i+shift < len(nums1) and j+shift < len(nums2) and nums1[i+shift] ==
nums2[j+shift]:
# python_1_to_1000/321_Create_Maximum_Number.py - h shift += 1
if i+shift == len(nums1):
_author_ = 'jake' use1 = False
_project_ = 'leetcode' elif j+shift == len(nums2):
use1 = True
# https://leetcode.com/problems/create-maximum-number/ elif nums2[j+shift] > nums1[i+shift]:
# Given two arrays of length m and n with digits 0-9 representing two numbers. Create the use1 = False
maximum number of else:
# length k <= m + n from digits of the two. The relative order of the digits from the use1 = True
same array must be preserved.
# Return an array of the k digits. if use1:
merged.append(nums1[i])
# For each partition of i digits from nums1 and (i from 0 to k) and k-i digits from nums i += 1
2, find the max number from else:
# each nums list using that many digits. The overall max is the merge of 2 individual merged.append(nums2[j])
max numbers. Merge by taking j += 1
# the larger digit from the front, if equal look forward to the next position where the
digits are different and take return merged + nums1[i:] + nums2[j:]
# the larger. Single num largest uses a stack, popping all smaller digits provided there
are enough remaining and
# 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) # python_1_to_1000/322_Coin_Change.py - m
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def maxNumber(self, nums1, nums2, k):
""" # https://leetcode.com/problems/coin-change/
:type nums1: List[int] # You are given coins of different denominations and a total amount of money amount.
:type nums2: List[int] Write a function to compute the
:type k: int # fewest number of coins that you need to make up that amount. If that amount of money
cannot be made up by any while node != parents[node]:
# combination of the coins, return -1. parents[node] = parents[parents[node]] # collapse, set parent to
grandparent
# Depth first search of the tree of coin combinations. Explore first branch by removing node = parents[parents[node]] # go up to parent
as many of largest coin until return node
# zero balance (result) or then try removing next smallest coins. Back up to decrement
number of largest coin. for a, b, in edges:
# Prune branches that cannot lead to an improved result.
# Time - O(c**d) where branching factor c is number of coins and d is depth of tree a_parent = update_parent(a)
(amount / smallest coin) b_parent = update_parent(b)
# Space - O(c**d)
if a_parent != b_parent:
class Solution(object): parents[a_parent] = b_parent
def coinChange(self, coins, amount): components -= 1
"""
:type coins: List[int] return components
:type amount: int
:rtype: int
""" # python_1_to_1000/324_Wiggle_Sort_II.py - m
coins.sort(reverse = True)
self.result = float("inf") _author_ = 'jake'
_project_ = 'leetcode'
def dfs(largest_coin, remainder, used_coins):
# https://leetcode.com/problems/wiggle-sort-ii/
if remainder == 0: # Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] <
self.result = min(self.result, used_coins) nums[3]....
# You may assume all input has valid answer.
for i in range(largest_coin, len(coins)): # try coins with
largest first # Find the median (can be O(n) QuickSelect as per "215_Kth_Largest_Element_in_an_Array").
Partition the array
if remainder >= coins[i] * (self.result - used_coins): # cannot improve # with numbers larger than median at swapped to the left, numbers higher swapped to the
on result right and numbers same
break # unswapped. Remap indices such that odd are filled first, then wrap around to start
if coins[i] <= remainder: # use this coin again with even.
dfs(i, remainder - coins[i], used_coins + 1) # Time - O(n log n)
# Space - O(1)
dfs(0, amount, 0)
return self.result if self.result != float("inf") else -1 class Solution(object):
def wiggleSort(self, nums):
"""
# python_1_to_1000/323_Number_of_Connected_Components_in_an_Undirected_Graph.py - m :type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
_author_ = 'jake' """
_project_ = 'leetcode' nums.sort()
median = nums[len(nums)//2]
# https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
# Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a # map larger to last even, smaller to first odd
pair of nodes), def mapping(i):
# write a function to find the number of connected components in an undirected graph. return (i*2 + 1) % (len(nums) | 1) # modulo next odd number

# Union find. Each node is initially its own parent. For each edge, find ultimate parent # < left are > median, >= left and < i are == median, > right are < median
of each node. # >= i and <= right are unsorted
# If ultimate parents are different, union the components. Collapse unnecessary links left, i, right = 0, 0, len(nums) - 1
while finding parents.
# Alternatively, BFS or DFS (better with adjacency list representation). while i <= right:
# Time - O(m log* n) for m edges and n nodes if nums[mapping(i)] > median:
# Space - O(n) nums[mapping(i)], nums[mapping(left)] = nums[mapping(left)],
nums[mapping(i)]
class Solution(object): left += 1
def countComponents(self, n, edges): i += 1
""" elif nums[mapping(i)] < median:
:type n: int nums[mapping(i)], nums[mapping(right)] = nums[mapping(right)],
:type edges: List[List[int]] nums[mapping(i)]
:rtype: int right -= 1
""" else:
parents = [i for i in range(n)] i += 1
components = n

def update_parent(node): # python_1_to_1000/325_Maximum_Size_Subarray_Sum_Equals_k.py - m

_author_ = 'jake' # python_1_to_1000/327_Count_of_Range_Sum.py - h


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/?tab=Description _project_ = 'leetcode'
# Given an array nums and a target value k, find the maximum length of a subarray that
sums to k. # https://leetcode.com/problems/count-of-range-sum/
# If there isn't one, return 0 instead. # Given an integer array nums, return the number of range sums that lie in [lower, upper]
inclusive.
# Store the first index of every cumulative sum in a dictionary. For each cumulative # Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j
sum, lookup the prefix sum that (i ≤ j), inclusive.
# would give a subarray ending at i and summing to k.
# Time - O(n) # Create an array of the cumulative prefix sums. Mergesort this array, counting the
# Space - O(n) number of range sums purely
# within LHS and RHS. Then given that both sides are sorted, for each prefix_sum in LHS
class Solution(object): find the indices i and j
def maxSubArrayLen(self, nums, k): # that define the ranges summing to between lower and upper. Perform the merge using
""" python sorted().
:type nums: List[int] # Time - O(n log n)
:type k: int # Space - O(n)
:rtype: int
""" class Solution(object):
cumul, max_length = 0, 0 def countRangeSum(self, nums, lower, upper):
first_index = {} """
:type nums: List[int]
for i, num in enumerate(nums): :type lower: int
cumul += num :type upper: int
:rtype: int
if cumul == k: """
max_length = i + 1 # must be the longest cumul = [0]
elif cumul - k in first_index: for num in nums:
max_length = max(max_length, i - first_index[cumul - k]) cumul.append(num + cumul[-1])

if cumul not in first_index: # add if cumul not seen before def mergesort(cumul, left, right): # sorting cumul[left:right]
first_index[cumul] = i count = 0
if right - left <= 1:
return max_length return count

mid = (left + right) // 2


# python_1_to_1000/326_Power_of_Three.py count += mergesort(cumul, left, mid) + mergesort(cumul, mid, right) #
range counts within both sides
_author_ = 'jake' i, j = mid, mid
_project_ = 'leetcode' for prefix_sum in cumul[left:mid]: # range count across
mid
while i < right and cumul[i] - prefix_sum < lower: # find first index in
# https://leetcode.com/problems/power-of-three/ RHS that sums >= lower
# Given an integer, write a function to determine if it is a power of three. i += 1
while j < right and cumul[j] - prefix_sum <= upper: # find last index in
# Find the maximum power of 3 within a 4 byte signed integer. When divided by a power of RHS that sums > upper
3, this number will have no j += 1
# remainder. count += (j - i) # for next prefix_sum, restart at i and j since they
# Time - O(1) can only increase
# Space - O(1)
cumul[left:right] = sorted(cumul[left:right]) # merge
import math return count

class Solution(object): return mergesort(cumul, 0, len(cumul))


def isPowerOfThree(self, n):
"""
:type n: int
:rtype: bool
""" # python_1_to_1000/328_Odd_Even_Linked_List.py - m
if n <= 0:
return False _author_ = 'jake'
max_int = 2 ** 31 - 1 _project_ = 'leetcode'
max_power = int(math.log(max_int, 3))
return 3 ** max_power % n == 0 # https://leetcode.com/problems/odd-even-linked-list/
# Given a singly linked list, group all odd nodes together followed by the even nodes.
# 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. def dfs(self, r, c, matrix, memo):
# The first node is considered odd, the second node even and so on ... if memo[r][c] != -1:
return memo[r][c]
# Create 2 new dummy heads for odd and even index nodes. Connect each pair of nodes to longest_here = 1 # can visit at least this cell
the odd and even lists for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
# respectively. Break if no even node or next odd node. Connect the odd and even lists. if 0 <= r + dr < len(matrix) and 0 <= c + dc < len(matrix[0]) and matrix[r +
# Time - O(n) dr][c + dc] > matrix[r][c]:
# Space - O(1) longest_here = max(longest_here, self.dfs(r + dr, c + dc, matrix, memo) +
1)
# Definition for singly-linked list. memo[r][c] = longest_here
class ListNode(object): return longest_here
def __init__(self, x):
self.val = x
self.next = None
# python_1_to_1000/330_Patching_Array.p - mh
class Solution(object):
def oddEvenList(self, head): _author_ = 'jake'
""" _project_ = 'leetcode'
:type head: ListNode
:rtype: ListNode # https://leetcode.com/problems/patching-array/
""" # Given a sorted positive integer array nums and an integer n, add/patch elements to the
even_head = even = ListNode(None) array such that any number
odd_head = odd = ListNode(None) # in range [1, n] inclusive can be formed by the sum of some elements in the array.
# Return the minimum number of patches required.
while head:
odd.next = head # append head to odd list # At each stage we add the lowest missing number to the sequence. If the next num is <=
odd = odd.next # update head of odd list next_missing then it can
even.next = head.next # append head.next to even list # be used to extend the sequence without a patch. Or else we patch with next_missing,
even = even.next # update head of even list which extends the sequence
# as far as possible.
head = head.next.next if even else None # will break if no even or no # Time - O(m + log n) where m = len(nums)
even.next # Space - O(1)

odd.next = even_head.next # join lists, break link from last odd to last even class Solution(object):
return odd_head.next def minPatches(self, nums, n):
"""
:type nums: List[int]
# python_1_to_1000/329_Longest_Increasing_Path_in_a_Matrix.py - h :type n: int
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode' next_missing = 1
patches = 0
# https://leetcode.com/problems/longest-increasing-path-in-a-matrix/ i = 0
# 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. while next_missing <= n:
# You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not if i < len(nums) and nums[i] <= next_missing:
allowed). next_missing += nums[i]
i += 1
# For each starting cell, depth first search to explore all greater neighbours within the else:
matrix. Memoise results. next_missing += next_missing
# Time - O(m * n) patches += 1
# Space - O(m * n)
return patches
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]] # python_1_to_1000/331_Verify_Preorder_Serialization_of_a_Binary_Tree.py - m
:rtype: int
""" _author_ = 'jake'
if not matrix or not matrix[0]: _project_ = 'leetcode'
return 0
longest = 0 # https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/
memo = [[-1 for _ in range(len(matrix[0]))] for _ in range(len(matrix))] # One way to serialize a binary tree is to use pre-order traversal. When we encounter a
non-null node, we record the
for r in range(len(matrix)): # node's value. If it is a null node, we record a sentinel value such as #. Given a
for c in range(len(matrix[0])): string of comma separated values,
longest = max(longest, self.dfs(r, c, matrix, memo)) # verify whether it is a correct preorder traversal serialization of a binary tree.
return longest

# The number of leaves = number of internal nodes + 1. Count the number of future leaves flights = defaultdict(list)
based upon the internal for start, end in tickets: # key is start, value is list of ends (lowest
# nodes seen. If this is zero and there are other nodes left then we already have a alphabetical is last)
complete tree and there can be flights[start].append(end)
# no more nodes. Likewise if there are any expected leaves remaining after parsing the journey = []
tree it is not complete.
# Time - O(n) def visit(airport):
# Space - O(1) while flights[airport]:
visit(flights[airport].pop())
class Solution(object): journey.append(airport)
def isValidSerialization(self, preorder):
""" visit("JFK")
:type preorder: str return journey[::-1]
:rtype: bool
"""
if not preorder: class Solution2(object):
return True def findItinerary(self, tickets):
expected_leaves = 1 """
:type tickets: List[List[str]]
for node in preorder.split(","): :rtype: List[str]
if expected_leaves == 0: """
return False flights = defaultdict(list)
if node == "#": tickets.sort(reverse = True)
expected_leaves -= 1
else: for start, end in tickets:
expected_leaves += 1 flights[start].append(end)

return expected_leaves == 0 route, stack = [], ['JFK']

while stack:
# python_1_to_1000/332_Reconstruct_Itinerary.py - h while flights[stack[-1]]: # while some flight out of top of
stack airport
_author_ = 'jake' stack.append(flights[stack[-1]].pop()) # add first flight out to stack
_project_ = 'leetcode' route.append(stack.pop()) # no flights out of top of stack
- add to result
# https://leetcode.com/problems/reconstruct-itinerary/
# Given a list of airline tickets represented by pairs of departure and arrival airports return route[::-1]
[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.
# If there are multiple valid itineraries, you should return the itinerary that has the
smallest lexical order when # python_1_to_1000/333_Largest_BST_Subtree.py - m
# read as a single string. For example, the itinerary ["JFK", "LGA"] has a smaller
lexical order than ["JFK", "LGB"]. _author_ = 'jake'
# You may assume all tickets form at least one valid itinerary. _project_ = 'leetcode'

# Sort the tickets so that for for each starting location the destinations are in reverse # https://leetcode.com/problems/largest-bst-subtree/
alphabetical order. Create # Given a binary tree, find the largest subtree which is a Binary Search Tree (BST),
# a mapping from each start airport to a list of end airports in reverse alphabetical where largest means subtree
order. DFS the graph, always # with largest number of nodes in it.
# taking the lexicographically first next airport. When we reach an end, this airport
has an odd number of edges # Bottom-up recursively determine whether a subtree is a BST if its children and BSTs and
# and must be the ultimate end of the itinerary so add it to the result. Backtrack, he root node value is
adding airports to the result # between the highest in left subtree and smallest in right subtree.
# when there is no other choice, or else exploring. # Time - O(n)
# Alternatively, iteratively. # Space - O(1)
# Time - O(n), number of tickets
# Space - O(n) # Definition for a binary tree node.
class TreeNode(object):
from collections import defaultdict def __init__(self, x):
self.val = x
class Solution(object): self.left = None
def findItinerary(self, tickets): self.right = None
"""
:type tickets: List[List[str]] class Solution(object):
:rtype: List[str] def largestBSTSubtree(self, root):
""" """
tickets.sort(reverse = True) # reverse start destination, then ties broken by :type root: TreeNode
reverse end :rtype: int
""" # In other words, after each move your direction changes counter-clockwise.
self.largest = 0
# There are 3 scenarios for a crossing (described from the perspective of the first move
def is_bst(node): # return largest in subtree, smallest in subtree, subtree m0 being vertically up),
count # 1) After 4 moves. Down move m2 <= up move m0 and left move m3 >= right move m1.
# subtree count = -1 if not a BST # 2) After 5 moves. Left move m1 == right move m3 and final up move m4 >= distance to
if not node: start m2 - m0.
return float("-inf"), float("inf"), 0 # 3) After 6 moves. Final up move m4 <= previous down move m2 and also >= distance to
start m2 - m0. Final right move
left_bst = is_bst(node.left) # m5 >= previous left move m3 and also left move m3 > right move m1 and final right move
right_bst = is_bst(node.right) m5 >= distance to
# start m3 - m1.
if left_bst[2] != -1 and right_bst[2] != -1: # both sides are BSTs # Time - O(n)
if left_bst[0] < node.val < right_bst[1]: # node.val within bounds # Space - O(1)
set by subtrees
size = 1 + left_bst[2] + right_bst[2] # update largest class Solution(object):
self.largest = max(self.largest, size) def isSelfCrossing(self, x):
return max(right_bst[0], node.val), min(left_bst[1], node.val), size """
:type x: List[int]
return 0, 0, -1 :rtype: bool
"""
is_bst(root) # ignore return value for i in range(len(x)):
return self.largest # assume staring with verical move up
if i >= 3:
# move down <= move up and move left >= move right
if x[i - 1] <= x[i - 3] and x[i] >= x[i - 2]:
return True
# python_1_to_1000/334_Increasing_Triplet_Subsequence.py - m if i >= 4:
# move right equal to move left and last move up >= vertical distance
_author_ = 'jake' from start
_project_ = 'leetcode' if x[i - 1] == x[i - 3] and x[i] >= x[i - 2] - x[i - 4]:
return True
# https://leetcode.com/problems/increasing-triplet-subsequence/ if i >= 5:
# Given an unsorted array return whether an increasing subsequence of length 3 exists or # final move right >= horizontal distance to start and left move > first
not in the array. right move and
# final vertical move >= vertical distance to start but also <= down move
# Track the smallest num seen so far and the next_smallest. If we see a num larger than if x[i] >= x[i - 2] - x[i - 4] and x[i - 2] > x[i - 4] and x[i - 3] - x[i
next_smallest, return True. - 5] <= x[i - 1] <= x[i - 3]:
# Time - O(n) return True
# Space - O(1)
return False
class Solution(object):
def increasingTriplet(self, nums):
"""
:type nums: List[int] # python_1_to_1000/336_Palindrome_Pairs.py - h
:rtype: bool
""" _author_ = 'jake'
smallest, next_smallest = float("inf"), float("inf") _project_ = 'leetcode'

for num in nums: # https://leetcode.com/problems/palindrome-pairs/


smallest = min(smallest, num) # Given a list of unique words, find all pairs of distinct indices (i, j) in the given
if num > smallest: list, so that the concatenation
next_smallest = min(next_smallest, num) # of the two words, i.e. words[i] + words[j] is a palindrome.
if num > next_smallest:
return True # Build a mapping from each word to its index in words. Partition each word at ever
possible point. If left is a
return False # palindrome and reverse right is a word (but not the word itself), then add rev_right +
word to the result.
# Repeat for right being a palindrome and rev_left a word. Remove duplicates from words
# python_1_to_1000/335_Self_Crossing.py - h and their reverses by
# requiring left not to be empty.
_author_ = 'jake' # Time - O(n * k**2) where k is the max length of a word
_project_ = 'leetcode' # Space - O(n * k)

# https://leetcode.com/problems/self-crossing/ class Solution(object):


# You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] def palindromePairs(self, words):
metres to the north, """
# then x[1] metres to the west, x[2] metres to the south, x[3] metres to the east and so :type words: List[str]
on. :rtype: List[List[int]]

""" left_with, left_without = self.helper(node.left)


palindromes = [] right_with, right_without = self.helper(node.right)
word_to_index = {}
max_with = node.val + left_without + right_without
for i, word in enumerate(words): max_without = max(left_with, left_without) + max(right_with, right_without)
word_to_index[word] = i
return max_with, max_without
for i, word in enumerate(words):

for first_right in range(len(word) + 1): # python_1_to_1000/338_Counting_Bits.py

left, right = word[:first_right], word[first_right:] _author_ = 'jake'


rev_left, rev_right = left[::-1], right[::-1] _project_ = 'leetcode'

if first_right != 0 and left == rev_left and rev_right in word_to_index # https://leetcode.com/problems/counting-bits/


and word_to_index[rev_right] != i: # Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num
palindromes.append([word_to_index[rev_right], i]) calculate the number of 1's
# in their binary representation and return them as an array.
if right == rev_right and rev_left in word_to_index and
word_to_index[rev_left] != i: # Dynamic programming. Number of set bits is 1 + the number of set bits in the number
palindromes.append([i, word_to_index[rev_left]]) after removing the lowest
# set bit.
return palindromes # Time - O(n)
# Space - O(n)

class Solution(object):
# python_1_to_1000/337_House_Robber_III.py - m def countBits(self, num):
"""
_author_ = 'jake' :type num: int
_project_ = 'leetcode' :rtype: List[int]
"""
# https://leetcode.com/problems/house-robber-iii/ ones = [0]
# The thief has found himself a new place for his thievery again. There is only one for i in range(1, num + 1):
entrance to this area, ones.append(1 + ones[i & (i - 1)]) # i & (i-1) removes the lowest set
# called the "root." Besides the root, each house has one and only one parent house. bit
After a tour, the smart thief return ones
# realized that "all houses in this place forms a binary tree". It will automatically
contact the police if two
# directly-linked houses were broken into on the same night.
# Determine the maximum amount of money the thief can rob tonight without alerting the # python_1_to_1000/339_Nested_List_Weighted_Sum.py - m
police.
_author_ = 'jake'
# Bottom-up recursion. For each node find the max gain with and without robbing that _project_ = 'leetcode'
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 # https://leetcode.com/problems/nested-list-weight-sum/
# root + same for right subtree. # Given a nested list of integers, return the sum of all integers in the list weighted by
# Time - O(n) their depth.
# Space - O(1) # Each element is either an integer, or a list -- whose elements may also be integers or
other lists.
# Definition for a binary tree node.
class TreeNode(object): # Iterate over the nestedList. If an element isInteger, add it to the total multiplied by
def __init__(self, x): its depth. Else increment
self.val = x # the depth and recurse to sum the deeper list.
self.left = None # Time - O(n)
self.right = None # Space - O(1)

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


def rob(self, root): def depthSum(self, nestedList):
""" """
:type root: TreeNode :type nestedList: List[NestedInteger]
:rtype: int :rtype: int
""" """
return max(self.helper(root)) def helper(nested, depth):

def helper(self, node): total = 0


if not node: for item in nested:
return 0, 0
if item.isInteger():
total += depth * item.getInteger() # """
else: # This is the interface that allows for creating nested lists.
total += helper(item.getList(), depth + 1) # You should not implement it, or speculate about its implementation
# """
return total # class NestedInteger(object):
# def isInteger(self):
return helper(nestedList, 1) # """
# @return True if this NestedInteger holds a single integer, rather than a nested
list.
# python_1_to_1000/340_Longest_Substring_with_At_Most_K_Distinct_Characters.py - m # :rtype bool
# """
_author_ = 'jake' #
_project_ = 'leetcode' # def getInteger(self):
# """
# https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/ # @return the single integer that this NestedInteger holds, if it holds a single
# Given a string, find the length of the longest substring T that contains at most k integer
distinct characters. # Return None if this NestedInteger holds a nested list
# :rtype int
# Maintain that last index of each character seen in a sliding window. Extend the window # """
by adding a new character #
# and if there are then more than k distinct characters, slide the start of the window # def getList(self):
forward until a char is removed. # """
# Time - O(n) # @return the nested list that this NestedInteger holds, if it holds a nested list
# Space - O(k) # Return None if this NestedInteger holds a single integer
# :rtype List[NestedInteger]
from collections import defaultdict # """

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


def lengthOfLongestSubstringKDistinct(self, s, k):
""" def __init__(self, nestedList):
:type s: str """
:type k: int Initialize your data structure here.
:rtype: int :type nestedList: List[NestedInteger]
""" """
start, longest = 0, 0 self.flat = []
last_seen = defaultdict(int) # key is char, value is last index of key def flatten(nested):
for n in nested:
for end, c in enumerate(s): if n.isInteger():
last_seen[c] = end # add c to mapping self.flat.append(n.getInteger())
else:
while len(last_seen) > k: # too many distinct chars in flatten(n.getList())
s[start:end + 1] flatten(nestedList)
if last_seen[s[start]] == start: # last_seen of start char is start self.flat = self.flat[::-1]
index
del last_seen[s[start]] # remove start char def next(self):
start += 1 # move front of window forwards """
:rtype: int
else: # longest can increase if have not entered """
while loop return self.flat.pop()
longest = max(longest, end - start + 1)

return longest def hasNext(self):


"""
:rtype: bool
# python_1_to_1000/341_Flatten_Nested_List_Iterator.py - m """
return bool(self.flat)
_author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/flatten-nested-list-iterator/ # python_1_to_1000/342_Power_of_Four.py
# 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 _author_ = 'jake'
other lists. _project_ = 'leetcode'

# Recursively flatten the list. If isInteger() then append that integer to the list, # https://leetcode.com/problems/power-of-four/
else depth first search. # Given an integer (signed 32 bits), write a function to check whether it is a power of
# Time - O(n) to initialise, O(1) for next() and hasNext() 4.
# Space - O(n)
# If log base 4 is not an integer then rounding to integer and raising to power 4 will

not return the original num. # either split k or keep, same for i - j
# Time - O(1) max_break = max(max_break, max(j, max_breaks[j]) * max(i - j,
# Space - O(1) max_breaks[i - j]))

import math max_breaks.append(max_break)

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


def isPowerOfFour(self, num):
"""
:type num: int # python_1_to_1000/344_Reverse_String.py
:rtype: bool
""" _author_ = 'jake'
if num <= 0: _project_ = 'leetcode'
return False
# https://leetcode.com/problems/reverse-string/
return 4 ** int(math.log(num, 4)) == num # Write a function that takes a string as input and returns the string reversed.

# Reverse with slice operator.


# Time - O(n)
# Space - O(n)
# python_1_to_1000/343_Integer_Break.py - m
class Solution(object):
_author_ = 'jake' def reverseString(self, s):
_project_ = 'leetcode' """
:type s: str
# https://leetcode.com/problems/integer-break/ :rtype: str
# Given a positive integer n, break it into the sum of at least two positive integers and """
maximize the product return s[::-1]
# of those integers. Return the maximum product you can get.

# For numbers > 4, subtract as many 3s as possible since any larger number should itself # python_1_to_1000/345_Reverse_Vowels_of_a_String.py
be broken and 3*3 > 2*2*2 so
# subtracting 3s is better than 2s. _author_ = 'jake'
# Alternatively, dynamic programming to try all splits. _project_ = 'leetcode'
# Time - O(1)
# Space - O(1) # https://leetcode.com/problems/reverse-vowels-of-a-string/
# Write a function that takes a string as input and reverse only the vowels of a string.
class Solution(object):
def integerBreak(self, n): # Find list of indices of vowels in s. Swap vowel at first index with vowel at last
""" index, until meeting in middle
:type n: int # of list of vowels.
:rtype: int # Time - O(n)
""" # Space - O(n)
if n <= 3:
return n - 1 class Solution(object):
def reverseVowels(self, s):
threes, remainder = divmod(n - 4, 3) """
product = 3**threes :type s: str
remainder += 4 :rtype: str
"""
if remainder == 4: vowels = {"a", "e", "i", "o", "u"}
return product * 2 * 2 vowels |= {c.upper() for c in vowels}
if remainder == 5:
return product * 3 * 2 vowel_i = [i for i, c in enumerate(s) if c in vowels]
return product * 3 * 3 n_vowel = len(vowel_i)

s = [c for c in s]
class Solution2(object): for j in range(n_vowel // 2):
def integerBreak(self, n): s[vowel_i[j]], s[vowel_i[n_vowel - j - 1]] = s[vowel_i[n_vowel - j - 1]],
""" s[vowel_i[j]]
:type n: int
:rtype: int return "".join(s)
"""
max_breaks = [0, 1]
# python_1_to_1000/346_Moving_Average_from_Data_Stream.py
for i in range(2, n + 1):
max_break = 0 _author_ = 'jake'
_project_ = 'leetcode'
for j in range(1, (i // 2) + 1):
# https://leetcode.com/problems/moving-average-from-data-stream/
# Given a stream of integers and a window size, calculate the moving average of all top_k = []
integers in the sliding window. while k:
while not frequencies[n]:
# Circular array. Replace array at index i with next val, update total and increment i. n -= 1
When i reaches end of array, top_k.append(frequencies[n].pop())
# reset i to start of array. k -= 1
# Time - O(n) where n == size for __init__(). O(1) for next().
# Space - O(n) return top_k

class MovingAverage(object):
# python_1_to_1000/348_Design_Tic-Tac-Toe.py - m
def __init__(self, size):
""" _author_ = 'jake'
Initialize your data structure here. _project_ = 'leetcode'
:type size: int
""" # https://leetcode.com/problems/design-tic-tac-toe/
self.array = [None for _ in range(size)] # sliding window contents # Design a Tic-tac-toe game that is played between two players on a n x n grid.
self.i = 0 # next index of array to be updated # A move is guaranteed to be valid and is placed on an empty block.
self.total = 0 # sum of array # Once a winning condition is reached, no more moves is allowed.
# A player who succeeds in placing n of their marks in a horizontal, vertical, or
def next(self, val): diagonal row wins the game.
"""
:type val: int # Arrays store the sums of each row and column, integers store the sums of the diagonals.
:rtype: float Convert player to +/-1 and
""" # increment sum of row, col and potentially diagonals. Check if any of row, col or
if self.array[self.i] is not None: # subtract entry leaving window from diagonal has absolute sum of n.
total # Time - O(n) for constructor and to O(1) for move()
self.total -= self.array[self.i] # Space - O(n)
self.total += val
self.array[self.i] = val class TicTacToe(object):

self.i = (self.i + 1) % len(self.array) def __init__(self, n):


"""
count = len(self.array) # find number of entries Initialize your data structure here.
if self.array[-1] is None: :type n: int
count = self.i """
self.rows, self.cols = [0 for _ in range(n)], [0 for _ in range(n)]
return self.total / float(count) self.d_up, self.d_down = 0, 0

def move(self, row, col, player):


# python_1_to_1000/347_Top_K_Frequent_Elements.py - m """
Player {player} makes a move at ({row}, {col}).
_author_ = 'jake' @param row The row of the board.
_project_ = 'leetcode' @param col The column of the board.
@param player The player, can be either 1 or 2.
# https://leetcode.com/problems/top-k-frequent-elements/ @return The current winning condition, can be either:
# Given a non-empty array of integers, return the k most frequent elements. 0: No one wins.
1: Player 1 wins.
# Count the frequency of each element. Bucket sort the elements by frequency since the 2: Player 2 wins.
highest frequency cannot be :type row: int
# more than the length of nums. Take the most frequent buckets, ties are split randomly. :type col: int
# Time - O(n) :type player: int
# Space - O(n) :rtype: int
"""
from collections import Counter n = len(self.rows)
score = (2 * player) - 3 # convert player to -1 or +1
class Solution(object):
def topKFrequent(self, nums, k): self.rows[row] += score
""" self.cols[col] += score
:type nums: List[int] if abs(self.rows[row]) == n or abs(self.cols[col]) == n:
:type k: int return player
:rtype: List[int]
""" if row == col:
n = len(nums) self.d_up += score
frequencies = [[] for _ in range(n + 1)] if abs(self.d_up) == n:
return player
for num, freq in Counter(nums).items(): if row + col == n - 1:
frequencies[freq].append(num) self.d_down += score

if abs(self.d_down) == n:
return player # https://leetcode.com/problems/android-unlock-patterns/
# Given an Android 3x3 key lock screen and two integers m and n, where 1 ≤ m ≤ n ≤ 9,
return 0 count the total number of
# unlock patterns of the Android lock screen, which consist of minimum of m keys and
maximum n keys.
# - Each pattern must connect at least m keys and at most n keys.
# python_1_to_1000/349_Intersection_of_Two_Arrays.py # - All the keys must be distinct.
# - If the line connecting two consecutive keys in the pattern passes through any other
_author_ = 'jake' keys, the other keys must
_project_ = 'leetcode' # have previously selected in the pattern. No jumps through non selected key is allowed.
# - The order of keys used matters.
# https://leetcode.com/problems/intersection-of-two-arrays/
# Given two arrays, write a function to compute their intersection. # BFS. For each of 3 starting positions (corner, middle edge, centre) extend all paths
by all possible new digits.
# Convert to sets, find intersection and convert back to list. # An extension is possible if the new digit has not been used before and any required
# Time - O(n + m) intervening digits have been
# Space - O(n + m) # used. Alternatively, DFS uses less memory.
# Alternatively, having worked out the result for each digit, store the results and
class Solution(object): perform a simple sum.
def intersection(self, nums1, nums2): # Time - O(n!)
""" # Space - O(n!)
:type nums1: List[int]
:type nums2: List[int] class Solution(object):
:rtype: List[int] def numberOfPatterns(self, m, n):
""" """
return list(set(nums1) & set(nums2)) :type m: int
:type n: int
:rtype: int
# python_1_to_1000/350_Intersection_of_Two_Arrays_II.py """
skips = [(1, 7, 4), (1, 9, 5), (1, 3, 2), (2, 8, 5),
_author_ = 'jake' (3, 7, 5), (3, 9, 6), (4, 6, 5), (7, 9, 8)]
_project_ = 'leetcode' jumps = {}
for start, end, skip in skips:
# https://leetcode.com/problems/intersection-of-two-arrays-ii/ jumps[(start, end)] = skip # to extend from start to end requires going
# Given two arrays, write a function to compute their intersection. via skip
# Each element in the result should appear as many times as it shows in both arrays. jumps[(end, start)] = skip
# The result can be in any order.
def count_patterns(start):
# Count frequencies of nums in nums1. Iterate over nums2, for every num in nums1 with a
positive count, append to paths = [[{start}, start]]
# result and decrement count in nums1. patterns = 1 if m == 1 else 0
# Time - O(m + n) for length in range(2, n + 1):
# Space - O(m)
new_paths = []
from collections import Counter for visited, last in paths:

class Solution(object): for extension in range(1, 10):


def intersect(self, nums1, nums2): if extension in visited: # cannot extend is already visited
""" digit
:type nums1: List[int] continue
:type nums2: List[int] if (last, extension) in jumps and jumps[(last, extension)] not in
:rtype: List[int] visited:
""" continue # cannot extend if have not visited
freq1 = Counter(nums1) any intervening digit
new_visited = set(visited)
result = [] new_visited.add(extension)
for i, num in enumerate(nums2): new_paths.append([new_visited, extension])
if num in freq1 and freq1[num] > 0:
freq1[num] -= 1 paths = new_paths
result.append(num)
if length >= m:
return result patterns += len(paths)

return patterns
# python_1_to_1000/351_Android_Unlock_Patterns.py - m
return 4 * count_patterns(1) + 4 * count_patterns(2) + count_patterns(5) #
_author_ = 'jake' symmetry
_project_ = 'leetcode'
interval_node = interval_node.parent
class Solution2(object): return interval_node
def numberOfPatterns(self, m, n):
""" def addNum(self, val):
:type m: int """
:type n: int :type val: int
:rtype: int :rtype: void
""" """
patterns = [0, 9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704] if val in self.parents: # already seen val, ignore
return sum(patterns[m:n+1]) return

lower = self.get_parent(val - 1)
upper = self.get_parent(val + 1)

# python_1_to_1000/352_Data_Stream_as_Disjoint_Intervals.py - h if lower and upper: # update lower, remove upper


lower.inner.end = upper.inner.end
_author_ = 'jake' self.parents[val] = lower
_project_ = 'leetcode' upper.parent = lower
self.intervals.remove(upper.inner)
# https://leetcode.com/problems/data-stream-as-disjoint-intervals/
# Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the elif lower:
numbers seen so far as a lower.inner.end += 1
# list of disjoint intervals in order of interval starting value. self.parents[val] = lower

# Create a wrapper class for interval that adds a parent attribute. For each number map elif upper:
it to an IntervalNode which upper.inner.start -= 1
# may itself be mapped to further IntervalNodes in a tree. Separately track all ultimate self.parents[val] = upper
intervals in a set.
# When a new value is added, check for integers above and below for their ultimate parent else:
intervals. Collapsing the new_inner = Interval(val, val)
# tree in a union-find structure. If only one is found, update that interval with the self.parents[val] = IntervalNode(new_inner)
new value. self.intervals.add(new_inner)
# If both are found, update the lower interval to merge them, remove the upper interval
and update the parent of the
# upper IntervalNode to the lower IntervalNode. def getIntervals(self):
# Alternatively store intervals as an sorted list with O(n) to insert then sort then O(1) """
to getIntervals(). :rtype: List[Interval]
# Alternatively store vals as an unsorted list then sort the list and merge to form """
intervals in getIntervals(). result = list(self.intervals)
# Alternatively, use BST. result.sort(key = lambda x : x.start)
# Time - O(log*n) to find parent, O(n log n) to sort intervals return result
# Space - O(n)

# Definition for an interval. # python_1_to_1000/353_Design_Snake_Game.py - m


# class Interval(object):
# def __init__(self, s=0, e=0): _author_ = 'jake'
# self.start = s _project_ = 'leetcode'
# self.end = e
# https://leetcode.com/problems/design-snake-game/
class IntervalNode(object): # Design a Snake game that is played on a device with screen size = width x height.
def __init__(self, interval): # The snake is initially positioned at the top left corner (0,0) with length = 1 unit.
self.inner = interval # You are given a list of food's positions in row-column order. When a snake eats the
self.parent = self food, its length and the game's
# score both increase by 1. Each food appears one by one on the screen. For example, the
class SummaryRanges(object): second food will not appear
# until the first food was eaten by the snake. When a food does appear on the screen, it
def __init__(self): is guaranteed that it will not
""" # appear on a block occupied by the snake.
Initialize your data structure here.
""" # Dictionary maps one segment of snake body to the next. Check for collision with wall
self.parents = {} # mapping from val to its IntervalNode or body apart from tail.
self.intervals = set() # all intervals that have not been joined # Score is len(snake) - 1.
# Time - O(f) for constructor (nb food), O(1) to move()
def get_parent(self, v): # Space - O(n)
if v not in self.parents:
return None class SnakeGame(object):
interval_node = self.parents[v]
while interval_node != interval_node.parent: def __init__(self, width,height,food):
interval_node.parent = interval_node.parent.parent """

Initialize your data structure here. # Create nested envelopes by wrapping larger ones around smaller. Sort by increasing
@param width - screen width width, with ties broken by
@param height - screen height # decreasing height. If widths are unique then when envelopes are considered in order we
@param food - A list of food positions can always wrap the
E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second # next envelope around any previous in the width dimension. If widths are same then
is at [1,0]. largest height first ensures we
:type width: int # do not put same width envelopes inside each other.
:type height: int # Maintain a list of the smallest outer envelope height for each number of nested
:type food: List[List[int]] envelopes. For each envelope find the
""" # longest nested list that can be extended. Update the best extended list with the new
self.rows, self.cols = height, width envelope if it has smaller
self.food = [tuple(f) for f in food] # convert to tuples # height, or make a new longest list.
self.snake = {(0, 0) : None} # map from position to next position # Time - O(n log n)
self.head, self.tail = (0, 0), (0, 0) # Space - O(n)
self.moves = {"U" : (-1, 0), "D" : (1, 0), "L" : (0, -1), "R" : (0, 1)}
class Solution(object):
def move(self, direction): def maxEnvelopes(self, envelopes):
""" """
Moves the snake. :type envelopes: List[List[int]]
@param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down :rtype: int
@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. # increasing width, ties broken by decreasing height
:type direction: str envelopes.sort(key = lambda x : (x[0], -x[1]))
:rtype: int
""" # nested[i] is smallest height outer envelope for i - 1 in total
# get new head position nested = []
new_head = (self.head[0] + self.moves[direction][0], self.head[1] +
self.moves[direction][1]) # find the index of the first number in nested >= target
# i.e. the first nested that can be improved (or stay same) by target
# check collision with wall # i.e. index after last nested than target can increase
if new_head[0] < 0 or new_head[0] >= self.rows or new_head[1] < 0 or new_head[1] def bin_search(target):
>= self.cols: left, right = 0, len(nested) - 1
return -1 while left <= right:
# check if hits body (apart from tail which will move or not be hit since eating mid = (left + right) // 2
food) if target > nested[mid]: # first greater than target must be on RHS
if new_head in self.snake and new_head != self.tail: left = mid + 1
return -1 else: # target <= nested[mid], target cannot fit around
nested[mid] so look st LHS
# update head right = mid - 1
self.snake[self.head] = new_head return left
self.head = new_head
for _, h in envelopes:
# move tail if not eaten food i = bin_search(h)
if len(self.snake) - 1 >= len(self.food) or new_head != self.food[len(self.snake) if i == len(nested):
- 1]: nested.append(h)
old_tail = self.tail else:
self.tail = self.snake[self.tail] nested[i] = h # h <= nested[i] so nested[i] can only improve
del self.snake[old_tail] # head has moved on fo safe even if length 1
return len(nested)
# extend length
self.snake[self.head] = None

return len(self.snake) - 1
# python_1_to_1000/355_Design_Twitter.py - m

_author_ = 'jake'
# python_1_to_1000/354_Russian_Doll_Envelopes.py - h _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/design-twitter/


_project_ = 'leetcode' # Design a simplified version of Twitter where users can post tweets, follow/unfollow
another user and is able to
# https://leetcode.com/problems/russian-doll-envelopes/ # see the 10 most recent tweets in the user's news feed. Your design should support the
# You have a number of envelopes with widths and heights given as a pair of integers (w, following methods:
h). One envelope can fit # - postTweet(userId, tweetId): Compose a new tweet.
# into another if and only if both the width and height of one envelope is greater than # - getNewsFeed(userId): Retrieve the 10 most recent tweet ids in the user's news feed.
the width and height of the Each item in the news feed must be posted by users who the user followed or by the user
# other envelope. What is the maximum number of envelopes can you Russian doll? (put one herself. Tweets must be ordered from most recent to least recent.
inside other) # - follow(followerId, followeeId): Follower follows a followee.
# - unfollow(followerId, followeeId): Follower unfollows a followee.
:rtype: void
# Map users to set of followers and list of tweets with timestamps. getNewsFeed by """
creating a heap of the most recent self.followers[followerId].add(followeeId)
# tweet from each followed (including self).
# Time - O(1) for init, postTweet, follow and unfollow. O(n) where n is nb followed to def unfollow(self, followerId, followeeId):
getNewsFeed """
# Space - O(max(u**2), t) where u is nb users who could potentially all folow each other, Follower unfollows a followee. If the operation is invalid, it should be a no-op.
t is nb tweets :type followerId: int
:type followeeId: int
from collections import defaultdict :rtype: void
import heapq """
self.followers[followerId].discard(followeeId)
class Twitter(object):

def __init__(self): # python_1_to_1000/356_Line_Reflection.py - m


"""
Initialize your data structure here. _author_ = 'jake'
""" _project_ = 'leetcode'
self.followers = defaultdict(set)
self.tweets = defaultdict(list) # https://leetcode.com/problems/line-reflection/
self.time = 0 # Given n points on a 2D plane, find if there is such a line parallel to y-axis that
reflect the given points.
def postTweet(self, userId, tweetId):
""" # Find the set of the x-values of all points with the same y-value. For each y-value
Compose a new tweet. make a sorted list of distinct
:type userId: int # x-values. Reflection axis is the mid-point between outer elements of the list. Only
:type tweetId: int if all other pairs (moving
:rtype: void # from outside of list inwards) match same reflection axis then all points can be
""" reflected.
self.tweets[userId].append([-self.time, tweetId]) # Time - O(n log n) due to sorting of x-values
self.time += 1 # Space - O(n)

def getNewsFeed(self, userId): from collections import defaultdict


"""
Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the class Solution(object):
news feed must be posted by def isReflected(self, points):
users who the user followed or by the user herself. Tweets must be ordered from """
most recent to least recent. :type points: List[List[int]]
:type userId: int :rtype: bool
:rtype: List[int] """
""" y_to_x = defaultdict(set) # set since multiple points can map to same point
self.followers[userId].add(userId) # always follow self for x, y in points:
(even if unfollowed earlier) y_to_x[y].add(x)
following = {u for u in self.followers[userId] if self.tweets[u]} # list of
people followed who have tweeted reflection = None # x-value of reflection line
last_tweet_i = {u : len(self.tweets[u]) - 1 for u in following} # mapping for y in y_to_x:
from followed user to index of last tweet xs = sorted(list(y_to_x[y]))
tweet_heap = [self.tweets[u][last_tweet_i[u]] + [u] for u in following] # left, right = 0, len(xs) - 1
most recent tweet from each followed
heapq.heapify(tweet_heap) if reflection is None:
feed = [] reflection = xs[left] + xs[right] # store sum (= 2 * x-axis of
while following and len(feed) < 10: # stop if 10 tweets or no more reflection) to maintain integer
from followed left += 1
_, tweetId, u = heapq.heappop(tweet_heap) # uses included so can update right -= 1
with next most recent tweet
feed.append(tweetId) while left <= right:
last_tweet_i[u] -= 1 if xs[right] + xs[left] != reflection :
if last_tweet_i[u] == -1: return False
following.remove(u) # no more tweets left += 1
else: right -= 1
heapq.heappush(tweet_heap, self.tweets[u][last_tweet_i[u]] + [u])
return True
return feed

def follow(self, followerId, followeeId):


""" # python_1_to_1000/357_Count_Numbers_with_Unique_Digits.py - m
Follower follows a followee. If the operation is invalid, it should be a no-op.
:type followerId: int _author_ = 'jake'
:type followeeId: int _project_ = 'leetcode'

rearranged = []
# https://leetcode.com/problems/count-numbers-with-unique-digits/
# Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < while heap:
10**n. too_close = [] # save most frequent letters that cannot be used
neg_f, letter = heapq.heappop(heap)
# For a single digit there are 10 choices. For exactly 2 digits, all of the single digit
results apart from 0 can have while letter in last_used and len(rearranged) - last_used[letter] < k: #
# any of the 9 unused digit appended. For exactly 3 digits we can append any of the 8 keep letter to add back later
unused digits to each of the too_close.append((neg_f, letter))
# 2 digit solutions. With more than 10 digits there are no more uniquie combinations. if not heap: # no more letters can be used
# Time - O(1) since at most 10 digits return ""
# Space - O(1) neg_f, letter = heapq.heappop(heap)

class Solution(object): last_used[letter] = len(rearranged)


def countNumbersWithUniqueDigits(self, n): rearranged.append(letter)
""" neg_f += 1
:type n: int if neg_f: # do not put back in heap if freq is zero
:rtype: int heapq.heappush(heap, (neg_f, letter))
"""
if n == 0: for item in too_close: # add back to heap
return 1 heapq.heappush(heap, item)

uniques = 10 # for 1 digit return "".join(rearranged)


can_expand = 9 # numbers that can be expanded by adding another digit

for digits in range(2, min(n, 10) + 1): # no increase after used all digits
can_expand *= (11 - digits) # python_1_to_1000/359_Logger_Rate_Limiter.py
uniques += can_expand
_author_ = 'jake'
return uniques _project_ = 'leetcode'

# https://leetcode.com/problems/logger-rate-limiter/
# Design a logger system that receive stream of messages along with its timestamps, each
message should be printed
# python_1_to_1000/358_Rearrange_String_k_Distance_Apart.py - h # if and only if it is not printed in the last 10 seconds.
# Given a message and a timestamp (in seconds granularity), return true if the message
_author_ = 'jake' should be printed in the
_project_ = 'leetcode' # given timestamp, otherwise returns false.
# It is possible that several messages arrive roughly at the same time.
# https://leetcode.com/problems/rearrange-string-k-distance-apart/
# Given a non-empty string s and an integer k, rearrange the string such that the same # Dictionary maps messages to last print time. If message not sen before or not seen for
characters are at least 10 seconds then update last
# distance k from each other. All input strings are given in lowercase letters. If it is # print time and return true. Else return false.
not possible to rearrange # Time - O(1)
# the string, return an empty string # Space - O(n)

# Count the frequency of each letter. Greedily add the most frequent letter to the class Logger(object):
result if it has not been used
# in the last k letters. Keep a heap of remaining frequency of each letter. Remove most def __init__(self):
frequent until letter can be """
# used, decrement remaining count and add back most frequent. Initialize your data structure here.
# Time - O(n log k) """
# Space - O(n) self.last = {}

from collections import Counter def shouldPrintMessage(self, timestamp, message):


import heapq """
Returns true if the message should be printed in the given timestamp, otherwise
class Solution(object): returns false.
def rearrangeString(self, s, k): If this method returns false, the message will not be printed.
""" The timestamp is in seconds granularity.
:type s: str :type timestamp: int
:type k: int :type message: str
:rtype: str :rtype: bool
""" """
freq = Counter(s) if message not in self.last or timestamp - self.last[message] >= 10:
heap = [(-count, letter) for letter, count in freq.items()] self.last[message] = timestamp
heapq.heapify(heap) return True

last_used = {} # map from letter to index in result of last use return False
class Solution(object):
# python_1_to_1000/360_Sort_Transformed_Array.py - m def maxKilledEnemies(self, grid):
"""
_author_ = 'jake' :type grid: List[List[str]]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/sort-transformed-array/ if not grid or not grid[0]:
# Given a sorted array of integers nums and integer values a, b and c. Apply a function return 0
of the form f(x) = ax2 + bx + c rows, cols = len(grid), len(grid[0])
# to each element x in the array. The returned array must be in sorted order. max_kill_enemies, row_kill, col_kill = 0, 0, [0 for _ in range(cols)]

# Shape of transformed function is U if a is positive. for r in range(rows):


# If a is +ve largest values are at ends. Take largest and mve inwards, reverse final for c in range(cols):
order.
# If a is -ve or zero then smallest values are at ends. Take smallest and move inwards. if c == 0 or grid[r][c - 1] == "W": # wall on left
# Time - O(n) row_kill, i = 0, c
# Space - O(n) while i < cols and grid[r][i] != "W": # go right until end or
wall
class Solution(object): row_kill += grid[r][i] == "E" # count enemies
def sortTransformedArray(self, nums, a, b, c): i += 1
"""
:type nums: List[int] if r == 0 or grid[r - 1][c] == "W": # wall above
:type a: int col_kill[c], i = 0, r
:type b: int while i < rows and grid[i][c] != "W": # go down until end or
:type c: int wall
:rtype: List[int] col_kill[c] += grid[i][c] == "E" # count enemies
""" i += 1
def transform(x):
return a * x * x + b * x + c if grid[r][c] == "0":
max_kill_enemies = max(max_kill_enemies, row_kill + col_kill[c])
transformed = [transform(num) for num in nums]
left, right = 0, len(nums) - 1 return max_kill_enemies
result = []

while left <= right:


# python_1_to_1000/362_Design_Hit_Counter.py - m
if (a > 0 and transformed[left] > transformed[right]) or (a <= 0 and
transformed[right] > transformed[left]): _author_ = 'jake'
result.append(transformed[left]) _project_ = 'leetcode'
left += 1
else: # https://leetcode.com/problems/design-hit-counter/
result.append(transformed[right]) # Design a hit counter which counts the number of hits received in the past 5 minutes.
right -= 1 # Each function accepts a timestamp parameter (in seconds granularity) and you may assume
that calls are being made to
return result[::-1] if a > 0 else result # the system in chronological order (ie, the timestamp is monotonically increasing). The
earliest timestamp starts at 1.

# Store each hit in a deque. For getHits() remove all hits longer than or equal to 300
seconds ago.
# python_1_to_1000/361_Bomb_Enemy.py - m # Alternatively, to reduce memory use and increase performance of getHits() store the
count along with timestamp so
_author_ = 'jake' # multiple hits at same timestamp are grouped.
_project_ = 'leetcode' # Time - O(1) for init and hit(), O(n) for getHits(), number of hits since previous
getHits
# https://leetcode.com/problems/bomb-enemy/ # Space - O(n)
# Given a 2D grid, each cell is either a wall 'W', an enemy 'E' or empty '0' (the number
zero), return the maximum from collections import deque
# enemies you can kill using one bomb. The bomb kills all the enemies in the same row
and column from the planted class HitCounter(object):
# point until it hits the wall since the wall is too strong to be destroyed.
# Note that you can only put the bomb at an empty cell. def __init__(self):
"""
# Whenever there is a wall to the left or above we have the start of a new clear row/col. Initialize your data structure here.
Run along the row/col until """
# either end or next wall counting enemies. At every clear space, add the current row self.time_diff = 300
and col enemies. self.q = deque()
# Time - O(m * n)
# Space - O(n) def hit(self, timestamp):

""" :rtype: int


Record a hit. """
@param timestamp - The current timestamp (in seconds granularity). if not matrix or not matrix[0]:
:type timestamp: int return 0
:rtype: void rows, cols = len(matrix), len(matrix[0])
""" max_sum = float("-inf")
self.q.append(timestamp)
for i in range(cols):
def getHits(self, timestamp): row_sums = [0 for _ in range(rows)]
"""
Return the number of hits in the past 5 minutes. for j in range(i, cols):
@param timestamp - The current timestamp (in seconds granularity). sorted_sums = [0] # sum of rows between these columns
:type timestamp: int all_row_sum = 0 # sum of cols i to j (inclusive), rows 0 to r
:rtype: int (inclusive)
"""
while self.q and timestamp - self.q[0] >= self.time_diff: for r in range(rows):
self.q.popleft() row_sums[r] += matrix[r][j]
return len(self.q) all_row_sum += row_sums[r]

larger = bisect.bisect_left(sorted_sums, all_row_sum - k) #


class HitCounter2(object): if larger != len(sorted_sums):
if all_row_sum - sorted_sums[larger] == k: # cannot improve,
def __init__(self): early return
self.time_diff = 300 return k
self.q = deque() max_sum = max(max_sum, all_row_sum - sorted_sums[larger])
self.count = 0
bisect.insort_left(sorted_sums, all_row_sum) # insert
def hit(self, timestamp): all_row_sum in sorted list
if self.q and self.q[len(self.q) - 1][0] == timestamp:
self.q[len(self.q) - 1][1] += 1 return max_sum
else:
self.q.append([timestamp, 1])
self.count += 1
# python_1_to_1000/364_Nested_List_Weight_Sum_II.py - m
def getHits(self, timestamp):
while self.q and timestamp - self.q[0][0] >= self.time_diff: _author_ = 'jake'
_, num = self.q.popleft() _project_ = 'leetcode'
self.count -= num
return self.count # https://leetcode.com/problems/nested-list-weight-sum-ii/
# Given a nested list of integers, return the sum of all integers in the list weighted by
their depth.
# python_1_to_1000/363_Max_Sum_of_Rectangle_No_Larger_Than_K.py - h # Each element is either an integer, or a list -- whose elements may also be integers or
other lists.
_author_ = 'jake' # Different from the previous question where weight is increasing from root to leaf, now
_project_ = 'leetcode' the weight is defined from
# bottom up. i.e., the leaf level integers have weight 1, and the root level integers
# https://leetcode.com/problems/max-sum-of-sub-matrix-no-larger-than-k/ have the largest weight.
# Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in
the matrix such that # DFS to calculate the sum of integers at each depth, starting with the shallowest. When
# its sum is no larger than k. max_depth is known,
# weight each depth sum by its number of layers above max_depth.
# For each column forming the left edge of the rectangle, calculate cumulative row_sums # Alternatively, BFS calculating the cumulative unweighted sum and repeatedly adding it
for each column at the right at each depth.
# edge of the rectangle. For each right edge column, iterate over rows and maintain a # Time - O(n)
sorted list of the sum of the # Space - O(n)
# cells between those columns for each row. For each row, find the value in the list that
makes a rectangle with sum class Solution(object):
# not more than k. Insert cumulative row sum into list. def depthSumInverse(self, nestedList):
# Alternatively use skip list or self-balancing tree to maintain sorted list. """
# Time - O(n**2 * m**2) :type nestedList: List[NestedInteger]
# Space - O(m) :rtype: int
"""
import bisect depth_sums = [] # depth_sums[i] is the sum of integers at depth i
for nested in nestedList:
class Solution(object): self.dfs(nested, 0, depth_sums)
def maxSumSubmatrix(self, matrix, k):
""" total = 0
:type matrix: List[List[int]] max_depth = len(depth_sums)
:type k: int for i, depth_sum in enumerate(depth_sums):
total += (max_depth - i) * depth_sum a, b = b, a % b
return total return a

if z == 0:
def dfs(self, nested, depth, depth_sums): return True
if len(depth_sums) <= depth: # new depth, extend list g = gcd(x, y)
depth_sums.append(0) if g == 0:
return False
if nested.isInteger(): # add to sum at depth return z % g == 0 and z <= x + y
depth_sums[depth] += nested.getInteger()
else:
for n in nested.getList(): # recurse at greater depth # python_1_to_1000/366_Find_Leaves_of_Binary_Tree.py - m
self.dfs(n, depth + 1, depth_sums)
_author_ = 'jake'
class Solution2(object): _project_ = 'leetcode'
def depthSumInverse(self, nestedList):
unweighted, weighted = 0, 0 # https://leetcode.com/problems/find-leaves-of-binary-tree/
q = nestedList # Given a binary tree, collect a tree's nodes as if you were doing this: Collect and
remove all leaves,
while q: # repeat until the tree is empty.
new_q = []
# Bottom-up preorder traversal to find height of each node (1 + max height of children).
for nested in q: # Time - O(n)
if nested.isInteger(): # Space - O(n)
unweighted += nested.getInteger()
else: # Definition for a binary tree node.
new_q += nested.getList() # class TreeNode(object):
# def __init__(self, x):
q = new_q # self.val = x
weighted += unweighted # self.left = None
# self.right = None
return weighted
class Solution(object):
def findLeaves(self, root):
"""
# python_1_to_1000/365_Water_And_Jug_Problem.py - m :type root: TreeNode
:rtype: List[List[int]]
_author_ = 'jake' """
_project_ = 'leetcode' leaves = [] # leaves[i] is ordered list of nodes with height i
self.height(root, leaves)
# https://leetcode.com/problems/water-and-jug-problem/ return leaves
# You are given two jugs with capacities x and y litres. There is an infinite amount of
water supply available. def height(self, node, leaves):
# You need to determine whether it is possible to measure exactly z litres using these if not node:
two jugs. return -1
# If z liters of water is measurable, you must have z liters of water contained within h = 1 + max(self.height(node.left, leaves), self.height(node.right, leaves))
one or both buckets by the end. if h >= len(leaves): # increase list size
# Operations allowed: leaves.append([])
# Fill any of the jugs completely with water. leaves[h].append(node.val)
# Empty any of the jugs. return h
# Pour water from one jug into another till the other jug is completely full or the
first jug itself is empty.
# python_1_to_1000/367_Valid_Perfect_Square.py - m
# z must be a multiple of the greatest common divisor of x and y, and not more than the
sum of x and y _author_ = 'jake'
# Time - O(log n) _project_ = 'leetcode'
# Space - O(1)
# https://leetcode.com/problems/valid-perfect-square/
# Given a positive integer num, write a function which returns True if num is a perfect
class Solution(object): square else False.
def canMeasureWater(self, x, y, z):
""" # Binary search between 1 and num. Test if middle of earch region is the square root of
:type x: int num. If not, search region
:type y: int # to left or right until solution or no more search region.
:type z: int # Time - O(log n)
:rtype: bool # Space - O(1)
"""
def gcd(a, b): class Solution(object):
while b != 0: def isPerfectSquare(self, num):

""" # You may assume the integer do not contain any leading zero, except the number 0 itself.
:type num: int # The digits are stored such that the most significant digit is at the head of the list.
:rtype: bool
""" # Add zero to the front then find the digit before the first 9. Increment that digit and
left, right = 1, num set all digits after to zero.
# remove leading zero if not incremented.
while left <= right: # Time - O(n)
# Space - O(1)
mid = (left + right) // 2
square = mid * mid # Definition for singly-linked list.
class ListNode(object):
if square == num: def __init__(self, x):
return True self.val = x
self.next = None
if square > num:
right = mid - 1 class Solution(object):
else: def plusOne(self, head):
left = mid + 1 """
:type head: ListNode
return False :rtype: ListNode
"""
new_head = ListNode(0) # make a new head with zero digit
# python_1_to_1000/368_Largest_Divisible_Subset.py - m new_head.next = head
i, j = new_head, new_head # pointers
_author_ = 'jake'
_project_ = 'leetcode' while i.next: # iterate along the list
i = i.next
# https://leetcode.com/problems/largest-divisible-subset/ if i.val != 9: # update j to find the last node that is not 9
# Given a set of distinct positive integers, find the largest subset such that every pair j = i
(Si, Sj) of elements in this
# subset satisfies: Si % Sj = 0 or Sj % Si = 0. If there are multiple solutions, return j.val += 1 # increment j
any subset. j = j.next
while j: # set all after j to zero
# For each num starting with smallest, create a set where every pair is divisible. j.val = 0
Search through all existing sets j = j.next
# to find the largest where num is divisible by its largest element (therefore num is
divisible by all of its elements) if new_head.val == 0: # not incremented new_head
# Time - O(n**2) return head
# Space - O(n) return new_head

class Solution(object):
def largestDivisibleSubset(self, nums):
""" # python_1_to_1000/370_Range_Addition.py - m
:type nums: List[int]
:rtype: List[int] _author_ = 'jake'
""" _project_ = 'leetcode'
max_to_set = {-1 : set()} # mapping from largest value in a set to its elements
nums.sort() # https://leetcode.com/problems/range-addition/
# Assume you have an array of length n initialized with all 0's and are given k update
for num in nums: operations.
# Each operation is represented as a triplet: [startIndex, endIndex, inc] which
num_set = set() # the set that has num as its largest value increments each element of
for max_in_s, s in max_to_set.items(): # subarray A[startIndex ... endIndex] (startIndex and endIndex inclusive) with inc.
if num % max_in_s == 0 and len(s) > len(num_set): # Return the modified array after all k operations were executed.
num_set = s
# To a list of length length + 1, add increments at starting index of each update and
max_to_set[num] = num_set | {num} # include num in the set decrements after ending index.
# Iterate over shifts, creating a cumulative sum.
return list(max(max_to_set.values(), key = len)) # max set by length # Time - O(n + k) where n = length and k = len(updates)
# Space - O(n)

# python_1_to_1000/369_Plus_One_Linked_List.py - m class Solution(object):


def getModifiedArray(self, length, updates):
_author_ = 'jake' """
_project_ = 'leetcode' :type length: int
:type updates: List[List[int]]
# https://leetcode.com/problems/plus-one-linked-list/ :rtype: List[int]
# Given a non-negative integer represented as non-empty a singly linked list of digits, """
plus one to the integer. if length <= 0:
return [] """
:type a: int
shifts = [0] * (length + 1) :type b: List[int]
for start, end, inc in updates: :rtype: int
shifts[start] += inc """
shifts[end + 1] -= inc result = 1

output = [shifts[0]] for digit in b: # pow() takes modulo as input


for i in range(1, length): result = (pow(result, 10, 1337) * pow(a, digit, 1337)) % 1337
output.append(output[-1] + shifts[i])
return result
return output

# python_1_to_1000/373_Find_K_Pairs_With_Smallest_Sums.py - m
# python_1_to_1000/371_Sum_of_Two_Integers.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/find-k-pairs-with-smallest-sums/
# https://leetcode.com/problems/sum-of-two-integers/ # You are given two integer arrays nums1 and nums2 sorted in ascending order and an
# Calculate the sum of two integers a and b, but you are not allowed to use the operator integer k.
+ and -. # Define a pair (u,v) which consists of one element from the first array and one element
from the second array.
# Use mask to isolate 32 bits. Sum of 2 bits is the XOR. If both bits are set, carry to # Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums.
next bit. Repeat until no
# more carry. Ir result is more than MAX_INT, subtract 2**32. # Maintain a heap from which the smallest sums are removed. Add the sum of elements at
# Time - O(log n) index 0 in both arrays to heap.
# Space - O(1) # Pop smallest from heap, add to heap the pair with incremented index from nums1 unless
at end of nums1. Add to heap
class Solution(object): # the pair
def getSum(self, a, b): # Time - O(k log k)
""" # Space - O(k)
:type a: int
:type b: int import heapq
:rtype: int
""" class Solution(object):
MASK = 0xFFFFFFFF # 2**32 - 1 def kSmallestPairs(self, nums1, nums2, k):
MAX_INT = 0x7FFFFFFF # 2**31 - 1 """
:type nums1: List[int]
while b != 0: :type nums2: List[int]
:type k: int
total = (a ^ b) & MASK :rtype: List[List[int]]
carry = ((a & b) << 1) & MASK # shift pattern when both bits are set """
print(a, b, total, carry) if not nums1 or not nums2:
a, b = total, carry return []

return a if a < MAX_INT else ~(a ^ MASK) # a - 2**321 smallest = []


frontier = [(nums1[0] + nums2[0], 0, 0)]

while frontier and len(smallest) < k:


_, i, j = heapq.heappop(frontier)
# python_1_to_1000/372_Super_Pow.py - m smallest.append([nums1[i], nums2[j]])
if len(frontier) >= k: # limit heap size
_author_ = 'jake' continue
_project_ = 'leetcode' if i < len(nums1) - 1: # not the last element of nums1
heapq.heappush(frontier, (nums1[i + 1] + nums2[j], i + 1, j))
# https://leetcode.com/problems/super-pow/ if i == 0 and j < len(nums2) - 1: # first element of nums 1 and not the
# Your task is to calculate a**b mod 1337 where a is a positive integer and b is an last element of nums2
extremely large positive integer heapq.heappush(frontier, (nums1[i] + nums2[j + 1], i, j + 1))
# given in the form of an array.
return smallest
# Base case is 1 (since a cannot be zero). For each digit of b starting with first,
iteratively raise to the power 10
# and multiply by a**digit, all modulo 1337 # python_1_to_1000/374_Guess_Number_Higher_or_Lower.py
# Time - O(log b)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def superPow(self, a, b): # https://leetcode.com/problems/guess-number-higher-or-lower/

# We are playing the Guess Game. The game is as follows: for range_length in range(3, n + 1):
# I pick a number from 1 to n. You have to guess which number I picked min_money.append([])
# Every time you guess wrong, I'll tell you whether the number is higher or lower. for lower in range(1, n + 2 - range_length):
# You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or upper = lower + range_length - 1
0): min_cost = float('inf')
for guess in range((lower + upper) // 2, upper): # guesses of LHS and
# Binary search. upper are never optimal
# Time - O(log n) cost = guess + max(min_money[guess - lower - 1][lower - 1],
# Space - O(1) min_money[upper - guess - 1][guess])
min_cost = min(min_cost, cost)
class Solution(object):
def guessNumber(self, n): min_money[-1].append(min_cost)
"""
:type n: int return min_money[n - 1][0]
:rtype: int
"""
low, high = 1, n
# python_1_to_1000/376_Wiggle_Subsequence.py - m
while True:
_author_ = 'jake'
mid = (low + high) // 2 _project_ = 'leetcode'
g = guess(mid)
# https://leetcode.com/problems/wiggle-subsequence/
if g == -1: # search lower region # A sequence of numbers is called a wiggle sequence if the differences between successive
high = mid - 1 numbers strictly alternate
elif g == 1: # search higher region # between positive and negative. The first difference (if one exists) may be either
low = mid + 1 positive or negative. A sequence
else: # with fewer than two elements is trivially a wiggle sequence.
return mid # Given a sequence of integers, return the length of the longest subsequence that is a
wiggle sequence. A subsequence
# is obtained by deleting some number of elements (potentially zero) from the original
sequence, leaving the remaining
# python_1_to_1000/375_Guess_Number_Higher_or_Lower_II.py - m # elements in their original order.

_author_ = 'jake' # If next move is in opposite direction to previous move then increase max_length. If
_project_ = 'leetcode' not then update previous so
# the last element of the increasing/decreasing/same subsequence is used.
# https://leetcode.com/problems/guess-number-higher-or-lower-ii/ # Time - O(n)
# We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. # Space - O(1)
You have to guess which
# number I picked. Every time you guess wrong, I'll tell you whether the number I picked class Solution(object):
is higher or lower. However, def wiggleMaxLength(self, nums):
# when you guess a number x, and you guess wrong, you pay $x. You win the game when you """
guess the number I picked. :type nums: List[int]
# Given a particular n ≥ 1, find out how much money you need to have to guarantee a win. :rtype: int
"""
# Dynamic programming. Min money for any range is the minimum cost after all possible if not nums:
next guesses. Min cost of return 0
# a particular guess is the guess + worst case of having to recurse on the range either
above or below the guess. max_length = 1
# Best guess is never in LHS of range since then the RHS is longer and has greater prev = nums[0]
numbers so we always want LHS to be direction = 0 # last move undetermined, +1 = up, -1 = down
# longer.
# Alternatively, top-down recursive. for num in nums[1:]:
# Time - O(n**3) if direction != -1 and num < prev:
# Space - O(n**2) max_length += 1
direction = -1
class Solution(object): elif direction != 1 and num > prev:
def getMoneyAmount(self, n): max_length += 1
""" direction = 1
:type n: int prev = num
:rtype: int
""" return max_length
# 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 # python_1_to_1000/377_Combination_Sum_IV.py - m
# if length == 2, min_money = lower value of range
min_money = [[0 for _ in range(n)], [i for i in range(1, n)]] _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/combination-sum-iv/ import heapq
# Given an integer array with all positive numbers and no duplicates, find the number of
possible combinations that class Solution(object):
# add up to a positive integer target. def kthSmallest(self, matrix, k):
"""
# Top-down nb ways to make k for any num in nums is 1 if num == k, 0 if num > k, recurse :type matrix: List[List[int]]
if num < k. :type k: int
# Alternatively, bottom up dynamic programming. :rtype: int
# Time - O(k) where k = target """
# Space - O(k * n) where n = len(nums) # start at opposite corner if more than half
rows, cols = len(matrix), len(matrix[0])
class Solution(object):
def combinationSum4(self, nums, target): if k > (rows * cols) // 2:
""" back = True
:type nums: List[int] k = rows * cols - k + 1
:type target: int frontier = [(-matrix[rows - 1][cols - 1], rows - 1, cols - 1)]
:rtype: int else:
""" back = False
memo = {} frontier = [(matrix[0][0], 0, 0)]
self.helper(nums, target, memo)
return memo[target] while k:
val, r, c = heapq.heappop(frontier)
def helper(self, nums, target, memo): k -= 1
if target < 0: if not back:
return 0 if c != len(matrix[0]) - 1:
if target == 0: heapq.heappush(frontier, (matrix[r][c + 1], r, c + 1))
return 1 if c == 0 and r != len(matrix) - 1:
if target in memo: heapq.heappush(frontier, (matrix[r + 1][c], r + 1, c))
return memo[target] else:
if c != 0:
combos = 0 heapq.heappush(frontier, (-matrix[r][c - 1], r, c - 1))
for num in nums: if c == cols - 1 and r != 0:
combos += self.helper(nums, target - num, memo) heapq.heappush(frontier, (-matrix[r - 1][c], r - 1, c))
memo[target] = combos
return combos return -val if back else val

class Solution2(object):
def combinationSum4(self, nums, target): # python_1_to_1000/379_Design_Phone_Directory.py - h
combos = [0] * (target + 1) # combos[i] is nb ways wo make i
combos[0] = 1 _author_ = 'jake'
_project_ = 'leetcode'
for i in range(1, target + 1):
for num in nums: # https://leetcode.com/problems/design-phone-directory/
if i >= num: # Design a Phone Directory which supports the following operations:
combos[i] += combos[i - num] # get: Provide a number which is not assigned to anyone.
# check: Check if a number is available or not.
return combos[-1] # release: Recycle or release a number.

# Store the set of all unused numbers. Storing the used numbers does not allow finding a
new number in O(1) time.
# python_1_to_1000/378_Kth_Smallest_Element_in_a_Sorted_Matrix.py - m # Time - O(n) to initialise, O(1) all other operations
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' class PhoneDirectory(object):

# https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/ def __init__(self, maxNumbers):


# Given a n x n matrix where each of the rows and columns are sorted in ascending order, """
find the kth smallest Initialize your data structure here
# element in the matrix. Note that it is the kth smallest element in the sorted order, @param maxNumbers - The maximum numbers that can be stored in the phone
not the kth distinct element. directory.
:type maxNumbers: int
# Maintain a heap of frontier numbers to be checked. Remove smallest and add next """
smallest column (if not end) and # need to find new numbers that are free, not numbers that are used
# if first column also add next smallest row (if any) to heap. # so only store the free set
# If k if is more than half the size of the matrix, look for m * n - k + 1th largest. self.free = set(range(maxNumbers))
# Time - O(m * n)
# Space - O(m + n) def get(self):

""" return False


Provide a number which is not assigned to anyone.
@return - Return an available number. Return -1 if none is available. def remove(self, val):
:rtype: int """
""" Removes a value from the set. Returns true if the set contained the specified
return self.free.pop() if self.free else -1 element.
:type val: int
def check(self, number): :rtype: bool
""" """
Check if a number is available or not. if val not in self.mapping:
:type number: int return False
:rtype: bool index = self.mapping[val]
""" self.items[index] = self.items[-1] # replace removed item with last item
return number in self.free self.mapping[self.items[index]] = index # update mapping for replacemnt item
self.items.pop()
def release(self, number): del self.mapping[val]
""" return True
Recycle or release a number.
:type number: int def getRandom(self):
:rtype: void """
""" Get a random element from the set.
self.free.add(number) :rtype: int
"""
# assumes self.items is not empty
# python_1_to_1000/380_Insert_Delete_GetRandom_O(1).py - m return self.items[random.randint(0, len(self.items) - 1)]

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/381_Insert_Delete_GetRandom_O(1)_Duplicates_Allowed.py - h

# https://leetcode.com/problems/insert-delete-getrandom-o1/ _author_ = 'jake'


# Design a data structure that supports all following operations in average O(1) time. _project_ = 'leetcode'
# insert(val): Inserts an item val to the set if not already present.
# remove(val): Removes an item val from the set if present. # https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/
# getRandom: Returns a random element from current set of elements. Each element must # Design a data structure that supports all following operations in average O(1) time.
have the same probability # Note: Duplicate elements are allowed.
# of being returned. # insert(val): Inserts an item val to the collection.
# remove(val): Removes an item val from the collection if present.
# Maintain a list of the vals as they are added and a mapping from each val to its index # getRandom: Returns a random element from current collection of elements. The
in the list. probability of each element being
# Upon removal replace with last val in list (self if removing last val), update mapping # returned is linearly related to the number of same value the collection contains.
for replacement val then
# delete mapping for removed val. # Maintain a list of vals and a mapping from val to all indices in list with that val.
# Note that using a set and no list is also O(1) but pop() does not produce a random val To remove, replace in list
and random.sample is slow. # with last val and update mapping of replacement.
# Time - O(1) # Time - O(1)
# Space - O(n) # Space - O(n)

import random from collections import defaultdict


import random

class RandomizedSet(object):
def __init__(self): class RandomizedCollection(object):
""" def __init__(self):
Initialize your data structure here. """
""" Initialize your data structure here.
self.mapping = {} # key is item, value is index in items list """
self.items = [] # list of items self.nums = []
self.indices = defaultdict(set) # value is the set of indices in self.nums with
def insert(self, val): values of key
"""
Inserts a value to the set. Returns true if the set did not already contain the def insert(self, val):
specified element. """
:type val: int Inserts a value to the collection. Returns true if the collection did not already
:rtype: bool contain the specified element.
""" :type val: int
if val not in self.mapping: # append to list and update mapping :rtype: bool
self.items.append(val) """
self.mapping[val] = len(self.items) - 1 result = True
return True if val in self.indices:
result = False self.head = head
self.count = 0
self.nums.append(val) while head:
self.indices[val].add(len(self.nums) - 1) self.count += 1
return result head = head.next

def remove(self, val): def getRandom(self):


""" """
Removes a value from the collection. Returns true if the collection contained the Returns a random node's value.
specified element. :rtype: int
:type val: int """
:rtype: bool randnode = random.randint(0, self.count - 1)
""" node = self.head
if val not in self.indices: for _ in range(randnode):
return False node = node.next
return node.val
i = self.indices[val].pop() # remove any index with this val

if not self.indices[val]: # delete val from mapping


del self.indices[val] # python_1_to_1000/383_Ransom_Note.py

if i == len(self.nums) - 1: # only need to remove from list _author_ = 'jake'


self.nums.pop() _project_ = 'leetcode'
else:
replacement = self.nums[-1] # https://leetcode.com/problems/ransom-note/
self.nums[i] = replacement # Given an arbitrary ransom note string and another string containing letters from all
self.nums.pop() the magazines, write a function
self.indices[replacement].discard(len(self.nums)) # change index in # that will return true if the ransom note can be constructed from the magazines ;
replacement mapping otherwise, it will return false.
self.indices[replacement].add(i) # Each letter in the magazine string can only be used once in your ransom note.
return True # You may assume that both strings contain only lowercase letters.

def getRandom(self): # Count all chars in ransom note asd magazines. If any char is in ransom note but not
""" magazine or has a lower count in
Get a random element from the collection. # magazine then return False.
:rtype: int # Time - O(m + n)
""" # Space - O(1)
return self.nums[random.randint(0, len(self.nums) - 1)]
from collections import Counter

# python_1_to_1000/382_Linked_List_Random_Node.py - m class Solution(object):


def canConstruct(self, ransomNote, magazine):
_author_ = 'jake' """
_project_ = 'leetcode' :type ransomNote: str
:type magazine: str
# https://leetcode.com/problems/linked-list-random-node/ :rtype: bool
# Given a singly linked list, return a random node's value from the linked list. Each """
node must have the same mag_count = Counter(magazine)
# probability of being chosen. ransom_count = Counter(ransomNote)

# Count length and move along a random number of nodes. Alternatively if getRandom() is for c in ransom_count:
called many times, store if c not in mag_count or mag_count[c] < ransom_count[c]:
# vals in a list and choose a random index (O(n) space and O(1) getRandom). return False
# Alternatively, reservoir sampling. Choose first item, for each subsequent ith item,
replace chosen with ith with return True
# probability 1/(1+i). Slow due to multiple random samples.
# Time - O(n)
# Space - O(1) # python_1_to_1000/384_Shuffle_an_Array.py - m

import random _author_ = 'jake'


_project_ = 'leetcode'
class Solution(object):
def __init__(self, head): # https://leetcode.com/problems/shuffle-an-array/
""" # Shuffle a set of numbers without duplicates.
@param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one # Copy original array and swap each entry with entry in a random position.
node. # Time - O(n)
:type head: ListNode # Space - O(n)
"""

import random
return nested
class Solution(object):

def __init__(self, nums): # python_1_to_1000/386_Lexicographical_Numbers.py - m


"""
:type nums: List[int] _author_ = 'jake'
:type size: int _project_ = 'leetcode'
"""
self.nums = nums # https://leetcode.com/problems/lexicographical-numbers/
# Given an integer n, return 1 - n in lexicographical order.
def reset(self):
""" # Next lexical num is previous * 10 if less than n.
Resets the array to its original configuration and return it. # Else divide by 10 and increment until less than n, rhen remove all zeros.
:rtype: List[int] # Alternatively, enumerate list id strings, sort and convert back to ints.
""" # Time - O(n)
return self.nums # Space - O(n)

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


""" def lexicalOrder(self, n):
Returns a random shuffling of the array. """
:rtype: List[int] :type n: int
""" :rtype: List[int]
result = self.nums[:] """
for i in range(len(result)): lexical = [1]
swap = random.randint(i, len(result) - 1)
result[i], result[swap] = result[swap], result[i] while len(lexical) < n:
return result
num = lexical[-1] * 10
while num > n: # increment the smallest digit possible
# python_1_to_1000/385_Mini_Parser.py - m num //= 10
num += 1
_author_ = 'jake' while num % 10 == 0: # strip off zeros
_project_ = 'leetcode' num //= 10
lexical.append(num)
# https://leetcode.com/problems/mini-parser/
# Given a nested list of integers represented as a string, implement a parser to return lexical
deserialize it.
# Each element is either an integer, or a list -- whose elements may also be integers or class Solution2(object):
other lists. def lexicalOrder(self, n):
# Note: You may assume that the string is well-formed: strings = list(map(str, range(1, n + 1)))
# String is non-empty. strings.sort()
# String does not contain white spaces. return list(map(int, strings))
# String contains only digits 0-9, [, - ,, ].

# Evaluate the string to convert to a nested list of ints. If s_eval is an int, return
NestedInteger with that int. # python_1_to_1000/387_First_Unique_Character_in_a_String.py
# Else create a NestedInteger of an empty list and recursively add all elements of
s_eval. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/first-unique-character-in-a-string/
class Solution(object): # Given a string, find the first non-repeating character in it and return it's index. If
def deserialize(self, s): it doesn't exist, return -1.
"""
:type s: str # Count frequency of each letter. Then iterate over s again, finding the index of the
:rtype: NestedInteger first letter with count of 1.
""" # Time - O(n)
return self.helper(eval(s)) # eval converts string to expression (nested list of # Space - O(1)
ints)
class Solution(object):
def helper(self, s_eval): def firstUniqChar(self, s):
"""
if isinstance(s_eval, int): :type s: str
return NestedInteger(s_eval) :rtype: int
"""
nested = NestedInteger() # nested is empty list counts = [0 for _ in range(26)]
for item in s_eval:
nested.add(self.helper(item)) for c in s:
counts[ord(c) - ord("a")] += 1 # is the additional letter in t.
# Time - O(n)
for i, c in enumerate(s): # Space - O(1)
if counts[ord(c) - ord("a")] == 1:
return i class Solution(object):
def findTheDifference(self, s, t):
return -1 """
:type s: str
:type t: str
# python_1_to_1000/388_Longest_Absolute_File_Path.py - m :rtype: str
"""
_author_ = 'jake' counts = [0 for _ in range(26)]
_project_ = 'leetcode'
for c in s:
# https://leetcode.com/problems/longest-absolute-file-path/ counts[ord(c) - ord("a")] += 1
# 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 for c in t:
contains an empty sub-directory index = ord(c) - ord("a")
# subdir1 and a sub-directory subdir2 containing a file file.ext. counts[index] -= 1
# Given a string representing the file system in the above format, return the length of if counts[index] < 0:
the longest absolute path to return c
# file in the abstracted file system. If there is no file in the system, return 0.

# For each line, depth is number of prefix tabs. If line cointains "." update longest # python_1_to_1000/390_Elimination_Game.py - m
with stripped line length +
# depth (for intervening "/") + depths[depth] (for directories). Else if not a file, _author_ = 'jake'
update the next directory _project_ = 'leetcode'
# length as directory length at this depth + new directory length.
# Time - O(n) # https://leetcode.com/problems/elimination-game/
# Space - O(n) # There is a list of sorted integers from 1 to n. Starting from left to right, remove the
first number and every other
class Solution(object): # number afterward until you reach the end of the list. Repeat the previous step again,
def lengthLongestPath(self, input): but this time from right to
""" # left, remove the right most number and every other number from the remaining numbers.
:type input: str # We keep repeating the steps again, alternating left to right and right to left, until a
:rtype: int single number remains.
""" # Find the last number that remains starting with a list of length n.
longest = 0
depths = [0] # depths[i] is the cumulative length of all directory strings # Track the first remaining number until only 1 number is left. On left to right passes,
preceeding file at depth i. head moves by step. On right
# to left passes, head moves by step only if an odd number remain else head stays. Step
for line in input.splitlines(): doubles and remaining halves
# every pass.
stripped = line.lstrip("\t") # Time - O(log n), half remaining each pass
depth = len(line) - len(stripped) # Space - O(1)

if "." in line: class Solution(object):


longest = max(longest, len(stripped) + depth + depths[depth]) def lastRemaining(self, n):
else: """
if len(depths) <= depth + 1: :type n: int
depths.append(0) :rtype: int
depths[depth + 1] = depths[depth] + len(stripped) """
head = 1 # first remaining number
return longest l_to_r = True # direction of next movement
step = 1 # numbers jumped over in each move

# python_1_to_1000/389_Find_the_Difference.py while n > 1: # remaining live numbers

_author_ = 'jake' if l_to_r:


_project_ = 'leetcode' head += step
else: # head only moves if odd number remaining
# https://leetcode.com/problems/find-the-difference/ if n % 2 != 0:
# Given two strings s and t which consist of only lowercase letters. head += step
# String t is generated by random shuffling string s and then add one more letter at a
random position. step *= 2
# Find the letter that was added in t. n //= 2 # reduce by half, +1 if n is odd
l_to_r = not l_to_r
# Count frequencies of letters in s. For each letter in t, decrement count. If any letter
count is negative then it return head

# (length ~= 500,000) string, and s is a short string (<=100).

# Iterate over t looking for first char of s. When found continue iteration over t
# python_1_to_1000/391_Perfect_Rectangle.py - h looking for next char of s.
# Alternatively if many different s, create lists if indices of each char in t then
_author_ = 'jake' binary search list for each char of
_project_ = 'leetcode' # s to find index in t after previous index in t.
# Time - O(n) when len(t) = n
# https://leetcode.com/problems/perfect-rectangle/ # Space - O(1)
# Given N axis-aligned rectangles where N > 0, determine if they together form an exact
cover of a rectangular region. class Solution(object):
# Each rectangle is represented as a bottom-left point and a top-right point. def isSubsequence(self, s, t):
"""
# Total area of all rectangles must equal covered region area. Corners of region must be :type s: str
counted once, other corners :type t: str
# match either 2 or 4 rectangles. :rtype: bool
# Time - O(n), number of rectangles """
# Space - O(n) if not s:
return True
from collections import defaultdict
i = 0 # next char to match in s
class Solution(object): for c in t:
def isRectangleCover(self, rectangles): if c == s[i]:
""" i += 1
:type rectangles: List[List[int]] if i == len(s):
:rtype: bool return True
""" return False
min_r, min_c = float("inf"), float("inf") # find extent of all rectangles
max_r, max_c = float("-inf"), float("-inf")
area = 0 # sum of areas of all rectangles # python_1_to_1000/393_UTF-8_Validation.py - m
corners = defaultdict(int) # count of number of corner by
(r, c) _author_ = 'jake'
_project_ = 'leetcode'
for r1, c1, r2, c2 in rectangles:
area += (r2 - r1) * (c2 - c1) # https://leetcode.com/problems/utf-8-validation/
min_r = min(min_r, r1) # A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules:
min_c = min(min_c, c1) # For 1-byte character, the first bit is a 0, followed by its unicode code.
max_r = max(max_r, r2) # For n-bytes character, the first n-bits are all one's, the n+1 bit is 0, followed by
max_c = max(max_c, c2) n-1 bytes with most
# significant 2 bits being 10.
corners[(r1, c1)] += 1 # Given an array of integers representing the data, return whether it is a valid utf-8
corners[(r2, c2)] += 1 encoding.
corners[(r1, c2)] += 1
corners[(r2, c1)] += 1 # If first bit set then count number of leading 1s, not 1 or more than 4, check following
bytes start with 10
rows = max_r - min_r # Time - O(n)
cols = max_c - min_c # Space - O(1)
if area != rows * cols:
return False class Solution(object):
def validUtf8(self, data):
for r, c in corners: """
if r in {min_r, max_r} and c in {min_c, max_c}: :type data: List[int]
if corners[(r, c)] != 1: :rtype: bool
return False """
elif corners[(r, c)] % 2 != 0: i = 0
return False while i < len(data):

return True byte = data[i]

if byte & (1 << 7) == 0: # first bit is a zero


# python_1_to_1000/392_Is_Subsequence.py i += 1
continue
_author_ = 'jake'
_project_ = 'leetcode' bit = 6
while byte & (1 << bit) and bit > 3:
# https://leetcode.com/problems/is-subsequence/ bit -= 1
# Given a string s and a string t, check if s is subsequence of t. if byte & (1 << bit) or bit == 6: # 1 or more than 4 leading 1 bits
# You may assume that there is only lower case English letters in both s and t. t is return False
potentially a very long
bytes = 6 - bit # expeted number of bytes starting with 10 :type s: str
i += 1 :rtype: str
while bytes: """
if i >= len(data) or data[i] & (128 + 64) != 128: self.i = 0 # next index in s to be decoded
return False return "".join(self.decode(s))
bytes -= 1
i += 1 def decode(self, s):
result = []
return True
while self.i < len(s) and s[self.i] != "]": # loop until end of s or closing
bracket

# python_1_to_1000/394_Decode_String.py - m if s[self.i] not in "0123456789": # add characters to result


result.append(s[self.i])
_author_ = 'jake' self.i += 1
_project_ = 'leetcode' else:
repeats = 0
# https://leetcode.com/problems/decode-string/ while s[self.i] in "0123456789": # calculate number of repetitions
# Given an encoded string, return it's decoded string. repeats = repeats * 10 + int(s[self.i])
# The encoding rule is: k[encoded_string], where the encoded_string inside the square self.i += 1
brackets is being repeated self.i += 1 # skip over "["
# exactly k times. Note that k is guaranteed to be a positive integer. result += (self.decode(s) * repeats) # recurse inside brackets and
# You may assume that the input string is always valid; No extra white spaces, square repeat
brackets are well-formed, etc. self.i += 1 # skip over "]"

# Build stack of chars of result. Iterate over input, pushing chars to stack. return result
# 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.
# Alternatively, recursively. # python_1_to_1000/395_Longest_Substring_with_At_Least_K_Repeating_Characters.py - m
# Time - O(2**n), integer creates sequence of length 2**n
# Space - O(2**n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def decodeString(self, s): # https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/
""" # Find the length of the longest substring T of a given string (consists of lowercase
:type s: str letters only) such that every
:rtype: str # character in T appears no less than k times.
"""
stack = [] # Split string by all chars with frequency less than k. Repeat with substrings until all
repeats = 0 chars are present >= k times.
digits = set("0123456789") # Discard substrings shorter than current longest.
# Time - O(n**3), every while loop removes one char from original s, for every c in freq,
for c in s: splitting is O(n)
# Space - O(n)
if c == "]":
item = stack.pop() from collections import Counter
current = []
while not isinstance(item, int): class Solution(object):
current.append(item) def longestSubstring(self, s, k):
item = stack.pop() """
stack += (current[::-1] * item) :type s: str
:type k: int
elif c in digits: :rtype: int
repeats = repeats * 10 + int(c) """
longest = 0
elif c == "[": # must have preceeding integer to_split = [s] # list of all substrings that may have infrequent
stack.append(repeats) chars
repeats = 0
while to_split:
else: t = to_split.pop() # any substring to be checked
stack.append(c) freq = Counter(t)
splitted = [t] # the result of removing all infrequent chars from t
return "".join(stack)
for c in freq:
if freq[c] < k: # split t by every infrequent character
class Solution2(object): new_splitted = []
def decodeString(self, s): for spl in splitted:
""" new_splitted += spl.split(c)

splitted = new_splitted # Time - O(log n)


# Space - O(1)
if len(splitted) == 1: # cound not be split, candicate for longest
longest = max(longest, len(splitted[0])) class Solution(object):
else: # only add back candidates that are sufficiently long def integerReplacement(self, n):
to_split += [spl for spl in splitted if len(spl) > longest] """
:type n: int
return longest :rtype: int
"""
operations = 0
# python_1_to_1000/396_Rotate_Function.py - m
while n > 1:
_author_ = 'jake'
_project_ = 'leetcode' operations += 1

# https://leetcode.com/problems/rotate-function/ if n % 2 == 0:
# Given an array of integers A and let n to be its length. n //= 2
# Assume Bk to be an array obtained by rotating the array A k positions clock-wise, we
define a "rotation function" F elif n == 3 or (n - 1) % 4 == 0:
# on A as follow: n -= 1
# F(k) = 0 * Bk[0] + 1 * Bk[1] + ... + (n-1) * Bk[n-1].
# Calculate the maximum value of F(0), F(1), ..., F(n-1). else:
n += 1
# Calculate the initial rotated_value and sum of all elements. To rotate, every element
is incremented and last element return operations
# is reduced from n-1 to zero times.
# Time - O(n)
# Space - O(n) # python_1_to_1000/398_Random_Pick_Index.py - m

class Solution(object): _author_ = 'jake'


def maxRotateFunction(self, A): _project_ = 'leetcode'
"""
:type A: List[int] # https://leetcode.com/problems/random-pick-index/
:rtype: int # Given an array of integers with possible duplicates, randomly output the index of a
""" given target number.
rotate_val, sum_A = 0, 0 # 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
for i, num in enumerate(A): the judge.
sum_A += num
rotate_val += i * num # To pick, reservoir sample indices by replacing previous result with probability 1 /
count of targets seen.
max_rotate = rotate_val # Alternatively create a list of i where nums[i] == target and randomly choose and index
for i in range(len(A) - 1, -1, -1): of that list. Only one
rotate_val += sum_A - (len(A) * A[i]) # last element net n-1 reduction # random choice but more memory.
max_rotate = max(max_rotate, rotate_val) # Alternatively map each num to a list of indices which adds O(n) memory and time to
intialise pick but reduces time to
return max_rotate # pick.
# Time - O(1) to initialise, O(n) to pick
# Space - O(1)
# python_1_to_1000/397_Integer_Replacement.py - m
import random
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def __init__(self, nums):
# https://leetcode.com/problems/integer-replacement/ """
# Given a positive integer n and you can do operations as follow:
# If n is even, replace n with n/2. :type nums: List[int]
# If n is odd, you can replace n with either n + 1 or n - 1. :type numsSize: int
# What is the minimum number of replacements needed for n to become 1? """
self.nums = nums
# 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 def pick(self, target):
# which is better than incrementing to make last 2 bits 10. """
# If (n-1)%4 != 0 then the last 2 bits of n are 11, decrementing will make the last 2 :type target: int
bits 10, incrementing will :rtype: int
# 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 count = 0
# bits. Incrementing is at least as good as decrementing. for i, num in enumerate(self.nums):
# 3 is the exception where n-1 is not divisible by 4 bit it is still better to decrement. if num == target:
if random.randint(0, count) == 0: # There are 9 digits of length 1, 2 * 90 of length 2, 3 * 900 of length 3 ... Find the
result = i length of the number containing
count += 1 # the nth digit by subtracting all shorter length digits. Then divide n - 1 by length to
return result get the number. Remainder is
# the required digit.
# Time - O(log n)
# python_1_to_1000/399_Evaluate_Division.py - m # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def findNthDigit(self, n):
"""
# https://leetcode.com/problems/evaluate-division/ :type n: int
# Equations are given in the format A / B = k, where A and B are variables represented as :rtype: int
strings, and k is a real """
# number (floating point number). Given some queries, return the answers. If the answer length = 1
does not exist, return -1.0. digits = 9

# Create a graph with nodes as variables and directed edge A->B weighted by the ratio while n > digits:
A/B. Floyd-Warshall calculates n -= digits
# weights of paths between all pairs of nodes by iteratively adding paths between 2 nodes digits = (length + 1) * 9 * (10 ** length)
(j and k) that can be reached length += 1
# from node i.
# Time - O(n**3) where n is number of variables start = 10 ** (length - 1) # first number of this length
# Space - O(n**2) num, digit = divmod(n - 1, length)
num += start
from collections import defaultdict
return int(str(num)[digit])
class Solution(object):
def calcEquation(self, equations, values, queries):
""" # python_1_to_1000/401_Binary_Watch.py
:type equations: List[List[str]]
:type values: List[float] _author_ = 'jake'
:type queries: List[List[str]] _project_ = 'leetcode'
:rtype: List[float]
""" # https://leetcode.com/problems/binary-watch/
graph = defaultdict(dict) # outer dict key is source node, value is # A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs
destination node on the bottom represent
for i in range(len(equations)): # innder dict key is destination node, value # the minutes (0-59). Each LED represents a zero or one, with the least significant bit
is ratio on the right.
num, den, val = equations[i][0], equations[i][1], values[i] # Given a non-negative integer n which represents the number of LEDs that are currently
graph[num][den] = val on, return all possible times
graph[den][num] = 1 / val # 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
for i in graph: be "1:00".
for j in graph[i]: # The minute must be consist of two digits and may contain a leading zero, for example
for k in graph[i]: "10:2" is not valid.
graph[j][k] = graph[j][i] * graph[i][k] # graph[j][j] = 1
# Enumerate the possible arrangements of setting num bits. Set bits one at a time,
results = [] initially the first bit can be in
for num, den in queries: # any position that allows enough space for the remaining bits. Then for each setting add
if num in graph and den in graph[num]: the next bit in all positions
results.append(graph[num][den]) # that allow space for the remaining bits.
else:
results.append(-1) # For each setting, convert the first 4 bits to the hour and the last 6 to minutes.
return results Reject if impossible. Format as
# time with zero padding for single-digit minutes.
# Time - O(n * 10! / n!(10 - n)!) 10 choose n possibilities, each of length n
# Space - O(n * 10! / n!(10 - n)!)

class Solution(object):
# python_1_to_1000/400_Nth_Digit.py - m def readBinaryWatch(self, num):
"""
_author_ = 'jake' :type num: int
_project_ = 'leetcode' :rtype: List[str]
"""
# https://leetcode.com/problems/nth-digit/ if num == 0:
# Find the nth digit of the infinite integer sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, return ["0:00"]
...
bits_set = [[i] for i in range(10)] # list if times, each time is a list

of which bits are set while k:


result.pop()
for max_bit in range(10 - num + 1, 10): # allow space for other bits to be k -= 1
set
return "".join(result).lstrip("0") or "0" # "0" if result is empty
new_bits_set = []

for time in bits_set: # python_1_to_1000/403_Frog_Jump.py - h


for bit in range(time[-1] + 1, max_bit + 1):
new_bits_set.append(time + [bit]) # set all possible next bits _author_ = 'jake'
_project_ = 'leetcode'
bits_set = new_bits_set
# https://leetcode.com/problems/frog-jump/
result = [] # 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.
for time in bits_set: # The frog can jump on a stone, but it must not jump into the water.
# Given a list of stones' positions (in units) in sorted ascending order, determine if
hours, mins = 0, 0 the frog is able to cross the
# river by landing on the last stone. Initially, the frog is on the first stone and
for bit in time: assume the first jump must be 1 unit.
if bit >= 6: # hours bits # If the frog's last jump was k units, then its next jump must be either k - 1, k, or k +
hours += 1 << (bit - 6) 1 units.
else: # minutes bits # Note that the frog can only jump in the forward direction.
mins += 1 << bit
# For each stone, create a set of previous jump distances that can reach that stone.
if hours < 12 and mins < 60: # valid time # For each jump size that can reach each stone, for each of the 3 jump sizes, if this
reaches another stone add it
mins = str(mins) # to the set of jumps that can reach that next stone.
if len(mins) == 1: # pad with leading zero # Time - O(n**2)
mins = "0" + mins # Space - O(n**2)
result.append(str(hours) + ":" + mins)
class Solution(object):
return result def canCross(self, stones):
"""
:type stones: List[int]
# python_1_to_1000/402_Remove_K_Digits.py - m :rtype: bool
"""
_author_ = 'jake' jumps = {} # key is stone position, value is set of jump sizes that can reach
_project_ = 'leetcode' that stone
for stone in stones:
# https://leetcode.com/problems/remove-k-digits/ jumps[stone] = set()
# Given a non-negative integer num represented as a string, remove k digits from the jumps[0].add(0)
number so that the new number
# is the smallest possible. for stone in stones:
for jump in jumps[stone]:
# Iterate over num. If previous digit > current digit then preferable to remove previous for shift in [-1, 0, 1]:
digit provided k is +ve. if jump + shift > 0 and stone + jump + shift in jumps:
# This creates result in non-descending order. Add all digits to result. jumps[stone + jump + shift].add(jump + shift)
# If any k remain, remove least significant digits. Remove leading zeros.
# Time - O(n) return bool(jumps[stones[-1]])
# Space - O(n)

class Solution(object): # python_1_to_1000/404_Sum_of_Left_Leaves.py


def removeKdigits(self, num, k):
""" _author_ = 'jake'
:type num: str _project_ = 'leetcode'
:type k: int
:rtype: str # https://leetcode.com/problems/sum-of-left-leaves/
""" # Find the sum of all left leaves in a given binary tree.
result = []
# If node has a left child with no children then return the left child val + recurse
for c in num: right. Else recurse left and right.
# Time - O(n)
while k and result and result[-1] > c: # Space - O(1)
result.pop()
k -= 1 class Solution(object):
def sumOfLeftLeaves(self, root):
result.append(c) """
:type root: TreeNode
:rtype: int # Group people by height. Sort heights descending from tallest. For each group of people
""" of the same height, sort
if not root: # from least to most in front and insert into queue. if_front is correct insertion
return 0 position because there are no
# shorter people already in queue.
if root.left and not root.left.left and not root.left.right: # Time - O(n**2), each person inserted into list.
return root.left.val + self.sumOfLeftLeaves(root.right) # Space - O(n)

return self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right) from collections import defaultdict

class Solution(object):
# python_1_to_1000/405_Convert_a_Number_to_Hexadecimal.py def reconstructQueue(self, people):
"""
_author_ = 'jake' :type people: List[List[int]]
_project_ = 'leetcode' :rtype: List[List[int]]
"""
# https://leetcode.com/problems/convert-a-number-to-hexadecimal/ queue = []
# Given an integer, write an algorithm to convert it to hexadecimal. For negative height_groups = defaultdict(list)
integer, two’s complement method
# is used. for height, in_front in people:
# All letters in hexadecimal (a-f) must be in lowercase. height_groups[height].append(in_front)
# The hexadecimal string must not contain extra leading 0s. If the number is zero, it is
represented by a single zero all_heights = list(height_groups.keys())
# character '0'; otherwise, the first character in the hexadecimal string will not be the all_heights.sort(reverse = True)
zero character.
# The given number is guaranteed to fit within the range of a 32-bit signed integer. for height in all_heights:
height_groups[height].sort()
# Repeatedly divide by 16, converting the remainder to a digit or letter (if > 9). for in_front in height_groups[height]:
Reverse the result so most queue.insert(in_front, [height, in_front])
# significant bit is first.
# Time - O(log n) return queue
# Space - O(log n)

class Solution(object): # python_1_to_1000/407_Trapping_Rain_Water_II.py - h


def toHex(self, num):
""" _author_ = 'jake'
:type num: int _project_ = 'leetcode'
:rtype: str
""" # https://leetcode.com/problems/trapping-rain-water-ii/
if num == 0: # special case, while loop is not entered # Given an m x n matrix of positive integers representing the height of each unit cell in
return "0" a 2D elevation map,
if num < 0: # 2s complement of negative numbers # compute the volume of water it is able to trap after raining.
num += 2 ** 32
# Simulate raising the water level from the outside of the map. Add to a heap all cells
result = [] on the outer perimeter.
# Pop the lowest cell and for each neighbour not previously visited, add water to the
while num != 0: height of the original cell
# and add neighbour to the heap.
num, digit = divmod(num, 16) # Time - O(mn log mn)
if digit > 9: # convert to char # Space - O(mn)
result.append(chr(ord("a") + digit - 10))
else: import heapq
result.append(str(digit))

return "".join(result[::-1]) # reverse class Solution(object):


def trapRainWater(self, heightMap):
"""
# python_1_to_1000/406_Queue_Reconstruction_by_Height.py - m :type heightMap: List[List[int]]
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode' if not heightMap or not heightMap[0]:
return 0
# https://leetcode.com/problems/queue-reconstruction-by-height/
# Suppose you have a random list of people standing in a queue. Each person is described rows, cols = len(heightMap), len(heightMap[0])
by a pair of integers (h, k), water = 0
# where h is the height of the person and k is the number of people in front of this q = []
person who have a
# height greater than or equal to h. Write an algorithm to reconstruct the queue. for r in range(rows):
heapq.heappush(q, (heightMap[r][0], r, 0))

heapq.heappush(q, (heightMap[r][cols - 1], r, cols - 1))


for c in range(1, cols - 1):
heapq.heappush(q, (heightMap[0][c], 0, c))
heapq.heappush(q, (heightMap[rows - 1][c], rows - 1, c)) # python_1_to_1000/409_Longest_Palindrome.py

visited = {(r, c) for _, r, c in q} _author_ = 'jake'


_project_ = 'leetcode'
while q:
# https://leetcode.com/problems/longest-palindrome/
h, r, c = heapq.heappop(q) # Given a string which consists of lowercase or uppercase letters, find the length of the
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]: longest palindromes that
r1, c1 = r + dr, c + dc # can be built with those letters. This is case sensitive, for example "Aa" is not
if (r1, c1) not in visited and r1 >= 0 and c1 >= 0 and r1 < rows and c1 < considered a palindrome here.
cols:
visited.add((r1, c1)) # Iterate over s maintaining a set of letters seen. If a letter is seen again, add 2 to
water += max(0, h - heightMap[r1][c1]) length of palindrome and
heapq.heappush(q, (max(h, heightMap[r1][c1]), r1, c1)) # 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
return water # there are any single letters after iteration.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/408_Valid_Word_Abbreviation.py
class Solution(object):
_author_ = 'jake' def longestPalindrome(self, s):
_project_ = 'leetcode' """
:type s: str
# https://leetcode.com/problems/valid-word-abbreviation/ :rtype: int
# Given a non-empty string s and an abbreviation abbr, return whether the string matches """
with the given abbreviation. max_length = 0
# Assume s contains only lowercase letters and abbr contains only lowercase letters and letters = set()
digits.
for c in s:
# Iterate over abbreviation. If char then check if matches words and increment both if c in letters:
pointer. If digit, parse the max_length += 2
# number and move forward the pointer in word. Return false if pointers do not reach the letters.remove(c)
end of word and abbr else:
# simultaneously. letters.add(c)
# Time - O(n) length of abbr
# Space - O(1) return max_length + bool(letters)

class Solution(object):
def validWordAbbreviation(self, word, abbr): # python_1_to_1000/410_Split_Array_Largest_Sum.py - h
"""
:type word: str _author_ = 'jake'
:type abbr: str _project_ = 'leetcode'
:rtype: bool
""" # https://leetcode.com/problems/split-array-largest-sum/
i, j = 0, 0 # Given an array which consists of non-negative integers and an integer m, you can split
the array into m non-empty
while j < len(abbr): # continuous subarrays. Write an algorithm to minimize the largest sum among these m
subarrays.
if abbr[j] < "a": # digit
# Binary search the range of possible smallest max subarray sums. If x is valid, search
if abbr[j] == "0": # cannot lead with zero or skip zero letters range x and below else search
return False # above x.
count = 0 # Binary search must make progress each iteration. Since mid can equal left then next
while j < len(abbr) and abbr[j] < "a": iteration brings right down to
count = count * 10 + int(abbr[j]) # mid instead of left up (which may result in no change). right = mid-1 and left=mid may
j += 1 not make progress.
i += count # Time - O(n log sum(n))
# Space - O(1)
else: # letter
if i >= len(word) or abbr[j] != word[i]: class Solution(object):
return False def splitArray(self, nums, m):
i += 1 """
j += 1 :type nums: List[int]
:type m: int
return i == len(word) # must use all of word :rtype: int
"""
left, right = max(nums), sum(nums) # search range else: # char in target can be abbreviated
count += 1
while left < right: # if left == right then return num >>= 1 # right shift, divide by 2
mid = (left + right) // 2
if self.can_split(nums, m, mid): # recurse on LHS (smaller max subarray if count:
sums) including mid word.append(str(count))
right = mid # mid < right so always make progress return "".join(word)
else:
left = mid + 1 m = len(target)
diffs = [] # representation of each word in terms of which chars are different
return left from target

def can_split(self, nums, m, max_subarray): # can nums be split into m subarrays for word in dictionary:
each sum <= max_subarray ? if len(word) != m:
continue
subarray_sum = 0 bits = 0
for num in nums: for i, char in enumerate(word):
if num + subarray_sum > max_subarray: # num makes sum too big if char != target[i]: # set bits when chars are different
m -= 1 # one less subarray bits += 2 ** i
if m <= 0: # at least num remain with no more subarrays to use diffs.append(bits)
return False
subarray_sum = num # num in next subarray if not diffs:
else: return str(m)
subarray_sum += num
min_abbr = target
return True 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
abbr_i = abbr(target, i)
# python_1_to_1000/411_Minimum_Unique_Word_Abbreviation.py - h if len(abbr_i) < len(min_abbr):
min_abbr = abbr_i
_author_ = 'jake'
_project_ = 'leetcode' return min_abbr

# https://leetcode.com/problems/minimum-unique-word-abbreviation/
# A string such as "word" contains the following abbreviations: # python_1_to_1000/412_Fizz_Buzz.py
# ["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1",
"1o2", "2r1", "3d", "w3", "4"] _author_ = 'jake'
# Given a target string and a set of strings in a dictionary, find an abbreviation of _project_ = 'leetcode'
this target string with the
# smallest possible length such that it does not conflict with abbreviations of the # https://leetcode.com/problems/fizz-buzz/
strings in the dictionary. # Write a program that outputs the string representation of numbers from 1 to n.
# Each number or letter in the abbreviation is considered length = 1. For example, the # But for multiples of three it should output “Fizz” instead of the number and for the
abbreviation "a32bc" has length = 4. multiples of five output “Buzz”.
# In the case of multiple answers, you may return any one of them. # For numbers which are multiples of both three and five output “FizzBuzz”.

# Encode each word in dictionary with same length as target, setting bits where word char # Test if divisible by 15 or 5 or 3 or none of these.
!= target char. # Time - O(n)
# For each possible pattern of chars in target to to retain, check if target differs from # Space - O(n)
each word by at least one
# char. If so convert bitwise encoded trget to string and compare with shortest. class Solution(object):
# Time - O(n * k * 2**n) where len(target) = n and len(dictionary) = k def fizzBuzz(self, n):
# Space - O(kn) """
:type n: int
class Solution(object): :rtype: List[str]
""" """
:type target: str result = []
:type dictionary: List[str]
:rtype: str for i in range(1, n + 1):
""" if i % 15 == 0:
def minAbbreviation(self, target, dictionary): result.append("FizzBuzz")
def abbr(target, num): elif i % 3 == 0:
word, count = [], 0 # count of char sequence that can be abbreviated result.append("Fizz")
for w in target: elif i % 5 == 0:
if num & 1 == 1: # char in target must remain result.append("Buzz")
if count: else:
word += str(count) result.append(str(i))
count = 0
word.append(w) return result

"""
maxima = [float("-inf")] * 3 # maxima[0] is largest unique number seen,
maxima[1] is second
# python_1_to_1000/413_Arithmetic_Slices.py - m
for num in nums:
_author_ = 'jake'
_project_ = 'leetcode' if num in maxima:
continue
# https://leetcode.com/problems/arithmetic-slices/
# A sequence of number is called arithmetic if it consists of at least three elements and if num > maxima[0]:
if the difference between maxima = [num] + maxima[:2]
# any two consecutive elements is the same. elif num > maxima[1]:
# Return the number of arithmetic slices in the array. maxima[1:] = [num, maxima[1]]
elif num > maxima[2]:
# If the current diff is the same as the previous, add to result all slices ending here. maxima[2] = num
Else reset progression start.
# Time - O(n) return maxima[2] if maxima[2] != float("-inf") else maxima[0]
# Space - O(1)

class Solution(object):
def numberOfArithmeticSlices(self, A): # python_1_to_1000/415_Add_Strings.py
"""
:type A: List[int] _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
n = len(A) # https://leetcode.com/problems/add-strings/
if n < 3: # Given two non-negative integers num1 and num2 represented as string, return the sum of
return 0 num1 and num2.

diff = A[1] - A[0] # Reverse the numbers so we start iterating over the least significant digit. Pad the
start, slices = 0, 0 # start of current progression shorter number with leading zeros.
# Add each pair of digits plus carry, mod 10 to update the carry. Append the final carry
for i in range(2, n): then reverse the result.
# Time - O(max(m, n)) where m and n are the lengths of the input strings
next_diff = A[i] - A[i - 1] # Space - O(max(m, n))

if next_diff == diff: class Solution(object):


slices += i - start - 1 def addStrings(self, num1, num2):
else: """
diff = next_diff :type num1: str
start = i - 1 :type num2: str
:rtype: str
return slices """
num1, num2 = num1[::-1], num2[::-1]

# python_1_to_1000/414_Third_Maximum_Number.py length_diff = len(num1) - len(num2)


if length_diff < 0:
_author_ = 'jake' num1 += "0" * -length_diff
_project_ = 'leetcode' else:
num2 += "0" * length_diff
# https://leetcode.com/problems/third-maximum-number/
# Given a non-empty array of integers, return the third maximum number in this array. If result, carry = [], 0
it does not exist, return for d1, d2 in zip(num1, num2):
# the maximum number. The time complexity must be in O(n). carry, digit = divmod(int(d1) + int(d2) + carry, 10)
result.append(str(digit))
# Iterate over nums. If a number is already one of the top 3 largest unique numbers then
ignore it. If larger than if carry:
# the largest, update largest and demote the first and second largest to second and result.append(str(carry))
third. Else if more than the
# second largest, replace second largest and demote previous second to third. Else if return "".join(result[::-1])
more than third, replace third.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/416_Partition_Equal_Subset_Sum.py - m
class Solution(object):
def thirdMax(self, nums): _author_ = 'jake'
""" _project_ = 'leetcode'
:type nums: List[int]
:rtype: int # https://leetcode.com/problems/partition-equal-subset-sum/
# Given a non-empty array containing only positive integers, find if the array can be
partitioned into two subsets _author_ = 'jake'
# such that the sum of elements in both subsets is equal. _project_ = 'leetcode'

# Dynamic programming. Maintain array of which sums can be reached. Initially only zero. # https://leetcode.com/problems/pacific-atlantic-water-flow/
For each num starting with # Given an m x n matrix of non-negative integers representing the height of each unit
# largest, add this to all xisting sums starting with largest existing. cell in a continent,
# Alternatively, recursively use each remaining unique num and subtract from remaining # the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic
target. ocean" touches the right and
# Time - O(n * sum(nums)) # bottom edges. Water can only flow in four directions (up, down, left, or right) from a
# Space - O(sum(nums)) cell to another one with
# height equal or lower. Find the list of grid coordinates where water can flow to both
class Solution(object): the Pacific and Atlantic ocean.
def canPartition(self, nums):
""" # Maintain a frontier of all cells that flow to each ocean, initially edges of matrix.
:type nums: List[int] Expand the frontier by adding
:rtype: bool # all higher neighbours.
""" # Time - O(mn)
sum_nums = sum(nums) # Space - O(mn)
if sum_nums % 2 == 1:
return False class Solution(object):
def pacificAtlantic(self, matrix):
nums.sort(reverse = True) # try largest nums first """
target = sum_nums // 2 :type matrix: List[List[int]]
:rtype: List[List[int]]
subset_sum = [True] + [False] * target """
if not matrix or not matrix[0]:
for num in nums: return []
for i in range(target - 1, -1, -1): # backwards so cannot use same num
repeatedly rows, cols = len(matrix), len(matrix[0])
if subset_sum[i] and i + num <= target: atlantic, pacific = set(), set() # cells that flow to each ocean
if i + num == target: # early return, solution found
return True for r in range(rows):
subset_sum[i + num] = True # mark this value atlantic.add((r, cols - 1))
pacific.add((r, 0))
return False for c in range(cols):
atlantic.add((rows - 1, c))
pacific.add((0, c))
from collections import Counter
for ocean in [atlantic, pacific]:
class Solution2(object):
def canPartition(self, nums): frontier = set(ocean)
nums_sum = sum(nums) while frontier:
if nums_sum % 2 == 1: new_frontier = set()
return False for r, c in frontier:
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
freq = Counter(nums) r1, c1 = r + dr, c + dc # neighbouring cell
return self.partition(freq, nums_sum // 2) if r1 < 0 or r1 >= rows or c1 < 0 or c1 >= cols or (r1, c1) in
ocean:
def partition(self, freq, target): continue # ignore already found or outside
if target == 0: matrix
return True if matrix[r1][c1] >= matrix[r][c]: # nbor flows to ocean
if target < 0: new_frontier.add((r1, c1))
return False frontier = new_frontier # update frontier
ocean |= new_frontier # add newly discovered to ocean
for num in freq:
if freq[num] == 0: return list(atlantic & pacific) # set intersection
continue
freq[num] -= 1 # remove from frequency count
if self.partition(freq, target - num):
return True # python_1_to_1000/418_Sentence_Screen_Fitting.py - m
freq[num] += 1 # add back to frequency count
_author_ = 'jake'
return False _project_ = 'leetcode'

# https://leetcode.com/problems/sentence-screen-fitting/
# Given a rows x cols screen and a sentence represented by a list of non-empty words,
find how many times the given
# python_1_to_1000/417_Pacific_Atlantic_Water_Flow.py - m # sentence can be fitted on the screen.

# A word cannot be split into two lines.


# Two consecutive words in a line must be separated by a single space. # Sweep from top to bottom, left to right. New ship found if cell contains X and no X to
left or above.
# Preprocess to find the number of complete sentences and the index of next starting # Time - O(mn)
word, for a row starting # Space - O(1)
# with each word. Fill row with complete sentences, then fill word by word. For each row
find number of class Solution(object):
# sentences and next starting word. def countBattleships(self, board):
# Time - O(nc + r) where n is number of words, c is cols, r is rows. """
# Space - O(n) :type board: List[List[str]]
:rtype: int
class Solution(object): """
def wordsTyping(self, sentence, rows, cols): if not board or not board[0]:
""" return 0
:type sentence: List[str]
:type rows: int rows, cols = len(board), len(board[0])
:type cols: int ships = 0
:rtype: int
""" for r in range(rows):
sentence_len = sum(len(w) for w in sentence) + len(sentence) for c in range(cols):

# line_fits[i] = (number of complete sentences, index of next starting word) for if board[r][c] == ".":
a row starting with sentences[i] continue
line_fits = [] if r != 0 and board[r - 1][c] == "X":
continue
for start_word_index in range(len(sentence)): if c != 0 and board[r][c - 1] == "X":
continue
row_length, sentences = 0, 0 ships += 1
word_index = start_word_index
return ships
while row_length + sentence_len <= cols: # can fit next sentence in row
row_length += sentence_len
sentences += 1 # python_1_to_1000/420_Strong_Password_Checker.py - h

while row_length + len(sentence[word_index]) <= cols: # can fit next word in _author_ = 'jake'
row _project_ = 'leetcode'
row_length += len(sentence[word_index]) + 1 # extend row_length by word
and space # https://leetcode.com/problems/strong-password-checker/
word_index += 1 # move to next word # A password is considered strong if below conditions are all met:
if word_index == len(sentence): # fitted last word of sentence # It has at least 6 characters and at most 20 characters.
sentences += 1 # It must contain at least one lowercase letter, at least one uppercase letter, and at
word_index = 0 least one digit.
# It must NOT contain three repeating characters in a row.
line_fits.append((sentences, word_index)) # Write a function that takes a string s as input, and return the MINIMUM change required
to make s a strong password.
fits, word_index = 0, 0 # If s is already strong, return 0.
for r in range(rows): # Insertion, deletion or replace of any one character are all considered as one change.
sentences, next_word_index = line_fits[word_index]
fits += sentences # For difficult case of length > 20. Use required deletions to reduce the number of
word_index = next_word_index substitutions required.
# Time - O(n)
return fits # Space - O(1)

class Solution(object):
# python_1_to_1000/419_Battleships_in_a_Board.py - m def strongPasswordChecker(self, s):
"""
_author_ = 'jake' :type s: str
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/battleships-in-a-board/ upper, lower, digit = False, False, False
# Given an 2D board, count how many battleships are in it. The battleships are subs, i = 0, 0 # nb subs to remove sequences, index counter
represented with 'X's, empty slots are singles, doubles = 0, 0 # nb single and double deletions
# represented with '.'s. You may assume the following rules:
# You receive a valid board, made of only battleships or empty slots. while i < len(s):
# Battleships can only be placed horizontally or vertically. In other words, they can
only be made of the shape 1xN if s[i].isdigit():
# (1 row, N columns) or Nx1 (N rows, 1 column), where N can be of any size. digit = True
# At least one horizontal or vertical cell separates between two battleships - there are if s[i].isupper():
no adjacent battleships. upper = True
if s[i].islower():
lower = True return max_xor

if i >= 2 and s[i] == s[i - 1] == s[i - 2]: # sequence of 3


seq = 2
while i < len(s) and s[i] == s[i - 1]: # find length of sequence
seq += 1 # python_1_to_1000/422_Valid_Word_Square.py
i += 1
_author_ = 'jake'
subs += seq // 3 _project_ = 'leetcode'
if seq % 3 == 0:
singles += 1 # https://leetcode.com/problems/valid-word-square/
if seq % 3 == 1: # Given a sequence of words, check whether it forms a valid word square.
doubles += 1 # A sequence of words forms a valid word square if the kth row and column read the exact
same string,
else: # where 0 ≤ k < max(numRows, numColumns).
i += 1
# Make a square of same length sides by padding words with spaces. If any word is longer
types_missing = 3 - (digit + upper + lower) than the first word then
# it is longer than the corresponding column so not a valid square. Check each row
if len(s) < 6: against each column.
return max(types_missing, 6 - len(s)) # Time - O(n**2)
if len(s) <= 20: # Space - O(n**2)
return max(types_missing, subs)
class Solution(object):
deletions = len(s) - 20 def validWordSquare(self, words):
"""
subs -= min(deletions, singles) :type words: List[str]
subs -= min(max(deletions - singles, 0), doubles * 2) / 2 :rtype: bool
subs -= max(deletions - singles - 2 * doubles, 0) / 3 """
if len(words) != len(words[0]): # ensure the sides of the square have the
return deletions + max(types_missing, subs) same length
return False

n = len(words[0])
# python_1_to_1000/421_Maximum_XOR_of_Two_Numbers_in_an_Array.py - m
for i, word in enumerate(words[1:], 1):
_author_ = 'jake' m = len(word)
_project_ = 'leetcode' if m > n: # no other word can be longer than first word
return False
# https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/ words[i] += (n - m) * " " # pad words with spaces to make complete
# Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 2**31. square
# Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.
for i in range(n):
# Starting from prefix of 1st bit, create a set of all prefixes. For each prefix, check for j in range(n):
the set for another prefix if words[i][j] != words[j][i]:
# that when xored together extend the max_xor by a bit. return False
# Time - O(n)
# Space - O(n) return True

class Solution(object):
def findMaximumXOR(self, nums): # python_1_to_1000/423_Reconstruct_Original_Digits_from_English.py - m
"""
:type nums: List[int] _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
mask = 0 # used to isolate the prefix bits of each num # https://leetcode.com/problems/reconstruct-original-digits-from-english/
max_xor = 0 # current best result # Given a non-empty string containing an out-of-order English representation of digits 0-
9, output the digits in
for bit in range(31, -1, -1): # most significant bit first # ascending order.
# Input contains only lowercase English letters.
mask |= (1 << bit) # update mask with latest bit set # Input is guaranteed to be valid and can be transformed to its original digits.
prefixes = {mask & num for num in nums}
target = max_xor | (1 << bit) # xor of 2 prefixes with bit set # Count the occurrences of letters that uniquely identify thier words (0, 2, 4, 6, 8).
For other digits, count the
for prefix in prefixes: # if p ^ t = q then p ^ t ^ p = t = q ^ p # occurences of a letter and subtract letters from digits already counted.
if prefix ^ target in prefixes: # Time - O(n)
max_xor = target # Space - O(1)
break

from collections import Counter

class Solution(object):
def originalDigits(self, s): # python_1_to_1000/425_Word_Squares.py - h
"""
:type s: str _author_ = 'jake'
:rtype: str _project_ = 'leetcode'
"""
digit_freq = [0] * 10 # https://leetcode.com/problems/word-squares/
letter_freq = Counter(s) # Given a set of words (without duplicates), find all word squares you can build from
#(letter to be counted, words already counted with this letter, digit) them.
words = [("z", [], 0), ("w", [], 2), ("u", [], 4), ("x", [], 6), ("g", [], 8), # A sequence of words forms a valid word square if the kth row and column read the exact
("o", [0, 2, 4], 1), ("r", [0, 4], 3), ("f", [4], 5), ("v", [5], 7), same string.
("i", [5, 6, 8], 9)] # All words will have the exact same length.

for letter, other_digits, digit in words: # Build a mapping of each prefix to all words that have that prefix. For each starting
word_count = letter_freq[letter] word, find all words with
for other_digit in other_digits: # appropriate prefixes to build next row of square.
word_count -= digit_freq[other_digit] # Time - O((nk)**k) where k = len(word). For each of n words, calculate prefix of max
digit_freq[digit] = word_count length k, then recurse n times.
# Space - O(nk)
result = []
for digit, count in enumerate(digit_freq): from collections import defaultdict
result += [str(digit)] * count
return "".join(result) class Solution(object):
def wordSquares(self, words):
"""
:type words: List[str]
:rtype: List[List[str]]
# python_1_to_1000/424_Longest_Repeating_Character_Replacement.py - m """
prefixes = defaultdict(list)
_author_ = 'jake' for word in words:
_project_ = 'leetcode' for i in range(1, len(word)): # create all non-empty prefixes
(excluding full word)
# https://leetcode.com/problems/longest-repeating-character-replacement/ prefixes[word[:i]].append(word)
# Given a string that consists of only uppercase English letters, you can replace any
letter in the string with another squares = []
# letter at most k times. Find the length of a longest substring containing all repeating for word in words:
letters you can get after self.build_square([word], prefixes, squares) # try all words in first row
# performing the above operations. return squares

# Maintain a sliding window, moving end forwards every iteration. Move start forwards so
that there are at most k chars def build_square(self, partial, prefixes, squares):
# in the window that are not the most frequent.
# Time - O(n) if len(partial) == len(partial[0]): # complete square
# Space - O(1) squares.append(list(partial)) # copy partial
return
from collections import defaultdict
prefix = []
class Solution(object): col = len(partial)
def characterReplacement(self, s, k): for row in range(len(partial)):
""" prefix.append(partial[row][col])
:type s: str next_words = prefixes["".join(prefix)]
:type k: int
:rtype: int for next_word in next_words:
""" partial.append(next_word)
longest, start = 0, 0 self.build_square(partial, prefixes, squares)
freq = defaultdict(int) partial.pop() # remove next_word

for end in range(len(s)):


freq[s[end]] += 1
# while more than k chars in window that are not the most frequent # python_1_to_1000/426_Convert_Binary_Search_Tree_to_Sorted_Doubly_Linked_List.py - m
while (end - start + 1) - max(freq.values()) > k:
freq[s[start]] -= 1 _author_ = 'jake'
start += 1 _project_ = 'leetcode'

longest = max(longest, end - start + 1) # https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/


# Convert a BST to a sorted circular doubly-linked list in-place.
return longest # Think of the left and right pointers as synonymous to the previous and next pointers in
a doubly-linked list. class Solution(object):
# Each node in a doubly linked list has a predecessor and successor. def construct(self, grid):
# For a circular doubly linked list, the predecessor of the first element is the last """
element, :type grid: List[List[int]]
# and the successor of the last element is the first element. :rtype: Node
"""
# Recursively convert left and right subtrees to circular linked lists. Link tail of left def helper(r, c, side): # construct quad tree for grid from cell (r, c) with
subtree to root and head of side length of side
# right subtree to root. Complete the circle by linking head and tail.
# Time - O(n) if side == 1: # base case of single cell
# Space - O(n) return Node(bool(grid[r][c]), True, None, None, None, None)

class Solution(object): top_left = helper(r, c, side // 2)


def treeToDoublyList(self, root): top_right = helper(r, c + side // 2, side // 2)
""" bottom_left = helper(r + side // 2, c, side // 2)
:type root: Node bottom_right = helper(r + side // 2, c + side // 2, side // 2)
:rtype: Node
""" if top_left.isLeaf and top_right.isLeaf and bottom_left.isLeaf and
if not root: bottom_right.isLeaf:
return None if top_left.val == top_right.val == bottom_left.val == bottom_right.val:
return Node(top_left.val, True, None, None, None, None)
left_head = self.treeToDoublyList(root.left)
right_head = self.treeToDoublyList(root.right) node_val = any((top_left.val, top_right.val, bottom_left.val,
bottom_right.val))
if left_head: return Node(node_val, False, top_left, top_right, bottom_left, bottom_right)
root.left = left_head.left # link root to tail of left subtree
left_head.left.right = root if not grid:
else: return None
left_head = root # no subtree on left, root is left_head return helper(0, 0, len(grid))

if right_head:
root.right = right_head # link root to head of right_subtree # python_1_to_1000/428_Serialize_and_Deserialize_N-ary_Tree.py - h
right_tail = right_head.left # store right_tail
right_head.left = root _author_ = 'jake'
else: _project_ = 'leetcode'
right_tail = root # no subtree on right, root is right_tail
# https://leetcode.com/problems/serialize-and-deserialize-n-ary-tree/
left_head.left = right_tail # link head and tail # Serialization is the process of converting a data structure or object into a sequence
right_tail.right = left_head of bits so that it can be
# stored in a file or memory buffer, or transmitted across a network connection link to
return left_head be reconstructed later in the
# same or another computer environment.
# Design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a
# python_1_to_1000/427_Construct_Quad_Tree.py - m rooted tree in which each node
# has no more than N children. There is no restriction on how your
_author_ = 'jake' serialization/deserialization algorithm should work.
_project_ = 'leetcode' # Ensure that an N-ary tree can be serialized to a string and this string can be
deserialized to the tree structure.
# 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 # Serialize with preorder traversal where sentinel "#" indicates the final child of a
only be true or false. node has been processed, so the
# The root node represents the whole grid. For each node, it will be subdivided into four # function returns to its parent call.
children nodes until the # Deserialize by creating a deque (could also use an iterator with next() instead of
# values in the region it represents are all the same. popleft()). While the next item is
# Each node has another two boolean attributes : isLeaf and val. isLeaf is true if and # not "#", create a child with the item, add the child to the list of children and
only if the node is a leaf node. recurse to create its subtree.
# The val attribute for a leaf node contains the value of the region it represents. # Repeat until there are no more children, then ignore the "#".
# Your task is to use a quad tree to represent a given grid. # Time - O(n)
# For the non-leaf nodes, val is True if any of the child node vals are True. # Space - O(n)
# N is less than 1000 and guaranteed to be a power of 2.
from collections import deque
# Bottom-up recursion. Base case of a single cell. For any grid, recurse for each of the
4 quadrants. If all are class Codec:
# leaves with the same value, the root representing the grid is also a leaf. Else the
root is a node with children of def serialize(self, root):
# the 4 quadrant nodes. """Encodes a tree to a single string.
# Time - O(n**2) :type root: Node
# Space - O(n**2) :rtype: str
"""

serial = [] result = []
level = [root] # list of nodes in current level
def preorder(node):
while level:
if not node:
return new_level = []
for node in level:
serial.append(str(node.val)) new_level += node.children
result.append([node.val for node in level])
for child in node.children: level = new_level
preorder(child)
return result
serial.append("#") # indicates no more children, continue serialization
from parent

preorder(root) # python_1_to_1000/430_Flatten_a_Multilevel_Doubly_Linked_List.py - m
return " ".join(serial)
_author_ = 'jake'
def deserialize(self, data): _project_ = 'leetcode'
"""Decodes your encoded data to tree.
:type data: str # https://leetcode.com/problems/flatten-a-multilevel-doubly-linked-list/
:rtype: Node # You are given a doubly linked list which in addition to the next and previous pointers,
""" # it could have a child pointer, which may or may not point to a separate doubly linked
if not data: list.
return None # These child lists may have one or more children of their own, and so on, to produce a
multilevel data structure.
tokens = deque(data.split()) # Flatten the list so that all the nodes appear in a single-level, doubly linked list.
root = Node(int(tokens.popleft()), []) # You are given the head of the first level of the list.

def helper(node): # Iterate along the main list, inserting child lists. Ensure links are in both directions
and remove links to
if not tokens: # children when flattened.
return # Time - O(n)
# Space - O(n)
while tokens[0] != "#": # add child nodes with subtrees
value = tokens.popleft() class Solution(object):
child = Node(int(value), []) def flatten(self, head):
node.children.append(child) """
helper(child) :type head: Node
:rtype: Node
tokens.popleft() # discard the "#" """
node = head # save the head to be returned
helper(root)
return root while node: # iterate over the list

if node.child:
# python_1_to_1000/429_N-ary_Tree_Level_Order_Traversal.py - m
old_next = node.next # save the next so we can link the tail of the
_author_ = 'jake' flattened child list
_project_ = 'leetcode' node.next = self.flatten(node.child) # insert the flattened child list
node.next.prev = node # link child list back to node
# https://leetcode.com/problems/n-ary-tree-level-order-traversal/ node.child = None # remove the child since it is now flattened
# Given an n-ary tree, return the level order traversal of its nodes' values. (ie, from
left to right, level by level). while node.next:
node = node.next # find tail of child list
# Breadth-first search. For each level, add all child nodes to new_level and append list node.next = old_next # link tail to old_next
of node vals to result. if old_next: # link in other direction
# Time - O(n) old_next.prev = node
# Space - O(n)
node = node.next # move to the next node
class Solution(object):
def levelOrder(self, root): return head
"""
:type root: Node
:rtype: List[List[int]] # python_1_to_1000/431_Encode_N-ary_Tree_to_Binary_Tree.py - h
"""
if not root: _author_ = 'jake'
return [] _project_ = 'leetcode'
# https://leetcode.com/problems/encode-n-ary-tree-to-binary-tree/ guaranteed to be non-empty string.
# Design an algorithm to encode an N-ary tree into a binary tree and decode the binary # Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements
tree to get the original an existing key by 1. If the
# N-ary tree. An N-ary tree is a rooted tree in which each node has no more than N # key does not exist, this function does nothing. Key is guaranteed to be a non-empty
children. string.
# Similarly, a binary tree is a rooted tree in which each node has no more than 2 # GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return
children. an empty string "".
# There is no restriction on how your encode/decode algorithm should work. You just need # GetMinKey() - Returns one of the keys with minimal value. If no element exists, return
to ensure that an N-ary tree an empty string "".
# can be encoded to a binary tree and this binary tree can be decoded to the original N-
nary tree structure. # Create doubly linked list of blocks. Each block contains all the keys for a given
value. Blocks are in value order.
# The left child of a binary node is the subtree encoding all the children of the # Also maintain a mapping from key to its block.
corresponding n-ary node. # Time - O(1), all operations
# The right child of a binary node is a chain of the binary root nodes encoding each # Space - O(n)
sibling of the n-ary node.
# Hence the root node has no right binary child, because the root has no sibilings. class Block(object):
# Time - O(n) def __init__(self, val=0):
# Space - O(n) self.val = val
self.keys = set()
class Codec: self.before = None
self.after = None
def encode(self, root):
"""Encodes an n-ary tree to a binary tree. def remove(self):
:type root: Node self.before.after = self.after
:rtype: TreeNode self.after.before = self.before
""" self.before, self.after = None, None
if not root:
return None def insert_after(self, new_block):
old_after = self.after
binary = TreeNode(root.val) # create a binary root self.after = new_block
if not root.children: new_block.before = self
return binary new_block.after = old_after
old_after.before = new_block
binary.left = self.encode(root.children[0]) # left child of binary is the
encoding of all n-ary children,
node = binary.left # starting with the first child. class AllOne(object):
for child in root.children[1:]: # other children of n-ary root are def __init__(self):
right child of previous child """
node.right = self.encode(child) Initialize your data structure here.
node = node.right """
self.begin = Block() # sentinel
return binary self.end = Block() # sentinel
self.begin.after = self.end
def decode(self, data): self.end.before = self.begin
"""Decodes your binary tree to an n-ary tree. self.mapping = {} # key to block
:type data: TreeNode
:rtype: Node def inc(self, key):
""" """
if not data: Inserts a new key <Key> with value 1. Or increments an existing key by 1.
return None :type key: str
:rtype: void
nary = Node(data.val, []) # create n-ary root """
node = data.left # move to first child of n-ary root if not key in self.mapping: # find current block and remove key
while node: # while more children of n-ary root current_block = self.begin
nary.children.append(self.decode(node)) # append to list else:
node = node.right # and move to next child current_block = self.mapping[key]
current_block.keys.remove(key)
return nary
if current_block.val + 1 != current_block.after.val: # insert new block
new_block = Block(current_block.val + 1)
# python_1_to_1000/432_All_Oone_Data_Structure.py - h current_block.insert_after(new_block)
else:
_author_ = 'jake' new_block = current_block.after
_project_ = 'leetcode'
new_block.keys.add(key) # update new_block
# https://leetcode.com/problems/all-oone-data-structure/ self.mapping[key] = new_block # ... and mapping of key to new_block
# 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 if not current_block.keys and current_block.val != 0: # delete current block if

not seninel # it a valid gene string.


current_block.remove() # Given start, end, bank, your task is to determine what is the minimum number of
mutations needed to mutate from
def dec(self, key): # "start" to "end". If there is no such a mutation, return -1.
""" # Starting point is assumed to be valid, so it might not be included in the bank.
Decrements an existing key by 1. If Key's value is 1, remove it from the data # You may assume start and end string is not the same.
structure.
:type key: str # NOTE THAT THIS PROBLEM IS IN DRAFT STATUS IN LEETCODE
:rtype: void # BFS. For each gene in frontier, try all possible mutations. If mutation is in bank then
""" remove, hence no need to
if not key in self.mapping: # check for loops.
return # Time - O(n) where n is size of bank
# Space - O(n)
current_block = self.mapping[key]
del self.mapping[key] # could use self.mapping.pop(key) class Solution(object):
current_block.keys.remove(key) def minMutation(self, start, end, bank):
"""
if current_block.val != 1: :type start: str
if current_block.val - 1 != current_block.before.val: # insert new block :type end: str
new_block = Block(current_block.val - 1) :type bank: List[str]
current_block.before.insert_after(new_block) :rtype: int
else: """
new_block = current_block.before chars = set("ACGT")
new_block.keys.add(key) bank = set(bank) # convert to a set
self.mapping[key] = new_block if end not in bank: # early return
return -1
if not current_block.keys: # delete current block distance = 0
current_block.remove()
frontier = [start]
def getMaxKey(self): while frontier:
"""
Returns one of the keys with maximal value. new_frontier = []
:rtype: str distance += 1
"""
if self.end.before.val == 0: for gene in frontier:
return ""
key = self.end.before.keys.pop() # pop and add back to get arbitrary (but not for i in range(len(gene)):
random) element for c in chars:
self.end.before.keys.add(key)
return key if c == gene[i]:
continue
def getMinKey(self):
""" mutation = list(gene) # convert to list, mutate and
Returns one of the keys with Minimal value. back to string
:rtype: str mutation[i] = c
""" mutation = "".join(mutation)
if self.begin.after.val == 0:
return "" if mutation == end: # ok since have returned early if
key = self.begin.after.keys.pop() end not in bank
self.begin.after.keys.add(key) return distance
return key if mutation in bank:
bank.discard(mutation) # will not be shorter if same
mutation is revisited
new_frontier.append(mutation)

frontier = new_frontier
# python_1_to_1000/433_Minimum_Genetic_Mutation.py - m
return -1
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/434_Number_of_Segments_in_a_String.py
# https://leetcode.com/problems/minimum-genetic-mutation/
# A gene string can be represented by an 8-character long string, with choices from "A", _author_ = 'jake'
"C", "G", "T". _project_ = 'leetcode'
# Suppose we need to investigate about a mutation (mutation from "start" to "end"), where
ONE mutation is defined as # https://leetcode.com/problems/number-of-segments-in-a-string/
# ONE single character changed in the gene string. # Count the number of segments in a string, where a segment is defined to be a contiguous
# Also, there is a given gene "bank", which records all the valid gene mutations. A gene sequence of
must be in the bank to make # non-space characters.
_project_ = 'leetcode'
# Split by spaces.
# Time - O(n) # https://leetcode.com/problems/find-right-interval/
# Space - O(1) # Given a set of intervals, for each of the interval i, check if there exists an interval
j whose start point is
class Solution(object): # bigger than or equal to the end point of the interval i, which can be called that j is
def countSegments(self, s): on the "right" of i.
""" # For any interval i, you need to store the minimum interval j's index, which means that
:type s: str the interval j has the
:rtype: int # minimum start point to build the "right" relationship for interval i. If the interval j
""" doesn't exist, store -1 for
return len(s.split()) # the interval i. Finally, you need output the stored value of each interval as an array.

# Sort tuples of intervals and original indices. For each interval, binary search for
start point that is not less than
# python_1_to_1000/435_Non-overlppaping_Intervals.py - m # end point.
# Time - O(n log n)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
# Definition for an interval.
# https://leetcode.com/problems/non-overlapping-intervals/ class Interval(object):
# Given a collection of intervals, find the minimum number of intervals you need to def __init__(self, s=0, e=0):
remove to make the rest of the self.start = s
# intervals non-overlapping. self.end = e
# 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 class Solution(object):
other. def findRightInterval(self, intervals):
"""
# Sort by increasing start point. If the next interval starts before the current end, set :type intervals: List[Interval]
current end to be lesser of :rtype: List[int]
# current and next ends. Else set current end to be next end if no overlap. """
# Time - O(n log n) intervals = [[intervals[i], i] for i in range(len(intervals))]
# Space - O(1) intervals.sort(key=lambda x: x[0].start)

# Definition for an interval. result = [-1] * len(intervals) # default to no right interval


class Interval(object):
def __init__(self, s=0, e=0): for interval, i in intervals:
self.start = s
self.end = e left, right = 0, len(intervals) # right = len(intervals) indicates no right
interval

class Solution(object): while left < right:


def eraseOverlapIntervals(self, intervals):
""" mid = (left + right) // 2
:type intervals: List[Interval] if intervals[mid][0].start < interval.end:
:rtype: int left = mid + 1
""" else:
erase = 0 right = mid
if not intervals:
return 0 if left == len(intervals):
continue
intervals.sort(key=lambda x: x.start) # sort by increasing start result[i] = intervals[left][1]
current_end = intervals[0].start # does not overlap with first interval
return result
for interval in intervals:
if current_end > interval.start: # overlap
erase += 1
if interval.end > current_end: # retain current since end is less so # python_1_to_1000/437_Path_Sum_III.py - m
fewer future overlaps
continue _author_ = 'jake'
current_end = interval.end # update current if no overlap or best _project_ = 'leetcode'
choice
# https://leetcode.com/problems/path-sum-iii/
return erase # 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
# python_1_to_1000/436_Find_Right_Interval.py - m (traveling only from parent
# nodes to child nodes).
_author_ = 'jake'

# Maintain dictionary counting the paths from root to current node. Visit each node and freq = defaultdict(int) # map from char to net count of char in sliding
count the paths ending at that window
# node with target sum. Increment the count of the path to the node in the dictionary and result = []
recurse left and right.
# Decremetn count after recursion. if n > len(s): # no anagrams are possible
# Time - O(n) return result
# Space - O(n)
def update_freq(c, step): # updates dictionary and deletes zero values
from collections import defaultdict freq[c] += step
if freq[c] == 0:
class Solution(object): del freq[c]
def pathSum(self, root, sum):
""" for c1, c2 in zip(p, s[:n]): # populate initial window
:type root: TreeNode update_freq(c1, -1)
:type sum: int update_freq(c2, 1)
:rtype: int
""" for i in range(len(s) - n):
paths = defaultdict(int) # key is sum of path from root, value is the count of if not freq:
such paths result.append(i)
paths[0] = 1 # one path has zero sum update_freq(s[i], -1) # remove char at back of window
update_freq(s[i + n], 1) # add char at front of window
def helper(node, partial):
if not freq:
if not node: result.append(len(s) - n)
return 0 return result

partial += node.val
count = paths[partial - sum] # paths ending at node
# python_1_to_1000/439_Ternary_Expression_Parser.py - m
paths[partial] += 1
count += helper(node.left, partial) _author_ = 'jake'
count += helper(node.right, partial) _project_ = 'leetcode'
paths[partial] -= 1
# https://leetcode.com/problems/ternary-expression-parser/
return count # Given a string representing arbitrarily nested ternary expressions, calculate the
result of the expression. You can
return helper(root, 0) # 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.
# python_1_to_1000/438_Find_All_Anagrams_in_a_String.py - m # 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
_author_ = 'jake' digit.
_project_ = 'leetcode' # The result of the expression will always evaluate to either a digit 0-9, T or F.

# https://leetcode.com/problems/find-all-anagrams-in-a-string/ # Move form left to right adding all chars to a stack unless top of stack is '?'. In
# Given a string s and a non-empty string p, find all the start indices of p's anagrams which case pop off true_val and
in s. # false_val, then push back to stack result depending on current char.
# Strings consists of lowercase English letters only and the length of both strings s and # Time - O(n)
p will not be larger than 20,100. # Space - O(n)
# The order of output does not matter.
class Solution(object):
# Maintain a count of each letter in a sliding window in s, minus the counts of letters def parseTernary(self, expression):
in p. Populate the dictionary """
# with the intial counts, then slide along removing chars at the back and adding chars at :type expression: str
the front. Add to result if :rtype: str
# dictionary is empty (all values zero). """
# Time - O(n) len(s) stack = []
# Space - O(m) len(p)
for c in expression[::-1]:
from collections import defaultdict
if stack and stack[-1] == "?":
class Solution(object): stack.pop() # remove '?'
def findAnagrams(self, s, p): true_val = stack.pop()
""" stack.pop() # remove ':'
:type s: str false_val = stack.pop()
:type p: str if c == "T":
:rtype: List[int] stack.append(true_val)
""" else:
n = len(p) stack.append(false_val)
# Time - O(1)
else: # Space - O(1)
stack.append(c)
import math
return stack.pop()
class Solution(object):
def arrangeCoins(self, n):
# python_1_to_1000/440_K-th_Smallest_in_Lexicographical_Order.py - h """
:type n: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
return int(math.sqrt(1 + 8.0 * n) - 1) / 2
# https://leetcode.com/problems/k-th-smallest-in-lexicographical-order/
# Given integers n and k, find the lexicographically k-th smallest integer in the range
from 1 to n. # python_1_to_1000/442_Find_All_Duplicates_in_an_Array.py - m

# Search integers beginning with 1, if not found increment first digit to 2, 3, ... etc. _author_ = 'jake'
# Given a beginning digit kth, repeatedly multiply the start and end of search range by _project_ = 'leetcode'
10 until the range includes n.
# If range does not include solution, increment beginning digit kth. Else use kth and # https://leetcode.com/problems/find-all-duplicates-in-an-array/
multiply range start by 10. # Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear
twice and others appear once.
# Time - O(logn ** 2) # Find all the elements that appear twice in this array.
# Space - O(1)
# Indicate that nums[i] has been seen by setting the i-1th entry to be negative.
class Solution(object): # Time - O(n)
def findKthNumber(self, n, k): # Space - O(1)
"""
:type n: int class Solution(object):
:type k: int def findDuplicates(self, nums):
:rtype: int """
""" :type nums: List[int]
kth = 1 :rtype: List[int]
k -= 1 """
result = []
while k > 0:
for i in range(len(nums)):
lower, upper = kth, kth + 1 # check range including lower, excluding upper
count = 0 num = abs(nums[i]) # nums[i] may be negative because we have seen i + 1,
which is irrelevant here
while lower <= n: # at least some of range is valid
count += min(upper, n + 1) - lower if nums[num - 1] < 0: # already seen num
lower *= 10 result.append(num)
upper *= 10 continue

if count <= k: # count numbers do not reach k nums[num - 1] = -nums[num - 1] # flag num as having been seen
k -= count # use all count numbers
kth += 1 # increment start point for next range return result
else:
k -= 1 # use kth
kth *= 10 # next range start

return kth # python_1_to_1000/443_String_Compression.py - m

_author_ = 'jake'
# python_1_to_1000/441_Arranging_Coins.py _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/string-compression/


_project_ = 'leetcode' # Given an array of characters, compress it in-place.
# The length after compression must always be smaller than or equal to the original
# https://leetcode.com/problems/arranging-coins/ array.
# You have a total of n coins that you want to form in a staircase, where every k-th row # Every element of the array should be a character (not int) of length 1.
must have exactly k coins. # After you are done modifying the input array in-place, return the new length of the
# Given n, find the total number of full staircase rows that can be formed. array.
# n is a non-negative integer and fits within the range of a 32-bit signed integer.
# Iterate over chars, finding when a sequence ends. Add the char to result and if the
# k complete rows contain the sum form 1 to k coins = k(k + 1) / 2. Solve this quadratic sequence is longer than 1 char
polynomial for k and round down # then we compress and add the digits of the number of chars to the result.
# to nearest integer. # Time - O(n)

# Space - O(1) for seq in seqs:

class Solution(object): for n1, n2 in zip([None] + seq, seq):


def compress(self, chars):
""" if n2 not in num_to_index or num_to_index[n2] <= num_to_index[n1]:
:type chars: List[str] return False
:rtype: int last_index = num_to_index[n2]
"""
chars += " " # append with ASCII value 32, will not appear in chars pairs.discard((n1, n2))
char_start = 0 # start index of sequence of current char
result_length = 0 # next index for result to be updated return not pairs

for i, c in enumerate(chars):
# python_1_to_1000/445_Add_Two_Numbers_II.py - m
if c != chars[char_start]: # not extending same sequence of chars
_author_ = 'jake'
chars[result_length] = chars[char_start] # add this char to result _project_ = 'leetcode'
result_length += 1
# https://leetcode.com/problems/add-two-numbers-ii/
seq_length = i - char_start # You are given two non-empty linked lists representing two non-negative integers. The
most significant digit comes
if seq_length > 1: # can compress # first and each of their nodes contain a single digit. Add the two numbers and return it
digits = list(str(seq_length)) as a linked list.
digits_length = len(digits) # You may assume the two numbers do not contain any leading zero, except the number 0
chars[result_length:result_length + digits_length] = digits # insert itself.
digits
result_length += digits_length # Iterate over lists to calculate the integers they represent and sum them. Build
resulting list from the least
char_start = i # significant digit by repeatedly dividing by 10.
# Time - O(m + n)
return result_length # Space - O(max(m, n))

# Definition for singly-linked list.


class ListNode(object):
def __init__(self, x):
# python_1_to_1000/444_Sequence_Reconstruction.py - m self.val = x
self.next = None
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def addTwoNumbers(self, l1, l2):
# https://leetcode.com/problems/sequence-reconstruction/ """
# Check whether the original sequence org can be uniquely reconstructed from the :type l1: ListNode
sequences in seqs. The org sequence :type l2: ListNode
# is a permutation of the integers from 1 to n, with 1 ≤ n ≤ 104. Reconstruction means :rtype: ListNode
building a shortest common """
# supersequence of the sequences in seqs (i.e., a shortest sequence so that all sequences num1, num2 = 0, 0
in seqs are subsequences
# of it). Determine whether there is only one sequence that can be reconstructed from node = l1
seqs and it is the org sequence. while node:
num1 = num1 * 10 + node.val
# Note org is permutation hence no duplicates. Create set of all consecutive pair in org node = node.next
and mapping from each num in node = l2
# org to its index. For each seq remove any consecutive pair from pairs and check numbers while node:
appear in increasing index num2 = num2 * 10 + node.val
# order in org. Consecutive pairs in some seq ensures there is no choise condition node = node.next
# Time - O(s + n), total length of all seqs + org
# Space - O(n) total = num1 + num2
if total == 0: # return single node with zero
class Solution(object): return ListNode(0)
def sequenceReconstruction(self, org, seqs): result = None
"""
:type org: List[int] while total:
:type seqs: List[List[int]] total, digit = divmod(total, 10)
:rtype: bool new_node = ListNode(digit)
""" new_node.next = result # make digit start of result
extended = [None] + org # prepend with None to catch len(org) == 1 result = new_node
pairs = set((n1, n2) for n1, n2 in zip(extended, org))
num_to_index = {num: i for i, num in enumerate(extended)} return result
points at that distance
# python_1_to_1000/446_Arithmetic_Slices_II-Subsequence.py - h # can mane a boomerang, which is the number of pairs of points.
# Time - O(n**2)
_author_ = 'jake' # Space - O(n**2)
_project_ = 'leetcode'
from collections import defaultdict
# https://leetcode.com/problems/arithmetic-slices-ii-subsequence/
# A sequence of numbers is called arithmetic if it consists of at least three elements
and if the difference between class Solution(object):
# any two consecutive elements is the same. def numberOfBoomerangs(self, points):
# A zero-indexed array A consisting of N numbers is given. A subsequence slice of that """
array is any sequence of :type points: List[List[int]]
# integers (P0, P1, ..., Pk) such that 0 ≤ P0 < P1 < ... < Pk < N. :rtype: int
# 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. def dist_squared(p1, p2):
# The function should return the number of arithmetic subsequence slices in the array A. return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2

# For each num, create a dictionary mapping arithmetic progression differences to the boomerangs = 0
count of APs of length >= 2 and
# ending at num. For each num find the diff from all previous nums. All APs of length >= for middle in points:
2 ending at previous num distances = defaultdict(int)
# with that diff can be extended to make a valid subsequence slice. All APs form new APs
ending at num plus the new for i, other in enumerate(points):
# AP from A[i] to A[j]. distances[dist_squared(middle, other)] += 1
# Time - O(n**2)
# Space - O(n**2) for count in distances.values():
boomerangs += count * (count - 1)
from collections import defaultdict
return boomerangs
class Solution(object):
def numberOfArithmeticSlices(self, A):
""" # python_1_to_1000/448_Find_All_Numbers_Disappeared_in_an_Array.py
:type A: List[int]
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
count = 0
subsequences = [] # list of dicts, each dict maps from a difference value to # https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/
the count of subsequence slices # Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear
# ending at A[i] with that difference and of length 2 or more twice and others appear once.
for i in range(len(A)): # Find all the elements of [1, n] inclusive that do not appear in this array.
subsequences.append(defaultdict(int))
# Iterate over the list. For every number seen, set the number with index of num - 1 to
for j in range(i): # for each previous num be negative.
diff = A[i] - A[j] # Iterate again over the list, finding all indices that are still positive and so have
diff_count = subsequences[j].get(diff, 0) # default to zero not been seen.
count += diff_count # all sequences (length 2 or more) can be # Time - O(n)
extended and end here # Space - O(1)
subsequences[-1][diff] += diff_count + 1 # add new sequence from i
to j class Solution(object):
def findDisappearedNumbers(self, nums):
return count """
:type nums: List[int]
:rtype: List[int]
# python_1_to_1000/447_Number_of_Boomerangs.py - m """
for num in nums:
_author_ = 'jake' num = abs(num) # may be negative so take absolute
_project_ = 'leetcode' value
nums[num - 1] = -abs(nums[num - 1]) # set nums[num - 1] to indicate num -
# https://leetcode.com/problems/number-of-boomerangs/ 1 seen
# Given n points in the plane that are all pairwise distinct, a "boomerang" is a tuple of
points (i, j, k) such that return [i + 1 for i, num in enumerate(nums) if num > 0]
# the distance between i and j equals the distance between i and k (the order of the
tuple matters).
# Find the number of boomerangs.
# python_1_to_1000/449_Serialize_and_Deserialize_BST.py - m
# For each point, calculate the distances to all other points and create a mapping from
each distance to the number of _author_ = 'jake'
# points with that distance. For each distance, calculate the the number of ways that the _project_ = 'leetcode'

# Given a root node reference of a BST and a key, delete the node with the given key in
# https://leetcode.com/problems/serialize-and-deserialize-bst/ the BST.
# Design an algorithm to serialize and deserialize a binary search tree. There is no # Return the root node reference (possibly updated) of the BST.
restriction on how your
# serialization/deserialization algorithm should work. You just need to ensure that a # Recursively test if key is root value. If not recurse left or right and update subtree.
binary search tree can be If root has key, replace root
# serialized to a string and this string can be deserialized to the original tree # value with next largest value and recurse to update root right subtree having deleted
structure. node with next largest value.
# Time - O(n), height of tree
# Serialize by preorder traversal. String of values joined by spaces, no None markers. # Space - O(1)
# Deserialze from deque. If first value is in range, use value as root and recurse left
and right subtrees with ranges # Definition for a binary tree node.
# less than and more than value respectively. class TreeNode(object):
# Time - O(n) def __init__(self, x):
# Space - O(n) self.val = x
self.left = None
# Definition for a binary tree node. self.right = None
class TreeNode(object):
def __init__(self, x): class Solution(object):
self.val = x def deleteNode(self, root, key):
self.left = None """
self.right = None :type root: TreeNode
:type key: int
from collections import deque :rtype: TreeNode
"""
if not root:
def serialize(self, root): return None
"""Encodes a tree to a single string.
:type root: TreeNode if key > root.val: # key in right subtree, keep root and update right subtree
:rtype: str root.right = self.deleteNode(root.right, key)
""" elif key < root.val:
serial_list = [] root.left = self.deleteNode(root.left, key)

def serial(node): else:


if not node: if not (root.left and root.right): # one or no children
return root = root.left or root.right
serial_list.append(str(node.val)) else: # both children
serial(node.left) next_largest = root.right
serial(node.right) while next_largest.left:
next_largest = next_largest.left
serial(root) root.val = next_largest.val
return " ".join(serial_list) root.right = self.deleteNode(root.right, root.val)

def deserialize(self, data): return root


"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode # python_1_to_1000/451_Sort_Characters_by_Frquency.py - m
"""
preorder = deque(int(val) for val in data.split()) # convert to integers _author_ = 'jake'
_project_ = 'leetcode'
# if first preorder is between low and high, create tree of all vals in that range
with first preorder as root # https://leetcode.com/problems/sort-characters-by-frequency/
def deserial(low, high): # Given a string, sort it in decreasing order based on the frequency of characters.
if preorder and low < preorder[0] < high:
val = preorder.popleft() # Count frequency of chars and sort tuples of (-count, char) into frequency order.
node = TreeNode(val) # Time - O(n log n)
node.left = deserial(low, val) # Space - O(n)
node.right = deserial(val, high)
return node from collections import Counter

return deserial(float("-inf"), float("inf"))


class Solution(object):
def frequencySort(self, s):
# python_1_to_1000/450_Delete_Node_in_a_BST.py - m """
:type s: str
_author_ = 'jake' :rtype: str
_project_ = 'leetcode' """
freq = Counter(s)
# https://leetcode.com/problems/delete-node-in-a-bst/ pairs = [(count, c) for c, count in freq.items()]
pairs.sort(reverse = True)
class Solution(object):
result = [] def minMoves(self, nums):
for count, c in pairs: """
result += [c] * count :type nums: List[int]
:rtype: int
return "".join(result) """
return sum(nums) - min(nums) * len(nums)

# python_1_to_1000/452_Minimum_Number_of_Arrows_to_Burst_Balloons.py - m
# python_1_to_1000/454_4Sum_II.py - m
_author_ = 'jake'
_project_ = 'leetcode' _author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/
# There are a number of spherical balloons spread in two-dimensional space. For each # https://leetcode.com/problems/4sum-ii/
balloon, provided input is the # Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l)
# start and end coordinates of the horizontal diameter. Since it's horizontal, y- there are such that
coordinates don't matter and hence # A[i] + B[j] + C[k] + D[l] is zero. All A, B, C, D have same length.
# the x-coordinates of start and end of the diameter suffice. Start is always smaller
than end. # Count all sums of pairs in lists A and B. For each pair in C and D, increment total by
# An arrow can be shot up exactly vertically from different points along the x-axis. A count of -(c + d) from AB.
balloon with xstart and xend # Time - O(n**2)
# bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of # Space - O(n**2)
arrows that can be shot.
# An arrow once shot keeps travelling up infinitely. The problem is to find the minimum from collections import defaultdict
number of arrows that must be
# shot to burst all balloons. class Solution(object):
def fourSumCount(self, A, B, C, D):
# Sort by ending edge. Greedily shoot first ending edge, which bursts all balloons that """
start before or after that edge. :type A: List[int]
# Time - O(n) :type B: List[int]
# Space - O(1) :type C: List[int]
:type D: List[int]
class Solution(object): :rtype: int
def findMinArrowShots(self, points): """
""" AB = defaultdict(int)
:type points: List[List[int]] count = 0
:rtype: int
""" for a in A:
arrows, last_arrow = 0, float("-inf") for b in B:
points.sort(key = lambda x: x[1]) AB[a + b] += 1

for start, end in points: for c in C:


for d in D:
if start > last_arrow: if -(c + d) in AB:
arrows += 1 count += AB[-(c + d)]
last_arrow = end
return count
return arrows

# python_1_to_1000/455_Assign_Cookies.py
# python_1_to_1000/453_Minimum_Moves_to_Equal_Array_Elements.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/assign-cookies/
# https://leetcode.com/problems/minimum-moves-to-equal-array-elements/ # Assume you are an awesome parent and want to give your children some cookies. But, you
# Given a non-empty integer array of size n, find the minimum number of moves required to should give each child at
make all array elements # most one cookie. Each child i has a greed factor gi, which is the minimum size of a
# equal, where a move is incrementing n - 1 elements by 1. cookie that the child will be
# content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j
# Incrementing n - 1 elements is equivalent to incrementing all n elements and to the child i, and the
decrementing 1 element. Incrementing all # child i will be content. Your goal is to maximize the number of your content children
# elements does not equalize the array, so we need to count the number of moves to and output the maximum number.
decrement all elements to be equal.
# For each element, this is the difference between its value and the minimum value. # Sort both lists in ascending order. For each cookie, offer it to the next child. If it
# Time - O(n) is accepted, increment the
# Space - O(1) # 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.
# Time - O(n) # python_1_to_1000/457_Circular_Array_Loop.py - m
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def findContentChildren(self, g, s):
""" # https://leetcode.com/problems/circular-array-loop/
:type g: List[int] # You are given an array of positive and negative integers. If a number n at an index is
:type s: List[int] positive, then move forward
:rtype: int # n steps. Conversely, if it's negative (-n), move backward n steps.
""" # Assume the first element of the array is forward next to the last element, and the last
content = 0 # number of content children element is backward next to
child = 0 # index of next child # the first element. Determine if there is a loop in this array.
g.sort() # A loop starts and ends at a particular index with more than 1 element along the loop.
s.sort() # 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 ->
for cookie in s: 0.
# Example 2: Given the array [-1, 2], there is no loop.
if child == len(g): # early return, no more children # Note: The given array is guaranteed to contain no element "0".
break
# For each starting num, attempt to find a sequence of n steps, which implies there must
if g[child] <= cookie: # child accepts cookie be a loop. A loop is not found
content += 1 # if any step returns to the same index or moves in the opposite direction.
child += 1 # Time - O(n)
# Space - O(1)
return content
class Solution(object):
def circularArrayLoop(self, nums):
# python_1_to_1000/456_132_Pattern.py - m """
:type nums: List[int]
_author_ = 'jake' :rtype: bool
_project_ = 'leetcode' """
n = len(nums)
# https://leetcode.com/problems/132-pattern/
# Given a sequence of n integers a1, a2, ..., an, a 132 pattern is a subsequence ai, aj, for i, num in enumerate(nums):
ak such that i < j < k
# and ai < ak < aj. Design an algorithm that takes a list of n numbers as input and pos = num > 0 # direction of movements
checks whether there is a j = (i + num) % n # take the first step
# 132 pattern in the list. steps = 1

# Iterate over nums in reverse order. If num < two then we have a solution because some while steps < n and nums[j] % n != 0 and (nums[j] > 0) == pos:
number greater than two was j = (j + nums[j]) % n # take the next step
# seen after two (and caused two to be popped off stack). Stack is ascending from top to steps += 1
bottom, so last pop is
# greatest number less than num. if steps == n: # loop is found
# Time - O(n) return True
# Space - O(n)
nums[i] = 0
class Solution(object): j = (i + num) % n # set everything visited to zero to avoid
def find132pattern(self, nums): repeating
""" while nums[j] % n != 0 and (nums[j] > 0) == pos:
:type nums: List[int] j, nums[j] = (j + nums[j]) % n, 0
:rtype: bool
""" return False
two = float("-inf")
stack = []

for i in range(len(nums) - 1, -1, -1): # python_1_to_1000/458_Poor_Pigs.py - h

if nums[i] < two: _author_ = 'jake'


return True _project_ = 'leetcode'

while stack and stack[-1] < nums[i]: # https://leetcode.com/problems/poor-pigs/


two = stack.pop() # There are 1000 buckets, one and only one of them contains poison, the rest are filled
with water.
stack.append(nums[i]) # 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
return False poison within one hour.
# Answer this question, and write an algorithm for the follow-up general case. # It should support the following operations: get and put.
# If there are n buckets and a pig drinking poison will die within m minutes, how many # get(key) - Get the value (will always be positive) of the key if the key exists in the
pigs (x) you need to figure out cache, otherwise return -1.
# the "poison" bucket within p minutes? There is exact one bucket with poison. # put(key, value) - Set or insert the value if the key is not already present. When the
cache reaches its capacity, it
# Find the number of rounds of tests that can be run as the integer division of the total # should invalidate the least frequently used item before inserting a new item. For the
time over time to die. purpose of this problem, when
# Arrange the buckets in a hypercube with side of rounds + 1. # there is a tie (i.e., two or more keys that have the same frequency), the least
# Each pig finds the coordinate in one dimension of the hypercube by drinking from rounds recently used key would be evicted.
+ 1 buckets in each round.
# If a pig dies, we find the coordinate in that dimension, if it doesn't we know the # Maintain dict form key to value, dict from key to (freq, time), priority queue and set
coordinate is the final index. of keys to update in queue.
# Hence buckets in hypercube = (rounds + 1) ** pigs. So pigs = ln(buckets) / ln(rounds + # For get and put existing key, do not update queue but add key to update set. For put
1), rounded up to the next when cache is full, update queue
# integer. # until top item does not need updating.
# Time - O(1) # Time - O(1) for get, O(k log k) for put
# Space - O(1) # Space - O(k)

from math import log, ceil import heapq

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


def poorPigs(self, buckets, minutesToDie, minutesToTest): def __init__(self, capacity):
""" """
:type buckets: int :type capacity: int
:type minutesToDie: int """
:type minutesToTest: int self.capacity = capacity
:rtype: int self.time = 0
""" self.map = {} # key to value
rounds = minutesToTest // minutesToDie self.freq_time = {} # key to (freq, time)
self.priority_queue = [] # (freq, time, key), only updated when new key is added
return int(ceil(log(buckets) / log(rounds + 1))) self.update = set() # keys that have been get/put since last new key was added

def get(self, key):


# python_1_to_1000/459_Repeated_Substring_Pattern.py """
:type key: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
self.time += 1
# 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 if key in self.map:
appending multiple copies of freq, _ = self.freq_time[key]
# the substring together. You may assume the given string consists of lowercase English self.freq_time[key] = (freq + 1, self.time)
letters only. self.update.add(key)
return self.map[key]
# If a string consists of 2 copies of a substring, then appending the string to itself
and removing the first and last return -1
# letters will still contain 2 copies of the substring. The same is true if there are
more than 2 copies. def put(self, key, value):
# Conversely, if the string is not a repeated substring then it cannot be built this way """
from 2 copies. :type key: int
# Time - O(n) :type value: int
# Space - O(n) :rtype: void
"""
class Solution(object): if self.capacity <= 0:
def repeatedSubstringPattern(self, s): return
"""
:type s: str self.time += 1
:rtype: bool if not key in self.map:
"""
return s in (s[1:] + s[:-1]) if len(self.map) >= self.capacity: # must remove least frequent from cache

while self.priority_queue and self.priority_queue[0][2] in self.update:


# python_1_to_1000/460_LFU_Cache.py - h # whilst (least frequent, oldest) needs to be updated, update it and
add back to heap
_author_ = 'jake' _, _, k = heapq.heappop(self.priority_queue)
_project_ = 'leetcode' f, t = self.freq_time[k]
heapq.heappush(self.priority_queue, (f, t, k))
# https://leetcode.com/problems/lfu-cache/ self.update.remove(k)
# Design and implement a data structure for Least Frequently Used (LFU) cache.

# remove (least frequent, oldest) """


_, _, k = heapq.heappop(self.priority_queue) :type nums: List[int]
self.map.pop(k) :rtype: int
self.freq_time.pop(k) """
nums.sort()
self.freq_time[key] = (0, self.time) front, back = 0, len(nums) - 1
heapq.heappush(self.priority_queue, (0, self.time, key)) moves = 0
while front < back:
else: moves += nums[back] - nums[front]
freq, _ = self.freq_time[key] front += 1
self.freq_time[key] = (freq + 1, self.time) back -= 1
self.update.add(key)
return moves
self.map[key] = value

# python_1_to_1000/463_Island_Perimeter.py

# python_1_to_1000/461_Hamming_Distance.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/island-perimeter/
# You are given a map in form of a two-dimensional integer grid where 1 represents land
# https://leetcode.com/problems/hamming-distance/ and 0 represents water.
# The Hamming distance between two integers is the number of positions at which the # Grid cells are connected horizontally/vertically (not diagonally). The grid is
corresponding bits are different. completely surrounded by water,
# Given two integers x and y, calculate the Hamming distance. # and there is exactly one island (i.e., one or more connected land cells). The island
doesn't have "lakes" (water
# Iterate over the bits of z and y together. If least significant bits are different, # inside that isn't connected to the water around the island). One cell is a square with
increment result. Right shift side length 1. The grid
# to move to next bit until both integers are zero. # is rectangular, width and height don't exceed 100. Determine the perimeter of the
# Time - O(log n) island.
# Space - O(1)
# Iterate over grid. If a cell is land, add 4 to perimeter assuming cell is surrounded by
class Solution(object): water. Then for each of lower
def hammingDistance(self, x, y): # and right cells that are land, decrement the perimeter by 2 (both sides of the internal
""" edge).
:type x: int # Time - O(mn)
:type y: int # Space - O(mn)
:rtype: int
""" class Solution(object):
hamming = 0 def islandPerimeter(self, grid):
"""
while x or y: :type grid: List[List[int]]
hamming += (x & 1) != (y & 1) :rtype: int
x >>= 1 """
y >>= 1 rows, cols = len(grid), len(grid[0])
for row in grid: # pad with water
return hamming row.append(0)
grid.append([0] * (cols + 1))
perimiter = 0
# python_1_to_1000/462_Minimum_Moves_to_Equal_Array_Elements_II.py - m
for r in range(rows):
_author_ = 'jake' for c in range(cols):
_project_ = 'leetcode' if grid[r][c] == 1:
perimiter += 4
# https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/ if grid[r + 1][c] == 1:
# Given a non-empty integer array, find the minimum number of moves required to make all perimiter -= 2
array elements equal, where a if grid[r][c + 1] == 1:
# move is incrementing a selected element by 1 or decrementing a selected element by 1. perimiter -= 2

# Sort and remove front and back in pairs. The difference between each pair has to be return perimiter
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. # python_1_to_1000/464_Can_I_Win.py - m
# Time - O(n log n)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def minMoves2(self, nums): # https://leetcode.com/problems/can-i-win/
# In the "100 game," two players take turns adding, to a running total, any integer from # Calculate the net balance owed to or from each person. For any sequence of net
1..10. The player who first balances, calculate the number of
# causes the running total to reach or exceed 100 wins. What if we change the game so # transfers recursively. Take the net balance of the first person. If any other person
that players cannot re-use has the opposite balance then
# integers? # net them off (one transfer) and calculate the transfers to settle the remaining
# Given an integer maxChoosableInteger and another integer desiredTotal, determine if the balances. Else find the minimum
first player to move can # transfers from netting with each other person.
# force a win, assuming both players play optimally. # Time - O(m + (n - 1)!) where m = len(transactions) and n is the number of people, since
t(n) = (n-1) * t(n-1)
# Keep unused numbers in an ordered list (not a set, so can be converted to stable tuple # Space - O(n**2)
for memo, largest can be
# identified). If for any number, opposition cannot win then can win. Memoise lists as from collections import defaultdict
tuples.
# Time - O(n * n!), n = maxChoosableInteger. n choices initially, n-1, n-2. Each choice class Solution(object):
takes O(n) to construct list. def minTransfers(self, transactions):
# Space - O(n * n!) """
:type transactions: List[List[int]]
class Solution(object): :rtype: int
def canIWin(self, maxChoosableInteger, desiredTotal): """
""" balances = defaultdict(int) # map person to net balance
:type maxChoosableInteger: int for lender, receiver, amount in transactions:
:type desiredTotal: int balances[lender] += amount
:rtype: bool balances[receiver] -= amount
"""
if maxChoosableInteger * (maxChoosableInteger + 1) // 2 < desiredTotal: net_balances = [b for b in balances.values() if b != 0]
return False # all numbers cannot reduce desiredTotal to zero
def transfers(net_balances):
return self.next_player_win(desiredTotal, list(range(1, maxChoosableInteger +
1)), {}) if not net_balances: # base case
return 0

def next_player_win(self, target, unused, memo): b = net_balances[0]


for i in range(1, len(net_balances)): # optimal to net exactly
if unused[-1] >= target: if b == -net_balances[i]:
return True return 1 + transfers(net_balances[1:i] + net_balances[i + 1:])

tup = tuple(unused) min_transfers = float("inf")


if tup in memo: for i in range(1, len(net_balances)):
return memo[tup] if b * net_balances[i] < 0: # opposite signs
count = 1 + transfers(net_balances[1:i] + net_balances[i + 1:] + [b +
for i in range(len(unused) - 1, -1, -1): net_balances[i]])
min_transfers = min(min_transfers, count)
opposition_win = self.next_player_win(target - unused[i], unused[:i] +
unused[i + 1:], memo) return min_transfers
if not opposition_win:
memo[tup] = True return transfers(net_balances)
return True

memo[tup] = False # python_1_to_1000/466_Count_The_Repetition.py - h


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

# python_1_to_1000/465_Optimal_Account_Balancing.py - h # https://leetcode.com/problems/count-the-repetitions/
# Define S = [s,n] as the string S which consists of n connected strings s. For example,
_author_ = 'jake' ["abc", 3] ="abcabcabc".
_project_ = 'leetcode' # On the other hand, we define that string s1 can be obtained from string s2 if we can
remove some characters from s2
# https://leetcode.com/problems/optimal-account-balancing/ # such that it becomes s1. For example, “abc” can be obtained from “abdbec” based on our
# A group of friends went on holiday and sometimes lent each other money. For example, definition, but it can not
Alice paid for Bill's lunch for # be obtained from “acbbe”.
# $10. Then later Chris gave Alice $5 for a taxi ride. We can model each transaction as a # You are given two non-empty strings s1 and s2 and two integers n1 and n2. Now consider
tuple (x, y, z) which means the strings S1 and S2,
# person x gave person y $z. Assuming Alice, Bill, and Chris are person 0, 1, and 2 # where S1=[s1,n1] and S2=[s2,n2]. Find the maximum integer M such that [S2,M] can be
respectively (0, 1, 2 are the obtained from S1.
# person's ID), the transactions can be represented as [[0, 1, 10], [2, 0, 5]].
# Given a list of transactions between a group of people, return the minimum number of # Step through s1, incrementing also in s2 if chars match. Go back to the beginning and
transactions to settle the debt. increment reps at the end of
# 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. return s2_reps // n2
# Time - O(m * n), iterate over s1 until have seen all ending positions in s2
# Space - O(m * n)

class Solution(object): # python_1_to_1000/467_Unique_Substrings_in_Wraparound_String.py - m


def getMaxRepetitions(self, s1, n1, s2, n2):
""" _author_ = 'jake'
:type s1: str _project_ = 'leetcode'
:type n1: int
:type s2: str # https://leetcode.com/problems/unique-substrings-in-wraparound-string/
:type n2: int # Consider the string s to be the infinite wraparound string of
:rtype: int "abcdefghijklmnopqrstuvwxyz", so s will look like
""" # this: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....".
if any(c for c in set(s2) if c not in set(s1)): # early return if no result # Now we have another string p. Your job is to find out how many unique non-empty
possible substrings of p are present in s.
return 0 # In particular, your input is the string p and you need to output the number of
different non-empty substrings of p
i, j = 0, 0 # index counters in s1 and s2 # in the string s. p consists of only lowercase English letters.
s1_reps, s2_reps = 0, 0 # numbers of complete
repetitions of s1 and s2 used # Record the longest substring ending with each of the 26 letters. Iterate over p,
s2_index_to_reps = {0 : (0, 0)} # map from j to (s1_reps, incrementing the substring length
s2_reps) # if letter incerements previous. Update max substring ending with current letter. Result
is sum of all substrings for
while s1_reps < n1: # break if n1 copies of s1 # all letters.
used # Time - O(n)
# Space - O(1)
if s1[i] == s2[j]:
j += 1 # increment j if chars match class Solution(object):
i += 1 def findSubstringInWraproundString(self, p):
"""
if j == len(s2): :type p: str
j = 0 :rtype: int
s2_reps += 1 """
substring_ending = [0] * 26 # length of longest substring ending with char
if i == len(s1): length = 0
i = 0
s1_reps += 1 for i, c in enumerate(p):
if j in s2_index_to_reps: # same position in s2 as
before, in a loop if i != 0 and (ord(c) == ord(p[i - 1]) + 1 or ord(c) == ord(p[i - 1]) - 25):
break length += 1
s2_index_to_reps[j] = (s1_reps, s2_reps) # record reps at this else:
position in s2 length = 1

if s1_reps == n1: # no loop found substring_ending[ord(c) - ord("a")] = max(substring_ending[ord(c) -


return s2_reps // n2 ord("a")], length)

initial_s1_reps, initial_s2_reps = s2_index_to_reps[j] return sum(substring_ending)


loop_s1_reps = s1_reps - initial_s1_reps
loop_s2_reps = s2_reps - initial_s2_reps
loops = (n1 - initial_s1_reps) // loop_s1_reps # number of loops possible
after initial_s1_reps # python_1_to_1000/468_Validate_IP_Address.py - m

s1_reps = initial_s1_reps + loops * loop_s1_reps _author_ = 'jake'


s2_reps = initial_s2_reps + loops * loop_s2_reps _project_ = 'leetcode'

while s1_reps < n1: # until n1 copies of s1 used # https://leetcode.com/problems/validate-ip-address/


# Write a function to check whether an input string is a valid IPv4 address or IPv6
if s1[i] == s2[j]: address or neither.
j += 1 # IPv4 addresses are canonically represented in dot-decimal notation, which consists of
i += 1 four decimal numbers, each
# ranging from 0 to 255, separated by dots ("."). leading zeros in IPv4 are invalid.
if i == len(s1): # IPv6 addresses are represented as eight groups of four hexadecimal digits, each group
i = 0 representing 16 bits. The
s1_reps += 1 # groups are separated by colons (":"). Leading zeros are optional. Upper or lower case
letters are allowed.
if j == len(s2): # However, we don't replace a consecutive group of zero value with a single empty group
j = 0 using two consecutive colons
s2_reps += 1 # (::) to pursue simplicity.
# You may assume there is no extra space or special characters in the input string. cross_product = vector[0] * previous[1] - vector[1] * previous[0]

# Split by "." to check if IPv4. All group members must be integers >= 0 and <= 255. if cross_product != 0:
Split by ":" to check IPv6. if previous_cross * cross_product < 0:
# Time - O(n) return False
# Space - O(n) previous_cross = cross_product

class Solution(object): previous = vector


def validIPAddress(self, IP):
""" return True
:type IP: str
:rtype: str
""" # python_1_to_1000/470_Implement_Rand10()_Using_Rand7().py - m
ip_list = IP.split(".")
if len(ip_list) == 4: _author_ = 'jake'
for group in ip_list: _project_ = 'leetcode'
n = int(group)
if n < 0 or n > 255 or len(str(n)) != len(group): # len checks for # https://leetcode.com/problems/implement-rand10-using-rand7/
leading zeros or minus zero # Given a function rand7 which generates a uniform random integer in the range 1 to 7,
return "Neither" write a function rand10 which
return "IPv4" # generates a uniform random integer in the range 1 to 10.

ip_list = IP.split(":") # Create a 2 digit number in base 7, of which there are 49. Use only the first 40, where
if len(ip_list) != 8: the units in base 10 have
return "Neither" # an equal probability of being each digit.
# Time - O(infinity), expected is sum of arithmetico–geometric sequence
for group in ip_list: # Space - O(1)
n = int(group, 16)
if n < 0 or n > int("FFFF", 16) or len(group) > 4 or group[0] == "-": # class Solution(object):
eliminate "00000" and "-0" def rand10(self):
return "Neither" """
:rtype: int
return "IPv6" """
units = rand7() - 1
sevens = rand7() - 1
# python_1_to_1000/469_Convex_Polygon.py - m num = 7 * sevens + units # between 0 and 48 inclusive

_author_ = 'jake' if num >= 40: # use on 0 to 39 inclusive


_project_ = 'leetcode' return self.rand10()

# https://leetcode.com/problems/convex-polygon/ return (num % 10) + 1 # take units digit


# 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/471_Encode_String_With_Shortest_Length.py - h
# 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 _author_ = 'jake'
polygon definition). In other _project_ = 'leetcode'
# words, we ensure that exactly two edges intersect at each vertex, and that edges
otherwise don't intersect each other. # https://leetcode.com/problems/encode-string-with-shortest-length/
# Given a non-empty string, encode the string such that its encoded length is the
# For each edge, calculate cross product with previous edge. All cross products must have shortest.
same sign to be convex. # The encoding rule is: k[encoded_string], where the encoded_string inside the square
# Time - O(n) brackets is being
# Space - O(1) # repeated exactly k times.
# k will be a positive integer and encoded string will not be empty or have extra space.
class Solution(object): # You may assume that the input string contains only lowercase English letters.
def isConvex(self, points): # If an encoding process does not make the string shorter, then do not encode it.
""" # If there are several solutions, return any of them is fine.
:type points: List[List[int]]
:rtype: bool # Take the minumum length of 3 possible encoding types:
""" # 1) If s consists entirely of a repeated substring, encode as that substring with
points.append(points[0]) # close the polygon by appending first edge to end recursion.
points.append(points[1]) # ditto # 2) For all breakpoints in s, recursively encode LHS and RHS
previous = [points[1][0] - points[0][0], points[1][1] - points[0][1]] # 3) s without encoding
previous_cross = 0 # Memoise results.

for i in range(2, len(points)): # Time - O(n**3) every one of O(n**2) substring is encoded, taking O(n) time to construct
each.
vector = [points[i][0] - points[i - 1][0], points[i][1] - points[i - 1][1]] # Space - O(n**3)

class Solution(object): # python_1_to_1000/473_Matchsticks_to_Square.py - m


def encode(self, s, memo = {}): # amend signature to add memo, empty by default
""" _author_ = 'jake'
:type s: str _project_ = 'leetcode'
:rtype: str
""" # https://leetcode.com/problems/matchsticks-to-square/
if s in memo: # Your input will be several matchsticks, represented with their stick length. Your
return memo[s] output will either be true or
# false, to represent whether you could make one square using all the matchsticks.
encodings = [s] # list of possible encodings
i = (s + s).find(s, 1) # repeated substring problem # Put each match in each side with capacity then recurse for next match.
if i != -1 and i != len(s): # s consists of a repeated substring (which is # 3 heuristics to improve speed, 1) sort in descending order, 2) avoid duplicate
not s itself) recursive call, 3) pre-fill sides
encodings.append(str(len(s) / i) + "[" + self.encode(s[:i], memo) + "]") # # with exact matches
recurse # Time - O(4**n)
# Space - O(1)
for i in range(1, len(s)): # all possible break points
encodings.append(self.encode(s[:i], memo) + self.encode(s[i:], memo)) class Solution(object):
def makesquare(self, nums):
result = min(encodings, key = len) # minimum length of all encodings """
memo[s] = result :type nums: List[int]
return result :rtype: bool
"""

# python_1_to_1000/472_Concatenated_Words.py - h def dfs(index):

_author_ = 'jake' if index == len(nums): # all sides are full


_project_ = 'leetcode' return True

# https://leetcode.com/problems/concatenated-words/ for side in range(4):


# Given a list of words (without duplicates), please write a program that returns all if sides[side] + nums[index] > target or sides[side] in sides[side + 1:]:
concatenated words in the given # match too long or
# list of words. A concatenated word is defined as a string that is comprised entirely of continue # skip if replicated side length to avoid
at least two shorter words duplicate recusrsion
# in the given array. sides[side] += nums[index] # add match to side
if dfs(index + 1):
# For each prefix of each word, if prefix is a word test whether suffix is a word or a return True
concatenation of words sides[side] -= nums[index] # remove match if cannot fill all sides
# Time - O(n * k**2) for n words of max length k return False # match cannot fit on any side
# Space - O(k)
perimeter = sum(nums)
class Solution(object): target, remainder = divmod(perimeter, 4)
def findAllConcatenatedWordsInADict(self, words): if not perimeter or remainder: # no matches or not divisible by 4
""" return False
:type words: List[str]
:rtype: List[str] nums.sort(reverse = True) # fail early, e.g 5 matches are >
""" target/2
if nums[0] > target: # longest is greater than side length
def is_concat(word): return False
if not word or word in word_set: # word will not be empty on first call
return True sides = [0] * 4 # total length of matches on each side
i = 0
for i in range(1, len(word) + 1): # check to end of word while i < 4 and nums[i] == target: # prefill any side with matches of exact
if word[:i] in word_set and is_concat(word[i:]): length
return True sides[i] = target
i += 1
return False
return dfs(i)
word_set = set(words)
results = []
for word in words:
for i in range(1, len(word)): # prefix/suffix where prefix is in dict and # python_1_to_1000/474_Ones_and_Zeros.py - m
suffix is not empty
if word[:i] in word_set and is_concat(word[i:]): _author_ = 'jake'
results.append(word) _project_ = 'leetcode'
break
return results # 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. :type houses: List[int]
# For now, suppose you are a dominator of m 0s and n 1s respectively. On the other hand, :type heaters: List[int]
there is an array with :rtype: int
# strings consisting of only 0s and 1s. Now your task is to find the maximum number of """
strings that you can form with heaters.sort()
# given m 0s and n 1s. Each 0 and 1 can be used at most once. houses.sort()
heaters = [float("-inf")] + heaters + [float("inf")]
# Dynamic programming. max_form[i][j] is the max number of strings that can be formed
form i zeros and j ones. i = 0
# For each string, if i or j are insufficient cannot form string so keep max_form radius = -1
unchanged. If can form string, take
# max of incremented max_form and using s_zeros, s_ones, or same max_form and not using for house in houses:
any zeros or ones.
# Time - O(mnk), where k = len(strs) while heaters[i + 1] < house:
# Space - O(mn) i += 1
left_distance = house - heaters[i]
class Solution(object): right_distance = heaters[i + 1] - house # could be zero
def findMaxForm(self, strs, m, n): closest = min(left_distance, right_distance)
""" radius = max(radius, closest)
:type strs: List[str]
:type m: int return radius
:type n: int
:rtype: int
"""
max_form = [[0 for _ in range(n + 1)] for _ in range(m + 1)] # python_1_to_1000/476_Number_Complement.py
for s in strs:
_author_ = 'jake'
s_zeros = sum([True for c in s if c == "0"]) _project_ = 'leetcode'
s_ones = len(s) - s_zeros
# https://leetcode.com/problems/number-complement/
for i in range(m, -1, -1): # Given a positive integer, output its complement number. The complement strategy is to
for j in range(n, -1, -1): flip the bits of its
if i >= s_zeros and j >= s_ones: # keep max_form[i][j] unchanged # binary representation.
if insufficient 0s or 1s
max_form[i][j] = max(max_form[i][j], 1 + max_form[i - s_zeros][j # Find the number with all 1s that is the same length as num. Then take the XOR to flip
- s_ones]) the bits.
# Time - O(log n)
return max_form[-1][-1] # for all strs, max_form from m, n # Space - O(1)

class Solution(object):
def findComplement(self, num):
# python_1_to_1000/475_Heaters.py - m """
:type num: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
i = 1
# https://leetcode.com/problems/heaters/
# Winter is coming! Your first job during the contest is to design a standard heater with while i <= num:
fixed warm radius to warm i <<= 1
# all the houses.
# Now, you are given positions of houses and heaters on a horizontal line, find out return (i - 1) ^ num
minimum radius of heaters so that
# all houses could be covered by those heaters.
# So, your input will be the positions of houses and heaters seperately, and your
expected output will be the minimum # python_1_to_1000/477_Total_Hamming_Diatance.py - m
# radius standard of heaters.
_author_ = 'jake'
# Sort heaters and houses. Add sentinel heaters at + and - infinity. For each house, move _project_ = 'leetcode'
along the heaters until the
# current heater is on the left of the house and the next heater is at or on the right of # https://leetcode.com/problems/total-hamming-distance/
the house. One of these # The Hamming distance between two integers is the number of positions at which the
# heaters is the closest to the house. Update the radius to be the max of the current corresponding bits are different.
radius and the closest heater. # Now your job is to find the total Hamming distance between all pairs of the given
# Time - O(m log m + n log n) numbers.
# Space - O(m) where m = len(heaters)
# For each of the 32 bits, count how many nums have that bit set. Add to total hamming
class Solution(object): distance count of pairs from
def findRadius(self, houses, heaters): # nums where one num has bit set and one num soes not have bit set.
""" # Time - O(n)

# Space - O(1) if x * x + y * y > 1: # outside circle,


repeat
class Solution(object): return self.randPoint()
def totalHammingDistance(self, nums): return [x * self.radius + self.x_center, y * self.radius + self.y_center] #
""" translate from unit circle
:type nums: List[int]
:rtype: int def randPoint2(self):
""" radius = random.random() ** 0.5 * self.radius
n = len(nums) angle = random.random() * 2 * math.pi
hamming = 0 return [radius * math.sin(angle) + self.x_center, radius * math.cos(angle) +
self.y_center]
for bit in range(32):
set_bits = 0 # count of nums with this bit set
for num in nums: # python_1_to_1000/479_Largest_Palindrome_Product.py - h
set_bits += (num >> bit) & 1
_author_ = 'jake'
hamming += (n - set_bits) * set_bits _project_ = 'leetcode'

return hamming # 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
# python_1_to_1000/478_Generate_Random_Point_in_a_Circle.py - m 1337.

_author_ = 'jake' # Build palindromes with 2 * n digits, starting from the largest palindrome and check if
_project_ = 'leetcode' they can be factorised.
# Define palindrome as upper * 10**n + lower.
# https://leetcode.com/problems/generate-random-point-in-a-circle/ # The two factors are M = 10**n - i and L = 10**n - j where i and j are small.
# Given the radius and x-y positions of the center of a circle, write a function # Hence palindrome = (10**n - i) * (10**n - j) = 10**n * (10**n - (i + j)) + i * j =
randPoint which generates a uniform upper * 10**n + lower.
# random point in the circle. # So upper = 10**n - (i + j) and lower = i * j.
# Note: # Define a = i + j. This means that a = 10**n - upper.
# input and output values are in floating-point. # Substituting for j = a - i, the equation for lower can be rewritten as lower = a * i -
# radius and x-y position of the center of the circle is passed into the class i * i.
constructor. # Solving for i, in order for i to be an integer sqrt(a**2 - 4 * lower) must be an
# a point on the circumference of the circle is considered to be in the circle. integer.
# randPoint returns a size 2 array containing x-position and y-position of the random # Time - O(n * 10**n) for the for loop
point, in that order. # Space - O(1)

# Rejection sampling from the square containing the circle. Choos a random point inside class Solution(object):
the square with x and y def largestPalindrome(self, n):
# between -1 and 1. This has probability of pi / 4 of being in the circle of radius 1. """
Else repeat until random point :type n: int
# is in the circle. :rtype: int
# Alternatively use polar coordinates with a random distance and angle. Square root of """
distance is required to if n == 1:
# normalise the density of points, or else the probability decreases with radius. return 9
# Time - O(1) expected 4 / pi
# Space - O(1) for a in range(1, 9 * 10 ** (n - 1)):

import random hi = (10 ** n) - a # most significant digits of palindrome


lo = int(str(hi)[::-1]) # least significant digits of palindrome
class Solution(object):
if a ** 2 - 4 * lo < 0:
def __init__(self, radius, x_center, y_center): continue
"""
:type radius: float if (a ** 2 - 4 * lo) ** .5 == int((a ** 2 - 4 * lo) ** .5): # sqrt(a**2 -
:type x_center: float 4*lo) is an integer
:type y_center: float return (lo + 10 ** n * (10 ** n - a)) % 1337
"""
self.radius = radius
self.x_center = x_center
self.y_center = y_center # python_1_to_1000/480_Sliding_Window_Median.py - h

def randPoint(self): _author_ = 'jake'


""" _project_ = 'leetcode'
:rtype: List[float]
""" # https://leetcode.com/problems/sliding-window-median/
x, y = 2 * random.random() - 1, 2 * random.random() - 1 # x and y between -1 # Given an array nums, there is a sliding window of size k which is moving from the very
and 1 left of the array to the
# very right. You can only see the k numbers in the window. Each time the sliding window while lower and -lower[0] in junk:
moves right by one position. removed = -heapq.heappop(lower)
# Your job is to output the median array for each window in the original array. junk[removed] -= 1
if junk[removed] == 0:
# Maintain 2 heaps, upperr with values >= median and lower with values <= median. If del junk[removed]
window is odd length, upper
# contains the odd value. Fill heaps with initial window then iterate over remaining if k % 2 == 1:
nums. At star of each iteration medians.append(float(upper[0]))
# balance = 0. Add median to result, add start of old window to junk and add end of else:
window to new heap, both times medians.append((upper[0] - lower[0]) / 2.0)
# updating balance. If imbalance then shift a num from one heap to the other. Remove junk return medians
from top of heaps.
# Time - O(n log k)
# Space - O(n)
# python_1_to_1000/481_Magical_String.py - m
from collections import defaultdict
import heapq _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def medianSlidingWindow(self, nums, k): # https://leetcode.com/problems/magical_string/
""" # A magical string S consists of only '1' and '2' and obeys the following rules:
:type nums: List[int] # The string S is magical because concatenating the number of contiguous occurrences of
:type k: int characters '1' and '2' generates the string S itself.
:rtype: List[float] # The first few elements of string S is the following: S = "1221121221221121122……"
""" # 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
lower, upper = [], [] # heaps of nums in window 22 ......
# 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
for i in range(k): # push k nums onto upper ......
heapq.heappush(upper, nums[i]) # You can see that the occurrence sequence above is the S itself.
for i in range(k // 2): # swap k//2 nums onto lower # Given an integer N as input, return the number of '1's in the first N number in the
heapq.heappush(lower, -heapq.heappop(upper)) magical string S.

medians = [] # For each s[i], append to s i copies of a different digit from that currently at the end
junk = defaultdict(int) # key is num, val is count of s.
# Time - O(n)
for i in range(k, len(nums)): # Space - O(n)

if k % 2 == 1: class Solution(object):
medians.append(float(upper[0])) def magicalString(self, n):
else: """
medians.append((upper[0] - lower[0]) / 2.0) :type n: int
:rtype: int
balance = 0 # +ve implies surplus in upper, -ve is surplus in lower """
if n == 0:
if nums[i - k] >= upper[0]: return 0
balance -= 1
else: i = 2 # next index to be processed
balance += 1 s = [1, 2, 2]
junk[nums[i - k]] += 1 ones = 1

if nums[i] >= upper[0]: while len(s) < n:


balance += 1
heapq.heappush(upper, nums[i]) digit = s[-1] ^ 3 # next digits(s) are different from previous end
else:
balance -= 1 s.append(digit)
heapq.heappush(lower, -nums[i]) if s[i] == 2:
s.append(digit)
# balance == +/-2 or 0
# if either heap has a surplus, it's top value cannot be junk if digit == 1:
if balance > 0: ones += s[i]
heapq.heappush(lower, -heapq.heappop(upper))
elif balance < 0: i += 1
heapq.heappush(upper, -heapq.heappop(lower))
if len(s) > n and s[-1] == 1: # added too many ones
while upper and upper[0] in junk: ones -= 1
removed = heapq.heappop(upper) return ones
junk[removed] -= 1
if junk[removed] == 0:
del junk[removed]

# python_1_to_1000/482_License_Key_Formatting.py # Space - O(1)

_author_ = 'jake' import math


_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/license-key-formatting/ def smallestGoodBase(self, n):
# You are given a string S, which represents a software license key which we would like """
to format. The string S is :type n: str
# composed of alphanumerical characters and dashes. The dashes split the alphanumerical :rtype: str
characters within the string """
# into groups. (i.e. if there are M dashes, the string is split into M+1 groups). The n = int(n)
dashes in the given string are
# possibly misplaced. for max_power in range(int(math.log(n, 2)), 1, -1): # largest max_power
# We want each group of characters to be of length K (except for possibly the first implies smallest base
group, which could be shorter, but
# still must contain at least one character). To satisfy this requirement, we will base = int(n ** max_power ** -1) # find the only possible
reinsert dashes. Additionally, all base for this max_power
# the lower case letters in the string must be converted to upper case. if n == ((base ** (max_power + 1)) - 1) // (base - 1): # sum of
# You are given a non-empty string S, representing a license key to format, and an geometric series
integer K. And you need to return str(base)
# return the license key formatted according to the description above.
return str(n - 1) # fallback to base n-1, represents any n as "11"
# Replace "-" by "" and convert to upper case. Append complete blocks of length K to
result working from back of string.
# If any stub append that, reverse blocks and join.
# Time - O(n) # python_1_to_1000/484_Find_Permutation.py - m
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def licenseKeyFormatting(self, S, K):
""" # https://leetcode.com/problems/find-permutation/
:type S: str # You are given a secret signature consisting of character 'D' and 'I'. 'D' represents a
:type K: int decreasing relationship
:rtype: str # between two numbers, 'I' represents an increasing relationship between two numbers. And
""" our secret signature was
key = S.replace("-", "").upper() # constructed by a special integer array, which contains uniquely all the different
formatted = [] number from 1 to n (n is the
# length of the secret signature plus 1).
i = len(key) - K # For example, the secret signature "DI" can be constructed by array [2,1,3] or [3,1,2],
while i >= 0: but won't be constructed by
formatted.append(key[i:i + K]) # array [3,2,4] or [2,1,3,4].
i -= K # Your job is to find the lexicographically smallest permutation of [1, 2, ... n] that
could refer to the given secret
if i != -K: # signature in the input.
formatted.append(key[:i + K])
return "-".join(formatted[::-1]) # Using a stack, iterate over integers i to n - 1, pushing each integer. If the next
letter is "I", we have reached
return "-".join(formatted) # the end of a sequence of "D"s (potentialy of length zero). Pop entire stack and append
to result (hence appearing
# in decreasing order).
# Time - O(n)
# Space - O(n)

# python_1_to_1000/483_Smallest_Good_Base.py - h class Solution(object):


def findPermutation(self, s):
_author_ = 'jake' """
_project_ = 'leetcode' :type s: str
:rtype: List[int]
# https://leetcode.com/problems/smallest-good-base/ """
# For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1. permutation, stack = [], []
# Given a string representing n, you should return the smallest good base of n in string
format. for i in range(1, len(s) + 1):
stack.append(i)
# For base b, n = b**k + b**(k-1) + .. n + 1 for some b and max_power k. if s[i - 1] == "I":
# Try max powers from largest (base 2 = binary representation) down to 2. Since n > while stack:
base**max_power and permutation.append(stack.pop())
# n < (base+1)**max_power, base must be int(n**(1/max_power). Test if true. Fallback to
base n-1. stack.append(len(s) + 1)
# Time - O(log n) while stack:
permutation.append(stack.pop()) if right < left: # base case
return 0
return permutation if right == left: # base case
return nums[left]
if (left, right) in memo:
# python_1_to_1000/485_Max_Consecutive_Ones.py return memo[(left, right)]

_author_ = 'jake' left_right = helper(left + 1, right - 1)


_project_ = 'leetcode' left_left = helper(left + 2, right)
take_left = nums[left] + min(left_right - nums[right], left_left - nums[left
# https://leetcode.com/problems/max-consecutive-ones/ + 1])
# Given a binary array, find the maximum number of consecutive 1s in this array.
right_right = helper(left, right - 2) # reuse left_right
# Iterate over nums. If we see a zero, update max_consecutive and reset consecutive. If take_right = nums[right] + min(left_right - nums[left], right_right -
we see a one, increment nums[right - 1])
# consecutive.
# Time - O(n) result = max(take_left, take_right)
# Space - O(1) memo[(left, right)] = result
return result
class Solution(object):
def findMaxConsecutiveOnes(self, nums): memo = {}
""" return helper(0, len(nums) - 1) >= 0
:type nums: List[int]
:rtype: int
"""
consecutive, max_consecutive = 0, 0 # python_1_to_1000/487_Max_Consecutive_Ones_II.py - m

for num in nums: _author_ = 'jake'


if num == 0: _project_ = 'leetcode'
max_consecutive = max(max_consecutive, consecutive)
consecutive = 0 # https://leetcode.com/problems/max-consecutive-ones-ii/
else: # Given a binary array, find the maximum number of consecutive 1s in this array if you
consecutive += 1 can flip at most one 0.

return max(max_consecutive, consecutive) # check final sequence # Record the start of the current sequence and the start of the previous sequence
(flipping a zero).
# Iterate over array, incrementing sequence end. If two zeros, reset prev_start to
current. If single zero, update max
# python_1_to_1000/486_Predict_the_Winner.py - m # and prev_start to start.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/predict-the-winner/ def findMaxConsecutiveOnes(self, nums):
# Given an array of scores that are non-negative integers. Player 1 picks one of the """
numbers from either end of the :type nums: List[int]
# array followed by the player 2 and then player 1 and so on. Each time a player picks a :rtype: int
number, that number will not """
# be available for the next player. This continues until all the scores have been chosen. max_consecutive = 0
# The player with the maximum score wins. If the scores of both players are equal, then i = 0
player 1 is still the winner. while i < len(nums) and nums[i] == 0: # find first one
# Given an array of scores, predict whether player 1 is the winner. You can assume each i += 1
player maximizes his score. start, prev_start = i, max(i - 1, 0)

# Recursively remove left and right. For each case, find score after worst case next for j in range(i + 1, len(nums)):
opponent move. Take best score of
# each case. Memoize. if nums[j] == 0:
# Time - O(n**2) if j != 0 and nums[j - 1] == 0:
# Space - O(n**2) prev_start = j # prefix new sequence by 1
else:
class Solution(object): max_consecutive = max(max_consecutive, j - prev_start)
def PredictTheWinner(self, nums): prev_start = start # use 1 to fill gap
"""
:type nums: List[int] start = j + 1 # start new sequence at next index
:rtype: bool
""" return max(max_consecutive, len(nums) - prev_start) # cover case of final
sequence
def helper(left, right):

min_balls = min(need + min_end, min_balls)


# python_1_to_1000/488_Zuma_Game.py - h hand[colour] += need # put balls back

_author_ = 'jake' start = end


_project_ = 'leetcode'
end += 1
# https://leetcode.com/problems/zuma-game/
# You have a row of balls on the table, colored red(R), yellow(Y), blue(B), green(G), and return -1 if min_balls == 6 else min_balls
white(W). You also have
# several balls in your hand. hand = Counter(hand)
# Each time, you may choose a ball in your hand, and insert it into the row (including return helper(board)
the leftmost place and
# 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 # python_1_to_1000/489_Robot_Room_Cleaner.py - h
# on the table. If you cannot remove all the balls, output -1.
_author_ = 'jake'
# Iterate over board. When a sequence ends, if enough of same colour in hand to make a _project_ = 'leetcode'
run of 3, add those balls
# from hand and recurse. # https://leetcode.com/problems/robot-room-cleaner/
# Time - T(n) for board of length n = n**2 * T(n-3) since n recursions, each taking n # Given a robot cleaner in a room modeled as a grid.
time to remove_sequences # Each cell in the grid can be empty or blocked.
# then solving sub-problem of length n-3. # The robot cleaner with 4 given APIs can move forward, turn left or turn right. Each
turn it made is 90 degrees.
from collections import Counter # When it tries to move into a blocked cell, its bumper sensor detects the obstacle and
it stays on the current cell.
class Solution(object): # Design an algorithm to clean the entire room using only the 4 given APIs shown below.
def findMinStep(self, board, hand): # boolean move() - returns True if it is possible to move in the current facing direction
""" # void turnLeft()
:type board: str # void turnRight()
:type hand: str # void clean()
:rtype: int
""" # Depth-first search. Each state is a location and direction. Clean the location and add
def remove_sequences(board): # recursively remove any sequences of length 3 or to visited set.
more # For each of the 4 neighbouring cells, if neighbour has not been visited and can be
start, end = 0, 0 moved to, recurse to visit
while end < len(board): # neighbour, then move back to original cell and turn left.
if board[start] == board[end]: # Time - O(mn)
end += 1 # Space - O(mn)
elif end - start >= 3:
return remove_sequences(board[:start] + board[end:]) class Solution:
else: def cleanRoom(self, robot):
start = end """
if end - start >= 3: :type robot: Robot
board = board[:start] :rtype: None
return board """
visited = set()
def helper(board):
if not board: def dfs(x, y, dx, dy):
return 0
if not hand: robot.clean()
return -1 visited.add((x, y))

min_balls = 6 # since len(hand) <= 5 for _ in range(4):


start, end = 0, 0
if ((x + dx, y + dy)) not in visited and robot.move():
while end < len(board) + 1: dfs(x + dx, y + dy, dx, dy)
robot.turnLeft() # revert to original position and direction
if end == len(board) or board[start] != board[end]: robot.turnLeft()
need = 3 - (end - start) # number needed in hand to make a robot.move()
sequence of 3 robot.turnLeft()
colour = board[start] robot.turnLeft()
if hand[colour] >= need:
robot.turnLeft()
hand[colour] -= need dx, dy = -dy, dx
next_board = remove_sequences(board[:start] + board[end:])
min_end = helper(next_board) dfs(0, 0, 0, 1)
if min_end != -1:
class Solution(object):
# python_1_to_1000/490_The_Maze.py - m def findSubsequences(self, nums):
"""
_author_ = 'jake' :type nums: List[int]
_project_ = 'leetcode' :rtype: List[List[int]]
"""
# https://leetcode.com/problems/the-maze/ subsequences = set()
# There is a ball in a maze with empty spaces and walls. The ball can go through empty
spaces by rolling up, down, for num in nums:
# left or right, but it won't stop rolling until hitting a wall. When the ball stops, it new_subsequences = set()
could choose the next direction. new_subsequences.add((num,))
# Given the ball's start position, the destination and the maze, determine whether the for s in subsequences:
ball can stop at the destination. if num >= s[-1]:
# The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty new_subsequences.add(s + (num,)) # tuple not list so can store in
space. You may assume that the set
# borders of the maze are all walls. The start and destination coordinates are
represented by row and column indexes. subsequences |= new_subsequences

# DFS. Maintain queue of stopping points. For the next point, move in all 4 directions to return [s for s in subsequences if len(s) > 1] # convert to list and filter out
find next stopping points. if too short
# Store visisted points to avoid repetition.
# Time - O(m * n)
# Space - O(m * n) # python_1_to_1000/492_Construct_the_Rectangle.py

class Solution(object): _author_ = 'jake'


def hasPath(self, maze, start, destination): _project_ = 'leetcode'
"""
:type maze: List[List[int]] # https://leetcode.com/problems/construct-the-rectangle/
:type start: List[int] # For a web developer, it is very important to know how to design a web page's size.
:type destination: List[int] # So, given a specific rectangular web page’s area, your job by now is to design a
:rtype: bool rectangular web page, whose
""" # length L and width W satisfy the following requirements:
queue = [start] # 1. The area of the rectangular web page you designed must equal to the given target
dirns = ((1, 0), (-1, 0), (0, 1), (0, -1)) area.
visited = set() # 2. The width W should not be larger than the length L, which means L >= W.
# 3. The difference between length L and width W should be as small as possible.
while queue: # You need to output the length L and the width W of the web page you designed in
start_r, start_c = queue.pop() sequence.
visited.add((start_r, start_c))
# Find the largest integer less than or equal to the square root of the area that divides
for dr, dc in dirns: the area. Try the integer
r, c = start_r, start_c # move as far as possible # less than or equal to the square root and if it does not divide area, decrement until
while 0 <= r + dr < len(maze) and 0 <= c + dc < len(maze[0]) and maze[r + it does.
dr][c + dc] == 0: # Time - O(area**0.5)
r += dr # Space - O(1)
c += dc
class Solution(object):
if (r, c) not in visited: def constructRectangle(self, area):
if [r, c] == destination: """
return True :type area: int
queue.append((r, c)) # DFS since add to end of queue :rtype: List[int]
"""
return False side = int(area ** 0.5)

while area % side != 0: # decrement to find shorter side, faster than


# python_1_to_1000/491_Increasing_Subsequences.py - m increment to find longer side
side -= 1
_author_ = 'jake'
_project_ = 'leetcode' return [area // side, side]

# https://leetcode.com/problems/increasing-subsequences/
# Given an integer array, your task is to find all the different possible increasing
subsequences of the given array, # python_1_to_1000/493_Reverse_Pairs.py - h
# and the length of an increasing subsequence should be at least 2 .
_author_ = 'jake'
# For each number, create a set of subsequences by extending all previous subsequences. _project_ = 'leetcode'
# Time - O(n**4), sum from i = 1 to n of i**3
# Space - O(n**3), n**2 subsequences of length n # https://leetcode.com/problems/reverse-pairs/

# Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] >
2*nums[j].
# You need to return the number of important reverse pairs in the given array. class Solution(object):
def findTargetSumWays(self, nums, S):
# Mergesort. Before merge, count reversed pairs in sorted left and right lists. """
# Time - O(n log n) :type nums: List[int]
# Space - O(n log n) :type S: int
:rtype: int
class Solution(object): """
def reversePairs(self, nums): sums = defaultdict(int)
""" sums[0] = 1
:type nums: List[int] running = nums[:] # calc remaining sum from each index
:rtype: int
""" for i in range(len(nums) - 2, -1, -1):
self.pairs = 0 running[i] += running[i + 1]

def mergesort(nums): for i, num in enumerate(nums):


if len(nums) < 2:
return nums new_sums = defaultdict(int)
for old_sum in sums:
mid = len(nums) // 2 if S <= old_sum + running[i]: # add to neew_sums if not too large
left = mergesort(nums[:mid]) new_sums[old_sum + num] += sums[old_sum]
right = mergesort(nums[mid:]) if S >= old_sum - running[i]:
return merge(left, right) new_sums[old_sum - num] += sums[old_sum]
sums = new_sums
def merge(left, right):
j = 0 if S not in sums:
for num in left: return 0
while j < len(right) and num > 2 * right[j]: return sums[S]
j += 1
self.pairs += j # num is greater than right[j-1] and lower
# python_1_to_1000/495_Teemo_Attacking.py
# return sorted(left + right) is faster than manual merge below
merged = [] _author_ = 'jake'
i, j = 0, 0 _project_ = 'leetcode'
while i < len(left) and j < len(right):
if left[i] < right[j]: # https://leetcode.com/problems/teemo-attacking/
merged.append(left[i]) # In LOL world, there is a hero called Teemo and his attacking can make his enemy Ashe be
i += 1 in poisoned condition.
else: # Now, given the Teemo's attacking ascending time series towards Ashe and the poisoning
merged.append(right[j]) time duration per Teemo's
j += 1 # attacking, you need to output the total time that Ashe is in poisoned condition.
# You may assume that Teemo attacks at the very beginning of a specific time point, and
return merged + left[i:] + right[j:] makes Ashe be in poisoned condition immediately.

mergesort(nums) # For each time step, add min of the step and duration.
return self.pairs # Time - O(n)
# Space - O(1)

class Solution(object):
def findPoisonedDuration(self, timeSeries, duration):
# python_1_to_1000/494_Target_Sum.py - m """
:type timeSeries: List[int]
_author_ = 'jake' :type duration: int
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/target-sum/ poisoned = 0
# You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now timeSeries.append(float("inf"))
you have 2 symbols + and -. for i in range(1, len(timeSeries)):
# For each integer, you should choose one from + and - as its new symbol. poisoned += min(duration, timeSeries[i] - timeSeries[i- 1])
# Find out how many ways to assign symbols to make sum of integers equal to target S. return poisoned

# Keep count of frequency of all possible sums that could reach target in dictionary. For
each num, increment and # python_1_to_1000/496_Next_Greater_Element_I.py
# decreement all sums, removing those that cannot reach target.
# Time - O(2**(n+1)) _author_ = 'jake'
# Space - O(2**n) _project_ = 'leetcode'

from collections import defaultdict # https://leetcode.com/problems/next-greater-element-i/


# You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements
are subset of nums2. class Solution(object):
# Find all the next greater numbers for nums1's elements in the corresponding places of
nums2. def __init__(self, rects):
# The Next Greater Number of a number x in nums1 is the first greater number to its right """
in nums2. :type rects: List[List[int]]
# If it does not exist, output -1 for this number. """
self.cumul_area = [0] # cumul_area[i] == sum of areas of rects[:i]
# Map the integers to be found to their indices in the result. Iterate over nums2, self.x_dimensions = [0] # x_dimensions[i] == rects[i - 1][2] - rects[i - 1]
maintaining a stack of nums seen [0]
# without a greater number, hence stack is descending. For each num, pop from stack all self.rects = rects
smaller nums and update the
# result if they are in nums1. Add each num to stack. for x1, y1, x2, y2 in rects:
# Time - O(n) len(nums2) x_dim, y_dim = x2 - x1 + 1, y2 - y1 + 1
# Space - O(m) len(nums1) self.x_dimensions.append(x_dim)
self.cumul_area.append(self.cumul_area[-1] + x_dim * y_dim)
class Solution(object):
def nextGreaterElement(self, nums1, nums2): def pick(self):
""" """
:type findNums: List[int] :rtype: List[int]
:type nums: List[int] """
:rtype: List[int] n = random.randint(1, self.cumul_area[-1]) # random n in [1, total area]
""" i = bisect.bisect_left(self.cumul_area, n) # index of chosen rectangle
result = [-1] * len(nums1) # default -1 if not overwritten n -= (self.cumul_area[i - 1] + 1) # point in rectangle

find_to_i = {} # key is num to be found, value dy, dx = divmod(n, self.x_dimensions[i]) # convert n to dx, dy
is index x, y = self.rects[i - 1][:2]
for i, num in enumerate(nums1): return [x + dx, y + dy]
find_to_i[num] = i

stack = [] # python_1_to_1000/498_Diagonal_Traverse.py - m
for num in nums2:
while stack and num > stack[-1]: # num is first greater than top _author_ = 'jake'
of stack _project_ = 'leetcode'
smaller = stack.pop()
if smaller in find_to_i: # https://leetcode.com/problems/diagonal-traverse/
result[find_to_i[smaller]] = num # Given a matrix of M x N elements (M rows, N columns), return all elements of the matrix
stack.append(num) in diagonal order as shown
# below. Input:
return result # [
# [ 1, 2, 3 ],
# [ 4, 5, 6 ],
# [ 7, 8, 9 ]
# python_1_to_1000/497_Random_Point_in_Non-overlapping_Rectangles.py - m # ]
# Output: [1,2,4,7,5,3,6,8,9]
_author_ = 'jake'
_project_ = 'leetcode' # Boolan up_right determines direction of travel. Reverse when reach an edge.
# Time - O(mn)
# https://leetcode.com/problems/random-point-in-non-overlapping-rectangles/ # Space - O(1)
# Given a list of non-overlapping axis-aligned rectangles rects, write a function pick
which randomly and uniformly class Solution(object):
# picks an integer point in the space covered by the rectangles. def findDiagonalOrder(self, matrix):
# An integer point is a point that has integer coordinates. """
# A point on the perimeter of a rectangle is included in the space covered by the :type matrix: List[List[int]]
rectangles. :rtype: List[int]
# ith rectangle = rects[i] = [x1,y1,x2,y2], where [x1, y1] are the integer coordinates of """
the bottom-left corner, diagonal = []
# and [x2, y2] are the integer coordinates of the top-right corner. if not matrix or not matrix[0]:
return diagonal
# Create a list of the cumulative areas of the rectangles. Choose random n in [1, total
area] and find the rows, cols = len(matrix), len(matrix[0])
# corresponding rectangle by binary search of the cumulative list. Subtract the areas of up_right = True
all previous rectangles r, c = 0, 0
# to get a point in the rectangle, which is converteed to an x, y coordinate by divide
and modulo. while len(diagonal) < rows * cols:
# Time - O(n) for __init__, O(log n) for pick
# Space - O(n) diagonal.append(matrix[r][c])

import bisect, random if up_right:

if c == cols - 1: # right edge, move down 1 row


r += 1 def vertical(dirn):
up_right = False # top edge, move across 1 column return dirn in {"d", "u"}
elif r == 0:
c += 1 def perpendicular(dirn):
up_right = False return ["r", "l"] if vertical(dirn) else ["u", "d"] # reverse
else: lexicographical order
r -= 1
c += 1 visited = set() # stores tuples (r, c, dirn)
queue = deque()
else: dirns = {"d": (1, 0), "u": (-1, 0), "r": (0, 1), "l": (0, -1)}
if r == rows - 1: # bottom edge, move across 1 column for dirn in "dlru":
c += 1 queue.append((ball[0], ball[1], [dirn]))
up_right = True
elif c == 0: # left edge, move down 1 row while queue:
r += 1 r, c, moves = queue.popleft()
up_right = True if (r, c, moves[-1]) in visited:
else: continue
r += 1 visited.add((r, c, moves[-1]))
c -= 1
dr, dc = dirns[moves[-1]]
return diagonal nm = maze_cell(r + dr, c + dc)

if nm == -1:
# python_1_to_1000/499_The_Maze_III.py - h return "".join(moves)

_author_ = 'jake' # move in same direction as previous if possible


_project_ = 'leetcode' elif nm == 0:
queue.append((r + dr, c + dc, moves)) # add to back of queue
# 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 # else move in a perpendicular direction if possible and not at start
spaces by rolling up (u), elif [r, c] != ball:
# down (d), left (l) or right (r), but it won't stop rolling until hitting a wall. When trial_dirns = perpendicular(moves[-1])
the ball stops, it could choose for trial_dirn in trial_dirns:
# the next direction. There is also a hole in this maze. The ball will drop into the hole queue.appendleft((r, c, moves + [trial_dirn])) # add to front of
if it rolls on to the hole. queue
# Given the ball position, the hole position and the maze, find out how the ball could
drop into the hole by moving return "impossible"
# the shortest distance. The distance is defined by the number of empty spaces traveled
by the ball from the start
# 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 # python_1_to_1000/500_Keyboard_Row.py
smallest way.
# If the ball cannot reach the hole, output "impossible". _author_ = 'jake'
_project_ = 'leetcode'
# Deque stores positions and previous direction. If can move in same direction, add to
back of deque. If cannot, try # https://leetcode.com/problems/keyboard-row/
# to move in perpendicular directions by adding to front of deque. # Given a List of words, return the words that can be typed using letters of alphabet on
# Time - O(mn) only one row of a keyboard.
# Space - O(mn)
# Map each of the 26 keys to its row. Iterate over word, setting the row of the first
from collections import deque char and checking that the rows
# of all other characters are the same as the first.
class Solution(object): # Time - O(n) total number of characters in words.
def findShortestWay(self, maze, ball, hole): # Space - O(1) excluding result.
"""
:type maze: List[List[int]] class Solution(object):
:type ball: List[int] def findWords(self, words):
:type hole: List[int] """
:rtype: str :type words: List[str]
""" :rtype: List[str]
"""
def maze_cell(r, c): keyboard = {}
if [r, c] == hole: rows = ["qwertyuiop", "asdfghjkl", "zxcvbnm"]
return -1 for i, row in enumerate(rows):
elif 0 <= r < len(maze) and 0 <= c < len(maze[0]) and maze[r][c] == 0: for c in row:
return 0 keyboard[c] = i
return 1
result = [] self.mode_count = self.count # new unique mode
modes.clear() # Python 3.3+, else pop until empty or
for word in words: use instance variable
row = -1 modes.append(node.val)

for c in word: inorder(node.right)


if row == -1: # set the row of first char
row = keyboard[c.lower()] inorder(root)
elif keyboard[c.lower()] != row: # compare to previous rows return modes
break
else:
result.append(word)
# python_1_to_1000/502_IPO.py - h
return result
_author_ = 'jake'
_project_ = 'leetcode'

# python_1_to_1000/501_Find_Mode_in_Binary_Search_Tree.py # https://leetcode.com/problems/ipo/
# Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares
_author_ = 'jake' to Venture Capital, LeetCode
_project_ = 'leetcode' # would like to work on some projects to increase its capital before the IPO. Since it
has limited resources, it can
# https://leetcode.com/problems/find-mode-in-binary-search-tree/ # only finish at most k distinct projects before the IPO. Help LeetCode design the best
# Given a binary search tree (BST) with duplicates, find all the mode(s) (the most way to maximize its total
frequent elements) in the BST. # capital after finishing at most k distinct projects.
# Assume a BST is defined as follows: # You are given several projects. For each project i, it has a pure profit Pi and a
# The left subtree of a node contains only nodes with keys less than or equal to the minimum capital of Ci is needed to
node's key. # start the corresponding project. Initially, you have W capital. When you finish a
# The right subtree of a node contains only nodes with keys greater than or equal to the project, you will obtain its pure
node's key. # profit and the profit will be added to your total capital.
# Both the left and right subtrees must also be binary search trees. # To sum up, pick a list of at most k distinct projects from given projects to maximize
your final capital, and output
# Inorder traversal visiting each node in sorted order. If a node value is the same as # your final maximized capital.
the previous node value then
# extend the current sequence. Else start a new sequence. If a sequence has the same # Sort projects in increasing order of capital required. Add all projects available with
count as the previous mode then current capital to heap. Pop
# add the value to the mode list. If a sequence has a greater count than the previous # from heap project with most profit.
mode then value is the only mode. # Time - O(n log n)
# Time - O(n) # Space - O(n)
# Space - O(n) if all values are unique.
import heapq
class Solution(object):
def findMode(self, root): class Solution(object):
""" def findMaximizedCapital(self, k, W, Profits, Capital):
:type root: TreeNode """
:rtype: List[int] :type k: int
""" :type W: int
self.prev = float("inf") :type Profits: List[int]
self.count = 0 :type Capital: List[int]
self.mode_count = 0 :rtype: int
modes = [] # mutable, not an instance variable """
projects = sorted(zip(Capital, Profits))
def inorder(node):
i = 0
if not node: # base case available = [] # profits of projects requiring at most current capital W
return
while k > 0:
inorder(node.left) # recurse left
while i < len(projects) and projects[i][0] <= W:
if node.val == self.prev: # extend sequence of same value heapq.heappush(available, -projects[i][1])
self.count += 1 i += 1
else:
self.prev = node.val # start new sequence if not available: # cannot do any projects
self.count = 1 return W
best_profit = heapq.heappop(available)
if self.count == self.mode_count:
modes.append(node.val) # another mode with same count as existing W -= best_profit
mode(s) k -= 1
elif self.count > self.mode_count:

return W
while num:
num, digit = divmod(num, 7)
# python_1_to_1000/503_Next_Greater_Element_II.py - m base_7.append(str(digit))

_author_ = 'jake' if negative:


_project_ = 'leetcode' base_7.append("-")

# https://leetcode.com/problems/next-greater-element-ii/ return "".join(base_7[::-1]) or "0" # base_7 is empty if num == 0


# Given a circular array (the next element of the last element is the first element of
the array), print the Next
# Greater Number for every element. The Next Greater Number of a number x is the first # python_1_to_1000/505_The_Maze_II.py - m
greater number to its
# traversing-order next in the array, which means you could search circularly to find its _author_ = 'jake'
next greater number. _project_ = 'leetcode'
# If it doesn't exist, output -1 for this number.
# https://leetcode.com/problems/the-maze-ii/
# Stack holds indices of numbers without greater element, hence decreasing order. Pop of # There is a ball in a maze with empty spaces and walls. The ball can go through empty
all numbers lower than spaces by rolling up, down,
# current and set their next_greater to current. Repeat iteration over nums to account # left or right, but it won't stop rolling until hitting a wall. When the ball stops, it
for circularity. can choose the next direction.
# Time - O(n) # Given the ball's start position, the destination and the maze, find the shortest
# Space - O(n) distance for the ball to stop at the
# destination. The distance is defined by the number of empty spaces traveled by the ball
class Solution(object): from the start position
def nextGreaterElements(self, nums): # (excluded) to the destination (included). If the ball cannot stop at the destination,
""" return -1.
:type nums: List[int] # The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty
:rtype: List[int] space. You may assume that the
""" # borders of the maze are all walls. The start and destination coordinates are
n = len(nums) represented by row and column indexes.
stack = [] # indices whose nums form decreasing sequence
next_greater = [-1] * n # default -1 if no greater # BFS. If can move in same direction, add to new_queue. Else check if solution, move
perpendicular. Memoize visited
for i in range(2 * n): # locations and directions.
num = nums[i % n] # wrap around # Time - O(mn)
while stack and num > nums[stack[-1]]: # Space - O(mn)
next_greater[stack.pop()] = num
if i < n: class Solution(object):
stack.append(i) def shortestDistance(self, maze, start, destination):
"""
return next_greater :type maze: List[List[int]]
:type start: List[int]
:type destination: List[int]
:rtype: int
# python_1_to_1000/504_Base_7.py """
rows, cols = len(maze), len(maze[0])
_author_ = 'jake' distance = 0
_project_ = 'leetcode' visited = set()
dirns = {"u": (-1, 0), "d": (1, 0), "l": (0, -1), "r": (0, 1)}
# https://leetcode.com/problems/base-7/ perps = {"u": ("l", "r"), "d": ("l", "r"), "l": ("u", "d"), "r": ("u", "d")}
# Given an integer, return its base 7 string representation. queue = [(start[0], start[1], d) for d in dirns]

# Record if num is negative and convert to positive. Repeatedly divide by 7 and add digit while queue:
to result. Result is in
# reverse order with least significant digit first. Add leading minus sign is negative, new_queue = []
reverse list and join.
# Time - O(log n) while queue:
# Space - O(log n)
r, c, dirn = queue.pop()
class Solution(object): if ((r, c, dirn)) in visited:
def convertToBase7(self, num): continue
""" visited.add((r, c, dirn))
:type num: int
:rtype: str dr, dc = dirns[dirn]
""" if 0 <= r + dr < rows and 0 <= c + dc < cols and maze[r + dr][c + dc] ==
negative = num < 0 # flag for negative num 0:
num = abs(num) new_queue.append((r + dr, c + dc, dirn))
base_7 = [] else:
if [r, c] == destination:
return distance import math
perp = perps[dirn]
for new_dirn in perp: class Solution(object):
queue.append((r, c, new_dirn)) def checkPerfectNumber(self, num):
"""
distance += 1 :type num: int
queue = new_queue :rtype: bool
"""
return -1 if num <= 1: # negative, 0 and 1 are not
perfect
return False

sum_divisors = 1
# python_1_to_1000/506_Relative_Ranks.py
for i in range(2, int(math.sqrt(num)) + 1): # sqrt slightly faster than
_author_ = 'jake' num**0.5
_project_ = 'leetcode'
div, mod = divmod(num, i)
# https://leetcode.com/problems/relative-ranks/ if mod == 0:
# Given scores of N athletes, find their relative ranks and the people with the top three sum_divisors += i + div
highest scores, who will be
# awarded medals: "Gold Medal", "Silver Medal" and "Bronze Medal". return sum_divisors == num

# Create a list of tuples of num and its index in nums. Sort descending by num. Iterate
over list, setting result # python_1_to_1000/508_Most_Frequent_Subtree_Sum.py - m
# with medals for the first 3 then rank as a string for others.
# Time - O(n log n) _author_ = 'jake'
# Space - O(n) _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/most-frequent-subtree-sum/


def findRelativeRanks(self, nums): # Given the root of a tree, you are asked to find the most frequent subtree sum. The
""" subtree sum of a node is defined
:type nums: List[int] # as the sum of all the node values formed by the subtree rooted at that node (including
:rtype: List[str] the node itself). So what is
""" # the most frequent subtree sum value? If there is a tie, return all the values with the
num_i = [(num, i) for i, num in enumerate(nums)] highest frequency in any order.
num_i.sort(reverse=True)
# Bottom-up recursion finding sum for each each subtree and adding to counter. Find max
result = [None for _ in range(len(nums))] value of counter then find
medals = ["Gold", "Silver", "Bronze"] # all keys with max value.
# Time - O(n)
for rank, (_, i) in enumerate(num_i): # Space - O(n)
if rank < 3: # best ranked 3 get medals
result[i] = medals[rank] + " Medal" from collections import defaultdict
else:
result[i] = str(rank + 1) # add 1 since enumeration is from class Solution(object):
zero def findFrequentTreeSum(self, root):
"""
return result :type root: TreeNode
:rtype: List[int]
"""

# python_1_to_1000/507_Perfect_Number.py def count_sums(node):


if not node:
_author_ = 'jake' return 0
_project_ = 'leetcode'
total_sum = node.val + count_sums(node.left) + count_sums(node.right)
# https://leetcode.com/problems/perfect-number/ tree_sums[total_sum] += 1
# We define a Perfect Number as a positive integer that is equal to the sum of all its
positive divisors except itself. return total_sum
# Now, given an integer n, write a function that returns true when it is a perfect number
and false when it is not. if not root:
return []
# Check all divisor integers up to and including sqrt(num). If divisor has no remainder, tree_sums = defaultdict(int)
add divisor and result of count_sums(root)
# division.
# Time - O(n**0.5) max_sum = max(tree_sums.values())
# Space - O(1) result = []

for key, val in tree_sums.items(): class Solution(object):


if val == max_sum: def inorderSuccessor(self, node):
result.append(key) """
return result :type node: Node
:rtype: Node
"""
# python_1_to_1000/509_Fibonacci_Number.py if node.right:
node = node.right # move right
_author_ = 'jake' while node.left:
_project_ = 'leetcode' node = node.left # then as far left as possible
return node
# https://leetcode.com/problems/fibonacci-number/
# The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci while node.parent and node == node.parent.right:
sequence, such that each number node = node.parent
# is the sum of the two preceding ones, starting from 0 and 1. That is, return node.parent
# F(0) = 0, F(1) = 1
# F(N) = F(N - 1) + F(N - 2), for N > 1.
# Given N, calculate F(N).
# python_1_to_1000/513_Find_Bottom_Left_Tree_Value.py - m
# Iterate N times, storing anf updating the last 2 numbers of the sequence.
# Time - O(n) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'

class Solution: # https://leetcode.com/problems/find-bottom-left-tree-value/


def fib(self, N): # Given a binary tree, find the leftmost value in the last row of the tree.
"""
:type N: int # BFS from right to left so final node is left most.
:rtype: int # Time - O(n)
""" # Space - O(n)
i, j = 0, 1
for _ in range(N): from collections import deque
i, j = j, i + j
class Solution(object):
return i def findBottomLeftValue(self, root):
"""
:type root: TreeNode
:rtype: int
# python_1_to_1000/510_Inorder_Successor_in_BST_II.py - m """
queue = deque([root])
_author_ = 'jake'
_project_ = 'leetcode' while queue:
node = queue.popleft()
# https://leetcode.com/problems/inorder-successor-in-bst-ii/ if node.right:
# Given a binary search tree and a node in it, find the in-order successor of that node queue.append(node.right)
in the BST. if node.left:
# The successor of a node p is the node with the smallest key greater than p.val. queue.append(node.left)
# 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. return node.val

# We want to perform the next visit in an inorder traversal from a given starting node.
There are 2 cases: # python_1_to_1000/514_Freedom_Trail.py - h
# 1) If the starting node has a right child we move to the right child then repeatedly
moves to the left child. _author_ = 'jake'
# When inorder(node.left) returns, there is no left child and we have found the _project_ = 'leetcode'
successor.
# 2) Otherwise (no starting node right child) the next node visited is after returning to # https://leetcode.com/problems/freedom-trail/
the parent. # In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a
# We move up the tree until we find a node that is the left child of its parent. The metal dial called the "Freedom
parent is then the successor. # Trail Ring", and use the dial to spell a specific keyword in order to open the door.
# The first case is when the successor is further down the tree and within the subtree # Given a string ring, which represents the code engraved on the outer ring and another
rooted at the starting node. string key, which represents
# In the second case we must move up the tree. # the keyword needs to be spelled. You need to find the minimum number of steps in order
# Note that there may be no node that is a left child of its parent, to spell all the characters
# in which case we have the last node of the inorder traversal (highest value) which has # in the keyword.
no successor. # Initially, the first character of the ring is aligned at 12:00 direction. You need to
spell all the characters in
# Time - O(n) # the string key one by one by rotating the ring clockwise or anticlockwise to make each
# Space - O(1) character of the string key
# 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]:
# You can rotate the ring clockwise or anticlockwise one place, which counts as 1 step. class Solution(object):
The final purpose of the def largestValues(self, root):
# rotation is to align one of the string ring's characters at the 12:00 direction, where """
this character must equal to :type root: TreeNode
# the character key[i]. :rtype: List[int]
# If the character key[i] has been aligned at the 12:00 direction, you need to press the """
center button to spell, which result = []
# also counts as 1 step. After the pressing, you could begin to spell the next character if not root:
in the key (next stage), return []
# otherwise, you've finished all the spelling. queue = [root]

# For each char of key, for all indices in ring of this char, calculate the min distance while queue:
to reach that index from new_queue = []
# every index of previous char. Store min distances to previous char in dictionary. max_val = float("-inf")
# Time - O(k * r**2) where k is length of k and r is length of ring for node in queue:
# Space - O(r) max_val = max(max_val, node.val)
if node.left:
from collections import defaultdict new_queue.append(node.left)
if node.right:
class Solution(object): new_queue.append(node.right)
def findRotateSteps(self, ring, key):
""" result.append(max_val)
:type ring: str queue = new_queue
:type key: str
:rtype: int return result
"""

def dist(i, j): # python_1_to_1000/516_Longest_Palindromic_Subsequence.py - m


return min(abs(i - j), len(ring) - abs(i - j))

char_to_ring = defaultdict(list) # key is char, values is list of indices in _author_ = 'jake'


ring of that char _project_ = 'leetcode'
for i, c in enumerate(ring):
char_to_ring[c].append(i) # https://leetcode.com/problems/longest-palindromic-subsequence/
# Given a string s, find the longest palindromic subsequence's length in s. You may
i_to_steps = {0: 0} # key is index in ring, value is to min steps to reach char assume that the maximum length
at that index # of s is 1000.
for k in key:
# Dynamic progrmming. Iterate over lengths. If end chars of substring of s of length l
new_i_to_steps = {} starting at index i are same,
new_indices = char_to_ring[k] # indices in ring with next required character # max length is 2 + max length without end chars. Else take max of leaving off one end
of key char.
for new_i in new_indices: # Time - O(n**2)
# Space - O(n)
min_steps = float("inf")
for i in i_to_steps: class Solution(object):
min_steps = min(min_steps, i_to_steps[i] + dist(i, new_i)) def longestPalindromeSubseq(self, s):
new_i_to_steps[new_i] = min_steps """
:type s: str
i_to_steps = new_i_to_steps :rtype: int
"""
return min(i_to_steps.values()) + len(key) # add button press step for each n = len(s)
char if s == s[::-1]: # early return for palindromes
return n

subsequence_2 = [0 for _ in range(n)] # subsequences of length - 2 for each


# python_1_to_1000/515_Find_Largest_Value_in_Each_Tree_Row.py - m starting index
subsequence_1 = [1 for _ in range(n)] # subsequences of length - 1 for each
_author_ = 'jake' starting index
_project_ = 'leetcode'
for length in range(2, n + 1):
# https://leetcode.com/problems/find-largest-value-in-each-tree-row/ subsequence = []
# You need to find the largest value in each row of a binary tree. for i in range(0, n - length + 1):

# BFS. Queue of all nodes by row. Iterate over queue, updating row max and generating if s[i] == s[i + length - 1]:
next row. subsequence.append(2 + subsequence_2[i + 1])
# Time - O(n) else:
# Space - O(n) subsequence.append(max(subsequence_1[i], subsequence_1[i + 1]))

# Time - O(mn) where m is the amount and n nis the number of coins
subsequence_2 = subsequence_1 # Space - O(m)
subsequence_1 = subsequence
class Solution(object):
return subsequence[0] def change(self, amount, coins):
"""
:type amount: int
:type coins: List[int]
# python_1_to_1000/517_Super_Washing_Machines.py - h :rtype: int
"""
_author_ = 'jake' dp = [0 for _ in range(amount + 1)] # dp[i] nb ways to make i using no
_project_ = 'leetcode' coins
dp[0] = 1 # one way to make amount of zero
# https://leetcode.com/problems/super-washing-machines/
# You have n super washing machines on a line. Initially, each washing machine has some for coin in coins:
dresses or is empty.
# For each move, you could choose any m (1 ? m ? n) washing machines, and pass one dress for i in range(coin, amount + 1):
of each washing machine to one dp[i] += dp[i - coin]
# of its adjacent washing machines at the same time .
# Given an integer array representing the number of dresses in each washing machine from return dp[-1]
left to right on the line,
# you should find the minimum number of moves to make all the washing machines have the
same number of dresses. # python_1_to_1000/519_Random_Flip_Matrix.py - m
# If it is not possible to do it, return -1.
_author_ = 'jake'
# Max of max positive balance on any machine, and max imbalance from any machine to the _project_ = 'leetcode'
next (since dresses must flow
# to correct that imbalance). # https://leetcode.com/problems/random-flip-matrix/
# Time - O(n) # You are given the number of rows n_rows and number of columns n_cols of a 2D binary
# Space - O(1) matrix where all values are
# initially 0. Write a function flip which chooses a 0 value uniformly at random, changes
class Solution(object): it to 1,
def findMinMoves(self, machines): # and then returns the position [row.id, col.id] of that value.
""" # Also, write a function reset which sets all values back to 0.
:type machines: List[int] # Try to minimize the number of calls to system's Math.random() and optimize the time and
:rtype: int space complexity.
"""
dresses = sum(machines) # Reduce 2D matrix to a 1D list of length rows * cols. For every random choice, increment
if dresses % len(machines) != 0: # early return if not possible the start index in the list
return -1 # and map the used number to an unused number that is now outside the [start, end] range.
If random choice has been
target = dresses // len(machines) # used already, get its mapping instead.
moves, running = 0, 0 # If x has been chosen before use it
machines = [m - target for m in machines] # Time - O(1)
# Space - O(k) number of calls to flip()
for machine in machines:
running += machine import random
# max of the net imbalance for any split point and the positive balance on
the current machine class Solution(object):
moves = max(moves, abs(running), machine)
def __init__(self, n_rows, n_cols):
return moves """
:type n_rows: int
:type n_cols: int
# python_1_to_1000/518_Coin_Change_2.py - m """
self.start, self.end = 0, n_rows * n_cols - 1
_author_ = 'jake' self.used_to_free = {} # map chosen random ints to an unchosen ints outside
_project_ = 'leetcode' [start, end]
self.cols = n_cols
# https://leetcode.com/problems/coin-change-2/
# You are given coins of different denominations and a total amount of money. def flip(self):
# Write a function to compute the number of combinations that make up that amount. """
# You may assume that you have infinite number of each kind of coin. :rtype: List[int]
"""
# Dynamic programming. List stores the number of ways to make each amount. Use each coin x = random.randint(self.start, self.end)
in turn. index = self.used_to_free.get(x, x) # returned index is x if not used,
# For each amount >= the coin value, increment the number of ways to make that amount else mapping of x
with the number of ways to self.used_to_free[x] = self.used_to_free.get(self.start, self.start) # map x to
# make the amount - coin value. start or mapping of start
self.start += 1 # The input will be two strings, and the output needs to be the length of the longest
return list(divmod(index, self.cols)) # convert index to 2d coordinates uncommon subsequence.
# If the longest uncommon subsequence doesn't exist, return -1.
def reset(self):
""" # If the strings are identical then there is no uncommon subsequence. Else the longer
:rtype: void string cannot be a subsequence of
""" # the shorter. If strings are same length but not identical they are uncommon
self.start = 0 subsequences of each other.
self.used_to_free = {} # Time - O(m + n)
# Space - O(1)

# python_1_to_1000/520_Detect_Capital.py class Solution(object):


def findLUSlength(self, a, b):
_author_ = 'jake' """
_project_ = 'leetcode' :type a: str
:type b: 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 if a == b:
holds: return -1
# All letters in this word are capitals, like "USA". return max(len(a), len(b))
# All letters in this word are not capitals, like "leetcode".
# Only the first letter in this word is capital if it has more than one letter, like
"Google".
# Otherwise, we define that this word doesn't use capitals in a right way. # python_1_to_1000/522_Longest_Uncommon_Subsequence_II.py - m

# For the first and second letter, the only disallowed combination is lower case then _author_ = 'jake'
upper case. All letter after _project_ = 'leetcode'
# the second character must be the same case as the second character.
# Time - O(n) # https://leetcode.com/problems/longest-uncommon-subsequence-ii/
# Space - O(1) # Given a list of strings, you need to find the longest uncommon subsequence among them.
The longest uncommon
class Solution(object): # subsequence is defined as the longest subsequence of one of these strings and this
def detectCapitalUse(self, word): subsequence should not be any
""" # subsequence of the other strings.
:type word: str # A subsequence is a sequence that can be derived from one sequence by deleting some
:rtype: bool characters without changing the
""" # order of the remaining elements. Trivially, any string is a subsequence of itself and
if len(word) <= 1: # empty string or single letter an empty string is a
return True # subsequence of any string.
# The input will be a list of strings, and the output needs to be the length of the
first = word[0] <= "Z" longest uncommon subsequence.
second = word[1] <= "Z" # If the longest uncommon subsequence doesn't exist, return -1.
if not first and second: # first is not capital but second is
return False # COunrt freq of each string. Sort list of keys by decreasing length. If key is not
unique, add to seen set. Else if
for c in word[2:]: # not a subsequence of any string already seen, return its length.
if (c <= "Z") != second: # Time - O(s * n**2) where s is max length of string and n is number of strings
return False # Space - O(sn)

return True from collections import Counter

class Solution(object):
# python_1_to_1000/521_Longest_Uncommon_Subsequence_I.py - m def findLUSlength(self, strs):
"""
_author_ = 'jake' :type strs: List[str]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/longest-uncommon-subsequence-i/ def is_subsequence(s, t): # return True if s is a subsequence of t
# Given a group of two strings, you need to find the longest uncommon subsequence of this i, j = 0, 0
group of two strings. while i < len(s) and j < len(t):
# The longest uncommon subsequence is defined as the longest subsequence of one of these if s[i] == t[j]:
strings and this subsequence i += 1
# should not be any subsequence of the other strings. j += 1
# A subsequence is a sequence that can be derived from one sequence by deleting some if i == len(s):
characters without changing the return True
# order of the remaining elements. Trivially, any string is a subsequence of itself and return False
an empty string is a
# subsequence of any string. counts = Counter(strs)

unique_strs = list(counts.keys()) string.


unique_strs.sort(key=len, reverse=True)
seen = set() # Sort by length then by lexicogrphic order. For each string from longest, test if is a
subsequence of s.
for s in unique_strs: # Time - O(mn + knlogn) where knlogn is time taken to sort for n strings and s is of
length m
if counts[s] == 1: # Space - O(1)
if not any([is_subsequence(s, t) for t in seen]):
return len(s) class Solution(object):
else: def findLongestWord(self, s, d):
seen.add(s) """
:type s: str
return -1 :type d: List[str]
:rtype: str
"""
# python_1_to_1000/523_Continuous_Subarray_Sum.py - m
def is_subsequence(s, t): # return True if s is a subsequence of t
_author_ = 'jake' i, j = 0, 0
_project_ = 'leetcode' while i < len(s) and (len(t) - j) >= (len(s) - i): # nb chars remaining in t
>= nb chars remaining in s
# https://leetcode.com/problems/continuous-subarray-sum/ if s[i] == t[j]:
# Given a list of non-negative numbers and a target integer k, write a function to check i += 1
if the array has a continuous j += 1
# subarray of size at least 2 that sums up to the multiple of k, that is, sums up to n*k if i == len(s):
where n is also an integer. return True
return False
# Subarray is difference between prefix sums a and b. a - b = nk. (a - b) % k = 0 hence
a%k - b%k = 0. d.sort(key=lambda x: (-len(x), x)) # primary and secondary keys
# Store prefix sums % k in dictionary.
# prefix sums % k is zero. for word in d:
# Time - O(n) if is_subsequence(word, s):
# Space - O(n) return word

class Solution(object): return ""


def checkSubarraySum(self, nums, k):
"""
:type nums: List[int] # python_1_to_1000/525_Contiguous_Array.py - m
:type k: int
:rtype: bool _author_ = 'jake'
""" _project_ = 'leetcode'
prefix_sum, prefix_sums = 0, {0: -1} # key is prefix sum mod k, value is index
in nums
# https://leetcode.com/problems/contiguous-array/
for i, n in enumerate(nums): # Given a binary array, find the maximum length of a contiguous subarray with equal
number of 0 and 1.
prefix_sum += n
if k != 0: # if k == 0 then look for prefix sum difference of zero # Store in dictionary net balance of 1s and 0s for every prefix array. Search for same
prefix_sum = prefix_sum % k net balance.
# Time - O(n)
if prefix_sum in prefix_sums: # Space - O(n)
if i - prefix_sums[prefix_sum] > 1: # check length >= 2
return True class Solution(object):
else: def findMaxLength(self, nums):
prefix_sums[prefix_sum] = i # do not overwrite if key present already """
:type nums: List[int]
return False :rtype: int
"""
max_len = 0
# python_1_to_1000/524_Longest_Word_in_Dictionary_through_Deleting.py - m balance = 0 # net 1s - 0s
balances = {0: -1} # key is balance, value is index
_author_ = 'jake'
_project_ = 'leetcode' for i, num in enumerate(nums):

# https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/ if num == 1:
# Given a string and a string dictionary, find the longest string in the dictionary that balance += 1
can be formed by deleting else:
# some characters of the given string. If there are more than one possible results, balance -= 1
return the longest word with the
# smallest lexicographical order. If there is no possible result, return the empty if balance in balances:
max_len = max(max_len, i - balances[balance])
else: # Create abbreviation for each word ignoring conflicts. Group words by abbreviation. If
balances[balance] = i single word in group, retain
# abbreviation. Else recurse on group, creating new groups by next char until group
return max_len lengths are 1 (which will always
# happen since words are unique).
# Time - O(nk) for n words of max length k
# Space - O(nk)
# python_1_to_1000/526_Beautiful_Arrangement.py - m
from collections import defaultdict
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def wordsAbbreviation(self, dictionary):
# https://leetcode.com/problems/beautiful-arrangement/ """
# Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array :type dict: List[str]
that is constructed by these :rtype: List[str]
# N numbers successfully if one of the following is true for the ith position (1 <= i <= """
N) in this array:
# The number at the ith position is divisible by i. def make_abbreviation(word, i):
# i is divisible by the number at the ith position. abbreviation = word[:i + 1] + str(len(word) - (i + 2)) + word[-1]
# Given N, how many beautiful arrangements can you construct? return word if len(abbreviation) >= len(word) else abbreviation

# For each position from final index working forwards, insert all valid numbers and def abbreviate(group, prefix_end): # prefix_end is last char of prefix
recurse. Backwards ensures less new_groups = defaultdict(list)
# branching resulting in failures. for i in group:
# Time - O(n!) new_groups[dictionary[i][prefix_end]].append(i) # key is char, value
# Space - O(n) is list of words
for new_group in new_groups.values():
class Solution(object): if len(new_group) == 1:
def countArrangement(self, N): abbreviations[new_group[0]] =
""" make_abbreviation(dictionary[new_group[0]], prefix_end)
:type N: int else:
:rtype: int abbreviate(new_group, prefix_end + 1)
"""
used = [False for _ in range(N + 1)] n = len(dictionary)
self.count = 0 abbreviations = ["" for _ in range(n)]

def helper(i): # i is position to be filled # group words by initial abbreviation


if i == 0: # solution found groups = defaultdict(list)
self.count += 1 for i, word in enumerate(dictionary):
return groups[make_abbreviation(word, 0)].append(i)

for num in range(1, N + 1): # iterate over groups


if not used[num] and (num % i == 0 or i % num == 0): for abbreviation, group in groups.items():
used[num] = True if len(group) == 1:
helper(i - 1) abbreviations[group[0]] = abbreviation
used[num] = False else:
abbreviate(group, 1)
helper(N)
return self.count return abbreviations

# python_1_to_1000/527_Word_Abbreviation.py - h # python_1_to_1000/528_Random_Pick_with_Weight.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# https://leetcode.com/problems/word-abbreviation/ # https://leetcode.com/problems/random-pick-with-weight/
# Given an array of n distinct non-empty strings, you need to generate minimal possible # Given an array w of positive integers, where w[i] describes the weight of index i,
abbreviations for every word write a function pickIndex which
# following rules below. # randomly picks an index in proportion to its weight.
# Begin with the first character and then the number of characters abbreviated, which
followed by the last character. # Create a list of cumulative weights. Choose a random integer between 1 and the sum of
# If there are any conflict, that is more than one words share the same abbreviation, a all weights. Binary search the
longer prefix is used instead # cumulative list for the index where the random integer would be inserted and return
# of only the first character until making the map from word to abbreviation become that index. Probability of
unique. In other words, a final # choosing an index is proprtional to its weight.
# abbreviation cannot map to more than one original words. # Time - O(n log n) for number of weights n
# If the abbreviation doesn't make the word shorter, then keep it as original. # Space - O(n)

return board
import random, bisect
def helper(r, c):
class Solution(object): if board[r][c] == "B": # return unchanged if blank
return
def __init__(self, w):
""" mines = 0 # count adjacent mines
:type w: List[int] for dr in [-1, 0, 1]:
""" for dc in [-1, 0, 1]:
self.cumulative = [] if dr == dc == 0:
total = 0 continue
for weight in w: if 0 <= r + dr < rows and 0 <= c + dc < cols and board[r + dr][c +
total += weight dc] == "M":
self.cumulative.append(total) mines += 1

def pickIndex(self): if mines != 0: # update with count or blank


""" board[r][c] = str(mines)
:rtype: int return
""" board[r][c] = "B"
x = random.randint(1, self.cumulative[-1])
return bisect.bisect_left(self.cumulative, x) for dr in [-1, 0, 1]: # recurse
for dc in [-1, 0, 1]:
if 0 <= r + dr < rows and 0 <= c + dc < cols:
# python_1_to_1000/529_Minesweeper.py - m helper(r + dr, c + dc)

_author_ = 'jake' helper(r, c)


_project_ = 'leetcode' return board

# https://leetcode.com/problems/minesweeper/
# Let's play the minesweeper game (Wikipedia, online game)! # python_1_to_1000/530_Minimum_Absolute_Difference_in_BST.py
# You are given a 2D char matrix representing the game board. 'M' represents an
unrevealed mine, 'E' represents an _author_ = 'jake'
# unrevealed empty square, 'B' represents a revealed blank square that has no adjacent _project_ = 'leetcode'
(above, below, left, right, and
# all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to # https://leetcode.com/problems/minimum-absolute-difference-in-bst/
this revealed square, and # Given a binary search tree with non-negative values, find the minimum absolute
# finally 'X' represents a revealed mine. difference between values of
# Now given the next click position (row and column indices) among all the unrevealed # any two nodes.
squares ('M' or 'E'), return the
# board after revealing this position according to the following rules: # Inorder traversal, visits nodes in order of ascending value. Track the value of the
# If a mine ('M') is revealed, then the game is over - change it to 'X'. previous node visited. For each
# If an empty square ('E') with no adjacent mines is revealed, then change it to revealed # node update the min_diff with the difference between node.val and prev, if lower than
blank ('B') and all of its current min_diff.
# adjacent unrevealed squares should be revealed recursively. # Time - O(n)
# If an empty square ('E') with at least one adjacent mine is revealed, then change it to # Space - O(1)
a digit ('1' to '8')
# representing the number of adjacent mines. class Solution(object):
# Return the board when no more squares will be revealed. def getMinimumDifference(self, root):
"""
# BFS. If mine, update and return. If blank count adjacent mines. If zero then recurse, :type root: TreeNode
else return count. :rtype: int
# Time - O(mn) """
# Space - O(mn) self.min_diff = float("inf")
self.prev = float("-inf")
class Solution(object):
def updateBoard(self, board, click): def inorder(node):
"""
:type board: List[List[str]] if not node:
:type click: List[int] return
:rtype: List[List[str]]
""" inorder(node.left)
r, c = click
rows, cols = len(board), len(board[0]) self.min_diff = min(self.min_diff, node.val - self.prev)
self.prev = node.val
for row in range(rows): # convert row string to list of chars
board[row] = [col for col in board[row]] inorder(node.right)

if board[r][c] == "M": # return if mine inorder(root)


board[r][c] = "X" return self.min_diff
class Solution(object):
# python_1_to_1000/531_Lonely_Pixel_I.py - m def findPairs(self, nums, k):
"""
_author_ = 'jake' :type nums: List[int]
_project_ = 'leetcode' :type k: int
:rtype: int
# https://leetcode.com/problems/lonely-pixel-i/ """
# Given a picture consisting of black and white pixels, find the number of black lonely if k < 0:
pixels. return 0
# The picture is represented by a 2D char array consisting of 'B' and 'W', which means
black and white pixels freq = Counter(nums)
# respectively. A black lonely pixel is character 'B' that located at a specific position pairs = 0
where the same row and same
# column don't have any other black pixels. for num in freq:
if k == 0:
# Record black pixels in each row and counts by column. Then for each row with 1 pixel, if freq[num] > 1:
check if that column also pairs += 1
# has 1 pixel. else:
# Time - O(mn) if num + k in freq:
# Space - O(mn) pairs += 1

class Solution(object): return pairs


def findLonelyPixel(self, picture):
"""
:type picture: List[List[str]] # python_1_to_1000/533_Lonely_Pixel_II.py - m
:rtype: int
""" _author_ = 'jake'
pixels = 0 _project_ = 'leetcode'
rows, cols = len(picture), len(picture[0])
# https://leetcode.com/problems/lonely-pixel-ii/
col_counts = [0 for _ in range(cols)] # black pixels per column # Given a picture consisting of black and white pixels, and a positive integer N, find
row_pixels = [[] for _ in range(rows)] # black pixels indices by row the number of black pixels
# located at some specific row R and column C that align with all the following rules:
for r in range(rows): # Row R and column C both contain exactly N black pixels.
for c in range(cols): # For all rows that have a black pixel at column C, they should be exactly the same as
if picture[r][c] == "B": row R
col_counts[c] += 1 # The picture is represented by a 2D char array consisting of 'B' and 'W' pixels.
row_pixels[r].append(c)
# Iterate over picture, for each row that contains N black pixels, increment row_strings
for r in range(rows): counter which maps from a string
if len(row_pixels[r]) == 1: # representation of that row to its frequency. Also count black pixels by column.
c = row_pixels[r][0] # Then for each row_string with N copies, increment the result by N for each pixel for a
if col_counts[c] == 1: column with a count of N.
pixels += 1 # if a row string does not have N copies then each black pixel either cannot have
col_count of N or is not from
return pixels # an identical row.
# Time - O(mn)
# Space - O(mn)

# python_1_to_1000/532_K-diff_Pairs_in_an_Array.py - m from collections import defaultdict

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def findBlackPixel(self, picture, N):
"""
# https://leetcode.com/problems/k-diff-pairs-in-an-array/ :type picture: List[List[str]]
# Given an array of integers and an integer k, you need to find the number of unique k- :type N: int
diff pairs in the array. :rtype: int
# 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 pixels = 0
# absolute difference is k. rows, cols = len(picture), len(picture[0])

# Count the frequency of each num. If k is zero, count the duplicated nums. Else for each col_counts = [0 for _ in range(cols)] # black pixels per column
num, add to the result count row_strings = defaultdict(int) # string representation of row mapped to
# if num + k is in nums. its frequency
# Time - O(n)
# Space - O(n) for r in range(rows):
row_count = 0 # black pixels in this row
from collections import Counter for c in range(cols):

if picture[r][c] == "B":
col_counts[c] += 1 _author_ = 'jake'
row_count += 1 _project_ = 'leetcode'
if row_count == N:
row_strings["".join(picture[r])] += 1 # https://leetcode.com/problems/construct-binary-tree-from-string/
# You need to construct a binary tree from a string consisting of parenthesis and
for row_string in row_strings: integers.
if row_strings[row_string] == N: # else not all rows with black pixel in a # The whole input represents a binary tree. It contains an integer followed by zero, one
given col are identical or two pairs of parenthesis.
for i, col in enumerate(row_string): # The integer represents the root value and a pair of parenthesis contains a child binary
if col == "B" and col_counts[i] == N: tree with the same structure.
pixels += N # You always start to construct the left child node of the parent first if it exists.

return pixels # 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.
# python_1_to_1000/535_Encode_and_Decode_TinyURL.py - m Skip closing bracket after
# either subtree.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/encode-and-decode-tinyurl/ # Definition for a binary tree node.


# TinyURL is a URL shortening service where you enter a URL such as class TreeNode(object):
https://leetcode.com/problems/design-tinyurl and def __init__(self, x):
# it returns a short URL such as http://tinyurl.com/4e9iAk. self.val = x
# Design the encode and decode methods for the TinyURL service. There is no restriction self.left = None
on how your encode/decode self.right = None
# algorithm should work. You just need to ensure that a URL can be encoded to a tiny URL
and the tiny URL can be class Solution(object):
# decoded to the original URL. def __init__(self):
self.i = 0 # index of next char of s to be processed
# Encode as a random selection of 6 letters and digits. If encoding already used, repeat.
# Time - O(1) average if load factor sufficiently low def str2tree(self, s):
# Space - O(nk) for n URLs of max length k """
:type s: str
import random :rtype: TreeNode
"""
class Codec:
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" # class def next_num(): # returns a TreeNode containing the integer at the prefix of s,
variable also increments self.i
num, neg = 0, False
def __init__(self): if s[self.i] == "-":
self.map = {} # shortUrl to longUrl neg = True
self.i += 1
def encode(self, longUrl): while self.i < len(s) and s[self.i] not in {"(", ")"}:
"""Encodes a URL to a shortened URL. num = num * 10 + int(s[self.i])
:type longUrl: str self.i += 1
:rtype: str return TreeNode(-num) if neg else TreeNode(num)
"""
encoding = [] def helper():
for i in range(6): if self.i >= len(s):
encoding.append(self.letters[random.randint(0, 61)]) return None
encoding = "".join(encoding) root = next_num()
if self.i < len(s) and s[self.i] == "(":
if encoding in self.map: # repeat if collision self.i += 1 # opening bracket
encoding = self.encode(longUrl) root.left = helper()
self.i += 1 # closing bracket
self.map[encoding] = longUrl if self.i < len(s) and s[self.i] == "(":
return encoding self.i += 1 # opening bracket
root.right = helper()
def decode(self, shortUrl): self.i += 1 # closing bracket
"""Decodes a shortened URL to its original URL.
:type shortUrl: str return root
:rtype: str
""" return helper()
return self.map[shortUrl]

# python_1_to_1000/536_Construct_Binary_Tree_from_String.py - m # python_1_to_1000/537_Complex_Number_Multiplication.py - m
return root
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/539_Minimum_Time_Difference.py - m
# https://leetcode.com/problems/complex-number-multiplication/
# Given two strings representing two complex numbers. _author_ = 'jake'
# You need to return a string representing their multiplication. Note i2 = -1 according _project_ = 'leetcode'
to the definition.
# https://leetcode.com/problems/minimum-time-difference/
# Split by "+" into real and imaginary. # Given a list of 24-hour clock time points in "Hour:Minutes" format, find the minimum
# Time - O(max(m, n)) minutes difference between any
# Space - O(max(m , n)) # two time points in the list.

class Solution(object): # Convert times to minutes, append first time + 24hrs so neighboring pairs list all
def complexNumberMultiply(self, a, b): differences are listed and find min
""" # Time - O(n log n)
:type a: str # Space - O(n)
:type b: str
:rtype: str class Solution(object):
""" def findMinDifference(self, timePoints):
a_real, a_im = a.split("+") """
a_real, a_im = int(a_real), int(a_im[:-1]) :type timePoints: List[str]
:rtype: int
b_real, b_im = b.split("+") """
b_real, b_im = int(b_real), int(b_im[:-1]) minutes = []
for time in timePoints:
c_real = a_real * b_real - a_im * b_im hrs, mins = time.split(":")
c_im = a_real * b_im + a_im * b_real minutes.append(int(hrs) * 60 + int(mins))

return str(c_real) + "+" + str(c_im) + "i" minutes.sort()


minutes.append(minutes[0] + 24 * 60) # len(minutes) guaranteed to be >= 2

min_diff = 24 * 60
# python_1_to_1000/538_Convert_BST_to_Greater_Tree.py - m for i in range(1, len(minutes)):
min_diff = min(min_diff, minutes[i] - minutes[i - 1])
_author_ = 'jake'
_project_ = 'leetcode' return min_diff

# https://leetcode.com/problems/convert-bst-to-greater-tree/
# Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of # python_1_to_1000/540_Single_Element_in_a_Sorted_Array.py - m
the original BST is changed to
# the original key plus sum of all keys greater than the original key in BST. _author_ = 'jake'
_project_ = 'leetcode'
# Reverse inorder traversal. Visit right subtree (containing all greater values), update
node value and running sum, # https://leetcode.com/problems/single-element-in-a-sorted-array/
# then visit left subtree. # Given a sorted array consisting of only integers where every element appears twice
# Time - O(n) except for one element which
# Space - O(1) # appears once. Find this single element that appears only once.

class Solution(object): # Binary search of even indices. Find first even index whose next number is different or
def convertBST(self, root): missing.
""" # Time - O(log n)
:type root: TreeNode # Space - O(1)
:rtype: TreeNode
""" class Solution(object):
self.running_sum = 0 def singleNonDuplicate(self, nums):
"""
def inorder(node): :type nums: List[int]
if not node: :rtype: int
return """
left, right = 0, len(nums) - 1 # len(nums) - 1 is always even
inorder(node.right)
while left < right:
node.val += self.running_sum mid = (left + right) // 2
self.running_sum = node.val if mid % 2 == 1: # take lower even index
mid -= 1
inorder(node.left)
if mid + 1 == len(nums) or nums[mid + 1] != nums[mid]:
inorder(root) right = mid

else: :type matrix: List[List[int]]


left = mid + 2 :rtype: List[List[int]]
"""
return nums[left] rows, cols = len(matrix), len(matrix[0])
deltas = [(1, 0), (-1, 0), (0, 1), (0, -1)]
frontier = deque() # tuples of matrix coordinates

# python_1_to_1000/541_Reverse_String_II.py max_dist = max(rows, cols)


for r in range(rows):
_author_ = 'jake' for c in range(cols):
_project_ = 'leetcode' if matrix[r][c] == 1:
matrix[r][c] = max_dist
# https://leetcode.com/problems/reverse-string-ii/ else:
# Given a string and an integer k, you need to reverse the first k characters for every frontier.append((r, c))
2k characters counting from
# the start of the string. If there are less than k characters left, reverse all of them. while frontier:
If there are less than 2k r, c = frontier.popleft()
# but greater than or equal to k characters, then reverse the first k characters and left for dr, dc in deltas:
the other as original. if 0 <= r + dr < rows and 0 <= c + dc < cols and matrix[r][c] + 1 <
matrix[r + dr][c + dc]:
# Iterate over s in steps of k. matrix[r + dr][c + dc] = matrix[r][c] + 1
# Time - O(n) frontier.append((r + dr, c + dc))
# Space - O(n)
return matrix
class Solution(object):
def reverseStr(self, s, k):
""" class Solution2(object):
:type s: str def updateMatrix(self, matrix):
:type k: int """
:rtype: str :type matrix: List[List[int]]
""" :rtype: List[List[int]]
reverse = True """
result = [] rows, cols = len(matrix), len(matrix[0])
deltas = [(1, 0), (-1, 0), (0, 1), (0, -1)]
for i in range(0, len(s), k): unknown = set() # tuples of matrix coordinates where distance to nearest zero is
block = s[i:i + k] unknown
if reverse:
result.append(block[::-1]) for r in range(rows):
else: for c in range(cols):
result.append(block) if matrix[r][c] == 1:
reverse = not reverse unknown.add((r, c))

return "".join(result) while unknown:


new_unknown = set()
for r, c in unknown:
# python_1_to_1000/542_01_Matrix.py - m for dr, dc in deltas:
if 0 <= r + dr < rows and 0 <= c + dc < cols and (r + dr, c + dc) not
_author_ = 'jake' in unknown:
_project_ = 'leetcode' matrix[r][c] = matrix[r + dr][c + dc] + 1
break
# https://leetcode.com/problems/01-matrix/ else: # no known neighbours
# Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell. new_unknown.add((r, c))
# The distance between two adjacent cells is 1.
unknown = new_unknown
# Queue of cells with known distances, initially 0 cells. 1 cells are set max possible
distance. For each cell in\ return matrix
# frontier, reduce distance of all neighbours to 1 + frontier distance and add neighbours
back to queue.
# Alternatively maintain set of cells with unknown distances. If any cell with unknown # python_1_to_1000/543_Diameter_of_Binary_Tree.py
distance is next to a known
# cell then set distance. May iterate over unknowns many times but faset in practice. _author_ = 'jake'
# Time - O(mn) _project_ = 'leetcode'
# Space - O(mn)
# https://leetcode.com/problems/diameter-of-binary-tree/
from collections import deque # Given a binary tree, you need to compute the length of the diameter of the tree.
# The diameter of a binary tree is the length of the longest path between any two nodes
class Solution(object): in a tree.
def updateMatrix(self, matrix): # This path may or may not pass through the root.
"""
# Bottom up recursion.
# The longest path passing with a node as root is the longest downwards left path + return result[0]
longest downwards right path.
# 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.
# Time - O(n) # python_1_to_1000/545_Boundary_of_Binary_Tree.py - m
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def diameterOfBinaryTree(self, root):
""" # https://leetcode.com/problems/boundary-of-binary-tree/
:type root: TreeNode # Given a binary tree, return the values of its boundary in anti-clockwise direction
:rtype: int starting from root. Boundary
""" # includes left boundary, leaves, and right boundary in order without duplicate nodes.
self.result = 0 # Left boundary is defined as the path from root to the left-most node. Right boundary is
defined as the path from
def helper(node): # return longest downwards path # root to the right-most node. If the root doesn't have left subtree or right subtree,
if not node: then the root itself is left
return -1 # so leaf returns zero # boundary or right boundary. Note this definition only applies to the input binary tree,
left = helper(node.left) and not applies to any subtrees.
right = helper(node.right) # The left-most node is defined as a leaf node you could reach when you always firstly
self.result = max(self.result, 2 + left + right) travel to the left subtree
return max(1 + left, 1 + right) # 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.
helper(root) # ignore return value
return self.result # Find left edge until leaf. Inorder traversal to append all leaves. Find right edge and
reverse.
# Time - O(n)
# python_1_to_1000/544_Output_Contest_Matches.py - m # Space - O(n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def boundaryOfBinaryTree(self, root):
"""
# https://leetcode.com/problems/output-contest-matches/ :type root: TreeNode
# During the NBA playoffs, we always arrange the rather strong team to play with the :rtype: List[int]
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 def left_side(node):
# given n teams, you need to output their final contest matches in the form of a string. if not node or (not node.left and not node.right):
# The n teams are given in the form of positive integers from 1 to n, which represents return
their initial rank. (Rank 1 is boundary.append(node.val)
# the strongest team and Rank n is the weakest team.) We'll use parentheses('(', ')') and if node.left:
commas(',') to represent the left_side(node.left)
# contest team pairing - parentheses('(' , ')') for pairing and commas(',') for else:
partition. During the pairing process left_side(node.right)
# in each round, you always need to follow the strategy of making the rather strong one
pair with the rather weak one. def right_side(node):
if not node or (not node.left and not node.right):
# Create list of strings of all teams. While length of list > 1, iterate over list return
pairing first and last teams/matches right_edge.append(node.val)
# (with brackets and comma to make new string) until middle. if node.right:
# Time - O(n log n), final result is of length O(n log n) since each loop multiplies right_side(node.right)
total string length by 2.5 times. else:
# Space - O(n) right_side(node.left)

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


def findContestMatch(self, n): if not node:
""" return
:type n: int inorder(node.left)
:rtype: str if not node.left and not node.right:
""" boundary.append(node.val)
result = [str(i) for i in range(1, n + 1)] inorder(node.right)

while len(result) > 1: if not root:


new_result = [] return []
for i in range(len(result) // 2):
new_result.append("(" + result[i] + "," + result[len(result) - i - 1] + boundary, right_edge = [root.val], []
")")
result = new_result # ignore root

left_side(root.left)
inorder(root.left)
inorder(root.right) # python_1_to_1000/547_Friend_Circles.py - m
right_side(root.right)
_author_ = 'jake'
return boundary + right_edge[::-1] _project_ = 'leetcode'

# https://leetcode.com/problems/friend-circles/
# python_1_to_1000/546_Remove_Boxes.py - h # There are N students in a class. Some of them are friends, while some are not.
# Their friendship is transitive in nature. For example, if A is a direct friend of B,
_author_ = 'jake' and B is a direct friend of C,
_project_ = 'leetcode' # then A is an indirect friend of C.
# We define a friend circle is a group of students who are direct or indirect friends.
# https://leetcode.com/problems/remove-boxes/ # Given a N*N matrix M representing the friend relationship between students in the
# Given several boxes with different colors represented by different positive numbers. class, if M[i][j] = 1, then the
# You may experience several rounds to remove boxes until there is no box left. Each time # ith and jth students are direct friends with each other, otherwise not.
you can choose some continuous # You have to output the total number of friend circles among all the students.
# boxes with the same color (composed of k boxes, k >= 1), remove them and get k*k
points. # Union find structure. Initially each friend is in their own group. Iterate over the
# Find the maximum points you can get. matrix, only using the lower
# triangle because of the symmetry. For each friend relationship, union the groups by
# Dynamic programming. Consider subarray from boxes[left:right+1] with same boxes of same setting the group exemplar (an
colour as boxes[right] in a # arbitrary member of the gorup) of one friend to the group exemplar of the other.
# continuous subarray to the right of boxes[right]. Best score is either a) removing # Result is the final number of unique group exemplars.
right and all same boxes, then # Alternatively, dfs for each friend marking already explored friends.
# best score form remaining subarray with no same, or b) is any box in subarray is same # Time - O(n**2 log* n)
as boxes[right] then get best # Space - O(n)
# score from the subarray between this box and right, plus best score from left part of
bubarray with same + 1. class Solution(object):
# Time - O(n**3) def findCircleNum(self, M):
# Space - O(n**3) """
:type M: List[List[int]]
class Solution(object): :rtype: int
def removeBoxes(self, boxes): """
""" n = len(M)
:type boxes: List[int] group = [i for i in range(n)] # map from firend index to group exemplar
:rtype: int
""" def get_group(x): # get the group exemplar for x
while group[x] != x:
def helper(left, right, same): # same is number of boxes to right of group[x] = group[group[x]] # collapse parent to grandparent
boxes[right] that are same colour x = group[x]
return x
if left > right:
return 0 for i in range(1, n):
for j in range(i): # iterate over lower triangle of M
if (left, right, same) in memo: if M[i][j] == 1:
return memo[(left, right, same)] group[get_group(i)] = get_group(j) # set exemplar of i's group to
exemplar of j's group
# extend same to left of boxes[right] as far as possible
while right > left and boxes[right] == boxes[right - 1]: return len(set(get_group(i) for i in range(n)))
right -= 1
same += 1 class Solution2(object):
def findCircleNum(self, M):
result = helper(left, right - 1, 0) + (same + 1) ** 2 # remove boxes[right] """
and same :type M: List[List[int]]
:rtype: int
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 def dfs(i):
remove left to i with extended same for j in range(len(M)):
if boxes[i] == boxes[right]: if M[i][j] == 1:
result = max(result, helper(i + 1, right - 1, 0) + helper(left, i, if j not in seen:
same + 1)) seen.add(j)
dfs(j)
memo[(left, right, same)] = result
return result circles = 0
seen = set()
memo = {}
return helper(0, len(boxes) - 1, 0) for i in range(len(M)):
if i not in seen:
circles += 1 # https://leetcode.com/problems/binary-tree-longest-consecutive-sequence-ii/
dfs(i) # Given a binary tree, you need to find the length of Longest Consecutive Path in Binary
Tree.
return circles # Especially, this path can be either increasing or decreasing. For example, [1,2,3,4]
and [4,3,2,1] are both considered
# valid, but the path [1,2,4,3] is not valid. On the other hand, the path can be in the
# python_1_to_1000/548_Split_Array_with_Equal_Sum.py - h child-Parent-child order, where
# not necessarily be parent-child order.
_author_ = 'jake'
_project_ = 'leetcode' # Helper return longest increasing and decreasing paths from a node. Update longest
increasing and decreasing paths
# https://leetcode.com/problems/split-array-with-equal-sum/ # according to whether children exist and their values are +/-1 of node.val. Update
# Given an array with n integers, you need to find if there are triplets (i, j, k) which longest path without double-
satisfies following conditions: # counting node.
# 0 < i, i + 1 < j, j + 1 < k < n - 1 # Time - O(n)
# Sum of subarrays (0, i - 1), (i + 1, j - 1), (j + 1, k - 1) and (k + 1, n - 1) should # Space - O(1)
be equal.
# where we define that subarray (L, R) represents a slice of the original array starting class Solution(object):
from the element indexed L to def longestConsecutive(self, root):
# the element indexed R """
:type root: TreeNode
# For each possible middle index j, try all possible values of first index i and is this :rtype: int
creates 2 equal subarrays then """
# then add their sum to the candidates set. Then with the same value fo j, try all self.longest = 0 # instance variable to store longest path length
possible values of k. If the RHS
# subarrays have the same sum and that sum is in candidates the return True. def helper(node): # return tuple (longest increasing, longest decreasing)
# Time - O(n**2) (including node)
# Space - O(n) if not node:
return 0, 0
class Solution(object):
def splitArray(self, nums): l_i, l_d = helper(node.left)
""" r_i, r_d = helper(node.right)
:type nums: List[int]
:rtype: bool incr, decr = 1, 1 # leaf node
"""
n = len(nums) if node.left:
if n < 7: if node.left.val == node.val + 1: # increasing path
return False incr = 1 + l_i
elif node.left.val == node.val - 1: # decreasing path
cumul = [nums[0]] # array of cumulative sums for easy lookup of decr = 1 + l_d
subarray sums
for num in nums[1:]: if node.right:
cumul.append(num + cumul[-1]) if node.right.val == node.val + 1:
incr = max(incr, 1 + r_i) # update best increasing
for j in range(3, n - 3): # possible value of middle index elif node.right.val == node.val - 1:
candidates = set() decr = max(decr, 1 + r_d) # update best decreasing

for i in range(1, j - 1): self.longest = max(self.longest, incr + decr - 1) # -1 so as to not double


left_sum = cumul[i - 1] count node
right_sum = cumul[j - 1] - cumul[i]
if left_sum == right_sum: return incr, decr
candidates.add(left_sum)
helper(root)
for k in range(j + 2, n - 1): return self.longest
left_sum = cumul[k - 1] - cumul[j]
right_sum = cumul[n - 1] - cumul[k]
if left_sum == right_sum and left_sum in candidates: # python_1_to_1000/551_Student_Attendance_Record_I.py
return True
_author_ = 'jake'
return False _project_ = 'leetcode'

# https://leetcode.com/problems/student-attendance-record-i/
# You are given a string representing an attendance record for a student.
# The record only contains the following three characters:
# python_1_to_1000/549_Binary_Tree_Longest_Consecutive_Sequence_II.py - m # 'A' : Absent.
# 'L' : Late.
_author_ = 'jake' # 'P' : Present.
_project_ = 'leetcode' # A student could be rewarded if his attendance record doesn't contain more than one 'A'

(absent) or more than


# two continuous 'L' (late).
# You need to return whether the student could be rewarded according to his attendance # python_1_to_1000/553_Optimal_Division.py - m
record.
_author_ = 'jake'
# Find the count of 'A' and whether 'LLL' appears in s. _project_ = 'leetcode'
# Time - O(n)
# Space - O(1) # https://leetcode.com/problems/optimal-division/
# Given a list of positive integers, the adjacent integers will perform the float
class Solution(object): division.
def checkRecord(self, s): # For example, [2,3,4] -> 2 / 3 / 4.
""" # However, you can add any number of parenthesis at any position to change the priority
:type s: str of operations. You should
:rtype: bool # find out how to add parenthesis to get the maximum result, and return the corresponding
""" expression in string format.
return s.count("A") < 2 and "LLL" not in s # Your expression should NOT contain redundant parenthesis.

# First number is always numerator, second number is always denominator. Subsequent


# python_1_to_1000/552_Student_Attendance_Record_II.py - h numbers should all be in
# numerator (since all >= 1). This is achieved by bracketing all other numbers together.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(n)

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


# Given a positive integer n, return the number of all possible attendance records with def optimalDivision(self, nums):
length n, which will be """
# regarded as rewardable. The answer may be very large, return it after mod 10**9 + 7. :type nums: List[int]
# A student attendance record is a string that only contains the following three :rtype: str
characters: """
# 'A' : Absent. nums = [str(s) for s in nums]
# 'L' : Late. result = nums[0]
# 'P' : Present.
# A record is regarded as rewardable if it doesn't contain more than one 'A' (absent) or if len(nums) == 1:
more than two return result
# continuous 'L' (late). if len(nums) == 2:
return result + "/" + nums[1]
# Ignoring 'A', find the number of rewardable records for records of lengths up to n with
dynamic programming. Modulo return result + "/(" + "/".join(nums[1:]) + ")"
# all additions. Final result is case of no 'A' or an 'A' in any position.
# Time - O(n)
# Space - O(n)

class Solution(object): # python_1_to_1000/554_Brick_Wall.py - m


def checkRecord(self, n):
""" _author_ = 'jake'
:type n: int _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/brick-wall/
BASE = 10 ** 9 + 7 # There is a brick wall in front of you. The wall is rectangular and has several rows of
records = [1, 2] # rewardable records of lengths 0 and 1 bricks. The bricks have the
zero, one, two = 1, 1, 0 # rewardable records ending in zero, one or two 'L' # same height but different width. You want to draw a vertical line from the top to the
bottom and cross the least
# new zero formed from previous zero, one and two + 'P' # bricks.
# new one formed form previous zero + 'L' # The brick wall is represented by a list of rows. Each row is a list of integers
# new two formed form previous one + 'L' representing the width of each
for _ in range(2, n + 1): # brick in this row from left to right.
zero, one, two = (zero + one + two) % BASE, zero, one # If your line go through the edge of a brick, then the brick is not considered as
records.append((zero + one + two) % BASE) # all possible numbers of 'L' crossed.
# You need to find out how to draw the line to cross the least bricks and return the
# if A not present number of crossed bricks.
result = records[-1] # You cannot draw a line just along one of the two vertical edges of the wall.

# for each position of A # Count number of bricks in wall with right edges at every position. Choose the position
for i in range(n): with the most edges.
result += records[i] * records[n - 1 - i] # records on LHS of 'A' * records # Time - O(n), number of bricks
on RHS # Space - O(n)
result %= BASE
from collections import defaultdict
return result
class Solution(object):
def leastBricks(self, wall): _author_ = 'jake'
""" _project_ = 'leetcode'
:type wall: List[List[int]]
:rtype: int # https://leetcode.com/problems/next-greater-element-iii/
""" # Given a positive 32-bit integer n, you need to find the smallest 32-bit integer which
edges = defaultdict(int) # mapping from x-position of an edge to count of number has exactly the same
of edges # digits existing in the integer n and is greater in value than n. If no such positive
32-bit integer exists,
for row in wall: # you need to return -1.
edge = 0
# Moving from right to left, find the first pair where n[left] < n[right]. Then moving
for brick in row: right again, find the smallest
edge += brick # digit that is more than n[left] and swap. Put all digits to the right of n[left] in
edges[edge] += 1 increasing order.
# Time - O(log n), number of digits in n
del edges[sum(wall[0])] # delete RHS vertical edge # Space - O(1)

crossed = len(wall) # cross all brick if no edges, else choose path with most class Solution(object):
edges def nextGreaterElement(self, n):
return crossed if not edges else crossed - max(edges.values()) """
:type n: int
:rtype: int
# python_1_to_1000/555_Split_Concetenated_Strings.py - m """
num = [c for c in str(n)] # convert to list of chars
_author_ = 'jake'
_project_ = 'leetcode' i = len(num) - 1 # find num[i-1] < num[i], so swapping increases value
while i > 0 and num[i - 1] >= num[i]:
# https://leetcode.com/problems/split-concatenated-strings/ i -= 1
# Given a list of strings, you could concatenate these strings together into a loop,
where for each string you could if i == 0: # no increase possible
# choose to reverse it or not. Among all the possible loops, you need to find the return -1
lexicographically biggest string
# after cutting the loop, which will make the looped string into a regular one. j = i # find lowest nums[j] that is > nums[i-1]
# Specifically, to find the lexicographically biggest string, you need to experience two while j + 1 < len(num) and num[j + 1] > num[i - 1]:
phases: j += 1
# Concatenate all the strings into a loop, where you can reverse some strings or not and
connect them in the same order as given. num[j], num[i - 1] = num[i - 1], num[j] # swap i-1 and j
# 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. result = int("".join(num[:i] + sorted(num[i:]))) # sort after i
# And your job is to find the lexicographically biggest one among all the possible # 2**31 - 1 is the largest signed 32 bit number
regular strings. return -1 if result >= 2 ** 31 else result

# For each split point of each string and each reversed string, build the loop where each
other string is oriented to
# its highest value. # python_1_to_1000/557_Reverse_Words_in_a_String_III.py
# Time - O(n**2) for n total chars.
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def splitLoopedString(self, strs): # 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
:type strs: List[str] sentence while still preserving
:rtype: str # whitespace and initial word order.
"""
result = None # Split string by space into a list of words. Reverse each word. Join reversed words by
best = [max(s, s[::-1]) for s in strs] spaces.
# Time - O(n)
for i, s in enumerate(strs): # Space - O(n)
t = s[::-1]
for j in range(len(s)): class Solution(object):
test = s[j:] + "".join(best[i + 1:] + best[:i]) + s[:j] def reverseWords(self, s):
test2 = t[j:] + "".join(best[i + 1:] + best[:i]) + t[:j] """
result = max(result, test, test2) :type s: str
:rtype: str
return result """
return " ".join([w[::-1] for w in s.split(" ")])

# python_1_to_1000/556_Next_Greater_Element_III.py - m

# python_1_to_1000/558_Quad_Tree_Intersection.py - m # Time - O(n)


# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def maxDepth(self, root):
# https://leetcode.com/problems/quad-tree-intersection/ """
# A quadtree is a tree data in which each internal node has exactly four children: :type root: Node
topLeft, topRight, bottomLeft :rtype: int
# and bottomRight. Quad trees are often used to partition a two-dimensional space by """
recursively subdividing it into if not root:
# four quadrants or regions. return 0
# We want to store True/False information in our quad tree. if not root.children: # required to avoid taking max of empty sequence
# The quad tree is used to represent a N * N boolean grid. For each node, it will be return 1
subdivided into four children
# nodes until the values in the region it represents are all the same. Each node has return 1 + max(self.maxDepth(child) for child in root.children)
another two boolean
# 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. # python_1_to_1000/560_Subarray_Sum_Equals_K.py - m

# Information required but not in problem description: the val attribute for a non-leaf _author_ = 'jake'
node is False. _project_ = 'leetcode'
# Combine two leaves according the logical OR of their values. If one node is a leaf then
return it if is True, else # https://leetcode.com/problems/subarray-sum-equals-k/
# return the other node. If neither are leaves, intersect each of the 4 subtree children # Given an array of integers and an integer k, you need to find the total number of
and return a leaf if they are continuous subarrays whose
# all leaves with the same value, or else return a non-leaf with value of False. # sum equals to k.
# Time - O(n)
# Space - O(n) # Store counts of prefix sums in dictionary. Iterate over array, updating running_sum and
incrementing result if
class Solution(object): # running_sum == k. Lookup prefix value that makes a subararry of sum k.
def intersect(self, quadTree1, quadTree2): # Time - O(n)
""" # Space - O(n)
:type quadTree1: Node
:type quadTree2: Node from collections import defaultdict
:rtype: Node
""" class Solution(object):
if quadTree1.isLeaf: def subarraySum(self, nums, k):
return quadTree1 if quadTree1.val else quadTree2 """
if quadTree2.isLeaf: :type nums: List[int]
return quadTree2 if quadTree2.val else quadTree1 :type k: int
:rtype: int
topLeft = self.intersect(quadTree1.topLeft, quadTree2.topLeft) """
topRight = self.intersect(quadTree1.topRight, quadTree2.topRight) total = 0
bottomLeft = self.intersect(quadTree1.bottomLeft, quadTree2.bottomLeft) sums = defaultdict(int) # key is prefix sum, value is count of number of prefixes
bottomRight = self.intersect(quadTree1.bottomRight, quadTree2.bottomRight) running_sum = 0

children = [topLeft, topRight, bottomLeft, bottomRight] for num in nums:


values = [child.val for child in children]
leaves = [child.isLeaf for child in children] running_sum += num

if all(leaves) and (sum(values) == 0 or sum(values) == 4): if running_sum == k:


return Node(topLeft.val, True, None, None, None, None) total += 1
if running_sum - k in sums:
# non-leaf must have False val total += sums[running_sum - k]
return Node(False, False, topLeft, topRight, bottomLeft, bottomRight)
sums[running_sum] += 1

# python_1_to_1000/559_Maximum_Depth_of_N-ary_Tree.py return total

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/561_Array_Partition_I.py

# https://leetcode.com/problems/maximum-depth-of-n-ary-tree/ _author_ = 'jake'


# Given a n-ary tree, find its maximum depth. _project_ = 'leetcode'
# The maximum depth is the number of nodes along the longest path from the root node down
to the farthest leaf node. # https://leetcode.com/problems/array-partition-i/
# Given an array of 2n integers, your task is to group these integers into n pairs of
# Recursive function. Base cases of no node or leaf node. Else add 1 to the max depth of integer, say (a1, b1), (a2, b2),
any child. # ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as
possible. max_len = max(max_len, max(row_dp[-1]))

# Sort nums. The smallest num must be paired with some other num that will not form part previous_dp = row_dp
of the sum. In order to
# maximise the sum, the smallest number should be paired with the next smallest. Pair return max_len
each number with the next larger
# number, hence numbers of even indices form the resulting sum.
# Time - O(n log n)
# Space - O(n) for the sorted list # python_1_to_1000/563_Binary_Tree_Tilt.py

class Solution(object): _author_ = 'jake'


def arrayPairSum(self, nums): _project_ = 'leetcode'
"""
:type nums: List[int] # https://leetcode.com/problems/binary-tree-tilt/
:rtype: int # Given a binary tree, return the tilt of the whole tree.
""" # The tilt of a tree node is defined as the absolute difference between the sum of all
return sum(sorted(nums)[::2]) # iterate with step of 2 to select even indices left subtree node values and
# the sum of all right subtree node values. Null node has tilt 0.
# The tilt of the whole tree is defined as the sum of all nodes' tilt.
# python_1_to_1000/562_Longest_Line_of_Consecutive_One_in_Matrix.py - m
# Recursive helper function returns the sum of the values in a tree. Tilt is the absolute
_author_ = 'jake' difference between the
_project_ = 'leetcode' # left and right subtree sums.
# Time - O(n)
# https://leetcode.com/problems/longest-line-of-consecutive-one-in-matrix/ # Space - O(1)
# Given a 01 matrix M, find the longest line of consecutive one in the matrix.
# The line could be horizontal, vertical, diagonal or anti-diagonal. class Solution(object):
def findTilt(self, root):
# Dynamic programming. Iterate over matrix, if cell == 1 update longest line in each of 4 """
directions based on :type root: TreeNode
# longest lines to cells on left and in previous row. :rtype: int
# Time - O(mn) """
# Space - O(n), number of columns self.tilt = 0 # instance variable collects sum

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


def longestLine(self, M):
""" if not node: # base case
:type M: List[List[int]] return 0
:rtype: int
""" left, right = helper(node.left), helper(node.right)
if not M or not M[0]: self.tilt += abs(left - right) # update total tilt
return 0 return node.val + left + right # return sum of all values in tree

rows, cols = len(M), len(M[0]) helper(root)


max_len = 0 return self.tilt

# 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 # python_1_to_1000/564_Find_the_Closest_Palindrome.py - h
previous_dp = [[0 for _ in range(4)] for c in range(cols)]
_author_ = 'jake'
for r in range(rows): _project_ = 'leetcode'
row_dp = []
# https://leetcode.com/problems/find-the-closest-palindrome/
for c in range(cols): # Given an integer n, find the closest integer (not including itself), which is a
palindrome.
if M[r][c] == 0: # cannot extend any lines # The 'closest' is defined as absolute difference minimized between two integers.
row_dp.append([0 for _ in range(4)]) # The input n is a positive integer represented by string, whose length will not exceed
continue 18.
# If there is a tie, return the smaller one as answer.
row_dp.append([1 for _ in range(4)]) # default line length of this cell
# There are 5 possible candidates.
if c != 0: # 1) A number 1 digit shorter than n of all 9s
row_dp[-1][0] += row_dp[-2][0] # horizontal # 2) A number 1 digit longer than n ending and starting in 1 with all other zeros
row_dp[-1][1] += previous_dp[c][1] # vertical # 3) Reversed LHS replacing RHS and middle digit(s) same
if c != 0: # descending diagonal # 4) as 3) but middle index incremented
row_dp[-1][2] += previous_dp[c - 1][2] # 5) as 3) but middle index decremented
if c != cols - 1: # ascending diagonal # Make all candidates that exist (care of single digit n, 0 and 9 in middle. If length is
row_dp[-1][3] += previous_dp[c + 1][3] odd them middle is a
# single digit, else it is a pair.

# Find closest of candidates or lower if tie. """


# Time - O(n) :type nums: List[int]
# Space - O(n) :rtype: int
"""
class Solution(object): visited = set() # nums visited
def nearestPalindromic(self, n): longest = 0 # biggest set
"""
:type n: str for i, num in enumerate(nums):
:rtype: str
""" if num in visited:
digits = len(n) continue
candidates = {int("1" + "0" * (digits - 1) + "1")} # longer length e.g. 88 ->
101 current = set() # start a new set
if len(n) > 1: while num not in current:
candidates.add(int("9" * (digits - 1))) # shorter length e.g. 12 -> 9 current.add(num) # add num
num = nums[num] # move to next num
mid = len(n) // 2 # middle index if odd length, or first of RHS if even
left = n[:mid] longest = max(longest, len(current))
if longest >= len(nums) - i - 1: # early return
if len(n) % 2 == 1: break
centre_count = 1 # odd, so single middle index
centre = n[mid] visited |= current # add all of current to visited
right = left[::-1]
else: return longest
centre_count = 2 # even, so pair of middle indices
centre = left[-1]
left = left[:-1]
right = left[::-1] # python_1_to_1000/566_Reshape_the_Matrix.py

candidates.add(int(left + centre * centre_count + right)) _author_ = 'jake'


if centre != "9": _project_ = 'leetcode'
new_centre = str(int(centre) + 1)
candidates.add(int(left + new_centre * centre_count + right)) # https://leetcode.com/problems/reshape-the-matrix/
if centre != "0": # In MATLAB, there is a very useful function called 'reshape', which can reshape a matrix
new_centre = str(int(centre) - 1) into a new one with different
candidates.add(int(left + new_centre * centre_count + right)) # size but keep its original data.
# You're given a matrix represented by a two-dimensional array, and two positive integers
n_int = int(n) r and c representing the
candidates.discard(n_int) # row number and column number of the wanted reshaped matrix, respectively.
candidates = list(candidates) # The reshaped matrix need to be filled with all the elements of the original matrix in
candidates.sort(key=lambda x: (abs(x - n_int), x)) # sort by (abs difference the same row-traversing order
from n, value) # as they were. If the 'reshape' operation with given parameters is possible and legal,
return str(candidates[0]) output the new reshaped matrix.
# Otherwise, output the original matrix.

# python_1_to_1000/565_Array_Nesting.py - m # Iterate over nums, appending elements to reshape and starting new rows when full.
# Time - O(mn)
_author_ = 'jake' # Space - O(mn)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/array-nesting/ def matrixReshape(self, nums, r, c):
# 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, :type nums: List[List[int]]
# where S[i] = {A[i], A[A[i]], A[A[A[i]]], ... } subjected to the rule below. :type r: int
# Suppose the first element in S starts with the selection of element A[i] of index = i, :type c: int
the next element in S should :rtype: List[List[int]]
# be A[A[i]], and then A[A[A[i]]]… By that analogy, we stop adding right before a """
duplicate element occurs in S. rows, cols = len(nums), len(nums[0])
if rows * cols != r * c: # return if different number of elements
# Each set forms an independent cycle of nums. For each num, follow the cycle until a num return nums
repeats. Update the longest
# and add all nus in the cycle to the seen set. Iterate over nums finding the cycle for reshaped = [[]]
each num, ignoring any num
# already known to be part of a cycle. for i in range(rows):
# Time - O(n) for j in range(cols):
# Space - O(n)
if len(reshaped[-1]) == c: # end of column, start new column
class Solution(object): reshaped.append([])
def arrayNesting(self, nums): reshaped[-1].append(nums[i][j])
flight from the city i to the
return reshaped # city j, flights[i][j] = 0; Otherwise, flights[i][j] = 1. Also, flights[i][i] = 0 for
all i.
# You totally have K weeks (each week has 7 days) to travel. You can only take flights at
# python_1_to_1000/567_Permutation_in_String.py - m most once per day and can
# only take flights on each week's Monday morning. Since flight time is so short, we
_author_ = 'jake' don't consider the impact of
_project_ = 'leetcode' # flight time.
# For each city, you can only have restricted vacation days in different weeks, given an
# https://leetcode.com/problems/permutation-in-string/ N*K matrix called days
# Given two strings s1 and s2, write a function to return true if s2 contains the # representing this relationship. For the value of days[i][j], it represents the maximum
permutation of s1. days you could take vacation
# In other words, one of the first string's permutations is the substring of the second # in the city i in the week j.
string. # You're given the flights matrix and days matrix, and you need to output the maximum
# The input strings only contain lower case letters. vacation days you could take
# during K weeks.
# Count frequencies of letters in s1 in an array. Slide window of length len(s1) over s2.
Array maintains balance of # Dynamic programming. List stores max vacation days per city starting with the previous
# counts in s1 - counts in window. week, initally all zero.
# Time - O(m + n), sum of string lengths # For each week starting from the last and working forward, calculate the max vacation
# Space - O(1) for each city as a) vacation
# from staying in that city and b) for each city with flight, vacation from flying to
class Solution(object): that city
def checkInclusion(self, s1, s2): # Time - O(n**2 * w) cities * weeks
""" # Space - O(n) number of cities
:type s1: str
:type s2: str class Solution(object):
:rtype: bool def maxVacationDays(self, flights, days):
""" """
n1 = len(s1) :type flights: List[List[int]]
freq = [0] * 26 # counts of each char :type days: List[List[int]]
:rtype: int
for c in s1: """
freq[ord(c) - ord("a")] += 1 cities = len(flights)
weeks = len(days[0])
for i, c in enumerate(s2): if not cities or not weeks:
return 0
freq[ord(c) - ord("a")] -= 1 # decrement count of letter added to window
if i >= n1: prev_week_max_days = [0 for _ in range(cities)]
freq[ord(s2[i - n1]) - ord("a")] += 1 # increment count of letter
exiting window for week in range(weeks - 1, -1, -1):
this_week_max_days = [0 for _ in range(cities)]
if not any(freq):
return True for start in range(cities):
max_vacation = days[start][week] + prev_week_max_days[start] # stay in
return False same city

for end in range(cities):


# python_1_to_1000/568_Maximum_Vacation_Days.py - h if flights[start][end]: # try all cities with flights
max_vacation = max(max_vacation, days[end][week] +
_author_ = 'jake' prev_week_max_days[end])
_project_ = 'leetcode'
this_week_max_days[start] = max_vacation
# https://leetcode.com/problems/maximum-vacation-days/ prev_week_max_days = this_week_max_days
# LeetCode wants to give one of its best employees the option to travel among N cities to
collect algorithm problems. return this_week_max_days[0]
# But all work and no play makes Jack a dull boy, you could take vacations in some
particular cities and weeks. Your
# job is to schedule the traveling to maximize the number of vacation days you could # python_1_to_1000/572_Subtree_of_Another_Tree.py
take, but there are certain
# rules and restrictions you need to follow. _author_ = 'jake'
_project_ = 'leetcode'
# Rules and restrictions:
# You can only travel among N cities, represented by indexes from 0 to N-1. Initially, # https://leetcode.com/problems/subtree-of-another-tree/
you are in the city # Given two non-empty binary trees s and t, check whether tree t has exactly the same
# indexed 0 on Monday. structure and node values with a
# The cities are connected by flights. The flights are represented as a N*N matrix (not # subtree of s. A subtree of s is a tree consists of a node in s and all of this node's
necessary symmetrical), called descendants.
# flights representing the airline status from the city i to the city j. If there is no # The tree s could also be considered as a subtree of itself.

nuts_to_tree = 0 # sum of all distances from nut to tree


# Preorder traversal over s and t to serialize. Nodes are separated by commas (e.g. to best_gain = height * width # best change in total distance
distinguish 1 and 0 from 10).
# None nodes are identified with special symbol '#'. Check whether serialization of t is def distance(a, b):
contained in s. return abs(a[0] - b[0]) + abs(a[1] - b[1])
# Time - O(m + n)
# Space - O(m + n) for nut in nuts:
nut_to_tree = distance(nut, tree)
class Solution(object): squirrel_to_nut = distance(squirrel, nut)
def isSubtree(self, s, t): nuts_to_tree += nut_to_tree
""" best_gain = min(best_gain, squirrel_to_nut - nut_to_tree)
:type s: TreeNode
:type t: TreeNode return 2 * nuts_to_tree + best_gain
:rtype: bool
"""
def serialize(node):
if not node:
serial.append("#") # python_1_to_1000/575_Distribute_Candies.py
return
serial.append(",") _author_ = 'jake'
serial.append(str(node.val)) _project_ = 'leetcode'
serialize(node.left)
serialize(node.right) # https://leetcode.com/problems/distribute-candies/
# Given an integer array with even length, where different numbers in this array
serial = [] # list so append each symbol in O(1) represent different kinds of candies.
serialize(s) # Each number means one candy of the corresponding kind. You need to distribute these
s_serial = "".join(serial) candies equally in number to
serial = [] # brother and sister. Return the maximum number of kinds of candies the sister could
serialize(t) gain.
t_serial = "".join(serial)
# Sisted get len(candies) // 2 candies. If there are this number or more of different
return t_serial in s_serial candies, then sister can have
# all different candies. If there are fewer different kinds, then sister can have one of
each kind.
# python_1_to_1000/573_Squirrel_Simulation.py - m # Time - O(n)
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def distributeCandies(self, candies):
# https://leetcode.com/problems/squirrel-simulation/ """
# There's a tree, a squirrel, and several nuts. Positions are represented by the cells in :type candies: List[int]
a 2D grid. Your goal is to :rtype: int
# find the minimal distance for the squirrel to collect all the nuts and put them under """
the tree one by one. The return min(len(candies) // 2, len(set(candies)))
# squirrel can only take at most one nut at one time and can move in four directions -
up, down, left and right, to
# the adjacent cell. The distance is represented by the number of moves. # python_1_to_1000/576_Out_of_Boundary_Paths.py - m

# The only choice to make is which nut to collect first. The distance for all other nuts _author_ = 'jake'
is from the tree to the nut _project_ = 'leetcode'
# and back. For each starting nut, calculate the change in distance by going from
squirrel to nut and not from # https://leetcode.com/problems/out-of-boundary-paths/
# tree to nut. Add the greatest reduction in distance to the round-trips for all nuts. # There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you
# Time - O(n) number of nuts can move the ball to adjacent
# Space - O(1) # cell or cross the grid boundary in four directions (up, down, left, right). However,
you can at most move N times.
class Solution(object): # Find out the number of paths to move the ball out of grid boundary. The answer may be
def minDistance(self, height, width, tree, squirrel, nuts): very large,
""" # return it after mod 10^9 + 7.
:type height: int
:type width: int # Dynamic programming. For each time step, calculate the nb paths to reach each cell.
:type tree: List[int] Running total of paths to reach
:type squirrel: List[int] # boundary is increased at each step by number of previous paths to cells next to edge.
:type nuts: List[List[int]] Update paths at next step
:rtype: int # according to sum of all paths to neighbour cell from previous step.
""" # Alternatively, recursion requires more space but is practically faster.
if not nuts: # Time - O(m * n * N)
return 0 # Space - O(m * n)
class Solution(object):
def findPaths(self, m, n, N, i, j):
""" # python_1_to_1000/581_Shortest_Unsorted_Continuous_Subarray.py - m
:type m: int
:type n: int _author_ = 'jake'
:type N: int _project_ = 'leetcode'
:type i: int
:type j: int # https://leetcode.com/problems/shortest-unsorted-continuous-subarray/
:rtype: int # Given an integer array, you need to find one continuous subarray that if you only sort
""" this subarray in ascending
paths = 0 # order, then the whole array will be sorted in ascending order, too.
dp = [[0 for _ in range(n)] for _ in range(m)] # nb paths to reach each cell # You need to find the shortest such subarray and output its length.
dp[i][j] = 1 # intially 1 for start position
# Iterate over nums from left to right. If any num is less than the previous then the
for _ in range(N): previous must require sorting.
# Any number before the previous that is more than the minimum after the previous also
new_dp = [[0 for _ in range(n)] for _ in range(m)] requires sorting.
# Follow a similar procedure from right to left finding the first increase and subsequent
for r in range(m): maximum.
for c in range(n): # Alternatively, compare a sorted copy of the list to the original list and find the
first and last mismatches.
if r == 0: # Time - O(n)
paths += dp[r][c] # Space - O(1)
if r == m - 1:
paths += dp[r][c] class Solution(object):
if c == 0: def findUnsortedSubarray(self, nums):
paths += dp[r][c] """
if c == n - 1: :type nums: List[int]
paths += dp[r][c] :rtype: int
paths %= 10 ** 9 + 7 """
n = len(nums)
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]: right, left = -1, -1 # default values
if 0 <= r + dr < m and 0 <= c + dc < n:
new_dp[r + dr][c + dc] += dp[r][c] for i in range(1, n):
new_dp[r][c] %= 10 ** 9 + 7 if left == - 1 and nums[i] < nums[i - 1]:
left = i - 1 # first index to be sorted
dp = new_dp min_num = nums[i]
elif left != -1: # update subsequent minimum
return paths min_num = min(min_num, nums[i])

if left == -1: # still default, list already sorted


return 0
class Solution2(object):
def findPaths(self, m, n, N, i, j): for i in range(n - 2, -1, -1):
if right == -1 and nums[i] > nums[i + 1]:
def helper(r, c, steps): right = i + 1 # last index to be sorted
max_num = nums[i]
if steps == 0: elif right != -1: # update subsequent maximum
return 0 max_num = max(max_num, nums[i])

if (r, c, steps) in memo: while left > 0 and nums[left - 1] > min_num: # nums[left - 1] requires
return memo[(r, c, steps)] sorting
left -= 1
paths = 0 while right < n - 1 and nums[right + 1] < max_num: # nums[right + 1] requires
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]: sorting
if 0 <= r + dr < m and 0 <= c + dc < n: right += 1
paths += helper(r + dr, c + dc, steps - 1)
else: return right - left + 1
paths += 1 # one path to exit grid
paths %= 10 ** 9 + 7
# python_1_to_1000/582_Kill_Process.py - m
memo[(r, c, steps)] = paths
return paths _author_ = 'jake'
_project_ = 'leetcode'
memo = {}
return helper(i, j, N) # https://leetcode.com/problems/kill-process/
# Given n processes, each process has a unique PID (process id) and its PPID (parent
process id).
# Each process only has one parent process, but may have one or more children processes.

This is just like a def LCS(s, t):


# tree structure. Only one process has PPID that is 0, which means this process has no prev_dp = [0 for _ in range(len(word2) + 1)]
parent process.
# All the PIDs will be distinct positive integers. for i in range(1, len(word1) + 1): # length of word1 prefix
# We use two list of integers to represent a list of processes, where the first list dp = [0]
contains PID for each process
# and the second list contains the corresponding PPID. for j in range(1, len(word2) + 1): # length of word2 prefix
# Now given the two lists, and a PID representing a process you want to kill, return a if word1[i - 1] == word2[j - 1]:
list of PIDs of processes that dp.append(1 + prev_dp[j - 1])
# will be killed in the end. You should assume that when a process is killed, all its else:
children processes will be killed. dp.append(max(dp[-1], prev_dp[j]))
# No order is required for the final answer.
prev_dp = dp
# Create a dictionary mapping processes to their children. DFS. Keep processes to be
killed in a list. Pop process off return prev_dp[-1]
# list and add children.
# Time - O(n) return len(word1) + len(word2) - 2 * LCS(word1, word2)
# Space - O(n)

from collections import defaultdict # python_1_to_1000/587_Erect_The_Fence.py - h

class Solution(object): _author_ = 'jake'


def killProcess(self, pid, ppid, kill): _project_ = 'leetcode'
"""
:type pid: List[int] # https://leetcode.com/problems/erect-the-fence/
:type ppid: List[int] # There are some trees, where each tree is represented by (x,y) coordinate in a two-
:type kill: int dimensional garden. Your job is to
:rtype: List[int] # fence the entire garden using the minimum length of rope as it is expensive. The garden
""" is well fenced only if all
node_to_children = defaultdict(list) # the trees are enclosed. Your task is to help find the coordinates of trees which are
exactly located on the fence
for node, parent in zip(pid, ppid): # perimeter.
node_to_children[parent].append(node)
# Find the lowest point (most -ve y coordinate), breaking ties by most negative x-
killed, to_kill = [], [kill] coordinate. Create a convex hull
# starting from this point. Sort other points by gradient, breaking ties with highest y
while to_kill: coordinate then lowest x
process = to_kill.pop() # coordinate. For each point in sorted order (anti-clockwise around the hull), while the
killed.append(process) cross-product of this point
to_kill += node_to_children[process] # and the last 2 points on the hull is negative, the 3 points turn clockwise so remove
the last point from the hull.
return killed # Time - O(n log n)
# Space - O(n)

# python_1_to_1000/583_Delete_Operation_for_Two_Strings.py - m # Definition for a point.


class Point(object):
_author_ = 'jake' def __init__(self, a=0, b=0):
_project_ = 'leetcode' self.x = a
self.y = b
# https://leetcode.com/problems/delete-operation-for-two-strings/
# Given two words word1 and word2, find the minimum number of steps required to make class Solution(object):
word1 and word2 the same, where def outerTrees(self, points):
# in each step you can delete one character in either string. """
:type points: List[Point]
# Retain the longest common subsequence of both words, after deleting all other :rtype: List[Point]
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 if len(points) < 3:
without their final chars. return points
# Else take the longest LCS after ignoring the final char from one word.
# Time - O(m * n) def slope(a, b): # of line from a to b
# Space - O(n) if a.x == b.x:
return float("inf")
class Solution(object): return (b.y - a.y) / float(b.x - a.x)
def minDistance(self, word1, word2):
""" def cross_product(p):
:type word1: str v1 = [result[-1].x - result[-2].x, result[-1].y - result[-2].y]
:type word2: str v2 = [p.x - result[-2].x, p.y - result[-2].y]
:rtype: int return v1[0] * v2[1] - v1[1] * v2[0]
"""
# find point with lowest x value, then lowest y value if path[-1] in self.files:
start_point = min(points, key=lambda p: (p.x, p.y)) return [path[-1]] # list of single file
points.remove(start_point)
folder = self.root
# sort by slope, then closest (largest) y, then closest (smallest) x if path[-1] != "": # path of "/" is split to ["", ""]
points.sort(key=lambda p: (slope(start_point, p), -p.y, p.x)) for folder_string in path[1:]:
folder = folder.children[folder_string]
result = [start_point, points[0]] return sorted(list(folder.children.keys())) # sorted returns the list

for point in points[1:]: def mkdir(self, path):


while cross_product(point) < 0: """
result.pop() :type path: str
result.append(point) :rtype: void
"""
return result folder = self.root
for folder_string in path.split("/")[1:]: # ignore first empty string
if folder_string not in folder.children: # make new folder
folder.children[folder_string] = Folder()
folder = folder.children[folder_string]
# python_1_to_1000/588_Design_In-Memory_File_System.py - h
def addContentToFile(self, filePath, content):
_author_ = 'jake' """
_project_ = 'leetcode' :type filePath: str
:type content: str
# https://leetcode.com/problems/design-in-memory-file-system/ :rtype: void
# 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 path = filePath.split("/")
contains this file's name. If it is file_name = path[-1]
# a directory path, return the list of file and directory names in this directory. Your
output (file and directory if file_name in self.files:
# names together) should in lexicographic order. self.files[file_name] += content
# mkdir: Given a directory path that does not exist, you should make a new directory
according to the path. If the else:
# middle directories in the path don't exist either, you should create them as well. This self.files[file_name] = content
function has void return type. folder = self.root
# addContentToFile: Given a file path and file content in string format. If the file for folder_string in path[1:-1]:
doesn't exist, you need to create folder = folder.children[folder_string]
# that file containing given content. If the file already exists, you need to append folder.children[file_name] = None
given content to original content.
# This function has void return type. def readContentFromFile(self, filePath):
# readContentFromFile: Given a file path, return its content in string format. """
:type filePath: str
# Define a Folder as a mapping from names of files/folders to other Folders or None (for :rtype: str
files). File system consists """
# of root folder and mapping from file names to their contents. Separate file mapping file_name = filePath.split("/")[-1]
speeds content retrieval/update. return self.files[file_name]
# 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 # python_1_to_1000/589_N-ary_Tree_Preorder_Traversal.py
addContentToFile where t is
# total content. O(t) for readContentFromFile. _author_ = 'jake'
# Space - O(total nb folders + total content length) _project_ = 'leetcode'

class Folder(object): # https://leetcode.com/problems/n-ary-tree-preorder-traversal/


def __init__(self): # Given an n-ary tree, return the preorder traversal of its nodes' values.
self.children = {} # map from child names to Folders or None
# Stack contains nodes discovered and to be visited. Pop a node off the stack and append
its value to the result.
class FileSystem(object): # Add child nodes to stack in reverse order, so they are popped off in the original
def __init__(self): order.
self.root = Folder() # empty root folder # Time - O(n)
self.files = {} # map from file name to content # Space - O(n)

def ls(self, path): class Solution(object):


""" def preorder(self, root):
:type path: str """
:rtype: List[str] :type root: Node
""" :rtype: List[int]
path = path.split("/") """

if not root: # Among them, <TAG_NAME> is the start tag, and </TAG_NAME> is the end tag. The TAG_NAME
return [] 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
stack = [root] valid.
result = [] # 3) A valid TAG_NAME only contain upper-case letters, and has length in range [1,9].
Otherwise, the TAG_NAME
while stack: # is invalid.
# 4) A valid TAG_CONTENT may contain other valid closed tags, cdata and any characters
node = stack.pop() (see note1) EXCEPT
result.append(node.val) # unmatched <, unmatched start and end tag, and unmatched or closed tags with invalid
TAG_NAME.
for child in reversed(node.children): # Otherwise, the TAG_CONTENT is invalid.
stack.append(child) # 5) A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice
versa. However, you also need to
return result # consider the issue of unbalanced when tags are nested.
# 6) A < is unmatched if you cannot find a subsequent >. And when you find a < or </, all
the subsequent characters
# python_1_to_1000/590_N-ary_Tree_Postorder_Traversal.py # until the next > should be parsed as TAG_NAME (not necessarily valid).
# 7) The cdata has the following format : <![CDATA[CDATA_CONTENT]]>. The range of
_author_ = 'jake' 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
# https://leetcode.com/problems/n-ary-tree-postorder-traversal/ validator to parse CDATA_CONTENT,
# Given an n-ary tree, return the postorder traversal of its nodes' values. # so even it has some characters that can be parsed as tag (no matter valid or invalid),
you should treat it as
# Visit the nodes in reverse postorder and reverse the result i.e. visit a node, then the # regular characters.
children in reverse order.
# Stack contains nodes discovered and to be visited. # Iterate over input. status variable tracks whether we are in an opening or closing tag,
# While stack, pop off a node and visit it. Add children to stack in given order, so they or in cdata or in text.
are visited in reverse order. # Stack stores open tags.
# Time - O(n) # Time - O(n)
# Space - O(n) # Space - O(n)

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


def postorder(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
result = []
while i < len(code):
while stack: c = code[i]

node = stack.pop() if status == "text":


result.append(node.val) if c == "<":
if i + 1 < len(code) and code[i + 1] == "/":
for child in node.children: status = "closing"
stack.append(child) i += 2
tag_start = i # record starting index in oreedr to check
return result[::-1] length
elif i + 8 < len(code) and code[i + 1:i + 9] == "![CDATA[" and
tag_stack: # must have opened a tag
# python_1_to_1000/591_Tag_Validator.py - h status = "cdata"
i += 9
_author_ = 'jake' else:
_project_ = 'leetcode' status = "opening"
i += 1
# https://leetcode.com/problems/tag-validator/ tag_start = i
# Given a string representing a code snippet, you need to implement a tag validator to elif not tag_stack: # must have opened a tag
parse the code and return return False
# whether it is valid. A code snippet is valid if all the following rules hold: else:
i += 1
# 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 : elif status in ["opening", "closing"]:
<TAG_NAME>TAG_CONTENT</TAG_NAME>. if code[i] == ">":
tag = code[tag_start:i] end += 1
if len(tag) < 1 or len(tag) > 9: fraction = [int(expression[start:end + 1])]
return False
if status == "opening": start = end = end + 2
tag_stack.append(tag) while end + 1 < len(expression) and expression[end + 1] not in ["+", "-"]:
else: end += 1
if not tag_stack or tag_stack.pop() != tag: fraction.append(int(expression[start:end + 1]))
return False
if not tag_stack and i != len(code) - 1: # cannot close all lcm = fraction[1] * result[1] // GCD(fraction[1], result[1])
tags if not at end of code
return False result = [(result[0] * lcm // result[1]) + (fraction[0] * lcm //
status = "text" fraction[1]), lcm]
elif c not in upper: start = end + 1
return False
i += 1 if result[0] == 0:
return "0/1"
elif status == "cdata":
if i + 2 < len(code) and code[i:i + 3] == "]]>": gcd = GCD(result[0], result[1])
i += 3 return str(result[0] // gcd) + "/" + str(result[1] // gcd)
status = "text"
else:
i += 1 # python_1_to_1000/593_Valid_Square.py - m

return status == "text" and not tag_stack _author_ = 'jake'


_project_ = 'leetcode'

# https://leetcode.com/problems/valid-square/
# python_1_to_1000/592_Fraction_Addition_And_Subtraction.py - m # Given the coordinates of four points in 2D space, return whether the four points could
construct a square.
_author_ = 'jake' # The coordinate (x,y) of a point is represented by an integer array with two integers.
_project_ = 'leetcode'
# Calculate the squared distance from each point to each other point. A square has 4
# https://leetcode.com/problems/fraction-addition-and-subtraction/ sides of the same distance and 2
# Given a string representing an expression of fraction addition and subtraction, you # diagonals of twice the squared distance of the sides.
need to return the calculation # Time - O(1)
# result in string format. The final result should be irreducible fraction. If your final # Space - O(1)
result is an integer, say 2,
# you need to change it to the format of fraction that has denominator 1. So in this class Solution(object):
case, 2 should be converted to 2/1. def validSquare(self, p1, p2, p3, p4):
"""
# Parse the expression into integers, delimited by "/" for numerator and "+" or "-" for :type p1: List[int]
denominator. For each fraction, :type p2: List[int]
# find the lowest common multiple of the fraction denominator and the current result :type p3: List[int]
denominator. Convert both :type p4: List[int]
# fractions to this denominator and add their numerators to update the result. Repeat for :rtype: bool
all fractions. """
# Divide the result by the lowest common multiple of its numerator and denominator. def square_dist(a, b):
# Time - O(n log m) there n is number of fractions and m is hte maximum numerator or return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
denominator
# Space - O(1) points = [p1, p2, p3, p4]
square_dists = [square_dist(points[i], points[j]) for i in range(4) for j in
class Solution(object): range(i + 1, 4)]
def fractionAddition(self, expression):
""" side = min(square_dists)
:type expression: str if max(square_dists) != 2 * side:
:rtype: str return False
"""
def GCD(a, b): # Euclid's algortihm for greatest common divisor return square_dists.count(side) == 2 * square_dists.count(2 * side)
div, mod = divmod(a, b)
if mod == 0:
return b # python_1_to_1000/594_Longest_Harmonious_Subsequence.py
return GCD(b, mod)
_author_ = 'jake'
result = [0, 1] # list of numerator and denominator _project_ = 'leetcode'
start = 0
# https://leetcode.com/problems/longest-harmonious-subsequence/
while start < len(expression): # We define a harmonious array is an array where the difference between its maximum value
end = start and its minimum value
while expression[end + 1] != "/": # is exactly 1. Given an integer array, you need to find the length of its longest

harmonious subsequence among all _author_ = 'jake'


# its possible subsequences. _project_ = 'leetcode'

# Count the frequency of each num in nums. For each num we create a subsequence of that # https://leetcode.com/problems/minimum-index-sum-of-two-lists/
num and num + 1. If num + 1 is # Suppose Andy and Doris want to choose a restaurant for dinner, and they both have a
# not in nums then no subsequence can be created. Else update max_harmonious according to list of favorite restaurants
counts of num and num + 1. # represented by strings.
# Time - O(n) # You need to help them find out their common interest with the least list index sum.
# Space - O(n) # If there is a choice tie between answers, output all of them with no order requirement.
# You could assume there always exists an answer.
from collections import Counter
# Create a dictionary of the shorter list mapping restaurant to index. For each
class Solution(object): restaurant in the longer list, if it
def findLHS(self, nums): # 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
:type nums: List[int] # minimum then make it the lone result.
:rtype: int # Time - O(m + n)
""" # Space - O(min(m, n))
freq = Counter(nums)
max_harmonious = 0 class Solution(object):
def findRestaurant(self, list1, list2):
for num, count in freq.items(): """
if num + 1 in freq: # difference must be exactly one, not zero :type list1: List[str]
max_harmonious = max(max_harmonious, count + freq[num + 1]) :type list2: List[str]
:rtype: List[str]
return max_harmonious """
if len(list1) > len(list2): # swap to make list1 shorter
list1, list2 = list2, list1

# python_1_to_1000/598_Range_Addition_II.py dict1 = {rest: i for i, rest in enumerate(list1)}

_author_ = 'jake' result = []


_project_ = 'leetcode' min_sum = float("inf")

# https://leetcode.com/problems/range-addition-ii/ for i, rest in enumerate(list2):


# Given an m * n matrix M initialized with all 0's and several update operations.
# Operations are represented by a 2D array, and each operation is represented by an array if i > min_sum: # subsequent list2 entries cannot improve
with two positive break
# integers a and b, which means M[i][j] should be added by one for all 0 <= i < a and 0
<= j < b. if rest not in dict1:
# You need to count and return the number of maximum integers in the matrix after continue
performing all the operations.
sum_i = i + dict1[rest]
# Track the row and column edges of the part of the matrix containing the max integer.
For each operation, update if sum_i < min_sum: # new best
# the row and column edges according to the minimum of the current values and the row and min_sum = sum_i
columns of the operation. result = [rest]
# Time - O(n) elif sum_i == min_sum: # tie with current best
# Space - O(1) result.append(rest)

class Solution(object): return result


def maxCount(self, m, n, ops):
"""
:type m: int # python_1_to_1000/600_Non-negative_Integers_without_Consecutive_Ones.py - h
:type n: int
:type ops: List[List[int]] _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
max_r, max_c = m, n # initially whole matrix contains max integer # https://leetcode.com/problems/non-negative-integers-without-consecutive-ones/
# Given a positive integer n, find the number of non-negative integers less than or equal
for r, c in ops: to n, whose binary
max_r = min(max_r, r) # representations do NOT contain consecutive ones.
max_c = min(max_c, c)
# Use dynamic programming to calculate the number of integers without repeated set bits
return max_r * max_c and with most significant bit
# of 0 and of 1, up to the same number of bits as num.
# Also dynamically update count of valid integers as num is extended from least
# python_1_to_1000/599_Minimum_Index_Sum_of_Two_Lists.py 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 # hasNext() - Judge whether there is any letter needs to be uncompressed.
# this length are possible. If last bits are "01" then valid integers ending in 1 are all
previous valid integers # Serve the next letter on demand. Maintain the current letter and count of how many
# extended by one, valid integers ending in zero are all valid integers of this length remaining unused instances.
ending in zero. # Also maintain index of next letter in compressedString.
# Time - O(log n) # Time - O(n) for next, O(1) for init and hasNext.
# Space - O(log n) # Space - O(1)

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


def findIntegers(self, num):
""" def __init__(self, compressedString):
:type num: int """
:rtype: int :type compressedString: str
""" """
# remove "0b" prefix and reverse so least significant bit has lowest index self.letter = None
binary = bin(num)[2:][::-1] self.count = 0 # number of current letter remaining
self.i = 0 # index of next letter after current is used
# zero_highest[i] is the number of non-negative integers with i + 1 bits and self.s = compressedString
highest bit of zero
# that do not contain consecutive set bits. Note that zero_highest[i - 1] def next(self):
overlaps with and is a """
# subset of zero_highest[i] :rtype: str
zero_highest = [1] """
one_highest = [1] if not self.hasNext():
return " "
if binary[0] == "0":
count = 1 if self.count == 0:
else: self.move()
count = 2 self.count -= 1 # decrement count of this letter
return self.letter
for bit in range(1, len(binary)): # iterate over prefixes from least significant
bit def hasNext(self):
"""
# can append zero to all shorter valid numbers ending in zero or one :rtype: bool
zero_highest.append(zero_highest[-1] + one_highest[-1]) """
# can only append one to all shorter valid numbers ending in zero return self.count > 0 or self.i < len(self.s)
one_highest.append(zero_highest[-2])
def move(self):
if binary[bit] == "1" and binary[bit - 1] == "1": self.letter = self.s[self.i]
# prefix ends in "11" so all integers of same length or shorter self.count = 0
# without consecutive set bits are less than prefix regardless of ending self.i += 1
in 0 or 1.
# reset count to all valid integers while self.i < len(self.s) and self.s[self.i] <= "9": # while digit
count = zero_highest[-1] + one_highest[-1] self.count = self.count * 10 + int(self.s[self.i]) # update count with digit
self.i += 1
elif binary[bit] == "1" and binary[bit - 1] == "0":
# prefix ends in "10" so can append "1" to all previous integers
# plus can add all integers of this length ending with "0"
count += zero_highest[-1] # python_1_to_1000/605_Can_Place_Flowers.py

# else if most significant bit of prefix is "0" then count is unchanged _author_ = 'jake'
# but no incermentail new integers are valid _project_ = 'leetcode'

return count # https://leetcode.com/problems/can-place-flowers/


# Suppose you have a long flowerbed in which some of the plots are planted and some are
not.
# python_1_to_1000/604_Design_Compressed_String_Iterator.py # However, flowers cannot be planted in adjacent plots - they would compete for water and
both would die.
_author_ = 'jake' # Given a flowerbed (represented as an array containing 0 and 1, where 0 means empty and
_project_ = 'leetcode' 1 means not empty),
# and a number n, return if n new flowers can be planted in it without violating the no-
# https://leetcode.com/problems/design-compressed-string-iterator/ adjacent-flowers rule.
# Design and implement a data structure for a compressed string iterator.
# It should support the following operations: next and hasNext. # Iterate over flowerbed. Check for flowers at i + 1, i and i - 1 in that order. If
# The given compressed string will be in the form of each letter followed by a positive flower found, jump to next
integer representing the # possible empty index. Else plant flower (decrement count, no need to amend flowerbed)
# number of this letter existing in the original uncompressed string. and jump 2 indices.
# next() - if the original string still has uncompressed characters, return the next # Time - O(n)
letter; Otherwise return a space. # Space - O(1)

if not node.left and not node.right:


class Solution(object): return
def canPlaceFlowers(self, flowerbed, n):
""" result.append("(")
:type flowerbed: List[int] preorder(node.left)
:type n: int result.append(")")
:rtype: bool
""" if node.right:
flowerbed.append(0) # avoid special case for last index result.append("(")
i = 0 preorder(node.right)
result.append(")")
while n > 0 and i < len(flowerbed) - 1:
preorder(t)
if flowerbed[i + 1] == 1: return "".join(result)
i += 3
elif flowerbed[i] == 1:
i += 2 # python_1_to_1000/609_Find_Duplicate_File_in_System.py - m
elif i != 0 and flowerbed[i - 1] == 1:
i += 1 _author_ = 'jake'
else: _project_ = 'leetcode'
n -= 1
i += 2 # https://leetcode.com/problems/find-duplicate-file-in-system/
# Given a list of directory info including directory path, and all the files with
return n == 0 contents in this directory, you
# need to find out all the groups of duplicate files in the file system in terms of their
paths.
# python_1_to_1000/606_Construct_String_from_Binary_Tree.py - m # A group of duplicate files consists of at least two files that have exactly the same
content.
_author_ = 'jake' # A single directory info string in the input list has the following format:
_project_ = 'leetcode' # "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)"
# It means there are n files (f1.txt, f2.txt ... fn.txt with content f1_content,
# https://leetcode.com/problems/construct-string-from-binary-tree/ f2_content ... fn_content,
# You need to construct a string consists of parenthesis and integers from a binary tree # respectively) in directory root/d1/d2/.../dm. Note that n >= 1 and m >= 0. If m = 0, it
in a preorder traversal. means the directory is just
# The null node needs to be represented by empty parenthesis pair "()". And you need to # the root directory.
omit all the empty parenthesis # The output is a list of group of duplicate file paths. For each group, it contains all
# pairs that don't affect the one-to-one mapping relationship between the string and the the file paths of the files
original binary tree. # that have the same content. A file path is a string that has the following format:
# "directory_path/file_name.txt"
# Preorder traversal. Append to the result the string of the node.val. If neither left
nor right children, return. # Create mapping of file content to its path (including file name).
# Add brackets before and after left subtree, since empty brackets are required if left # Time - O(n * k), number of paths * max path length
subtree is None. If right # Space - O(n * k)
# subtree exists, add brackets before and after it.
# Time - O(n) from collections import defaultdict
# Space - O(n)
class Solution(object):
# Definition for a binary tree node. def findDuplicate(self, paths):
# class TreeNode(object): """
# def __init__(self, x): :type paths: List[str]
# self.val = x :rtype: List[List[str]]
# self.left = None """
# self.right = None content_to_path = defaultdict(list)

class Solution(object): for path in paths:


def tree2str(self, t): path_list = path.split(" ") # path_list[0] is the path, other entries are
""" files
:type t: TreeNode
:rtype: str for f in path_list[1:]:
""" open_bracket = f.index("(")
result = [] close_bracket = f.index(")")
content = f[open_bracket + 1:close_bracket]
def preorder(node): content_to_path[content].append(path_list[0] + "/" + f[:open_bracket])

if not node: return [dup for dup in content_to_path.values() if len(dup) > 1] # only return
return if at least 2 files

result.append(str(node.val))
# python_1_to_1000/611_Valid_Triangle_Number.py - m return 0
return factorial(n) // (factorial(n - k) * factorial(k))
_author_ = 'jake'
_project_ = 'leetcode' for i, (s1, c1) in enumerate(sides):
for j, (s2, c2) in enumerate(sides[i:]):
# https://leetcode.com/problems/valid-triangle-number/ j2 = j + i
# Given an array consists of non-negative integers, your task is to count the number of for s3, c3 in sides[j2:]:
triplets chosen from the if s1 == s2 == s3: # all sides same length
# array that can make triangles if we take them as side lengths of a triangle. triangles += binom(c1, 3)
elif s1 == s2: # shortest 2 sides are same lenght
# Iterate over sides in order of decreasing length. With current side as longest of if s1 + s2 > s3:
triangle, consider the range of triangles += c3 * binom(c1, 2)
# all shorter sides. Set shortest_side and middle_side as the shortest and longest sides elif s2 == s3: # longest sides are same length
in this range. If shortest + triangles += c1 * binom(c2, 2)
# middle <= longest then cannot make a triangle so increase shortest. If a triangle can else: # all different lengths
be made, then all longer if s1 + s2 > s3:
# shortest sides can also make a triangle so increment count and decrement middle side. triangles += c1 * c2 * c3
# Time - O(n**2)
# Space - O(1) return triangles
# 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. # python_1_to_1000/616_Add_Bold_Tag_in_String.py - m
O(n**3) but faster if
# many duplicate lengths. _author_ = 'jake'
_project_ = 'leetcode'
from collections import Counter
# https://leetcode.com/problems/add-bold-tag-in-string/
class Solution(object): # Given a string s and a list of strings dict, you need to add a closed pair of bold tag
def triangleNumber(self, nums): <b> and </b> to wrap the
""" # substrings in s that exist in dict. If two such substrings overlap, you need to wrap
:type nums: List[int] them together by only one pair
:rtype: int # of closed bold tag. Also, if two substrings wrapped by bold tags are consecutive, you
""" need to combine them.
nums.sort()
triangles = 0 # Create mapping of start letter to list of words in dictionary. Iterate over string,
maintaining a list of words from
for i, longest_side in enumerate(nums): # dictionary that have partially matched s up to the current index. Matches list consist
left, right = 0, i - 1 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
while left < right: matched, mark all those chars
shortest_side, middle_side = nums[left], nums[right] # in s as being in_tag. Finally, construct result by inserting opening and closing tags.
# Time - O(n * k * m), n words in dictionary of max length k, len(s) == m
if shortest_side + middle_side > longest_side: # equality is not a # Space - O(nk + m)
triangle
triangles += right - left # current shortest and all longer up to from collections import defaultdict
middle can make triangles
right -= 1 # decrement middle_side class Solution(object):
else: def addBoldTag(self, s, dict):
left += 1 # increment shortest_side """
:type s: str
return triangles :type dict: List[str]
:rtype: str
"""
from math import factorial in_tag = [False for _ in range(len(s))] # bool indicates whether char should be
class Solution2(object): inside bold tag
def triangleNumber(self, nums):
""" start_letters = defaultdict(list) # mapping from start char to list of
:type nums: List[int] words with that start char
:rtype: int for word in dict:
""" start_letters[word[0]].append(word)
sides = Counter(nums)
if 0 in sides: matches = [] # list of (word, word_index) that
del sides[0] partially match s up word_index
sides = list(sides.items()) # tuples of (side length, count)
sides.sort() for i, c in enumerate(s):
triangles = 0
new_matches = []
def binom(n, k):
if k > n: for word, word_index in matches:

if c == word[word_index + 1]:
if word_index + 1 == len(word) - 1: # end of word so mark range # python_1_to_1000/621_Task_Scheduler.py - m
of in_tag
for j in range(i - len(word) + 1, i + 1): _author_ = 'jake'
in_tag[j] = True _project_ = 'leetcode'
else:
new_matches.append([word, word_index + 1]) # add to new list # https://leetcode.com/problems/task-scheduler/
with next word_index # Given a char array representing tasks CPU need to do. It contains capital letters A to
Z where different letters
for word in start_letters[c]: # words with first char == c # represent different tasks.Tasks could be done without original order. Each task could
if len(word) == 1: be done in one interval.
in_tag[i] = True # For each interval, CPU could finish one task or just be idle.
else: # However, there is a non-negative cooling interval n that means between two same tasks,
new_matches.append([word, 0]) there must be at least n
# intervals that CPU are doing different tasks or just be idle.
matches = new_matches # You need to return the least number of intervals the CPU will take to finish all the
given tasks.
result = []
for i, c in enumerate(s): # Find the most frequent task and calculate the time to complete all instances of this
task as the wait between tasks
if in_tag[i] and (i == 0 or not in_tag[i - 1]): # open tag # (n + 1) times the number of waits (nb_tasks - 1). For each task with the same count as
result.append("<b>") the most frequent, increment
elif not in_tag[i] and (i != 0 and in_tag[i - 1]): # close tag # the finishing time. All less frequent tasks can be scheduled to fill the remaining idle
result.append("</b>") time, or else they extend
# the finish time without any idle time.
result.append(c) # In other words, the only situation when the tasks cannot be completed without idle time
is when the most frequent
if in_tag[-1]: # task(s) cannot be scheduled within the length of tasks.
result.append("</b>") # final close tag # Time - O(n * m), nb tasks * nb types of task
return "".join(result) # Space - O(m)

from collections import Counter


# python_1_to_1000/617_Merge_Two_Binary_Trees.py
class Solution(object):
_author_ = 'jake' def leastInterval(self, tasks, n):
_project_ = 'leetcode' """
:type tasks: List[str]
# https://leetcode.com/problems/merge-two-binary-trees/ :type n: int
# Given two binary trees and imagine that when you put one of them to cover the other, :rtype: int
some nodes of the two trees """
# are overlapped while the others are not. counts = Counter(tasks)
# You need to merge them into a new binary tree. The merge rule is that if two nodes max_count = max(counts.values())
overlap, then sum node values
# up as the new value of the merged node. Otherwise, the NOT null node will be used as result = (max_count - 1) * (n + 1) # n + 1 time between max_count tasks
the node of new tree.
for count in counts.values():
# If either or both of t1 and t2 are None, return t1 or t2. Else create a root node with if count == max_count: # each task pushes back finish time
the sum of the values and result += 1
# recursively create the left and right subtrees.
# Time - O(n) return max(result, len(tasks)) # other tasks fill idle time
# Space - O(1)

class Solution(object):
def mergeTrees(self, t1, t2):
"""
:type t1: TreeNode # python_1_to_1000/622_Design_Circular_Queue.py - m
:type t2: TreeNode
:rtype: TreeNode _author_ = 'jake'
""" _project_ = 'leetcode'
if t1 and t2:
root = TreeNode(t1.val + t2.val) # https://leetcode.com/problems/design-circular-queue/
# Design your implementation of the circular queue. The circular queue is a linear data
root.left = self.mergeTrees(t1.left, t2.left) structure in which the
root.right = self.mergeTrees(t1.right, t2.right) # operations are performed based on FIFO (First In First Out) principle and the last
position is connected back to
return root # the first position to make a circle. It is also called "Ring Buffer".
# One of the benefits of the circular queue is that we can make use of the spaces in
return t1 or t2 front of the queue.
# In a normal queue, once the queue becomes full, we cannot insert the next element even
if there is a space in front if self.isEmpty():
# of the queue. But using the circular queue, we can use the space to store new values. return -1
# Your implementation should support following operations: return self.q[(self.tail + 1) % self.k]
#
# MyCircularQueue(k): Constructor, set the size of the queue to be k. def isEmpty(self):
# Front: Get the front item from the queue. If the queue is empty, return -1. """
# Rear: Get the last item from the queue. If the queue is empty, return -1. Checks whether the circular queue is empty or not.
# enQueue(value): Insert an element into the circular queue. Return true if the operation :rtype: bool
is successful. """
# deQueue(): Delete an element from the circular queue. Return true if the operation is return self.head == self.tail
successful.
# isEmpty(): Checks whether the circular queue is empty or not. def isFull(self):
# isFull(): Checks whether the circular queue is full or not. """
Checks whether the circular queue is full or not.
# Use a python list as a circular array. Add an extra space, which allows us to :rtype: bool
distinguish between empty and full """
# queues. return (self.head + 1) % self.k == self.tail
# Time - O(1)
# Space - O(n)
# python_1_to_1000/623_Add_One_Row_to_Tree.py - m
class MyCircularQueue(object):
_author_ = 'jake'
def __init__(self, k): _project_ = 'leetcode'
"""
Initialize your data structure here. Set the size of the queue to be k. # https://leetcode.com/problems/add-one-row-to-tree/
:type k: int # 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
self.k = k + 1 # always have one space to separate head from tail # depth d. The root node is at depth 1.
self.q = [None] * self.k # The adding rule is: given a positive integer depth d, for each NOT null tree nodes N in
self.head = self.tail = 0 # tail is always empty depth d-1, create two tree
# nodes with value v as N's left subtree root and right subtree root. And N's original
def enQueue(self, value): left subtree should be the left
""" # subtree of the new left subtree root, its original right subtree should be the right
Insert an element into the circular queue. Return true if the operation is subtree of the new right subtree
successful. # root. If depth d is 1 that means there is no depth d-1 at all, then create a tree node
:type value: int with value v as the new root
:rtype: bool # of the whole original tree, and the original tree is the new root's left subtree.
"""
if self.isFull(): # If d == 1 create a new root. If d == 2 insert new nodes between root and its children.
return False Else recurse to next depth.
self.q[self.tail] = value # Time - O(n)
self.tail = (self.tail - 1) % self.k # Space - O(n)
return True
class Solution(object):
def deQueue(self): def addOneRow(self, root, v, d):
""" """
Delete an element from the circular queue. Return true if the operation is :type root: TreeNode
successful. :type v: int
:rtype: bool :type d: int
""" :rtype: TreeNode
if self.isEmpty(): """
return False if not root:
self.head = (self.head - 1) % self.k # just move head, no need to delete element return None
return True
if d == 1: # create a new root and put existing tree on left
def Front(self): root, root.left = TreeNode(v), root
""" elif d == 2: # new nodes as children of root
Get the front item from the queue. old_left, old_right = root.left, root.right
:rtype: int root.left, root.right = TreeNode(v), TreeNode(v)
""" root.left.left, root.right.right = old_left, old_right
if self.isEmpty(): else: # recurse at next depth
return -1 self.addOneRow(root.left, v, d - 1)
return self.q[self.head] self.addOneRow(root.right, v, d - 1)

def Rear(self): return root


"""
Get the last item from the queue.
:rtype: int # python_1_to_1000/624_Maximum_Distance_in_Arrays.py - m
"""

_author_ = 'jake'
_project_ = 'leetcode' result += digit * tens

# https://leetcode.com/problems/maximum-distance-in-arrays/ if result > 2 ** 31:


# Given m arrays, and each array is sorted in ascending order. Now you can pick up two return 0
integers from two different
# arrays (each array picks one) and calculate the distance. We define the distance a //= digit
between two integers a and b to be if a == 1:
# their absolute difference |a-b|. Your task is to find the maximum distance. return result
tens *= 10
# For each array, update the max_dist using either the maximum from this array and the
previous minimum from other return 0
# 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. # python_1_to_1000/628_Maximum_Product_of_Three_Numbers.py
# Time - O(n) number of arrays
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def maxDistance(self, arrays): # https://leetcode.com/problems/maximum-product-of-three-numbers/
""" # Given an integer array, find three numbers whose product is maximum and output the
:type arrays: List[List[int]] maximum product.
:rtype: int
""" # For 2 numbers, maximum is either largest pair or smallest (most negative) pair.
low, high = arrays[0][0], arrays[0][-1] # For 3 numbers, use the maximum from 2 numbers and the next largest.
max_dist = 0 # Sort the array to find the smallest and largest, alternatively iterate over array
tracking top 3 and bottom 2 in O(n).
for array in arrays[1:]: # Time - O(n log n)
# Space - O(1)
max_dist = max(max_dist, abs(array[-1] - low), abs(array[0] - high))
low = min(low, array[0]) class Solution(object):
high = max(high, array[-1]) def maximumProduct(self, nums):
"""
return max_dist :type nums: List[int]
:rtype: int
"""
# python_1_to_1000/625_Minimum_Factorization.py - m nums.sort()
top_3 = nums[-1] * nums[-2] * nums[-3]
_author_ = 'jake' top_bottom = nums[-1] * nums[0] * nums[1]
_project_ = 'leetcode'
return max(top_3, top_bottom)
# 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.
# If there is no answer or the answer is not fit in 32-bit signed integer, then return 0.
# python_1_to_1000/629_K_Inverse_Pairs_Array.py - h
# Iterating over the digits from 9 down to 2, find all the factors of each digit. Add
each factor to the result from _author_ = 'jake'
# the least significant digit first (which minimises the value since we start by removing _project_ = 'leetcode'
factors of 9). By starting
# with 9 we minimise the number of factors. # https://leetcode.com/problems/k-inverse-pairs-array/
# Time - O(log n) # Given two integers n and k, find how many different arrays consist of numbers from 1 to
# Space - O(1) n such that there are
# exactly k inverse pairs.
class Solution(object): # We define an inverse pair as following: For ith and jth element in the array, if i < j
def smallestFactorization(self, a): and a[i] > a[j] then it's
""" # an inverse pair; Otherwise, it's not.
:type a: int # Since the answer may be very large, the answer should be modulo 10**9 + 7.
:rtype: int
""" # Given the counts of arrangements with i inverse pairs of integers up to n, where i <=
if a == 1: k, find the counts for n + 1.
return 1 # Store the cumulative sums of arrangements by number of inverse pairs.
# We can put n + 1 at any position in the array to increase the number of arrangements by
result = 0 anywhere from 0 to n for
tens = 1 # all existing arrangements. To find the cumulative count for n + 1, nb_pairs, add the
cumulative count for n + 1,
for digit in range(9, 1, -1): # nb_pairs - 1 to the cumulative count for n, nb_pairs. If nb_pairs cannot be reached by
adding n pairs, subtract
while a != 1 and a % digit == 0: # these from cumulative sum.
"""
# Time - O(n * k) total_length = 0
# Space - O(k) taken_courses = []

class Solution(object): courses.sort(key=lambda c: c[1]) # sort by increasing end time


def kInversePairs(self, n, k):
""" for duration, end in courses:
:type n: int
:type k: int if total_length + duration <= end: # can take this course
:rtype: int total_length += duration
""" heapq.heappush(taken_courses, -duration)
if k == 0:
return 1 elif -taken_courses[0] > duration: # take this course instead of current
longest
MODULO = 10 ** 9 + 7 neg_longest = heapq.heappushpop(taken_courses, -duration)
total_length += neg_longest + duration
# inverse_pairs[i] is nb arrangements for current num with <= i inverse pairs
inverse_pairs = [0 for _ in range(k + 1)] return len(taken_courses)

for num in range(1, n + 1): # increment num from 1 up to n


# python_1_to_1000/631_Design_Excel_Sum_Formula.py - h
next_inverse_pairs = [1] # always one sorted arrangement with no inverse
pairs _author_ = 'jake'
_project_ = 'leetcode'
for nb_pairs in range(1, k + 1):
# https://leetcode.com/problems/design-excel-sum-formula/
next_inverse_pairs.append(next_inverse_pairs[-1]) # cumulative sum # Your task is to design the basic function of Excel and implement the function of sum
next_inverse_pairs[-1] += inverse_pairs[nb_pairs] # add arrangements for formula. Specifically, you need
num-1 up to nb_pairs # to implement the following functions:
if nb_pairs - num >= 0: # can only increase by num-1 pairs # Excel(int H, char W): This is the constructor. The inputs represents the height and
next_inverse_pairs[-1] -= inverse_pairs[nb_pairs - num] width of the Excel form.
next_inverse_pairs[-1] %= MODULO # H is a positive integer, range from 1 to 26. It represents the height. W is a character
range from 'A' to 'Z'.
inverse_pairs = next_inverse_pairs # It represents that the width is the number of characters from 'A' to W. The Excel form
content is represented by a
return (inverse_pairs[-1] - inverse_pairs[-2]) % MODULO # mod is always positive # 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'.
# python_1_to_1000/630_Course_Schedule_III.py - h # void Set(int row, char column, int val): Change the value at C(row, column) to be val.
# int Get(int row, char column): Return the value at C(row, column).
_author_ = 'jake' # int Sum(int row, char column, List of Strings : numbers): This function calculate and
_project_ = 'leetcode' set the value at C(row,
# column), where the value should be the sum of cells represented by numbers. This
# https://leetcode.com/problems/course-schedule-iii/ function return the sum result
# There are n different online courses numbered from 1 to n. Each course has some # at C(row, column). This sum formula should exist until this cell is overlapped by
duration(course length) t and closed another value or another
# on dth day. A course should be taken continuously for t days and must be finished # sum formula.
before or on the dth day. # numbers is a list of strings that each string represent a cell or a range of
# You will start at the 1st day. cells. If the string represent a
# Given n online courses represented by pairs (t,d), your task is to find the maximal # single cell, then it has the following format : ColRow. For example, "F7"
number of courses that represents the cell at (7, F).
# can be taken. # If the string represent a range of cells, then it has the following format :
ColRow1:ColRow2. The range will
# Sort by increasing deadline time. If a set of courses can be done before a deadline, # always be a rectangle, and ColRow1 represent the position of the top-left cell,
then they can be done and ColRow2 represents the
# consecutively from the start time without gaps. # position of the bottom-right cell.
# Given the total length of all courses than can be taken so far, the course with the
next deadline can also be taken # Convert excel cell format to indices. Cells store integer or list of sum ranges. To
# if it does not extend the total length beyond its deadline. sum, recurse on each cell in
# Time - O(n log n) # range until a value is found.
# Space - O(n) # Time - O(m * n) for init, get and sum. O(1) for set.
# Alternatively, store sum results in cells and use pointers from dependents to update
import heapq sums on set().
# Space - O(m * n)
class Solution(object):
def scheduleCourse(self, courses): class Excel(object):
""" def _indices(self, r, c): # convert excel format to indices
:type courses: List[List[int]] return [r - 1, ord(c) - ord("A")]
:rtype: int

def __init__(self, H, W):


""" # https://leetcode.com/problems/smallest-range/
:type H: int # You have k lists of sorted integers in ascending order. Find the smallest range that
:type W: str includes at least one
""" # number from each of the k lists.
rows, cols = self._indices(H, W) # We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a ==
self.excel = [[0 for _ in range(cols + 1)] for _ in range(rows + 1)] d-c.

def set(self, r, c, v): # Maintain a priority queue 'window' with one number from each list, initially the first.
""" Remove lowest num from
:type r: int # window and add next num from its list. Update the heap min and max, and potentially
:type c: str overall min and max.
:type v: int # Time - O(m log n) where m is the total number of nums and n is number of lists
:rtype: void # Space - O(n)
"""
r, c, = self._indices(r, c) import heapq
self.excel[r][c] = v
class Solution(object):
def get(self, r, c): def smallestRange(self, nums):
""" """
:type r: int :type nums: List[List[int]]
:type c: str :rtype: List[int]
:rtype: int """
""" n = len(nums) # number of lists
r, c = self._indices(r, c) window = [(nums[i][0], 0, i) for i in range(n)] # (num, index in list, index
return self.get_i(r, c) # call get_i with indices of list)
heapq.heapify(window)
def get_i(self, r, c): # uses indices instead of excel format heap_min, heap_max = window[0][0], max([nums[i][0] for i in range(n)])
""" best_min, best_max = heap_min, heap_max
:type r: int
:type c: int while True:
:rtype: int _, i, i_list = heapq.heappop(window) # remove smalles num from
""" window
contents = self.excel[r][c]
if isinstance(contents, int): # base case of integer if i + 1 >= len(nums[i_list]): # end of i_list
return contents return [best_min, best_max]

total = 0 heapq.heappush(window, (nums[i_list][i + 1], i + 1, i_list)) # push next


for cells in contents: num from i_list
cell_range = cells.split(":") heap_min = window[0][0]
r1, c1 = self._indices(int(cell_range[0][1:]), cell_range[0][0]) heap_max = max(heap_max, nums[i_list][i + 1])
if heap_max - heap_min < best_max - best_min: # keep current range if not
if len(cell_range) == 1: # single cell better
r2, c2 = r1, c1 best_min, best_max = heap_min, heap_max
else: # range
r2, c2 = self._indices(int(cell_range[1][1:]), cell_range[1][0])
# python_1_to_1000/633_Sum_of_Square_Numbers.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/sum-of-square-numbers/


# Given a non-negative integer c, your task is to decide whether there're two integers a
def sum(self, r, c, strs): and b such that a2 + b2 = c.
"""
:type r: int # Incremetn a from 0 until 2 a**2 >= c. Check if b is an integer.
:type c: str # Time - O(sqrt(n))
:type strs: List[str] # Space - O(1)
:rtype: int
""" from math import sqrt
r, c = self._indices(r, c)
self.excel[r][c] = strs class Solution(object):
return self.get_i(r, c) # call get_i with indices def judgeSquareSum(self, c):
"""
:type c: int
# python_1_to_1000/632_Smallest_Range.py - h :rtype: bool
"""
_author_ = 'jake' a = 0
_project_ = 'leetcode'
while a <= sqrt(c / 2): However, granularity means the time
# level for consideration. For example, start = "2017:01:01:23:59:59", end =
b = sqrt(c - a ** 2) "2017:01:02:23:59:59",
if int(b) == b: # granularity = "Day", it means that we need to find the logs within the range from
return True Jan. 1st 2017 to Jan. 2nd 2017.
a += 1
# Store ids and timestamps in list. Retrieve by matching timestamp prefix up to gra.
return False # Time - O(1) for put, O(n) for retrieve.
# Space - O(n)
# Alternatively create a tree (similar to a prefix trie) where each node stores all ids
# python_1_to_1000/634_Find_the_Derangement_of_An_Array.py - m with a specific prefix. Tree
# has 6 levels. Nodes are created as required by put(). Retrieve by finding all ids
_author_ = 'jake' greater than or equal to start that
_project_ = 'leetcode' # are also less than or equal to end. Faster to retrieve because does not have string
comparison with all ids.
# https://leetcode.com/problems/find-the-derangement-of-an-array/
# In combinatorial mathematics, a derangement is a permutation of the elements of a set, class LogSystem(object):
such that no element appears def __init__(self):
# in its original position. self.prefixes = {"Year": 4, "Month": 7, "Day": 10, "Hour": 13, "Minute": 16,
# There's originally an array consisting of n integers from 1 to n in ascending order, "Second": 19}
you need to find the number self.logs = []
# of derangement it can generate.
# Also, since the answer may be very large, you should return the output mod 1^9 + 7. def put(self, id, timestamp):
"""
# Dynamic programming. Derangements of n numbers can be constructed by, :type id: int
# 1) putting n at any of the n - 1 locations in a derangement of n - 1 numbers, and :type timestamp: str
moving the number that was at i :rtype: void
# to the end (location n) + """
# 2) taking any arrangement of n - 1 number with one number in the correct place, self.logs.append((id, timestamp))
replacing that correct number with n
# and moving n to the end. def retrieve(self, s, e, gra):
# Arrangements with one correct are created by putting any number in its correct place """
and deranging the remainder. :type s: str
# Time - O(n) :type e: str
# Space - O(1) :type gra: str
:rtype: List[int]
class Solution(object): """
def findDerangement(self, n): result = []
""" pref = self.prefixes[gra]
:type n: int s_prefix, e_prefix = s[:pref], e[:pref]
:rtype: int
""" for id, timestamp in self.logs:
MODULO = 10 ** 9 + 7 if s_prefix <= timestamp[:pref] <= e_prefix:
derange, one_correct = 0, 1 result.append(id)

for i in range(2, n + 1): return result


derange, one_correct = (derange * (i - 1) + one_correct) % MODULO, (i *
derange) % MODULO
# Alternative solution
return derange class LogNode(object):
def __init__(self, nb_children):
self.ids = set()
self.children = [None for _ in range(nb_children)]
# python_1_to_1000/635_Design_Log_Storage_Function.py - m
class LogSystem2(object):
_author_ = 'jake' def __init__(self):
_project_ = 'leetcode' self.periods = ["Year", "Month", "Day", "Hour", "Minute", "Second"]
self.nb_children = {"Year": 13, "Month": 32, "Day": 24, "Hour": 60, "Minute": 60,
# https://leetcode.com/problems/design-log-storage-system/ "Second": 0}
# You are given several logs that each log contains a unique id and timestamp. Timestamp self.root = LogNode(18)
is a string that has the
# following format: Year:Month:Day:Hour:Minute:Second, for example, 2017:01:01:23:59:59. def put(self, id, timestamp):
# All domains are zero-padded decimal numbers. timelist = timestamp.split(":")
# Design a log storage system to implement the following functions: timelist[0] = int(timelist[0]) - 2000
# void Put(int id, string timestamp): Given a log's unique id and timestamp, store the node = self.root
log in your storage system.
# int[] Retrieve(String start, String end, String granularity): Return the id of logs for t, period in zip(timelist, self.periods):
whose timestamps are within the if not node.children[int(t)]:
# range from start to end. Start and end all have the same format as timestamp. node.children[int(t)] = LogNode(self.nb_children[period])

node = node.children[int(t)] # new function onto stack and update time. Else if finish then update exclusive time of
node.ids.add(id) finished
# function (extra +1 because start is at perriod start and end is at end) and update
def retrieve(self, s, e, gra): time.
s_list, e_list = s.split(":"), e.split(":") # Time - O(n)
s_list[0], e_list[0] = int(s_list[0]) - 2000, int(e_list[0]) - 2000 # Space - O(n)
s_node, e_node = self.root, self.root
class Solution(object):
later, earlier = set(), set() def exclusiveTime(self, n, logs):
for i in range(len(s_list)): # find all ids later or eqaul to start """
:type n: int
s_val = int(s_list[i]) # get time period value :type logs: List[str]
s_child = s_node.children[s_val] # could be None :rtype: List[int]
for node in s_node.children[s_val + 1:]: # all later nodes """
if not node: stack = []
continue exclusive = [0 for _ in range(n)]
later |= node.ids start = None
if not s_child:
break for log in logs:
if gra == self.periods[i]: # add terminal node ids fn, state, time = log.split(":")
later |= s_child.ids fn, time = int(fn), int(time)
break
if state == "start":
s_node = s_child if stack:
exclusive[stack[-1]] += time - start
for i in range(len(e_list)): # find all ids earlier or eqaul to end stack.append(fn)
start = time
e_val = int(e_list[i])
e_child = e_node.children[e_val] # could be None else:
for node in e_node.children[:e_val]: exclusive[stack.pop()] += time - start + 1
if not node: start = time + 1
continue
earlier |= node.ids return exclusive
if not e_child:
break
if gra == self.periods[i]:
earlier |= e_child.ids
break # python_1_to_1000/637_Average_of_Levels_in_Binary_Tree.py

e_node = e_child _author_ = 'jake'


_project_ = 'leetcode'
return list(earlier & later) # set intersection
# 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.

# python_1_to_1000/636_Exclusive_Time_of_Functions.py - m # Breadth first search. Maintain a queue of nodes in the current level.
# Time - O(n)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/exclusive-time-of-functions/ def averageOfLevels(self, root):
# Given the running logs of n functions that are executed in a nonpreemptive single """
threaded CPU, find the exclusive :type root: TreeNode
# time of these functions. :rtype: List[float]
# Each function has a unique id, start from 0 to n-1. A function may be called """
recursively or by another function. nodes = [root]
# A log is a string has this format : function_id:start_or_end:timestamp. For example, result = []
"0:start:0" means function 0
# starts from the very beginning of time 0. "0:end:0" means function 0 ends to the very while True:
end of time 0.
# Exclusive time of a function is defined as the time spent within this function, the row_sum, row_count = 0, 0 # no need to use a list to store the values
time spent by calling other new_nodes = []
# functions should not be considered as this function's exclusive time. You should return
the exclusive time of each for node in nodes:
# function sorted by their function id. if not node: # ignore None
continue
# When a function starts, if there is a current function already running then update its row_sum += node.val
exclusive time. Push row_count += 1
new_nodes.append(node.left) # add children to next queue
new_nodes.append(node.right) memo[needs_tuple] = min_cost
return min_cost
if row_count == 0:
break
result.append(row_sum / float(row_count)) memo = {}
nodes = new_nodes # check next row even if all nodes are None return helper()

return result
# python_1_to_1000/639_Decode_Ways_II.py - h

# python_1_to_1000/638_Shopping_Offers.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/decode-ways-ii/
# A message containing letters from A-Z is being encoded to numbers using the following
# https://leetcode.com/problems/shopping-offers/ mapping way:
# In LeetCode Store, there are some kinds of items to sell. Each item has a price. # 'A' -> 1
# However, there are some special offers, and a special offer consists of one or more # 'B' -> 2
different kinds of items with # ...
# a sale price. # 'Z' -> 26
# You are given the each item's price, a set of special offers, and the number we need to # Beyond that, now the encoded string can also contain the character '*', which can be
buy for each item. treated as one of the
# The job is to output the lowest price you have to pay for exactly certain items as # numbers from 1 to 9.
given, where you could make # Given the encoded message containing digits and the character '*', return the total
# optimal use of the special offers. number of ways to decode it.
# Each special offer is represented in the form of an array, the last number represents # Also, since the answer may be very large, you should return the output mod 10**9 + 7.
the price you need to pay
# for this special offer, other numbers represents how many specific items you could get # Dynamic programming. Iterate over s. New ways to encode = choices for c * existing ways
if you buy this offer. + choices for c and prev_char
# You could use any of special offers as many times as you want. # * prev_ways. Note that * cannot encode 0.
# Time - O(n)
# Given a list of needs, find the cost of buying all items without special offers. Then # Space - O(1)
for each special offer, if it
# does not involve more than needed of each item, use that offer and recurse. class Solution(object):
# Space - O(n**m) where n is nb items and m is max nb of each item (nb tuples in memo) def numDecodings(self, s):
# Time - O(kn * n**m) where k is nb specials. For each tuple, iterate over each item of """
each special. :type s: str
:rtype: int
class Solution(object): """
def shoppingOffers(self, price, special, needs): ways = 0
""" if s[0] == "*":
:type price: List[int] ways = 9
:type special: List[List[int]] elif s[0] != "0":
:type needs: List[int] ways = 1
:rtype: int prev_char = s[0]
""" prev_ways = 1
def helper():
for c in s[1:]:
needs_tuple = tuple(needs)
if needs_tuple in memo: new = 0
return memo[needs_tuple] # multiply ways by choices for c
if c == "*":
min_cost = 0 new = 9 * ways
for cost, need in zip(price, needs): elif c != "0":
min_cost += need * cost new = ways
if min_cost == 0: # base case
return 0 # multiply prev_ways by choices for c and prev_char
if prev_char == "*":
for offer in special: if c == "*": # 11 to 19 and 21 to 26
for i, need in enumerate(needs): new += prev_ways * 15
if offer[i] > need: elif "0" <= c <= "6": # prev_char is 1 or 2
break # cannot use this offer new += prev_ways * 2
else: elif "7" <= c <= "9": # prev_char is 1
for i, need in enumerate(needs): new += prev_ways
needs[i] -= offer[i]
min_cost = min(min_cost, offer[-1] + helper()) elif prev_char == "1":
for i, need in enumerate(needs): if c == "*":
needs[i] += offer[i] new += prev_ways * 9

else: val += num * neg


new += prev_ways
if i < len(equation) and equation[i] == "=":
elif prev_char == "2": base *= -1
if c == "*": i += 1
new += prev_ways * 6
elif c <= "6": if x == 0 and val == 0:
new += prev_ways return "Infinite solutions"
if x == 0:
new %= 10 ** 9 + 7 return "No solution"
return "x=" + str(-val // x)
prev_ways, ways = ways, new
prev_char = c
# python_1_to_1000/641_Design_Circular_Deque.py - m
return ways
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/640_Solve_the_Equation.py - m
# https://leetcode.com/problems/design-circular-deque/
_author_ = 'jake' # Design your implementation of the circular double-ended queue (deque).
_project_ = 'leetcode' # Your implementation should support following operations:
# MyCircularDeque(k): Constructor, set the size of the deque to be k.
# https://leetcode.com/problems/solve-the-equation/ # insertFront(): Adds an item at the front of Deque. Return true if the operation is
# Solve a given equation and return the value of x in the form of string "x=#value". successful.
# The equation contains only '+', '-' operation, the variable x and its coefficient. # insertLast(): Adds an item at the rear of Deque. Return true if the operation is
# If there is no solution for the equation, return "No solution". successful.
# If there are infinite solutions for the equation, return "Infinite solutions". # deleteFront(): Deletes an item from the front of Deque. Return true if the operation is
# If there is exactly one solution for the equation, we ensure that the value of x is an successful.
integer. # deleteLast(): Deletes an item from the rear of Deque. Return true if the operation is
successful.
# On each iteration of while loop, 1) identify any sign, 2) parse num or set to 1 if # getFront(): Gets the front item from the Deque. If the deque is empty, return -1.
None, 3) add to total of x or val. # getRear(): Gets the last item from Deque. If the deque is empty, return -1.
# When equals sign is found, reverse base to subtract counts on RHS of equals from LHS. # isEmpty(): Checks whether Deque is empty or not.
# Time - O(n) # isFull(): Checks whether Deque is full or not.
# Space - O(1)
# Use a python list as a circular array. Adding an extra space allows distinction between
class Solution(object): sull and empty queues.
def solveEquation(self, equation): # Deleted elements are not removed, pointers are just moved.
""" # Time - O(n)
:type equation: str # Space - O(1)
:rtype: str
""" class MyCircularDeque(object):
x, val = 0, 0 # count of x and sum of integers
base = 1 # set to -1 after seeing "=" def __init__(self, k):
"""
i = 0 Initialize your data structure here. Set the size of the deque to be k.
while i < len(equation): :type k: int
"""
neg = base self.k = k + 1
if equation[i] == "+": self.q = [None] * self.k
i += 1 self.head = self.tail = 0
if equation[i] == "-":
neg = -base def insertFront(self, value):
i += 1 """
Adds an item at the front of Deque. Return true if the operation is successful.
num = None :type value: int
while i < len(equation) and "0" <= equation[i] <= "9": :rtype: bool
if num is None: """
num = 0 if self.isFull():
num = num * 10 + int(equation[i]) return False
i += 1 self.head = (self.head + 1) % self.k
self.q[self.head] = value
if num is None: return True
num = 1
def insertLast(self, value):
if i < len(equation) and equation[i] == "x": """
x += num * neg Adds an item at the rear of Deque. Return true if the operation is successful.
i += 1 :type value: int
else: :rtype: bool
""" least one word and end with
if self.isFull(): # a special character '#'). For each character they type except '#', you need to return
return False the top 3 historical hot
self.q[self.tail] = value # sentences that have prefix the same as the part of sentence already typed. Here are the
self.tail = (self.tail - 1) % self.k specific rules:
return True # The hot degree for a sentence is defined as the number of times a user typed the
exactly same sentence before.
def deleteFront(self): # The returned top 3 hot sentences should be sorted by hot degree (The first is the
""" hottest one). If several
Deletes an item from the front of Deque. Return true if the operation is # sentences have the same degree of hot, you need to use ASCII-code order (smaller one
successful. appears first).
:rtype: bool # If less than 3 hot sentences exist, then just return as many as you can.
""" # When the input is a special character, it means the sentence ends, and in this case,
if self.isEmpty(): you need to return
return False # an empty list.
self.head = (self.head - 1) % self.k # Your job is to implement the following functions:
return True # The constructor function:
# AutocompleteSystem(String[] sentences, int[] times): This is the constructor. The
def deleteLast(self): input is historical data.
""" # Sentences is a string array consists of previously typed sentences. Times is the
Deletes an item from the rear of Deque. Return true if the operation is corresponding times a sentence
successful. # 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:
if self.isEmpty(): # List<String> input(char c): The input c is the next character typed by the user. The
return False character will only be
self.tail = (self.tail + 1) % self.k # lower-case letters ('a' to 'z'), blank space (' ') or a special character ('#').
return True Also, the previously typed
# sentence should be recorded in your system. The output will be the top 3 historical
def getFront(self): hot sentences that have prefix
""" # the same as the part of sentence already typed.
Get the front item from the deque.
:rtype: int # 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
if self.isEmpty(): sentences that match the first
return -1 # char, sorted by decreasing count. Then for each subsequent char, all we need to do is
return self.q[self.head] filter the existing list,
# keeping only sentences that match the char in its correct position.
def getRear(self): # At the end of the input, simply increment the count.
""" # Time - O(n) for constructor when n is number of sentences. O(n log n) to input first
Get the last item from the deque. char then O(n).
:rtype: int # Space - O(n)
"""
if self.isEmpty(): from collections import defaultdict
return -1
return self.q[(self.tail + 1) % self.k] class AutocompleteSystem(object):
def __init__(self, sentences, times):
def isEmpty(self): """
""" :type sentences: List[str]
Checks whether the circular deque is empty or not. :type times: List[int]
:rtype: bool """
""" self.partial = [] # previously seen chars of current sentence
return self.head == self.tail self.matches = [] # matching sentences in decreasing frequency order

def isFull(self): self.counts = defaultdict(int) # map from sentence to its frequency


""" for sentence, count in zip(sentences, times):
Checks whether the circular deque is full or not. self.counts[sentence] = count
:rtype: bool
""" def input(self, c):
return (self.head + 1) % self.k == self.tail """
:type c: str
:rtype: List[str]
# python_1_to_1000/642_Design_Search_Autocomplete_System.py - h """
if c == "#":
_author_ = 'jake' sentence = "".join(self.partial)
_project_ = 'leetcode' self.counts[sentence] += 1
self.partial = [] # reset partial and matches
# https://leetcode.com/problems/design-search-autocomplete-system/ self.matches = []
# Design a search autocomplete system for a search engine. Users may input a sentence (at return []

k.
if not self.partial: # first char of sentence # Time - O(n log r) where r is range between max an min values of array. O(nk) for small
self.matches = [(-count, sentence) for sentence, count in self.counts.items() k.
if sentence[0] == c] # Space - O(n) fro small k, O(1) for binary search.
self.matches.sort()
self.matches = [sentence for _, sentence in self.matches] # drop the counts class Solution(object):
else: def findMaxAverage(self, nums, k):
i = len(self.partial) # filter matches for c """
self.matches = [sentence for sentence in self.matches if len(sentence) > i :type nums: List[int]
and sentence[i] == c] :type k: int
:rtype: float
self.partial.append(c) """
return self.matches[:3] n = len(nums)

if k < 80:
cumulative = [0]
# python_1_to_1000/643_Maximum_Average_Subarray_I.py for num in nums:
cumulative.append(cumulative[-1] + num)
_author_ = 'jake' result = float('-inf')
_project_ = 'leetcode' for length in range(k, min(n + 1, 2 * k)):
max_sum = max([cumulative[length + i] - cumulative[i] for i in range(n -
# https://leetcode.com/problems/maximum-average-subarray-i/ length + 1)])
# Given an array consisting of n integers, find the contiguous subarray of given length k result = max(result, max_sum / float(length))
that has the maximum return result
# average value. And you need to output the maximum average value.
def has_average(x):
# Maintain a window with the sum of k elements. Slide the sindow along nums, updating the
sum and max_average. subarray_sum = 0
# Time - O(n) for i in range(k):
# Space - O(1) subarray_sum += nums[i] - x
if subarray_sum >= 0:
class Solution(object): return True
def findMaxAverage(self, nums, k):
""" prefix_sum, min_prefix = 0, 0
:type nums: List[int] for i in range(k, n):
:type k: int subarray_sum += nums[i] - x
:rtype: float prefix_sum += nums[i - k] - x
""" min_prefix = min(min_prefix, prefix_sum)
window_sum = sum(nums[:k]) # assumes len(nums) >= k if subarray_sum - min_prefix >= 0:
max_average = window_sum / float(k) return True

for i in range(len(nums) - k): return False


window_sum += nums[i + k] - nums[i]
max_average = max(max_average, window_sum / float(k)) left, right = min(nums), max(nums)
while right - left > 1e-5:
return max_average mid = (left + right) / 2.0
if has_average(mid):
left = mid
# python_1_to_1000/644_Maximum_Average_Subarray_II.py - h else:
right = mid
_author_ = 'jake'
_project_ = 'leetcode' return left

# https://leetcode.com/problems/maximum-average-subarray-ii/
# Given an array consisting of n integers, find the contiguous subarray whose length is # python_1_to_1000/645_Set_Mismatch.py
greater than or equal to k that
# has the maximum average value. And you need to output the maximum average value. _author_ = 'jake'
_project_ = 'leetcode'
# If k is low (< 80) then calculate the cumulative sum array of nums and for each length
find the average of all # https://leetcode.com/problems/set-mismatch/
# subarrays. Any subarray longer than 2k can be divided into 2 subarrays of length at # The set S originally contains numbers from 1 to n. But unfortunately, one of the
least k, at one of which has an numbers in the set got duplicated
# average at least as good as the whole subarray. Hence restrict to max length less than # to another number in the set, which results in repetition of one number and loss of
2k. another number.
# For larger k, binary search the space of averages. has_average(x) determines whether # Given an array nums representing the data status of this set after the error. Your task
there is some subarray of is to firstly find the
# length at least k with an average of at least x. Subtract x from all elements of nums, # number occurs twice and then find the number that is missing. Return them in the form
then for all prefixes of of an array.
# length at least k, find the minimum sum prefix that still allows subarray to be length
# Iterate over nums. When num is seen, set the num at index of abs(num) - 1 to negative. # python_1_to_1000/647_Palindromic_Substrings.py - m
If the num at that index is
# already negative, it is the duplicate. Then find the index i that is not negative, _author_ = 'jake'
which means i + 1 is missing. _project_ = 'leetcode'
# Time - O(n)
# Space - O(1) # https://leetcode.com/problems/palindromic-substrings/
# Given a string, your task is to count how many palindromic substrings in this string.
class Solution(object): The substrings with different
def findErrorNums(self, nums): # start indexes or end indexes are counted as different substrings even they consist of
""" same characters.
:type nums: List[int]
:rtype: List[int] # For each char or neighbouring pair of chars, extend outwards as long as left and right
""" match.
for num in nums: # Time - O(n**2)
if nums[abs(num) - 1] < 0: # Space - O(1)
duplicate = abs(num)
else: class Solution(object):
nums[abs(num) - 1] *= -1 def countSubstrings(self, s):
"""
for i, num in enumerate(nums): :type s: str
if num > 0: :rtype: int
missing = i + 1 """
break count = 0

return [duplicate, missing] for i in range(2 * len(s) + 1):

left = right = i // 2
# python_1_to_1000/646_Maximum_Length_of_Pair_Chain.py - m if i % 2 == 1:
right += 1
_author_ = 'jake'
_project_ = 'leetcode' while left >= 0 and right < len(s) and s[left] == s[right]:
count += 1
# https://leetcode.com/problems/maximum-length-of-pair-chain/ left -= 1
# You are given n pairs of numbers. In every pair, the first number is always smaller right += 1
than the second number.
# Define a pair (c, d) can follow another pair (a, b) if and only if b < c. return count
# Chain of pairs can be formed in this fashion.
# Given a set of pairs, find the length longest chain which can be formed. You needn't
use up all the given pairs. # python_1_to_1000/648_Replace_Words.py - m
# You can select pairs in any order.
_author_ = 'jake'
# Sort by first number of the pair. For each pair, if first number is after previous _project_ = 'leetcode'
chain end then this pair can be
# used to extend chain to new pair end. Else last member of chain can be replace with new # https://leetcode.com/problems/replace-words/
pair if it reduces chain end. # In English, we have a concept called root, which can be followed by some other words to
# Replacement is always possible because new pair must have same or larger first member. form another longer word -
# Time - O(n log n) # let's call this word successor. For example, the root an, followed by other, which can
# Space - O(1) form another word another.
# Now, given a dictionary consisting of many roots and a sentence. You need to replace
class Solution(object): all the successor in the
def findLongestChain(self, pairs): # sentence with the root forming it. If a successor has many roots can form it, replace
""" it with the root with the
:type pairs: List[List[int]] # shortest length.. You need to output the sentence after the replacement.
:rtype: int
""" # Create a trie where each letter of a word maps to the next letter, terminating in the
pairs.sort(key=lambda x: x[0]) word. Insert all words of
chain = 0 # dictionary into trie. Terminate without inserting if perfix of a word is longer than a
end = pairs[0][0] - 1 word already in trie.
# for each word in sentence, traverse through trie until no more nodes or word is found.
for pair in pairs: # Time - O(m + n) total number of chars in dictionary and sentence.
if end < pair[0]: # Space - O(m) number of chars in dictionary
chain += 1
end = pair[1] class Solution(object):
else: def replaceWords(self, dict, sentence):
end = min(end, pair[1]) """
:type dict: List[str]
return chain :type sentence: str
:rtype: str
"""

result = [] class Solution(object):


root = {} def predictPartyVictory(self, senate):
"""
for word in dict: :type senate: str
node = root :rtype: str
for c in word[:-1]: """
if c not in node: # create a new mapping n = len(senate)
node[c] = {} d, r = deque(), deque() # indices of remaining senators for each party
elif isinstance(node[c], str): # longer than an existing word for i, c in enumerate(senate):
break if c == "D":
node = node[c] d.append(i)
else: else:
node[word[-1]] = word # terminate with word r.append(i)

sentence = sentence.split(" ") while d and r:


for word in sentence: d_senator = d.popleft()
node = root r_senator = r.popleft()
for c in word: if d_senator < r_senator:
if c not in node: d.append(d_senator + n)
result.append(word) # no replacements else:
break r.append(r_senator + n)
if isinstance(node[c], str): # replacement found
result.append(node[c]) return "Radiant" if r else "Dire"
break
node = node[c]
else: # python_1_to_1000/650_2_Keys_Keyboard.py - m
result.append(word)
_author_ = 'jake'
return " ".join(result) _project_ = 'leetcode'

# https://leetcode.com/problems/2-keys-keyboard/
# python_1_to_1000/649_Dota2_Senate.py - m # Initially on a notepad only one character 'A' is present. You can perform two
operations on this notepad for each step:
_author_ = 'jake' # Copy All: You can copy all the characters present on the notepad (partial copy is not
_project_ = 'leetcode' allowed).
# Paste: You can paste the characters which are copied last time.
# https://leetcode.com/problems/dota2-senate/ # Given a number n. You have to get exactly n 'A' on the notepad by performing the
# In the world of Dota2, there are two parties: the Radiant and the Dire. minimum number of steps permitted.
# The Dota2 senate consists of senators coming from two parties. Now the senate wants to # Output the minimum number of steps to get n 'A'.
make a decision about a
# change in the Dota2 game. The voting for this change is a round-based procedure. # If n is prime, we can only make it by copying 'A' and pasting it n - 1 times.
# In each round, each senator can exercise one of the two rights: # Consider breaking n down to make a single 'A'. If we find a divisor d of n, then from n
# Ban one senator's right: A senator can make another senator lose all his rights in // d we can take d steps to
this and all the following rounds. # make n 'A's. Repeat this process as many times as possible with each divisor starting
# Announce the victory: If this senator found the senators who still have rights to vote from 2, until only 1 'A' left.
are all from the same party, # Solution is the sum of the factors (apart from 1).
# he can announce the victory and make the decision about the change in the game. # Time - O(n)
# Given a string representing each senator's party belonging. The character 'R' and 'D' # Space - O(1)
represent the Radiant party
# and the Dire party respectively. Then if there are n senators, the size of the given class Solution(object):
string will be n. def minSteps(self, n):
# The round-based procedure starts from the first senator to the last senator in the """
given order. This procedure will :type n: int
# last until the end of voting. All the senators who have lost their rights will be :rtype: int
skipped during the procedure. """
# Suppose every senator is smart enough and will play the best strategy for his own steps = 0
party, you need to predict which divisor = 2
# party will finally announce the victory and make the change in the Dota2 game. The
output should be Radiant or Dire. while n > 1:
while n % divisor == 0:
# Create a queue of senator for each part by index. Compare the indices of the first steps += divisor
senator from each party. The first n //= divisor
# will ban the rights of the second, so first is added to the back of the queue for this divisor += 1
part and second is rejected.
# Time - O(n), total number of senators since one senator is removed in each step. return steps
# Space - O(n)

from collections import deque


# python_1_to_1000/651_4_Keys_Keyboard.py - m
"""
_author_ = 'jake' def serialize(node):
_project_ = 'leetcode' if not node:
return "#"
# https://leetcode.com/problems/4-keys-keyboard/ serial = str(node.val) + "," + serialize(node.left) + "," +
# Imagine you have a special keyboard with the following keys: serialize(node.right)
# Key 1: (A): Print one 'A' on screen. subtrees[serial].append(node)
# Key 2: (Ctrl-A): Select the whole screen. return serial
# Key 3: (Ctrl-C): Copy selection to buffer.
# Key 4: (Ctrl-V): Print buffer on screen appending it after what has already been subtrees = defaultdict(list) # key is serialised subtree, value is list of
printed. subtree nodes
# Now, you can only press the keyboard for N times (with the above four keys), find out serialize(root) # ignore return value
the maximum numbers of 'A' you return [nodes[0] for serial, nodes in subtrees.items() if len(nodes) > 1]
# can print on screen.

# The maximum for a given N is either just by printing 'A' N times, or producing the # python_1_to_1000/653_Two_Sum_IV_-_Input_is_a_BST.py
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 _author_ = 'jake'
create at least one copy. _project_ = 'leetcode'
# In fact the optimal occurs when N - i is 4 or 5.
# Time - O(n) # https://leetcode.com/problems/two-sum-iv-input-is-a-bst/
# Space - O(n) # Given a Binary Search Tree and a target number, return true if there exist two elements
in the BST such that their
class Solution(object): # sum is equal to the given target.
def maxA(self, N):
""" # Traverse the BST. Preorder is used but could be postorder or inorder. For each node,
:type N: int check if k - node.val has
:rtype: int # already been visited. If node, add noe.val to the visited set. Would work equally well
""" for a binary tree that is not
def helper(n): # a BST.
if n in memo: # Time - O(n)
return memo[n] # Space - O(n)

max_A = n # press 'A' n times class Solution(object):


for i in range(max(n - 5, 0), n - 3): # i + 1 print 'A' to make def findTarget(self, root, k):
a base list """
max_A = max(max_A, helper(i) * (n - i - 1)) # then n - (i + 1) copies :type root: TreeNode
of the base list :type k: int
:rtype: bool
memo[n] = max_A """
return max_A visited = set()

memo = {} def traverse(node):


return helper(N)
if not node:
return False
# python_1_to_1000/652_Find_Duplicate_Subtrees.py - m
if k - node.val in visited:
_author_ = 'jake' return True
_project_ = 'leetcode' visited.add(node.val)

# https://leetcode.com/problems/find-duplicate-subtrees/ return traverse(node.left) or traverse(node.right)


# Given a binary tree, return all duplicate subtrees. For each kind of duplicate
subtrees, you only need to return return traverse(root)
# the root node of any one of them.
# Two trees are duplicate if they have the same structure with same node values.
# python_1_to_1000/654_Maximim_Binary_Tree.py - m
# Preorder traversal. Create a string representation of each subtree and map that string
to a list of root nodes. _author_ = 'jake'
# Time - O(n**2) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/maximum-binary-tree/
from collections import defaultdict # Given an integer array with no duplicates. A maximum tree building on this array is
defined as follow:
class Solution(object): # The root is the maximum number in the array.
def findDuplicateSubtrees(self, root): # The left subtree is the maximum tree constructed from left part subarray divided by the
""" maximum number.
:type root: TreeNode # The right subtree is the maximum tree constructed from right part subarray divided by
:rtype: List[TreeNode] the maximum number.

# Construct the maximum tree by the given array and output the root node of this tree. :rtype: List[List[str]]
"""
# For each array, find the maximum and set to root, then recurse for left and right
subtrees. def height(node):
# Time - O(n**2) if not node:
# Space - O(n) return 0
return 1 + max(height(node.left), height(node.right))
class Solution(object):
def constructMaximumBinaryTree(self, nums): rows = height(root)
""" cols = 2 ** rows - 1
:type nums: List[int]
:rtype: TreeNode result = [["" for _ in range(cols)] for _ in range(rows)]
"""
def place(node, r, c):
def helper(i, j): # construct subtree from nums[i:j + 1] if not node:
if i > j: return
return None result[r][c] = str(node.val)
shift = 2 ** (rows - r - 2) # next column shift as a function of r
max_num = float("-inf") place(node.left, r + 1, c - shift)
for k in range(i, j + 1): place(node.right, r + 1, c + shift)
if nums[k] > max_num:
max_num = nums[k] place(root, 0, cols // 2)
max_index = k return result

root = TreeNode(max_num)
root.left = helper(i, max_index - 1) # python_1_to_1000/656_Coin_Path.py - h
root.right = helper(max_index + 1, j)
_author_ = 'jake'
return root _project_ = 'leetcode'

return helper(0, len(nums) - 1) # https://leetcode.com/problems/coin-path/


# Given an array A (index starts at 1) consisting of N integers: A1, A2, ..., AN and an
integer B. The integer B
# python_1_to_1000/655_Print_Binary_Tree.py - m # 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
_author_ = 'jake' # array A indexed i+1, i+2, …, i+B if this place can be jumped to. Also, if you step on
_project_ = 'leetcode' the index i, you have to
# pay Ai coins. If Ai is -1, it means you can’t jump to the place indexed i in the array.
# https://leetcode.com/problems/print-binary-tree/ # Now, you start from the place indexed 1 in the array A, and your aim is to reach the
# Print a binary tree in an m*n 2D string array following these rules: place indexed N using the
# The row number m should be equal to the height of the given binary tree. # minimum coins. You need to return the path of indexes (starting from 1 to N) in the
# The column number n should always be an odd number. array you should take to get
# The root node's value (in string format) should be put in the exactly middle of the # to the place indexed N using minimum coins.
first row it can be put. # If there are multiple paths with the same cost, return the lexicographically smallest
# The column and the row where the root node belongs will separate the rest space into such path.
two parts (left-bottom part # If it's not possible to reach the place indexed N then you need to return an empty
# and right-bottom part). You should print the left subtree in the left-bottom part and array.
print the right subtree in
# the right-bottom part. The left-bottom part and the right-bottom part should have the # Dynamic programming. List contains the least coins to reach every index and it's path.
same size. Even if one Intialize the cost as
# subtree is none while the other is not, you don't need to print anything for the none # infinity and empty path apart from the first index. For all reachable indices of A,
subtree but still need to update their cost with the
# leave the space as large as that for the other subtree. However, if two subtrees are # the cost from i if better.
none, then you don't need # Time - O(nB)
# to leave space for both of them. # Space - O(n)
# Each unused space should contain an empty string "".
# Print the subtrees following the same rules. class Solution(object):
def cheapestJump(self, A, B):
# Find the height and calculate the width as 2**height - 1. Create an empty list of lists """
to hold result. The preorder :type A: List[int]
# traverse the tree, placing each value in the result and recursing to subtrees. :type B: int
# Time - O(2 ** (n + 1)), every node visited once but worst case time is to create result :rtype: List[int]
when height = n """
# Space - O(2 ** (n + 1)) cheapest = [[float("inf"), []] for _ in range(len(A))] # [cost, path] to reach
each index of A
class Solution(object): cheapest[0] = [A[0], [1]]
def printTree(self, root):
""" for i, cost in enumerate(A[:-1]): # do not jump from last
:type root: TreeNode index
if cost == -1: # cannot jump from i while left <= right:
continue mid = (left + right) // 2
if x == arr[mid]:
for j in range(i + 1, min(i + B + 1, len(A))): left, right = mid, mid
break
if A[j] == -1: # cannot jump to j elif x > arr[mid]:
continue left = mid + 1
new_cost = cheapest[i][0] + A[j] else:
new_path = cheapest[i][1] + [j + 1] # extend path right = mid - 1
cheapest[j] = min(cheapest[j], [new_cost, new_path]) # lowest cost
then lowest lexicographic path else: # find which of left and right is closer to x
if right == len(arr) or abs(arr[left] - x) <= abs(arr[right] - x):
return cheapest[-1][1] right = left
else:
left = right
# python_1_to_1000/657_Judge_Route_Circle.py
while right - left + 1 < k: # while result length less than k
_author_ = 'jake' if right + 1 == len(arr) or abs(arr[left - 1] - x) <= abs(arr[right + 1] -
_project_ = 'leetcode' x): # add arr[left]
left -= 1
# https://leetcode.com/problems/judge-route-circle/ else: # add arr[right]
# Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if right += 1
this robot makes a circle,
# which means it moves back to the original place. return arr[left:right + 1]
# The move sequence is represented by a string. And each move is represent by a
character. The valid robot moves are:
# R (Right), L (Left), U (Up) and D (down). The output should be true or false. # python_1_to_1000/659_Split_Array_into_Consecutive_Subsequences.py - m

# Ensure that vertical and horizontal moves balance i.e. number of up and down moves are _author_ = 'jake'
equal and number of left and _project_ = 'leetcode'
# right moves are equal.
# Time - O(n) # https://leetcode.com/problems/split-array-into-consecutive-subsequences/
# Space - O(1) # You are given an integer array sorted in ascending order (may contain duplicates), you
need to split them into
class Solution(object): # several subsequences, where each subsequences consist of at least 3 consecutive
def judgeCircle(self, moves): integers. Return whether you can
""" # make such a split.
:type moves: str
:rtype: bool # Count each num. For each num, reduce count and extend a sequence ending with num - 1 if
""" possible. Otherwise use num
return moves.count("U") == moves.count("D") and moves.count("L") == # and num + 1 and num + 2 to create a new sequence. Otherwise num cannot be used.
moves.count("R") # Time - O(n)
# Space - O(n)

# python_1_to_1000/658_Find_K_Closest_Elements.py - m from collections import Counter, defaultdict

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def isPossible(self, nums):
"""
# https://leetcode.com/problems/find-k-closest-elements/ :type nums: List[int]
# Given a sorted array, two integers k and x, find the k closest elements to x in the :rtype: bool
array. The result should also be """
# sorted in ascending order. If there is a tie, the smaller elements are always freq = Counter(nums)
preferred. sequences = defaultdict(int) # map from num to number of sequences ending with
num
# Binary search for value closest to x, then expand outwards.
# Time - O(log n + k) for num in nums:
# Space - O(1)
if freq[num] == 0: # num already used to extend other sequences
class Solution(object): continue
def findClosestElements(self, arr, k, x): freq[num] -= 1
"""
:type arr: List[int] if sequences[num - 1] != 0: # extend an existing sequence
:type k: int sequences[num - 1] -= 1
:type x: int sequences[num] += 1
:rtype: List[int]
""" elif freq[num + 1] > 0 and freq[num + 2] > 0: # create a new sequence
left, right = 0, len(arr) - 1 # region of search for x (inclusive) freq[num + 1] -= 1

freq[num + 2] -= 1 nbors, total = 0, 0


sequences[num + 2] += 1 for dr in (-1, 0, 1):
for dc in (-1, 0, 1):
else: # cannot use num
return False if r + dr < 0 or r + dr >= rows or c + dc < 0 or c + dc >= cols:
continue
return True total += M[r + dr][c + dc]
nbors += 1

smoothed[r][c] = total // nbors # round down


# python_1_to_1000/660_Remove_9.py - h
return smoothed
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/662_Maximum_Width_of_Binary_Tree.py - m
# https://leetcode.com/problems/remove-9/
# Start from integer 1, remove any integer that contains 9 such as 9, 19, 29... _author_ = 'jake'
# So now, you will have a new integer sequence: 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, ... _project_ = 'leetcode'
# Given a positive integer n, you need to return the n-th integer after removing. Note
that 1 will be the first integer. # https://leetcode.com/problems/maximum-width-of-binary-tree/
# Given a binary tree, write a function to get the maximum width of the given tree. The
# All remaining numbers without 9 are the base 9 numbers. Convert to base 9 by repeatedly width of a tree is the maximum
dividing by 9, reverse result. # width among all levels. The binary tree has the same structure as a full binary tree,
# Time - O(log n) but some nodes are null.
# Space - O(1) # The width of one level is defined as the length between the end-nodes (the leftmost and
right most non-null nodes in
class Solution(object): # the level, where the null nodes between the end-nodes are also counted into the length
def newInteger(self, n): calculation.
"""
:type n: int # For each level, create a list of all non-null nodes at the next level along with their
:rtype: int indices. Indices are relative
""" # to a complete binary tree i.e. left most node has index 0 and right most 2**depth - 1.
result = [] Width is separation between
# first and last nodes at each level.
while n: # Time - O(n)
result.append(str(n % 9)) # Space - O(n)
n //= 9
class Solution(object):
return int("".join(result[::-1])) def widthOfBinaryTree(self, root):
"""
:type root: TreeNode
# python_1_to_1000/661_Image_Smoother.py :rtype: int
"""
_author_ = 'jake' if not root:
_project_ = 'leetcode' return 0

# https://leetcode.com/problems/image-smoother/ max_width = 1
# Given a 2D integer matrix M representing the gray scale of an image, you need to design nodes = [(root, 0)] # list of nodes per level and their indices
a smoother to make the gray
# scale of each cell becomes the average gray scale (rounding down) of all the 8 while True:
surrounding cells and itself. new_nodes = []
# If a cell has less than 8 surrounding cells, then use as many as you can.
for node, i in nodes:
# Iterate over M. For each cell, count and sum the neighbours (including self). if node.left:
# Time - O(mn) new_nodes.append((node.left, i * 2))
# Space - O(mn) if node.right:
new_nodes.append((node.right, i * 2 + 1))
class Solution(object):
def imageSmoother(self, M): if not new_nodes:
""" break
:type M: List[List[int]] nodes = new_nodes
:rtype: List[List[int]] max_width = max(max_width, 1 + nodes[-1][1] - nodes[0][1])
"""
rows, cols = len(M), len(M[0]) return max_width
smoothed = [[0 for _ in range(cols)] for _ in range(rows)]

for r in range(rows): # python_1_to_1000/663_Equal_Tree_Partition.py - m


for c in range(cols):
_author_ = 'jake'
_project_ = 'leetcode' # same time in either case. So we can split the subproblems at every char that is the
same as the starting char and
# https://leetcode.com/problems/equal-tree-partition/ # take the minimum prints of all those split points.
# Given a binary tree with n nodes, your task is to check if it's possible to partition # Time - O(n**3), iterate over every of the n**2 substrings
the tree to two trees which # Space - O(n**2)
# have the equal sum of values after removing exactly one edge on the original tree.
class Solution(object):
# Modify the tree with bottom-up recursion so the value of each node is the sum of its def strangePrinter(self, s):
original subtree. Then find a """
# subtree with sum of half the total sum. :type s: str
# Time - O(n) :rtype: int
# Space - O(1) """
s = "".join([a for a, b in zip(s, "#" + s) if a != b]) # remove repeated chars
# Definition for a binary tree node. memo = {}
# class TreeNode(object):
# def __init__(self, x): def helper(i, j):
# self.val = x
# self.left = None if j - i + 1 <= 1: # length <= 1, return length
# self.right = None return j - i + 1

class Solution(object): if (i, j) in memo:


def checkEqualTree(self, root): return memo[(i, j)]
"""
:type root: TreeNode min_prints = 1 + helper(i + 1, j) # print first char, then print remiander
:rtype: bool
""" for k in range(i + 1, j + 1):
def make_sum(node): if s[k] == s[i]: # all chars that match first
if not node: min_prints = min(min_prints, helper(i, k - 1) + helper(k + 1, j))
return 0
node.val += make_sum(node.left) + make_sum(node.right) memo[(i, j)] = min_prints
return node.val return min_prints

tree_sum = make_sum(root) return helper(0, len(s) - 1)


if tree_sum % 2 == 1: # no partition possible
return False

def find_split(node):
if not node: # python_1_to_1000/665_Non-decreasing_Array.py - m
return False
_author_ = 'jake'
if node.left and node.left.val == tree_sum // 2: _project_ = 'leetcode'
return True
if node.right and node.right.val == tree_sum // 2: # https://leetcode.com/problems/non-decreasing-array/
return True # Given an array with n integers, check if it could become non-decreasing by modifying at
return find_split(node.left) or find_split(node.right) most 1 element.
# We define an array is non-decreasing if array[i] <= array[i + 1] holds for every i (1
return find_split(root) <= i < n).

# If an element is less than the previous element, if we have already modified the array
# python_1_to_1000/664_Strange_Printer.py - h then return False. Else we can
# either decrease the previous element or increase the current element. Decreasing the
_author_ = 'jake' previous is preferred
_project_ = 'leetcode' # because it does not have an affect on future elements but is only possible if there is
no element before previous
# https://leetcode.com/problems/strange-printer/ # or it is not more than the previous element. There is no need to actually modify the
# There is a strange printer with the following two special requirements: previous element since it is
# The printer can only print a sequence of the same character each time. # never used again.
# At each turn, the printer can print new characters starting from and ending at any # Time - O(n)
places, and will cover the # Space - O(1)
# original existing characters.
# Given a string consists of lower English letters only, your job is to count the minimum class Solution(object):
number of turns the printer def checkPossibility(self, nums):
# needed in order to print it. """
:type nums: List[int]
# First remove repeated characters since they will always be printed together. :rtype: bool
# 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 modified = False
# 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 for i, num in enumerate(nums[1:], 1):

return sum_paths((depth + 1, 2 * pos), new_partial) + sum_paths((depth + 1, 2


if num < nums[i - 1]: * pos + 1), new_partial)

if modified: return sum_paths((1, 0), 0)


return False

if i != 1 and nums[i - 2] > nums[i]: # must increase nums[i]


nums[i] = nums[i - 1] # python_1_to_1000/667_Beautiful_Arrangement_II.py - m

modified = True _author_ = 'jake'


_project_ = 'leetcode'
return True
# https://leetcode.com/problems/beautiful-arrangement-ii/
# 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:
# python_1_to_1000/666_Path_Sum_IV.py - m # Suppose this list is [a1, a2, a3, ... , an], then the list [|a1 - a2|, |a2 - a3|, |a3 -
a4|, ... , |an-1 - an|]
_author_ = 'jake' # has exactly k distinct integers.
_project_ = 'leetcode' # If there are multiple answers, print any of them.

# https://leetcode.com/problems/path-sum-iv/ # The criteria that there are k differences between consecutive numbers means those
# If the depth of a tree is smaller than 5, then this tree can be represented by a list differences are 1, 2, .. k.
of three-digits integers. # Use the first k + 1 nums to produce a list with all the required differences. Build the
# For each integer in this list: list with the largest
# The hundreds digit represents the depth D of this node, 1 <= D <= 4. # difference first, then taking numbers from each end in turn create all the other
# The tens digit represents the position P of this node in the level it belongs to, 1 <= differences.
P <= 8. The position is the # Then append all the remaining nums in order (since any differences will already have
# same as that in a full binary tree. been used).
# The units digit represents the value V of this node, 0 <= V <= 9. # Time - O(n)
# Given a list of ascending three-digits integers representing a binary with the depth # Space - O(n)
smaller than 5. You need to
# return the sum of all paths from the root towards the leaves. class Solution(object):
def constructArray(self, n, k):
# Create a mapping from each node's location to its value. Location is a tuple (depth, """
pos) where pos is indexed :type n: int
# from zero. Then recursively explore the tree from the root with depth-first search. If :type k: int
node has no children then :rtype: List[int]
# it is a leaf so return partial sum (including own value). Else return sums of paths via """
left and right subtrees. result = []
# Time - O(n) low, high = 1, k + 1
# Space - O(n) next_low = True

class Solution(object): while low <= high:


def pathSum(self, nums): if next_low:
""" result.append(low)
:type nums: List[int] low += 1
:rtype: int else:
""" result.append(high)
mapping = {} # key is (depth, pos) of node, value is val high -= 1
next_low = not next_low
for num in nums:
location, val = divmod(num, 10) return result + list(range(k + 2, n + 1))
depth, pos = divmod(location, 10)
mapping[(depth, pos - 1)] = val

def sum_paths(location, partial): # returns sum of all paths to leaves given


partial sum so far from root # python_1_to_1000/668_Kth_Smallest_Number_in_Multiplication_Table.py - h

if location not in mapping: _author_ = 'jake'


return 0 _project_ = 'leetcode'

depth, pos = location # https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/


new_partial = partial + mapping[location] # Nearly every one have used the Multiplication Table. But could you find out the k-th
left = (depth + 1, 2 * pos) smallest number quickly from
right = (depth + 1, 2 * pos + 1) # the multiplication table?
# Given the height m and the length n of a m * n Multiplication Table, and a positive
if left not in mapping and right not in mapping: # leaf node integer k, you need to return
return new_partial # the k-th smallest number in this table.
:rtype: TreeNode
# Binary search the range of possible answers, initially [1, m * n]. helper function """
determines whether there are at if not root:
# least k numbers in the multiplication table that are less than or equal to guess. return None
# Time - O(min(m, n) log(mn)
# Space - O(1) if root.val > R:
return self.trimBST(root.left, L, R)
class Solution(object): if root.val < L:
def findKthNumber(self, m, n, k): return self.trimBST(root.right, L, R)
"""
:type m: int root.left = self.trimBST(root.left, L, R)
:type n: int root.right = self.trimBST(root.right, L, R)
:type k: int return root
:rtype: int
"""
if m > n: # ensure m is smaller
m, n = n, m # python_1_to_1000/670_Maximum_Swap.py - m

def helper(guess): # return True if there are at least k numbers in _author_ = 'jake'
table <= guess _project_ = 'leetcode'
count = 0
for i in range(1, m + 1): # https://leetcode.com/problems/maximum-swap/
temp = guess // i # Given a non-negative integer, you could swap two digits at most once to get the maximum
if temp > n: # faster than count += min(n, guess // i) valued number.
count += n # Return the maximum valued number you could get.
else:
count += temp # Iterate backwards from the least to the most significant digit. When we have already
if count >= k: # stop iterating if count already too large seen a greater digit than the
return True # current digit they could be swapped and increase the value. Track the first occurrence
of greatest digit seen.
return False # If the current digit is lower, we have a new candidate for swapping. If it is higher,
we have a new max_seen.
left, right = 1, m * n # The last candidates found result in the greatest increase because they increase the
most significant digit possible.
while left < right: # Time - O(log n)
# Space - O(1)
mid = (left + right) // 2
if helper(mid): class Solution(object):
right = mid def maximumSwap(self, num):
else: """
left = mid + 1 :type num: int
:rtype: int
return left """
s = [int(c) for c in str(num)] # convert to list of digits

# python_1_to_1000/669_Trim_a_Binary_Search_Tree.py - m max_seen, max_seen_i = -1, -1 # max digit seen (from back) and its
index
_author_ = 'jake' demote, promote = -1, -1 # indices of best pair to swap
_project_ = 'leetcode'
for i in range(len(s) - 1, -1, -1): # iterate from least significant digit
# https://leetcode.com/problems/trim-a-binary-search-tree/ digit = s[i]
# Given a binary search tree and the lowest and highest boundaries as L and R, trim the if max_seen > digit: # greater digit later in num so swap will
tree so that all its elements increase value
# lies in [L, R] (R >= L). You might need to change the root of the tree, so the result demote, promote = i, max_seen_i
should return the new root of elif digit > max_seen: # update max_seen on first occurrence of
# the trimmed binary search tree. greater digit
max_seen, max_seen_i = digit, i
# If root val is in [L, R] then return root and trimmed left and right subtrees. If root
is ledd than left, root and if demote == -1: # nothing can be swapped
# all smaller values in left subtree should be trimmed, so return trimmed right subtree. return num
# Time - O(n)
# Space - O(1) s[demote], s[promote] = s[promote], s[demote]
result = 0
class Solution(object): for digit in s:
def trimBST(self, root, L, R): result = result * 10 + digit
""" return result
:type root: TreeNode
:type L: int
:type R: int # python_1_to_1000/671_Second_Minimum_Node_In_a_Binary_Tree.py

# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def flipLights(self, n, m):
# https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/ """
# Given a non-empty special binary tree consisting of nodes with the non-negative value, :type n: int
where each node in this tree :type m: int
# has exactly two or zero sub-node. :rtype: int
# If the node has two sub-nodes, then this node's value is the smaller value among its """
two sub-nodes. if n == 0:
# Given such a binary tree, output the second minimum value in the set made of all the return 0 # no lights
nodes' value in the whole tree. if m == 0:
# If no such second minimum value exists, output -1 instead. return 1 # no switches

# The root value is the minimum value, since all children are >= root value. Second if m == 1: # one switch
minimum must be a child of a node if n == 1:
# with the minimum (root) value. If a node has the root value then recursively check its return 2 # off or on
children. if n == 2:
# Else it has a larger value, so update second_min. return 3 # not both on
# Time - O(n) return 4 # evens, odds, every third or all off
# Space - O(n)
if m == 2: # two switches
class Solution(object): if n == 1:
def findSecondMinimumValue(self, root): return 2 # off or on
""" if n == 2:
:type root: TreeNode return 4 # all possibilities
:rtype: int if n >= 3:
""" return 7 # all apart from on, on, off
min_val = root.val # assumes root exists
self.second_min = float("inf") return 2 ** min(n, 3) # any combination of evens, odds, every third

def helper(node):
# python_1_to_1000/673_Number_of_Longest_Increasing_Subsequence.py - m
if not node:
return _author_ = 'jake'
_project_ = 'leetcode'
if node.val == min_val:
helper(node.left) # https://leetcode.com/problems/number-of-longest-increasing-subsequence/
helper(node.right) # Given an unsorted array of integers, find the number of longest increasing subsequence.
else: # node.val > min_val
self.second_min = min(node.val, self.second_min) # For each num, find the longest increasing subsequence of the array up to and including
that num, and the count of
helper(root) # such longest subsequences. Fro each num, consider all previous nums that are lower. If
we can make a new longest
return -1 if self.second_min == float("inf") else self.second_min # subsequence then we can extend every longest subsequence ending at the previous num. If
we can make the same longest
# subsequence then we can add every longest subsequence ending at the previous num to the
# python_1_to_1000/672_Bulb_Switcher_II.py - m count.
# Time - O(n**2)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/bulb-switcher-ii/ def findNumberOfLIS(self, nums):
# There is a room with n lights which are turned on initially and 4 buttons on the wall. """
After performing exactly m :type nums: List[int]
# unknown operations towards buttons, you need to return how many different kinds of :rtype: int
status of the n lights could be. """
# Suppose n lights are labeled as number [1, 2, 3 ..., n], function of these 4 buttons if not nums:
are given below: return 0
# Flip all the lights. lengths, counts = [], []
# Flip lights with even numbers.
# Flip lights with odd numbers. for i, num in enumerate(nums):
# Flip lights with (3k + 1) numbers, k = 0, 1, 2, ...
length, count = 1, 1 # default if num does not increase any subsequence
# 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 for j in range(i):
# possible states. Additional m or n do not lead to any more states. Smaller cases are if num > nums[j]: # num can extend sequence
considered individually. if lengths[j] + 1 > length: # new best length
# Time - O(1) length = lengths[j] + 1
count = counts[j] # Find all trees and sort in increasing height order. DFS from (0, 0) to check all treas
elif lengths[j] + 1 == length: # same best length can be reached.
count += counts[j] # add to count of best length # Sum distances between trees by attempting to take the most direct path. Any node that
is not closer to destination
lengths.append(length) # is added to next_queue and is used once queue is exhausted. The number of diversions
counts.append(count) increases until a path is found.
# Time - O(m**2 n**2) since mn maximum number of trees and each path explores all mn
longest = max(lengths) calls.
return sum([count for length, count in zip(lengths, counts) if length == # Space - O(mn)
longest])
class Solution(object):
def cutOffTree(self, forest):

# python_1_to_1000/674_Longest_Continuous_Increasing_Subsequence.py rows, cols = len(forest), len(forest[0])


trees = sorted((h, r, c) for r, row in enumerate(forest) # trees sorted by
_author_ = 'jake' increasing height
_project_ = 'leetcode' for c, h in enumerate(row) if h > 1)

# https://leetcode.com/problems/longest-continuous-increasing-subsequence/ to_visit = set((r, c) for _, r, c in trees) # check if all trees


# Given an unsorted array of integers, find the length of longest continuous increasing can be reached
subsequence (subarray). visited = set()
queue = [(0, 0)]
# Dynamic programming. Find longest CIS ending at each num. If non-increasing, reset
current sequence length. while queue:
# Time - O(n) r, c = queue.pop()
# Space - O(1) to_visit.discard((r, c))
visited.add((r, c))
class Solution(object): for r1, c1 in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]:
def findLengthOfLCIS(self, nums): # add to queue all neighbours within grid, not obstacles and have not
""" visited already
:type nums: List[int] if 0 <= r1 < rows and 0 <= c1 < cols and forest[r1][c1] and (r1, c1) not
:rtype: int in visited:
""" queue.append((r1, c1))
longest, current = 0, 0
if to_visit: # cannot reach all trees
for i, num in enumerate(nums): return -1

if i == 0 or num <= nums[i - 1]: def distance(r1, c1, r2, c2):


current = 0
direct = abs(r1 - r2) + abs(c1 - c2) # manhattan distance
current += 1 diversions = 0
longest = max(longest, current) queue = [(r1, c1)] # cells on paths with current number of diversions
next_queue = [] # cells on paths with next number of diversions
return longest visited = set()

while True:
# python_1_to_1000/675_Cut_Off_Trees_for_Golf_Event.py - h
if not queue: # cannot reach r2, c2 on path with current diversions
_author_ = 'jake' queue, next_queue = next_queue, [] # try paths with next number of
_project_ = 'leetcode' diversions
diversions += 1
# https://leetcode.com/problems/cut-off-trees-for-golf-event/
# You are asked to cut off trees in a forest for a golf event. r1, c1 = queue.pop()
# The forest is represented as a non-negative 2D map, in this map: if (r1, c1) == (r2, c2): # reached destination
# 0 represents the obstacle can't be reached. return direct + diversions * 2 # for every diversion, must take a
# 1 represents the ground can be walked through. step back in correct direction
# The place with number bigger than 1 represents a tree can be walked through, and this
positive number represents if (r1, c1) in visited:
# the tree's height. continue
# You are asked to cut off all the trees in this forest in the order of tree's height - visited.add((r1, c1))
always cut off the tree with
# lowest height first. And after cutting, the original place has the tree will become a for r1, c1, closer in (r1 + 1, c1, r1 < r2), (r1 - 1, c1, r1 > r2), (r1,
grass (value 1). c1 + 1, c1 < c2), (
# You will start from the point (0, 0) and you should output the minimum steps you need r1, c1 - 1, c1 > c2):
to walk to cut off all if 0 <= r1 < rows and 0 <= c1 < cols and forest[r1][c1]:
# the trees. If you can't cut off all the trees, output -1 in that situation. (queue if closer else next_queue).append((r1, c1))
# You are guaranteed that no two trees have the same height and there is at least one
tree needs to be cut off. result = 0
r1, c1 = 0, 0 # starting location

for _, r2, c2 in trees: return False


result += distance(r1, c1, r2, c2) # add distance between trees to
result if i == len(word): # end fo word, True if terminal node and 1
r1, c1 = r2, c2 # set next starting location mismatch
return "#" in node and mismatches == 1
return result
for c in node.keys():
if c == "#":
# python_1_to_1000/676_Implement_Magic_Dictionary.py - m continue
if helper(i + 1, mismatches + (c != word[i]), node[c]):
_author_ = 'jake' return True
_project_ = 'leetcode'
return False
# https://leetcode.com/problems/implement-magic-dictionary/
# Implement a magic directory with buildDict, and search methods. return helper(0, 0, self.root)
# For the method buildDict, you'll be given a list of non-repetitive words to build a
dictionary.
# For the method search, you'll be given a word, and judge whether if you modify exactly
one character into another # python_1_to_1000/677_Map_Sum_Pairs.py - m
# character in this word, the modified word is in the dictionary you just built.
_author_ = 'jake'
# Create a trie where each node is a mapping from a letter to the next node (which is _project_ = 'leetcode'
itself a mapping). Terminal
# nodes at the end of words are signified by a mapping to '#'. Search works by depth # https://leetcode.com/problems/map-sum-pairs/
first search on trie. # Implement a MapSum class with insert, and sum methods.
# Track the index of the next char to match in word and number of mistmatches seen so # For the method insert, you'll be given a pair of (string, integer). The string
far. For each char, move down represents the key and the integer
# the trie to all children incrementing the mismatches if then node is different from the # represents the value. If the key already existed, then the original key-value pair will
char of the word. Terminate be overridden to the new one.
# at either the end fo the word or too many mismatches are found. # For the method sum, you'll be given a string representing the prefix, and you need to
# Time - O(n) to buildDict where n is the total number of chars in all words in return the sum of all the
dictionary. O(m) to search where m is # pairs' value whose key starts with the prefix.
# the length of the word since there are a finite number (25) of mismatches at every
node. # Create a mapping from each prefix to the sum of vals of words with that prefix, and a
# Space - O(n) separate mapping of vals of
# each words. If inserting a word which has been seen already, update the difference
class MagicDictionary(object): between the new an old val for
# all prefixes.
def __init__(self): # Time - O(k**2) for insert and O(1) for sum
""" # Space - O(nk)
Initialize your data structure here.
""" from collections import defaultdict
self.root = {} # key is char, value is dictionary
class MapSum(object):
def buildDict(self, dict):
""" def __init__(self):
Build a dictionary through a list of words """
:type dict: List[str] Initialize your data structure here.
:rtype: void """
""" self.dict = defaultdict(int) # map prefix to sum of vals with that prefix
for word in dict: self.words = defaultdict(int) # map whole words to their val
node = self.root
def insert(self, key, val):
for c in word: """
if c not in node: :type key: str
node[c] = {} :type val: int
node = node[c] :rtype: void
node["#"] = None # signifies end of a word """
if key in self.words: # update words and update val to change in
def search(self, word): val
""" self.words[key], val = val, val - self.words[key]
Returns if there is any word in the trie that equals to the given word after else:
modifying exactly one character self.words[key] = val # insert into words
:type word: str
:rtype: bool for i in range(len(key)):
""" prefix = key[:i + 1]
def helper(i, mismatches, node): # index of next char to match, nb mismatches self.dict[prefix] += val # update dict for all prefixes

if mismatches == 2: # too many mismatches def sum(self, prefix):


"""
:type prefix: str # For any input list, iterate through every pair of numbers and combine them in all 6
:rtype: int possible ways. There are 6 ways
""" # because addition and multiplication are commutative but subtraction and division are
return self.dict[prefix] 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.
# python_1_to_1000/678_Valid_Parenthesis_String.py - m # The base case is a list with one element. Numerical precision implies this may not be
exactly 24 but the minimum
_author_ = 'jake' # number that can eb formed is 1 / (9 * 9 * 9) and sets a bound on the tolerance.
_project_ = 'leetcode' # Time - O(1) since here are a finite number of combinations.
# Space - O(1)
# https://leetcode.com/problems/valid-parenthesis-string/
# Given a string containing only three types of characters: '(', ')' and '*', write a class Solution(object):
function to check whether this def judgePoint24(self, nums):
# string is valid. We define the validity of a string by these rules: """
# 1. Any left parenthesis '(' must have a corresponding right parenthesis ')'. :type nums: List[int]
# 2. Any right parenthesis ')' must have a corresponding left parenthesis '('. :rtype: bool
# 3. Left parenthesis '(' must go before the corresponding right parenthesis ')'. """
# 4. '*' could be treated as a single right parenthesis ')' or a single left parenthesis n = len(nums)
'(' or an empty string. if n == 1:
# 5. An empty string is also valid. return abs(nums[0] - 24) < 0.001

# Track the range of possible open brackets when iterating over s. If "(" is seen, both for i in range(n - 1):
bounds of range increase. If for j in range(i + 1, n):
# ")" is seen both bounds decrease subject to the lower bound not becoming negative. If remainder = nums[:i] + nums[i + 1:j] + nums[j + 1:]
"*" is seen, upper bound
# increase and lower bound decreases, subject to zero. Upper bound can never be less than if self.judgePoint24(remainder + [nums[i] + nums[j]]):
zero. Lower bound must be return True
# zero at end of s. if self.judgePoint24(remainder + [nums[i] - nums[j]]):
# Time - O(n) return True
# Space - O(1) if self.judgePoint24(remainder + [nums[j] - nums[i]]):
return True
class Solution(object): if self.judgePoint24(remainder + [nums[i] * nums[j]]):
def checkValidString(self, s): return True
""" if nums[j] != 0 and self.judgePoint24(remainder + [float(nums[i]) /
:type s: str float(nums[j])]):
:rtype: bool return True
""" if nums[i] != 0 and self.judgePoint24(remainder + [float(nums[j]) /
min_open, max_open = 0, 0 float(nums[i])]):
return True
for c in s:
return False
if c == "(":
min_open += 1
max_open += 1 # python_1_to_1000/680_Valid_Palindrome_II.py
elif c == ")":
min_open = max(0, min_open - 1) _author_ = 'jake'
max_open -= 1 _project_ = 'leetcode'
else:
min_open = max(0, min_open - 1) # https://leetcode.com/problems/valid-palindrome-ii/
max_open += 1 # Given a non-empty string s, you may delete at most one character. Judge whether you can
make it a palindrome.
if max_open < 0:
return False # Iterate over s from front and back. If chars do not match, check if the remainder after
deleting either of the
return min_open == 0 # unmatched chars is a palindrome.
# Time - O(n)
# Space - O(n)

# python_1_to_1000/679_24_Game.py - h class Solution(object):


def validPalindrome(self, s):
_author_ = 'jake' """
_project_ = 'leetcode' :type s: str
:rtype: bool
# https://leetcode.com/problems/24-game/ """
# You have 4 cards each containing a number from 1 to 9. You need to judge whether they n = len(s)
could operated i = 0
# through *, /, +, -, (, ) to get the value of 24.

while i < n // 2:

if s[i] != s[n - 1 - i]: # python_1_to_1000/682_Baseball_Game.py


del_front = s[i + 1:n - i]
del_back = s[i:n - 1 - i] _author_ = 'jake'
return del_front == del_front[::-1] or del_back == del_back[::-1] _project_ = 'leetcode'

i += 1 # https://leetcode.com/problems/baseball-game/
# You're now a baseball game point recorder.
return True # 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.
# python_1_to_1000/681_Next_Closest_Time.py - m # "+" (one round's score): The points you get in this round are the sum of the last two
valid round's points.
_author_ = 'jake' # "D" (one round's score): The points you get in this round are the doubled data of the
_project_ = 'leetcode' last valid round's points.
# "C" (an operation, which isn't a round's score): The last valid round's points were
# https://leetcode.com/problems/next-closest-time/ invalid and should be removed.
# Given a time represented in the format "HH:MM", form the next closest time by reusing # Each round's operation is permanent and could have an impact on the round before and
the current digits. the round after.
# There is no limit on how many times a digit can be reused. # You need to return the sum of the points you could get in all the rounds.
# You may assume the given input string is always valid. For example, "01:34", "12:09"
are all valid. "1:34", "12:9" # Maintain a stack of previous scores, summed after applying all operations.
# are all invalid. # Time - O(n)
# Space - O(n)
# Iterate over time from least significant digit. Attempt to increase each digit by
looking for the smallest greater class Solution(object):
# digit. Maximum allowed digit depends on index in time. If an increase is possible, make def calPoints(self, ops):
it and return. Else try """
# again with next digit. :type ops: List[str]
# Time - O(1) :rtype: int
# Space - O(1) """
points = []
class Solution(object):
def nextClosestTime(self, time): for op in ops:
"""
:type time: str if op == "+": # assumes there are at least 2 previous socres
:rtype: str points.append(points[-1] + points[-2])
""" elif op == "D": # assumes at least one previous score
result = [c for c in time] points.append(2 * points[-1])
digits = set(int(c) for c in time[:2] + time[3:]) # set of digits in time elif op == "C": # remove previous
min_digit = min(digits) points.pop()
max_digits = {0 : 2, 3 : 5, 4 : 9} # max possible digit at else:
each index points.append(int(op))

def increase(i): return sum(points)


if i == 1: # max digit depends on
time[0]
if time[0] == "2":
max_digit = 3 # python_1_to_1000/683_K_Empty_Slots.py - h
else:
max_digit = 9 _author_ = 'jake'
else: _project_ = 'leetcode'
max_digit = max_digits[i]
# https://leetcode.com/problems/k-empty-slots/
larger_digits = [d for d in digits if int(time[i]) < d <= max_digit] # There is a garden with N slots. In each slot, there is a flower. The N flowers will
return min(larger_digits) if larger_digits else -1 bloom one by one in N days.
# In each day, there will be exactly one flower blooming and it will be in the status of
for i in [4, 3, 1, 0]: # iterate backwards, blooming since then.
ignoring ":" # Given an array flowers consists of number from 1 to N. Each number in the array
increaseed = increase(i) represents the place where the
if increaseed != -1: # flower will open in that day.
result[i] = str(increaseed) # For example, flowers[i] = x means that the unique flower that blooms at day i will be
break at position x, where i and x
else: # will be in the range from 1 to N.
result[i] = str(min_digit) # Also given an integer k, you need to output in which day there exists two flowers in
the status of blooming, and
return "".join(result) # also the number of flowers between them is k and these flowers are not blooming.
# If there isn't such day, output -1.
# Convert to a list where indices represent positions and values represent days. Create a # Every edge of a tree connects two sets of nodes that are not otherwise connected. Find
window with k intervening the edge that connects already
# flowers and check if any bloom earlier than those at the ends. If so, then reset the # connected nodes with union find structure.
window start to the earlier # Find parents of both nodes of an edge. If same then there is already a path between
# blooming flower, because flowers already visited bloom later and so cannot start a new nodes. Else connect
window. Else if no flower # the parents.
# blooms earlier than the window ends, update the earliest_day with the later of the # Time - O(n log* n)
flowers at the ends of the # Space - O(n)
# window and start a new window where the current window ends.
# Time - O(n) class Solution(object):
# Space - O(n) def findRedundantConnection(self, edges):
"""
class Solution(object): :type edges: List[List[int]]
def kEmptySlots(self, flowers, k): :rtype: List[int]
""" """
:type flowers: List[int] parents = {}
:type k: int
:rtype: int def find_parent(n):
"""
n = len(flowers) if n not in parents: # n is a new node or ultimate
days = [None for _ in range(n)] # index is position and value is day of parent
blooming return n
for day, pos in enumerate(flowers, 1): # index days from 1 parents[n] = find_parent(parents[n]) # collapse parent to be ultimate
days[pos - 1] = day # positions indexed from 0 parent
return parents[n] # return ultimate parent
left, right = 0, k + 1 # indices in days of ends of window
first_day = n + 1 # first day with a gap of length k for a, b in edges:
between 2 flowers
parent_a, parent_b = find_parent(a), find_parent(b)
while right < n: if parent_a == parent_b:
for i in range(left + 1, right): # check all intervening flowers between return [a, b]
ends of window
if days[i] < days[left] or days[i] < days[right]: # flower at i blooms parents[parent_a] = parent_b # union join
earlier than ends
left, right = i, i + k + 1 # start new window with earlier blloming
flower # python_1_to_1000/685_Redundant_Connection_II.py - h
break
else: _author_ = 'jake'
first_day = min(first_day, max(days[left], days[right])) # no _project_ = 'leetcode'
intervening bloom earlier
left, right = right, right + k + 1 # start new window at end of this # https://leetcode.com/problems/redundant-connection-ii/
window # In this problem, a rooted tree is a directed graph such that, there is exactly one node
(the root) for which all
return -1 if first_day == n + 1 else first_day # other nodes are descendants of this node, plus every node has exactly one parent,
except for the root node which
# has no parents.
# The given input is a directed graph that started as a rooted tree with N nodes (with
distinct values 1, 2, ..., N),
# python_1_to_1000/684_Redundant_Connection.py - m # with one additional directed edge added. The added edge has two different vertices
chosen from 1 to N, and was not
_author_ = 'jake' # an edge that already existed.
_project_ = 'leetcode' # The resulting graph is given as a 2D-array of edges. Each element of edges is a pair
[u, v] that represents a
# https://leetcode.com/problems/redundant-connection/ # directed edge connecting nodes u and v, where u is a parent of child v.
# In this problem, a tree is an undirected graph that is connected and has no cycles. # Return an edge that can be removed so that the resulting graph is a rooted tree of N
# The given input is a graph that started as a tree with N nodes (with distinct values 1, nodes.
2, ..., N), with one # If there are multiple answers, return the answer that occurs last in the given 2D-
# additional edge added. The added edge has two different vertices chosen from 1 to N, array.
and was not an edge that
# already existed. # Given a valid tree, a redundant connection is either A) to the root, causing all nodes
# The resulting graph is given as a 2D-array of edges. Each element of edges is a pair to have one parent or B) not
[u, v] with u < v, that # to the root, causing some node to have 2 parents. If case B, find the node with 2
# represents an undirected edge connecting nodes u and v. parents and the root. Remove one
# Return an edge that can be removed so that the resulting graph is a tree of N nodes. If # of the incoming edges to the node with 2 parents and if the tree is valid, the removed
there are multiple answers, edge is redundant else the
# return the answer that occurs last in the given 2D-array. The answer edge [u, v] should # other incoming edge to the node with 2 parents is redundant.
be in the same # If case A, try removing edges from the last of the input list until a valid tree is
# format, with u < v. found.

# Time - O(n**2) """


# Space - O(n) :type A: str
:type B: str
class Solution(object): :rtype: int
def findRedundantDirectedConnection(self, edges): """
""" if set(B) - set(A): # early return
:type edges: List[List[int]] return -1
:rtype: List[int]
""" div, mod = divmod(len(B), len(A))
n = len(edges)
parents = [[] for _ in range(n + 1)] if mod != 0:
nbors = [set() for _ in range(n + 1)] div += 1

for a, b in edges: # build parents and nbors lists for i in range(2):


parents[b].append(a) if B in A * (div + i):
nbors[a].add(b) return div + i

root = None return -1


for i, parent in enumerate(parents): # check if some node has 2 parents
if len(parent) == 2:
two_parents = i
if not parent: # identify the root # python_1_to_1000/687_Longest_Univalue_Path.py - m
root = i
_author_ = 'jake'
def valid(root): # test if all nodes can be visited once _project_ = 'leetcode'
and once only
visited = set() # https://leetcode.com/problems/longest-univalue-path/
queue = [root] # Given a binary tree, find the length of the longest path where each node in the path
while queue: has the same value.
node = queue.pop() # This path may or may not pass through the root.
if node in visited: # The length of path between two nodes is represented by the number of edges between
return False them.
visited.add(node)
queue += nbors[node] # Helper function updates longest for the univalue path that goes through each node.
return len(visited) == n Helper returns a tuple of the
# longest paths via the left and right children of each node.
if root: # case B, edge added to node that was not # Time - O(n)
root # Space - O(n)
p1, p2 = parents[two_parents]
nbors[p2].discard(two_parents) # discard second edge class Solution(object):
return [p2, two_parents] if valid(root) else [p1, two_parents] def longestUnivaluePath(self, root):
"""
for i in range(len(edges) - 1, -1, -1): # remove edges starting with last edge to :type root: TreeNode
be added :rtype: int
n1, n2 = edges[i] """
nbors[n1].discard(n2) # temporarily remove edge from n1 to n2 self.longest = 0
if valid(n2): # n2 becomes the root
return edges[i] def helper(node):
nbors[n1].add(n2) # put edge back if not node:
return 0, 0

# python_1_to_1000/686_Repeated_String_Match.py - m max_left = max(helper(node.left)) # longest univalue path from left


child
_author_ = 'jake' max_right = max(helper(node.right))
_project_ = 'leetcode'
# if left child has the same val as node, add one edge to longest path via
# https://leetcode.com/problems/repeated-string-match/ left child
# Given two strings A and B, find the minimum number of times A has to be repeated such left = 1 + max_left if node.left and node.left.val == node.val else 0
that B is a substring of it. right = 1 + max_right if node.right and node.right.val == node.val else 0
# If no such solution, return -1.
self.longest = max(self.longest, left + right)
# 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 left, right
# More copies of A are not required because at least one copy of A will not be used.
# Time - O(n + m) helper(root)
# Space - O(n + m) return self.longest

class Solution(object):
def repeatedStringMatch(self, A, B): # python_1_to_1000/688_Knight_Probability_in_Chessboard.py - m
new_probs[r1][c1] = prob # update cell
_author_ = 'jake' probs = new_probs # update board
_project_ = 'leetcode'
r, c = convert(r, c)
# https://leetcode.com/problems/knight-probability-in-chessboard/ return probs[r][c]
# On an NxN chessboard, a knight starts at the r-th row and c-th column and attempts to
make exactly K moves.
# 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 # python_1_to_1000/689_Maximum_Sum_of_3_Non-Overlapping_Subarrays.py - h
squares in a cardinal
# direction, then one square in an orthogonal direction. _author_ = 'jake'
# Each time the knight is to move, it chooses one of eight possible moves uniformly at _project_ = 'leetcode'
random (even if the piece
# would go off the chessboard) and moves there. # https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/
# The knight continues moving until it has made exactly K moves or has moved off the # In a given array nums of positive integers, find three non-overlapping subarrays with
chessboard. Return the maximum sum.
# probability that the knight remains on the board after it has stopped moving. # Each subarray will be of size k, and we want to maximize the sum of all 3*k entries.
# Return the result as a list of indices representing the starting position of each
# Base case for N == 0 is 100% probability of remaining on the board for all cells. interval (0-indexed).
# For each additional remaining move, calculate a grid of probabilities of remaining on # If there are multiple answers, return the lexicographically smallest one.
the board from each cell.
# The new probability from a cell is the sum of the probabilities from each of the 8 # Initialise one, tow and three as the first three contiguous subarrays of length k in
reachable cells given one fewer nums. Iterate over nums,
# remaining move. # moving the current 3 subarrays forward on every step. Update the best sum first
# Only consider the upper left quarter of the board, since the remainder is symmetrical. subarray if greater. Update the best
# Time - O(K * N**2) # sum first 2 subarrays if the new second subarray plus the best first is greater. Update
# Space - O(N**2) the best all 3 subarrays if
# the new third subarray plus the best first two sum is greater.
class Solution(object): # Time - O(n)
def knightProbability(self, N, K, r, c): # Space - O(1)
"""
:type N: int class Solution(object):
:type K: int def maxSumOfThreeSubarrays(self, nums, k):
:type r: int """
:type c: int :type nums: List[int]
:rtype: float :type k: int
""" :rtype: List[int]
M = N // 2 # M is the side length of the upper quarter """
if N % 2 == 1: # add central row and column if N is odd one_sum = sum(nums[:k]) # sums of current subarrays
M += 1 two_sum = sum(nums[k:k * 2])
three_sum = sum(nums[k * 2:k * 3])
def convert(r1, c1): # convert a cell to its symmetrical equivalent in the
upper quarter best_one = one_sum # best sums of one, two and three
if r1 >= M: subarrays
r1 = N - 1 - r1 best_two = one_sum + two_sum
if c1 >= M: best_three = one_sum + two_sum + three_sum
c1 = N - 1 - c1
return [r1, c1] best_one_i = 0 # start indices of best one, two and
three subarrays
probs = [[1 for _ in range(M)] for _ in range(M)] # 100% probability of best_two_i = [0, k]
remaining for no more moves best_three_i = [0, k, k * 2]

for _ in range(K): one_i = 1 # next array start index


two_i = k + 1
new_probs = [[0 for _ in range(M)] for _ in range(M)] three_i = k * 2 + 1

for r1 in range(M): while three_i <= len(nums) - k:


for c1 in range(M):
prob = 0 one_sum += nums[one_i + k - 1] - nums[one_i - 1] # update current subarray
for dr in [2, 1, -1, -2]: # for each possible move sums
for dc in [3 - abs(dr), abs(dr) - 3]: two_sum += nums[two_i + k - 1] - nums[two_i - 1]
three_sum += nums[three_i + k - 1] - nums[three_i - 1]
if 0 <= r1 + dr < N and 0 <= c1 + dc < N: # ignore if
outside the board if one_sum > best_one: # one_sum in an improvement
r2, c2 = convert(r1 + dr, c1 + dc) best_one = one_sum
prob += probs[r2][c2] / 8.0 # add 1/8 of best_one_i = one_i
probability
if best_one + two_sum > best_two: # two_sum and best_one are an

improvement
best_two = best_one + two_sum _author_ = 'jake'
best_two_i = [best_one_i, two_i] _project_ = 'leetcode'

if best_two + three_sum > best_three: # three_sum and best_two are an # https://leetcode.com/problems/stickers-to-spell-word/


improvement # We are given N different types of stickers. Each sticker has a lowercase English word
best_three = best_two + three_sum on it.
best_three_i = best_two_i + [three_i] # You would like to spell out the given target string by cutting individual letters from
your collection of stickers
one_i += 1 # and rearranging them.
two_i += 1 # You can use each sticker more than once if you want, and you have infinite quantities
three_i += 1 of each sticker.
# What is the minimum number of stickers that you need to spell out the target? If the
return best_three_i task is impossible, return -1.

# Remove chars from each sticker that are not in target and create mapping from char to
# python_1_to_1000/690_Employee_Importance.py - m set of stickers containing
# that char. Return -1 if every char of target is not contained in at least one sticker.
_author_ = 'jake' # Maintain a heap of candidate solutions. Pop item from heap with lowest used stickers,
_project_ = 'leetcode' breaking ties by lowest
# remaining target length. For each sticker that contains the first remaining letter of
# https://leetcode.com/problems/employee-importance/ target, remove all usable
# You are given a data structure of employee information, which includes the employee's # chars from target and add remaining target back to heap.
unique id, his importance # Space - O(n * k**2) where n is number of sickers and k is length of target. If target
# value and his direct subordinates' id. is a string of the same char
# For example, employee 1 is the leader of employee 2, and employee 2 is the leader of # repeated and every sticker is that char, then every sticker will be used for every char
employee 3. of target.
# They have importance value 15, 10 and 5, respectively. Then employee 1 has a data # Time - O(nk log(nk) * k * s**2) every item in heap created by taking every char of
structure like [1, 15, [2]], sticker, testing for char in
# and employee 2 has [2, 10, [3]], and employee 3 has [3, 5, []]. # target, then remving from sticker.
# Note that although employee 3 is also a subordinate of employee 1, the relationship is
not direct. import heapq
# Now given the employee information of a company, and an employee id, you need to return from collections import defaultdict
the total importance value
# of this employee and all his subordinates. class Solution(object):
def minStickers(self, stickers, target):
# Create mapping from employee id to importance and subordinates. Sum importance by """
recursive depth first search. :type stickers: List[str]
# Get importance of root employee and recursively add importance totals of subordinates. :type target: str
# Time - O(n) :rtype: int
# Space - O(n) """
target_set, remaining_target = set(target), set(target)
class Solution(object): char_to_word = defaultdict(set) # map char to set of words, where each word is a
def getImportance(self, employees, id): tuple of cleaned chars
"""
:type employees: Employee for sticker in stickers:
:type id: int cleaned = tuple(x for x in sticker if x in target_set) # remove chars that
:rtype: int are not in target
""" sticker_set = set(cleaned)
importance, subordinates = {}, {} for c in sticker_set:
char_to_word[c].add(cleaned)
for employee in employees: remaining_target -= sticker_set
importance[employee.id] = employee.importance
subordinates[employee.id] = employee.subordinates if remaining_target:
return -1
def sum_importance(emp_id): # return emp_id importance plus recursive sum
of subordinates heap = [(0, len(target), list(target))] # using a list for target allows remove

total = importance[emp_id] while True:

for sub in subordinates[emp_id]: used_words, target_len, target_str = heapq.heappop(heap) # try least used
total += sum_importance(sub) words, then shortest target

return total for sticker in char_to_word[target_str[0]]: # each word that contains first
char of target
return sum_importance(id) new_str = target_str[:]
for ch in sticker:
if ch in new_str:
# python_1_to_1000/691_Stickers_to_Spell_Word.py - h new_str.remove(ch)
if not new_str:
return used_words + 1 # python_1_to_1000/694_Number_of_Distinct_Islands.py - m
heapq.heappush(heap, (used_words + 1, len(new_str), new_str))
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/692_Top_K_Frequent_Words.py - m
# https://leetcode.com/problems/number-of-distinct-islands/
_author_ = 'jake' # Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's
_project_ = 'leetcode' (representing land) connected
# 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are
# https://leetcode.com/problems/top-k-frequent-words/ surrounded by water.
# Given a non-empty list of words, return the k most frequent elements. # Count the number of distinct islands. An island is considered to be the same as another
# Your answer should be sorted by frequency from highest to lowest. If two words have the if and only if one island
same frequency, then the # can be translated (and not rotated or reflected) to equal the other.
# word with the lower alphabetical order comes first.
# For each non-empty cell, breadth-first search for all adjacent non-empty cells. BFS by
# Count the frequencies and heapify tuples of (-count, word). The pop the first k entries creating a queue of cells
from the heap. # with positions relative to first cell, setting each cell to empty as it is found.
# Time - O(n + k log n) since O(n) to count and heapify, then O(log N) for each of the k Return tuple of relative positions
pops # which are counted in a set.
# Space - O(N) # Time - O(mn)
# Space - O(mn)
from collections import Counter
import heapq class Solution(object):
def numDistinctIslands(self, grid):
class Solution(object): """
def topKFrequent(self, words, k): :type grid: List[List[int]]
""" :rtype: int
:type words: List[str] """
:type k: int if not grid or not grid[0]:
:rtype: List[str] return 0
"""
freq = Counter(words) rows, cols = len(grid), len(grid[0])
pairs = [(-count, word) for word, count in freq.items()]
heapq.heapify(pairs) def BFS(r, c):
return [heapq.heappop(pairs)[1] for _ in range(k)]
queue = [(0, 0)] # relative to (r, c)
for r_rel, c_rel in queue: # queue is extended during iteration
# python_1_to_1000/693_Binary_Number_with_Alternating_Bits.py
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
_author_ = 'jake'
_project_ = 'leetcode' new_r, new_c = r_rel + dr + r, c_rel + dc + c

# https://leetcode.com/problems/binary-number-with-alternating-bits/ if 0 <= new_r < rows and 0 <= new_c < cols and grid[new_r][new_c] ==
# Given a positive integer, check whether it has alternating bits: namely, if two 1:
adjacent bits will always grid[new_r][new_c] = 0
# have different values. queue.append((new_r - r, new_c - c))

# Repeatedly divide by 2 where remainder is bit value. return tuple(queue)


# Time - O(log n)
# Space - O(1) islands = set()
for r in range(rows):
class Solution(object): for c in range(cols):
def hasAlternatingBits(self, n): if grid[r][c] == 0:
""" continue
:type n: int islands.add(BFS(r, c))
:rtype: bool
""" return len(islands)
n, bit = divmod(n, 2) # get first bit, avoids special case in while loop

while n: # python_1_to_1000/695_Max_Area_of_Island.py - m

if n % 2 == bit: # next bit is same as current bit _author_ = 'jake'


return False _project_ = 'leetcode'

n, bit = divmod(n, 2) # 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
return True (representing land) connected
# 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are

surrounded by water. for i, c in enumerate(s[1:], 1): # first digit already used


# Find the maximum area of an island in the given 2D array. (If there is no island, the
maximum area is 0.) if c != s[i - 1]: # c is different from previous char
count += min(seq, prev_seq) # add all balanced substrings
# Iterate over grid. If cell == 1 then perform depth-first search, setting cells to zero seq, prev_seq = 1, seq
so they are not revisited. else:
# Time - O(mn) seq += 1
# Space - O(1), modifies input grid
return count + min(seq, prev_seq) # add final balanced substrings
class Solution(object):
def maxAreaOfIsland(self, grid):
""" # python_1_to_1000/697_Degree_of_an_Array.py
:type grid: List[List[int]]
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
rows, cols = len(grid), len(grid[0])
neighbours = [(1, 0), (-1, 0), (0, 1), (0, -1)] # https://leetcode.com/problems/degree-of-an-array/
max_area = 0 # Given a non-empty array of non-negative integers nums, the degree of this array is
defined as the maximum frequency
def island_area(r, c): # of any one of its elements.
# Your task is to find the smallest possible length of a (contiguous) subarray of nums
grid[r][c] = 0 that has the same degree as nums.
area = 1
# Count the frequency of each num and record its first and last index. Then find the num
for dr, dc in neighbours: # faster to check valid land cell before or nums with the largest count.
recursing # Finally, find the shortest distance between first and last indices of each maximum
if 0 <= r + dr < rows and 0 <= c + dc < cols and grid[r + dr][c + dc] == count num.
1: # Time - O(n)
area += island_area(r + dr, c + dc) # Space - O(n)

return area from collections import defaultdict

for row in range(rows): class Solution(object):


for col in range(cols): def findShortestSubArray(self, nums):
if grid[row][col] == 1: # check only occupied cells """
max_area = max(max_area, island_area(row, col)) :type nums: List[int]
:rtype: int
return max_area """
counts, limits = defaultdict(int), {}

# python_1_to_1000/696_Count_Binary_Substrings.py for i, num in enumerate(nums):

_author_ = 'jake' counts[num] += 1


_project_ = 'leetcode'
if num not in limits:
# https://leetcode.com/problems/count-binary-substrings/ limits[num] = [i, i] # first and last indices are both i
# Give a string s, count the number of non-empty (contiguous) substrings that have the else:
same number of 0's and 1's, limits[num][-1] = i # new last index of i
# 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. max_count, max_nums = 0, [] # list of nums with max_count
for num, count in counts.items():
# When a sequence of one digit ends, count the required substrings using this sequence
and the previous sequence if count == max_count:
# (which uses the other digit). Count as many substrings as the lower of the sequence max_nums.append(num) # new num with same max_count
length and previous sequence elif count > max_count:
# length. max_nums = [num] # new unique max
# Time - O(n) max_count = count
# Space - O(1)
shortest = float("inf")
class Solution(object): for num in max_nums:
def countBinarySubstrings(self, s): shortest = min(shortest, limits[num][1] - limits[num][0] + 1)
"""
:type s: str return shortest
:rtype: int
"""
seq, prev_seq = 1, 0 # lengths of the current and previous # python_1_to_1000/698_Partion_to_K_Equal_Sum_Subsets.py - m
sequences
count = 0 _author_ = 'jake'
_project_ = 'leetcode'
if helper(i + 1):
# https://leetcode.com/problems/partition-to-k-equal-sum-subsets/ return True
# Given an array of integers nums and a positive integer k, find whether it's possible to partition[j] -= nums[i]
divide this array into k if partition[j] == 0: # do not try other empty buckets
# non-empty subsets whose sums are all equal. break

# Sort in decreasing order. Find some nums that sum to target, flagging each num in used. return False
If a num is used then only
# search smaller nums since any larger would have been used already. return helper(0)
# Alternatively, add each number to each bucket with capacity and recurse, backtracking
if a solution is not found.
# Time - O(k * 2**n) for k buckets, each number is or is not used in each # python_1_to_1000/699_Falling_Squares.py - h
# Space - O(k * 2**n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def canPartitionKSubsets(self, nums, k):
# https://leetcode.com/problems/falling-squares/
total = sum(nums) # On an infinite number line (x-axis), we drop given squares in the order they are given.
if total % k != 0: # The i-th square dropped (positions[i] = (left, side_length)) is a square with the left-
return False # nums are not divisible equally most point being
# positions[i][0] and sidelength positions[i][1].
target = total // k # The square is dropped with the bottom edge parallel to the number line, and from a
higher height than all currently
used = [False] * len(nums) # landed squares. We wait for each square to stick before dropping the next.
# The squares are infinitely sticky on their bottom edge, and will remain fixed to any
nums.sort(reverse = True) positive length surface they
if nums[0] > target: # largest num too big # touch (either the number line or another square). Squares dropped adjacent to each
return False other will not stick together
# prematurely.
def dfs(subsets, last, partial): # Return a list ans of heights. Each height ans[i] represents the current highest height
of any square we have
if subsets == 1: # base case, can always create one subset # dropped, after dropping squares represented by positions[0], positions[1], ...,
return True positions[i].

if partial == target: # start a new subset # For each box, check for overlap with each box already dropped. If overlap update top of
return dfs(subsets - 1, 0, 0) box as side length + top of
# overlapping box.
for i in range(last, len(nums)): # from last num onwards # Time - O(n**2)
# Space - O(n)
if not used[i] and partial + nums[i] <= target:
used[i] = True class Solution(object):
if dfs(subsets, i + 1, partial + nums[i]): # only search smaller def fallingSquares(self, positions):
nums """
return True :type positions: List[List[int]]
used[i] = False :rtype: List[int]
"""
return False box_heights = [positions[0][1]] # top edge height of dropped boxes
max_heights = [positions[0][1]]
return dfs(k, 0, 0)
for left, side in positions[1:]:
top = side # default to on ground, top of box is side length
class Solution2(object):
def canPartitionKSubsets(self, nums, k): for i in range(len(box_heights)): # loop over each previously dropped box
total = sum(nums) left2, side2 = positions[i]
nums.sort(reverse = True) if left2 < left + side and left2 + side2 > left: # horizontal overlap
target = total // k top = max(top, box_heights[i] + side) # on previous box
if total % k != 0 or nums[0] > target:
return False box_heights.append(top)
max_heights.append(max(top, max_heights[-1]))
partition = [0 for _ in range(k)]
return max_heights
def helper(i): # test whether nums[i] can be added to
some partition
if i == len(nums): # python_1_to_1000/700_Search_in_a_Binary_Search_Tree.py
return True
_author_ = 'jake'
for j in range(len(partition)): _project_ = 'leetcode'
if partition[j] + nums[i] <= target:
partition[j] += nums[i] # https://leetcode.com/problems/search-in-a-binary-search-tree/

# Given the root node of a binary search tree (BST) and a value.
# You need to find the node in the BST that the node's value equals the given value. else:
# Return the subtree rooted with that node. If such node doesn't exist, you should return if not node.right:
None. node.right = new_node
return root
# At each node, return if node has target val else recurse right or left depending node = node.right
whether val is greater or less than
# node.val.
# Time - O(n) # python_1_to_1000/702_Search_in_a_Sorted_Array_of_Unknown_Size.py - m
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def searchBST(self, root, val):
""" # https://leetcode.com/problems/search-in-a-sorted-array-of-unknown-size/
:type root: TreeNode # Given an integer array sorted in ascending order, write a function to search target in
:type val: int nums.
:rtype: TreeNode # If target exists, then return its index, otherwise return -1. However, the array size
""" is unknown to you.
if not root: # val is not in tree # You may only access the array using an ArrayReader interface, where ArrayReader.get(k)
return None returns the element of the
# array at index k (0-indexed).
if root.val == val: # You may assume all integers in the array are less than 10000, and if you access the
return root array out of bounds,
# ArrayReader.get will return 2147483647.
if val > root.val: # You may assume that all elements in the array are unique.
return self.searchBST(root.right, val) # The value of each element in the array will be in the range [-9999, 9999].
return self.searchBST(root.left, val)
# Since the array contains unique numbers from -9999 to 9999, there are not more than
20000 numbers.
# python_1_to_1000/701_Insert_into_a_Binary_Search_Tree.py - m # Use 20000 as the upper-bound index in binary search.
# This works because the ArrayReader returns MAXINT for indices beyond the array, which
_author_ = 'jake' is exactly the same as
_project_ = 'leetcode' # searching an array of 20000 elements where the last elements are MAXINT.
# Time - O(1), due to upper bound on size of array
# https://leetcode.com/problems/insert-into-a-binary-search-tree/ # Space - O(1)
# Given the root node of a binary search tree (BST) and a value to be inserted into the
tree, insert the value into class Solution(object):
# the BST. Return the root node of the BST after the insertion. def search(self, reader, target):
# 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 :type reader: ArrayReader
remains a BST after insertion. :type target: int
# You can return any of them. :rtype: int
"""
# Iterative solution. Move left or right according to whether val is less than or greater left, right = 0, 20000
than current node.val, until
# an empty node is found. while left <= right:
# Time - O(n)
# Space - O(1) mid = (left + right) // 2

class Solution(object): val = reader.get(mid)


def insertIntoBST(self, root, val): if target == val:
""" return mid
:type root: TreeNode if target > val:
:type val: int left = mid + 1
:rtype: TreeNode else:
""" right = mid - 1
new_node = TreeNode(val)
if not root: return -1
return new_node

node = root # python_1_to_1000/703_Kth_Largest_Element_in_a_Stream.py

while True: _author_ = 'jake'


_project_ = 'leetcode'
if val < node.val:
if not node.left: # https://leetcode.com/problems/kth-largest-element-in-a-stream/
node.left = new_node # Design a class to find the kth largest element in a stream.
return root # Note that it is the kth largest element in the sorted order, not the kth distinct
node = node.left element.
# Your KthLargest class will have a constructor which accepts an integer k and an integer left, right = 0, len(nums) - 1 # left and right most indices of nums that
array nums, could contain target
# which contains initial elements from the stream. For each call to the method
KthLargest.add, while left <= right:
# return the element representing the kth largest element in the stream.
mid = (left + right) // 2 # middle element of range
# Create a heap of nums and if there are more than k elements, pop off small elements
until it has the k largest. if target == nums[mid]:
# If val cannot change kth largest, discard it and return kth largest. Else insert val, return mid
pop off an element if the if target > nums[mid]: # check right side
# heap is too big and return the kth largest. left = mid + 1
# Time - O(n + (n - k)log n) for __init__ to heapify and pop off excess elements, O(log else: # check left side
k) for add right = mid - 1
# Space - O(k)
return -1
import heapq

class KthLargest(object): # python_1_to_1000/705_Design_HashSet.py

def __init__(self, k, nums): _author_ = 'jake'


""" _project_ = 'leetcode'
:type k: int
:type nums: List[int] # https://leetcode.com/problems/design-hashset/
""" # Design a HashSet without using any built-in hash table libraries.
heapq.heapify(nums) # To be specific, your design should include these functions:
while len(nums) > k: # add(value): Insert a value into the HashSet.
heapq.heappop(nums) # contains(value) : Return whether the value exists in the HashSet or not.
self.k = k # remove(value): Remove a value in the HashSet. If the value does not exist in the
self.nums = nums HashSet, do nothing.

def add(self, val): # Use list of size 10000 since there are at most 10000 operations so we will not fill
""" every element. There may be
:type val: int # collisions, which are handled by separate chaining. Use a simple modulo hash function.
:rtype: int # Time - O(1) average case
""" # Space - O(n)
if len(self.nums) == self.k and val <= self.nums[0]: # heap full and val does
not chahnge kth largest class MyHashSet(object):
return self.nums[0]
def __init__(self):
heapq.heappush(self.nums, val) """
if len(self.nums) > self.k: Initialize your data structure here.
heapq.heappop(self.nums) """
return self.nums[0] self.size = 10000
self.hashset = [[] for _ in range(self.size)]

def hash_function(self, key):


# python_1_to_1000/704_Binary_Search.py return key % self.size # could use builtin hash() for other objects

_author_ = 'jake' def add(self, key):


_project_ = 'leetcode' """
:type key: int
# https://leetcode.com/problems/binary-search/ :rtype: void
# Given a sorted (in ascending order) integer array nums of n elements and a target """
value, write a function to search if not self.contains(key): # do not add if key already present
# target in nums. If target exists, then return its index, otherwise return -1. self.hashset[self.hash_function(key)].append(key)

# Left and right pointers define the range of indices of nums that could contain target. def remove(self, key):
Reduce target by checking """
# middle element and either returning or then checking left or right side. :type key: int
# Time - O(log n) :rtype: void
# Space - O(1) """
if self.contains(key): # do not remove if key not present
class Solution(object): self.hashset[self.hash_function(key)].remove(key)
def search(self, nums, target):
""" def contains(self, key):
:type nums: List[int] """
:type target: int Returns true if this set contains the specified element
:rtype: int :type key: int
""" :rtype: bool

""" def hash_function(self, key):


return key in self.hashset[self.hash_function(key)] # check inner list return key % self.size

def key_index(self, key): # return the bucket that a key belongs to and its
# python_1_to_1000/706_Design_HashMap.py 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/design-hashmap/ return (bucket, i)
# Design a HashMap without using any built-in hash table libraries. return (bucket, -1)
# To be specific, your design should include these functions:
# put(key, value) : Insert a (key, value) pair into the HashMap. If the value already
exists, update the value. # python_1_to_1000/707_Design_Linked_List.py - m
# get(key): Returns the value to which the specified key is mapped, or -1 if this map
contains no mapping for the key. _author_ = 'jake'
# remove(key) : Remove the mapping for the value key if this map contains the mapping for _project_ = 'leetcode'
the key.
# https://leetcode.com/problems/design-linked-list/
# Use a list of size 10000 becasue there are at most 10000 additions and so a reasonable # Design your implementation of the linked list. You can choose to use the singly linked
number of collisions. list or the doubly linked list.
# Eech bucket of the list stores a list of [key, value] pairs where the key hashes to the # A node in a singly linked list should have two attributes: val and next. val is the
bucket index. value of the current node, and
# Time - O(1) average case # next is a pointer/reference to the next node. If you want to use the doubly linked
# Space - O(n) list, you will need one more
# attribute prev to indicate the previous node in the linked list. Assume all nodes in
class MyHashMap(object): the linked list are 0-indexed.
# Implement these functions in your linked list class:
def __init__(self): # get(index) : Get the value of the index-th node in the linked list. If the index is
""" invalid, return -1.
Initialize your data structure here. # addAtHead(val) : 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 # addAtTail(val) : Append a node of value val to the last element of the linked list.
self.hashmap = [[] for _ in range(self.size)] # addAtIndex(index, val) : Add a node of value val before the index-th node in the
linked list.
def put(self, key, value): # If index equals to the length of linked list, the node will be appended to the end of
""" linked list.
value will always be non-negative. # If index is greater than the length, the node will not be inserted.
:type key: int # deleteAtIndex(index) : Delete the index-th node in the linked list, if the index is
:type value: int valid.
:rtype: void
""" # Use a list. Alternatively define a Node class which allows addAtHead in O(1) time but
bucket, index = self.key_index(key) O(n) get method.
if index == -1: # Time - init O(1), get O(1), addAtHead O(n), addAtTail(1), addAtIndex(n),
self.hashmap[bucket].append([key, value]) deleteAtIndex(n)
else: # Space - O(n)
self.hashmap[bucket][index][1] = value
class MyLinkedList(object):
def get(self, key):
""" def __init__(self):
Returns the value to which the specified key is mapped, or -1 if this map """
contains no mapping for the key Initialize your data structure here.
:type key: int """
:rtype: int self.list = []
"""
bucket, index = self.key_index(key) def get(self, index):
return -1 if index == -1 else self.hashmap[bucket][index][1] """
Get the value of the index-th node in the linked list. If the index is invalid,
def remove(self, key): return -1.
""" :type index: int
Removes the mapping of the specified value key if this map contains a mapping for :rtype: int
the key """
:type key: int if index >= len(self.list):
:rtype: void return -1
""" return self.list[index]
bucket, index = self.key_index(key)
if index != -1: def addAtHead(self, val):
del self.hashmap[bucket][index] """
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. :type head: Node
:type val: int :type insertVal: int
:rtype: void :rtype: Node
""" """
self.list = [val] + self.list if not head: # list is empty, return node referencing
itself
def addAtTail(self, val): new_node = Node(insertVal, None)
""" new_node.next = new_node
Append a node of value val to the last element of the linked list. return new_node
:type val: int
:rtype: void def insert_after(node):
""" node.next = Node(insertVal, node.next)
self.list.append(val)
original_head = head # save so can be returned and can tell if
def addAtIndex(self, index, val): full cycle traversed
"""
Add a node of value val before the index-th node in the linked list. while True:
If index equals to the length of linked list, the node will be appended to the
end of linked list. if head.next.val > head.val: # next node is increasing
If index is greater than the length, the node will not be inserted. if insertVal >= head.val and insertVal <= head.next.val: # check if
:type index: int insertVal between node vals
:type val: int break
:rtype: void elif head.next.val < head.val: # next node is decreasing
""" if insertVal >= head.val or insertVal <= head.next.val: # check if
if index > len(self.list): insertVal beyond range of cycles
return break
self.list.insert(index, val) elif head.next == original_head: # all nodes
same value , insert anywhere
def deleteAtIndex(self, index): break
"""
Delete the index-th node in the linked list, if the index is valid. head = head.next
:type index: int
:rtype: void insert_after(head)
""" return (original_head)
if index >= len(self.list):
return
del self.list[index]
# python_1_to_1000/709_To_Lower_Case.py

# python_1_to_1000/708_Insert_into_a_Cyclic_Sorted_List.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/to-lower-case/
# Implement function ToLowerCase() that has a string parameter str, and returns the same
# https://leetcode.com/problems/insert-into-a-cyclic-sorted-list/ string in lowercase.
# Given a node from a cyclic linked list which is sorted in ascending order, write a
function to insert a value into # For each upper case character, convert to lower case by adding the ASCII code
# the list such that it remains a cyclic sorted list. The given node can be a reference difference between lower and
to any single node in the list, # upper cases.
# and may not be necessarily the smallest value in the cyclic list. # Time - O(n)
# If there are multiple suitable places for insertion, you may choose any place to insert # Space - O(n)
the new value.
# After the insertion, the cyclic list should remain sorted. class Solution(object):
# If the list is empty (i.e., given node is null), you should create a new single cyclic def toLowerCase(self, str):
list and return the reference """
# to that single node. Otherwise, you should return the original given node. :type str: str
:rtype: str
# Iterate along the list handling 3 cases, """
# 1) Increasing node values - insert if insertVal is between (inclusive) node and diff = ord("a") - ord("A")
node.next
# 2) Decreasing node values - insert if insertVal is >= node.val or <= node.next.val, return "".join(chr(ord(c) + diff) if "A" <= c <= "Z" else c for c in str)
i.e. beyond the range
# 3) Same node values - insert if revisiting start, since all nodes have the same value
# Time - O(n) # python_1_to_1000/710_Random_Pick_with_Blacklist.py - h
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def insert(self, head, insertVal):
""" # https://leetcode.com/problems/random-pick-with-blacklist/

# Given a blacklist B containing unique integers from [0, N), write a function to return :type grid: List[List[int]]
a uniform random integer :rtype: int
# from [0, N) which is NOT in B. """
# Optimize it such that it minimizes the call to system’s Math.random(). if not grid or not grid[0]:
return 0
# Create a mapping so that all of the allowed numbers are together. Make the first part
of the array the allowed rows, cols = len(grid), len(grid[0])
# whitelist. Find a list of all white numbers that are not in the first part of the
array. For each black number that def BFS(base_r, base_c):
# is in the first part of the array, map it to a white number that is not in the first
part. grid[base_r][base_c] = 0 # set base cell as visited
# Pick random indices from the length of the whitelist. If a number is mapped from black queue = [(base_r, base_c)]
to white, return its mapping for r, c in queue: # queue is extended during iteration
# else the number is not blacklisted so return it.
# Time - O(n) for init, O(1) for pick. for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
# Space - O(n) new_r, new_c = r + dr, c + dc

from random import randint if 0 <= new_r < rows and 0 <= new_c < cols and grid[new_r][new_c] ==
1:
class Solution(object): grid[new_r][new_c] = 0
queue.append((new_r, new_c))
def __init__(self, N, blacklist):
""" canonical = [] # create a standard representation of the island
:type N: int
:type blacklist: List[int] for _ in range(4): # make 8 shapes by rotation and rotation +
""" reflection
self.white = N - len(blacklist) # number of non-black numbers queue = [(c, -r) for r, c in queue] # clockwise 90 degree rotation
blacklist = set(blacklist) min_r, min_c = min([r for r, _ in queue]), min([c for _, c in queue])
self.white_to_move = [i for i in range(self.white, N) if i not in blacklist] canonical = max(canonical, sorted([(r - min_r, c - min_c) for r, c in
self.mapping = {b : self.white_to_move.pop() for b in blacklist if b < queue]))
self.white}
reflected = [(r, -c) for r, c in queue] # reflect
def pick(self): min_r, min_c = min([r for r, _ in reflected]), min([c for _, c in
""" reflected])
:rtype: int canonical = max(canonical, sorted([(r - min_r, c - min_c) for r, c in
""" reflected]))
rand = randint(0, self.white - 1)
return self.mapping[rand] if rand in self.mapping else rand return tuple(canonical) # tuple allows hashing in set

islands = set()
# python_1_to_1000/711_Number_of_Distinct_Islands_II.py - h for r in range(rows):
for c in range(cols):
_author_ = 'jake' if grid[r][c] == 0:
_project_ = 'leetcode' continue
islands.add(BFS(r, c))
# https://leetcode.com/problems/number-of-distinct-islands-ii/
# Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's return len(islands)
(representing land) connected
# 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are
surrounded by water. # python_1_to_1000/712_Minimum_ASCII_Delete_Sum_for_Two_Strings.py - m
# Count the number of distinct islands. An island is considered to be the same as another
if they have the same _author_ = 'jake'
# shape, or have the same shape after rotation (90, 180, or 270 degrees only) or _project_ = 'leetcode'
reflection (left/right direction
# or up/down direction). # 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
# Iterate over array, for each cell with 1 breadth-first search to find a list of all strings equal.
connected cells forming an island.
# For each of the 8 possible rotations and rotation + reflections, manipulate the island # Dynamic programming, similar to edit distance. Find the cost of equalising each prefix
then translate so the top left of s1 and prefix of s2.
# cell of the enclosing rectangle is (0, 0). Sort the resulting cells and set the # If either prefix is empty then all characters of the other prefix must be deleted. If
canonical representation to be the the final chars of prefixes are
# maximum. # equal then cost is same as for both prefixes without final chars. Else minumum cost of
# Time - O(mn * log(mn)) deleting a char from either
# Space - O(mn) # prefix.
# Time - O(mn)
class Solution(object): # Space - O(n)
def numDistinctIslands2(self, grid):
""" class Solution(object):
def minimumDeleteSum(self, s1, s2):
""" # python_1_to_1000/714_Best_Time_to_Buy_and_Sell_Stock_with_Transaction_Fee.py - m
:type s1: str
:type s2: str _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
dp = [0] # for empty prefix of s1 # https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
for c in s2: # cost is all chars in prefix of s2 # You are given an array of integers prices, for which the i-th element is the price of a
dp.append(dp[-1] + ord(c)) given stock on day i; and a
# non-negative integer fee representing a transaction fee.
for i in range(len(s1)): # You may complete as many transactions as you like, but you need to pay the transaction
fee for each sale.
new_dp = [dp[0] + ord(s1[i])] # empty prefix of s2, cost is sum of chars in # You may not buy more than 1 share of a stock at a time (ie. you must sell the stock
prefix of s1 share before you buy again.)
# Return the maximum profit you can make.
for j in range(len(s2)):
if s1[i] == s2[j]: # delete neither character # Track most cash after buying at current price and most cash after selling at current
new_dp.append(dp[j]) price. Most cash after buying is
else: # delete either character # higher of previous most and cash after buying here = sell - price. Most cash after
new_dp.append(min(ord(s1[i]) + dp[j + 1], ord(s2[j]) + new_dp[-1])) selling is higher of previous most
# and cash after selling here = buy + price - fee.
dp = new_dp # Time - O(n)
# Space - O(1)
return dp[-1]
class Solution(object):
def maxProfit(self, prices, fee):
# python_1_to_1000/713_Subarray_Product_Less_Than_K.py - m """
:type prices: List[int]
_author_ = 'jake' :type fee: int
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/subarray-product-less-than-k/ buy, sell = float("-inf"), 0
# You are given an array of positive integers nums. Count and print the number of
(contiguous) subarrays where the for price in prices:
# product of all the elements in the subarray is less than k. buy, sell = max(buy, sell - price), max(sell, buy + price - fee)

# Maintain a window with product <= k. For each num, add to window product. While window return sell
contains some nums and
# product is too large, remove from window start. Increment result by window length since
each subarray ending at end
# is valid. If start > end then product == 1. # python_1_to_1000/715_Range_Module.py - h
# Time - O(n)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def numSubarrayProductLessThanK(self, nums, k): # https://leetcode.com/problems/range-module/
""" # A Range Module is a module that tracks ranges of numbers. Your task is to design and
:type nums: List[int] implement the following
:type k: int # interfaces in an efficient manner.
:rtype: int # addRange(int left, int right) Adds the half-open interval [left, right), tracking
""" every real number in that
subarrays = 0 # interval. Adding an interval that partially overlaps with currently tracked numbers
start = 0 # index of window start should add any numbers in
product = 1 # current product # the interval [left, right) that are not already tracked.
# queryRange(int left, int right) Returns true if and only if every real number in the
for end, num in enumerate(nums): interval [left, right) is
# currently being tracked.
product *= num # removeRange(int left, int right) Stops tracking every real number currently being
tracked in the interval
while product >= k and start <= end: # remove from window if product too # [left, right).
large and window non-zero
product //= nums[start] # Maintain a list of points and whether all values from a point to the next are in a
start += 1 range. Binary search to find
# the insertion point of a new range. Query by checking all points between left and right
subarrays += end - start + 1 # if start = end + 1 then nothing are in range.
added # Time - O(n) to add and remove, O(log n) to query
# Space - O(n)
return subarrays
import bisect

class RangeModule(object): class MaxStack(object):


def __init__(self): def __init__(self):
self.points = [0, 10 ** 9] # list of points (not necessarily always ends of """
ranges after mergers) initialize your data structure here.
self.in_range = [False, False] # is ends[i] and points to ends[i + 1] in a range """
self.stack = [(float("-inf"), float("-inf"))] # pairs of (num, max_num)
def addRange(self, left, right, add=True):
""" def push(self, x):
:type left: int """
:type right: int :type x: int
:rtype: void :rtype: void
""" """
i = bisect.bisect_left(self.points, left) # find insertion index of left in list self.stack.append((x, max(x, self.stack[-1][1])))
of points
if self.points[i] != left: # if left does not exist in the list already def pop(self):
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 :rtype: int
required when inserting right """
x, _ = self.stack.pop()
j = bisect.bisect_left(self.points, right) return x
if self.points[j] != right:
self.points.insert(j, right) def top(self):
self.in_range.insert(j, self.in_range[j - 1]) # right is in_range if point """
before it was :rtype: int
"""
self.points[i:j] = [left] # consolidate points i to (but excluding) j return self.stack[-1][0]
self.in_range[i:j] = [add] # consolidate in_range
def peekMax(self):
def queryRange(self, left, right): """
""" :rtype: int
:type left: int """
:type right: int return self.stack[-1][1]
:rtype: bool
""" def popMax(self):
i = bisect.bisect(self.points, left) - 1 # if left is a point then we include """
it, else get the previous point :rtype: int
j = bisect.bisect_left(self.points, right) # ony check points before right """
return all(self.in_range[i:j]) temp = []
x, target = self.stack.pop()
def removeRange(self, left, right):
""" while x != target:
:type left: int temp.append(x)
:type right: int x, _ = self.stack.pop()
:rtype: void
""" for x in reversed(temp):
self.addRange(left, right, False) self.push(x)

return target
# python_1_to_1000/716_Max_Stack.py - h

_author_ = 'jake' # python_1_to_1000/717_1-bit_and_2-bit_Characters.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/max-stack/ _project_ = 'leetcode'
# Design a max stack that supports push, pop, top, peekMax and popMax.
# push(x) -- Push element x onto stack. # https://leetcode.com/problems/1-bit-and-2-bit-characters/
# pop() -- Remove the element on top of the stack and return it. # We have two special characters. The first character can be represented by one bit 0.
# top() -- Get the element on the top. # The second character can be represented by two bits (10 or 11).
# peekMax() -- Retrieve the maximum element in the stack. # Now given a string represented by several bits. Return whether the last character must
# popMax() -- Retrieve the maximum element in the stack, and remove it. If you find more be a one-bit character or not.
than one maximum elements, # The given string will always end with a zero.
# only remove the top-most one.
# If the first bit is 1, it must be a 2-bit character so move 2 spaces forwards. Else
# Stack contains tuples of (element, max element in stack). To popMax, pop until an move one space forwards.
element equal to max is seen. Then # Time - O(n)
# push back all elements before max in reverse order. # Space - O(1)
# Time - O(1) for all operations apart from O(n) for popMax
# Space - O(n) class Solution(object):
def isOneBitCharacter(self, bits):
""" # Sort nums. Binary search for the smallest difference that has at least k pairs. For mid
:type bits: List[int] difference, check if
:rtype: bool # k or more piars have that difference. If so, reduce hihg to mid, else increase low to
""" mid + 1.
i = 0 # Count number of differences <= diff by iterating over nums and for each num finding the
while i < len(bits) - 1: first other num <= diff.
# Time - O(n log n)
if bits[i] == 1: # Space - O(n)
i += 1
i += 1 class Solution(object):
def smallestDistancePair(self, nums, k):
return i == len(bits) - 1 """
:type nums: List[int]
:type k: int
# python_1_to_1000/718_Maximum_Length_of_Repeated_Subarray.py - m :rtype: int
"""
_author_ = 'jake'
_project_ = 'leetcode' def k_pair_distances(diff):
count, j = 0, 0
# https://leetcode.com/problems/maximum-length-of-repeated-subarray/ for i, num in enumerate(nums): # each starting num
# Given two integer arrays A and B, return the maximum length of an subarray that appears while num - nums[j] > diff: # increase j until distance <= diff
in both arrays. j += 1
count += i - j # add all pairs
# Binary search for the largest length of a mutual subarray in A and B. return count >= k
# Time - O(log(min(m, n)) * (m + n) * min(m, n))
# Space - O(m**2) nums.sort()
left, right = 0, nums[-1] - nums[0]
class Solution(object):
""" while left < right:
:type A: List[int]
:type B: List[int] mid = (left + right) // 2
:rtype: int
""" if k_pair_distances(mid): # at least k pairs with difference of mid, search
def findLength(self, A, B): mid and lower
right = mid
def mutual_subarray(length): else:
# make all subarrays of length in A left = mid + 1 # less than k pairs with distance mid, search
subarrays = set(tuple(A[i:i + length]) above mid
for i in range(len(A) - length + 1))
# check if any of same length are also in B return left
return any(tuple(B[j:j + length]) in subarrays
for j in range(len(B) - length + 1))

low, high = 0, min(len(A), len(B)) + 1


# python_1_to_1000/720_Longest_Word_in_Dictionary.py - m
while low < high: # search for smallest length with no mutual subarray
_author_ = 'jake'
mid = (low + high) // 2 _project_ = 'leetcode'

if mutual_subarray(mid): # mid has mutual subarray so search above mid # https://leetcode.com/problems/longest-word-in-dictionary/


low = mid + 1 # Given a list of strings words representing an English Dictionary, find the longest word
else: in words that can be built
high = mid # mid does not have mutual subarray so search mid # one character at a time by other words in words. If there is more than one possible
and below answer, return the longest word
# with the smallest lexicographical order.
return low - 1 # If there is no answer, return the empty string.

# Map lengths of words to sets of words with the same length.


# For each word longer than the current candidates (initially only the empty string is a
# python_1_to_1000/719_Find_K-th_Smallest_Pair_Distance.py - h candidate), add word to
# next_candidates if its prefix without final letter is already a candidate.
_author_ = 'jake' # Alternatively, for each word better than the longest word already found, check all
_project_ = 'leetcode' prefixes in set of dictionary.
# Time - O(nk) for n words of maximum length k
# https://leetcode.com/problems/find-k-th-smallest-pair-distance/ # Space - O(nk)
# Given an integer array, return the k-th smallest distance among all the pairs. The
distance of a pair (A, B) is from collections import defaultdict
# defined as the absolute difference between A and B.

class Solution(object):
def longestWord(self, words): for i, account in enumerate(accounts):
""" for email in account[1:]:
:type words: List[str] email_to_account[email].append(i)
:rtype: str
""" result = []
length_to_words = defaultdict(set) visited = [False for _ in range(len(accounts))]

for word in words: # map word lengths to set of words def dfs(i):
length_to_words[len(word)].add(word) emails = set()
if visited[i]:
candidates = {""} # initial candidate is the empty string return emails
length = 0 # length of current candidates visited[i] = True
for email in accounts[i][1:]:
while True: emails.add(email)
for account in email_to_account[email]:
next_candidates = set() emails |= dfs(account) # union existing and new emails
return emails
for longer_word in length_to_words[length + 1]: # check if each longer word
can be built from any candidate for i, account in enumerate(accounts):
if longer_word[:-1] in candidates: emails = dfs(i)
next_candidates.add(longer_word) if emails:
result.append([account[0]] + sorted(list(emails)))
if not next_candidates:
return sorted(list(candidates))[0] # sort to return return result
lexicographically lowest

length += 1
candidates = next_candidates

# python_1_to_1000/722_Remove_Comments.py - m
# python_1_to_1000/721_Accounts_Merge.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/remove-comments/
# https://leetcode.com/problems/accounts-merge/ # Given a C++ program, remove comments from it. The program source is an array where
# Given a list accounts, each element accounts[i] is a list of strings, where the first source[i] is the i-th line of the
element accounts[i][0] is a # source code. This represents the result of splitting the original source code string by
# name, and the rest of the elements are emails representing emails of the account. the newline character \n.
# Now, we would like to merge these accounts. Two accounts definitely belong to the same # In C++, there are two types of comments, line comments, and block comments.
person if there is some email # The string // denotes a line comment, which represents that it and rest of the
# that is common to both accounts. Note that even if two accounts have the same name, characters to the right of it in the
they may belong to different # same line should be ignored.
# people as people could have the same name. A person can have any number of accounts # The string /* denotes a block comment, which represents that all characters until the
initially, but all of their next (non-overlapping)
# accounts definitely have the same name. # occurrence of */ should be ignored. (Here, occurrences happen in reading order: line by
# After merging the accounts, return the accounts in the following format: the first line from left to right.)
element of each account is the # To be clear, the string /*/ does not yet end the block comment, as the ending would be
# name, and the rest of the elements are emails in sorted order. The accounts themselves overlapping the beginning.
can be returned in any order. # The first effective comment takes precedence over others: if the string // occurs in a
block comment, it is ignored.
# Create mapping from email to list of accounts with that email. For each account dfs to # Similarly, if the string /* occurs in a line or block comment, it is also ignored.
visit the accounts of its # If a certain line of code is empty after removing comments, you must not output that
# emails recursively. line: each string in the answer
# Time - O(n log n) where n is total number of emails. Each email visited once, then list # list will be non-empty.
sorted. # There will be no control characters, single quote, or double quote characters. For
# Space - O(n) example,
# source = "string s = "/* Not a comment. */";" will not be a test case. (Also, nothing
from collections import defaultdict else such as defines or macros
# will interfere with the comments.)
class Solution(object): # It is guaranteed that every open block comment will eventually be closed, so /* outside
def accountsMerge(self, accounts): of a line or block comment
""" # always starts a new comment.
:type accounts: List[List[str]] # Finally, implicit newline characters can be deleted by block comments. Please see the
:rtype: List[List[str]] examples below for details.
""" # After removing the comments from the source code, return the source code in the same
email_to_account = defaultdict(list) # email to list of account indices format.
containing that email
# Iterate over text, checking the string of the next 2 chars. Set comment_block according will drop outside the
to opening and closing # top boundary.)
# comments. At end of line, if not in a comment_block then add to result. # After the above steps, there may exist more candies that can be crushed. If so, you
# Time - O(n), total number of chars need to repeat the above steps.
# Space - O(n) # If there does not exist more candies that can be crushed (ie. the board is stable),
then return the current board.
class Solution(object): # You need to perform the above rules until the board becomes stable, then return the
def removeComments(self, source): current board.
"""
:type source: List[str] # Iterate over board setting to_crush for rows or columns of 3 identical (but not empty)
:rtype: List[str] candies. If nothing found,
""" # return board. For each column, create a new empty column and fill from bottom up with
removed = [] candies that are not crushed.
comment_block = False # Time - O((mn)**2), mn per cycle with mn // 3 max cycles.
new_line = [] # Space - O(mn)

for line in source: class Solution(object):


i = 0 def candyCrush(self, board):
"""
while i < len(line): :type board: List[List[int]]
:rtype: List[List[int]]
test = line[i:i + 2] """
if not comment_block and test == "/*": # do not skip if in block to rows, cols = len(board), len(board[0])
handle "/*/"
comment_block = True # else skip 2 chars while True:
i += 2
elif not comment_block and test == "//": # skip to end of line stable = True
i = len(line) to_crush = [[False for _ in range(cols)] for _ in range(rows)] # flag
elif comment_block and test == "*/": # end block, skip 2 chars which cells to crush
comment_block = False
i += 2 for c in range(cols):
elif comment_block: # ignore char for r in range(rows):
i += 1 # check vertical
else: # add char to result if r < rows - 2 and board[r][c] == board[r + 1][c] == board[r + 2][c]
new_line.append(line[i]) and board[r][c] != 0:
i += 1 to_crush[r][c] = to_crush[r + 1][c] = to_crush[r + 2][c] = True
stable = False
if not comment_block and new_line: # newline char is not # check horizontal
commented out if c < cols - 2 and board[r][c] == board[r][c + 1] == board[r][c + 2]
removed.append("".join(new_line)) and board[r][c] != 0:
new_line = [] to_crush[r][c] = to_crush[r][c + 1] = to_crush[r][c + 2] = True
stable = False
if new_line: # add final text
removed.append("".join(new_line)) if stable: # nothing to crush
return removed return board

for c in range(cols):
new_col = [0 for _ in range(rows)]
new_r = rows - 1
# python_1_to_1000/723_Candy_Crush.py - m for r in range(rows - 1, -1, -1): # from bottom upwards
if not to_crush[r][c]:
_author_ = 'jake' new_col[new_r] = board[r][c] # add to new_col if not crushed
_project_ = 'leetcode' new_r -= 1 # decrement new_r
if new_r != -1: # column has changed so update
# https://leetcode.com/problems/candy-crush/ board
# This question is about implementing a basic elimination algorithm for Candy Crush. for r in range(rows):
# Given a 2D integer array board representing the grid of candy, different positive board[r][c] = new_col[r]
integers board[i][j] represent
# 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 # python_1_to_1000/724_Find_Pivot_Index.py
# stable state by crushing candies according to the following rules:
# If three or more candies of the same type are adjacent vertically or horizontally, _author_ = 'jake'
"crush" them all at the same _project_ = 'leetcode'
# time - these positions become empty.
# After crushing all candies simultaneously, if an empty space on the board has candies # https://leetcode.com/problems/find-pivot-index/
on top of itself, then these # Given an array of integers nums, write a method that returns the "pivot" index of this
# candies will drop until they hit a candy or bottom at the same time. (No new candies array.

# We define the pivot index as the index where the sum of the numbers to the left of the :type k: int
index is equal to the sum of :rtype: List[ListNode]
# the numbers to the right of the index. """
# If no such index exists, we should return -1. If there are multiple pivot indexes, you node, count = root, 0
should return the left-most while node: # find length of linked list
# pivot index. count += 1
node = node.next
# Iterate over nums, maintaining sums of left and right sides relative to pivot. Remove
num from right, then check part_length, odd_parts = divmod(count, k)
# whether sides have equal sums, then add num to left. result = []
# Time - O(n) prev, node = None, root
# Space - O(1)
for _ in range(k):
class Solution(object):
def pivotIndex(self, nums): required = part_length # required length of this part
""" if odd_parts > 0:
:type nums: List[int] odd_parts -= 1
:rtype: int required += 1
"""
left, right = 0, sum(nums) # sums of left and right arrays relative to result.append(node)
pivot for _ in range(required):
prev, node = node, node.next
for i, num in enumerate(nums): if prev: # break link to next part
prev.next = None
right -= num
return result
if left == right:
return i

left += num # doing this last handles i == 0 better than # python_1_to_1000/726_Number_of_Atoms.py - h


adding previous before check
_author_ = 'jake'
return -1 _project_ = 'leetcode'

# https://leetcode.com/problems/number-of-atoms/
# python_1_to_1000/725_Split_Linked_List_in_Parts.py - m # Given a chemical formula (given as a string), return the count of each atom.
# An atomic element always starts with an uppercase character, then zero or more
_author_ = 'jake' lowercase letters,
_project_ = 'leetcode' # representing the name.
# 1 or more digits representing the count of that element may follow if the count is
# https://leetcode.com/problems/split-linked-list-in-parts/ greater than 1. If the count
# Given a (singly) linked list with head node root, write a function to split the linked # is 1, no digits will follow. For example, H2O and H2O2 are possible, but H1O2 is
list into k consecutive impossible.
# linked list "parts". # Two formulas concatenated together produce another formula. For example, H2O2He3Mg4 is
# The length of each part should be as equal as possible: no two parts should have a size also a formula.
differing by more than 1. # A formula placed in parentheses, and a count (optionally added) is also a formula. For
# This may lead to some parts being null. example, (H2O2)
# The parts should be in order of occurrence in the input list, and parts occurring # and (H2O2)3 are formulas.
earlier should always have a # Given a formula, output the count of all elements as a string in the following form:
# size greater than or equal parts occurring later. the first name
# Return a List of ListNode's representing the linked list parts that are formed. # (in sorted order), followed by its count (if that count is more than 1), followed by
# Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ] the second name
# (in sorted order), followed by its count (if that count is more than 1), and so on.
# Count length and calculate part lengths. Each part is previous root, count required
nodes then break link to # Iterate over formula. If start of a new element, add previous element to counts. If
# next part. bracket, find counts from
# Time - O(n) # within bracket and multiply by number after bracket.
# Space - O(1) # Time - O(n)
# Space - O(n)
# Definition for singly-linked list.
class ListNode(object): from collections import defaultdict
def __init__(self, x):
self.val = x class Solution(object):
self.next = None def countOfAtoms(self, formula):
"""
class Solution(object): :type formula: str
def splitListToParts(self, root, k): :rtype: str
""" """
:type root: ListNode
def count_atoms(start):
counts = defaultdict(int) class Solution(object):
element = None def minWindow(self, S, T):
element_count = 0 """
i = start :type S: str
:type T: str
while i < len(formula): :rtype: str
c = formula[i] """
next_in_s = [None for _ in range(len(S))] # next_in_s[i][j] is the next
if "A" <= c <= "Z": # start new atom occurrence of letter j in S[i + 1:]
if element: # add previous atom to counts next_by_letter = [-1 for _ in range(26)] # or -1 if not found
counts[element] += element_count if element_count != 0 else 1 for i in range(len(S) - 1, -1, -1):
element_count = 0 next_in_s[i] = next_by_letter[:]
element = c next_by_letter[ord(S[i]) - ord("a")] = i

elif "a" <= c <= "z": # add to name of current atom # matches is a list of windows [i, j] where i is the index in S matching the
element += c first char of T
# and j is the index matching the current char of T
elif "0" <= c <= "9": # increase count of current atom matches = [[i, i] for i, c in enumerate(S) if c == T[0]]
element_count = int(c) + (element_count * 10 if element_count != 0 if not matches:
else 0) return ""

elif c == "(": for i, c in enumerate(T[1:], 1): # iterate over T


bracket_count, i = count_atoms(i + 1) # get atom counts until
closing bracket new_matches = []
bracket_multiplier = 0
while i + 1 < len(formula) and "0" <= formula[i + 1] <= "9": # for s_start, s_last in matches: # for each window
multiplier of bracket s_next = next_in_s[s_last][ord(c) - ord("a")] # find the next index in
bracket_multiplier = bracket_multiplier * 10 + int(formula[i + S matching c
1]) if s_next != -1:
i += 1 new_matches.append([s_start, s_next]) # update matches if c is
for el, num in bracket_count.items(): found
counts[el] += num * (bracket_multiplier if bracket_multiplier > 0
else 1) if not new_matches:
return ""
else: # closing bracket matches = new_matches
if element: # add final element to counts
counts[element] += element_count if element_count != 0 else 1 # return the shortest window
return [counts, i] start, end = min(matches, key = lambda i, j: j - i)
return S[start:end + 1]
i += 1

return [counts, i] # python_1_to_1000/728_Self_Dividing_Numbers.py

formula = "(" + formula + ")" _author_ = 'jake'


counts = count_atoms(0)[0] _project_ = 'leetcode'
return "".join([atom + (str(count) if count > 1 else "") for atom, count in
sorted(counts.items())]) # https://leetcode.com/problems/self-dividing-numbers/
# A self-dividing number is a number that is divisible by every digit it contains.
# For example, 128 is a self-dividing number because 128 % 1 == 0, 128 % 2 == 0, and 128
# python_1_to_1000/727_Minimum_Window_Substring.py - h % 8 == 0.
# Also, a self-dividing number is not allowed to contain the digit zero.
_author_ = 'jake' # Given a lower and upper number bound, output a list of every possible self dividing
_project_ = 'leetcode' number, including the bounds.

# https://leetcode.com/problems/minimum-window-subsequence/ # Test each numbers. Repeatedly divide by 10 ro extract each digit, rejecting if original
# Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a number is not divisible by
subsequence of W. # digit or digit is zero.
# If there is no such window in S that covers all characters in T, return the empty # Time - O(n log k) where there are n numbers in range and k is the maximum number
string "". If there are multiple # Space - O(n log n)
# such minimum-length windows, return the one with the left-most starting index.
class Solution(object):
# Find all indices in S matching the first letter of T and create a list of windows. For def selfDividingNumbers(self, left, right):
each letter of T, for each """
# window find the next letter of S that matches the letter and extend the window. If the :type left: int
letter is not found, remove :type right: int
# the window. Return the smallest window. :rtype: List[int]
# Time - O(mn), worst case when all letters are identical means len(S) windows """
# Space - O(m)

def is_self_dividing(num): _author_ = 'jake'


_project_ = 'leetcode'
copy = num # make a copy since original num is also required
# https://leetcode.com/problems/count-different-palindromic-subsequences/
while copy > 0: # Given a string S, find the number of different non-empty palindromic subsequences in S,
and return that number
copy, digit = divmod(copy, 10) # modulo 10^9 + 7.
if digit == 0 or num % digit != 0: # A subsequence of a string S is obtained by deleting 0 or more characters from S.
return False # 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
return True which A_i != B_i.

return [num for num in range(left, right + 1) if is_self_dividing(num)] # 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
# python_1_to_1000/729_My_Calendar_I.py - m number of palindromes of the
# form x_x where _ is any other palindrome. Memoise results.
_author_ = 'jake' # Time - O(n**2)
_project_ = 'leetcode' # Space - O(n**2)

# https://leetcode.com/problems/my-calendar-i/ class Solution(object):


# Implement a MyCalendar class to store your events. A new event can be added if adding def countPalindromicSubsequences(self, S):
the event will not cause a """
# double booking. :type S: str
# Your class will have the method, book(int start, int end). Formally, this represents a :rtype: int
booking on the half open """
# interval [start, end), the range of real numbers x such that start <= x < end. NUM_LETTERS, MOD = 4, 10 ** 9 + 7
# A double booking happens when two events have some non-empty intersection (ie., there S = [ord(c) - ord("a") for c in S] # convert chars to integers
is some time that is common to memo = {}
# both events.)
# For each call to the method MyCalendar.book, return true if the event can be added to last_indices = [-1 for _ in range(NUM_LETTERS)]
the calendar successfully prev_index_letter = [None for _ in
# without causing a double booking. Otherwise, return false and do not add the event to range(len(S))] # prev_index_letter[i][j] is
the calendar. the previous occurrence of letter j
# Your class will be called like this: MyCalendar cal = new MyCalendar(); for i in range(len(S)): # at or before index i
MyCalendar.book(start, end) last_indices[S[i]] = i
prev_index_letter[i] = last_indices[:]
# Create sorted list of events. Binary search for position to insert new event and do so
if no overlap with previous last_indices = [-1 for _ in range(NUM_LETTERS)]
# or next events. next_index_letter = [None for _ in range(len(S))] # next_index_letter[i][j] is
# Time - O(n**2) the next occurrence of letter j
# Space - O(n) for i in range(len(S) - 1, -1, -1): # at or after index i
last_indices[S[i]] = i
import bisect next_index_letter[i] = last_indices[:]

class MyCalendar(object): def helper(i, j): # solution for S[i:j + 1]

def __init__(self): if (i, j) in memo:


self.bookings = [(float("-inf"), float("-inf")), (float("inf"), float("inf"))] return memo[(i, j)]

def book(self, start, end): count = 1 # empty string plus single


""" characters
:type start: int
:type end: int for letter in range(4):
:rtype: bool next_index = next_index_letter[i][letter] # first occurrence of letter
""" after or including index i
i = bisect.bisect_left(self.bookings, (start, end)) prev_index = prev_index_letter[j][letter] # next occurrence of letter
before or including index j
if end > self.bookings[i][0]:
return False if i <= next_index <= j: # single character
if start < self.bookings[i - 1][1]: palindromes
return False count += 1

self.bookings.insert(i, (start, end)) if next_index != -1 and prev_index != -1 and prev_index > next_index: #
return True string contains x_x
count += helper(next_index + 1, prev_index - 1)

# python_1_to_1000/730_Count_Different_Palindromic_Subsequences.py - h count %= MOD


memo[(i, j)] = count
return count # Your class will have one method, book(int start, int end). Formally, this represents a
booking on the half open
return helper(0, len(S) - 1) - 1 # remove empty string # interval [start, end), the range of real numbers x such that start <= x < end.
# A K-booking happens when K events have some non-empty intersection (ie., there is some
time that is common to all
# python_1_to_1000/731_My_Calendar_II.py - m # K events.)
# For each call to the method MyCalendar.book, return an integer K representing the
_author_ = 'jake' largest integer such that there
_project_ = 'leetcode' # exists a K-booking in the calendar.
# Your class will be called like this: MyCalendarThree cal = new MyCalendarThree();
# https://leetcode.com/problems/my-calendar-ii/ MyCalendarThree.book(start, end)
# Implement a MyCalendarTwo class to store your events. A new event can be added if
adding the event will not # Maintain a sorted list bookings of x values where the number of events changes. Each
# cause a triple booking. entry [x, n] represents n
# Your class will have one method, book(int start, int end). Formally, this represents a # overlapping events from point x until the next element of the bookings list.
booking on the half open # Time - O(n**2)
# interval [start, end), the range of real numbers x such that start <= x < end. # Space - O(n)
# A triple booking happens when three events have some non-empty intersection (ie., there
is some time that is common import bisect
# to all 3 events.)
# For each call to the method MyCalendar.book, return true if the event can be added to class MyCalendarThree(object):
the calendar successfully
# without causing a triple booking. Otherwise, return false and do not add the event to def __init__(self):
the calendar. self.bookings = [[float("-inf"), 0], [float("inf"), 0]] # sorted list of [x,
# Your class will be called like this: MyCalendar cal = new MyCalendar(); nb overlaps]
MyCalendar.book(start, end) self.max_booking = 0 # maximum number of
overlaps
# Create unsorted lists of double bookings and events. For a new booking, return False if
overlap with and double def book(self, start, end):
# booking. Else check for overlap with each existing interval and if so, append overlap """
to doubles. :type start: int
# List of doubles may contain overlaps but no triple booking is permitted. :type end: int
# Time - O(n**2) :rtype: int
# Space - O(n) """
i = bisect.bisect_left(self.bookings, [start, -1]) # find insertion
class MyCalendarTwo(object): index of start

def __init__(self): if self.bookings[i][0] != start: # insert if start is


self.doubles = [] # intervals with double bookings new x value
self.intervals = [] # all intervals count = self.bookings[i - 1][1]
self.bookings.insert(i, [start, count + 1])
def book(self, start, end): self.max_booking = max(self.max_booking, count + 1)
""" i += 1
:type start: int
:type end: int while end > self.bookings[i][0]: # increment all
:rtype: bool intervals before end
""" self.bookings[i][1] += 1
for i, j in self.doubles: # check overlap with existing double bookings self.max_booking = max(self.max_booking, self.bookings[i][1])
if start < j and end > i: i += 1
return False
if self.bookings[i][0] != end: # insert if end is
for i, j in self.intervals: # check overlap with existing bookings new x value
if start < j and end > i: count = self.bookings[i - 1][1]
self.doubles.append((max(start, i), min(end, j))) self.bookings.insert(i, [end, count - 1])

self.intervals.append((start, end)) # add to list of all events return self.max_booking

return True

# python_1_to_1000/732_My_Calendar_III.py - h # python_1_to_1000/733_Flood_Fill.py

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# https://leetcode.com/problems/my-calendar-iii/ # https://leetcode.com/problems/flood-fill/
# Implement a MyCalendarThree class to store your events. A new event can always be # An image is represented by a 2-D array of integers, each integer representing the pixel
added. value of the image

# (from 0 to 65535). # However, similarity is symmetric. E.g., "great" and "fine" means that "fine" and
# Given a coordinate (sr, sc) representing the starting pixel (row and column) of the "great" are similar.
flood fill, and a pixel value # Also, a word is always similar with itself.
# newColor, "flood fill" the image. # Finally, sentences can only be similar if they have the same number of words.
# To perform a "flood fill", consider the starting pixel, plus any pixels connected 4-
directionally to the starting # Create a mapping from a word to the set of similar words. Check each word of words1
# pixel of the same color as the starting pixel, plus any pixels connected 4- against the word of the same
directionally to those pixels (also with # index in words2 and vica versa. If words are same, continue.
# the same color as the starting pixel), etc. Replace the color of all of the # Else if there is no mapping between the words, return False.
aforementioned pixels with the newColor. # Time - O(m + n), len(pairs) + len(words)
# At the end, return the modified image. # Space - O(m)

# Depth-first search. Find startColor or sr, sc. If this is the same as newColor, return from collections import defaultdict
image unchanged (or else
# the while loop may not terminate). Stack contains pixels to be explored. Pop the next class Solution(object):
unexplored cell and if a def areSentencesSimilar(self, words1, words2, pairs):
# valid cell of startColor then change its colour and add neighbours to the stack. """
# Time - O(mn) :type words1: List[str]
# Space - O(mn) :type words2: List[str]
:type pairs: List[List[str]]
class Solution(object): :rtype: bool
def floodFill(self, image, sr, sc, newColor): """
""" if len(words1) != len(words2):
:type image: List[List[int]] return False
:type sr: int
:type sc: int similar = defaultdict(set)
:type newColor: int for w1, w2 in pairs:
:rtype: List[List[int]] similar[w1].add(w2) # map one way only
"""
rows, cols = len(image), len(image[0]) for w1, w2 in zip(words1, words2):

startColor = image[sr][sc] if w1 == w2: # samewords are always similar


if startColor == newColor: continue
return image
if (w1 not in similar or w2 not in similar[w1]) and (w2 not in similar or w1
stack = [(sr, sc)] not in similar[w2]):
return False
while stack:
return True
r, c = stack.pop()

if r < 0 or r >= rows or c < 0 or c >= cols:


continue # python_1_to_1000/735_Asteroid_Collision.py - m
if image[r][c] != startColor:
continue _author_ = 'jake'
_project_ = 'leetcode'
image[r][c] = newColor
for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
stack.append((r + dr, c + dc)) # https://leetcode.com/problems/asteroid-collision/
# We are given an array asteroids of integers representing asteroids in a row.
return image # 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.
# Find out the state of the asteroids after all collisions. If two asteroids meet, the
# python_1_to_1000/734_Sentence_Similarity.py smaller one will explode.
# If both are the same size, both will explode. Two asteroids moving in the same
_author_ = 'jake' direction will never meet.
_project_ = 'leetcode'
# Stack consists of a stable configuration of asteroids. For each new asteroid add to
# https://leetcode.com/problems/sentence-similarity/ stack if no collision. Else
# Given two sentences words1, words2 (each represented as an array of strings), and a # determine which to destroy. If top of stack is destroyed then repeat.
list of similar word pairs pairs, # Time - O(n)
# determine if two sentences are similar. # Space - O(n)
# For example, "great acting skills" and "fine drama talent" are similar, if the similar
word pairs are pairs = class Solution(object):
# [["great", "fine"], ["acting","drama"], ["skills","talent"]]. def asteroidCollision(self, asteroids):
# Note that the similarity relation is not transitive. For example, if "great" and "fine" """
are similar, and "fine" :type asteroids: List[int]
# and "good" are similar, "great" and "good" are not necessarily similar. :rtype: List[int]
""" # The helper function takes an index in the list of tokens and returns the value of the
stack = [] expression from that token
# until the corresponding closing bracket. It also return the index of the next token
for asteroid in asteroids: after the closing bracket.
# The helper function first removes any opening bracket from the the current token. If
while stack and stack[-1] > 0 > asteroid: # collision there is an opening bracket then
# we have moved up a level of scope, so copy all the previous variables in scope into a
if stack[-1] == -asteroid: # destroy both new dictionary.
stack.pop() # Count and remove the closing brackets.
break # Then there are 5 cases:
elif stack[-1] > -asteroid: # destroy asteroid # Integer - return its value.
break # Add - parse the next expression and subsequent expression then add them.
else: # destroy top of stack # Mult - parse the next expression and subsequent expression then multiply them them.
stack.pop() # Let - for every pair of variable / expression, map the variable to the evaluates
expression's value. The continue_let
else: # no collision between asteroid and top of stack # function determines whether this is the final expression to be returned.
stack.append(asteroid) # Variable - find its value from the mapping.
# Along with the return value we always also return the index of the next token to parse.
return stack # Before returning we pop off and discard any scopes that are removed due to closing
brackets.
# Time - O(n)
# python_1_to_1000/736_Parse_Lisp_Expression.py - h # Space - O(n**2), dictionaries may repeat the same variable

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def evaluate(self, expression):
"""
# https://leetcode.com/problems/parse-lisp-expression/ :type expression: str
# You are given a string expression representing a Lisp-like expression to return the :rtype: int
integer value of. """
# The syntax for these expressions is given as follows. tokens = expression.split(" ") # list of operators, variables and
# An expression is either an integer, a let-expression, an add-expression, a mult- integers
expression, or an assigned variable. scopes = [{}] # stack of dictionaries
# Expressions always evaluate to a single integer. (An integer could be positive or
negative.) def helper(start): # returns (value of expression, next
# A let-expression takes the form (let v1 e1 v2 e2 ... vn en expr), where let is always index to parse)
the string "let", then there
# are 1 or more pairs of alternating variables and expressions, meaning that the first if start >= len(tokens): # base case
variable v1 is assigned the return 0, start
# value of the expression e1, the second variable v2 is assigned the value of the
expression e2, and so on operator = tokens[start]
# sequentially; and then the value of this let-expression is the value of the expression if operator[0] == "(": # remove opening bracket if any
expr. operator = operator[1:]
# An add-expression takes the form (add e1 e2) where add is always the string "add", scopes.append(dict(scopes[-1])) # move up a level of scope, including all
there are always two previous variables
# expressions e1, e2, and this expression evaluates to the addition of the evaluation of
e1 and the evaluation of e2. closing_brackets = 0
# A mult-expression takes the form (mult e1 e2) where mult is always the string "mult", while operator[len(operator) - 1 - closing_brackets] == ")": # remove and
there are always two count closing brackets if any
# expressions e1, e2, and this expression evaluates to the multiplication of the closing_brackets += 1
evaluation of e1 and the evaluation if closing_brackets > 0:
# of e2. operator = operator[:-closing_brackets]
# For the purposes of this question, we will use a smaller subset of variable names. A
variable starts with a if operator.isdigit() or operator[0] == "-" and operator[1:].isdigit():
# lowercase letter, then zero or more lowercase letters or digits. Additionally for your result = int(operator), start + 1
convenience, the names
# "add", "let", or "mult" are protected and will never be used as variable names. elif operator == "add":
# Finally, there is the concept of scope. When an expression of a variable name is left, next_i = helper(start + 1)
evaluated, within the context of right, next_i = helper(next_i)
# that evaluation, the innermost scope (in terms of parentheses) is checked first for the result = (left + right, next_i)
value of that variable,
# and then outer scopes are checked sequentially. It is guaranteed that every expression elif operator == "mult":
is legal. left, next_i = helper(start + 1)
right, next_i = helper(next_i)
# Split the input by spaces. This gives a list of tokens, which may be operators, result = (left * right, next_i)
variables or integers. Brackets
# may be present before or after a token. elif operator == "let":
# Create a stack of dictionaries. The top of the stack is dictionary mapping variables to next_i = start + 1
their values in the current while continue_let(next_i):
# scope. variable = tokens[next_i]

expression, next_i = helper(next_i + 1) mapping[word] = mapping[mapping[word]] # collapse link from parent


scopes[-1][variable] = expression to grandparent
result = helper(next_i) word = mapping[word] # move up
return word
else: # operator is variable
result = (scopes[-1][operator], start + 1) if len(words1) != len(words2): # early return
return False
while closing_brackets > 0: # remove old scopes mapping = {} # map word to its parent,
closing_brackets -= 1 which maybe itself
scopes.pop()
for w1, w2 in pairs:
return result p1, p2 = find(w1), find(w2)
if p1:
# Determines whether we should continue parsing pairs of var/expression for let if p2:
operator mapping[p1] = p2 # may already be equal
def continue_let(i): # test for variable without closing else:
bracket mapping[w2] = p1 # insert mapping for w1
return "a" <= tokens[i][0] <= "z" and tokens[i][-1] != ")" else:
if p2:
return helper(0)[0] mapping[w1] = p2 # insert mapping for w2
else:
mapping[w1] = mapping[w2] = w1 # new pair separated from
other mappings
# python_1_to_1000/737_Sentence_Similarity_II.py - m
for w1, w2 in zip(words1, words2):
_author_ = 'jake'
_project_ = 'leetcode' if w1 == w2:
continue
# https://leetcode.com/problems/sentence-similarity-ii/
# Given two sentences words1, words2 (each represented as an array of strings), and a p1, p2 = find(w1), find(w2)
list of similar word pairs pairs, if not p1 or not p2 or p1 != p2: # no or different parents
# determine if two sentences are similar. return False
# For example, words1 = ["great", "acting", "skills"] and words2 = ["fine", "drama",
"talent"] are similar, if the return True
# similar word pairs are pairs = [["great", "good"], ["fine", "good"],
["acting","drama"], ["skills","talent"]].
# Note that the similarity relation is transitive. For example, if "great" and "good" are
similar, and "fine" and # python_1_to_1000/738_Monotone_Increasing_Digits.py - m
# "good" are similar, then "great" and "fine" are similar.
# Similarity is also symmetric. For example, "great" and "fine" being similar is the same _author_ = 'jake'
as "fine" and "great" _project_ = 'leetcode'
# being similar.
# Also, a word is always similar with itself. For example, the sentences words1 = # https://leetcode.com/problems/monotone-increasing-digits/
["great"], words2 = ["great"], # Given a non-negative integer N, find the largest number that is less than or equal to N
# pairs = [] are similar, even though there are no specified similar word pairs. with monotone
# Finally, sentences can only be similar if they have the same number of words. So a # increasing digits. Recall that an integer has monotone increasing digits if and only if
sentence like words1 = ["great"] each pair of adjacent
# can never be similar to words2 = ["doubleplus","good"]. # digits x and y satisfy x <= y.)

# Union-find. Create tree linking each word to its parent. Find parents of new words by # Convert input to a list of integer digits. Iterate over digits. If next digit is lower
moving up tree, collapsing than previous then move back
# links from parent to grandparent. If either word is not in tree then make its parent # along digits looking for a digit that can be decreased whilst maintaining monotone
the parent of the other word. increasing overall. When found,
# Time - O((n + p) log p ), len(words1) = n and len(pairs) = w2. p log p to create # decrease that digit and set all subsequent digits to 9 (max possible).
mapping + n log p to check. # Time - O(n)
# Space - O(n) # Space - O(n)

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


def areSentencesSimilarTwo(self, words1, words2, pairs): def monotoneIncreasingDigits(self, N):
""" """
:type words1: List[str] :type N: int
:type words2: List[str] :rtype: int
:type pairs: List[List[str]] """
:rtype: bool s = [int(c) for c in str(N)] # make list of digits
"""
def find(word): i = 0
if word not in mapping: while i + 1 < len(s):
return None
while mapping[word] != word: if s[i + 1] < s[i]: # next digit is decreasing
# Given an array nums of integers, you can perform operations on the array.
while i > 0 and s[i] - 1 < s[i - 1]: # move back until s[i] can be # In each operation, you pick any nums[i] and delete it to earn nums[i] points.
decremented # After, you must delete every element equal to nums[i] - 1 or nums[i] + 1.
i -= 1 # You start with 0 points. Return the maximum number of points you can earn by applying
such operations.
s[i] -= 1 # decrement
s[i + 1:] = [9] * (len(s) - i - 1) # all else set to 9 # Create a sorted list of nums and their frequencies. Iterate over the list, calculating
the max points if a num is
result = 0 # used and the max if it is not used. If not previous num or previous is not num - 1 then
for val in s: we can choose the max of
result = result * 10 + val # used and not_used for the new not_sed, addind the points from this num for the new
return result used. If previous is num - 1
# then new used must be not_used + points from num. Again, not_sed chan chosse max of
else: previous used and previous
i += 1 # not_used.
# Time - O(n log n)
return N # N is monotone increasing # Space - O(n)

from collections import Counter


# python_1_to_1000/739_Daily_Temperatures.py - m
class Solution(object):
_author_ = 'jake' def deleteAndEarn(self, nums):
_project_ = 'leetcode' """
:type nums: List[int]
# https://leetcode.com/problems/daily-temperatures/ :rtype: int
# Given a list of daily temperatures, produce a list that, for each day in the input, """
tells you how many days you freq = Counter(nums)
# would have to wait until a warmer temperature. If there is no future day for which this pairs = [(num, count) for num, count in freq.items()]
is possible, put 0 instead. pairs.sort()
# For example, given the list temperatures = [73, 74, 75, 71, 69, 72, 76, 73], your
output should be used, not_used = 0, 0
# [1, 1, 4, 2, 1, 1, 0, 0]
for i, (num, count) in enumerate(pairs):
# Stack contains previous temperatures that do not have a higher temperature, hence is
descending. Iterate over if i == 0 or pairs[i - 1][0] != num - 1: # no previous noum or not num - 1
# temperatures, popping off all lower temperatures and updating their results. Then add not_used = max(used, not_used) # choose max
new temperature and its used = num * count + not_used # add point from this num
# index to stack. else:
# Time - O(n) used, not_used = num * count + not_used, max(used, not_used)
# Space - O(n)
return max(used, not_used)
class Solution(object):
def dailyTemperatures(self, temperatures):
"""
:type temperatures: List[int] # python_1_to_1000/741_Cherry_Pickup.py - h
:rtype: List[int]
""" _author_ = 'jake'
result = [0 for _ in range(len(temperatures))] _project_ = 'leetcode'

stack = [] # https://leetcode.com/problems/cherry-pickup/
# In a N x N grid representing a field of cherries, each cell is one of three possible
for i, temp in enumerate(temperatures): integers.
# 0 means the cell is empty, so you can pass through;
while stack and stack[-1][0] < temp: # pop and set result for all lower # 1 means the cell contains a cherry, that you can pick up and pass through;
previous temperatures # -1 means the cell contains a thorn that blocks your way.
_, prev_i = stack.pop() # Your task is to collect maximum number of cherries possible by following the rules
result[prev_i] = i - prev_i below:
# Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down
stack.append((temp, i)) through valid path cells
# (cells with value 0 or 1);
return result # After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path
cells;
# When passing through a path cell containing a cherry, you pick it up and the cell
# python_1_to_1000/740_Delete_and_Earn.py - m becomes an empty cell (0);
# If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be
_author_ = 'jake' collected.
_project_ = 'leetcode'
# Instead of one person traversing there and back, consider two persons traversing
# https://leetcode.com/problems/delete-and-earn/ simultaneously.

# The column of the second person is fixed by the position of the first person (which # Space - O(n)
determines the number of steps
# taken) and the row of the second person, since both have taken the same number of class Solution(object):
steps. def findClosestLeaf(self, root, k):
# Top-down dynamic programming with 3 degrees of freedom. There are 4 cases of each """
person moving down or across. :type root: TreeNode
# Time - O(n**3) :type k: int
# Space - O(n**3) :rtype: int
"""
class Solution(object): nearest_leaves = {0: (float("inf"), 0)} # key is node.val, value is (distance to
def cherryPickup(self, grid): leaf, leaf.val)
"""
:type grid: List[List[int]] def closest_down(node): # create mapping for closes leaf node via
:rtype: int subtrees
"""
n = len(grid) if not node:
memo = {} return (float("inf"), 0)

def helper(r1, c1, r2): if not node.left and not node.right: # node is a leaf
result = (0, node.val)
c2 = r1 + c1 - r2 else:
left_dist, left_nearest = closest_down(node.left)
if r1 == n or c1 == n or r2 == n or c2 == n: # out of bounds right_dist, right_nearest = closest_down(node.right)
return float("-inf") if left_dist <= right_dist: # closest leaf is via left subtree
if grid[r1][c1] == -1 or grid[r2][c2] == -1: # either person is on a thorn result = (left_dist + 1, left_nearest)
return float("-inf") else:
result = (right_dist + 1, right_nearest)
if r1 == n - 1 and c1 == n - 1: # both paths at end cell
return grid[n - 1][n - 1] nearest_leaves[node.val] = result
return result
if (r1, c1, r2) in memo:
return memo[(r1, c1, r2)] def closest(node, parent_val): # update the mapping for nodes with
closer leaves via parents
result = grid[r1][c1] # cherry from first person
if r2 != r1 or c2 != c1: # if people not in same if not node:
position return
result += grid[r2][c2] # add cherry from second
person if 1 + nearest_leaves[parent_val][0] < nearest_leaves[node.val][0]: #
closer leaf via parent
result += max(helper(r1 + 1, c1, r2 + 1), helper(r1, c1 + 1, r2), nearest_leaves[node.val] = (1 + nearest_leaves[parent_val][0],
helper(r1 + 1, c1, r2), helper(r1, c1 + 1, r2 + 1)) nearest_leaves[parent_val][1])

memo[(r1, c1, r2)] = result closest(node.left, node.val)


return result closest(node.right, node.val)

return max(0, helper(0, 0, 0)) # convert -inf (no solution) closest_down(root)


to zero closest(root, 0)
return nearest_leaves[k][1]

# python_1_to_1000/743_Network_Delay_Time.py - m
# python_1_to_1000/742_Closest_Leaf_in_a_Binary_Tree.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/network-delay-time/
# https://leetcode.com/problems/closest-leaf-in-a-binary-tree/ # There are N network nodes, labelled 1 to N.
# Given a binary tree where every node has a unique value, and a target key k, find the # Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is
value of the nearest leaf node the source node, v is the
# to target k in the tree. Here, nearest to a leaf means the least number of edges # target node, and w is the time it takes for a signal to travel from source to target.
travelled on the binary tree to # Now, we send a signal from a certain node K. How long will it take for all nodes to
# reach any leaf of the tree. Also, a node is called a leaf if it has no children. receive the signal?
# There exists some node in the given binary tree for which node.val == k. # If it is impossible, return -1.

# Bottom-up recursion through the tree to find the closest leaf to every node when moving # Initialise the best time to reach each node as infinity apart from 0 for node K. Create
downwards to subtrees. a set of all nodes, find the
# The recurse through the tree again, updating closest leaves for cases that best path is # node in the set with the smallest time to reach and remove it from the set, since this
via parent. time cannot be improved by
# Time - O(n) # going via another node with a greater time to reach. Update the times to reach all
neighbours. Repeat removing :rtype: str
# closest node until all nodes have been tested or closest node cannot bee reached by """
other nodes. left, right = 0, len(letters) # initial search space is first letter to beyond
# Time - O(n**2 + e) where n is nb nodes and e is nb edges last letter (inclusive)
# Space - O(n + e)
while left < right: # stop if left == right
class Solution(object):
def networkDelayTime(self, times, N, K): mid = (left + right) // 2
"""
:type times: List[List[int]] if target >= letters[mid]: # search RHS excluding mid
:type N: int left = mid + 1
:type K: int else: # mid could be next greater letter
:rtype: int right = mid
"""
best_times = [float("inf") for _ in range(N + 1)] # best time for signal to letters.append(letters[0]) # handle wrap around
reach any node return letters[left]
best_times[K] = 0

network = [[] for _ in range(N + 1)] # map nodes to list of (nbor, # python_1_to_1000/745_Prefix_and_Suffix_Search.py - h
time)
for u, v, w in times: _author_ = 'jake'
network[u].append((v, w)) _project_ = 'leetcode'

nodes = {n for n in range(1, N + 1)} # set of all nodes to be # https://leetcode.com/problems/prefix-and-suffix-search/


tested # Given many words, words[i] has weight i.
# Design a class WordFilter that supports one function, WordFilter.f(String prefix,
while nodes: String suffix).
# It will return the word with given prefix and suffix with maximum weight. If no word
best_time = float("inf") exists, return -1.
for node in nodes: # find the remaining node
with smallest time # Create a trie to store each word in its usual order (forwards) and a trie to store each
if best_times[node] < best_time: word backwards.
best_time = best_times[node] # Find the sets of all words that match prexis and suffix from their respective tries.
next_node = node Take the max weight from the
# set intersection.
if best_time == float("inf"): # best_node has not been # Time - O(n) to __init__ where n is the total umber of chars in all words. O(p + s + k)
reached where p = len(prefix),
return -1 # s = len(suffix), k = number of words.
nodes.remove(next_node) # cannot improve time to # Space - O(n)
reach this node
class WordFilter(object):
for nbor, time in network[next_node]: # update times to reach
neighbours def __init__(self, words):
best_times[nbor] = min(best_times[nbor], best_time + time) """
:type words: List[str]
return max(best_times[1:]) # ignore best_times[0] """
self.prefix_root = [set(), [None for _ in range(26)]] # trie node is set of
words and list of next nodes
# python_1_to_1000/744_Find_Smallest_Letter_Greater_Than_Target.py self.suffix_root = [set(), [None for _ in range(26)]] # for each char
self.weights = {} # map word to weight
_author_ = 'jake'
_project_ = 'leetcode' def insert(word, forwards): # insert a word into a
trie
# https://leetcode.com/problems/find-smallest-letter-greater-than-target/ if forwards:
# Given a list of sorted characters letters containing only lowercase letters, and given node = self.prefix_root
a target letter target, iterate_word = word
# find the smallest element in the list that is larger than the given target. else:
# Letters also wrap around. For example, if the target is target = 'z' and letters = node = self.suffix_root
['a', 'b'], the answer is 'a'. iterate_word = word[::-1]

# Binary search for the next greater letter. node[0].add(word)


# Time - O(log n) for c in iterate_word:
# Space - O(1) if not node[1][ord(c) - ord("a")]: # create a new node of
None
class Solution(object): node[1][ord(c) - ord("a")] = [set(), [None for _ in range(26)]]
def nextGreatestLetter(self, letters, target): node = node[1][ord(c) - ord("a")]
""" node[0].add(word)
:type letters: List[str]
:type target: str for weight, word in enumerate(words):

self.weights[word] = weight # python_1_to_1000/747_Largest_Number_At_Least_Twice_of_Others.py


insert(word, True)
insert(word, False) _author_ = 'jake'
_project_ = 'leetcode'
def f(self, prefix, suffix):
""" # https://leetcode.com/problems/largest-number-at-least-twice-of-others/
:type prefix: str # In a given integer array nums, there is always exactly one largest element.
:type suffix: str # Find whether the largest element in the array is at least twice as much as every other
:rtype: int number in the array.
""" # If it is, return the index of the largest element, otherwise return -1.

def find_words(word, forwards): # Iterate over nums, tracking the index of the largest num seen and the second largest
if forwards: num seen.
node = self.prefix_root # Time - O(n)
iterate_word = word # Space - O(1)
else:
node = self.suffix_root class Solution(object):
iterate_word = word[::-1] def dominantIndex(self, nums):
"""
for c in iterate_word: :type nums: List[int]
node = node[1][ord(c) - ord("a")] :rtype: int
if not node: """
return -1 # early return if cannot match whole prefix or suffix first_i = 0 # index of largest num
return node[0] second = 0 # second largest num

prefix_matches = find_words(prefix, True) for i, num in enumerate(nums[1:], 1):


suffix_matches = find_words(suffix, False)
if prefix_matches == -1 or suffix_matches == -1: if num >= nums[first_i]:
return -1 first_i, second = i, nums[first_i] # update first_i and second
elif num > second:
matches = prefix_matches & suffix_matches second = num
weight = -1
for match in matches: return first_i if nums[first_i] >= 2 * second else -1 # check if first is at
weight = max(weight, self.weights[match]) least twice second
return weight

# python_1_to_1000/748_Shortest_Completing_Word.py
# python_1_to_1000/746_Min_Cost_Climbing_Stairs.py
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/shortest-completing-word/
# https://leetcode.com/problems/min-cost-climbing-stairs/ # Find the minimum length word from a given dictionary words, which has all the letters
# On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed). from the string licensePlate.
# Once you pay the cost, you can either climb one or two steps. You need to find minimum # Such a word is said to complete the given string licensePlate
cost to reach the top of # Here, for letters we ignore case. For example, "P" on the licensePlate still matches
# the floor, and you can either start from the step with index 0, or the step with index "p" on the word.
1. # It is guaranteed an answer exists. If there are multiple answers, return the one that
occurs first in the array.
# Dynamic programming. Track the cost of reaching each step and the previous step. The # The license plate might have the same letter occurring multiple times. For example,
cost of reaching any step is given a licensePlate of "PP",
# the cost of that step plus the lower cost of reaching the precious 2 steps. # the word "pair" does not complete the licensePlate, but the word "supper" does.
# Time - O(n)
# Space - O(1) # Count frequency fo each letter in licensePlate. Sort words in ascending order of
length. For each word, count the
class Solution(object): # frequency of each letter. If every letter in licensePlate has the same number or more
def minCostClimbingStairs(self, cost): copies in a word then return
""" # that word. Although sorting has worse time complexity, it is practically faster for the
:type cost: List[int] test cases than scanning the
:rtype: int # unsorted words.
""" # Time - O(kn log n) to sort for n log n comparisons, each taking O(k) for n strings of
prev, step = cost[:2] length k.
# Space - O(kn)
for c in cost[2:]:
prev, step = step, c + min(prev, step) from collections import Counter

return min(prev, step) # finish at last or penultimate step class Solution(object):


def shortestCompletingWord(self, licensePlate, words):
"""
:type licensePlate: str return
:type words: List[str] visited.add((r, c))
:rtype: str
""" for dr, dc in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
letters = [c.lower() for c in licensePlate if c > "9"] # remove digits and space r1, c1 = r + dr, c + dc
freq = Counter(letters) if r1 < 0 or r1 >= rows or c1 < 0 or c1 >= cols:
continue
words.sort(key=lambda x: len(x)) if grid[r1][c1] == 2: # ignore, already contained
continue
for word in words: if grid[r1][c1] == 0: # add to nbors and increase wall count
nbors.add((r1, c1))
if len(word) < len(letters): # ignore words that are walls[0] += 1
too short else:
continue get_nbors(r1, c1) # recurse

word_freq = Counter(word) def contain_region(r, c): # set all cells in a region to 2 to indicate
contained
for c, count in freq.items(): if r < 0 or r >= rows or c < 0 or c >= cols:
if c not in word_freq or word_freq[c] < count: return
break if grid[r][c] != 1:
else: return
return word grid[r][c] = 2
for dr, dc in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
contain_region(r + dr, c + dc)
# python_1_to_1000/749_Contain_Virus.py - h
while True:
_author_ = 'jake' regions = []
_project_ = 'leetcode' visited = set()

# https://leetcode.com/problems/contain-virus/ for r in range(rows):


# A virus is spreading rapidly, and your task is to quarantine the infected area by for c in range(cols):
installing walls. # for each viral region, find its neighbouring empty cells and walls
# The world is modeled as a 2-D array of cells, where 0 represents uninfected cells, and required
1 represents cells if (r, c) not in visited and grid[r][c] == 1:
# contaminated with the virus. A wall (and only one wall) can be installed between any nbors, walls = set(), [0]
two 4-directionally adjacent get_nbors(r, c)
# cells, on the shared boundary. regions.append([(r, c), set(nbors), walls[0]])
# Every night, the virus spreads to all neighboring cells in all four directions unless
blocked by a wall. regions.sort(key = lambda x: -len(x[1])) # sort by most neighbours
# Resources are limited. Each day, you can install walls around only one region -- the
affected area (continuous if not regions or len(regions[0][1]) == 0: # all contained or fully
# block of infected cells) that threatens the most uninfected cells the following night. infected
There will never be a tie. return used_walls
# Can you save the day? If so, what is the number of walls required? If not, and the
world becomes fully infected, used_walls += regions[0][2] # contain first region
# return the number of walls used. contain_region(regions[0][0][0], regions[0][0][1])

# Iterate over grid, finding regions of virus with dfs. For each region find its empty for _, expansion, _ in regions[1:]: # infect neighbours of other
neighbours and walls required regions
# to contain it. Contain the region with most neighbours by setting grid cells to 2 and for r, c in expansion:
increment wall count. grid[r][c] = 1
# 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
# Space - O(mn)
# python_1_to_1000/750_Number_Of_Corner_Rectangles.py - m
class Solution(object):
def containVirus(self, grid): _author_ = 'jake'
""" _project_ = 'leetcode'
:type grid: List[List[int]]
:rtype: int # 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.
rows, cols = len(grid), len(grid[0]) # A corner rectangle is 4 distinct 1s on the grid that form an axis-aligned rectangle.
used_walls = 0 # Note that only the corners need to have the value 1. Also, all four 1s used must be
distinct.
def get_nbors(r, c): # find all neighbouring empty cells and number of walls
to contain a region # For each row, find the set of column indices that are 1 in the grid. Then for each pair
if (r, c) in visited: of rows, find the common

# columns and caclulate the numbe of rectangles as each uniqie pair. mask = 33 - min((ip_num & -ip_num).bit_length(), n.bit_length())
# Time - O(m**2 n)
# Space - O(mn) results.append(num_to_ip(ip_num) + "/" + str(mask))
ip_num += 1 << (32 - mask)
class Solution(object): n -= 1 << (32 - mask)
def countCornerRectangles(self, grid):
""" return results
:type grid: List[List[int]]
:rtype: int
""" # python_1_to_1000/752_Open_the_Lock.py - m
rows, cols = len(grid), len(grid[0])
cols_by_row = [] _author_ = 'jake'
_project_ = 'leetcode'
for r in range(rows):
cols_by_row.append(set((c for c in range(cols) if grid[r][c]))) # https://leetcode.com/problems/open-the-lock/
# You have a lock in front of you with 4 circular wheels.
rectangles = 0 # Each wheel has 10 slots: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'.
# The wheels can rotate freely and wrap around: for example we can turn '9' to be '0', or
for high_row in range(1, rows): '0' to be '9'.
for low_row in range(high_row): # Each move consists of turning one wheel one slot.
common_cols = len(cols_by_row[high_row] & cols_by_row[low_row]) # The lock initially starts at '0000', a string representing the state of the 4 wheels.
if common_cols >= 2: # You are given a list of deadends dead ends, meaning if the lock displays any of these
rectangles += common_cols * (common_cols - 1) // 2 codes, the wheels of the lock
# will stop turning and you will be unable to open it.
return rectangles # Given a target representing the value of the wheels that will unlock the lock, return
the minimum total number of
# turns required to open the lock, or -1 if it is impossible.
# python_1_to_1000/751_IP_to_CIDR.py - m
# Bidirectional breadth-first search. From the starting position, move one wheel to all
_author_ = 'jake' next positions. Expand frontier
_project_ = 'leetcode' # until target is found, ignoring deadends and already seen combinations. Swap queue with
target after every iteration
# https://leetcode.com/problems/ip-to-cidr/ # to limit the size of the frontier.
# Given a start IP address ip and a number of ips we need to cover n, return a # Time - O(1), limit of 10000 possible combinations
representation of the range as a list # Space - O(1)
# (of smallest possible length) of CIDR blocks.
# A CIDR block is a string consisting of an IP, followed by a slash, and then the prefix class Solution(object):
length. def openLock(self, deadends, target):
# For example: "123.45.67.89/20". Prefix length "20" represents the number of common """
prefix bits in the specified range. :type deadends: List[str]
:type target: str
# Convert IP to an integer and convert back when adding to results. Add to the result a :rtype: int
block of addresses. The block """
# either covers all of n or all addresses until the least significant bit of the ip queue, target = {"0000"}, {target}
address changes. visited = set()
# Time - O(n) deadends = set(deadends)
# Space - O(1) steps = 0

class Solution(object): def shift(combo): # find all combinations that can be reached by moving one
def ipToCIDR(self, ip, n): wheel
""" shifts = set()
:type ip: str for i, c in enumerate(combo): # for each wheel
:type n: int shifted = (int(c) + 1) % 10 # move up
:rtype: List[str] shifts.add(combo[:i] + str(shifted) + combo[i + 1:])
""" shifted = (int(c) - 1) % 10 # move down
results = [] shifts.add(combo[:i] + str(shifted) + combo[i + 1:])
return shifts
def num_to_ip(num): # convert and integer to an IP address
ip = [] while queue:
for _ in range(4):
num, byte = divmod(num, 256) if target & queue: # intersection between queue and target
ip.append(str(byte)) return steps
return ".".join(ip[::-1])
new_queue = set()
ip_num = 0 steps += 1
for byte in ip.split("."): # convert the IP address to an integer
ip_num = ip_num * 256 + int(byte) for combo in queue:

while n > 0: if combo in visited or combo in deadends:


continue # ignore combinations seen before or not allowed _author_ = 'jake'
visited.add(combo) _project_ = 'leetcode'
new_queue |= shift(combo) # add all shifted combinations
# https://leetcode.com/problems/reach-a-number/
queue, target = target, new_queue # update queue and swap queue with target # You are standing at position 0 on an infinite number line. There is a goal at position
target.
return -1 # On each move, you can either go left or right. During the n-th move (starting from 1),
you take n steps.
# Return the minimum number of steps required to reach the destination.

# python_1_to_1000/753_Cracking_the_Safe.py - h # Take steps until we reach or go past target. position = steps * (steps + 1) // 2.
Invert this and solve quadratic
_author_ = 'jake' # polynomial to find the number of steps to reach or exceed position. If we are at exact
_project_ = 'leetcode' target or an even number
# of steps away then can reach target by inverting the sign of some moves. Else take one
# https://leetcode.com/problems/cracking-the-safe/ or two more steps until we
# There is a box protected by a password. The password is n digits, where each letter can # are an even number of moves from target.
be one of the first # Time - O(1)
# k digits 0, 1, ..., k-1. # Space - O(1)
# You can keep inputting the password, the password will automatically be matched against
the last n digits entered. import math
# For example, assuming the password is "345", I can open it when I type "012345", but I
enter a total of 6 digits. class Solution(object):
# Please return any string of minimum length that is guaranteed to open the box after the def reachNumber(self, target):
entire string is inputted. """
:type target: int
# Create a directed graph where each node is the last n-1 digits of the pattern used and :rtype: int
each node has k outgoing edges """
# each labeled by a digit such that node + edge represents a pattern (i.e. a password target = abs(target) # symmetry of positive and negative solutions
attempt).
# We need to find a Euler cycle that visits every edge of this graph. steps = int(math.ceil((math.sqrt(1 + 8 * target) - 1) / 2)) # ceil to round up
# From a node, take each edge in turn and if pattern has not been seen already then target -= steps * (steps + 1) // 2 # find remaining
explore from the next node with distance after steps
# depth first search until we reach a dead end, which must be on the current cycle since
each node has the same if target % 2 == 0: # includes target == 0
# number of incoming and outgoing edges. Record the digit of the last edge in the result, return steps
then back-up within the cycle,
# taking alternative paths. target += steps + 1 # take one more step
# Time - O(n * k**n) since k**n patterns each of length n if target % 2 == 0:
# Space - O(n * k**n) return steps + 1

class Solution(object): return steps + 2 # take one more step, must now be an even distance from
""" target
:type n: int
:type k: int
:rtype: str
""" # python_1_to_1000/755_Pour_Water.py - m
def crackSafe(self, n, k):
_author_ = 'jake'
seen = set() _project_ = 'leetcode'
digits = [str(i) for i in range(k)]
result = [] # https://leetcode.com/problems/pour-water/
# We are given an elevation map, heights[i] representing the height of the terrain at
def dfs(node): that index. The width at each
for x in digits: # index is 1. After V units of water fall at index K, how much water is at each index?
pattern = node + x # Water first drops at index K and rests on top of the highest terrain or water at that
if pattern not in seen: index. Then, it flows
seen.add(pattern) # according to the following rules:
dfs(pattern[1:]) # If the droplet would eventually fall by moving left, then move left.
result.append(x) # Otherwise, if the droplet would eventually fall by moving right, then move right.
# Otherwise, rise at it's current position.
dfs("0" * (n - 1)) # Here, "eventually fall" means that the droplet will eventually be at a lower level if
return "".join(result) + "0" * (n - 1) it moves in that direction.
# Also, "level" means the height of the terrain plus any water in that column.
# 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
# python_1_to_1000/754_Reach_a_Number.py - m has to be in exactly one block.

# For each drop, move left until the next index is higher, recording the lowest index. If first search for the next block.
the drop has fallen, update # If a completed row has one block, we have found the top of the pyramid. If a row has
# heights. Else follow the same procedure on the right. If the drop has not fallen on the one less block than the previous
right, put it at index K. # row then start the next row. Else find a list of possible next blocks. If there are
# Time - O(Vn) where len(heights) == n none then we cannot find any
# Space - O(n) # solution. If any of the next blocks allows us to fill the pyramid then there is a
solution, else there is not.
class Solution(object): # Time - O(k ** (n**2)) where k is the size of the alphabet and n == len(bottom). There
def pourWater(self, heights, V, K): are O(n**2) blocks to be added.
""" # Space - O(n**2)
:type heights: List[int]
:type V: int from collections import defaultdict
:type K: int
:rtype: List[int] class Solution(object):
""" def pyramidTransition(self, bottom, allowed):
heights = [float("inf")] + heights + [float("inf")] # pad before and after """
with infinite walls :type bottom: str
K += 1 :type allowed: List[str]
:rtype: bool
while V > 0: # iterate over drops """
V -= 1 triangles = defaultdict(list)
for triple in allowed:
i = K triangles[triple[:-1]].append(triple[-1])
lowest, lowest_i = heights[K], K
while heights[i - 1] <= lowest: # move left if same or def helper(prev, current): # inputs are the previous row and the
lower (partial) current row
i -= 1
if heights[i] < lowest: # update lowest seen if len(prev) == 1: # finished pyramid
lowest, lowest_i = heights[i], i return True
n = len(current)
if lowest < heights[K]: # fallen on left, no need if n == len(prev) - 1: # start a new row
to look right return helper(current, "")
heights[lowest_i] += 1
continue colours = triangles[prev[n:n + 2]] # allowed next blocks
if not colours:
i = K return False
lowest, lowest_i = heights[K], K
while heights[i + 1] <= lowest: for colour in colours:
i += 1 if helper(prev, current + colour):
if heights[i] < lowest: return True
lowest, lowest_i = heights[i], i return False

if lowest < heights[K]: return helper(bottom, "")


heights[lowest_i] += 1
else:
heights[K] += 1 # python_1_to_1000/757_Set_Intersection_Size_At_Least_Two.py - h

return heights[1:-1] _author_ = 'jake'


_project_ = 'leetcode'

# https://leetcode.com/problems/set-intersection-size-at-least-two/
# python_1_to_1000/756_Pyramid_Transition_Matrix.py - m # An integer interval [a, b] (for integers a < b) is a set of all consecutive integers
from a to b, including a and b.
_author_ = 'jake' # Find the minimum size of a set S such that for every integer interval A in intervals,
_project_ = 'leetcode' the intersection of S with A
# has size at least 2.
# https://leetcode.com/problems/pyramid-transition-matrix/
# We are stacking blocks to form a pyramid. Each block has a color which is a one letter # Sort intervals by ascending end point. Iterate over intervals. If the current interval
string, like `'Z'`. starts after the previous
# For every block of color `C` we place not in the bottom row, we are placing it on top # intersection points then add to the intersection the end and end - 1. These are the
of a left block of color `A` maximum values in order to
# and right block of color `B`. We are allowed to place the block there only if `(A, B, # maximise overlaps with future intervals, which all end at the same or greater values.
C)` is an allowed triple. Or else if the second largest
# We start with a bottom row of bottom, represented as a single string. We also start # value in intersection is outside the interval, add the interval end point. Or else the
with a list of allowed triples last 2 values from intersection
# allowed. Each allowed triple is represented as a string of length 3. # are included in interval so no action required.
# Return true if we can build the pyramid all the way to the top, otherwise false. # Time - O(n log n)
# Space - O(n)
# Create a mapping from a pair of blocks to a list allowed blocks on top. Then depth-
class Solution(object): tag
def intersectionSizeTwo(self, intervals): result.append("</b>")
""" result.append(S[i])
:type intervals: List[List[int]]
:rtype: int result = result[1:-1] # remove extra chars
""" return "".join(result)
intervals.sort(key=lambda x: x[1])
intersection = []
# python_1_to_1000/759_Employee_Free_Time.py - h
for start, end in intervals:
_author_ = 'jake'
if not intersection or start > intersection[-1]: _project_ = 'leetcode'
intersection.append(end - 1)
intersection.append(end) # https://leetcode.com/problems/employee-free-time/
elif start > intersection[-2]: # We are given a list schedule of employees, which represents the working time for each
intersection.append(end) employee.
# else previous 2 points in intersection are already in interval # Each employee has a list of non-overlapping Intervals, and these intervals are in
sorted order.
return len(intersection) # Return the list of finite intervals representing common, positive-length free time for
all employees,
# also in sorted order.

# python_1_to_1000/758_Bold_Words_in_String.py - m # Maintain a heap of the next meeting start time for every employee. Pop the next meeting
start time off the heap and
_author_ = 'jake' # replace it with the next interval from that employee (if not the last interval). If
_project_ = 'leetcode' start time is after last end time,
# there is free time so add interval to result. Update the last end time to end of this
# https://leetcode.com/problems/bold-words-in-string/ meeting if later than current
# Given a set of keywords words and a string S, make all appearances of all keywords in S # last end time.
bold. Any letters between # Time - O(m log n) where n is the number of employees and m is the number of meetings.
# <b> and </b> tags become bold. # Space - O(n)
# The returned string should use the least number of tags possible, and of course the
tags should form a import heapq
# valid combination.
# Definition for an interval.
# For each word, attempt to match with string. If match found, flag that matched chars class Interval(object):
should be bold then check again def __init__(self, s=0, e=0):
# if word matches next starting position in S until word does not match S. self.start = s
# Then iterate over S creating the result by inserting opening and closing tags amongst self.end = e
chars when flag changes to or
# from bold. class Solution(object):
# Time - O(n * m) for S of length n and m chars in all words. def employeeFreeTime(self, schedule):
# Space - O(n) """
:type schedule: List[List[Interval]]
class Solution(object): :rtype: List[Interval]
def boldWords(self, words, S): """
""" employees = len(schedule)
:type words: List[str] next_start_times = [(schedule[i][0].start, 0, i) for i in range(employees)]
:type S: str heapq.heapify(next_start_times) # heap of (start time, interval
:rtype: str index, employee)
""" last_end_time = next_start_times[0][0] # time when last meeting ended
S = "#" + S + "#" # add unused letter to avoid special result = []
cases for first and last chars
bold = [False for _ in range(len(S))] # flag which chars should be bold while next_start_times:

for word in words: interval_start_time, interval, employee = heapq.heappop(next_start_times)


i = S.find(word, 1) if interval + 1 < len(schedule[employee]): # add next interval for this
while i != -1: # while the word is found in S employee to heap
bold[i:i + len(word)] = [True] * len(word) # set bold flags heapq.heappush(next_start_times, (schedule[employee][interval + 1].start,
i = S.find(word, i + 1) # search again for word in S from i + 1 interval + 1, employee))

result = [] if interval_start_time > last_end_time: # free time between next start


time and last end time
for i in range(len(S)): result.append(Interval(last_end_time, interval_start_time))
last_end_time = max(last_end_time, schedule[employee][interval].end) #
if bold[i] and not bold[i - 1]: # change from not bold to bold, opening update last end time
tag
result.append("<b>") return result
elif not bold[i] and bold[i - 1]: # change from bold to not vold, closing

def makeLargestSpecial(self, S):


"""
# python_1_to_1000/760_Find_Anagram_Mappings.py :type S: str
:rtype: str
_author_ = 'jake' """
_project_ = 'leetcode' specials = []

# https://leetcode.com/problems/find-anagram-mappings/ if not S:
# Given two lists on integers A and B where B is an anagram of A. return ""
# 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. balance, start = 0, 0
# These lists A and B may contain duplicates. If there are multiple answers, output any for i, c in enumerate(S):
of them.
balance += 1 if c == "1" else -1
# Create a mapping from integers in b to their indices in b. If an integer is duplicated if balance == 0:
then the mapping if to the specials.append("1" + self.makeLargestSpecial(S[start + 1:i]) + "0")
# last index. For each num in a, look up its index in the mapping of indices in b. start = i + 1
# Time - O(n)
# Space - O(n) specials.sort(reverse = True)
return "".join(specials)
class Solution(object):
def anagramMappings(self, A, B):
"""
:type A: List[int] # python_1_to_1000/762_Prime_Number_of_Set_Bits_in_Binary_Representation.py
:type B: List[int]
:rtype: List[int] _author_ = 'jake'
""" _project_ = 'leetcode'
B_to_int = {}
for i, b in enumerate(B): # https://leetcode.com/problems/prime-number-of-set-bits-in-binary-representation/
B_to_int[b] = i # Given two integers L and R, find the count of numbers in the range [L, R] (inclusive)
having a prime number of set
result = [] # bits in their binary representation.
for a in A: # The number of set bits an integer has is the number of 1s present when written in
result.append(B_to_int[a]) 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
# python_1_to_1000/761_Special_Binary_String.py - h # Space - O(log n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def countPrimeSetBits(self, L, R):
"""
# https://leetcode.com/problems/special-binary-string/ :type L: int
# Special binary strings are binary strings with the following two properties: :type R: int
# The number of 0's is equal to the number of 1's. :rtype: int
# Every prefix of the binary string has at least as many 1's as 0's. """
# Given a special string S, a move consists of choosing two consecutive, non-empty, result = 0
special substrings of S, and primes = {2, 3, 5, 7, 11, 13, 17, 19}
# swapping them. (Two strings are consecutive if the last character of the first string
is exactly one index before the for i in range(L, R + 1):
# first character of the second string.) if bin(i).count("1") in primes:
# At the end of any number of moves, what is the lexicographically largest resulting result += 1
string possible?
return result
# Create a list of all optimal special strings, sort in order of most starting 1s and
join.
# To create an optimal special string, iterate over S finding the point there the next # python_1_to_1000/763_Partition_Labels.py - m
balance of 1s minus 0s falls to
# zero. Remove the leading 1 and trailing 0 and recurse on the middle part. Middle part _author_ = 'jake'
is a special string because _project_ = 'leetcode'
# 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 # https://leetcode.com/problems/partition-labels/
# processed, so every prefix of middle has as many 1s as 0s, which is the definition of a # A string S of lowercase letters is given. We want to partition this string into as many
special string. parts as possible so that
# Time - O(n**2) # each letter appears in at most one part, and return a list of integers representing the
# Space - O(n) size of these parts.

class Solution(object): # Map each character to its last index in S. Iterate over S, for each character update
the end of the partition to be distance = 0 if (r, c) in mines else distance + 1 # update distance
# the later of current end and last appearance of the character. If we reach the end of since last mine
the partition, add it to distances[r][c] = distance
# result and start new partition at next index.
# Time - O(n) distance = 0
# Space - O(n) for c in range(N - 1, -1, -1): # reverse direction
over rows
class Solution(object): distance = 0 if (r, c) in mines else distance + 1
def partitionLabels(self, S): distances[r][c] = min(distances[r][c], distance)
"""
:type S: str for c in range(N):
:rtype: List[int] distance = 0
""" for r in range(N):
last = {c: i for i, c in enumerate(S)} distance = 0 if (r, c) in mines else distance + 1
result = [] distances[r][c] = min(distances[r][c], distance)

start, end = 0, 0 # current partition distance = 0


for i, c in enumerate(S): for r in range(N - 1, -1, -1):
distance = 0 if (r, c) in mines else distance + 1
end = max(end, last[c]) distances[r][c] = min(distances[r][c], distance)
if i == end: # last appearance of all charcters in partition plus = max(plus, distances[r][c])
result.append(end - start + 1)
start = i + 1 # start new partition. end will be updated on next return plus
iteration.

return result # python_1_to_1000/765_Couples_Holding_Hands.py - h

_author_ = 'jake'
# python_1_to_1000/764_Largest_Plus_Sign.py - m _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/couples-holding-hands/


_project_ = 'leetcode' # 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/largest-plus-sign/ # that every couple is sitting side by side. A swap consists of choosing any two people,
# In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except those cells in then they stand up and
the given list mines which # switch seats.
# are 0. What is the largest axis-aligned plus sign of 1s contained in the grid? # The people and seats are represented by an integer from 0 to 2N-1, the couples are
# Return the order of the plus sign. If there is none, return 0. numbered in order, the first
# An "axis-aligned plus sign of 1s of order k" has some center grid[x][y] = 1 along with # couple being (0, 1), the second couple being (2, 3), and so on with the last couple
4 arms of length k-1 going up, being (2N-2, 2N-1).
# down, left, and right, and made of 1s. This is demonstrated in the diagrams below. Note # The couples' initial seating is given by row[i] being the value of the person who is
that there could be 0s or 1s initially sitting in i-th seat.
# beyond the arms of the plus sign, only the relevant area of the plus sign is checked
for 1s. # Create an undirected graph where nodes are seats (holding 2 people) and edges are links
to the seats of the partners
# Iterate over the array by row in both directions and by column in both directions (4 # of the people on the seat. Each node has 2 undirected edges. Walk the graph until a
times in total). cycle of length k is found. It
# In each direction, find the longest sequence of cells without a mine. Result for each # then takes k - 1 swaps so put couples together.
cell is the the shortest # Time - O(n)
# distance in any of the 4 directions. # Space - O(n)
# Time - O(N**2)
# Space - O(N**2) class Solution(object):
def minSwapsCouples(self, row):
class Solution(object): """
def orderOfLargestPlusSign(self, N, mines): :type row: List[int]
""" :rtype: int
:type N: int """
:type mines: List[List[int]] n = len(row) // 2 # number of couples
:rtype: int
""" couple_to_location = [[] for _ in range(n)] # map a couple index to current
mines = {(r, c) for r, c in mines} # convert to set for O(1) seating indices of the couple
lookup for i, person in enumerate(row): # where seats hold 2 people
distances = [[0 for _ in range(N)] for _ in range(N)] # min distance to mine in together
each of the 4 directions couple_to_location[person // 2].append(i // 2)
plus = 0
print(couple_to_location)
for r in range(N): adjacency = [[] for _ in range(n)] # map seat index to the seat
distance = 0 indices of the partners of the
for c in range(N): for a, b in couple_to_location: # 2 people at that seat index

adjacency[a].append(b) to result if is different


adjacency[b].append(a) # from the previous letter and add back to heap with decremented count. Else this is the
only letter, no solution is
print(adjacency) # possible. Else use the next most frequent letter then add the most frequent letter
swaps = n # for each cycle of length x, back.
require x - 1 swaps # Time - O(n log k) where len(S) == n and k is the size of the alphabet.
# so swaps = n - number of cycles # Space - O(n)
for start in range(n):
import heapq
if not adjacency[start]: from collections import Counter
continue
class Solution(object):
swaps -= 1 # found a cycle def reorganizeString(self, S):
a = start # starting seat index """
b = adjacency[start].pop() # seat index of a partner :type S: str
:rtype: str
while b != start: """
adjacency[b].remove(a) # remove link in other direction freq = Counter(S)
a, b = b, adjacency[b].pop() # move to next seat if any(count > (len(S) + 1) // 2 for count in freq.values()): # some letter is
too frequent
return swaps return ""

heap = [(-count, letter) for letter, count in freq.items()] # max heap of


count
# python_1_to_1000/766_Toeplitz_Matrix.py heapq.heapify(heap)

_author_ = 'jake' result = []


_project_ = 'leetcode'
def add_letter(letter, neg_count):
# https://leetcode.com/problems/toeplitz-matrix/ result.append(letter)
# A matrix is Toeplitz if every diagonal from top-left to bottom-right has the same neg_count += 1
element. if neg_count != 0: # remove from hep
# Now given an M x N matrix, return True if and only if the matrix is Toeplitz. if no remaining count
heapq.heappush(heap, (neg_count, letter))
# Iterate over matrix (in any order) apart from last row and last column. For each cell,
check that it has the same while heap:
# value as the cell to the bottom right.
# Time - O(mn) neg_count, letter = heapq.heappop(heap)
# Space - O(mn)
if not result or result[-1] != letter:
class Solution(object): add_letter(letter, neg_count)
def isToeplitzMatrix(self, matrix): continue
"""
:type matrix: List[List[int]] if not heap: # no other
:rtype: bool letters on heap
""" return ""
rows, cols = len(matrix), len(matrix[0])
neg_count2, letter2 = heapq.heappop(heap) # use next most
for r in range(rows - 1): frequent letter
for c in range(cols - 1): add_letter(letter2, neg_count2)
heapq.heappush(heap, (neg_count, letter)) # add back most
if matrix[r][c] != matrix[r + 1][c + 1]: frequent with same count
return False
return "".join(result)
return True

# python_1_to_1000/768_Max_Chunks_To_Make_Sorted_II.py - h
# python_1_to_1000/767_Reorganize_String.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/max-chunks-to-make-sorted-ii/
# https://leetcode.com/problems/reorganize-string/ # Given an array arr of integers (not necessarily distinct), we split the array into some
# Given a string S, check if the letters can be rearranged so that two characters that number of "chunks"
are adjacent to each other # (partitions), and individually sort each chunk. After concatenating them, the result
# are not the same. If possible, output any possible result. If not possible, return the equals the sorted array.
empty string. # What is the most number of chunks we could have made?

# Create heap of letter frequencies. Pop the most frequent letter off the heap and append # Iterate from right to left, finding the minimum value to the right of each number. Then
iterate from left to right
# tracking the maximum number in each partition. If the maximum is smaller or the same as partition_max = num if partition_max is None else max(partition_max, num)
all numbers to the right,
# the partition can be sorted and the whole list will be sorted. if partition_max < min_right[i]:
# Time - O(n) partitions += 1
# Space - O(n) partition_max = None

class Solution(object): return partitions


def maxChunksToSorted(self, arr):
"""
:type arr: List[int] # python_1_to_1000/770_Basic_Calculator_IV.py - h
:rtype: int
""" _author_ = 'jake'
min_right = [float("inf") for _ in range(len(arr))] # min_right[-1] == _project_ = 'leetcode'
float("inf")
# https://leetcode.com/problems/basic-calculator-iv/
for i in range(len(arr) - 2, -1, -1): # Given an expression such as expression = "e + 8 - a + 5" and an evaluation map such as
min_right[i] = min(min_right[i + 1], arr[i + 1]) {"e": 1}
# (given in terms of evalvars = ["e"] and evalints = [1]), return a list of tokens
partitions = 0 representing the simplified
partition_max = None # expression, such as ["-1*a","14"]
# An expression alternates chunks and symbols, with a space separating each chunk and
for i, num in enumerate(arr): symbol.
# A chunk is either an expression in parentheses, a variable, or a non-negative integer.
partition_max = num if partition_max is None else max(partition_max, num) # A variable is a string of lowercase letters (not including digits.) Note that variables
can be multiple letters,
if partition_max <= min_right[i]: # and note that variables never have a leading coefficient or unary operator like "2x" or
partitions += 1 "-x".
partition_max = None # Expressions are evaluated in the usual order: brackets first, then multiplication, then
addition and subtraction.
return partitions # For example, expression = "1 + 2 * 3" has an answer of ["7"].
# The format of the output is as follows:
# For each term of free variables with non-zero coefficient, we write the free variables
# python_1_to_1000/769_Max_Chunks_To_Make_Sorted.py - m within a term in sorted
# order lexicographically. For example, we would never write a term like "b*a*c", only
_author_ = 'jake' "a*b*c".
_project_ = 'leetcode' # Terms have degree equal to the number of free variables being multiplied, counting
multiplicity.
# https://leetcode.com/problems/max-chunks-to-make-sorted/ # (For example, "a*a*b*c" has degree 4.) We write the largest degree terms of our answer
# Given an array arr that is a permutation of [0, 1, ..., arr.length - 1], we split the first, breaking ties by
array into some number of # lexicographic order ignoring the leading coefficient of the term.
# "chunks" (partitions), and individually sort each chunk. After concatenating them, the # The leading coefficient of the term is placed directly to the left with an asterisk
result equals the sorted array. separating it from the variables
# What is the most number of chunks we could have made? # (if they exist.) A leading coefficient of 1 is still printed.
# An example of a well formatted answer is ["-2*a*a*a", "3*a*a*b", "3*b*b", "4*a", "5*c",
# Iterate from right to left, finding the minimum value to the right of each number. Then "-6"]
iterate from left to right # Terms (including constant terms) with coefficient 0 are not included.
# tracking the maximum number in each partition. If the maximum is smaller than all # For example, an expression of "0" has an output of [].
numbers to the right, the partition
# can be sorted and the whole list will be sorted. # Create a class that extends Counter by using a __mul__ method.
# Time - O(n) # Time - O(2**n + m) where len(expression) == n and len(evalvars) == m
# Space - O(n) # Space - O(n + m)

class Solution(object): from collections import Counter


def maxChunksToSorted(self, arr): import re
"""
:type arr: List[int] class Solution(object):
:rtype: int def basicCalculatorIV(self, expression, evalvars, evalints):
""" """
min_right = [float("inf") for _ in range(len(arr))] # min_right[-1] == :type expression: str
float("inf") :type evalvars: List[str]
:type evalints: List[int]
for i in range(len(arr) - 2, -1, -1): :rtype: List[str]
min_right[i] = min(min_right[i + 1], arr[i + 1]) """

partitions = 0 class CounterMul(Counter):


partition_max = None
def __add__(self, other):
for i, num in enumerate(arr): self.update(other)

return self # python_1_to_1000/772_Basic_Calculator_III.py - h

def __sub__(self, other): _author_ = 'jake'


self.subtract(other) _project_ = 'leetcode'
return self
# https://leetcode.com/problems/basic-calculator-iii/
def __mul__(self, other): # Implement a basic calculator to evaluate a simple expression string.
product = CounterMul() # The expression string may contain open ( and closing parentheses ), the plus + or minus
for x in self: sign -, non-negative integers
for y in other: # and empty spaces .
xy = tuple(sorted(x + y)) # The expression string contains only non-negative integers, +, -, *, / operators , open
product[xy] += self[x] * other[y] ( and closing parentheses )
return product # and empty spaces. The integer division should truncate toward zero.
# You may assume that the given expression is always valid.
vals = dict(zip(evalvars, evalints)) # mapping of variables to values
# Firstly, parse string to a list of integers, operators and sub-lists. Evaluate parsed
def make_counter(token): list by creating a list of
# integers to be summed by using divide and multiply with the next and previous integers.
token = str(vals.get(token, token)) # get mapping or return same token # Recursively calculate sub-lists.
# Time - O(n)
if token.isalpha(): # Space - O(n)
return CounterMul({(token,): 1}) # map token to count of one
return CounterMul({(): int(token)}) # map empty tuple to integer class Solution(object):
def calculate(self, s):
# wrap all tokens with a call to make_counter and evaluate to aggregate """
counter = eval(re.sub('(\w+)', r'make_counter("\1")', expression)) :type s: str
# '(\w+)' matches groups of 1 or more alphanumeric :rtype: int
# r'make_counter("\1")' uses \1 to to signify the matched groups and r so that \ """
is not special operators = {"+", "-", "*", "/"}

# sort keys by decreasing length then lexicographically def parse(i): # parse s from index i
sorted_terms = sorted(counter, key=lambda x: (-len(x), x))
parsed = []
result = []
for term in sorted_terms: while i < len(s):
if counter[term]: # ignore zero values c = s[i]
result.append("*".join((str(counter[term]),) + term))
if c in operators:
return result parsed.append(c)
elif "0" <= c <= "9":
if parsed and isinstance(parsed[-1], int): # part of previous
# python_1_to_1000/771_Jewels_and_Stones.py integer
parsed[-1] = parsed[-1] * 10 + int(c)
_author_ = 'jake' else: # start a new integer
_project_ = 'leetcode' parsed.append(int(c))
elif c == "(":
# https://leetcode.com/problems/jewels-and-stones/ sublist, i = parse(i + 1)
# You're given strings J representing the types of stones that are jewels, and S parsed.append(sublist)
representing the stones you have. elif c == ")":
# Each character in S is a type of stone you have. You want to know how many of the return parsed, i # parsed sub-string and
stones you have are also jewels. index to restart from
# The letters in J are guaranteed distinct, and all characters in J and S are letters.
Letters are case sensitive, i += 1 # ignores blank spaces
# so "a" is considered a different type of stone from "A".
return parsed, len(s)
# Check if each stone is in jewels. Generator saves creating a list.
# Time - O(m + n)
# Space - O(m) def calculate(tokens):

class Solution(object): if isinstance(tokens, int): # base case of single


def numJewelsInStones(self, J, S): integer
""" return tokens
:type J: str
:type S: str result = [calculate(tokens[0])] # list of integers
:rtype: int
""" for i in range(1, len(tokens), 2): # iterate over pairs of
return sum(1 for s in S if s in set(J)) operator and integer
op, num = tokens[i], calculate(tokens[i + 1])
if op == "/": seen.add(tuple(bd))
result.append(result.pop() // num) new_queue += [nb for nb in next_boards(bd) if tuple(nb) not in seen]
elif op == "*":
result.append(result.pop() * num) steps += 1
elif op == "+": queue = new_queue
result.append(num)
else: return -1
result.append(-num)

return sum(result)
# python_1_to_1000/774_Minimize_Max_Distance_to_Gas_Station.py - h
parsed_s, _ = parse(0)
return calculate(parsed_s) _author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/minimize-max-distance-to-gas-station/
# python_1_to_1000/773_Sliding_Puzzle.py - h # On a horizontal number line, we have gas stations at positions stations[0],
stations[1], ..., stations[N-1],
_author_ = 'jake' # where N = stations.length.
_project_ = 'leetcode' # Now, we add K more gas stations so that D, the maximum distance between adjacent gas
stations, is minimized.
# https://leetcode.com/problems/sliding-puzzle/ # Return the smallest possible value of D.
# On a 2x3 board, there are 5 tiles represented by the integers 1 through 5, and an empty
square represented by 0. # Create a list of distances between stations, sorted in descending order. Binary search
# A move consists of choosing 0 and a 4-directionally adjacent number and swapping it. the possible range of minimum
# The state of the board is solved if and only if the board is [[1,2,3],[4,5,0]]. # max distances. Initially this range is from zero to the maximum distance between
# Given a puzzle board, return the least number of moves required so that the state of stations. Test the middle distance,
the board is solved. # if it is possible to put K stations with this maximum distance, test lower distances
# If it is impossible for the state of the board to be solved, return -1. else test greater distances.
# Stop when required accuracy is achieved. Test if K stations can make the required
# Breadth-first search. Expand queue from board by moving to all board positions after distance by greedily using as many
making a swap. # stations as required for each interval.
# Alternatively, A* search with heap and heuristic of manhattan distance between each # Time - O(nlogn + ns) where s is the maximum number of search steps = log(r) where r =
tile and its target location. max_d / accuracy
# Time - O(mn * mn!) since there are mn! possible boards # Space - O(n)
# Space - O(mn * mn!)
class Solution(object):
class Solution(object): def minmaxGasDist(self, stations, K):
def slidingPuzzle(self, board): """
""" :type stations: List[int]
:type board: List[List[int]] :type K: int
:rtype: int :rtype: float
""" """
nbors = [[1, 3], [0, 2, 4], [1, 5], [0, 4], [1, 3, 5], [2, 4]] # indices of distances = [s1 - s2 for s1, s2 in zip(stations[1:], stations)]
neighbouring cells in linear board distances.sort(reverse=True)

def next_boards(b): # return list of next possible boards def can_minmax_dist(d):

i = b.index(0) remaining = K
next_bds = [] for dist in distances:
if dist < d or remaining < 0: # no more stations need to be added or no
for nbor in nbors[i]: more stations left to add
b_copy = b[:] # make a copy break
b_copy[i], b_copy[nbor] = b_copy[nbor], b_copy[i] # swap zero with remaining -= int(dist / d) # use stations to make the required
neighbour distance
next_bds.append(b_copy)
return next_bds return remaining >= 0

queue = [board[0] + board[1]] # convert board to linear board max_d, min_d = distances[0], 0 # initial range for binary search
steps = 0
seen = set() # visited linear boards, as tuples while max_d - min_d > 10 ** -6:

while queue: mid = (max_d + min_d) / 2.0


if can_minmax_dist(mid):
new_queue = [] max_d = mid # try smaller distances
else:
for bd in queue: min_d = mid # try larger distances
if bd == [1, 2, 3, 4, 5, 0]:
return steps return max_d

class Solution(object):
def splitBST(self, root, V):
"""
:type root: TreeNode
# python_1_to_1000/775_Global_and_Local_Inversions.py - m :type V: int
:rtype: List[TreeNode]
_author_ = 'jake' """
_project_ = 'leetcode' def splitter(node):

# https://leetcode.com/problems/global-and-local-inversions/ if not node:


# We have some permutation A of [0, 1, ..., N - 1], where N is the length of A. return [None, None]
# The number of (global) inversions is the number of i < j with 0 <= i < j < N and A[i] >
A[j]. if V < node.val:
# The number of local inversions is the number of i with 0 <= i < N and A[i] > A[i+1]. less, more = splitter(node.left) # recurse left, node.right is
# Return true if and only if the number of global inversions is equal to the number of unchanged
local inversions. node.left = more # new left is the tree with nodes > V
return [less, node]
# Every local inversion is also a global inversions, so we only need to check is there
are any other global inversions less, more = splitter(node.right) # recurse right, node.left is
# i.e. inversions separated by more than one index. Track the max value seen before the unchanged if V == node.val
previous value, if this is node.right = less
# greater than the current value we haev another global inversions. return [node, more]
# Time - O(n)
# Space - O(1) return splitter(root)

class Solution(object):
def isIdealPermutation(self, A): # python_1_to_1000/777_Swap_Adjacent_in_LR_String.py - m
"""
:type A: List[int] _author_ = 'jake'
:rtype: bool _project_ = 'leetcode'
"""
max_before_prev = -1 # https://leetcode.com/problems/swap-adjacent-in-lr-string/
# In a string composed of 'L', 'R', and 'X' characters, like "RXXLRXRXL", a move consists
for i in range(1, len(A)): of either replacing one
# occurrence of "XL" with "LX", or replacing one occurrence of "RX" with "XR".
if A[i] < max_before_prev: # Given the starting string start and the ending string end, return True if and only if
return False there exists a sequence of
max_before_prev = max(max_before_prev, A[i - 1]) # moves to transform one string to the other.

return True # "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.
# python_1_to_1000/776_Split_BST.py - m # If there is "R" in start and "L" in end then a swap is required. Final check for
overall balance.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/split-bst/ class Solution(object):


# Given a Binary Search Tree (BST) with root node root, and a target value V, split the def canTransform(self, start, end):
tree into two subtrees where """
# one subtree has nodes that are all smaller or equal to the target value, while the :type start: str
other subtree has all nodes that :type end: str
# are greater than the target value. It's not necessarily the case that the tree :rtype: bool
contains a node with value V. """
# Additionally, most of the structure of the original tree should remain. if len(start) != len(end): # early return
# Formally, for any child C with parent P in the original tree, if they are both in the return False
same subtree after the split,
# then node C should still have the parent P. left, right = 0, 0 # net balance of "L" and "R" in start minus end
# You should output the root TreeNode of both subtrees after splitting, in any order.
for c1, c2 in zip(start, end): # iterate over both strings together
# Helper function recursively splits BST into a tree with nodes <= V and a tree with
nodes > V. One side is always if c1 == "L":
# unchanged and the recursion splits the other side into 2 parst, one of which is added left += 1
back as a new left or right elif c1 == "R":
# subtree. right += 1
# Time - O(n)
# Space - O(n) if c2 == "L":
left -= 1
elif c2 == "R": heapq.heappush(frontier, (grid[r + dr][c + dc], r + dr, c + dc))
right -= 1

if left > 0 or right < 0: # more "L" in start, cannot move right to reach
those in end # python_1_to_1000/779_K-th_Symbol_in_Grammar.py - m
return False
if left < 0 and right > 0: # need to swap "L" and "R" _author_ = 'jake'
return False _project_ = 'leetcode'

return left == 0 and right == 0 # must be balanced # https://leetcode.com/problems/k-th-symbol-in-grammar/


# 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.
# python_1_to_1000/778_Swim_in_Rising_Water.py - h # Given row N and index K, return the K-th indexed symbol in row N. (The values of K are
1-indexed.) (1 indexed).
_author_ = 'jake'
_project_ = 'leetcode' # Each row consists of the concatenation of the previous row and the inverse of the
previous row. If K is more than
# https://leetcode.com/problems/swim-in-rising-water/ # half way along a row, it belongs to the inverse of the previous row hence flip the
# On an N x N grid, each square grid[i][j] represents the elevation at that point (i,j). logical flag. Repeat moving up
# Now rain starts to fall. At time t, the depth of the water everywhere is t. You can # rows until the final row is inversed (return 1) or not (return 0).
swim from a square to another # Time - O(log n)
# 4-directionally adjacent square if and only if the elevation of both squares # Space - O(1)
individually are at most t.
# You can swim infinite distance in zero time. You must stay within the boundaries of the class Solution(object):
grid during your swim. def kthGrammar(self, N, K):
# 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)? :type N: int
:type K: int
# Maintain a priority queue of cells on edge of explored region. Pop lowest cell and :rtype: int
update the high water mark. """
# Add neighbours to frontier if not already visited. If lower cells are added to frontier length = 2 ** (N - 1) # length of current row
they will be removed before
# any higher cells. inverse = False
# Time - O(n**2 logn)
# Space - O(n**2) while length > 1:

import heapq if K > length // 2: # on RHS of this row


inverse = not inverse
class Solution(object): K -= length // 2
def swimInWater(self, grid):
""" length //= 2
:type grid: List[List[int]]
:rtype: int return int(inverse)
"""
N = len(grid)
shifts = ((0, 1), (0, -1), (1, 0), (-1, 0))
frontier = [(grid[0][0], 0, 0)] # cells not explored but on edge of
explored region # python_1_to_1000/780_Reaching_Points.py - h
visited = {(0, 0)} # frontier and explored cells
_author_ = 'jake'
max_water = 0 _project_ = 'leetcode'

while True: # https://leetcode.com/problems/reaching-points/


# A move consists of taking a point (x, y) and transforming it to either (x, x+y) or
water, r, c = heapq.heappop(frontier) # lowest cell that is reachable (x+y, y).
# Given a starting point (sx, sy) and a target point (tx, ty), return True if and only if
max_water = max(max_water, water) a sequence of moves
# exists to transform the point (sx, sy) to (tx, ty). Otherwise, return False.
if r == c == N - 1: # reached target # sx, sy, tx, ty will all be integers in the range [1, 10^9].
return max_water
# Move back from tx, ty since there can be only one valid step (because sx and sy are
for dr, dc in shifts: both positive). In the other
# direction from sx, sy there are 2 possible moves. While both tx and ty are more than sx
if r + dr < 0 or r + dr >= N or c + dc < 0 or c + dc >= N: and sy respectively, subtract
continue # either ty from ty or ty from tx. Do this as many times as possible in one step with the
if (r + dr, c + dc) in visited: modulo operator.
continue # When either tx <= sx or ty <= sy, check if tx == sx and ty can reach sy by taking steps
visited.add((r + dr, c + dc)) of sx (or vica versa).

# Time - O(log n) # What is the minimum number of moves to transform the board into a "chessboard" - a
# Space - O(1) board where no 0s and no 1s
# are 4-directionally adjacent? If the task is impossible, return -1.
class Solution(object):
def reachingPoints(self, sx, sy, tx, ty): # If two rows are identical, then swapping columns does not change this. The solution has
""" two types of row and since we
:type sx: int # cannot change the number of row types by swapping columns, the board must only have two
:type sy: int types of row initially.
:type tx: int # The two types of row must be opposite and differ in their number of zeros by len(board)
:type ty: int % 1.
:rtype: bool # If len(board) is odd, find the type with the most zeros and count the moves to convert
""" it to the required target
while tx > sx and ty > sy: # beginning with zero. Else find the minimum steps to either the target beginning with
tx, ty = tx % ty, ty % tx # either tx % ty == zero or one.
# Time - O(mn)
if tx == sx and (ty - sy) % sx == 0: # Space - O(mn)
return True
return ty == sy and (tx - sx) % sy == 0 class Solution(object):
def movesToChessboard(self, board):
"""
# python_1_to_1000/781_Rabbits_in_Forest.py - m :type board: List[List[int]]
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode' n = len(board)

# https://leetcode.com/problems/rabbits-in-forest/ rows = {tuple(row) for row in board} # set of row tuples


# In a forest, each rabbit has some color. Some subset of rabbits (possibly all of them) cols = set(zip(*board)) # transpose, converts to column tuples
tell you how many other
# rabbits have the same color as them. Those answers are placed in an array. moves = 0
# Return the minimum number of rabbits that could be in the forest. for patterns in [rows, cols]: # process rows then columns

# Maintain a mapping for each colour (an integer) to the number of as yet unseen rabbits if len(patterns) != 2: # 2 types of row or column
with that colour. If a rabbit return -1
# has as many other rabbits as another rabbit already seen, then decrement the unseen
count. Else increase the total p1, p2 = list(patterns)
# count for the new colour by the rabbit plus all others.
# Time - O(n) zero_p1, zero_p2 = sum(x == 0 for x in p1), sum(x == 0 for x in p2)
# Space - O(n) if abs(zero_p1 - zero_p2) != n % 2 or not all(x ^ y for x, y in zip(p1, p2)):
# opposites
class Solution(object): return -1
def numRabbits(self, answers):
""" p = p1 if zero_p1 > zero_p2 else p2 # choose pattern with most zeros
:type answers: List[int] p_moves = sum(x != y for x, y in zip(p, [0, 1] * ((n + 1) // 2)))
:rtype: int if n % 2 == 0: # need to check steps to both targets for
""" even board lengths
colours = {} # map colour to number of unseen rabbits p_moves = min(p_moves, sum(x != y for x, y in zip(p, [1, 0] * ((n + 1) //
of that colour 2))))
rabbits = 0
moves += p_moves // 2 # each swap corrects the position of 2
for rabbit in answers: items

if colours.get(rabbit, 0) > 0: # default 0 if a new colour return moves


colours[rabbit] -= 1
else:
rabbits += rabbit + 1 # new colour
colours[rabbit] = rabbit # python_1_to_1000/783_Minimum_Distance_Between_BST_Nodes.py

return rabbits _author_ = 'jake'


_project_ = 'leetcode'

# python_1_to_1000/782_Transform_to_Chessboard.py - h # https://leetcode.com/problems/minimum-distance-between-bst-nodes/
# Given a Binary Search Tree (BST) with the root node root, return the minimum difference
_author_ = 'jake' between the values of any
_project_ = 'leetcode' # two different nodes in the tree.

# https://leetcode.com/problems/transform-to-chessboard/ # Inorder traversal visits nodes in increasing order of value. Update the previous node
# An N x N board contains only 0s and 1s. In each move, you can swap any 2 rows with each and minimum difference for
other, # each node.
# or any 2 columns with each other. # Time - O(n)
# Space - O(n) strings

class Solution(object):
def minDiffInBST(self, root): # python_1_to_1000/785_Is_Graph_Bipartite.py - m
"""
:type root: TreeNode _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
self.min_diff = float("inf") # https://leetcode.com/problems/is-graph-bipartite/
self.prev = float("-inf") # 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
def inorder(node): subsets A and B such that
if not node: # every edge in the graph has one node in A and another node in B.
return # The graph is given as follows: graph[i] is a list of indexes j for which the edge
between nodes i and j exists.
inorder(node.left) # 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
self.min_diff = min(self.min_diff, node.val - self.prev) contain any element twice.
self.prev = node.val
# Set the "colour" of each node to True or False. Iterate over nodes ignoring those that
inorder(node.right) have been visited before.
# Set the colour of an unvisited node arbitrarily to True and add it to queue. Queue
inorder(root) contains all nodes whose
return self.min_diff # 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.
# python_1_to_1000/784_Letter_Case_Permutation.py - m # Time - O(n) the number of edges
# Space - O(m) the number of nodes
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def isBipartite(self, graph):
# https://leetcode.com/problems/letter-case-permutation/ """
# Given a string S, we can transform every letter individually to be lowercase or :type graph: List[List[int]]
uppercase to create another string. :rtype: bool
# Return a list of all possible strings we could create. """
n = len(graph)
# Start with empty list as the only result. For each char in S, if char is a digit append colours = [None] * n # initially all nodes are not coloured
it ot each existing result.
# Else append the upper and lower case of char to each existing result. for i in range(len(graph)):
# Time - O(n * 2**n), since 2**n possible results of length n
# Space - O(n * 2**n) if colours[i] is not None:
continue
class Solution(object):
def letterCasePermutation(self, S): colours[i] = True
""" queue = [i] # coloured nodes whose edges have not been
:type S: str checked
:rtype: List[str]
""" while queue:
permutations = [[]]
v = queue.pop()
for c in S:
for nbor in graph[v]:
if "0" <= c <= "9":
for perm in permutations: if colours[nbor] is None:
perm.append(c) colours[nbor] = not colours[v] # set to opposite colour of v
queue.append(nbor)
else:
elif colours[nbor] == colours[v]: # inconsistency, cannot create
new_permutations = [] bipartite graph
upper, lower = c.upper(), c.lower() return False

for perm in permutations: return True


new_permutations.append(perm + [upper])
perm.append(lower)
new_permutations.append(perm) # python_1_to_1000/786_K-th_Smallest_Prime_Fraction.py - m

permutations = new_permutations _author_ = 'jake'


_project_ = 'leetcode'
return ["".join(perm) for perm in permutations] # convert lists of chars to

# https://leetcode.com/problems/k-th-smallest-prime-fraction/ v with a price w.


# A sorted list A contains 1, plus some number of primes. # Now given all the cities and fights, together with starting city src and the
# Then, for every p < q in the list, we consider the fraction p/q. destination dst, your task is to find
# What is the K-th smallest fraction considered? Return your answer as an array of ints, # the cheapest price from src to dst with up to k stops. If there is no such route,
# where answer[0] = p and answer[1] = q. output -1.

# Binary search the space of numbers between 0 and 1 for the number with K smaller # Create an adjacency list mapping from a city to all cities connected by a direct
fractions. flight.
# Since max prime is N = 30000 then min difference between two fractions is 1/N**2 > # Create a priority queue ordered by cost. Repeatedly pop city with lowest cost and add
10**-9. Hence binary search until it to visited set. If not
# the solution range < 10**-9. # the destination,
# For each numerator in turn, test greater denominators to find the first fraction < mid. # Time - O(m + n log n) where m == len(flights) and n == number of cities
Next numerator starts with # Space - O(m + n)
# previous denominator.
# Time - O(n ln k) where n is number of primes and k is max prime from collections import defaultdict
# Space - O(1) import heapq

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


def kthSmallestPrimeFraction(self, A, K): def findCheapestPrice(self, n, flights, src, dst, K):
""" """
:type A: List[int] :type n: int
:type K: int :type flights: List[List[int]]
:rtype: List[int] :type src: int
""" :type dst: int
def count_smaller_fractions(x): # return number for fractions < x and largest :type K: int
such fraction :rtype: int
"""
count, denominator, largest = 0, 1, [0, 1] flts = defaultdict(list) # map city to list of (destination,
cost)
for numerator in range(len(A) - 1): # for each numerator, find first for start, end, cost in flights:
denominator so fraction < x flts[start].append((end, cost))

while denominator < len(A) and A[numerator] >= x * A[denominator]: # queue = [(0, -1, src)] # -1 stops since zero stops are
fraction >= x direct flights
denominator += 1 visited = set() # cities where we know the cheapest
cost
if denominator != len(A) and A[numerator] * largest[1] > largest[0] *
A[denominator]: while queue:
largest = [A[numerator], A[denominator]] # new
largest cost, stops, location = heapq.heappop(queue)
visited.add(location)
count += len(A) - denominator # count this and all greater
denominators if location == dst:
return cost
return count, largest
if stops == K: # cannot make more stops along this
low, high = 0, 1.0 path
while high - low > 10 ** -9: continue

mid = (low + high) / 2 for end, next_cost in flts[location]:


count, largest = count_smaller_fractions(mid) if end not in visited: # do not revisit cities where we
if count < K: # insufficient fractions below mid, search larger already have the cheapest cost
candidates heapq.heappush(queue, (cost + next_cost, stops + 1, end))
low = mid
else: # sufficient fractions below mid, search smaller return -1 # destination cannot be reached
candidates
result = largest # update largest fraction where count == K
high = mid
# python_1_to_1000/788_Rotated_Digits.py - m
return result
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/787_Cheapest_Flights_Within_K_Stops.py - m
# https://leetcode.com/problems/rotated-digits/
_author_ = 'jake' # X is a good number if after rotating each digit individually by 180 degrees, we get a
_project_ = 'leetcode' valid number that is different
# from X. Each digit must be rotated - we cannot choose to leave it alone.
# https://leetcode.com/problems/cheapest-flights-within-k-stops/ # A number is valid if each digit remains a digit after rotation. 0, 1, and 8 rotate to
# There are n cities connected by m flights. Each fight starts from city u and arrives at 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 # python_1_to_1000/790_Domino_and_Tromino_Tiling.py - m
other number.
# Now given a positive number N, how many numbers X from 1 to N are good? _author_ = 'jake'
_project_ = 'leetcode'
# Test each integer. If any digit cannot be rotated then integer is not good. Also if
integer does not contain at least # https://leetcode.com/problems/domino-and-tromino-tiling/
# one digit that is different after rotation, it is bad. # We have two types of tiles: a 2x1 domino shape, and an "L" tromino shape. These shapes
# Time - O(n log n) since each integer has O(log n) digits. may be rotated.
# Space - O(log n) # Given N, how many ways are there to tile a 2 x N board? Return your answer modulo 10^9
+ 7.
class Solution(object): # In a tiling, every square must be covered by a tile. Two tilings are different if and
def rotatedDigits(self, N): only if there are two
""" # 4-directionally adjacent cells on the board such that exactly one of the tilings has
:type N: int both squares occupied by a tile.
:rtype: int
""" # For each length of board, find the number of tilings that fill the board exactly and
count = 0 the number of tilings that have
bad = {"3", "4", "7"} # one extra tile. To tile a board of length n exactly, we can use either a tiled board of
opposites = {"2", "5", "6", "9"} n - 1 and a horizontal
# domino, or a tiled board of n - 2 and two vertical dominos, or a board of n - 2 with
for i in range(1, N + 1): 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
digits = set(str(i)) of length n - 1 and a tromino
if not bad.intersection(digits) and opposites.intersection(digits): # in one of two orientations, or a a board of n - 2 with one extra tile and a vertical
count += 1 domino.
# Time - O(n)
return count # Space - O(1)

class Solution(object):
def numTilings(self, N):
# python_1_to_1000/789_Escape_The_Ghosts.py - m """
:type N: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
MOD = 10 ** 9 + 7
# https://leetcode.com/problems/escape-the-ghosts/ prev_tilings, tilings = 0, 1 # one way to fully tile board of length zero
# You are playing a simplified Pacman game. You start at the point (0, 0), and your prev_one_extra, one_extra = 0, 0 # no ways to tile boards of length -1 or 0
destination is with one extra
# (target[0], target[1]). There are several ghosts on the map, the i-th ghost starts at
(ghosts[i][0], ghosts[i][1]). for _ in range(N):
# Each turn, you and all ghosts simultaneously *may* move in one of 4 cardinal
directions: north, east, west, or south, next_tilings = (tilings + prev_tilings + prev_one_extra) % MOD
# going from the previous point to a new point 1 unit of distance away. next_one_extra = (2 * tilings + one_extra) % MOD
# You escape if and only if you can reach the target before any ghost reaches you (for
any given moves the ghosts tilings, prev_tilings = next_tilings, tilings
# may take.) If you reach any square (including the target) at the same time as a ghost, one_extra, prev_one_extra = next_one_extra, one_extra
it doesn't count as an escape.
# Return True if and only if it is possible to escape. return tilings

# If any ghost can reach the target before or at the same time as pacman then no escape
is possible. # python_1_to_1000/791_Custom_Sort_String.py - m
# Time - O(n)
# Space - O(1) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def escapeGhosts(self, ghosts, target): # https://leetcode.com/problems/custom-sort-string/
""" # S and T are strings composed of lowercase letters. In S, no letter occurs more than
:type ghosts: List[List[int]] once.
:type target: List[int] # S was sorted in some custom order previously. We want to permute the characters of T so
:rtype: bool that they match the order
""" # that S was sorted. More specifically, if x occurs before y in S, then x should occur
def manhattan(position): before y in the returned string.
return abs(position[0] - target[0]) + abs(position[1] - target[1]) # Return any permutation of T (as a string) that satisfies this property.

target_distance = manhattan((0, 0)) # Count the frequencies of all letters in T. For each letter in S, add to the result the
number of copies of the letter
return all(manhattan(ghost) > target_distance for ghost in ghosts) # in T. Finally add all copies of lteers in T that are not in S.
# Time - O(m + n)
# Space - O(m)

from collections import Counter return result

class Solution(object):
def customSortString(self, S, T): # python_1_to_1000/793_Preimage_Size_of_Factorial_Zeroes_Function.py - h
"""
:type S: str _author_ = 'jake'
:type T: str _project_ = 'leetcode'
:rtype: str
""" # https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/
result = [] # Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... *
t_count = Counter(T) 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
for c in S: 11! = 39916800 has 2 zeroes
result += [c] * t_count[c] # do not create strings with c * t_count[c] # at the end. Given K, find how many non-negative integers x have the property that f(x)
del t_count[c] = K.

for c, count in t_count.items(): # Binary search for the smallest x such that f(x) >= K. If f(x) == K then there is some
result += [c] * count integer with K trailing zeros
return "".join(result) # hence there are 5 such integers (the integers between successive factors of 5). Else
there is no integer with K
# trailing zeros.
# Time - O(log^2 K), log K for factorial_zeros and log K for binary search
# python_1_to_1000/792_Number_of_Matching_Subsequences.py - m # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def preimageSizeFZF(self, K):
"""
# https://leetcode.com/problems/number-of-matching-subsequences/ :type K: int
# Given string S and a dictionary of words words, find the number of words[i] that are a :rtype: int
subsequences of S. """
def factorial_zeros(n): # find the number of trailing zeros in n!, as per
# Maintain a mapping for each word from the next char to be matched to the remainder of problem 172
the word. For each char in factor = 5
# S, update the mapping by removing the key/value with the current char and adding the result = 0
words back with keys of their while factor <= n:
# chars to be matched. result += n // factor
# Time - O(m + n), len(S) + sum of all words factor *= 5
# Space - O(n) return result

from collections import defaultdict left, right = 0, 10 * K # solution is approximately 5 * K

class Solution(object): while left < right: # loop until only one candidate remains
def numMatchingSubseq(self, S, words):
""" mid = (left + right) // 2
:type S: str mid_zeros = factorial_zeros(mid)
:type words: List[str] if mid_zeros < K: # check strictly greater integers
:rtype: int left = mid + 1
""" else: # mid remains in range
letter_to_suffixes = defaultdict(list) # map next char of a word to suffix after right = mid
that char
letter_to_suffixes["#"] = words # special character will be matched return 5 if factorial_zeros(right) == K else 0
initially
result = 0

for c in "#" + S: # python_1_to_1000/794_Valid_Tic-Tac-Toe_State.py - m

suffixes = letter_to_suffixes[c] # cannot pop unless checking whether c is _author_ = 'jake'


in letter_to_suffixes _project_ = 'leetcode'
del letter_to_suffixes[c]
# https://leetcode.com/problems/valid-tic-tac-toe-state/
for suffix in suffixes: # A Tic-Tac-Toe board is given as a string array board.
# Return True if and only if it is possible to reach this board position during the
if len(suffix) == 0: # matched all of this word course of a valid tic-tac-toe game.
result += 1 # The board is a 3 x 3 array consisting of characters " ", "X", and "O". The " "
continue character represents an empty square.
# Here are the rules of Tic-Tac-Toe:
next_letter, next_suffix = suffix[0], suffix[1:] # Players take turns placing characters into empty squares (" ").
letter_to_suffixes[next_letter].append(next_suffix) # The first player always places "X" characters, while the second player always places
"O" characters. # subarray is at least L and at most R.
# "X" and "O" characters are always placed into empty squares, never filled ones.
# The game ends when there are 3 of the same (non-empty) character filling any row, # Dynamic programming. Find the number of solutions ending with each element of A. If the
column, or diagonal. element is greater than R
# The game also ends if all squares are non-empty. # then there are no solutions and we record the index of the latest element greater than
# No more moves can be played if the game is over. R. If the element is less than
# L then every solution ending with the previous element can be extended. If the element
# Count the number of Os and X and the number of winning rows of Os and Xs. Check only is between L and R inclusive
one winner and number of Os and # then every subarray starting after the last element greater than R is a solution.
# Xs in the cases of either winner and no winner. # Time - O(n)
# Time - O(1) since board has fixed size of 3 x 3 # Space - O(1)
# Space - O(1)
class Solution(object):
class Solution(object): def numSubarrayBoundedMax(self, A, L, R):
def validTicTacToe(self, board): """
""" :type A: List[int]
:type board: List[str] :type L: int
:rtype: bool :type R: int
""" :rtype: int
counts, lines = [0, 0], [0, 0] # counts of O and X, counts of lines of O """
and X subarrays, total = 0, 0 # subarrays ending at current index, grand total
last_above_max = -1 # index of last element > R
for i, char in enumerate(("O", "X")):
for i, num in enumerate(A):
for j, row in enumerate(board):
if num > R:
if row == char * 3: # row lines subarrays = 0
lines[i] += 1 last_above_max = i

if board[0][j] == board[1][j] == board[2][j] == char: # columns lines elif num < L: # all subarrays ending at previous index cn be extended
lines[i] += 1 total += subarrays

for c in row: # counts else: # count subarrays ending with i and starting after
if c == char: last_above_max
counts[i] += 1 subarrays = i - last_above_max
total += subarrays
if board[0][0] == board[1][1] == board[2][2] == char: # diagonal
lines[i] += 1 return total

if board[2][0] == board[1][1] == board[0][2] == char: # diagonal


lines[i] += 1
# python_1_to_1000/796_Rotate_String.py
if lines[0] and lines[1]: # cannot both win
return False _author_ = 'jake'
_project_ = 'leetcode'
if lines[0] and counts[0] != counts[1]: # O wins, same
number of each # https://leetcode.com/problems/rotate-string/
return False # We are given two strings, A and B. A shift of A consists of taking string A and moving
the leftmost character to the
if lines[1] and counts[1] != counts[0] + 1: # X wins, one # rightmost position. For example, if A = 'abcde', then it will be 'bcdea' after one
more X shift on A.
return False # Return True if and only if A can become B after some number of shifts on A.

if counts[1] - counts[0] > 1 or counts[1] - counts[0] < 0: # no winner # Rotation preserves length so if lengths differ there is no solution. If lengths are the
return False same, there must be a copy of
# A which is a substring of the concatenation of 2 copies of B.
return True # Alternatively, KMP algorithm performs substring search in O(n).
# Time - O(n**2) where n == len(A) == len(B)
# Space - O(n)
# python_1_to_1000/795_Number_of_Subarrays_with_Bounded_Maximum.py - m
class Solution(object):
_author_ = 'jake' def rotateString(self, A, B):
_project_ = 'leetcode' """
:type A: str
# https://leetcode.com/problems/number-of-subarrays-with-bounded-maximum/ :type B: str
# We are given an array A of positive integers, and two positive integers L and R (L <= :rtype: bool
R). """
# Return the number of (contiguous, non-empty) subarrays such that the value of the if len(A) != len(B):
maximum array element in that return False

def bestRotation(self, A):


return A in B + B """
:type A: List[int]
:rtype: int
# python_1_to_1000/797_All_Paths_From_Source_to_Target.py - m """
n = len(A)
_author_ = 'jake' rotations = [0 for _ in range(n)]
_project_ = 'leetcode'
for i, num in enumerate(A):
# 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 min_rot = (i + 1) % n # rotate element to end of array
node N-1 max_rot = (n - num + i + 1) % n # rotate past index of num
# and return them in any order.
# The graph is given as follows: the nodes are 0, 1, ..., graph.length - 1. graph[i] is rotations[min_rot] += 1
a list of all nodes j for rotations[max_rot] -= 1
# which the edge (i, j) exists. if min_rot > max_rot: # indices of rotation wrap around zero
rotations[0] += 1
# Breadth-first search. For each partial path, extend to all neighbours of the last node.
If the last node is the score, max_score, best_rotation = 0, 0, 0
# destination add a copy of path to results, else add to new partial paths.
# Time - O(n**2 * n**n) max path of length n, upper limit of n**n paths for i, r in enumerate(rotations):
# Space - O(n * n**n) score += r
if score > max_score:
class Solution(object): max_score = score
def allPathsSourceTarget(self, graph): best_rotation = i
"""
:type graph: List[List[int]] return best_rotation
:rtype: List[List[int]]
"""
paths, results = [[0]], [] # initial partial path of [0] # python_1_to_1000/799_Champagne_Tower.py - m

while paths: _author_ = 'jake'


_project_ = 'leetcode'
new_paths = []
# https://leetcode.com/problems/champagne-tower/
for path in paths: # We stack glasses in a pyramid, where the first row has 1 glass, the second row has 2
for next_node in graph[path[-1]]: glasses,
destination = results if next_node == len(graph) - 1 else new_paths # and so on until the 100th row. Each glass holds one cup (250ml) of champagne.
destination.append(path[:] + [next_node]) # Then, some champagne is poured in the first glass at the top. When the top most glass
is full, any excess liquid
paths = new_paths # poured will fall equally to the glass immediately to the left and right of it. When
those glasses become full,
return results # any excess champagne will fall equally to the left and right of those glasses, and so
on.
# A glass at the bottom row has it's excess champagne fall on the floor.
# Now after pouring some non-negative integer cups of champagne, return how full the j-th
# python_1_to_1000/798_Smallest_Rotation_with_Highest_Score.py - h glass in the i-th row is
# (both i and j are 0 indexed.)
_author_ = 'jake'
_project_ = 'leetcode' # Calculate the volume of champagne that is added to each glass. For each glass in the
current row, subtract 1 glass
# https://leetcode.com/problems/smallest-rotation-with-highest-score/ # which is the champagne that remains and divid the remainder by the 2 glasses below
# Given an array A, we may rotate it by a non-negative integer K so that the array (floored at zero).
becomes # Time - O(n**2)
# A[K], A[K+1], A{K+2], ... A[A.length - 1], A[0], A[1], ..., A[K-1]. # Space - O(n)
# 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 class Solution(object):
highest score we could receive. def champagneTower(self, poured, query_row, query_glass):
# If there are multiple answers, return the smallest such index K. """
:type poured: int
# For each element of A, find the interval of rotation that cause the element to score a :type query_row: int
point. Increment rotations at :type query_glass: int
# index where first rotation occurs and at index after last rotation. :rtype: float
# Iterate over rotations calculating a running sum of the number of open intervals and """
find the max. glasses = [poured]
# Time - O(n)
# Space - O(n) for row in range(query_row):

class Solution(object): new_glasses = [0 for _ in range(len(glasses) + 1)]


# At the end of some number of swaps, A and B are both strictly increasing.
for i, glass in enumerate(glasses): # A sequence is strictly increasing if and only if A[0] < A[1] < A[2] < ... < A[A.length
pour = max(glass - 1, 0) / 2.0 - 1].
new_glasses[i] += pour # Given A and B, return the minimum number of swaps to make both sequences strictly
new_glasses[i + 1] += pour increasing.
# It is guaranteed that the given input always makes it possible.
glasses = new_glasses
# Dynamic programming. For each index, find the minimum swaps to make an increasing
return min(glasses[query_glass], 1) sequence to (and including) that
# index, with and without swapping elements at that index.
# If the elements at index i in A and B are both increasing relative to their previous
# python_1_to_1000/800_Similar_RGB_Color.py elements, the cost without
# swapping is the previous cost without swapping and the cost with swapping is 1 + the
_author_ = 'jake' previous cost with swapping
_project_ = 'leetcode' # (since if i and i-1 are swapped then the lists are in the origina order). If the lists
are increasing after swapping
# https://leetcode.com/problems/similar-rgb-color/ # at index i, update the cost without swapping according to the previous cost with
# In the following, every capital letter represents some hexadecimal digit from 0 to f. swapping, and the cost with swapping
# The red-green-blue color "#AABBCC" can be written as "#ABC" in shorthand. # as 1 + the previous cost without swapping.
# For example, "#15c" is shorthand for the color "#1155cc". # Time - O(n)
# Now, say the similarity between two colors "#ABCDEF" and "#UVWXYZ" is -(AB - UV)^2 - # Space - O(1)
(CD - WX)^2 - (EF - YZ)^2.
# Given the color "#ABCDEF", return a 7 character color that is most similar to #ABCDEF, class Solution(object):
# and has a shorthand (that is, it can be represented as some "#XYZ" def minSwap(self, A, B):
"""
# Convert each pair of characters to integer and fins the absolute difference. If the :type A: List[int]
absolute difference is less than :type B: List[int]
# or equal to 8 then it is optimal to duplicate the first char of the pair. Otherwise the :rtype: int
first char is greater than """
# the second, it is a shorter distance to decrement the first char. Else increment the prev_no_swap, prev_swap = 0, 1 # min swaps without and with swapping
first char. at first index
# Time - O(1)
# Space - O(1) for i in range(1, len(A)): # start from second index

class Solution(object): no_swap, swap = float("inf"), float("inf") # default infinity if no


def similarRGB(self, color): increasing subsequences can be made
"""
:type color: str if A[i] > A[i - 1] and B[i] > B[i - 1]:
:rtype: str no_swap = prev_no_swap
""" swap = 1 + prev_swap
result = ["#"]
if A[i] > B[i - 1] and B[i] > A[i - 1]:
for i in range(1, 6, 2): # first char of each pair no_swap = min(no_swap, prev_swap)
swap = min(swap, 1 + prev_no_swap)
first, second = int(color[i], 16), int(color[i + 1], 16) # convert hex to
integer prev_no_swap, prev_swap = no_swap, swap
difference = first - second
return min(prev_no_swap, prev_swap)
if abs(difference) <= 8:
char = color[i]
elif difference > 0:
char = hex(first - 1)[2] # decrement and convert back to hex # python_1_to_1000/802_Find_Eventual_Safe_States.py - m
else: # difference < 0
char = hex(first + 1)[2] _author_ = 'jake'
result.append(char * 2) _project_ = 'leetcode'

return "".join(result) # https://leetcode.com/problems/find-eventual-safe-states/


# In a directed graph, we start at some node and every turn, walk along a directed edge
of the graph.
# python_1_to_1000/801_Minimum_Swaps_To_Make_Sequences_Increasing.py - h # If we reach a node that is terminal (that is, it has no outgoing directed edges), we
stop.
_author_ = 'jake' # Now, say our starting node is eventually safe if and only if we must eventually walk to
_project_ = 'leetcode' a terminal node.
# More specifically, there exists a natural number K so that for any choice of where to
# https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/ walk,
# We have two integer sequences A and B of the same non-zero length. # we must have stopped at a terminal node in less than K steps.
# We are allowed to swap elements A[i] and B[i]. Note that both elements are in the same # Which nodes are eventually safe? Return them as an array in sorted order.
index position in their # The directed graph has N nodes with labels 0, 1, ..., N-1, where N is the length of
# respective sequences. graph.

# The graph is given in the following form: graph[i] is a list of labels j such that (i,
j) is a directed edge. class Solution(object):
def hitBricks(self, grid, hits):
# Topological sort. Start with a list of all safe nodes without outgoing edges. For each """
node, remove its incoming :type grid: List[List[int]]
# edges from the outgoing edges of its neighbours. If any neighbour then has no outgoing :type hits: List[List[int]]
edges, add it to the safe list. :rtype: List[int]
# Alternatively DFS marking unvisied nodes as white, known safe nodes as black and """
visited uncertain node as grey. rows, cols = len(grid), len(grid[0])
# Time - O(m + n), nodes + edges are all visited once. nbors = ((1, 0), (0, 1), (-1, 0), (0, -1))
# Space - O(m + n)
for r, c in hits: # set to zero if a brick was hit, else set to -1
class Solution(object): grid[r][c] -= 1
def eventualSafeNodes(self, graph):
""" def dfs(row, col):
:type graph: List[List[int]] if row < 0 or row >= rows or col < 0 or col >= cols:
:rtype: List[int] return 0
""" if grid[row][col] != 1:
outgoing = [set(nbors) for nbors in graph] # convert neigbours to set of return 0
O(1) lookup grid[row][col] = 2
incoming = [[] for _ in range(len(graph))] # map node to list of nodes with return 1 + sum(dfs(row + dr, col + dc) for dr, dc in nbors)
incoming edges
for c in range(cols):
for node, nbors in enumerate(graph): dfs(0, c)
for nbor in nbors:
incoming[nbor].append(node) def connected(r, c):
if r == 0:
safe = [node for node, nbors in enumerate(outgoing) if not nbors] # nodes return True
without outgoing edges return any(0 <= (r + dr) < rows and 0 <= (c + dc) < cols \
and grid[r + dr][c + dc] == 2 for dr, dc in nbors)
for safe_node in safe: # extended during iteration,
could pop or use deque result = []
for r, c in reversed(hits):
nbors = incoming[safe_node] grid[r][c] += 1
for nbor in nbors: if grid[r][c] == 1 and connected(r, c):
outgoing[nbor].remove(safe_node) # remove edge safe_node -> nbor result.append(dfs(r, c) - 1) # ignore erased brick
if not outgoing[nbor]: # new eventually safe node else:
safe.append(nbor) result.append(0)

return [node for node, nbors in enumerate(outgoing) if not nbors] # all nodes return result[::-1]
that are now safe

# python_1_to_1000/803_Bricks_Falling_When_Hit.py - h # python_1_to_1000/804_Unique_Morse_Code_Words.py

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# https://leetcode.com/problems/bricks-falling-when-hit/ # https://leetcode.com/problems/unique-morse-code-words/
# We have a grid of 1s and 0s; the 1s in a cell represent bricks. A brick will not drop # International Morse Code defines a standard encoding where each letter is mapped to a
if and only if it is directly series of dots and dashes,
# connected to the top of the grid, or at least one of its (4-way) adjacent bricks will # as follows: "a" maps to ".-", "b" maps to "-...", "c" maps to "-.-.", and so on.
not drop. # Now, given a list of words, each word can be written as a concatenation of the Morse
# We will do some erasures sequentially. Each time we want to do the erasure at the code of each letter.
location (i, j), # For example, "cab" can be written as "-.-.-....-", (which is the concatenation "-.-." +
# the brick (if it exists) on that location will disappear, and then some other bricks "-..." + ".-").
may drop because of that erasure. # We'll call such a concatenation, the transformation of a word.
# Return an array representing the number of bricks that will drop after each erasure in # Return the number of different transformations among all words we have.
sequence.
# Create the transformation of each word as a list of the transformations of each letter.
# Add all hits to grid, differentiating between those that hit a brick and those that are # Create a set of all transformations.
empty. Depth-first from the # Time - O(n)
# top row to flag all bricks that are still attached. Add back each brick in reverse # Space - O(n)
order. If a brick added back has a
# neighbour that is attached, attach it and all connected bricks that are not already class Solution(object):
attached. def uniqueMorseRepresentations(self, words):
# Time - O(mn) """
# Space - O(mn) :type words: List[str]
:rtype: int n, sum_A = len(A), sum(A)
""" invalid = set() # memoize failed attempts
codes = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", C = sorted(A) # C initially contains all of A
"-.-", ".-..", "--", "-.",
"---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", for len_B in range(1, (n // 2) + 1): # try all possible lengths of B
"-.--", "--.."]
morse = set() target = sum_A * len_B / float(n)
if target != int(target): # target must be an integer
for word in words: continue

transformation = [] if n_sum_target(len_B, target, 0):


return True
for c in word:
transformation.append(codes[ord(c) - ord("a")]) return False

morse.add("".join(transformation))
# python_1_to_1000/806_Number_of_Lines_To_Write_String.py
return len(morse)
_author_ = 'jake'
_project_ = 'leetcode'

# python_1_to_1000/805_Split_Array_With_Same_Average.py - h # https://leetcode.com/problems/number-of-lines-to-write-string/
# We are to write the letters of a given string S, from left to right into lines.
_author_ = 'jake' # Each line has maximum width 100 units, and if writing a letter would cause the width of
_project_ = 'leetcode' the line to exceed 100 units,
# it is written on the next line. We are given an array widths, an array where widths[0]
# https://leetcode.com/problems/split-array-with-same-average/ is the width of 'a',
# In a given integer array A, we must move every element of A to either list B or list C. # widths[1] is the width of 'b', ..., and widths[25] is the width of 'z'.
# B and C initially start empty. # Now answer two questions: how many lines have at least one character from S,
# Return true if and only if after such a move, it is possible that the average value of # and what is the width used by the last such line? Return your answer as an integer list
B is equal to the average of length 2.
# value of C, and B and C are both non-empty.
# Track the current line number and its width. Start with zero lines of length 100 to
# For the averages of B and C to be equal, they must both be the average of A. handle empty S.
# For each length of B from 1 to half of the length of A, find the required sum of B. If # For each char in S, add it to the current line if there is room, else start another
this is an integer, attempt to line.
# find numbers in A to make B with the required length and sum with helper function # Time - O(n)
n_sum_target. # Space - O(1)
# Time - O(n * 2**n) since O(n) lengths of B, for which each element of A may or may not
be included class Solution(object):
# Space - O(2**n) def numberOfLines(self, widths, S):
"""
class Solution(object): :type widths: List[int]
def splitArraySameAverage(self, A): :type S: str
""" :rtype: List[int]
:type A: List[int] """
:rtype: bool line, width = 0, 100 # line number and width
"""
def n_sum_target(n, tgt, j): # helper fn, can we find n numbers in A[j:] that for c in S:
sum to tgt?
c_length = widths[ord(c) - ord("a")]
if (n, tgt, j) in invalid: # already know this is impossible
return False if width + c_length > 100: # cannot fit c on this line, start a new line
if n == 0: # if no more numbers can be chosen, line += 1
return tgt == 0 # then True if and only if we have exactly width = 0
reached the target
width += c_length
for i in range(j, len(C)):
return [line, width]
if C[i] > tgt: # remaining numbers are at least as large because
C is sorted
break # python_1_to_1000/807_Max_Increase_to_Keep_City_Skyline.py - m
if n_sum_target(n - 1, tgt - C[i], i + 1): # recurse having used num in
B _author_ = 'jake'
return True _project_ = 'leetcode'

invalid.add((n, tgt, j)) # https://leetcode.com/problems/max-increase-to-keep-city-skyline/


return False # 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 then the result is within
amounts can be different for # 10**-6 of 1 so we simply return 1 to the avoid the time limit being exceeded.
# different buildings). Height 0 is considered to be a building as well. # Time - O(1) due to the upper limit on N of 4800
# At the end, the "skyline" when viewed from all four directions of the grid, i.e. top, # Space - O(1)
bottom, left, and right,
# must be the same as the skyline of the original grid. A city's skyline is the outer class Solution(object):
contour of the rectangles formed def soupServings(self, N):
# by all the buildings when viewed from a distance. """
# What is the maximum total sum that the height of the buildings can be increased? :type N: int
:rtype: float
# Find the maximum height in each row an each columns. For each cell in the grid, the """
building can be increased to the memo = {}
# lower of the row and column maximum heights.
# Time - O(mn) def helper(A, B):
# Space - O(m + n)
if A <= 0 and B <= 0: # base case, both A and Bempty together
class Solution(object): return 0.5
def maxIncreaseKeepingSkyline(self, grid): if A <= 0: # base case, only A empty
""" return 1
:type grid: List[List[int]] if B <= 0: # base case, only B empty
:rtype: int return 0
"""
rows, cols = len(grid), len(grid[0]) if (A, B) in memo:
row_sky = [0 for _ in range(rows)] # max heights by row return memo[(A, B)]
col_sky = [0 for _ in range(cols)] # max heights by col
result = 0.25 * (helper(A - 4, B) + helper(A - 3, B - 1) + helper(A - 2, B -
for r in range(rows): 2) + helper(A - 1, B - 3))
for c in range(cols): memo[(A, B)] = result
row_sky[r] = max(row_sky[r], grid[r][c]) return result
col_sky[c] = max(col_sky[c], grid[r][c])
portions = math.ceil(N / float(25))
increase = 0 if N > 4800: #
return 1
for r in range(rows): return helper(portions, portions)
for c in range(cols):
increase += min(row_sky[r], col_sky[c]) - grid[r][c]
# python_1_to_1000/809_Expressive_Words.py - m
return increase
_author_ = 'jake'
_project_ = 'leetcode'
# python_1_to_1000/808_Soup_Servings.py - m
# https://leetcode.com/problems/expressive-words/
_author_ = 'jake' # Sometimes people repeat letters to represent extra feeling, such as "hello" ->
_project_ = 'leetcode' "heeellooo", "hi" -> "hiiii".
# Here, we have groups, of adjacent letters that are all the same character, and adjacent
# https://leetcode.com/problems/soup-servings/ characters to the group
# There are two types of soup: type A and type B. Initially we have N ml of each type of # are different. A group is extended if that group is length 3 or more, so "e" and "o"
soup. would be extended in the
# There are four kinds of operations: # first example, and "i" would be extended in the second example.
# Serve 100 ml of soup A and 0 ml of soup B # As another example, the groups of "abbcccaaaa" would be "a", "bb", "ccc", and "aaaa";
# Serve 75 ml of soup A and 25 ml of soup B and "ccc" and "aaaa" are the
# Serve 50 ml of soup A and 50 ml of soup B # extended groups of that string.
# Serve 25 ml of soup A and 75 ml of soup B # For some given string S, a query word is stretchy if it can be made to be equal to S by
# When we serve some soup, we give it to someone and we no longer have it. extending some groups.
# Each turn, we will choose from the four operations with equal probability 0.25. # Formally, we are allowed to repeatedly choose a group (as defined above) of characters
# If the remaining volume of soup is not enough to complete the operation, we will serve c, and add some number of the
as much as we can. # same character c to it so that the length of the group is 3 or more.
# We stop once we no longer have some quantity of both types of soup. # Note that we cannot extend a group of size one like "h" to a group of size two like
# Note that we do not have the operation where all 100 ml's of soup B are used first. "hh" - all extensions must leave
# Return the probability that soup A will be empty first, plus half the probability that # the group extended - ie., at least 3 characters long.
A and B become empty at # Given a list of query words, return the number of words that are stretchy.
# the same time.
# Answers within 10^-6 of the true value will be accepted as correct. # Helper function get_groups returns the characters in a word and their group counts, in
order.
# Convert the volume of soup to a number of portions. Given a number of portions of A and # Compare the groups of S with groups of a word. All characters must match and each group
of B, recurse for each of the cannot be larger in word and
# 4 possible operations, sum the results and divide by 4 to get the probability of A # groups cannot be extended to be of length 2.
being empty first. # Time - O(n) total length of all words and S.
# Memoize results to avoid repetition. If N is large enough (4800 found experimentally) # Space - O(s + t) where s = len(s) and t is the max length of any word.
# Return True if and only if Alice wins the game, assuming both players play optimally.
from collections import namedtuple
# If there are an even number of nums and xor is not zero, then there are at least 2
class Solution(object): different nums. Alice can always
def expressiveWords(self, S, words): # remove a number not equal to the xor of all numbers, so the xor will not be zero.
""" # Time - O(n)
:type S: str # Space - O(1)
:type words: List[str]
:rtype: int from functools import reduce
""" import operator
Groups = namedtuple("groups", ["chars", "counts"]) # lists of chars and
their counts class Solution(object):
def xorGame(self, nums):
def get_groups(word): # make Groups for word """
:type nums: List[int]
groups = Groups(chars = [], counts = []) :rtype: bool
count = 1 """
return reduce(operator.xor, nums) == 0 or len(nums) % 2 == 0
for i, c in enumerate(word):

if i == len(word) - 1 or c != word[i + 1]: # python_1_to_1000/811_Subdomain_Visit_Count.py - m


groups.chars.append(c)
groups.counts.append(count) _author_ = 'jake'
count = 1 _project_ = 'leetcode'
else:
count += 1 # https://leetcode.com/problems/subdomain-visit-count/
return groups # 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
result = 0 lowest level,
S_groups = get_groups(S) # "discuss.leetcode.com". When we visit a domain like "discuss.leetcode.com", we will
also visit the parent
for word in words: # domains "leetcode.com" and "com" implicitly.
# Now, call a "count-paired domain" to be a count (representing the number of visits this
word_groups = get_groups(word) domain received), followed
# by a space, followed by the address. An example of a count-paired domain might be "9001
if word_groups.chars != S_groups.chars: # all chars must match discuss.leetcode.com".
continue # We are given a list cpdomains of count-paired domains. We would like a list of count-
paired domains,
for S_count, word_count in zip(S_groups.counts, word_groups.counts): # (in the same format as the input, and in any order), that explicitly counts the number
of visits to each subdomain.
if word_count > S_count: # can only extend word groups
break # Split each cp domain into a count and list of domains. For each list of domains, form
if word_count < S_count and S_count == 2: # cannot externd word group all domains (max 3) as suffixes
to be of length 2 # of the list. Increment counts of all domains. Return list of formatted counts and
break domains.
else: # Time - O(n), since
result += 1 # Space - O(n)

return result from collections import defaultdict

class Solution(object):
def subdomainVisits(self, cpdomains):
"""
# python_1_to_1000/810_Chalkboard_XOR_Game.py - h :type cpdomains: List[str]
:rtype: List[str]
_author_ = 'jake' """
_project_ = 'leetcode' counts = defaultdict(int) # map a domain to its count

# https://leetcode.com/problems/chalkboard-xor-game/ for cpdomain in cpdomains:


# We are given non-negative integers nums[i] which are written on a chalkboard.
# Alice and Bob take turns erasing exactly one number from the chalkboard, with Alice count, domains = cpdomain.split(" ") # split count from domain
starting first. domains = domains.split(".") # split domain to components
# If erasing a number causes the bitwise XOR of all the elements of the chalkboard to
become 0, then that player loses. for i in range(len(domains)):
# Also, we'll say the bitwise XOR of one element is that element itself, and the bitwise domain = ".".join(domains[i:]) # build each suffix of domains
XOR of no elements is 0. counts[domain] += int(count) # increment count
# Also, if any player starts their turn with the bitwise XOR of all the elements of the
chalkboard equal to 0, return [str(count) + " " + domain for domain, count in counts.items()] # format
# then that player wins. result

subarrays

# python_1_to_1000/812_Largest_Triangle_Area.py if (i, k) in memo:


return memo[(i, k)]
_author_ = 'jake'
_project_ = 'leetcode' if k == 1:
memo[(i, k)] = sum(A[:i]) / float(i)
# https://leetcode.com/problems/largest-triangle-area/ return memo[(i, k)]
# You have a list of points in the plane. Return the area of the largest triangle that
can be formed by any best = 0
# 3 of the points. for j in range(k - 1, i): # retains A[:j] for the k - 1 subarrays and
calculate average of suffix
# For each 3 points, use shoelace formula as per best = max(best, helper(j, k - 1) + sum(A[j:i]) / float(i - j))
https://en.wikipedia.org/wiki/Shoelace_formula to calculate area.
# Time - O(n**3) memo[(i, k)] = best
# Space - O(1) return best

class Solution(object): return helper(len(A), K)


def largestTriangleArea(self, points):
"""
:type points: List[List[int]] # python_1_to_1000/814_Binary_Tree_Pruning.py - m
:rtype: float
""" _author_ = 'jake'
n = len(points) _project_ = 'leetcode'
largest = 0
# https://leetcode.com/problems/binary-tree-pruning/
for i in range(n - 2): # We are given the head node root of a binary tree, where additionally every node's value
for j in range(i + 1, n - 1): is either a 0 or a 1.
for k in range(j + 1, n): # Return the same tree where every subtree (of the given tree) not containing a 1 has
x1, y1 = points[i] been removed.
x2, y2 = points[j] # Recall that the subtree of a node X is X, plus every node that is a descendant of X.
x3, y3 = points[k]
# Recursive helper function returns boolean whether tree has a node with val == 1 and
area = 0.5 * abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) also removes subtrees not
largest = max(largest, area) # containing 1.
# Time - O(n)
return largest # Space - O(n)

class Solution(object):
# python_1_to_1000/813_Largest_Sum_of_Averages.py - m def pruneTree(self, root):
"""
_author_ = 'jake' :type root: TreeNode
_project_ = 'leetcode' :rtype: TreeNode
"""
# https://leetcode.com/problems/largest-sum-of-averages/ def contains_one(node):
# We partition a row of numbers A into at most K adjacent (non-empty) groups, then our
score is the sum of the average if not node:
# of each group. What is the largest score we can achieve? return False
# Note that our partition must use every number in A, and that scores are not necessarily left_one, right_one = contains_one(node.left), contains_one(node.right) #
integers. explore and prune children

# Dynamic programming. Base case of k == 1 is the average of the array. For k > 1, try if not left_one: # remove subtrees without 1s
all possible suffix arrays that node.left = None
# leave at least k - 1 elements in the prefix for the remainder. Calculate the average of if not right_one:
the suffix array and add to node.right = None
# recursion result on prefix.
# Time - O(n**2 * k) return node.val == 1 or left_one or right_one # 1 in node or subtrees
# Space - O(n * k)
return root if contains_one(root) else None # handle tree with no 1s
class Solution(object):
def largestSumOfAverages(self, A, K):
""" # python_1_to_1000/815_Bus_Routes.py - h
:type A: List[int]
:type K: int _author_ = 'jake'
:rtype: float _project_ = 'leetcode'
"""
memo = {} # https://leetcode.com/problems/bus-routes/
# We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats
def helper(i, k): # max average for A[:i] partitioned into k forever.
# For example if routes[0] = [1, 5, 7], this means that the first bus (0-th indexed) # We had some 2-dimensional coordinates, like "(1, 3)" or "(2, 0.5)".
travels in the # Then, we removed all commas, decimal points, and spaces, and ended up with the string
# sequence 1->5->7->1->5->7->1->... forever. S.
# We start at bus stop S (initially not on a bus), and we want to go to bus stop T. # Return a list of strings representing all possibilities for what our original
# Travelling by buses only, what is the least number of buses we must take to reach our coordinates could have been.
destination? # Our original representation never had extraneous zeroes, so we never started with
# Return -1 if it is not possible. numbers like "00", "0.0", "0.00",
# "1.0", "001", "00.01", or any other number that can be represented with less digits.
# Bidirectional breadth-first search. # Also, a decimal point within a number never occurs without at least one digit occuring
# Create mapping from each stop to all routes that the stop is on. Maintain front and before it, so we never
back frontiers of stops that # started with numbers like ".1".
# can be reached. Expand the smaller frontier in each round with all stops that have not # The final answer list can be returned in any order.
been visited and are on the # Also note that all coordinates in the final answer have exactly one space between them
# same route as a stop in the current frontier. Terminate when frontiers intersect or one (occurring after the comma.
is empty.
# Time - O(n), number of stops # Split the coordinates into two non-zero pieces where the comma will be inserted. For
# Space - O(n) each piece, calculate a list of
# all possible numbers with a digit.
from collections import defaultdict # If number has leading and trailing zeros zero it can only be zero.
# If a number has a leading zero, it must have a decimal point after the zero.
class Solution(object): # If a number has a trailing zero, it cannot have a decimal point.
def numBusesToDestination(self, routes, S, T): # Else insert the decimal point in all possible places.
""" # Create all possible combinations of the left and right pieces.
:type routes: List[List[int]] # Time - O(n**4), O(n**3) possible coordinates
:type S: int # Space - O(n**4)
:type T: int
:rtype: int class Solution(object):
""" def ambiguousCoordinates(self, S):
routes = [set(route) for route in routes] # convert routes so set for """
faster merging later :type S: str
stop_to_routes = defaultdict(set) # map each stop to set of routes :rtype: List[str]
it is on """

for route, stops in enumerate(routes): def insert_decimal(s): # return list of possible representations of a number
for stop in stops:
stop_to_routes[stop].add(route) if s == "0": # special case of leading and trailing zero
return [s]
front, back = {S}, {T} # frontier sets if s[0] == "0" and s[-1] == "0": # cannot have both leading and trailing
visited = set() # stops that should not be zeros
visited again return []
buses = 0 if s[0] == "0": # cannot have multiple leading zeros before decimal point
return ["0." + s[1:]]
while front and back and not (front & back): # end if either set is empty or if s[-1] == "0": # cannot have any trailing zeros after decimal point
there is intersection return [s]

if len(front) < len(back): # swap to expand smaller set return [s[:i] + "." + s[i:] for i in range(1, len(s))] + [s]
front, back = back, front
S = S[1:-1] # remove brackets
buses += 1 result = []
new_front = set()
visited |= front # add all frontier to visited for i in range(1, len(S)): # insert comma after index i

for stop in front: left = insert_decimal(S[:i])


for route in stop_to_routes[stop]: right = insert_decimal(S[i:])
new_front |= routes[route] # add all stops on the routes result += ["(" + ", ".join([l, r]) + ")" for l in left for r in right]
that stop is on to new_front
return result
front = new_front - visited # remove all visited

return buses if front & back else -1


# python_1_to_1000/817_Linked_List_Components.py - m

_author_ = 'jake'
# python_1_to_1000/816_Ambiguous_Coordinates.py - m _project_ = 'leetcode'

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


_project_ = 'leetcode' # We are given head, the head node of a linked list containing unique integer values.
# We are also given the list G, a subset of the values in the linked list.
# https://leetcode.com/problems/ambiguous-coordinates/ # Return the number of connected components in G, where two values are connected if they

appear consecutively in :type target: int


# the linked list. :rtype: int
"""
# Iterate over list, tracking whether the current node is or is not part of a connected min_steps = {0: 0} # map distance to min steps
component. Every time a new
# connected component starts, increment the count. def helper(dist):
# Time - O(n)
# Space - O(1) if dist in min_steps:
return min_steps[dist]
class Solution(object):
def numComponents(self, head, G): k = dist.bit_length()
""" if 2 ** k - 1 == dist: # k steps reaches target
:type head: ListNode exactly
:type G: List[int] return k
:rtype: int
""" steps = k + 1 + helper(2 ** k - 1 - dist) # k steps goes past target,
H = set(G) # convert to set for O(1) lookup reverse and recurse
for j in range(k - 1): # k - 1 steps, reverse, j
count = 0 steps of acceleration and reverse
connected = False # is there a current connected component? steps = min(steps, k + j + 1 + helper(dist - 2 ** (k - 1) + 2 ** j))

while head: min_steps[dist] = steps


return steps
if head.val in H and not connected: # start new connected component
connected = True return helper(target)
count += 1
elif head.val not in G and connected: # end existing connected component
connected = False # python_1_to_1000/819_Most_Common_Word.py

head = head.next _author_ = 'jake'


_project_ = 'leetcode'
return count
# https://leetcode.com/problems/most-common-word/
# Given a paragraph and a list of banned words, return the most frequent word that is not
# python_1_to_1000/818_Race_Car.py - h in the list of banned words.
# It is guaranteed there is at least one word that isn't banned, and that the answer is
_author_ = 'jake' unique.
_project_ = 'leetcode' # Words in the list of banned words are given in lowercase, and free of punctuation.
# Words in the paragraph are not case sensitive. The answer is in lowercase.
# https://leetcode.com/problems/race-car/
# Your car starts at position 0 and speed +1 on an infinite number line. (Your car can # Split paragraph, convert words to lower case and remove punctuation. Count remaining
go into negative positions.) word frequencies if not banned.
# Your car drives automatically according to a sequence of instructions A (accelerate) # Time - O(n) total length of all words + banned
and R (reverse). # Space - O(n)
# When you get an instruction "A", your car does the following: position += speed, speed
*= 2. from collections import defaultdict
# When you get an instruction "R", your car does the following: if your speed is positive
then speed = -1, class Solution(object):
# otherwise speed = 1. (Your position stays the same.) def mostCommonWord(self, paragraph, banned):
# For example, after commands "AAR", your car goes to positions 0->1->3->3, and your """
speed goes to 1->2->4->-1. :type paragraph: str
# Now for some target position, say the length of the shortest sequence of instructions :type banned: List[str]
to get there. :rtype: str
"""
# After k steps of acceleration, we have travelled 2 ** k - 1 distance. Find k such that banned = set(banned)
distance >= target, punct = {"!", "?", ",", ".", ";", "'"}
# this is the number of bits used in target. counter = defaultdict(int)
# If this distance reaches the target exactly, we cannot do better. Else we either go
past the target, reverse and for word in (s.lower() for s in paragraph.split(" ")):
# recurse for the remaining distance having already moved k + 1 steps, or reverse after k word = "".join(c for c in word if c not in punct)
- 1 steps then accelerate if word not in banned:
# for j steps before reversing again. Memoize results to avoid repetition. counter[word] += 1
# Time - O(n log n) since each distance up to n may be calculated, each taking log n to
iterate over j return max(counter.items(), key=lambda x: x[1])[0] # key with max value
# Space - O(n)

class Solution(object):
def racecar(self, target):
"""
# python_1_to_1000/820_Short_Encoding_of_Words.py - m for i, c in enumerate(S):

_author_ = 'jake' if c == C:
_project_ = 'leetcode' prev_C = i
shortest.append(i - prev_C)
# https://leetcode.com/problems/short-encoding-of-words/
# Given a list of words, we may encode it by writing a reference string S and a list of next_C = float("inf")
indexes A. for i in range(len(S) - 1, -1, -1):
# For example, we can write words ["time", "me", "bell"], as S = "time#bell#" and indexes
= [0, 2, 5]. c = S[i]
# Then for each index, we will recover the word by reading from the reference string from if c == C:
that index until we next_C = i
# reach a "#" character. shortest[i] = min(shortest[i], next_C - i)
# What is the length of the shortest reference string S possible that encodes the given
words? return shortest

# Create the set of required words, initially as all words without duplicates. For each
word, remove all suffixes # python_1_to_1000/822_Card_Flipping_Game.py - m
# fromt the required set. Sum the lengths of all remaining words + 1 char per word for
the sentinel "#". _author_ = 'jake'
# Time - O(nk) for n words of maximum length k _project_ = 'leetcode'
# Space - O(nk)
# https://leetcode.com/problems/card-flipping-game/
class Solution(object): # On a table are N cards, with a positive integer printed on the front and back of each
def minimumLengthEncoding(self, words): card (possibly different).
""" # We flip any number of cards, and after we choose one card.
:type words: List[str] # If the number X on the back of the chosen card is not on the front of any card, then
:rtype: int this number X is good.
""" # What is the smallest number that is good? If no number is good, output 0.
required = set(words) # Here, fronts[i] and backs[i] represent the number on the front and back of card i.
# A flip swaps the front and back numbers, so the value on the front is now on the back
for word in words: # iterate over list, not the required and vice versa.
set
for i in range(1, len(word) - 1): # remove from required any suffix of # Iterate over both lists, finding cards with duplicate number of front and back.
word # Then iterate again, if a pair of numbers are different then each number that is not a
required.discard(word[i:]) # discard() not remove() duplicate can potentially
# be a solution.
return sum(len(w) for w in required) + len(required) # Time - O(n)
# Space - O(n)

# python_1_to_1000/821_Shortest_Distance_to_a_Character.py class Solution(object):


def flipgame(self, fronts, backs):
_author_ = 'jake' """
_project_ = 'leetcode' :type fronts: List[int]
:type backs: List[int]
# https://leetcode.com/problems/shortest-distance-to-a-character/ :rtype: int
# Given a string S and a character C, return an array of integers representing the """
shortest distance from the duplicates = {f for f, b in zip(fronts, backs) if f == b}
# character C in the string. result = float("inf")
# S string length is in [1, 10000].
# C is a single character, and guaranteed to be in string S. for f, b in zip(fronts, backs):
# All letters in S and C are lowercase. if f != b:
if f not in duplicates:
# Iterate from left to right, for each character recording the distance from the previous result = min(result, f)
C. The iterate from right if b not in duplicates:
# to left, updating the distance from the previous C if lower. result = min(result, b)
# Time - O(n)
# Space - O(n) return 0 if result == float("inf") else result

class Solution(object):
def shortestToChar(self, S, C): # python_1_to_1000/823_Binary_Trees_With_Factors.py - m
"""
:type S: str _author_ = 'jake'
:type C: str _project_ = 'leetcode'
:rtype: List[int]
""" # https://leetcode.com/problems/binary-trees-with-factors/
shortest = [] # Given an array of unique integers, each integer is strictly greater than 1.
# We make a binary tree using these integers and each number may be used for any number
prev_C = float("-inf") # index of previous C of times.

# Each non-leaf node's value should be equal to the product of the values of it's :rtype: str
children. """
# How many binary trees can we make? Return the answer modulo 10 ** 9 + 7. S = S.split()
vowels = {"a", "e", "i", "o", "u"}
# Sort the numbers in ascending order. For each num, try all previous nums as a left
child and if we can find for i, word in enumerate(S):
# left child * right child == num then add to the count of trees with num as root each
tree with all possible if word[0].lower() not in vowels:
# combinations of left and right subtrees. S[i] = S[i][1:] + S[i][0]
# Time - O(n**2)
# Space - O(n) S[i] += "ma" + "a" * (i + 1)

from collections import Counter return " ".join(S)

class Solution(object):
def numFactoredBinaryTrees(self, A): # python_1_to_1000/825_Friends_Of_Appropriate_Ages.py - m
"""
:type A: List[int] _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
MOD = 10 ** 9 + 7 # https://leetcode.com/problems/friends-of-appropriate-ages/
num_to_trees = Counter(A) # initially each num is a tree, all nums are # Some people will make friend requests. The list of their ages is given and ages[i] is
unique as per question the age of the ith person.
A.sort() # Person A will NOT friend request person B (B != A) if any of the following conditions
are true:
for i, num in enumerate(A): # age[B] <= 0.5 * age[A] + 7
# age[B] > age[A]
for left in A[:i]: # age[B] > 100 && age[A] < 100
right, remainder = divmod(num, left) # Otherwise, A will friend request B.
if right <= 1: # Note that if A requests B, B does not necessarily request A. Also, people will not
break friend request themselves.
if remainder == 0 and right in num_to_trees: # How many total friend requests are made?
num_to_trees[num] += num_to_trees[left] * num_to_trees[right]
# Group all people of same age together and sort by age. For each age, only consider
return sum(num_to_trees.values()) % MOD younger people. Add to result
# 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)
# python_1_to_1000/824_Goat_Latin.py # Time - O(n**2)
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' from collections import Counter

# https://leetcode.com/problems/goat-latin/ class Solution(object):


# A sentence S is composed of words separated by spaces. Each word consists of lowercase def numFriendRequests(self, ages):
and uppercase letters only. """
# We would like to convert the sentence to "Goat Latin" (a made-up language similar to :type ages: List[int]
Pig Latin.) :rtype: int
# The rules of Goat Latin are as follows: """
# If a word begins with a vowel (a, e, i, o, or u), append "ma" to the end of the word. freq = Counter(ages)
# For example, the word 'apple' becomes 'applema'. age_counts = [(k, v) for k, v in freq.items()]
# If a word begins with a consonant (i.e. not a vowel), remove the first letter and age_counts.sort()
append it to the end, then add "ma". requests = 0
# 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 for a, (age_a, count_a) in enumerate(age_counts):
with 1.
# For example, the first word gets "a" added to the end, the second word gets "aa" added for age_b, count_b in age_counts[:a]: # age_b < age_a
to the end and so on. if age_b > 0.5 * age_a + 7 and (age_b < 100 or age_a > 100):
# Return the final sentence representing the conversion from S to Goat Latin. requests += count_a * count_b

# Split by spaces. If a word does not start with a vowel, move first letter to end of if age_a > 14: # people of same age
word. Append word with "ma" and requests += count_a * (count_a - 1)
# "a" according to index.
# Time - O(n) return requests
# Space - O(n)

class Solution(object): # python_1_to_1000/826_Most_Profit_Assigning_Work.py - m


def toGoatLatin(self, S):
""" _author_ = 'jake'
:type S: str _project_ = 'leetcode'
# https://leetcode.com/problems/most-profit-assigning-work/ class Solution(object):
# We have jobs: difficulty[i] is the difficulty of the ith job, and profit[i] is the def largestIsland(self, grid):
profit of the ith job. """
# Now we have some workers. worker[i] is the ability of the ith worker, which means that :type grid: List[List[int]]
this worker can only complete :rtype: int
# a job with difficulty at most worker[i]. """
# Every worker can be assigned at most one job, but one job can be completed multiple rows, cols = len(grid), len(grid[0])
times. nbors = ((0, 1), (1, 0), (-1, 0), (0, -1))
# For example, if 3 people attempt the same job that pays $1, then the total profit will
be $3. def island(r, c):
# If a worker cannot complete any job, his profit is $0. if r < 0 or r >= rows or c < 0 or c >= cols: # outside grid
# What is the most profit we can make? return 0
if grid[r][c] == 2: # already explored
# Zip the difficulties and profits together then sort to create a list of tuples with return 0
ascending difficulty. if grid[r][c] == 0: # neighbour
# Sort the workers then iterate over workers. For each worker step through the list of edge.add((r, c))
jobs, updating best_profit for return 0
# all jobs that this worker can do. grid[r][c] = 2 # set to visited
# Time - O(mlogm + nlogn) where len(difficulty) == m and len(worker) = n return 1 + sum(island(r + dr, c + dc) for dr, dc in nbors)
# Space - O(m)
cell_to_areas = defaultdict(int) # map each neighbour cell to
class Solution(object): list of areas of islands
def maxProfitAssignment(self, difficulty, profit, worker):
""" for r in range(rows):
:type difficulty: List[int] for c in range(cols):
:type profit: List[int] edge = set()
:type worker: List[int] area = island(r, c)
:rtype: int if area != 0:
""" for cell in edge:
max_profits = list(zip(difficulty, profit)) cell_to_areas[cell] += area
max_profits.sort()
max_profits.append((float("inf"), 0)) if not cell_to_areas: # grid empty or full
return 1 if grid[0][0] == 0 else rows * cols
total_profit = 0 return 1 + max(areas for areas in cell_to_areas.values())
best_profit = 0
i = 0

worker.sort() # python_1_to_1000/828_Unique_Letter_String.py - h
for diff in worker:
_author_ = 'jake'
while max_profits[i][0] <= diff: # all jobs worker can _project_ = 'leetcode'
do
best_profit = max(best_profit, max_profits[i][1]) # update best_profit # https://leetcode.com/problems/unique-letter-string/
i += 1 # A character is unique in string S if it occurs exactly once in it.
total_profit += best_profit # 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.
return total_profit # 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.
# python_1_to_1000/827_Making_A_Large_Island.py - h # If there are two or more equal substrings at different positions in S, we consider them
different.
_author_ = 'jake' # Since the answer can be very large, return the answer modulo 10 ^ 9 + 7.
_project_ = 'leetcode'
# For each letter, make a list of indices in S of the letter. For each in index in each
# https://leetcode.com/problems/making-a-large-island/ list part from the first and
# In a 2D grid of 0s and 1s, we change at most one 0 to a 1. # last, we can make subarrays where the letter is unique with left edges up to the
# After, what is the size of the largest island? (An island is a 4-directionally previous index and right edges up
connected group of 1s). # to the next index.
# Time - O(n)
# For each cell of the grid, find the area of its island and the set of cells # Space - O(n)
neighbouring the island with depth-first
# search. Map each neighbour cell to a list of areas of neighbouring islands. Find the class Solution(object):
cell with the largest sum of def uniqueLetterString(self, S):
# neighbouring islands. """
# Time - O(mn) :type S: str
# Space - O(mn) :rtype: int
"""
from collections import defaultdict unique = 0

indices = [[-1] for _ in range(26)] # Time - O(n)


# Space - O(n)
for i, c in enumerate(S):
indices[ord(c) - ord("A")].append(i) class Solution(object):
def largeGroupPositions(self, S):
for index_list in indices: """
:type S: str
index_list.append(len(S)) :rtype: List[List[int]]
for i in range(1, len(index_list) - 1): """
unique += (index_list[i] - index_list[i - 1]) * (index_list[i + 1] - result = []
index_list[i]) start = 0

return unique % (10 ** 9 + 7) for i, c in enumerate(S):

if i == len(S) - 1 or c != S[i + 1]:


# python_1_to_1000/829_Consecutive_Numbers_Sum.py - h if i - start >= 2:
result.append([start, i])
_author_ = 'jake' start = i + 1 # update start index of next group
_project_ = 'leetcode'
return result
# https://leetcode.com/problems/consecutive-numbers-sum/
# Given a positive integer N, how many ways can we write it as a sum of consecutive
positive integers? # python_1_to_1000/831_Masking_Personal_Information.py - m

# The sum of consecutive numbers (x + 1) + (x + 2) + ... + (x + k) = kx + k(k + 1)//2. _author_ = 'jake'


# We seek k and x to make this equation equal to N. _project_ = 'leetcode'
# Rearranging gives kx = N - k(k + 1)//2. Try all values of k from 1 until the RHS of
this becomes negative. # https://leetcode.com/problems/masking-personal-information/
# We have a solution if the RHS is divisible by k. # We are given a personal information string S, which may represent either an email
# Time - O(sqrt(n)) address or a phone number.
# Space - O(1) # We would like to mask this personal information according to the following rules:
# 1. Email address:
class Solution(object): # We define a name to be a string of length ≥ 2 consisting of only lowercase letters a-z
def consecutiveNumbersSum(self, N): or uppercase letters A-Z.
""" # An email address starts with a name, followed by the symbol '@', followed by a name,
:type N: int followed by the dot '.'
:rtype: int # and followed by a name.
""" # All email addresses are guaranteed to be valid and in the format of
k = 1 # start from sequences of length 1 "[email protected]".
temp = N - ((k + 1) * k) // 2 # RHS of equation # To mask an email, all names must be converted to lowercase and all letters between the
result = 0 first and last letter of the
# first name must be replaced by 5 asterisks '*'.
while temp >= 0: # 2. Phone number:
# A phone number is a string consisting of only the digits 0-9 or the characters from the
if temp % k == 0: # RHS is divisible by k, solution found set {'+', '-', '(', ')', ' '}.
result += 1 # You may assume a phone number contains 10 to 13 digits.
k += 1 # The last 10 digits make up the local number, while the digits before those make up the
temp = N - ((k + 1) * k) // 2 country code.
# Note that the country code is optional. We want to expose only the last 4 digits and
return result mask all other digits.
# 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
# python_1_to_1000/830_Positions_of_Large_Groups.py form "+***-***-***-1111".
# The '+' sign and the first '-' sign before the local number should only exist if there
_author_ = 'jake' is a country code.
_project_ = 'leetcode' # For example, a 12 digit phone number mask should start with "+**-".
# Note that extraneous characters like "(", ")", " ", as well as extra dashes or plus
# https://leetcode.com/problems/positions-of-large-groups/ signs not part of the above
# In a string S of lowercase letters, these letters form consecutive groups of the same # formatting scheme should be removed.
character. # Return the correct "mask" of the information provided.
# For example, a string like S = "abbxxxxzyy" has the groups "a", "bb", "xxxx", "z" and
"yy". # If S contains "@" it is an email. Split email by "@", amend name to first and last
# Call a group large if it has 3 or more characters. Find the starting and ending letters.
positions of every large group. # If phone, retain all digits and split into country (maybe empty) and local.
# The final answer should be in lexicographic order. # Time - O(n)
# Space - O(n)
# Iterate over S. When the next char is different from the previous char, add to the
result if the group length >= 3. class Solution(object):
def maskPII(self, S): "cd", y = "ffff", then
""" # because "cd" starts at position 2 in the original string S, we will replace it with
:type S: str "ffff".
:rtype: str # Using another example on S = "abcd", if we have both the replacement operation i = 0, x
""" = "ab", y = "eee",
if "@" in S: # as well as another replacement operation i = 2, x = "ec", y = "ffff", this second
name, address = S.lower().split("@") operation does nothing because in
return name[0] + "*****" + name[-1] + "@" + address # 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
digits = [c for c in S if "0" <= c <= "9"] # remove all non-digits overlap in replacement:
country, local = digits[:-10], digits[-10:] # split country and local # for example, S = "abc", indexes = [0, 1], sources = ["ab","bc"] is not a valid test
numbers case.
result = []
if country: # Convert to mutable list of chars. For each index, if substring string of length source
result = ["+"] + ["*"] * len(country) + ["-"] # masked country with "+" is same as source string,
prefix # replace the first char with the target and remaining chars of source with empty
result += ["***-***-"] + local[-4:] # masked local apart from strings.
last 4 digits # Time - O(min(k, nm)) for n replacements of max length m, len(S) == k
return "".join(result) # Space - O(k + mn)

class Solution(object):
def findReplaceString(self, S, indexes, sources, targets):
# python_1_to_1000/832_Flipping_an_Image.py """
:type S: str
_author_ = 'jake' :type indexes: List[int]
_project_ = 'leetcode' :type sources: List[str]
:type targets: List[str]
# https://leetcode.com/problems/flipping-an-image/ :rtype: str
# Given a binary matrix A, we want to flip the image horizontally, then invert it, and """
return the resulting image. replaced = [c for c in S] # convert to list
# To flip an image horizontally means that each row of the image is reversed.
# For example, flipping [1, 1, 0] horizontally results in [0, 1, 1]. for i, src, tgt in zip(indexes, sources, targets):
# To invert an image means that each 0 is replaced by 1, and each 1 is replaced by 0.
# For example, inverting [0, 1, 1] results in [1, 0, 0]. n = len(src)
if S[i:i + n] == src:
# Reverse each row set each value to 1 - value so 0 becomes 1 and 1 becomes 0. replaced[i] = tgt
# Time - O(mn) replaced[i + 1:i + n] = [""] * (n - 1)
# Space - O(mn)
return "".join(replaced)
class Solution(object):
def flipAndInvertImage(self, A):
""" # python_1_to_1000/834_Sum_of_Distances_in_Tree.py - h
:type A: List[List[int]]
:rtype: List[List[int]] _author_ = 'jake'
""" _project_ = 'leetcode'
result = []
# https://leetcode.com/problems/sum-of-distances-in-tree/
for row in A: # An undirected, connected tree with N nodes labelled 0...N-1 and N-1 edges are given.
result.append([1 - val for val in reversed(row)]) # The ith edge connects nodes edges[i][0] and edges[i][1] together.
# Return a list ans, where ans[i] is the sum of the distances between node i and all
return result other nodes.

# Create map from node to neighbours. Depth-first search from node 0, counting the number
of nodes in each subtree and
# python_1_to_1000/833_Find_And_Replace_in_String.py - m # calculating the distance from each root to all nodes in subtree. The distances from
node 0 is then correct.
_author_ = 'jake' # Depth-first search again, calculating the distance to every child as the parent
_project_ = 'leetcode' distance minus 1 for every node in
# the subtree (which is now closer), plus 1 for every node not in subtree (which is now
# https://leetcode.com/problems/find-and-replace-in-string/ further away).
# To some string S, we will perform some replacement operations that replace groups of # Time - O(n)
letters with new ones # Space - O(n)
# (not necessarily the same size).
# Each replacement operation has 3 parameters: a starting index i, a source word x and a from collections import defaultdict
target word y.
# The rule is that if x starts at position i in the original string S, then we will class Solution(object):
replace that occurrence of x with y. def sumOfDistancesInTree(self, N, edges):
# If not, we do nothing. """
# For example, if we have S = "abcd" and we have some replacement operation i = 2, x = :type N: int

:type edges: List[List[int]] for i, bit in enumerate(reversed(row)):


:rtype: List[int] if bit == 1:
""" num += (bit << i)
neighbours = defaultdict(set) # map node to set of neighbours bits.append(num)
for a, b in edges: return bits
neighbours[a].add(b)
neighbours[b].add(a) A_bits, B_bits = image_to_bits(A), image_to_bits(B)
rows, cols = len(A), len(A[0])
subtree_counts = [1] * N # number of nodes in subtree with max_overlap = 0
node i as roor
distances = [0] * N for slide, static in ((A_bits, B_bits), (B_bits, A_bits)): # keep one image
static and slide the other
def subtree_distances(node, parent): for row_shift in range(rows):
for child in neighbours[node]: for col_shift in range(cols):
if child != parent: # graph is undirected, do not go back
to parent overlap = 0
subtree_distances(child, node) for slide_row in range(rows - row_shift): # the numebr of rows
subtree_counts[node] += subtree_counts[child] to slide
distances[node] += distances[child] + subtree_counts[child] # each shifted = slide[slide_row] >> col_shift # right shift the
node in subtree is 1 unit further bits in this row
row_and = bin(shifted & static[slide_row + row_shift]) # AND
def update_distances(node, parent): with the static row
for child in neighbours[node]: overlap += row_and.count("1") # count the mutual
if child != parent: set bits
distances[child] = distances[node] - subtree_counts[child] + (N -
subtree_counts[child]) max_overlap = max(max_overlap, overlap)
update_distances(child, node)
return max_overlap
subtree_distances(0, None)
update_distances(0, None)
return distances # python_1_to_1000/836_Rectangle_Overlap.py

_author_ = 'jake'
# python_1_to_1000/835_Image_Overlap.py - m _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/rectangle-overlap/


_project_ = 'leetcode' # A rectangle is represented as a list [x1, y1, x2, y2], where (x1, y1) are the
coordinates of its bottom-left corner,
# https://leetcode.com/problems/image-overlap/ # and (x2, y2) are the coordinates of its top-right corner.
# Two images A and B are given, represented as binary, square matrices of the same size # Two rectangles overlap if the area of their intersection is positive.
# A binary matrix has only 0s and 1s as values. # To be clear, two rectangles that only touch at the corner or edges do not overlap.
# We translate one image however we choose (sliding it left, right, up, or down any # Given two (axis-aligned) rectangles, return whether they overlap.
number of units), and place it on
# top of the other image. After, the overlap of this translation is the number of # Find overlap distance in x direction as the overlap of 2 line segments. If positive,
positions that are 1 in both images. check overlap in y direction.
# What is the largest possible overlap? # Time - O(1)
# Space - O(1)
# Convert each 2-d image to a 1-d list of integers. Each integer represents a row, where
setting the ith bit of the class Solution(object):
# integer means the pixel at row[i] is set in the image. def isRectangleOverlap(self, rec1, rec2):
# Then slide each image to all possible positions relative to the other image. For each """
overlapping row, right shift the :type rec1: List[int]
# integer representation of the slide row by the row shift, perform the logical AND with :type rec2: List[int]
the static row and count the :rtype: bool
# set bits. """
# Time - O(n**3) x_overlap = min(max(0, rec1[2] - rec2[0]), max(0, rec2[2] - rec1[0]))
# Space - O(n) if x_overlap == 0:
return False
class Solution(object):
def largestOverlap(self, A, B): return min(max(0, rec1[3] - rec2[1]), max(0, rec2[3] - rec1[1])) > 0
"""
:type A: List[List[int]]
:type B: List[List[int]] # python_1_to_1000/837_New_21_Game.py - m
:rtype: int
""" _author_ = 'jake'
def image_to_bits(image): # convert each row to an integer _project_ = 'leetcode'
bits = []
for row in image: # https://leetcode.com/problems/new-21-game/
num = 0 # 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. # closest "L" and iterating left to right. Then each domino that has not fallen falls
# During each draw, she gains an integer number of points randomly from the range [1, W], according to whether an "R" or
where W is an integer. # "L" that can impact it is closer.
# Each draw is independent and the outcomes have equal probabilities. # Time - O(n)
# Alice stops drawing numbers when she gets K or more points. What is the probability # Space - O(n)
that she has N or less points?
class Solution(object):
# Maintain the sum of the probabilities being at all numbers that can reach the next def pushDominoes(self, dominos):
number. Update the next i as the """
# window divided by W since each number in window has 1/W probability of moving to i. Add :type dominos: str
to window with new :rtype: str
# probability and remove probability from front of window. """
# Time - O(N) prev_R = float("-inf") # current index of previous "R"
# Space - O(N) rights = [] # indices of previous "R" on the left of each
domino
class Solution(object): for i, c in enumerate(dominos):
def new21Game(self, N, K, W): rights.append(prev_R)
""" if c == "R": # new prev_R
:type N: int prev_R = i
:type K: int elif c == "L": # no "R" can reach this domino
:type W: int prev_R = float("-inf")
:rtype: float
""" prev_L = float("inf") # current index of previous "L"
if K == 0 or N >= K + W: # no draws or every reachable number <= N lefts = [0] * len(dominos) # indices of previous "L" on the right of
return 1 each domino
for i in range(len(dominos) - 1, -1, -1):
probability = [0] * (N + 1) lefts[i] = prev_L
probability[0] = 1.0 if dominos[i] == "L": # new prev_L
window = 1.0 # sum of probabilities of numbers that can reach prev_L = i
next number elif dominos[i] == "R": # no "L" can reach this domino
prev_L = float("inf")
for i in range(1, N + 1):
dominos = [c for c in dominos]
probability[i] = window / W # 1 / W times the probability of each number that for i in range(len(dominos)):
can reach i if dominos[i] == ".": # not fallen already
if i < K: diff = (lefts[i] - i) - (i - rights[i]) # closest falling domino,
window += probability[i] # add to window negative for left, pos for right
if i - W >= 0: if diff < 0:
window -= probability[i - W] # drop out from window dominos[i] = "L"
elif diff > 0:
return sum(probability[K:]) dominos[i] = "R"

return "".join(dominos)
# python_1_to_1000/838_Push_Dominoes.py - m

_author_ = 'jake' # python_1_to_1000/839_Similar_String_Groups.py - h


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/push-dominoes/ _project_ = 'leetcode'
# 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 # https://leetcode.com/problems/similar-string-groups/
the right. # Two strings X and Y are similar if we can swap two letters (in different positions) of
# After each second, each domino that is falling to the left pushes the adjacent domino X, so that it equals Y.
on the left. # For example, "tars" and "rats" are similar (swapping at positions 0 and 2), and "rats"
# Similarly, the dominoes falling to the right push their adjacent dominoes standing on and "arts" are similar,
the right. # but "star" is not similar to "tars", "rats", or "arts".
# When a vertical domino has dominoes falling on it from both sides, it stays still due # Together, these form two connected groups by similarity: {"tars", "rats", "arts"} and
to the balance of the forces. {"star"}.
# For the purposes of this question, we will consider that a falling domino expends no # Notice that "tars" and "arts" are in the same group even though they are not similar.
additional force to a falling # Formally, each group is such that a word is in the group if and only if it is similar
# or already fallen domino. to at least one other
# Given a string "S" representing the initial state. S[i] = 'L', if the i-th domino has # word in the group.
been pushed to the left; # We are given a list A of strings. Every string in A is an anagram of every other string
# S[i] = 'R', if the i-th domino has been pushed to the right; S[i] = '.', if the i-th in A. Count the groups.
domino has not been pushed.
# Return a string representing the final state. # For each word, depth-first search all similar words to visit all words in a group. 2
different approaches are taken
# Iterate over dominos from right to left, for each domino finding the closest "R" that # to find similar words depensing whether there are few long words or many short words.
reach this domino. Repeat for # If few long words, create a mapping from each word to the set of its similar words.

Mapping is made by iterating over each row, column,


# all pairs of words and checking if similar. # and both diagonals all have the same sum.
# If many short words, find similar words by swapping all pairs of characters in a word. # Given an grid of integers, how many 3 x 3 "magic square" subgrids are there? (Each
# Time - O(min(W N**2, N W**3) subgrid is contiguous).
# Space - O(N W**3) since each word may have W**2 neighbours
# Iterate over all possible top left corners of 3 x 3 squares. Reject if centre is not 5
from collections import defaultdict or any number outside [0, 9].
# In each square, sum the rows, columns and diagonals.
class Solution(object): # Time - O(mn)
def numSimilarGroups(self, A): # Space - O(1)
"""
:type A: List[str] class Solution(object):
:rtype: int def numMagicSquaresInside(self, grid):
""" """
N, W = len(A), len(A[0]) :type grid: List[List[int]]
word_swap = defaultdict(set) :rtype: int
"""
if N < 2 * W: # if few long words def is_magic(row, col):

for i, w1 in enumerate(A): if grid[row + 1][col + 1] != 5: # centre must be 5


for j in range(i + 1, len(A)): return False
w2 = A[j]
if len([True for c1, c2 in zip(w1, w2) if ord(c1) - ord(c2) != 0]) == line_sums = [0 for _ in range(6)] # line_sums[:3] are sums of rows,
2: line_sums[3:] are sums of cols
word_swap[w1].add(w2) diag1, diag2 = 0, 0 # descending and ascending diagonal
word_swap[w2].add(w1)
else: for dr in range(3):
A_set = set(A) for dc in range(3):

def get_neighbours(a): val = grid[row + dr][col + dc]


if word_swap: if val < 1 or val > 9: # reject if number outside range
return word_swap[a] return False
neighbours = set()
for i in range(W - 1): line_sums[dr] += val # incerement all sums using this cell
for j in range(i + 1, W): line_sums[dc + 3] += val
if a[i] != a[j]: if dr == dc:
neighbour = a[:i] + a[j] + a[i + 1:j] + a[i] + a[j + 1:] diag1 += val
if neighbour in A_set: if dr + dc == 2:
neighbours.add(neighbour) diag2 += val

return neighbours if any(line_sum != 15 for line_sum in line_sums):


return False
groups = 0 if diag1 != 15 or diag2 != 15:
visited = set() return False
return True
def dfs(w):
visited.add(w) rows, cols = len(grid), len(grid[0])
for nbor in get_neighbours(w): magic = 0
if nbor not in visited:
dfs(nbor) for r in range(rows - 2):
for c in range(cols - 2):
for word in A: magic += is_magic(r, c)
if word in visited:
continue return magic
groups += 1
dfs(word)
# python_1_to_1000/841_Keys_and_Rooms.py - m
return groups
_author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/keys-and-rooms/
# python_1_to_1000/840_Magic_Squares_In_Grid.py - m # 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
_author_ = 'jake' # have some keys to access the next room.
_project_ = 'leetcode' # 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]
# https://leetcode.com/problems/magic-squares-in-grid/ # where N = rooms.length. A key rooms[i][j] = v opens the room with number v.
# A 3 x 3 magic square is a 3 x 3 grid filled with distinct numbers from 1 to 9 such that # Initially, all the rooms start locked (except for room 0).
# You can walk back and forth between rooms freely.
# Return true if and only if you can enter every room. next_num = fib[-1] + fib[-2]
if next_num > MAX_NUM:
# Depth-first search from the first room, recursively visiting all reachable rooms and return []
ignoring those already visited. next_str = str(next_num)
# Time - O(n) if S[i:i + len(next_str)] != next_str: # next_str must match the next
# Space - O(n) part of S
return []
class Solution(object): fib.append(next_num)
def canVisitAllRooms(self, rooms): i += len(next_str)
"""
:type rooms: List[List[int]] return fib
:rtype: bool
""" for len1 in range(1, (len(S) + 1) // 2):
visited = set()
if len1 > 1 and S[0] == "0": # no leading zero unless zero
def dfs(room): return []
n1 = int(S[:len1])
if room in visited: if n1 > MAX_NUM:
return return []
visited.add(room)
for key in rooms[room]: len2 = 1
dfs(key) while len(S) - len1 - len2 >= max(len1, len2):

dfs(0) if len2 > 1 and S[len1] == "0": # no leading zero unless zero
return len(visited) == len(rooms) break
n2 = int(S[len1:len1 + len2])
if n2 > MAX_NUM:
# python_1_to_1000/842_Split_Array_into_Fibonacci_Sequence.py - m break

_author_ = 'jake' fibonacci = helper(len1 + len2, n1, n2)


_project_ = 'leetcode' if fibonacci:
return fibonacci
# https://leetcode.com/problems/split-array-into-fibonacci-sequence/ len2 += 1
# Given a string S of digits, such as S = "123456579", we can split it into a Fibonacci-
like sequence [123, 456, 579]. return []
# Formally, a Fibonacci-like sequence is a list F of non-negative integers such that:
# 0 <= F[i] <= 2^31 - 1, (that is, each integer fits a 32-bit signed integer type);
# F.length >= 3; # python_1_to_1000/843_Guess_the_Word.py - h
# and F[i] + F[i+1] = F[i+2] for all 0 <= i < F.length - 2.
# Also, note that when splitting the string into pieces, each piece must not have extra _author_ = 'jake'
leading zeroes, _project_ = 'leetcode'
# except if the piece is the number 0 itself.
# Return any Fibonacci-like sequence split from S, or return [] if it cannot be done. # https://leetcode.com/problems/guess-the-word/
# This problem is an interactive problem new to the LeetCode platform.
# Try all possible lengths of starting number. Max starting number length is less than # We are given a word list of unique words, each word is 6 letters long, and one word in
half the length of S to allow this list is chosen as secret.
# a sequence of at least 3 numbers. Try all possible lengths of second number, allowing # You may call master.guess(word) to guess a word.
for the remaining string to # The guessed word should have type string and must be from the original list with 6
# be at least as long as the longets of the 2 numbers. Attempt to build a sequence for lowercase letters.
the remainder of S given # This function returns an integer type, representing the number of exact matches (value
# the first 2 numbers. and position) of your guess
# Time - O(n**2) # to the secret word. Also, if your guess is not in the given wordlist, it will return
# Space - O(n) -1 instead.
# For each test case, you have 10 guesses to guess the word. At the end of any number of
class Solution(object): calls, if you have made 10
def splitIntoFibonacci(self, S): # or less calls to master.guess and at least one of these guesses was the secret, you
""" pass the testcase.
:type S: str # Besides the example test case below, there will be 5 additional test cases, each with
:rtype: List[int] 100 words in the word list.
""" # The letters of each word in those testcases were chosen independently at random from
MAX_NUM = 2 ** 31 - 1 'a' to 'z',
# such that every word in the given word lists is unique.
def helper(i, n1, n2): # build sequence from S[i] onwards starting with
n1 and n2 # Repeatedly choose a word to guess and eliminate all words that do not have the same
number of matches as the
fib = [n1, n2] # chosen word. Words are chosen so they have maximum overlap (same chars in same
positions) with other words.
while i < len(S): # This reduces candidate list more than choosing a random word which may not overlap with

any other words and so delete = delete + 1 if string[i] == "#" else delete - 1
# does not allow any other words to be eliminated. i -= 1
# Time - O(n) return i
# Space - O(n)
while True:
class Solution(object):
def findSecretWord(self, wordlist, master): s_i = next_char(S, s_i)
""" t_i = next_char(T, t_i)
:type wordlist: List[Str]
:type master: Master if s_i == -1 and t_i == -1: # both strings ended
:rtype: None return True
""" if s_i == -1 or t_i == -1: # one string ended
def pair_matches(a, b): # count the number of matching characters return False
return sum(c1 == c2 for c1, c2 in zip(a, b)) if S[s_i] != T[t_i]: # chars do not match
return False
def most_overlap_word():
counts = [collections.defaultdict(int) for _ in range(6)] # counts[i] maps s_i -= 1 # move to next chars
chars to count of words with char at index i t_i -= 1
for word in candidates:
for i, c in enumerate(word):
counts[i][c] += 1 # all words with same # python_1_to_1000/845_Longest_Mountain_in_Array.py - m
chars in same positions
_author_ = 'jake'
return max(candidates, key=lambda x:sum(counts[i][c] for i, c in _project_ = 'leetcode'
enumerate(x)))
# https://leetcode.com/problems/longest-mountain-in-array/
candidates = wordlist[:] # all remaining candidates, initially all words # Let's call any (contiguous) subarray B (of A) a mountain if the following properties
while candidates: hold:
# B.length >= 3
s = most_overlap_word() # guess the word that overlaps with most others # There exists some 0 < i < B.length - 1 such that B[0] < B[1] < ... B[i-1] < B[i] >
matches = master.guess(s) B[i+1] > ... > B[B.length - 1]
# (Note that B could be any subarray of A, including the entire array A.)
if matches == 6: # Given an array A of integers, return the length of the longest mountain.
return # Return 0 if there is no mountain.

candidates = [w for w in candidates if pair_matches(s, w) == matches] # # Iterate over A, comparing successive difference between points. Track the last valley
filter words with same matches where a mountain starts and
# the peak of the last mountain.
# Time - O(n)
# Space - O(1)
# python_1_to_1000/844_Backspace_String_Compare.py
class Solution(object):
_author_ = 'jake' def longestMountain(self, A):
_project_ = 'leetcode' """
:type A: List[int]
# https://leetcode.com/problems/backspace-string-compare/ :rtype: int
# Given two strings S and T, return if they are equal when both are typed into empty text """
editors. valley, peak = 0, 0
# "#" means a backspace character. prev = 0 # previous difference: 0 == same, +1 == up, -1 ==
down
# Start at the ends of both strings. Step backwards to find the next non-deleted chars in longest = 0
both strings. Increment the
# chars to be deleted when "#" is seen, else decrement the number of chars to be deleted. for i in range(1, len(A)):
# Time - O(max(m, n))
# Space - O(1) if A[i] == A[i - 1]: # if same, reset valley and peak to this index
valley, peak = i, i
class Solution(object): prev = 0
def backspaceCompare(self, S, T):
""" elif A[i] > A[i - 1]:
:type S: str if prev == 1: # new peak
:type T: str peak = i
:rtype: bool else: # previous index was valley
""" valley = i - 1
s_i, t_i = len(S) - 1, len(T) - 1 prev = 1

def next_char(string, i): # finds index of next char not deleted elif A[i] < A[i - 1]:
delete = 0 if prev == 1: # previous index was peak
while i >= 0 and (delete or string[i] == "#"): # while more chars to be peak = i - 1
deleted longest = max(longest, i - valley + 1)
else: # more recent peak than valley makes a mountain
if peak > valley: # https://leetcode.com/problems/shortest-path-visiting-all-nodes/
longest = max(longest, i - valley + 1) # An undirected, connected graph of N nodes (labeled 0, 1, 2, ..., N-1) is given as
prev = -1 graph.
# graph.length = N, and j != i is in the list graph[i] exactly once, if and only if nodes
return longest i and j are connected.
# 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
# python_1_to_1000/846_Hand_of_Straights.py - m reuse edges.

_author_ = 'jake' # Breadth-first search. States consist of (visited, node) where node is the most recent
_project_ = 'leetcode' node and visited is an
# integer with a bit set for every node visited. Expand frontier by visiting all
# https://leetcode.com/problems/hand-of-straights/ neighbours of each node of each
# Alice has a hand of cards, given as an array of integers. # state. Only consider states not visited already.
# Now she wants to rearrange the cards into groups so that each group is size W, and # Time - O(n * 2**n) the number of possible states, since 2**n possible values for
consists of W consecutive cards. visited and n values for node
# Return true if and only if she can. # Space - O(n * 2**n)

# Sort the integers. Maintain a heap of partial straights. For each integer, if it's the class Solution(object):
same as the end of partial def shortestPathLength(self, graph):
# straight with the lowest end integer, start another partial straight. If it's more than """
1 + the end of the first :type graph: List[List[int]]
# partial straight, this straight cannot be completed. Else extend the straight and :rtype: int
complete it if length W. """
# Time - O(n log n) if len(graph) == 0 or len(graph[0]) == 0:
# Space - O(n) return 0

import heapq n = len(graph)


frontier = {(1 << node, node) for node in range(n)} # set the bit for each
class Solution(object): node
def isNStraightHand(self, hand, W): visited = set(frontier)
""" distance = 0
:type hand: List[int]
:type W: int while True:
:rtype: bool
""" new_frontier = set()
if len(hand) % W != 0: # cannot make a whole number of straights
return False for bit_nodes, node in frontier:
if W == 1:
return True if bit_nodes == 2 ** n - 1: # all nodes visited
return distance
hand.sort()
partials = [] # heap of partial straights (last integer, straight for nbor in graph[node]:
length)
new_bit_nodes = bit_nodes | 1 << nbor # set bit for nbor
for num in hand: if (new_bit_nodes, nbor) not in visited:
new_frontier.add((new_bit_nodes, nbor))
if not partials or partials[0][0] == num: # start a new straight
heapq.heappush(partials, (num, 1)) visited |= new_frontier # update visited
continue distance += 1
frontier = new_frontier
if num > partials[0][0] + 1: # gap between num and end of
first stright cannot be filled
return False # python_1_to_1000/848_Shifting_Letters.py - m

end, length = heapq.heappop(partials) # num == partials[0][0] + 1, _author_ = 'jake'


extend straight _project_ = 'leetcode'
if length != W - 1:
heapq.heappush(partials, (num, length + 1)) # https://leetcode.com/problems/shifting-letters/
# We have a string S of lowercase letters, and an integer array shifts.
return not partials # Call the shift of a letter, the next letter in the alphabet, (wrapping around so that
'z' becomes 'a').
# 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.
# python_1_to_1000/847_Shortest_Path_Visiting_All_Nodes.py - h # Return the final string after all such shifts to S are applied.

_author_ = 'jake' # Iterate backwards over shifts. Maintain the cumulative_shift, adding each shift and
_project_ = 'leetcode' shifting the char by the

# cumulative_shift. seat_i, left_distance = empty_seats.pop()


# Time - O(n) max_distance = max(max_distance, left_distance)
# Space - O(n)
return max_distance
class Solution(object):
def shiftingLetters(self, S, shifts):
""" # python_1_to_1000/850_Rectangle_Area_II.py - h
:type S: str
:type shifts: List[int] _author_ = 'jake'
:rtype: str _project_ = 'leetcode'
"""
s = [ord(c) - ord("a") for c in S] # convert to list of integers in # https://leetcode.com/problems/rectangle-area-ii/
[0, 25] # We are given a list of (axis-aligned) rectangles. Each rectangle[i] = [x1, y1, x2,
y2], where (x1, y1) are the
cumulative_shift = 0 # coordinates of the bottom-left corner, and (x2, y2) are the coordinates of the top-
for i in range(len(s) - 1, -1, -1): right corner of the ith rectangle.
cumulative_shift += shifts[i] # Find the total area covered by all rectangles in the plane.
s[i] = (s[i] + cumulative_shift) % 26 # apply cumulative_shift to char # Since the answer may be too large, return it modulo 10^9 + 7.

return "".join(chr(c + ord("a")) for c in s) # 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.
# python_1_to_1000/849_Maximize_Distance_to_Closest_Person.py - m Update the set of rectangles
# alive at x, then create a sorted list of y direction edges of alive rectangles. Iterate
_author_ = 'jake' along the y edges, updating
_project_ = 'leetcode' # the y length between y edges provided some rectangle is alive.
# Time - O(n**2 log n)
# https://leetcode.com/problems/maximize-distance-to-closest-person/ # Space - O(n)
# In a row of seats, 1 represents a person sitting in that seat, and 0 represents that
the seat is empty. class Solution(object):
# There is at least one empty seat, and at least one person sitting. def rectangleArea(self, rectangles):
# Alex wants to sit in the seat such that the distance between him and the closest person """
to him is maximized. :type rectangles: List[List[int]]
# Return that maximum distance to closest person. :rtype: int
"""
# Iterate over seats, maintaining a list of empty seats as tuples of (index of empty x_events = [] # edges of rectangles along x axis (x, start,
seat, distance to seat on left). index)
# If a seat is occupied, update max_distance for each empty seat with the minimum of the for i, (x1, y1, x2, y2) in enumerate(rectangles):
distances to its left and x_events.append((x1, True, i))
# right occupied seats. Else add to the list of empty seats if max_distance could be x_events.append((x2, False, i))
improved. x_events.sort()
# Time - O(n)
# Space - O(1) area = 0
alive = set() # all rectangle indices currently alive at
class Solution(object): this value of x
def maxDistToClosest(self, seats): y_coverage = 0 # the length covered by rectangle in y
""" direction
:type seats: List[int] x_prev = 0
:rtype: int
""" for x, start, i in x_events:
empty_seats = []
max_distance = 0 area += (x - x_prev) * y_coverage # update the area as the distance since
last_seat = float("-inf") previous x * y length covered
x_prev = x
for i, seat in enumerate(seats):
if start: # update the alive set for this edge
if seat == 1: # occupied, update alive.add(i)
max_distance for all empty_seats else:
while empty_seats: alive.discard(i)
seat_i, left_distance = empty_seats.pop()
max_distance = max(max_distance, min(left_distance, i - seat_i)) y_events = [] # edges of alive rectangles along y axis
last_seat = i for i in alive:
y_events.append((rectangles[i][1], 1)) # opening edge
elif i - last_seat > max_distance: # add to empty_seats if y_events.append((rectangles[i][3], -1)) # closing edge
max_distance can be improved y_events.sort()
empty_seats.append((i, i - last_seat))
y_coverage = 0
while empty_seats: # remaining seats have no prev_y = 0
occupied seat on right alive_y = 0 # count of open rectangles
for y, start_y in y_events: for i in range(n):
update_results(i)
if alive_y > 0: # some rectangle(s) are alive so cover length
since previous y return result
y_coverage += y - prev_y

alive_y += start_y # increment or decrement the alive count


prev_y = y # python_1_to_1000/852_Peak_Index_in_a_Mountain_Array.py - m

return area % (10 ** 9 + 7) _author_ = 'jake'


_project_ = 'leetcode'

# https://leetcode.com/problems/peak-index-in-a-mountain-array/
# Let's call an array A a mountain if the following properties hold:
# python_1_to_1000/851_Loud_and_Rich.py - m # A.length >= 3
# There exists some 0 < i < A.length - 1 such that A[0] < A[1] < ... A[i-1] < A[i] >
_author_ = 'jake' A[i+1] > ... > A[A.length - 1]
_project_ = 'leetcode' # Given an array that is definitely a mountain, return any i such that
# A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1].
# https://leetcode.com/problems/loud-and-rich/
# In a group of N people (labelled 0, 1, 2, ..., N-1), each person has different amounts # Binary search for the first index where the number at the next element is lower.
of money, # Time - O(log n)
# and different levels of quietness. # Space - O(l)
# For convenience, we'll call the person with label x, simply "person x".
# We'll say that richer[i] = [x, y] if person x definitely has more money than person y. class Solution(object):
# Note that richer may only be a subset of valid observations. def peakIndexInMountainArray(self, nums):
# Also, we'll say quiet[x] = q if person x has quietness q. """
# Now, return answer, where answer[x] = y if y is the least quiet person (that is, the :type A: List[int]
person y with the smallest :rtype: int
# value of quiet[y]), among all people who definitely have equal to or more money than """
person x. left, right = 1, len(nums) - 2

# Create graph mapping people to richer people. For each person, depth-first search the while left < right:
graph, first updating the
# results of all richer people, then if any richer people have a quieter result, update mid = (left + right) // 2
the result of the person.
# Time - O(m + n), number of richer relationships + number of people if nums[mid + 1] < nums[mid]:
# Space - O(m + n) right = mid
else:
class Solution(object): left = mid + 1
def loudAndRich(self, richer, quiet):
""" return left
:type richer: List[List[int]]
:type quiet: List[int]
:rtype: List[int] # python_1_to_1000/853_Car_Fleet.py - m
"""
n = len(quiet) _author_ = 'jake'
richer_than = [set() for _ in range(n)] # map person to richer people _project_ = 'leetcode'

for a, b in richer: # https://leetcode.com/problems/car-fleet/


richer_than[b].add(a) # N cars are going to the same destination along a one lane road. The destination is
target miles away.
result = [None] * n # Each car i has a constant speed speed[i] (in miles per hour), and initial position
position[i] miles towards the
def update_results(person): # target along the road.
# A car can never pass another car ahead of it, but it can catch up to it, and drive
if result[person] is not None: # already found result bumper to bumper at the same speed.
return # The distance between these two cars is ignored - they are assumed to have the same
position.
result[person] = person # default to self # A car fleet is some non-empty set of cars driving at the same position and same speed.
# Note that a single car is also a car fleet.
for rich in richer_than[person]: # If a car catches up to a car fleet right at the destination point, it will still be
update_results(rich) # update the results for richer considered as one car fleet.
people # How many car fleets will arrive at the destination?
if quiet[result[rich]] < quiet[result[person]]: # if quiet is lower for
result of richer ... # Sort the cars in decreasing order of position. Iterate over the cars. If a car arrives
result[person] = result[rich] # ... then result of this person is after the previous car it
result of richer person # forms a new fleet.
# Time - O(n log n)

# Space - O(n) i += 1

class Solution(object): for j in range(i + 1, len(A)):


def carFleet(self, target, position, speed):
""" if word[j] != B[i]: # reject if word[j] is not the the
:type target: int letter we need at word[i]
:type position: List[int] continue
:type speed: List[int] swapped = word[:i] + word[j] + word[i + 1:j] + word[i] + word[j + 1:]
:rtype: int # swap word[i], word[j]
""" new_frontier.add(swapped)
fleets = 0
previous = -1 # time of arrival of previous car at target k += 1
visited |= frontier # add old frontier to visited
cars = zip(position, speed) frontier = new_frontier
cars.sort(reverse = True) # greatest distance first

for pos, spd in cars:


# python_1_to_1000/855_Exam_Room.py - m
time = (target - pos) / float(spd) # time of arrival at target
if time > previous: _author_ = 'jake'
fleets += 1 _project_ = 'leetcode'
previous = time # new later time of arrival
# https://leetcode.com/problems/exam-room/
return fleets # In an exam room, there are N seats in a single row, numbered 0, 1, 2, ..., N-1.
# When a student enters the room, they must sit in the seat that maximizes the distance
to the closest person.
# python_1_to_1000/854_K-Similar_Strings.py - m # 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.
_author_ = 'jake' # Return a class ExamRoom(int N) that exposes two functions: ExamRoom.seat() returning an
_project_ = 'leetcode' int representing what seat
# the student sat in, and ExamRoom.leave(int p) representing that the student in seat
# https://leetcode.com/problems/k-similar-strings/ number p now leaves the room.
# Strings A and B are K-similar (for some non-negative integer K) if we can swap the # It is guaranteed that any calls to ExamRoom.leave(p) have a student sitting in seat p.
positions of two letters in A
# exactly K times so that the resulting string equals B. # Maintain a sorted list of seats that are occupied. If room is empty use the first seat.
# Given two anagrams A and B, return the smallest K for which A and B are K-similar. Else check the distances to
# the first seat, between all pairs of seats and to the last seat. Insert in sorted order
# Breadth-first search. For each word in the frontier, find the index of the first letter and remove to leave.
out of place and swap it with # Time - O(n) for seat() and leave()
# all letters which should be in that place. Memoize visited words. # Space - O(n)
# Time - O(n * n!) since n! possible words of length n if letters are unique
# Space - O(n * n!) import bisect

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


def kSimilarity(self, A, B):
""" def __init__(self, N):
:type A: str """
:type B: str :type N: int
:rtype: int """
""" self.seats = []
visited = set() self.N = N
k = 0
frontier = {A} def seat(self):
"""
while True: :rtype: int
"""
if B in frontier: if not self.seats: # empty room, use seat zero
return k self.seats.append(0)
return 0
new_frontier = set()
max_dist, index = self.seats[0], 0 # max_dist is the distance from zero to
for word in frontier: the first occupied seat

if word in visited: for i in range(len(self.seats) - 1): # each pair of occupied seats


continue dist = (self.seats[i + 1] - self.seats[i]) // 2 # best case distance
if dist > max_dist: # improved best case
i = 0 max_dist = dist
while word[i] == B[i]: # find the first word[i] that is not index = self.seats[i] + dist
correct
if self.N - 1 - self.seats[-1] > max_dist: # put in last seat if further
distance # https://leetcode.com/problems/minimum-cost-to-hire-k-workers/
index = self.N - 1 # There are N workers. The i-th worker has a quality[i] and a minimum wage expectation
wage[i].
bisect.insort(self.seats, index) # insert seat in order # Now we want to hire exactly K workers to form a paid group.
return index # 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
def leave(self, p): other workers in the paid group.
""" # Every worker in the paid group must be paid at least their minimum wage expectation.
:type p: int # Return the least amount of money needed to form a paid group satisfying the above
:rtype: void conditions.
"""
self.seats.remove(p) # Sort worker by increasing wage_per_quality. The cost of employing a group is the
maximum wage_per_quality * sum of
# quality of the group. Form a group of the first K workers and find its total_quality
# python_1_to_1000/856_Score_of_Parentheses.py - m and cost.
# Add each additional worker to the group, which increases the maximum wage_per_quality.
_author_ = 'jake' Remove the worker with the
_project_ = 'leetcode' # highest quality, since they are most expensive to employ.
# Time - O(n logn)
# https://leetcode.com/problems/score-of-parentheses/ # Space - O(n logn)
# Given a balanced parentheses string S, compute the score of the string based on the
following rule: import heapq
# () has score 1
# AB has score A + B, where A and B are balanced parentheses strings. class Solution(object):
# (A) has score 2 * A, where A is a balanced parentheses string. def mincostToHireWorkers(self, quality, wage, K):
"""
# Maintain a stack of opening brackets and the score within each opening bracket. When we :type quality: List[int]
see a closing bracket, :type wage: List[int]
# either add or append 1, or multiply the previous top of stack by 2. :type K: int
# Time - O(n) :rtype: float
# Space - O(n) """
wage_per_quality = [(w / float(q), q) for w, q in zip(wage, quality)]
class Solution(object): wage_per_quality.sort()
def scoreOfParentheses(self, S):
""" workers = [-q for _, q in wage_per_quality[:K]] # -qualities of workers
:type S: str in current group
:rtype: int heapq.heapify(workers)
""" total_quality = -sum(workers)
stack = [] # opening brackets, followed by the score within that cost = wage_per_quality[K - 1][0] * total_quality # cost depends on highest
open bracket wage_per_quality

for s in S: for wpq, q in wage_per_quality[K:]:


heapq.heappush(workers, -q)
if s == "(": total_quality += q + heapq.heappop(workers) # remove worker with
stack.append(s) highest quality
cost = min(cost, wpq * total_quality)
else: # closing bracket
item = stack.pop() return cost
if item == "(": # matched pair of "()"
num = 1
else: # item is an integer
stack.pop() # discard opening bracket before integer # python_1_to_1000/858_Mirror_Reflection.py - m
num = 2 * item
_author_ = 'jake'
if stack and stack[-1] != "(": # add if top of stack is a num, else _project_ = 'leetcode'
append
stack[-1] += num # https://leetcode.com/problems/mirror-reflection/
else: # There is a special square room with mirrors on each of the four walls.
stack.append(num) # Except for the southwest corner, there are receptors on each of the remaining corners,
numbered 0, 1, and 2.
return stack[0] # 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.
# Return the number of the receptor that the ray meets first.
# python_1_to_1000/857_Minimum_Cost_to_Hire_K_Workers.py - h # It is guaranteed that the ray will meet a receptor eventually.

_author_ = 'jake' # Simulate the reflections. After k steps the vertical distance is kq, if this is
_project_ = 'leetcode' divisible by p, we are at a corner.

# Identify which corner according to whether the number of reflections is odd or even and return score
whether the vertical distance
# is an odd or even multiple of the side length.
# Time - O(p), all possible points on the wall could be visited before finding a corner # python_1_to_1000/860_Lemonade_Change.py
# Space - O(1)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def mirrorReflection(self, p, q):
""" # https://leetcode.com/problems/lemonade-change/
:type p: int # At a lemonade stand, each lemonade costs $5.
:type q: int # Customers are standing in a queue to buy from you, and order one at a time (in the
:rtype: int order specified by bills).
""" # Each customer will only buy one lemonade and pay with either a $5, $10, or $20 bill.
k = 1 # You must provide the correct change to each customer, so that the net transaction is
while (k * q) % p != 0: # vertical distance kq is not a multiple of side that the customer pays $5.
length p # Note that you don't have any change in hand at first.
k += 1 # Return true if and only if you can provide every customer with correct change.

if k % 2 == 0: # even number of steps # Maintain a count of the number of 5 and 10 dollar notes held. For $5 paid, no change is
return 2 given and for $10 paid
if ((k * q) // p) % 2 == 0: # vertical distance kq is an even multiple of # we must give $5 change. For $20 given, try to use $10 in change if possible since there
side length p is no other use for $10.
return 0 # Time - O(n)
return 1 # Space - O(1)

class Solution(object):
# python_1_to_1000/859_Buddy_Strings.py def lemonadeChange(self, bills):
"""
_author_ = 'jake' :type bills: List[int]
_project_ = 'leetcode' :rtype: bool
"""
# https://leetcode.com/problems/buddy-strings/ fives, tens = 0, 0 # no need to record twnetys, since they can never be
# Given two strings A and B of lowercase letters, return true if and only if we can swap used for change
two letters in A so that
# the result equals B. for bill in bills:

# We can always set all the bits in the first column by either flipping rows that start if bill == 5: # no change required
with zero, or flipping all fives += 1
# rows that start with one then flipping the whole column. These two cases result in the
bits in the other columns elif bill == 10: # must have $5 change
# being opposites. In either case we can flip each column so that the most common bit in if fives == 0:
that column is set. return False
# Time - O(mn) fives -= 1
# Space - O(mn) tens += 1

class Solution(object): elif bill == 20: # try to use $10 + $5


def matrixScore(self, A): if tens >= 1 and fives >= 1:
""" tens -= 1
:type A: List[List[int]] fives -= 1
:rtype: int elif fives >= 3: # else try 3 * $5
""" fives -= 3
rows, cols = len(A), len(A[0]) else:
return False
for r in range(rows):
if A[r][0] == 0: # row starts with zero return True
for c in range(1, cols): # flip all bits in the row
A[r][c] = 1 - A[r][c]
# python_1_to_1000/861_Score_After_Flipping_Matrix.py - m
score = rows * 2 ** (cols - 1) # first columns bits are all set
_author_ = 'jake'
for c in range(1, cols): # all other columns _project_ = 'leetcode'
col_count = sum(A[r][c] for r in range(rows)) # count set bits in
column # https://leetcode.com/problems/score-after-flipping-matrix/
best_col_count = max(col_count, rows - col_count) # flip if required, so # We have a two dimensional matrix A where each value is 0 or 1.
most common bit is set # A move consists of choosing any row or column, and toggling each value in that row or
col_val = 2 ** ((cols - 1) - c) # score for a bit in this column:
column # changing all 0s to 1s, and all 1s to 0s.
score += col_val * best_col_count # After making any number of moves, every row of this matrix is interpreted as a binary
number,
# and the score of the matrix is the sum of these numbers. prefix_sums = [0] * (n + 1)
# Return the highest possible score. for i in range(n):
prefix_sums[i + 1] = prefix_sums[i] + A[i]
# Return False if lengths are not equal. If strings are the same then return True if any
letter is duplicated in A, queue = deque()
# else return False. Otherwise find the indices in A of letters that are in the wrong result = n + 1
place. If there are not 2 such
# indices, return False. Finally, check if swapping the letters in the out of place for i in range(n + 1):
positions will change A into B.
# Time - O(n) while queue and prefix_sums[i] - prefix_sums[queue[0]] >= K:
# Space - O(n) result = min(result, i - queue.popleft()) # check and discard in order
of decreasing subarray length
from collections import Counter
while queue and prefix_sums[queue[-1]] >= prefix_sums[i]:
class Solution(object): queue.pop() # remove all greater prefix sums
def buddyStrings(self, A, B):
""" queue.append(i) # append to right of queue
:type A: str
:type B: str return result if result <= n else -1
:rtype: bool
"""
if len(A) != len(B): # python_1_to_1000/863_All_Nodes_Distance_K_in_Binary_Tree.py - m
return False
_author_ = 'jake'
if A == B: _project_ = 'leetcode'
return any(count > 1 for count in Counter(A).values())
# https://leetcode.com/problems/all-nodes-distance-k-in-binary-tree/
diffs = [i for i in range(len(A)) if A[i] != B[i]] # indices of letters out # We are given a binary tree (with root node root), a target node, and an integer value
of place in A K.
if len(diffs) != 2: # Return a list of the values of all nodes that have a distance K from the target node.
return False # The answer can be returned in any order.
return A[diffs[0]] == B[diffs[1]] and A[diffs[1]] == B[diffs[0]] # swapping
letters at misplaced indices # 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
# python_1_to_1000/862_Shortest_Subarray_with_Sum_at_Least_K.py - h node to results, else if
# distance to target is less than K then explore the subtree that does not contain
_author_ = 'jake' target, adding to results all nodes
_project_ = 'leetcode' # that are total distance K form target.
# Time - O(n)
# https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/ # Space - O(n)
# Return the length of the shortest, non-empty, contiguous subarray of A with sum at
least K. class Solution(object):
# If there is no non-empty subarray with sum at least K, return -1. def distanceK(self, root, target, K):
"""
# Calculate the prefix sums of the array. Maintain an queue of prefix sums that have not :type root: TreeNode
been used in order of :type target: TreeNode
# increasing index. :type K: int
# For each new prefix sum, update the result using the smallest indices in the queue, as :rtype: List[int]
long as the subarray """
# sum is >= K. The last value used creates the shortest subarray, so all earlier values results = []
can be discarded. The last
# value can be also discarded because all later prefix sums will make longer subarrays. def nodes_at_distance(node, distance): # update results for all subtree
# Remove from the right of the queue all greater prefixes, since they would make longer nodes at distance from node
subarrays.
# Time - O(n) if not node:
# Space - O(n) return
if distance == 0:
from collections import deque results.append(node.val)
else:
class Solution(object): nodes_at_distance(node.left, distance - 1)
def shortestSubarray(self, A, K): nodes_at_distance(node.right, distance - 1)
"""
:type A: List[int] def helper(node): # returns distance to target in this
:type K: int subtree or -1 if no target
:rtype: int
""" if not node:
n = len(A) return -1

if node == target: start_r, start_c = r, c


nodes_at_distance(node, K) # add to results all nodes at elif grid[r][c] in possible_keys:
distance K in this subtree keys.add(grid[r][c])
return 0
steps = 0
left, right = helper(node.left), helper(node.right) frontier = [(start_r, start_c, "")] # states as tuples of (row, column, locks
if left == -1 and right == -1: # target is in neither subtree acquired)
return -1 visited = set()
distance_to_target = 1 + max(left, right) # target is in a subtree neighbours = ((1, 0), (-1, 0), (0, 1), (0, -1))

if K - distance_to_target == 0: # add this node to results while frontier:


nodes_at_distance(node, 0)
elif K - distance_to_target > 0: # find nodes on other_side that are K new_frontier = set()
from target
other_side = node.left if left == -1 else node.right for r, c, open_locks in frontier:
nodes_at_distance(other_side, K - distance_to_target - 1)
if (r, c, open_locks) in visited: # ignore visited, outside grid,
return distance_to_target obstacle and locked doors
continue
helper(root) if r < 0 or r >= rows or c < 0 or c >= cols:
return results continue
if grid[r][c] == "#":
continue
# python_1_to_1000/864_Shortest_Path_to_Get_All_Keys.py - h if "A" <= grid[r][c] <= "F" and grid[r][c] not in open_locks:
continue
_author_ = 'jake'
_project_ = 'leetcode' visited.add((r, c, open_locks))

# https://leetcode.com/problems/shortest-path-to-get-all-keys/ if grid[r][c] in keys and grid[r][c].upper() not in open_locks:


# We are given a 2-dimensional grid. "." is an empty cell, "#" is a wall, "@" is the open_locks = "".join(sorted(open_locks + grid[r][c].upper())) #
starting point, update sorted string of open locks
# ("a", "b", ...) are keys, and ("A", "B", ...) are locks.
# We start at the starting point, and one move consists of walking one space in one of if len(open_locks) == len(keys):
the 4 cardinal directions. return steps
# We cannot walk outside the grid, or walk into a wall. If we walk over a key, we pick it
up. for dr, dc in neighbours:
# We can't walk over a lock unless we have the corresponding key. new_frontier.add((r + dr, c + dc, open_locks))
# For some 1 <= K <= 6, there is exactly one lowercase and one uppercase letter of the
first K letters of the frontier = new_frontier
# English alphabet in the grid. steps += 1
# This means that there is exactly one key for each lock, and one lock for each key; and
also that the letters used return -1
# to represent the keys and locks were chosen in the same order as the English alphabet.
# Return the lowest number of moves to acquire all keys. If it's impossible, return -1.
# python_1_to_1000/865_Smallest_Subtree_with_all_the_Deepest_Nodes.py - m
# Find which keys are in the grid and the starting location. Breadth-first search the
graph of states until all keys _author_ = 'jake'
# have been found. States consist of a location and sorted string of the keys found so _project_ = 'leetcode'
far. In each cycle, every state
# in the frontier takes a step in all possible directions, potentially updating the locks # https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/
acquired for the next state. # Given a binary tree rooted at root, the depth of each node is the shortest distance to
# Visited states are stored in a set so as not to be repeated. the root.
# Time - O(mn * 2**k * k log k) for k keys # A node is deepest if it has the largest depth possible among any node in the entire
# Space - O(mn * k * 2**k) tree.
# The subtree of a node is that node, plus the set of all descendants of that node.
class Solution(object): # Return the node with the largest depth such that it contains all the deepest nodes in
def shortestPathAllKeys(self, grid): its subtree.
"""
:type grid: List[str] # Helper function returns the depth of the deepest node and the deepest node that is a
:rtype: int parent of all deepest nodes.
""" # Recursively explore left and right subtrees. If the deepest depths are equal, the
rows, cols = len(grid), len(grid[0]) current nodeis the deepest parent
possible_keys = set("abcdef") # of those deepest nodes. Else return the node from the deeper side.
keys = set() # Time - O(n)
# Space - O(n)
for r in range(rows): # find the starting position and which
keys are in the grid from collections import namedtuple
for c in range(cols):
if grid[r][c] == "@": class Solution(object):
def subtreeWithAllDeepest(self, root): lhs = 10 ** (n // 2) # left side of candidate,
""" including middle digit
:type root: TreeNode while True:
:rtype: TreeNode candidate = int(str(lhs) + str(lhs)[-2::-1]) # will have odd length
""" if candidate >= N and is_prime(candidate):
Result = namedtuple("Result", ["node", "depth"]) # object returned by helper return candidate
function lhs += 1

def helper(node):
# python_1_to_1000/867_Transpose_Matrix.py
if not node:
return Result(None, -1) _author_ = 'jake'
_project_ = 'leetcode'
left_result, right_result = helper(node.left), helper(node.right)
# https://leetcode.com/problems/transpose-matrix/
depth_diff = left_result.depth - right_result.depth # Given a matrix A, return the transpose of A.
# The transpose of a matrix is the matrix flipped over it's main diagonal,
if depth_diff == 0: # switching the row and column indices of the matrix.
return Result(node, left_result.depth + 1)
# Explode A into rows, which are zipped together with the ith element of each row (i.e.
if depth_diff > 0: column i) being combined in
return Result(left_result.node, left_result.depth + 1) # each tuple of the result.
return Result(right_result.node, right_result.depth + 1) # Time - O(mn)
# Space - O(mn)
return helper(root).node
class Solution(object):
def transpose(self, A):
# python_1_to_1000/866_Prime_Palindrome.py - m """
:type A: List[List[int]]
_author_ = 'jake' :rtype: List[List[int]]
_project_ = 'leetcode' """
return zip(*A)
# https://leetcode.com/problems/prime-palindrome/
# Find the smallest prime palindrome greater than or equal to N.
# Recall that a number is prime if it's only divisors are 1 and itself, and it is greater # python_1_to_1000/868_Binary_Gap.py
than 1.
# For example, 2,3,5,7,11 and 13 are primes. _author_ = 'jake'
# Recall that a number is a palindrome if it reads the same from left to right as it does _project_ = 'leetcode'
from right to left.
# For example, 12321 is a palindrome. # https://leetcode.com/problems/binary-gap/
# Given a positive integer N, find and return the longest distance between two
# Iterate through palindromes until we find one >= N and prime. For N of length n, build consecutive 1's in the
palindromes of length n if n # binary representation of N.
# is odd, else of length n + 1. Since 11 is the only even length prime palindromes, we # If there aren't two consecutive 1's, return 0.
only consider odd length
# candidates. Prime checking of x is by testing divisibility by all odd integers <= # Check each bit (from least significant to most significant). Track the index of the
sqrt(x). previous set bit and the
# Time - O(n) # maximum distance so far.
# Space - O(log n) # Time - O(log n)
# Space - O(1)
class Solution(object):
def primePalindrome(self, N): class Solution(object):
""" def binaryGap(self, N):
:type N: int """
:rtype: int :type N: int
""" :rtype: int
def is_prime(x): """
if x < 2 or x % 2 == 0: # remove 0, 1 and even numbers previous, max_gap = None, 0 # index of previous 1
return x == 2 i = 0 # current index in binary representation
for i in range(3, int(x ** 0.5) + 1, 2): # check odds <= sqrt(x)
if x % i == 0: while N > 0:
return False
return True if N & 1: # bit is set
if previous is not None:
if 8 <= N <= 11: # 11 is the only result with even max_gap = max(max_gap, i - previous)
number of digits previous = i
return 11
N >>= 1 # remove bit
n = len(str(N)) i += 1

def advantageCount(self, A, B):


return max_gap """
:type A: List[int]
:type B: List[int]
# python_1_to_1000/869_Reordered_Power_of_2.py - m :rtype: List[int]
"""
_author_ = 'jake' B_i = sorted([(b, i) for i, b in enumerate(B)])
_project_ = 'leetcode' result = [None] * len(A)
i = 0
# https://leetcode.com/problems/reordered-power-of-2/
# Starting with a positive integer N, we reorder the digits in any order (including the for a in sorted(A):
original order)
# such that the leading digit is not zero. if a > B_i[i][0]:
# Return true if and only if we can do this in a way such that the resulting number is a result[B_i[i][1]] = a
power of 2. i += 1
else:
# Find the smallest power of 2 with the same length as N. Check the digit of this and all result[B_i.pop()[1]] = a
subsequent powers of 2
# until the length is greater than N. return result
# Time - O(log n)
# Space - O(log n)
# python_1_to_1000/871_Minimum_Number_of_Refueling_Stops.py - h
from math import ceil, log
from collections import Counter _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def reorderedPowerOf2(self, N): # https://leetcode.com/problems/minimum-number-of-refueling-stops/
""" # A car travels from a starting position to a destination which is target miles east of
:type N: int the starting position.
:rtype: bool # Along the way, there are gas stations.
""" # Each station[i] represents a gas station that is station[i][0] miles east of the
digit_count = Counter(str(N)) # count the digits of starting position,
N # and has station[i][1] liters of gas.
len_N = len(str(N)) # The car starts with an infinite tank of gas, which initially has startFuel liters of
power_of_two = 2 ** int(ceil(log(10 ** (len_N - 1), 2))) # the smallest power fuel in it.
of 2 of length len_N # It uses 1 liter of gas per 1 mile that it drives.
str_power_of_two = str(power_of_two) # When the car reaches a gas station, it may stop and refuel, transferring all the gas
from the station into the car.
while len(str_power_of_two) == len_N: # until length is too # What is the least number of refueling stops the car must make in order to reach its
long destination?
if Counter(str_power_of_two) == digit_count: # If it cannot reach the destination, return -1.
return True # Note that if the car reaches a gas station with 0 fuel left, the car can still refuel
power_of_two *= 2 there.
str_power_of_two = str(power_of_two) # If the car reaches the destination with 0 fuel left, it is still considered to have
arrived.
return False
# Maintain a heap of fuel at previous stations that has not been used. At each station
the total fuel used must not be
# python_1_to_1000/870_Advantage_Shuffle.py - m # less than the distance. If it is less, use fuel from previous stations starting with
the largest amounts. If no more
_author_ = 'jake' # fuel is unused, we cannot reach the target.
_project_ = 'leetcode' # Time - O(n log n)
# Space - O(n)
# https://leetcode.com/problems/advantage-shuffle/
# Given two arrays A and B of equal size, the advantage of A with respect to B is the import heapq
number of indices i
# for which A[i] > B[i]. class Solution:
# Return any permutation of A that maximizes its advantage with respect to B. def minRefuelStops(self, target, startFuel, stations):
"""
# Sort B, storing the index of each element along with its value. For each element a of :type target: int
sorted(A), if a > smallest :type startFuel: int
# unused element of B then put a in the result at the index of the smallest unused :type stations: List[List[int]]
element of B. Else a is not :rtype: int
# greater than any element of B, so put it in the result at the largest unused element of """
B. stops = 0
# Time - O(n log n) fuel = startFuel # total fuel used
# Space - O(n) past_fuels = [] # heap of unused fuel from
previous stations
class Solution(object): stations.append([target, 0]) # target is beyond final station
# n >= 3
for distance, station_fuel in stations: # X_i + X_{i+1} = X_{i+2} for all i + 2 <= n
# Given a strictly increasing array A of positive integers forming a sequence,
while fuel < distance: # cannot reach this station # find the length of the longest fibonacci-like subsequence of A. If one does not exist,
without more fuel return 0.
# Recall that a subsequence is derived from another sequence A by deleting any number of
if not past_fuels: # no more unused previous elements (including none)
stations # from A, without changing the order of the remaining elements.
return -1
# For each pair of numbers, attempt to build a Fibonacci sequence. Copy the integers into
fuel -= heapq.heappop(past_fuels) # use the previous station with a set for O(1) lookup when
the most fuel # testing if a sequence can be extended.
stops += 1 # Time - O(n**2)
# Space - O(n)
heapq.heappush(past_fuels, -station_fuel) # add this station's fuel to
unused fuel class Solution(object):
def lenLongestFibSubseq(self, A):
return stops """
:type A: List[int]
:rtype: int
# python_1_to_1000/872_Leaf-Similar_Trees.py """
A_set = set(A)
_author_ = 'jake' max_length = 0
_project_ = 'leetcode'
for i, num in enumerate(A):
# https://leetcode.com/problems/leaf-similar-trees/
# Consider all the leaves of a binary tree. for num2 in A[i + 1:]:
# From left to right order, the values of those leaves form a leaf value sequence.
# Two binary trees are considered leaf-similar if their leaf value sequence is the same. prev_num = num2
# Return true if and only if the two given trees with head nodes root1 and root2 are next_num = num + num2
leaf-similar. length = 2
while next_num in A_set: # sequence can be extended
# Generate the leaves by inorder traversal. Yield from the left subtree, yield the node length += 1
value then yield from the next_num, prev_num = next_num + prev_num, next_num
# right subtree. Zip the inorder traversals together up to the longest sequence and check
all values are equal. max_length = max(max_length, length)
# Time - O(n)
# Space - O(1) return max_length if max_length >= 3 else 0

import itertools
# python_1_to_1000/874_Walking_Robot_Simulation.py - m
class Solution(object):
def leafSimilar(self, root1, root2): _author_ = 'jake'
""" _project_ = 'leetcode'
:type root1: TreeNode
:type root2: TreeNode # https://leetcode.com/problems/walking-robot-simulation/
:rtype: bool # A robot on an infinite grid starts at point (0, 0) and faces north.
""" # The robot can receive one of three possible types of commands:
# -2: turn left 90 degrees
def inorder(node): # -1: turn right 90 degrees
if node.left: # check left subtree # 1 <= x <= 9: move forward x units
yield from inorder(node.left) # Some of the grid squares are obstacles.
if not node.left and not node.right: # yield the leaf val # The i-th obstacle is at grid point (obstacles[i][0], obstacles[i][1])
yield node.val # If the robot would try to move onto them, the robot stays on the previous grid square
if node.right: # check right subtree instead (but still
yield from inorder(node.right) # continues following the rest of the route.)
# Return the square of the maximum Euclidean distance that the robot will be from the
leaves = itertools.zip_longest(inorder(root1), inorder(root2)) origin.

return all(l1 == l2 for l1, l2 in leaves) # Track the postition and orientation of the robot. When moving forwards, check if the
next position is an obstacle
# and stop if so.
# python_1_to_1000/873_Length_of_Longest_Fibonacci_Subsequence.py - m # Time - O(n) total number of operations (since at most 9 steps forwards)
# Space - O(m) number of obstacles
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def robotSim(self, commands, obstacles):
# https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/ """
# A sequence X_1, X_2, ..., X_n is fibonacci-like if: :type commands: List[int]

:type obstacles: List[List[int]] min_rate = (bananas + H - 1) // H # equivalent to ceil(bananas / H)


:rtype: int max_rate = max_pile
"""
NORTH, EAST, SOUTH, WEST = 0, 1, 2, 3 while min_rate < max_rate:
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] # change of position in each
direction rate = (min_rate + max_rate) // 2

position, orientation = (0, 0), NORTH time = 0


max_sqr_distance = 0 for pile in piles:
obstacles = {tuple(obstacle) for obstacle in obstacles} # convert to set for time += (pile + rate - 1) // rate # time to eat this pile
O(1) lookup if time > H: # stop if already taken too long
break
for command in commands:
if command == -2: if time > H: # increase minimum rate
orientation = (orientation - 1) % 4 # turn left min_rate = rate + 1
elif command == -1: else: # result is this rate or lower
orientation = (orientation + 1) % 4 # turn right max_rate = rate
else:
for _ in range(command): return min_rate
next_position = (position[0] + directions[orientation][0],
position[1] + directions[orientation][1])
if next_position in obstacles: # stop moving if obstacle # python_1_to_1000/876_Middle_of_the_Linked_List.py
break
position = next_position _author_ = 'jake'
max_sqr_distance = max(max_sqr_distance, position[0] ** 2 + _project_ = 'leetcode'
position[1] ** 2)
# https://leetcode.com/problems/middle-of-the-linked-list/
return max_sqr_distance # Given a non-empty, singly linked list with head node head, return a middle node of
linked list.
# If there are two middle nodes, return the second middle node.

# Move fast pointer for 2 steps and slow pointer for 1 step until fast does not have a
# python_1_to_1000/875_Koko_Eating_Bananas.py - m next next.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/koko-eating-bananas/ def middleNode(self, head):
# Koko loves to eat bananas. There are N piles of bananas, the i-th pile has piles[i] """
bananas. :type head: ListNode
# The guards have gone and will come back in H hours. :rtype: ListNode
# Koko can decide her bananas-per-hour eating speed of K. Each hour, she chooses some """
pile of bananas, slow, fast = head, head
# and eats K bananas from that pile. while fast and fast.next:
# If the pile has less than K bananas, she eats all of them instead, and won't eat any slow, fast = slow.next, fast.next.next
more bananas during this hour. return slow
# 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/877_Stone_Game.py - m

# Binary search the range of possible speeds. Maximum possible rate is to eat the largest _author_ = 'jake'
pile in an hour. _project_ = 'leetcode'
# Minimum possible rate is to eat bananas constantly, so the sum of all bananas in the
total time. # https://leetcode.com/problems/stone-game/
# Chech the middle rate between maximum and minimum and adjust the search range until one # Alex and Lee play a game with piles of stones.
integer remains. # There are an even number of piles arranged in a row, and each pile has a positive
# The time to eat any pile is the size of the pile / rate, rounded up to the nearest integer number of stones piles[i].
integer. # The objective of the game is to end with the most stones. The total number of stones is
# Time - O(n log n) odd, so there are no ties.
# Space - O(1) # Alex and Lee take turns, with Alex starting first.
# Each turn, a player takes the entire pile of stones from either the beginning or the
class Solution(object): end of the row.
def minEatingSpeed(self, piles, H): # This continues until there are no more piles left, at which point the person with the
""" most stones wins.
:type piles: List[int] # Assuming Alex and Lee play optimally, return True if and only if Alex wins the game.
:type H: int
:rtype: int # Alex can initially take the first pile (an even index) or the last pile (an odd index).
""" If Alex takes an even index
bananas, max_pile = sum(piles), max(piles) # 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 _project_ = 'leetcode'
# 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 # https://leetcode.com/problems/profitable-schemes/
piles are not equal # There are G people in a gang, and a list of various crimes they could commit.
# (because the total sum is odd), Alex can always take more stones in total. # The i-th crime generates a profit[i] and requires group[i] gang members to participate.
# Time - O(1) # If a gang member participates in one crime, that member can't participate in another
# Space - O(1) crime.
# Let's call a profitable scheme any subset of these crimes that generates at least P
class Solution(object): profit,
def stoneGame(self, piles): # and the total number of gang members participating in that subset of crimes is at most
""" G.
:type piles: List[int] # How many schemes can be chosen? Since the answer may be very large, return it modulo
:rtype: bool 10^9 + 7.
"""
return True # 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
# python_1_to_1000/878_Nth_Magical_Number.py - h large as the job_gang, and for all
# profits where schemes with profits > P are included in the profits == P cells. Return
_author_ = 'jake' all schemes with profit at
_project_ = 'leetcode' # least P for any gang size in the matrix.
# Time - O(NGP)
# https://leetcode.com/problems/nth-magical-number/ # Space - O(GP)
# 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 class Solution(object):
10^9 + 7. def profitableSchemes(self, G, P, group, profit):
"""
# Binary search the range of all possible solutions. Given a guess x, the number of :type G: int
magical numbers <= x is :type P: int
# x // A + x // B - x // lcm(A, B), i.e. all the integers divisible by A + all the :type group: List[int]
integers divisible by B - all the :type profit: List[int]
# integers divisible by both A and B (to avoid double-counting). :rtype: int
# Time - O(1) """
# Space - O(1) MOD = 10 ** 9 + 7

class Solution(object): schemes = [[0] * (G + 1) for _ in range(P + 1)] # schemes[i][j] is nb schemes


def nthMagicalNumber(self, N, A, B): for profit i and gang j
""" schemes[0][0] = 1
:type N: int
:type A: int for job_profit, job_gang in zip(profit, group):
:type B: int
:rtype: int for p in range(P, -1, -1): # for schemes with all
""" profits ...
low, high = 1, 10 ** 14 for g in range(G, job_gang - 1, -1): # and enough members to do
this job
def gcd(a, b): capped_profit = min(P, p + job_profit) # cap profit including this
a, b = b, a % b job at P
if b == 0: schemes[capped_profit][g] += schemes[p][g - job_gang] # add schemes
return a before this job
return gcd(a, b)
return sum(schemes[-1]) % MOD # all schemes with profit at
lcm = A * B // gcd(A, B) least P and gang <= G

while low < high:


# python_1_to_1000/880_Decoded_String_at_Index.py - m
mid = (low + high) // 2
num = (mid // A) + (mid // B) - (mid // lcm) # guess the result _author_ = 'jake'
if num < N: # result must be greater than _project_ = 'leetcode'
low
low = mid + 1 # https://leetcode.com/problems/decoded-string-at-index/
elif num >= N: # result is at most high # An encoded string S is given. To find and write the decoded string to a tape,
high = mid # the encoded string is read one character at a time and the following steps are taken:
# If the character read is a letter, that letter is written onto the tape.
return low % (10 ** 9 + 7) # If the character read is a digit (say d), the entire current tape is repeatedly written
d-1 more times in total.
# Now for some encoded string S, and an index K, find and return the K-th letter (1
# python_1_to_1000/879_Profitable_Schemes.py - h indexed) in the decoded string.

_author_ = 'jake' # Find the index of S where the decoded string is of length at least K. Iterate backwards

in S from the found index. while light <= heavy:


# For every digit, divide the decoded length by the digit and update K to be the
remainder when dividing by the new boats += 1 # add heaviest to a new boat
# length. For every character, return if the decoded string has the required length else
decrement the length. if people[light] + people[heavy] <= limit: # capacity for lightest and
# Time - O(n) heaviest
# Space - O(1) light += 1

class Solution(object): heavy -= 1


def decodeAtIndex(self, S, K):
""" return boats
:type S: str
:type K: int
:rtype: str # python_1_to_1000/882_Reachable_Nodes_In_Subdivided_Graph.py - h
"""
length = 0 _author_ = 'jake'
for index, c in enumerate(S): _project_ = 'leetcode'
if "0" <= c <= "9": # multiply the length of the decoded string
length *= int(c) # https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/
else: # increment the length of the decoded string # Starting with an undirected graph (the "original graph") with nodes from 0 to N-1,
length += 1 # subdivisions are made to some of the edges.
if length >= K: # The graph is given as follows: edges[k] is a list of integer pairs (i, j, n) such that
break (i, j) is an edge of the
# original graph, and n is the total number of new nodes on that edge.
for i in range(index, -1, -1): # iterate backwards along S # Then, the edge (i, j) is deleted from the original graph, n new nodes (x_1, x_2, ...,
c = S[i] x_n) are added to the
if "0" <= c <= "9": # original graph, and n+1 new edges (i, x_1), (x_1, x_2), (x_2, x_3), ..., (x_{n-1},
length //= int(c) x_n), (x_n, j) are added to
K %= length # the original graph.
else: # Now, you start at node 0 from the original graph, and in each move, you travel along
if K == length or K == 0: # K == 0 results from modulo one edge.
return c # Return how many nodes you can reach in at most M moves.
length -= 1
# Modified Dijkstra's algorithm. Maintain a priority queue of nodes sorted by the minimum
number of steps to reach a
# python_1_to_1000/881_Boats_to_Save_People.py - m # that node. For each node in queue, travel along all adjacent edges visiting as many of
the edges along the node as
_author_ = 'jake' # possible. If all edge nodes are visited, add the neighbouring node to the queue. Record
_project_ = 'leetcode' the number of nodes vistied
# from both ends of each edge. Sum all real nodes visited plus the node from both sides
# https://leetcode.com/problems/boats-to-save-people/ of each edges, capped at the
# The i-th person has weight people[i], and each boat can carry a maximum weight of # the total number of edge nodes.
limit. # Time - O(n log n) where n is the length of edges, since each edge can be added to the
# Each boat carries at most 2 people at the same time, provided the sum of the weight of heap.
those people is at most limit. # Space - O(n)
# Return the minimum number of boats to carry every given person.
# It is guaranteed each person can be carried by a boat. import heapq
from collections import defaultdict
# Sort the people in weight order. Maintain 2 pointers to the lightest and heaviest
people not yet allocated to a boat. class Solution(object):
# Add the heaviest person to a boat. If the lightest person can join them without going def reachableNodes(self, edges, M, N):
over the weight limit, then add """
# the lightest person. When the heaviest person is added to a boat, if the lightest :type edges: List[List[int]]
person cannot join them then there :type M: int
# is no other person that can join them and the heaviest person must be alone. :type N: int
# Time - O(n log n) :rtype: int
# Space - O(1) """
adjacency = defaultdict(set) # map node to set of (nbor,
class Solution(object): number of nodes on edge)
def numRescueBoats(self, people, limit): subdivisions = {} # map an edge to (number of nodes
""" on edge, visited nodes)
:type people: List[int]
:type limit: int for a, b, intermediate in edges:
:rtype: int subdivisions[(a, b)] = [intermediate, 0]
""" subdivisions[(b, a)] = [intermediate, 0]
boats = 0 adjacency[a].add((b, intermediate))
people.sort() adjacency[b].add((a, intermediate))
light, heavy = 0, len(people) - 1
queue = [(0, 0)] # (steps taken, node)
visited = set()
# python_1_to_1000/884_Uncommon_Words_from_Two_Sentences.py
while queue and len(visited) < N:
steps, node = heapq.heappop(queue) _author_ = 'jake'
if node in visited: # already visited with lower or _project_ = 'leetcode'
same steps
continue # https://leetcode.com/problems/uncommon-words-from-two-sentences/
visited.add(node) # We are given two sentences A and B. A sentence is a string of space separated words.
# Each word consists only of lowercase letters.
for nbor, distance in adjacency[node]: # visit as many nodes as possible # A word is uncommon if it appears exactly once in one of the sentences, and does not
along this edge appear in the other sentence.
subdivisions[(node, nbor)][1] = min(distance, M - steps) # Return a list of all uncommon words in any order.

if steps + distance + 1 <= M: # visited all node on edge, add # Add the counts of frequencies of words in each sentence. Return the list of words whose
nbor to queue total count is one.
heapq.heappush(queue, (steps + distance + 1, nbor)) # Time - O(m + n)
# Space - O(m + n)
result = len(visited) # all nodes
for (a, b), (distance, covered) in subdivisions.items(): from collections import Counter
if a < b:
result += min(distance, covered + subdivisions[(b, a)][1]) # sum edge class Solution(object):
nodes from both sides def uncommonFromSentences(self, A, B):
"""
return result :type A: str
:type B: str
:rtype: List[str]
# python_1_to_1000/883_Projection_Area_of_3D_Shapes.py """
counts = Counter(A.split(" ")) + Counter(B.split(" "))
_author_ = 'jake' return [word for word, count in counts.items() if count == 1]
_project_ = 'leetcode'

# https://leetcode.com/problems/projection-area-of-3d-shapes/ # python_1_to_1000/885_Spiral_Matrix_III.py - m
# On a N * N grid, we place some 1 * 1 * 1 cubes that are axis-aligned with the x, y, and
z axes. _author_ = 'jake'
# Each value v = grid[i][j] represents a tower of v cubes placed on top of grid cell (i, _project_ = 'leetcode'
j).
# Now we view the projection of these cubes onto the xy, yz, and zx planes. # https://leetcode.com/problems/spiral-matrix-iii/
# A projection is like a shadow, that maps our 3 dimensional figure to a 2 dimensional # On a 2 dimensional grid with R rows and C columns, we start at (r0, c0) facing east.
plane. # Here, the north-west corner of the grid is at the first row and column, and the south-
# Here, we are viewing the "shadow" when looking at the cubes from the top, the front, east corner of the
and the side. # grid is at the last row and column.
# Return the total area of all three projections. # Now, we walk in a clockwise spiral shape to visit every position in this grid.
# Whenever we would move outside the boundary of the grid, we continue our walk outside
# Base area is the count of all cells with height > 0. Side areas are the sums of maximum the grid
heights by column and by # (but may return to the grid boundary later.)
# row respectively. # Eventually, we reach all R * C spaces of the grid.
# Time - O(mn) # Return a list of coordinates representing the positions of the grid in the order they
# Space - O(m + n) were visited.

class Solution(object): # Move in a spiral until all cells of the grid have been visited. Step along each side,
def projectionArea(self, grid): then turn to next direction.
""" # Each cell visited within the grid is appended to the result. Spiral has two sides of
:type grid: List[List[int]] the same length, then two sides
:rtype: int # of length + 1, etc.
""" # Time - O(max(m, n)**2)
n = len(grid) # Space - O(mn)
row_heights, col_heights = [0] * n, [0] * n
base_area = 0 class Solution(object):
def spiralMatrixIII(self, R, C, r0, c0):
for row in range(n): """
for col in range(n): :type R: int
:type C: int
if grid[row][col] != 0: :type r0: int
base_area += 1 :type c0: int
row_heights[row] = max(row_heights[row], grid[row][col]) :rtype: List[List[int]]
col_heights[col] = max(col_heights[col], grid[row][col]) """
moves = [[0, 1], [1, 0], [0, -1], [-1, 0]] # change in r and c foa move in
return base_area + sum(row_heights) + sum(col_heights) each direction
r, c = r0, c0

direction = 0 this, other = set(), set() # 2 groups of people


result = [[r0, c0]]
side = 1 # current length of side of for i in range(1, N + 1):
spiral
if i in this or i in other: # already placed this person in a group
while len(result) < R * C: continue
to_add = {i}
dr, dc = moves[direction]
while to_add:
for _ in range(side): # step along the side
r += dr this |= to_add # put to_add in this
c += dc
if 0 <= r < R and 0 <= c < C: # append to result if within disliked = set() # people disliked by the people in to_add
bounds of grid for num in to_add:
result.append([r, c]) disliked |= dislike[num]
if disliked & this: # somebody dislikes somebody else in this
direction = (direction + 1) % 4 # next direction group
dr, dc = moves[direction] return False

for _ in range(side): disliked -= other # remove people already in other


r += dr to_add = disliked
c += dc this, other = other, this
if 0 <= r < R and 0 <= c < C:
result.append([r, c]) return True

direction = (direction + 1) % 4
side += 1 # after 2 sides of spiral, # python_1_to_1000/887_Super_Egg_Drop.py - h
increase side length
_author_ = 'jake'
return result _project_ = 'leetcode'

# https://leetcode.com/problems/super-egg-drop/
# python_1_to_1000/886_Possible_Bipartition.py - m # 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.
_author_ = 'jake' # You know that there exists a floor F with 0 <= F <= N such that any egg dropped at a
_project_ = 'leetcode' floor higher than F will break,
# and any egg dropped at or below floor F will not break.
# https://leetcode.com/problems/possible-bipartition/ # Each move, you may take an egg (if you have an unbroken one) and drop it from any floor
# Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into X (with 1 <= X <= N).
two groups of any size. # Your goal is to know with certainty what the value of F is.
# Each person may dislike some other people, and they should not go into the same group. # What is the minimum number of moves that you need to know with certainty what F is,
# Formally, if dislikes[i] = [a, b], it means it is not allowed to put the people # regardless of the initial value of F?
numbered a and b into the same group.
# Return true if and only if it is possible to split everyone into two groups in this # If we know the maximum height of building for which we can learn the highest floor that
way. an egg can be dropped from
# without breaking for a certain number of drops (d) and a certain number of eggs (e).
# Map each person to the set of people they dislike. For each person, put them in a group Call this f(d, e).
then find all the people # We also know the same result for the same number of drops and one fewer egg = f(d, e -
# they dislike. If any of the disliked are in the group then return False, else remove 1).
from disliked all those already # Now we take an additional drop from floor f(d, e - 1) + 1.
# in the other group, swap the groups and repeat by placing the disliked. # If it breaks, we know that we can find the result with one less egg f(d, e - 1).
# Time - O(n**2), the length of dislikes # If it doesn't break, we can explore the f(d, e) floors above the one we just dropped
# Space - O(n**2) from.
# So we can get the result for a building of height 1 + f(d, e - 1) + f(d, e).
from collections import defaultdict
# Time - O(K log N) since floors[K] grows exponentially with each drop.
class Solution(object): # Space - O(K)
def possibleBipartition(self, N, dislikes):
""" class Solution(object):
:type N: int def superEggDrop(self, K, N):
:type dislikes: List[List[int]] """
:rtype: bool :type K: int
""" :type N: int
dislike = defaultdict(set) # map each person to the set of people they :rtype: int
dislike """
for a, b in dislikes: drops = 0
dislike[a].add(b) floors = [0 for _ in range(K + 1)] # floors[i] is the number of floors that can
dislike[b].add(a) be checked with i eggs
while floors[K] < N: # including form the right subtree. The nodes in post that form the left subtree are
deduced from the length of the
for eggs in range(K, 0, -1): # sile of pre that forms the left subtree. A mapping of pre from value to index ensures
floors[eggs] += 1 + floors[eggs - 1] finding a node is O(1).
drops += 1 # Time - O(n)
# Space - O(n)
return drops
class Solution(object):
def constructFromPrePost(self, pre, post):
# python_1_to_1000/888_Fair_Candy_Swap.py """
:type pre: List[int]
_author_ = 'jake' :type post: List[int]
_project_ = 'leetcode' :rtype: TreeNode
"""
# https://leetcode.com/problems/fair-candy-swap/ def helper(pre_start, pre_end, post_start, post_end): # build subtree using
# Alice and Bob have candy bars of different sizes: A[i] is the size of the i-th bar of pre[pre_start:pre_end]
candy that Alice has, # and post[post_start,
# and B[j] is the size of the j-th bar of candy that Bob has. post_end]
# Since they are friends, they would like to exchange one candy bar each so that after if pre_start == pre_end:
the exchange, return None
# 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. root = TreeNode(pre[pre_start])
# Return an integer array ans where ans[0] is the size of the candy bar that Alice must if post_end == post_start + 1:
exchange, and ans[1] is the return root
# size of the candy bar that Bob must exchange.
# If there are multiple answers, you may return any one of them. It is guaranteed an idx = pre_indices[post[post_end - 2]] # index of root of right subtree
answer exists. in pre
left_size = idx - pre_start - 1 # number of nodes in left subtree
# The difference of the sizes of the bars that they must swap is half of the difference root.left = helper(pre_start + 1, idx, post_start, post_start + left_size)
of their total candy, since root.right = helper(idx, pre_end, post_start + left_size, post_end - 1)
# exchanging such bars will make the difference zero. For each bar in A, check if there
is bar in B with the return root
# required difference.
# Time - O(m + n) pre_indices = {val: i for i, val in enumerate(pre)} # map from node value to
# Space - O(n) index in pre
return helper(0, len(pre), 0, len(post))
class Solution(object):
def fairCandySwap(self, A, B):
""" # python_1_to_1000/890_Find_and_Replace_Pattern.py - h
:type A: List[int]
:type B: List[int] _author_ = 'jake'
:rtype: List[int] _project_ = 'leetcode'
"""
A_candy, B_candy = sum(A), sum(B) # https://leetcode.com/problems/find-and-replace-pattern/
difference = (A_candy - B_candy) // 2 # difference of sizes of bars that must # You have a list of words and a pattern, and you want to know which words in words
be exchanged matches the pattern.
# A word matches the pattern if there exists a permutation of letters p so that after
B_set = set(B) replacing every letter x in
for a in A: # the pattern with p(x), we get the desired word.
if a - difference in B_set: # Recall that a permutation of letters is a bijection from letters to letters: every
return [a, a - difference] letter maps to another letter,
# and no two letters map to the same letter.
return [] # Return a list of the words in words that match the given pattern.
# You may return the answer in any order.

# python_1_to_1000/889_Construct_Binary_Tree_from_Preorder_and_Postorder_Traversal.py - m # Each word and the pattern are converted to their canonical representations, which can
then be compared.
_author_ = 'jake' # In a canonical representation, characters are mapped to integers in order of their
_project_ = 'leetcode' appearance in the string.
# The first character is mapped to 0, as are all subsequent appearances of that
# https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder- character. The second unique character
traversal/ # is mapped to 1, etc.
# Return any binary tree that matches the given preorder and postorder traversals. # Time - O(n) total length of all words and pattern
# Values in the traversals pre and post are distinct positive integers. # Space - O(n)

# The root is the first node of pre and the last node of post. The penultimate node of from collections import defaultdict
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 class Solution(object):
subtree and all after and def findAndReplacePattern(self, words, pattern):

""" # https://leetcode.com/problems/surface-area-of-3d-shapes/
:type words: List[str] # On a N * N grid, we place some 1 * 1 * 1 cubes.
:type pattern: str # Each value v = grid[i][j] represents a tower of v cubes placed on top of grid cell (i,
:rtype: List[str] j).
""" # Return the total surface area of the resulting shapes.
def canonical(s): # return a canonical representation of a string
result = [] # list of integers # For each cell, add the area of top, bottom and all sides. Then subtract the side areas
mapping = {} # map char to value that are covered by
value = 0 # next value (equal to number of unique chars # neighbours.
seen) # Time - O(mn)
# Space - O(1)
for c in s:
if c not in mapping: # create a new mapping if c has not been seen class Solution(object):
before def surfaceArea(self, grid):
mapping[c] = value """
value += 1 :type grid: List[List[int]]
result.append(mapping[c]) :rtype: int
return tuple(result) """
n = len(grid)
pattern = canonical(pattern) area = 0
return [word for word in words if canonical(word) == pattern]
for row in range(n):
for col in range(n):

# python_1_to_1000/891_Sum_of_Subsequence_Widths.py - h if grid[row][col] == 0: # ignore if no height


continue
_author_ = 'jake'
_project_ = 'leetcode' height = grid[row][col]
area += 4 * height + 2
# https://leetcode.com/problems/sum-of-subsequence-widths/
# Given an array of integers A, consider all non-empty subsequences of A. if row != 0:
# For any sequence S, let the width of S be the difference between the maximum and area -= min(grid[row - 1][col], height)
minimum element of S. if col != 0:
# Return the sum of the widths of all subsequences of A. area -= min(grid[row][col - 1], height)
# As the answer may be very large, return the answer modulo 10^9 + 7. if row != n - 1:
area -= min(grid[row + 1][col], height)
# Sort the numbers. For each number A[i] there are 2**i subsequences where A[i] is the if col != n - 1:
maximum. Add to the result the area -= min(grid[row][col + 1], height)
# maximum value of all such subsequences.
# There are 2**(len(A)-1-i) subsequences where A[i] is the minimum. Subtract from the return area
result the minimum value of all
# such subsequences. For every subsequence the maximum is added and the minimum is
subtracted, resulting in the width. # python_1_to_1000/893_Groups_of_Special-Equivalent_Strings.py - m
# Bitwise shift is faster than pow() or the ** operator.
# Time - O(n log n) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/groups-of-special-equivalent-strings/


def sumSubseqWidths(self, A): # You are given an array A of strings.
""" # Two strings S and T are special-equivalent if after any number of moves, S == T.
:type A: List[int] # A move consists of choosing two indices i and j with i % 2 == j % 2, and swapping S[i]
:rtype: int with S[j].
""" # Now, a group of special-equivalent strings from A is a non-empty subset S of A such
result = 0 that any string not in S is
n = len(A) # not special-equivalent with any string in S.
A.sort() # Return the number of groups of special-equivalent strings from A.

for i, num in enumerate(A): # For each string create a canonical representation, which is the same for special-
result += (1 << i) * num equivalent strings.
result -= (1 << (n - 1 - i)) * num # Strings are special-equivalent if their chars at even indices can be arranged to be
identical and their chars at
return result % (10 ** 9 + 7) # 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.
# python_1_to_1000/892_Surface_Area_of_3D_Shapes.py # Create a set of the unique representations.
# Time - O(n), total length of all strings
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
class Solution(object):
def numSpecialEquivGroups(self, A):
"""
:type A: List[str] # python_1_to_1000/895_Maximum_Frequency_Stack.py - m
:rtype: int
""" _author_ = 'jake'
def canonical(s): _project_ = 'leetcode'
evens = sorted([s[i] for i in range(0, len(s), 2)])
odds = sorted([s[i] for i in range(1, len(s), 2)]) # https://leetcode.com/problems/maximum-frequency-stack/
return "".join(evens + odds) # Implement FreqStack, a class which simulates the operation of a stack-like data
structure.
return len({canonical(s) for s in A}) # FreqStack has two functions:
# push(int x), which pushes an integer x onto the stack.
# pop(), which removes and returns the most frequent element in the stack.
# python_1_to_1000/894_All_Possible_Full_Binary_Trees.py - m # If there is a tie for most frequent element, the element closest to the top of the
stack is removed and returned.
_author_ = 'jake'
_project_ = 'leetcode' # Maintain a dictionary counting the number of each element in the stack and a
stack_of_stacks. stack_of_stacks
# https://leetcode.com/problems/all-possible-full-binary-trees/ # contains stacks of elements grouped by their counts. push() an element to the stack
# A full binary tree is a binary tree where each node has exactly 0 or 2 children. according to its count.
# Return a list of all possible full binary trees with N nodes. # pop() an element from the top stack_of_stacks.
# Each element of the answer is the root node of one possible tree. # Time - O(1) for all methods
# Each node of each tree in the answer must have node.val = 0. # Space - O(n)
# You may return the final list of trees in any order.
from collections import defaultdict
# 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 class FreqStack(object):
# subtree, build all possible left and right subtrees. Combine the left and right
subtrees in all possible ways. def __init__(self):
# Memoize intermediate results to avoid repetition. self.counter = defaultdict(int) # count of each element in stack
# Time - O(2**n) self.stack_of_stacks = [] # stack_of_stacks[i] is stack of elelemts
# Space - O(2**n) with count of i + 1

class Solution(object): def push(self, x):


def allPossibleFBT(self, N): """
""" :type x: int
:type N: int :rtype: void
:rtype: List[TreeNode] """
""" self.counter[x] += 1
memo = {} count = self.counter[x]

def helper(n): if count > len(self.stack_of_stacks): # new stack


self.stack_of_stacks.append([])
if n % 2 == 0: self.stack_of_stacks[count - 1].append(x)
return []
if n == 1: def pop(self):
return [TreeNode(0)] """
if n in memo: :rtype: int
return memo[n] """
num = self.stack_of_stacks[-1].pop() # pop from highest count stack
result = [] self.counter[num] -= 1

for left_size in range(1, n, 2): if not self.stack_of_stacks[-1]: # remove empty highest stack
self.stack_of_stacks.pop()
right_size = n - 1 - left_size
left_subtrees = helper(left_size) return num
right_subtrees = helper(right_size)

for left_subtree in left_subtrees: # python_1_to_1000/896_Monotonic_Array.py


for right_subtree in right_subtrees:
root = TreeNode(0) _author_ = 'jake'
root.left = left_subtree _project_ = 'leetcode'
root.right = right_subtree
result.append(root) # https://leetcode.com/problems/monotonic-array/
# An array is monotonic if it is either monotone increasing or monotone decreasing.
memo[n] = result # An array A is monotone increasing if for all i <= j, A[i] <= A[j].
return result # 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.
return helper(N)

# Iterate an check all A[i] >= A[i + 1] or A[i] <= A[i + 1] # Space - O(n)
# Time - O(n)
# Space - O(1) class Solution(object):
def subarrayBitwiseORs(self, A):
class Solution(object): """
def isMonotonic(self, A): :type A: List[int]
""" :rtype: int
:type A: List[int] """
:rtype: bool all_or, subarray_or = set(), set()
"""
return all(A[i] <= A[i + 1] for i in range(len(A) - 1)) or all(A[i] >= A[i + 1] for num in A:
for i in range(len(A) - 1)) new_or = {num | x for x in subarray_or}
new_or.add(num)

# python_1_to_1000/897_Increasing_Order_Search_Tree.py all_or |= new_or


subarray_or = new_or
_author_ = 'jake'
_project_ = 'leetcode' return len(all_or)

# https://leetcode.com/problems/increasing-order-search-tree/
# Given a tree, rearrange the tree in in-order so that the leftmost node in the tree is
now the root of the tree, # python_1_to_1000/899_Orderly_Queue.py - h
# and every node has no left child and only 1 right child.
_author_ = 'jake'
# Amend the function signature so it converts a tree and then appends a tail tree. _project_ = 'leetcode'
# 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/orderly-queue/
# subtree and append the tail. Convert the left subtree and append the right subtree. # A string S of lowercase letters is given. Then, we may make any number of moves.
# Time - O(n) # In each move, we choose one of the first K letters (starting from the left), remove it,
# Space - O(n) # and place it at the end of the string.
# Return the lexicographically smallest string we could have after any number of moves.
class Solution(object):
def increasingBST(self, root, tail=None): # tail is appended after converting # If K == 1, we can cycle through the string appending any number of the first characters
tree from root to the end. In this case, try
""" # all possible numbers of characters moved.
:type root: TreeNode # Otherwise if K >= 2 then we can always swap the first 2 characters by moving the second
:rtype: TreeNode before the first.
""" # Since we can perform any number of swaps, we
if root is None: # Time - O(n**2)
return tail # Space - O(n)

copy_root = TreeNode(root.val) # make a duplicate, so root.left and class Solution(object):


root.right are retained def orderlyQueue(self, S, K):
copy_root.right = self.increasingBST(root.right, tail) """
return self.increasingBST(root.left, copy_root) :type S: str
:type K: int
:rtype: str
# python_1_to_1000/898_Bitwise_ORs_of_Subarrays.py - m """
if K > 1:
_author_ = 'jake' return "".join(sorted(S))
_project_ = 'leetcode'
return min(S[i:] + S[:i] for i in range(len(S)))
# https://leetcode.com/problems/bitwise-ors-of-subarrays/
# We have an array A of non-negative integers.
# For every (contiguous) subarray B = [A[i], A[i+1], ..., A[j]] (with i <= j), we take # python_1_to_1000/900_RLE_Iterator.py - m
the bitwise OR of all the
# elements in B, obtaining a result A[i] | A[i+1] | ... | A[j]. _author_ = 'jake'
# Return the number of possible results. _project_ = 'leetcode'
# Results that occur more than once are only counted once in the final answer.
# https://leetcode.com/problems/rle-iterator/
# Create sets of all numbers that can be created by OR and all numbers that can be # Write an iterator that iterates through a run-length encoded sequence.
created using the subarray ending # The iterator is initialized by RLEIterator(int[] A), where A is a run-length encoding
# at the current index. For each index i, the results for the subarray ending at i are of some sequence.
the OR of all previous results # More specifically, for all even i, A[i] tells us the number of times that the non-
# and A[i], and A[i] alone. Update all the results with the results from each index. negative integer value A[i+1] is
# Time - O(n) since the length of subarray_or is at most 30 (the number of bits in any # repeated in the sequence.
num) because each longer # The iterator supports one function: next(int n), which exhausts the next n elements (n
# subarray ending at a given index covers al least all the bits covered by a shorter >= 1) and returns the last
subarray. # element exhausted in this way. If there is no element left to exhaust, next returns -1
instead.
# For example, we start with A = [3,8,0,9,2,5], which is a run-length encoding of the def next(self, price):
sequence [8,8,8,5,5]. """
# This is because the sequence can be read as "three eights, zero nines, two fives". :type price: int
:rtype: int
# Maintain index of the count of the next element to be checked. While next requires mode """
elements than the current result = 1 # today's price has a span of 1
# count, decrement the required n by the count and move to the next element. The
decrement the count by n and return while self.stack and price >= self.stack[-1][0]:
# that element. _, count = self.stack.pop()
# Time - O(1) to initialize, O(n) for next result += count
# Space - O(n)
self.stack.append([price, result])
class RLEIterator(object): return result

def __init__(self, A):


"""
:type A: List[int]
""" # python_1_to_1000/902_Numbers_At_Most_N_Given_Digit_Set.py - h
self.encoding = A
self.length = len(A) _author_ = 'jake'
self.i = 0 # index of next count to be used _project_ = 'leetcode'

def next(self, n): # https://leetcode.com/problems/numbers-at-most-n-given-digit-set/


""" # We have a sorted set of digits D, a non-empty subset of
:type n: int {'1','2','3','4','5','6','7','8','9'}.
:rtype: int # Note that '0' is not included.
""" # Now, we write numbers using these digits, using each digit as many times as we want.
while self.i < self.length and self.encoding[self.i] < n: # require more # For example, if D = {'1','3','5'}, we may write numbers such as '13', '551', '1351315'.
elements than current count # Return the number of positive integers that can be written (using the digits of D) that
n -= self.encoding[self.i] # use all elements are less than or equal to N.
self.i += 2 # move to next count
# Iterate over N from the least to most significant digit. For each suffix of N,
if self.i >= self.length: calculate the number of solutions
return -1 # with the same number of digits as the suffix. Attempt to use each digit d of D as the
first digit of the suffix.
self.encoding[self.i] -= n # use some elements # If d is less than the first digit of suffix the all combinations of other digits are
return self.encoding[self.i + 1] allowed. If d is the same as the
# first digit of the suffix, the results for the previous suffix are allowed.
# Finally add all solutions that use fewer digits.
# python_1_to_1000/901_Online_Stock_Span.py - m # Time - O(log N) (since len(D) is at most 9)
# Space - O(log N)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def atMostNGivenDigitSet(self, D, N):
# https://leetcode.com/problems/online-stock-span/ """
# Write a class StockSpanner which collects daily price quotes for some stock, and :type D: List[str]
returns the span of that stock's :type N: int
# price for the current day. :rtype: int
# The span of the stock's price today is defined as the maximum number of consecutive """
days (starting from today and S = str(N)
# going backwards) for which the price of the stock was less than or equal to today's K = len(S)
price.
# For example, if the price of a stock over the next 7 days were [100, 80, 60, 70, 60, dp = [0] * K + [1] # dp[i] is the result for suffix N[i:] with the same number
75, 85], of digits as N[i:]
# then the stock spans would be [1, 1, 1, 2, 1, 4, 6].
for i in range(K - 1, -1, -1):
# Maintain a stack of descending prices and their spans. While the next price is greater
than or equal to the previous for d in D:
# price, remove the previous price from the stack and add its count to the result. Append
the price and its span to if d < S[i]: # every combination of less significant digits is allowed
# the stack before returning the span. dp[i] += len(D) ** (K - i - 1)
# Time - O(n), worst case is everything must be popped off stack elif d == S[i]: #
# Space - O(n) dp[i] += dp[i + 1]

class StockSpanner(object): return dp[0] + sum(len(D) ** i for i in range(1, K)) # add solutions with
fewer digits
def __init__(self):
self.stack = []

# The problem is to find the longest contiguous subarray containing only 2 different
# python_1_to_1000/903_Valid_Permutations_for_DI_Sequence.py - h elements.
# For the 2 fruits in baskets, store the fruit and their first and last indices in the
_author_ = 'jake' subarray.
_project_ = 'leetcode' # For each new fruit there are 5 cases:
# No previous fruits - set prev
# https://leetcode.com/problems/valid-permutations-for-di-sequence/ # Only one previous fruit - swap prev to other and update prev and the result
# We are given S, a length n string of characters from the set {'D', 'I'}. # Fruit same as prev - update last index of prev and result
# These letters stand for "decreasing" and "increasing". # Fruit same as other - update last index of prev, swap prev and other and update result
# A valid permutation is a permutation P[0], P[1], ..., P[n] of integers {0, 1, ..., n}, # Different fruit - replace other with prev and start index after the end index of other
such that for all i: # Time - O(n)
# If S[i] == 'D', then P[i] > P[i+1], and; # Space - O(1)
# If S[i] == 'I', then P[i] < P[i+1].
# How many valid permutations are there? Since the answer may be large, return your class Solution:
answer modulo 10^9 + 7. def totalFruit(self, tree):
"""
# Dynamic programming. For each character dp[i] is the number of results where the last :type tree: List[int]
number of the permutation is :rtype: int
# the i + 1th smallest amongst all numbers unused so far in that permutation (including """
that last number). prev = [None, float("inf"), float("inf")] # [fruit, first_i, last_i]
# If the next character is "D" then update dp[i] with the sum of all existing dp[j] where other = [None, float("inf"), float("inf")]
j > i, since we can move down
# from any solution where the final digit was ranked higher. result = 1
# Time - O(n**2)
# Space - O(n) for i, fruit in enumerate(tree):

class Solution: if fruit == prev[0]:


def numPermsDISequence(self, S): prev[2] = i
""" result = max(result, i + 1 - min(prev[1], other[1]))
:type S: str
:rtype: int elif fruit == other[0]:
""" other[2] = i
dp = [1] * (len(S) + 1) # dp[i] is nb solutions where the last number other, prev = prev, other
# is the i+1th smallest amongst all unused numbers result = max(result, i + 1 - min(prev[1], other[1]))
for move in S:
elif prev[0] is None:
if move == "D": prev = [fruit, i, i]
dp = dp[1:] # move down from all last numbers apart from smallest
for i in range(len(dp) - 2, -1, -1): elif other[0] is None:
dp[i] += dp[i + 1] # add all solutions with higher ranked last other, prev = prev, [fruit, i, i]
number result = max(result, i + 1 - other[1])
else:
dp = dp[:-1] # move up from all last numbers apart from smallest else:
for i in range(1, len(dp)): other = [prev[0], other[2] + 1, prev[2]]
dp[i] += dp[i - 1] # add all solutions with lower ranked last prev = [fruit, i, i]
number
return result
return dp[0] % (10 ** 9 + 7)

# python_1_to_1000/904_Fruit_Into_Baskets.py - m # python_1_to_1000/905_Sort_Array_By_Parity.py

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# https://leetcode.com/problems/fruit-into-baskets/ # https://leetcode.com/problems/sort-array-by-parity/
# In a row of trees, the i-th tree produces fruit with type tree[i]. # Given an array A of non-negative integers, return an array consisting of all the even
# You start at any tree of your choice, then repeatedly perform the following steps: elements of A,
# Add one piece of fruit from this tree to your baskets. If you cannot, stop. # followed by all the odd elements of A.
# Move to the next tree to the right of the current tree. If there is no tree to the # You may return any answer array that satisfies this condition
right, stop.
# Note that you do not have any choice after the initial choice of starting tree: you # Iterate over A, alternately adding elements to lists of elements at add and even
must perform step 1, indices. Concatenate result.
# then step 2, then back to step 1, then step 2, and so on until you stop. # In Pythonn the iteration is achieved by list comprehension.
# You have two baskets, and each basket can carry any quantity of fruit, but you want # Time - O(n)
each basket to only carry # Space - O(n)
# one type of fruit each.
# What is the total amount of fruit you can collect with this procedure? class Solution(object):
def sortArrayByParity(self, A): result += 1
"""
:type A: List[int] prev_palis, palis = palis, new_palis
:rtype: List[int]
"""
return [num for num in A if num % 2 == 0] + [num for num in A if num % 2 == 1] # python_1_to_1000/907_Sum_of_Subarray_Minimums.py - m

_author_ = 'jake'
# python_1_to_1000/906_Super_Palindromes.py - h _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/sum-of-subarray-minimums/


_project_ = 'leetcode' # Given an array of integers A, find the sum of min(B), where B ranges over every
(contiguous) subarray of A.
# https://leetcode.com/problems/super-palindromes/ # Since the answer may be large, return the answer modulo 10^9 + 7.
# Let's say a positive integer is a superpalindrome if it is a palindrome, and it is also
the square of a palindrome. # Stack contains indices of elements that have not been used as the minimum of some
# Now, given two positive integers L and R (represented as strings), return the number of subarray.
superpalindromes # Stack refers to elements in non-decreasing order. Iterate over A. While the current
# in the inclusive range [L, R]. element of A is less than the
# top of the stack, then the top of the stack is the minimum of all subarrays bounded by
# For all palindromes between sqrt(L) and sqrt(R), test if their square is a palindrome. the previous stack item
# Build ordered lists of palindromes of length x by surrounding all palindromes of length # and the current element. Add to the result the value of the element * number of
x - 2 with each digit. subarrays with all possible left
# Palindromes that begin with 0 are built but not check if they are superpalindromes. # and right boundaries.
# Time - O(n log n) # Time - O(n)
# Max length of palindrome to check is k = log(R ** 0.5) = 0.5 * log R # Space - O(n)
# Number of palindromes of length <= k is O(10 ** ((k + 1) // 2)), each takes O(k) time
to build and check if square is class Solution:
# a super palindrome. def sumSubarrayMins(self, A):
# Space - O(n log n) """
:type A: List[int]
class Solution(object): :rtype: int
def superpalindromesInRange(self, L, R): """
""" A = [float("-inf")] + A + [float("-inf")]
:type L: str result = 0
:type R: str stack = []
:rtype: int
""" for i, num in enumerate(A):
L_sqrt = int(int(L) ** 0.5)
R_sqrt = int((int(R) + 1) ** 0.5) while stack and num < A[stack[-1]]:
digits = [str(i) for i in range(10)] j = stack.pop()
result += A[j] * (j - stack[-1]) * (i - j) # left boundaries of (j - top
def is_palindrome(i): of stack), right of (i - j)
return str(i) == str(i)[::-1]
stack.append(i)
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)) return result % (10 ** 9 + 7)

for _ in range(2, 11): # gradually increase the palindrome


length
# python_1_to_1000/908_Smallest_Range_I.py
new_palis = []
_author_ = 'jake'
for digit in digits: _project_ = 'leetcode'
for pal in prev_palis: # palindromes of length - 2
# https://leetcode.com/problems/smallest-range-i/
new_pal = digit + pal + digit # make new palindrome # Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <=
new_palis.append(new_pal) K, and add x to A[i].
# After this process, we have some array B.
if new_pal[0] == "0": # do not check if superpalindrome # Return the smallest possible difference between the maximum value of B and the minimum
continue value of B.

num = int(new_pal) # 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
if num > R_sqrt: # greater than maximum possible # then all elements can be equalized. Else the range can be decreased by 2K.
palindrome # Time - O(n)
return result # Space - O(1)

if L_sqrt <= num and is_palindrome(num ** 2): # superpalindrome class Solution:

def smallestRangeI(self, A, K):


""" if i in visited or i >= len(linear): # ignore positions seen already
:type A: List[int] or too far
:type K: int continue
:rtype: int visited.add(i)
"""
range = max(A) - min(A) if linear[i] != -1: # snake or ladder
return max(0, range - 2 * K) i = linear[i]
if i == len(linear) - 1:
return moves
# python_1_to_1000/909_Snakes_and_Ladders.py - m
for step in range(1, 7): # take 1 to 6 steps
_author_ = 'jake' new_queue.add(i + step)
_project_ = 'leetcode'
moves += 1
# https://leetcode.com/problems/snakes-and-ladders/ visited |= queue
# On an N x N board, the numbers from 1 to N*N are written boustrophedonically starting queue = new_queue
from the bottom left of the
# board, and alternating direction each row. return -1
# You start on square 1 of the board (which is always in the last row and first column).
# 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. # python_1_to_1000/910_Smallest_Range_II.py - m
# (This choice simulates the result of a standard 6-sided die roll: ie., there are always
at most 6 destinations.) _author_ = 'jake'
# If S has a snake or ladder, you move to the destination of that snake or ladder. _project_ = 'leetcode'
Otherwise, you move to S.
# A board square on row r and column c has a "snake or ladder" if board[r][c] != -1. # https://leetcode.com/problems/smallest-range-ii/
# The destination of that snake or ladder is board[r][c]. # Given an array A of integers, for each integer A[i] we need to choose either x = -K or
# Note that you only take a snake or ladder at most once per move: if the destination to x = K,
a snake or ladder is the # and add x to A[i] (only once).
# start of another snake or ladder, you do not continue moving. # After this process, we have some array B.
# For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination # Return the smallest possible difference between the maximum value of B and the minimum
square is `2`, then you value of B.
# 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, # Sort the array (its starting order is irrelevant). For each split point i, the smaller
return -1. 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.
# Breadth-first search. First convert the board to a 1-dimensional list of the squares in Find the minimum of the left
order. # and right sides, and the maximum of the left and right sides. Update the result with
# Queue contains all current indices. In each cycle of the while loop, for each index the difference of the maximum
move up or down any ladder # and minimum if lower than the current result.
# or snake, then take from 1 to 6 steps. # Time - O(n log n)
# Time - O(n**2) # Space - O(n)
# Space - O(n**2)
class Solution:
class Solution: def smallestRangeII(self, A, K):
def snakesAndLadders(self, board): """
""" :type A: List[int]
:type board: List[List[int]] :type K: int
:rtype: int :rtype: int
""" """
linear = [-1] # convert board to a list (deboustrophedonization) A = sorted(A)
reverse = False # alternate rows are appended not reversed and result = A[-1] - A[0] # move all elemnts in same direction
reversed
left_min = A[0] + K # min of left and max of right are fixed
for row in board[::-1]: # start from last row right_max = A[-1] - K
linear += row[::-1] if reverse else row
reverse = not reverse for i in range(len(A) - 1): # A[i] is the last index moved up, A[i + 1] is first
moved down
moves = 0
visited = set() # indices (before any snake or ladder) lower = min(left_min, A[i + 1] - K) # min of left and right
queue = {1} # board moves are indexed from 1 upper = max(right_max, A[i] + K) # max of left and right
result = min(upper - lower, result)
while queue:
return result
new_queue = set()

for i in queue: # python_1_to_1000/911_Online_Election.py - m


_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/sort-an-array/
# https://leetcode.com/problems/online-election/ # Given an array of integers nums, sort the array in ascending order.
# In an election, the i-th vote was cast for persons[i] at time times[i].
# Now, we would like to implement the following query function: TopVotedCandidate.q(int # Use the in-built sorting function.
t) will return the number # Time - O(n log n)
# of the person that was leading the election at time t. # Space - O(n)
# Votes cast at time t will count towards our query.
# In the case of a tie, the most recent vote (among tied candidates) wins. class Solution(object):
def sortArray(self, nums):
# Create a list of the leading candidate at each time. Add each candidate to a dictionary """
of counts. If there is a :type nums: List[int]
# clear leader, update leader with thie candidate alone, else append candidate to :rtype: List[int]
leaders. Use max_count to identify """
# whether a candidate is a leader. return sorted(nums)
# Binary search to look up a time. If time at index returned is later than t then return
the leading candidate at
# the previous index. If time at index returned == t then return the leading candidate at
that index. # python_1_to_1000/913_Cat_and_Mouse.py - h
# Time - O(n) for init, O(log n) for q
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
from collections import defaultdict
import bisect # https://leetcode.com/problems/cat-and-mouse/
# A game on an undirected graph is played by two players, Mouse and Cat, who alternate
class TopVotedCandidate: turns.
# The graph is given as follows: graph[a] is a list of all nodes b such that ab is an
def __init__(self, persons, times): edge of the graph.
""" # Mouse starts at node 1 and goes first, Cat starts at node 2 and goes second, and there
:type persons: List[int] is a Hole at node 0.
:type times: List[int] # During each player's turn, they must travel along one edge of the graph that meets
""" where they are.
self.times = times # For example, if the Mouse is at node 1, it must travel to any node in graph[1].
self.leader = [] # leader[i] is the leading candidate at # Additionally, it is not allowed for the Cat to travel to the Hole (node 0.)
times[i] # Then, the game can end in 3 ways:
counts = defaultdict(int) # cumulative count of votes for each # If ever the Cat occupies the same node as the Mouse, the Cat wins.
candidate # If ever the Mouse reaches the Hole, the Mouse wins.
max_count = 0 # number of votes for the leading # If ever a position is repeated (ie. the players are in the same position as a previous
candidate turn, and it is the
# same player's turn to move), the game is a draw.
for person, time in zip(persons, times): # Given a graph, and assuming both players play optimally, return 1 if the game is won by
Mouse, 2 if the game
counts[person] += 1 # is won by Cat, and 0 if the game is a draw.

if counts[person] > max_count: # new unique leader # Create a graphs of states of (mouse_node, cat_node, next_mover). Attempt to find the
max_count += 1 winner from each state.
leaders = [person] # Initially states with mouse at node 0 has mouse as winner and states with cat at node
elif counts[person] == max_count: # join other leaders of mouse have cat as winner.
leaders.append(person) # All other states are drawn initially. Add states with known winners to a queue.
# Initialise a count of the number of nodes that are connected to each state and do not
self.leader.append(leaders[-1]) # most recent if tied have known winners.
# For each state in the queue, check each predecessor state with an unknown winner. If we
def q(self, t): can move from the predecessor
""" # to the state with the known winner, predecessor state has the same winner. Else reduce
:type t: int the count of unknown winners
:rtype: int # linked to the predecessor. If the count is zero, the animal whose turn it is to move at
""" the predecessor cannot win.
i = bisect.bisect_left(self.times, t) # Time - O(n**3) since there are O(n**2) states each with O(n) links.
# Space - O(n**2)
if i == len(self.times) or self.times[i] > t:
return self.leader[i - 1] from collections import defaultdict, deque

return self.leader[i] class Solution(object):


def catMouseGame(self, graph):
"""
# python_1_to_1000/912_Sort_an_Array.py - m :type graph: List[List[int]]
:rtype: int

""" # Time - O(n**2)


DRAW, MOUSE, CAT = 0, 1, 2 # Space - O(n)
n = len(graph)
from collections import Counter
def parents(mouse, cat, turn): # find predecessor states
if turn == CAT: class Solution:
return [(new_mouse, cat, 3 - turn) for new_mouse in graph[mouse]] def hasGroupsSizeX(self, deck):
return [(mouse, new_cat, 3 - turn) for new_cat in graph[cat] if new_cat != 0] """
:type deck: List[int]
state_winner = defaultdict(int) # map from state to its winner, DRAW by :rtype: bool
default """
freq = Counter(deck)
degree = {} # map node to count of connected states that
are not winners min_count = min(freq.values())
for mouse in range(n): if min_count == 1: # each group must have at least 2 cards
for cat in range(n): return False
degree[mouse, cat, MOUSE] = len(graph[mouse])
degree[mouse, cat, CAT] = len(graph[cat]) - (0 in graph[cat]) for X in range(2, min_count + 1):
if all(count % X == 0 for count in freq.values()):
queue = deque() # queue contains all states with known winner return True
for i in range(n):
for turn in [MOUSE, CAT]: return False
state_winner[0, i, turn] = MOUSE # mouse wins if at hole for any turn
and any cat position
queue.append((0, i, turn, MOUSE)) # python_1_to_1000/915_Partition_Array_into_Disjoint_Intervals.py - m
if i > 0: # cat wins if at mouse unless at hole, for
any turn and any mouse position _author_ = 'jake'
state_winner[i, i, turn] = CAT _project_ = 'leetcode'
queue.append((i, i, turn, CAT))
# https://leetcode.com/problems/partition-array-into-disjoint-intervals/
while queue: # Given an array A, partition it into two (contiguous) subarrays left and right so that:
# Every element in left is less than or equal to every element in right.
i, j, turn, winner = queue.popleft() # get state with known winner # left and right are non-empty.
# left has the smallest possible size.
for i2, j2, prev_turn in parents(i, j, turn): # for all predecessor states # Return the length of left after such a partitioning. It is guaranteed that such a
without known winners partitioning exists.
if state_winner[i2, j2, prev_turn] is DRAW:
# Iterate along array tracking the maximum number in left partition, its index and the
if prev_turn == winner: # can move to a winning state overall maximum number.
state_winner[i2, j2, prev_turn] = winner # If the next number is less than the maximum in the left partition, it must extend the
queue.append((i2, j2, prev_turn, winner)) left partition. When the left
# partition is extended, its maximum becomes the overall maximum.
else: # reduce count of unknown winner # Time - O(n)
predecessor states # Space - O(1)
degree[i2, j2, prev_turn] -= 1
if degree[i2, j2, prev_turn] == 0: # predecessor always leads to class Solution:
loss def partitionDisjoint(self, A):
state_winner[i2, j2, prev_turn] = turn """
queue.append((i2, j2, prev_turn, turn)) :type A: List[int]
:rtype: int
return state_winner[1, 2, MOUSE] """
last_left = 0
max_left = max_overall = A[0]
# python_1_to_1000/914_X_of_a_Kind_in_a_Deck_of_Cards.py
for i, num in enumerate(A[1:], 1):
_author_ = 'jake'
_project_ = 'leetcode' max_overall = max(max_overall, num)

# https://leetcode.com/problems/x-of-a-kind-in-a-deck-of-cards/ if num < max_left: # smaller must be included in left


# In a deck of cards, each card has an integer written on it. last_left = i
# Return true if and only if you can choose X >= 2 such that it is possible to split the max_left = max_overall
entire deck into
# 1 or more groups of cards, where: return last_left + 1
# Each group has exactly X cards.
# All the cards in each group have the same integer.
# python_1_to_1000/916_Word_Subsets.py - m
# Count the number of each card. Attempt all values of X from 2 to the size of the
smallest group. Check whether _author_ = 'jake'
# each group is divisible by X. _project_ = 'leetcode'
left, right = 0, len(S) - 1
# https://leetcode.com/problems/word-subsets/
# We are given two arrays A and B of words. Each word is a string of lowercase letters. while left < right:
# Now, say that word b is a subset of word a if every letter in b occurs in a, including
multiplicity. while left < right and S[left] not in letters:
# For example, "wrr" is a subset of "warrior", but is not a subset of "world". left += 1
# Now say a word a from A is universal if for every b in B, b is a subset of a. while left < right and S[right] not in letters:
# Return a list of all universal words in A. You can return the words in any order. right -= 1

# Find the maximum required number of each letter for all words in B. S[left], S[right] = S[right], S[left]
# Check each word in A to see if it has at least the required number of each letter in B. left += 1
# Time - O(m + n), total length of all words in A and B right -= 1
# Space - O(1) since dictionary keys are limited by the number of distinct letters
return "".join(S)
from collections import Counter, defaultdict

class Solution: # python_1_to_1000/918_Maximim_Sum_Circular_Subarray.py - m


def wordSubsets(self, A, B):
""" _author_ = 'jake'
:type A: List[str] _project_ = 'leetcode'
:type B: List[str]
:rtype: List[str] # https://leetcode.com/problems/maximum-sum-circular-subarray/
""" # Given a circular array C of integers represented by A, find the maximum possible sum of
required = defaultdict(int) # map of each required letter in B to its required a non-empty subarray of C.
count # Here, a circular array means the end of the array connects to the beginning of the
array.
for b in B: # Formally, C[i] = A[i] when 0 <= i < A.length, and C[i+A.length] = C[i] when i >= 0.
freq = Counter(b) # Also, a subarray may only include each element of the fixed buffer A at most once.
for letter, count in freq.items(): # Formally, for a subarray C[i], C[i+1], ..., C[j], there does not exist i <= k1, k2 <= j
required[letter] = max(required[letter], count) with
# k1 % A.length = k2 % A.length.
results = []
for a in A: # Iterate over A, finding the max and min sum subarrays that end at each index.
# The result either does not use the circularity of A, in which case it is the maximum
freq = Counter(a) sum subarray within A.
if all(freq[letter] >= count for letter, count in required.items()): # Or the result is the sum of A minus the minimum sun subarray within A.
results.append(a) # Time - O(n)
# Space - O(1)
return results
class Solution(object):
def maxSubarraySumCircular(self, A):
"""
# python_1_to_1000/917_Reverse_Only_Letters.py :type A: List[int]
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode' if all(num <= 0 for num in A):
return max(A)
# https://leetcode.com/problems/reverse-only-letters/
# Given a string S, return the "reversed" string where all characters that are not a overall_max, overall_min = float('-inf'), float('inf')
letter stay in the same place, max_ending_here, min_ending_here = 0, 0
# and all letters reverse their positions.
for num in A:
# Convert to list. 2 pointers start from left and right. Move each pointer inwards until
they both reach letters. max_ending_here = max(max_ending_here, 0) + num # if previous max
# Swap the letters and move the pointers another step each. Stop when pointers overlap. negative, set to zero
# Time - O(n) min_ending_here = min(min_ending_here, 0) + num # if previous min
# Space - O(n) positive, set to zero

import string overall_max = max(overall_max, max_ending_here)


overall_min = min(overall_min, min_ending_here)
class Solution:
def reverseOnlyLetters(self, S): return max(overall_max, sum(A) - overall_min)
"""
:type S: str
:rtype: str # python_1_to_1000/919_Complete_Binary_Tree_Inserter.py - m
"""
letters = set(string.ascii_lowercase + string.ascii_uppercase) _author_ = 'jake'
_project_ = 'leetcode'
S = [c for c in S]

# https://leetcode.com/problems/complete-binary-tree-inserter/ # Every song is played at least once


# A complete binary tree is a binary tree in which every level, except possibly the last, # A song can only be played again only if K other songs have been played
is completely filled, # Return the number of possible playlists. As the answer can be very large, return it
# and all nodes are as far left as possible. modulo 10^9 + 7.
# Write a data structure CBTInserter that is initialized with a complete binary tree and
supports the following: # We can extend a partial playlist by A) adding any song that has not been played before
# CBTInserter(TreeNode root) initializes the data structure on a given tree with head (if any), or
node root; # B) adding a song that has been played before but is not in the K most recent songs.
# CBTInserter.insert(int v) will insert a TreeNode into the tree with value node.val = v # Create a mapping from the number of different songs used to the count of playlists.
so that the tree remains # Initially there is one playlist with no songs.
# complete, and returns the value of the parent of the inserted TreeNode; # For each additional song, add playlists with every new song, If we have used more than
# CBTInserter.get_root() will return the head node of the tree. K songs, add playlists with
# all songs not in the most recent K. Note the most recent K are all different songs.
# Create a list of nodes of the tree from each row in order. Insert a new node by # Time - O(LN)
appending it to the list. Node's # Space - O(N)
# parent has index (i - 1) // 2 - 1 where i is node index (indices start from zero). Link
parent to node according from collections import defaultdict
# to parity of node index.
# Time - O(n) for init, O(1) for insert and get_root class Solution:
# Space - O(n) def numMusicPlaylists(self, N, L, K):
"""
class CBTInserter: :type N: int
:type L: int
def __init__(self, root): :type K: int
""" :rtype: int
:type root: TreeNode """
""" used_count = {0: 1} # used_count[i] is the number of playlists that have used
self.nodelist = [root] i different songs

for node in self.nodelist: # list is extended by children during for song in range(L):
iteration
if node.left: new_used_count = defaultdict(int)
self.nodelist.append(node.left) for used, count in used_count.items():
if node.right:
self.nodelist.append(node.right) new_used_count[used + 1] += count * (N - used) # add any of the (N -
used) unused songs
def insert(self, v): if used > K:
""" new_used_count[used] += count * (used - K) # add any used song not
:type v: int in the most recent K songs
:rtype: int
""" used_count = new_used_count
node = TreeNode(v) # add new node to list
self.nodelist.append(node) return used_count[N] % (10 ** 9 + 7)
n = len(self.nodelist)

parent = self.nodelist[(n // 2) - 1] # python_1_to_1000/921_Minimum_Add_to_Make_Parentheses_Valid.py - m


if n % 2 == 0:
parent.left = node _author_ = 'jake'
else: _project_ = 'leetcode'
parent.right = node
# https://leetcode.com/problems/inimum-add-to-make-parentheses-valid/
return parent.val # Given a string S of '(' and ')' parentheses, we add the minimum number of parentheses (
'(' or ')',
def get_root(self): # and in any positions ) so that the resulting parentheses string is valid.
""" # Formally, a parentheses string is valid if and only if:
:rtype: TreeNode # It is the empty string, or
""" # It can be written as AB (A concatenated with B), where A and B are valid strings, or
return self.nodelist[0] # tree structure is maintained so just return root # It can be written as (A), where A is a valid string.
# Given a parentheses string, return the minimum number of parentheses we must add to
make the resulting string valid.
# python_1_to_1000/920_Number_of_Music_Playlists.py - h
# Track net balance of open minus closed brackets. Add an opening bracket whenever the
_author_ = 'jake' balance is negative, because
_project_ = 'leetcode' # there cannot be more closed than open brackets. At the end, add closing brackets for
all open brackets.
# https://leetcode.com/problems/number-of-music-playlists/ # Time - O(n)
# Your music player contains N different songs and she wants to listen to L (not # Space - O(1)
necessarily different)
# songs during your trip. You create a playlist so that: class Solution:
def minAddToMakeValid(self, S): # to equal the target. Reject cases when the other number is outside the possible range
""" or any count is zero.
:type S: str # If all numbers are the same, add to the result the count of combinations of 3 indices
:rtype: int with that number.
""" # If the 2 numbers in the pair are the same, add to the result the count of combinations
additions = 0 # number of brackets added of 2 indices with that
net_open = 0 # balance of opening brackets minus closing brackets # number times the count of other.
# If other > med, add all combinations of the 3 numbers. These are only added to the
for c in S: result when in order to avoid
# double counting.
net_open += 1 if c == "(" else -1 # update the net_open balance # Time - O(n + k**2) where k is the range of values of A
# Space - O(k)
if net_open == -1: # more closing than opening, add an opening bracket
additions += 1 class Solution:
net_open = 0 def threeSumMulti(self, A, target):
"""
return additions + net_open # close all remaining open brackets :type A: List[int]
:type target: int
:rtype: int
# python_1_to_1000/922_Sort_Array_By_Parity_II.py """
counts = [0] * 101
_author_ = 'jake' for num in A:
_project_ = 'leetcode' counts[num] += 1

# https://leetcode.com/problems/sort-array-by-parity-ii/ result = 0
# Given an array A of non-negative integers, half of the integers in A are odd, and half
of the integers are even. for small, small_count in enumerate(counts):
# Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is if small_count == 0:
even. continue
# You may return any answer array that satisfies this condition.
for med, med_count in enumerate(counts[small:], small):
# Iterate over even indices, tracking the next odd index to be checked. If the value at if med_count == 0:
an even index is not even, continue
# find the next odd index that is not odd and swap values.
# Time - O(n) other = target - small - med
# Space - O(n) if other < 0 or other > 100 or counts[other] == 0:
continue
class Solution: other_count = counts[other]
def sortArrayByParityII(self, A):
""" if small == med == other:
:type A: List[int] result += small_count * (small_count - 1) * (small_count - 2) // 6
:rtype: List[int] elif small == med: # exactly 2 numbers are the same
""" result += small_count * (small_count - 1) * other_count // 2
odd = 1 elif other > med: # add if in order (med is always > small)
result += small_count * med_count * other_count
for even in range(0, len(A), 2):
return result % (10 ** 9 + 7)
if A[even] % 2 == 1:

while A[odd] % 2 == 1: # python_1_to_1000/924_Minimize_Malware_Spread.py - h


odd += 2
A[odd], A[even] = A[even], A[odd] _author_ = 'jake'
_project_ = 'leetcode'
return A
# https://leetcode.com/problems/minimize-malware-spread/
# In a network of nodes, each node i is directly connected to another node j if and only
# python_1_to_1000/923_3Sum_With_Multiplicity.py - m if graph[i][j] = 1.
# Some nodes initial are initially infected by malware.
_author_ = 'jake' # Whenever two nodes are directly connected and at least one of those two nodes is
_project_ = 'leetcode' infected by malware,
# both nodes will be infected by malware.
# https://leetcode.com/problems/3sum-with-multiplicity/ # This spread of malware will continue until no more nodes can be infected in this
# Given an integer array A, and an integer target, return the number of tuples i, j, k manner.
such that i < j < k # Suppose M(initial) is the final number of nodes infected with malware in the entire
# and A[i] + A[j] + A[k] == target. network,
# As the answer can be very large, return it modulo 10^9 + 7. # after the spread of malware stops.
# We will remove one node from the initial list.
# Count the frequency of each number in A. For each pair of numbers, determine the other # Return the node that if removed, would minimize M(initial).
number required for the sum # If multiple nodes could be removed to minimize M(initial), return such a node with the

smallest index. in typed. If there are more


# Note that if a node was removed from the initial list of infected nodes, it may still # chars in name, it was not long pressed. Ensure all chars of typed have been accounted
be infected later as for.
# a result of the malware spread. # Time - O(m + n)
# Space - O(1)
# For each node, find all connected nodes. If there is only one initially infected node
in the connected group, if it class Solution:
# was not infected it would improve overall the infection by the count of the group. def isLongPressedName(self, name, typed):
# Find the group of each node, ignoring nodes that already have groups. """
# If every group has more than one initially infected node, return the node with the :type name: str
lowest index since removing :type typed: str
# any node cannot reduce the ultimate infection. :rtype: bool
# Time - O(n) each node is visited and tested for membership of initial """
# Space - O(n) typed_i, name_i = 0, 0 # indices of next char to check in each
string
class Solution:
def minMalwareSpread(self, graph, initial): while name_i < len(name):
"""
:type graph: List[List[int]] c, c_count = name[name_i], 1 # the char and the its count
:type initial: List[int] name_i += 1
:rtype: int while name_i < len(name) and name[name_i] == c: # count identical
""" chars in name
best_reduction = 0 # the best reduction of infected nodes name_i += 1
best_node = min(initial) # the node that improves the infection, by c_count += 1
default the lowest index
initial = set(initial) # convert to set while typed_i < len(typed) and typed[typed_i] == c: # count identical
chars in typed
def connected(node): # recursively update group with all connected typed_i += 1
nodes c_count -= 1
if node in group:
return if c_count > 0: # more in name than typed
group.add(node) return False
[connected(nbor) for nbor, linked in enumerate(graph[node]) if linked == 1] #
loop return typed_i == len(typed) # must use all of typed

visited = set() # all nodes that are part of a group


for node in range(len(graph)): # python_1_to_1000/926_Flip_String_to_Monotone_Increasing.py - m

if node in visited: _author_ = 'jake'


continue _project_ = 'leetcode'

group = set() # https://leetcode.com/problems/flip-string-to-monotone-increasing/


connected(node) # A string of '0's and '1's is monotone increasing if it consists of some number of '0's
overlap = initial & group # set of all nodes in the group that are (possibly 0),
initially infected # followed by some number of '1's (also possibly 0.)
# 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
if len(overlap) == 1 and len(group) > best_reduction: a '0'.
best_reduction = len(group) # Return the minimum number of flips to make S monotone increasing.
best_node = overlap.pop()
# To make monotone increasing, there is one point in S where all chars on the left are 0
visited |= group and all on the right are 1.
# Count the zeros. Initial case is to flip all zeros to ones.
return best_node # For each char, if zero then decrement the number of zeros to be flipped (since the zero
is then on the left).
# If one, then increment the number of ones to be flipped.
# python_1_to_1000/925_Long_Pressed_Name.py # Time - O(n)
# Space - O(1)
_author_ = 'jake'
_project_ = 'leetcode' class Solution:
def minFlipsMonoIncr(self, S):
# https://leetcode.com/problems/long-pressed-name/ """
# Your friend is typing his name into a keyboard. :type S: str
# Sometimes, when typing a character c, the key might get long pressed, and the character :rtype: int
will be typed 1 or more times. """
# You examine the typed characters of the keyboard. zeros, ones = S.count("0"), 0
# Return True if it is possible that it was your friends name, with some characters result = zeros
(possibly none) being long pressed.
for c in S:
# For each char of name, count the run of identical chars. Count the run of the same char
if c == "0": return [-1, -1] # first and second part set bit patterns must be
zeros -= 1 same
else:
ones += 1 third_start = second_start + length
while A[third_start] == 0:
result = min(result, zeros + ones) third_start += 1

return result if A[first_start:first_end + 1] != A[third_start:third_start + length]:


return [-1, -1]

# python_1_to_1000/927_Three_Equal_Parts.py - h trailing_zeros = len(A) - third_start - length # extend 1st and 2nd parts by
trailing_zeros from 3rd part
_author_ = 'jake' first_end += trailing_zeros
_project_ = 'leetcode' second_end = second_start + length - 1 + trailing_zeros

# https://leetcode.com/problems/three-equal-parts/ if second_start < first_end + 1 or third_start < second_end + 1: # cannot have


# Given an array A of 0s and 1s, divide the array into 3 non-empty parts such that all of overlap of parts
these parts represent the return [-1, -1]
# same binary value.
# If it is possible, return any [i, j] with i+1 < j, such that: return [first_end, second_end + 1]
# A[0], A[1], ..., A[i] is the first part;
# A[i+1], A[i+2], ..., A[j-1] is the second part, and
# A[j], A[j+1], ..., A[A.length - 1] is the third part.
# All three parts have equal binary value. # python_1_to_1000/928_Minimize_Malware_Spread_II.py - h
# If it is not possible, return [-1, -1].
# Note that the entire part is used when considering what binary value it represents. _author_ = 'jake'
# For example, [1,1,0] represents 6 in decimal, not 3. _project_ = 'leetcode'
# Also, leading zeros are allowed, so [0,1,1] and [1,1] represent the same value.
# https://leetcode.com/problems/minimize-malware-spread-ii/
# The number of set bits must be divisible by 3. Find the start and end indices # In a network of nodes, each node i is directly connected to another node j if and only
containing one_count // 3 set bits. if graph[i][j] = 1.
# Check that the second and third parts with the first bit set and the same length as the # Some nodes initial are initially infected by malware.
first part are identical. # Whenever two nodes are directly connected and at least one of those two nodes is
# Find the trailing zeros from the third part and extend the ends of the first and second infected by malware,
parts accordingly. # both nodes will be infected by malware.
# Check that the parts do not overlap. There may be additional leading zeros. # This spread of malware will continue until no more nodes can be infected in this
# Time - O(n) manner.
# Space - O(1) # Suppose M(initial) is the final number of nodes infected with malware in the entire
network,
class Solution: # after the spread of malware stops.
def threeEqualParts(self, A): # We will remove one node from the initial list, completely removing it and any
""" connections from this node
:type A: List[int] # to any other node.
:rtype: List[int] # Return the node that if removed, would minimize M(initial).
""" # If multiple nodes could be removed to minimize M(initial), return such a node with the
one_count = sum(A) smallest index.
if one_count == 0: # all zeros, split anywhere
return [0, 2] # 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
ones_per_part, remainder = divmod(one_count, 3) count the number of nodes
if remainder != 0: # cannot divide set bits into 3 equal groups # initially infected.
return [-1, -1] # The remove each initial node in turn and count the nodes that can be infected from the
remaining initial nodes.
first_start = 0 # Time - O(n**3), where n is the number of nodes since O(n**2) to explore the graph and
while A[first_start] == 0: # find first set bit O(n) initial nodes.
first_start += 1 # Space - O(n**2)

first_end = first_start class Solution:


count = 1 def minMalwareSpread(self, graph, initial):
while count < ones_per_part: # find ones_per_part-th set bit """
first_end += 1 :type graph: List[List[int]]
count += A[first_end] :type initial: List[int]
length = first_end - first_start + 1 :rtype: int
"""
second_start = first_end + 1 neighbours = {} # map node to list of neighbours
while A[second_start] == 0: # first set bit of second part for i, row in enumerate(graph):
second_start += 1 neighbours[i] = [j for j, val in enumerate(row) if val == 1 and j != i]

if A[first_start:first_end + 1] != A[second_start:second_start + length]: def infected(): # return number of infected nodes, starting

from initial for email in emails:


for node in initial:
connected(node) local, domain = email.split("@")
return len(visited)
plus = local.index("+")
def connected(node): # visit all connected nodes recursively if plus != -1:
if node in visited: local = local[:plus]
return
visited.add(node) local = local.replace(".", "")
for nbor in neighbours[node]:
connected(nbor) unique.add(local + domain)

visited = set() return len(unique)


initial_infected = infected()

best_gain = 0 # best reduction in infection, achieved by # python_1_to_1000/930_Binary_Subarrays_With_Sum.py - m


removing best_node
best_node = None _author_ = 'jake'
_project_ = 'leetcode'
for removed in sorted(initial): # sort so lowest index is returned first in
the event of a tie # https://leetcode.com/problems/binary-subarrays-with-sum/
# In an array A of 0s and 1s, how many non-empty subarrays have sum S?
visited = {removed} # do not visit removed
infected() # Iterate along A, counting the number of each prefix sum of A.
gain = initial_infected - len(visited) + 1 # add one for removed node # For every prefix subarray, we can make a subarray of sum S with every other prefix
if gain > best_gain: subarray of sum running - S.
best_gain = gain # Time - O(n)
best_node = removed # Space - O(n)

return best_node from collections import defaultdict

class Solution:
# python_1_to_1000/929_Unique_Email_Addresses.py def numSubarraysWithSum(self, A, S):
"""
_author_ = 'jake' :type A: List[int]
_project_ = 'leetcode' :type S: int
:rtype: int
# https://leetcode.com/problems/unique-email-addresses/ """
# Every email consists of a local name and a domain name, separated by the @ sign. result = 0
# For example, in [email protected], alice is the local name, and leetcode.com is the running = 0 # prefix sum
domain name. partials = defaultdict(int, {0: 1}) # map prefix sum to its count
# 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 for i, a in enumerate(A):
address, mail sent there will running += a
# be forwarded to the same address without dots in the local name. result += partials[running - S]
# For example, "[email protected]" and "[email protected]" forward to the same email partials[running] += 1 # increment the count with this prefix
address. sum
# Note that this rule does not apply for domain names.
# If you add a plus ('+') in the local name, everything after the first plus sign will be return result
ignored.
# This allows certain emails to be filtered, for example [email protected] will be
forwarded to [email protected]. # python_1_to_1000/931_Minimum_Falling_Path_Sum.py - m
# Again, this rule does not apply for domain names.
# It is possible to use both of these rules at the same time. _author_ = 'jake'
# Given a list of emails, we send one email to each address in the list. _project_ = 'leetcode'
# How many different addresses actually receive mails?
# https://leetcode.com/problems/minimum-falling-path-sum/
# Split by "@" then discard any part of the local name afte the "+" and remove all ".". # Given a square array of integers A, we want the minimum sum of a falling path through
# Time - O(n) A.
# Space - O(n) # A falling path starts at any element in the first row, and chooses one element from
each row.
class Solution: # The next row's choice must be in a column that is different from the previous row's
def numUniqueEmails(self, emails): column by at most one.
"""
:type emails: List[str] # Dynamic programming. For each row from the bottom upwards, find the minimum falling
:rtype: int path sum from each cell.
""" # The minimum from any cell is the value of that cell plus the minimum of the results
unique = set() from the 3 cells in the row below.
# Time - O(n**2)
# Space - O(n)

class Solution: # python_1_to_1000/933_Number_of_Recent_Calls.py


def minFallingPathSum(self, A):
""" _author_ = 'jake'
:type A: List[List[int]] _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/number-of-recent-calls/
n = len(A) # Write a class RecentCounter to count recent requests.
row_minima = [0] * n # It has only one method: ping(int t), where t represents some time in milliseconds.
# Return the number of pings that have been made from 3000 milliseconds ago until now.
for r in range(n - 1, -1, -1): # from bottom row upwards # Any ping with time in [t - 3000, t] will count, including the current ping.
# It is guaranteed that every call to ping uses a strictly larger value of t than before.
new_row_minima = list(A[r]) # initilaise minimum path sums with the value
of each cell # Add each time to a queue.
# Remove all previous times that are longer than 3000ms ago and return the length of the
for c in range(n): queue.
new_row_minima[c] += min(row_minima[max(0, c - 1):c + 2]) # add the # Time - O(n) worst case for ping, O(1) on average.
lowest of the 3 cells below # Space - O(n)

row_minima = new_row_minima from collections import deque

return min(row_minima) # start from any cell of top row class RecentCounter:

def __init__(self):
self.times = deque()
# python_1_to_1000/932_Beautiful_Array.py - m self.WINDOW = 3000

_author_ = 'jake' def ping(self, t):


_project_ = 'leetcode' """
:type t: 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: self.times.append(t)
# For every i < j, there is no k with i < k < j such that A[k] * 2 = A[i] + A[j]. while t - self.times[0] > self.WINDOW:
# Given N, return any beautiful array A. (It is guaranteed that one exists.) self.times.popleft()

# The condition is equivalent to saying that the average of a pair of numbers cannot be return len(self.times)
between those numbers.
# Make separate arrays of even and odd numbers, since when concatenated the average of an
even and and odd number is # python_1_to_1000/934_Shortest_Bridge.py - m
# not an integer so does not violate the required condition.
# Note also that if an array is beautiful a common factor can be added to or multiplied _author_ = 'jake'
by all elements and it _project_ = 'leetcode'
# remains beautiful. Hence create odds and evens arrays of the required lengths using
integers, then scale the # https://leetcode.com/problems/shortest-bridge/
# elements to the required odd or even numbers. # In a given 2D binary array A, there are two islands.
# Time - O(n log n) # An island is a 4-directionally connected group of 1s not connected to any other 1s.
# Space - O(n log n) # 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
class Solution: answer is at least 1.)
def beautifulArray(self, N):
""" # Traverse the grid until we any cell from an island. Then depth-first search to find all
:type N: int perimeter cells of the island
:rtype: List[int] # which are at the edge of the island. Breath-first search from the perimeter. Ignore
""" cells that are already visited.
if N == 1: # Return when any island cell is found.
return [1] # Time - O(mn)
# Space - O(mn)
evens = self.beautifulArray(N // 2)
if N % 2 == 0: # reuse same array if odds and evens are same length class Solution:
odds = evens[:] def shortestBridge(self, A):
else: """
odds = self.beautifulArray((N + 1) // 2) :type A: List[List[int]]
:rtype: int
odds = [(2 * i) - 1 for i in odds] """
evens = [2 * i for i in evens] rows, cols = len(A), len(A[0])
visited = set()
return evens + odds perimeter = set()

# Store the count of distinct numbers ending with each digit.


def neighbours(r, c): # yields cells neighbouring (r, c) that are within # For each move, add the count of solutions ending with each digit to the count of
the grid A solutions ending with each
if r != 0: # reachable next digit.
yield (r - 1, c) # Time - O(n) since there are 10 digits and so at most 10 reachable next digits.
if r != rows - 1: # Space - O(1)
yield (r + 1, c)
if c != 0: class Solution:
yield (r, c - 1) def knightDialer(self, N):
if c != rows - 1: """
yield (r, c + 1) :type N: int
:rtype: int
def get_perimeter(r, c): """
can_reach = [[4, 6], # can_reach[i] is the list of digits that can be
if r < 0 or r >= rows or c < 0 or c >= cols: reached from i
return [6, 8],
if A[r][c] == 0 or (r, c) in visited: [7, 9],
return [4, 8],
visited.add((r, c)) [0, 3, 9],
[],
for r1, c1 in neighbours(r, c): [0, 1, 7],
if A[r1][c1] == 0: # neighbours of an island cell that are not part [2, 6],
of the island [1, 3],
perimeter.add((r1, c1)) [2, 4]]
else: # recurse to explore island
get_perimeter(r1, c1) counts = [1] * 10 # one distinct number ending with each digit
for _ in range(N - 1):
for r in range(rows):
for c in range(cols): new_counts = [0] * 10
if perimeter: # stop when any perimeter is found
break for digit, count in enumerate(counts):
get_perimeter(r, c) for next_digit in can_reach[digit]:
new_counts[next_digit] += count
steps = 1 # perimeter is one step from the island
counts = new_counts
while True:
return sum(counts) % (10 ** 9 + 7)
new_perimeter = set()
for r, c in perimeter:
for r1, c1 in neighbours(r, c): # python_1_to_1000/936_Stamping_The_Sequence.py - h
if (r1, c1) in visited:
continue _author_ = 'jake'
if A[r1][c1] == 1: # other island found _project_ = 'leetcode'
return steps
new_perimeter.add((r1, c1)) # https://leetcode.com/problems/stamping-the-sequence/
# You want to form a target string of lowercase letters.
visited |= new_perimeter # At the beginning, your sequence is target.length '?' marks. You also have a stamp of
perimeter = new_perimeter lowercase letters.
steps += 1 # On each turn, you may place the stamp over the sequence, and replace every letter in
the sequence with the
# corresponding letter from the stamp. You can make up to 10 * target.length turns.
# For example, if the initial sequence is "?????", and your stamp is "abc",
# python_1_to_1000/935_Knight_Dialer.py - m # then you may make "abc??", "?abc?", "??abc" in the first turn.
# Note that the stamp must be fully contained in the boundaries of the sequence in order
_author_ = 'jake' to stamp.
_project_ = 'leetcode' # If the sequence is possible to stamp, then return an array of the index of the left-
most letter being stamped
# https://leetcode.com/problems/knight-dialer/ # at each turn. If the sequence is not possible to stamp, return an empty array.
# A chess knight can move 2 squares horizontal/vertical and one square # For example, if the sequence is "ababc", and the stamp is "abc", then we could return
vertical/horizontal. the answer [0, 2],
# This time, we place our chess knight on any numbered key of a phone pad (indicated # corresponding to the moves "?????" -> "abc??" -> "ababc".
above), # Also, if the sequence is possible to stamp, it is guaranteed it is possible to stamp
# and the knight makes N-1 hops. Each hop must be from one key to another numbered key. within 10 * target.length moves.
# Each time it lands on a key (including the initial placement of the knight), # Any answers specifying more than this number of moves will not be accepted.
# it presses the number of that key, pressing N digits total.
# How many distinct numbers can you dial in this manner? # From given indices i of target and j of stamp, recursively attempt to build a solution.
# Since the answer may be large, output the answer modulo 10^9 + 7. # 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
# Create a mapping of which digits can be reached from each digit. suffix (may be the whole stamp).
# If stamp and target chars match, we can continue with next chars of stamp and target, # The letter-logs are ordered lexicographically ignoring identifier, with the identifier
or try to start a new stamp. used in case of ties.
# Memoize results. # The digit-logs should be put in their original order.
# Time - O(mn) since there are mn possible states and building results is O(1) due to max # Return the final order of the logs.
length of 10.
# Space - O(mn) # For each log, find the first char after the space. If it is a digit, append to list of
numbers logs.
class Solution: # If it is a letter, create a tuple of the log with the identifier moved to the end and
def movesToStamp(self, stamp, target): the original log.
""" # Sort the letter tuples and retain only the original logs in the solution.
:type stamp: str # Time - O(kn log n) to sort n strings of maximum length k
:type target: str # Space - O(nk)
:rtype: List[int]
""" class Solution:
memo = {} def reorderLogFiles(self, logs):
"""
def helper(i, j, results): # stamp from target[i] and stamp[j] given :type logs: List[str]
list of partial results :rtype: List[str]
"""
if (i, j) in memo: letters, numbers = [], []
return memo[(i, j)] digits = {str(i) for i in range(10)}

if len(results) > 10 * len(target): # too many stamps for log in logs:


return [] space = log.find(" ")
first = log[space + 1]
if i == len(target): # end of target, check if end of stamp if first in digits:
return results if j == len(stamp) else [] numbers.append(log)
else:
if j == len(stamp): # end of stamp letters.append((log[space + 1:] + log[:space], log))
for k in range(len(stamp)):
temp = helper(i, k, [i - k] + results) # stamp before existing letters.sort() # sort by log with identifier at end to break ties
result so only suffix shows
if temp: return [log for _, log in letters] + numbers
result = temp
break
else: # python_1_to_1000/938_Range_Sum_of_BST.py
result = []
_author_ = 'jake'
elif target[i] != stamp[j]: # cannot continue current stamp _project_ = 'leetcode'
result = []
# https://leetcode.com/problems/range-sum-of-bst/
else: # Given the root node of a binary search tree, return the sum of values of all nodes with
temp = helper(i + 1, j + 1, results) # continue current stamp value between
if temp: # L and R (inclusive).
result = temp # The binary search tree is guaranteed to have unique values.
else: # start a new stamp
result = helper(i + 1, 0, results + [i + 1]) # If the node value is more than R then recurse left only because all node values in
right subtree are even greater.
memo[(i, j)] = result # If the node value is less than L then recurse right only because all node values in
return result left subtree are even lower.
# Else return the sum of the node value (since it is in the target range) plus the
return helper(0, 0, [0]) results from the left and right
# subtrees.
# Time - O(n)
# Space - O(n)

# python_1_to_1000/937_Reorder_Log_Files.py - m class Solution:


def rangeSumBST(self, root, L, R):
_author_ = 'jake' """
_project_ = 'leetcode' :type root: TreeNode
:type L: int
# https://leetcode.com/problems/reorder-log-files/ :type R: int
# You have an array of logs. Each log is a space delimited string of words. :rtype: int
# 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; def helper(node):
# Each word after the identifier will consist only of digits.
# We will call these two varieties of logs letter-logs and digit-logs. if not node:
# It is guaranteed that each log has at least one word after its identifier. return 0
# Reorder the logs so that all of the letter-logs come before any digit-log.

if node.val > R:
return helper(node.left) return 0 if result == float('inf') else result
if node.val < L:
return helper(node.right)
# python_1_to_1000/940_Distinct_Subsequences_II.py - h
return node.val + helper(node.left) + helper(node.right)
_author_ = 'jake'
return helper(root) _project_ = 'leetcode'

# https://leetcode.com/problems/distinct-subsequences-ii/
# python_1_to_1000/939_Minimum_Area_Rectangle.py - m # Given a string S, count the number of distinct, non-empty subsequences of S.
# Since the result may be large, return the answer modulo 10^9 + 7.
_author_ = 'jake'
_project_ = 'leetcode' # Create a mapping from each char to the count of subsequences that have been extended by
the char.
# https://leetcode.com/problems/minimum-area-rectangle/ # For each char, we can extend all existing subsequences apart from those previously
# Given a set of points in the xy-plane, determine the minimum area of a rectangle formed extended by the same char.
from these points, # Also update the mapping for the number of subsequences that have been extended by the
# with sides parallel to the x and y axes. char.
# If there isn't any rectangle, return 0. # Time - O(n)
# Space - O(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 from collections import defaultdict
value to a list of row values.
# Sort the row values. For each row, sort the column values. For each pair of columns in class Solution:
that row, if the column def distinctSubseqII(self, S):
# pair has appeared in a previous row then we have a rectangle. """
# Update the mapping with each column pair to it's most recent row. :type S: str
# Time - O(max(m, n) * min(m, n) ** 2) since we swap to ensure the inner loop over pairs :rtype: int
is over the shorter list """
# Space - O(mn) total = 1 # start with the empty subsequence
extended = defaultdict(int) # map char to number of subsequences before last
from collections import defaultdict using this char

class Solution: for c in S:


def minAreaRect(self, points): total, extended[c] = 2 * total - extended[c], total
"""
:type points: List[List[int]] total -= 1 # remove empty subsequence
:rtype: int return total % (10 ** 9 + 7)
"""
rows, cols = set(), set() # sets of unque row and column values
for r, c in points:
rows.add(r) # python_1_to_1000/941_Valid_Mountain_Array.py
cols.add(c)
_author_ = 'jake'
row_to_cols = defaultdict(list) # map from a row to the list of columns _project_ = 'leetcode'
if len(rows) > len(cols):
for r, c in points: # https://leetcode.com/problems/valid-mountain-array/
row_to_cols[r].append(c) # Given an array A of integers, return true if and only if it is a valid mountain array.
else: # swap map to be from column to list of # Recall that A is a mountain array if and only if:
rows # A.length >= 3
for r, c in points: # There exists some i with 0 < i < A.length - 1 such that:
row_to_cols[c].append(r) # A[0] < A[1] < ... A[i-1] < A[i]
# A[i] > A[i+1] > ... > A[B.length - 1]
result = float("inf")
# Increment left pointer as long as array is increasing. Decrement right pointer as long
col_pair_to_row = {} # map from pair of column values to a row as array is decreasing.
# Pointers must meet and not be at ends.
for r in sorted(row_to_cols): # Time - O(n)
# Space - O(1)
columns = sorted(row_to_cols[r])
class Solution:
for i, c1 in enumerate(columns[:-1]): def validMountainArray(self, A):
for c2 in columns[i + 1:]: """
:type A: List[int]
if (c1, c2) in col_pair_to_row: # previous row has this column :rtype: bool
pair """
result = min(result, (r - col_pair_to_row[c1, c2]) * (c2 - c1)) n = len(A)
col_pair_to_row[c1, c2] = r left, right = 0, n - 1
"""
while left + 1 < n - 1 and A[left + 1] > A[left]: :type A: List[str]
left += 1 :rtype: str
while right - 1 > 0 and A[right - 1] > A[right]: """
right -= 1 N = len(A)

return 0 < left == right < n - 1 overlaps = [[0] * N for _ in range(N)] # overlaps[i][j] is nb chars overlapping
between x and y

# python_1_to_1000/942_DI_String_Match.py for i, x in enumerate(A):


for j, y in enumerate(A):
_author_ = 'jake' if i != j:
_project_ = 'leetcode' for ans in range(min(len(x), len(y)), 0, -1):
if x.endswith(y[:ans]):
# https://leetcode.com/problems/di-string-match/ overlaps[i][j] = ans
# Given a string S that only contains "I" (increase) or "D" (decrease), let N = S.length. break
# Return any permutation A of [0, 1, ..., N] such that for all i = 0, ..., N-1:
# If S[i] == "I", then A[i] < A[i+1] dp = [[0] * N for _ in range(1 << N)] # dp[mask][i] is most overlap with mask,
# If S[i] == "D", then A[i] > A[i+1] ending with ith element
parent = [[None] * N for _ in range(1 << N)] # parent[mask][i] is word index of
# Iterate over S, tracking the next lowest and highest unused numbers. previous word
# When the char is "I", append to the result the lowest unused number, since all future
numbers are increasing. for mask in range(1, 1 << N): # mask has a set bit for each used word index
# When the char is "D", append to the result the highest unused number, since all future for bit in range(N):
numbers are decreasing.
# Time - O(n) if (mask >> bit) & 1: # for each word used in mask
# Space - O(n)
prev_mask = mask ^ (1 << bit) # get mask without this word
class Solution(object): if prev_mask == 0:
def diStringMatch(self, S): continue
"""
:type S: str for i in range(N):
:rtype: List[int]
""" if (prev_mask >> i) & 1: # for each word in previous mask
result = []
low, high = 0, len(S) overlap = dp[prev_mask][i] + overlaps[i][bit]
if overlap > dp[mask][bit]: # better overlap
for c in S: dp[mask][bit] = overlap
parent[mask][bit] = i
if c == "I":
result.append(low) mask = (1 << N) - 1
low += 1 i = max(range(N), key=lambda x: dp[-1][x]) # index of last word used
else: result = [A[i]]
result.append(high) used = {i}
high -= 1
while True:
return result + [low] # append the last unused number
mask, j = mask ^ (1 << i), parent[mask][i] # get parent word and update mask
if j is None:
# python_1_to_1000/943_Find_the_Shortest_Superstring.py - h break
overlap = overlaps[j][i]
_author_ = 'jake' prefix = A[j] if overlap == 0 else A[j][:-overlap]
_project_ = 'leetcode' result.append(prefix)
used.add(j)
# https://leetcode.com/problems/find-the-shortest-superstring/ i = j
# Given an array A of strings, find any smallest string that contains each string in A as
a substring. result = result[::-1] + [A[i] for i in range(N) if i not in used] # reverse, add
# We may assume that no string in A is substring of another string in A. unused words

# For each pair of words (in both orders) find the overlap. return "".join(result)
# 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. # python_1_to_1000/944_Delete_Columns_to_Make_Sorted.py
# Time - O(n**2 (2**n + k)) where k is max string length
# Space - O(n (2**n + k)) where the nk is for the final result _author_ = 'jake'
_project_ = 'leetcode'
class Solution:
def shortestSuperstring(self, A): # https://leetcode.com/problems/delete-columns-to-make-sorted/

# We are given an array A of N lowercase letter strings, all of the same length.
# Now, we may choose any set of deletion indices, and for each string, we delete all the _author_ = 'jake'
characters in those indices. _project_ = 'leetcode'
# For example, if we have an array A = ["abcdef","uvwxyz"] and deletion indices {0, 2,
3}, # https://leetcode.com/problems/validate-stack-sequences/
# then the final array after deletions is ["bef", "vyz"], # Given two sequences pushed and popped with distinct values, return true if and only if
# and the remaining columns of A are ["b","v"], ["e","y"], and ["f","z"]. this could have been the
# Formally, the c-th column is [A[0][c], A[1][c], ..., A[A.length-1][c]]. # result of a sequence of push and pop operations on an initially empty stack.
# Suppose we chose a set of deletion indices D such that after deletions,
# each remaining column in A is in non-decreasing sorted order. # Build the stack by iterating over pushed.
# Return the minimum possible value of D.length. # Pop off top off stack whenever it matched the next element of popped.
# At the end, the stack must be empty.
# Rotate the array to iterate over columns. Check if each column is sorted. # Time - O(n)
# Time - O(m n log n) # Space - O(n)
# Space - O(mn)
class Solution:
class Solution: def validateStackSequences(self, pushed, popped):
def minDeletionSize(self, A): """
""" :type pushed: List[int]
:type A: List[str] :type popped: List[int]
:rtype: int :rtype: bool
""" """
deletions = 0 stack = []
i = 0 # next index of popped
for col in zip(*A): # pass each string as a positional argument to zip
for num in pushed:
if list(col) != sorted(col):
deletions += 1 stack.append(num)
while stack and stack[-1] == popped[i]:
return deletions i += 1
stack.pop()

# python_1_to_1000/945_Minimum_Increment_to_Make_Array_Unique.py - m return i == len(popped) # stack is empty if i == popped()

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/947_Most_Stones_Removed_with_Same_Row_or_Column.py - m

# https://leetcode.com/problems/minimum-increment-to-make-array-unique/ _author_ = 'jake'


# Given an array of integers A, a move consists of choosing any A[i], and incrementing it _project_ = 'leetcode'
by 1.
# Return the least number of moves to make every value in A unique. # https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/
# On a 2D plane, we place stones at some integer coordinate points. Each coordinate
# Iterate over the sorted numbers. If a number is more than that last number used, it point may have at most one stone.
does not need incrementing. # Now, a move consists of removing a stone that shares a column or row with another stone
# Else increment it to last_used + 1. In both cases update last_used. on the grid.
# Time - O(n log n) # What is the largest possible number of moves we can make?
# Space - O(n)
# Any connected component of the graph (points are connected by a common row or column)
class Solution: can be reduced to a single
def minIncrementForUnique(self, A): # point by repeatedly pruning.
""" # Use union-find tree to identify rows and columns that are connected. Remove all stones
:type A: List[int] apart from one per
:rtype: int # connected component.
""" # Time - O(n log n)
increments = 0 # Space - O(n)
last_used = -1
class Solution:
for num in sorted(A): def removeStones(self, stones):
"""
if num <= last_used: :type stones: List[List[int]]
increments += last_used + 1 - num :rtype: int
last_used += 1 """
else: parents = {} # map row or column to its parent
last_used = num
def find(x):
return increments while x != parents[x]:
x = parents[x]
return x
# python_1_to_1000/946_Validate_Stack_Sequences.py - m
def union(x, y):
parents.setdefault(x, x) # sets parents[x] to x if not in dictionary _author_ = 'jake'
parents.setdefault(y, y) _project_ = 'leetcode'
parents[find(x)] = find(y)
# https://leetcode.com/problems/largest-time-for-given-digits/
for i, j in stones: # Given an array of 4 digits, return the largest 24 hour time that can be made.
union(i, ~j) # ~j == -j - 1, so columns are distinct from rows # The smallest 24 hour time is 00:00, and the largest is 23:59.
# Starting from 00:00, a time is larger if more time has elapsed since midnight.
return len(stones) - len({find(x) for x in parents}) # Return the answer as a string of length 5. If no valid time can be made, return an
empty string.

# python_1_to_1000/948_Bag_of_Tokens.py - m # Check all permutations of the digits. Reject those which are not valid times.
# Time - O(1) since 4! times are possible
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
from itertools import permutations
# https://leetcode.com/problems/bag-of-tokens/
# You have an initial power P, an initial score of 0 points, and a bag of tokens. class Solution(object):
# Each token can be used at most once, has a value token[i], and has potentially two ways def largestTimeFromDigits(self, A):
to use it. """
# If we have at least token[i] power, we may play the token face up, losing token[i] :type A: List[int]
power, and gaining 1 point. :rtype: str
# If we have at least 1 point, we may play the token face down, gaining token[i] power, """
and losing 1 point. best_minutes = -1 # most minutes past midnight
# Return the largest number of points we can have after playing any number of tokens.
for time in permutations(A):
# Sort the tokens. Use as many low value tokens to get as many points as possible. Then
repeatedly use the highest hours = time[0] * 10 + time[1]
# value token to convert one point into power and use as many low value tokens to convert if hours >= 24:
all available continue
# power into points.
# Time - O(n) minutes = time[2] * 10 + time[3]
# Space - O(1) if minutes >= 60:
continue
class Solution:
def bagOfTokensScore(self, tokens, P): total_minutes = hours * 60 + minutes
""" if total_minutes > best_minutes:
:type tokens: List[int] best_minutes = total_minutes
:type P: int best = time
:rtype: int
""" if best_minutes == -1:
points, power = 0, P return ""
left, right = 0, len(tokens) - 1
best = [str(x) for x in best]
tokens.sort() return "".join(best[:2]) + ":" + "".join(best[2:])

while left < len(tokens) and tokens[left] <= power:


power -= tokens[left] # python_1_to_1000/950_Reveal_Cards_In_Increasing_Order.py - m
points += 1
left += 1 _author_ = 'jake'
_project_ = 'leetcode'
if not points: # never possible to have any points
return 0 # https://leetcode.com/problems/reveal-cards-in-increasing-order/
# In a deck of cards, every card has a unique integer. You can order the deck in any
while right - left > 1: order you want.
# Initially, all the cards start face down (unrevealed) in one deck.
points -= 1 # Now, you do the following steps repeatedly, until all cards are revealed:
power += tokens[right] # Take the top card of the deck, reveal it, and take it out of the deck.
right -= 1 # If there are still cards in the deck, put the next top card of the deck at the bottom
of the deck.
while right - left >= 0 and tokens[left] <= power: # If there are still unrevealed cards, go back to step 1. Otherwise, stop.
power -= tokens[left] # Return an ordering of the deck that would reveal the cards in increasing order.
points += 1 # The first entry in the answer is considered to be the top of the deck.
left += 1
# For each card from lowest to highest, add the card to the next empty index in the
return points result.
# Then move to next empty index to the back of the queue of indices - the card that is
ultimately placed here will
# python_1_to_1000/949_Largest_Time_for_Given_Digits.py - m # be moved to the bottom of the deck.

# Time - O(n log n) _project_ = 'leetcode'


# Space - O(n)
# https://leetcode.com/problems/largest-component-size-by-common-factor/
from collections import deque # Given a non-empty array of unique positive integers A, consider the following graph:
# There are A.length nodes, labelled A[0] to A[A.length - 1];
class Solution: # There is an edge between A[i] and A[j] if and only if A[i] and A[j] share a common
def deckRevealedIncreasing(self, deck): factor greater than 1.
""" # Return the size of the largest connected component in the graph.
:type deck: List[int]
:rtype: List[int] # 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
n = len(deck) seen before then map the factor
index = deque(range(n)) # to the index in A of the element. Else union the index of the element with the index
result = [None] * n already mapped to the factor
# and update the size of the connected component.
for card in sorted(deck): # Time - O(n k**0.5 log*(n k**0.5)) since there are O(k**0.5) factors for each element
# Space - O(n)
result[index.popleft()] = card
if index: class Solution(object):
index.append(index.popleft()) def largestComponentSize(self, A):
"""
return result :type A: List[int]
:rtype: int
"""
# python_1_to_1000/951_Flip_Equivalent_Binary_Trees.py - m
def prime_factors(x): # calculate set of prime factors of x
_author_ = 'jake' factors = set()
_project_ = 'leetcode'
while x % 2 == 0: # remove factors of 2, so next loop uses step of 2
# https://leetcode.com/problems/flip-equivalent-binary-trees/ factors.add(2)
# For a binary tree T, we can define a flip operation as follows: choose any node, and x //= 2
swap the left and right
# child subtrees. for i in range(3, int(x ** 0.5) + 1, 2):
# A binary tree X is flip equivalent to a binary tree Y if and only if we can make X while x % i == 0:
equal to Y after some number of factors.add(i)
# flip operations. x //= i
# Write a function that determines whether two binary trees are flip equivalent.
# The trees are given by root nodes root1 and root2. if x > 2: # x is originally prime
factors.add(x)
# Base cases are when at least one root is None. Else root values must be the same. Then
recursively check whether return factors
# the subtrees are flip equivalent either with or without swapping right and left.
# Time - O(n) def find(x): # return ultimate parent of x and collapse tree
# Space - O(n) while x != parents[x]:
parents[x] = parents[parents[x]] # link x to grandparent
class Solution: x = parents[x]
def flipEquiv(self, root1, root2): return x
"""
:type root1: TreeNode def union(x, y):
:type root2: TreeNode x, y = find(x), find(y)
:rtype: bool if x == y:
""" return
if not root1 and not root2: # equivalent because both empty parents[x] = y # all children of x are moved to y
return True sizes[y] += sizes[x]
if not root1 or not root2: # only one empty sizes[x] = 0
return False
n = len(A)
if root1.val != root2.val: parents = [i for i in range(n)] # index to parent mapping
return False sizes = [1] * n # sizes[i] is the size of component with A[i]
parent
return (self.flipEquiv(root1.left, root2.left) and self.flipEquiv(root1.right, prime_to_index = {} # prime factor mapped to index in A of first num
root2.right)) \ to use that factor
or (self.flipEquiv(root1.left, root2.right) and
self.flipEquiv(root1.right, root2.left)) for i, a in enumerate(A):

primes = prime_factors(a)
# python_1_to_1000/952_Largest_Component_Size_by_Common_Factor.py - h
for p in primes:
_author_ = 'jake' if p in prime_to_index:
union(i, prime_to_index[p]) """
prime_to_index[p] = i :type A: List[int]
:rtype: bool
return max(sizes) """
counts = Counter(A)

# python_1_to_1000/953_Verifying_an_Alien_Dictionary.py for num in sorted(counts, key=abs): # iterate over keys sorted by absolute
value
_author_ = 'jake'
_project_ = 'leetcode' if counts[num] > counts[num * 2]:
return False
# https://leetcode.com/problems/verifying-an-alien-dictionary/ counts[num * 2] -= counts[num]
# In an alien language, surprisingly they also use english lowercase letters, but
possibly in a different order. return True
# The order of the alphabet is some permutation of lowercase letters.
# 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 # python_1_to_1000/955_Delete_Columns_to_Make_Sorted_II.py - m
language.
_author_ = 'jake'
# Create a mapping from each char to its index in the alphabet. For each word, map each _project_ = 'leetcode'
char to its index in the
# alphabet. Compare the mapped list lexicographically to the previous word's mapped list. # https://leetcode.com/problems/delete-columns-to-make-sorted-ii/
# Time - O(nk) for n words of maximum length k # We are given an array A of N lowercase letter strings, all of the same length.
# Space - O(k) # Now, we may choose any set of deletion indices, and for each string, we delete all the
characters in those indices.
class Solution(object): # For example, if we have an array A = ["abcdef","uvwxyz"] and deletion indices {0, 2,
def isAlienSorted(self, words, order): 3}, then the final array after
""" # deletions is ["bef","vyz"].
:type words: List[str] # Suppose we chose a set of deletion indices D such that after deletions,
:type order: str # the final array has its elements in lexicographic order (A[0] <= A[1] <= A[2] ... <=
:rtype: bool A[A.length - 1]).
""" # Return the minimum possible value of D.length.
indices = {c: i for i, c in enumerate(order)}
prev = [] # Iterate over columns, tracking which rows must be checked (i.e. are not known to be
sorted).
for word in words: # For each column, compare the char at each row to be checked against the previous row.
mapping = [indices[c] for c in word] If any char is not sorted, the
if mapping < prev: # column must be deleted. Chars that are in the correct order are flagged so as not to be
return False tested again, unless the
prev = mapping # column is deleted. Identical chars are left to be checked in the next column.
# Time - O(mn)
return True # Space - O(m), number of rows

class Solution(object):
# python_1_to_1000/954_Array_of_Doubled_Pairs.py - m def minDeletionSize(self, A):
"""
_author_ = 'jake' :type A: List[str]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/array-of-doubled-pairs/ rows, cols = len(A), len(A[0])
# Given an array of integers A with even length, return true if and only if it is cols_deleted = 0
possible to reorder it rows_to_check = {row for row in range(1, rows)} # all rows apart from first
# such that A[2 * i + 1] = 2 * A[2 * i] for every 0 <= i < len(A) / 2.
for col in range(cols):
# Solution requires that numbers are paired as (num, num * 2), hence each element of the
input must be the lower new_checks = set(rows_to_check)
# or higher member of such a pair. Construct pairs from lowest absolute element first. for row in rows_to_check:
# Count occurrences of each number. For each unique number starting with the smallest
absolute value, if the count of char = A[row][col]
# num * 2 is less than the count of num then we cannot construct the required list of prev_char = A[row - 1][col]
pairs. Otherwise reduce the
# remaining count of num * 2. if char < prev_char: # incorrect order
# Time - O(n) cols_deleted += 1
# Space - O(n) break
elif char > prev_char: # correct order, do not check
from collections import Counter again
new_checks.remove(row)
class Solution(object):
def canReorderDoubled(self, A): else: # col not deleted

if not new_checks: # finished have two adjacent neighbors.


break # We describe the current state of the prison in the following way: cells[i] == 1 if the
rows_to_check = new_checks # update rows_to_check i-th cell is occupied,
# else cells[i] == 0.
return cols_deleted # Given the initial state of the prison, return the state of the prison after N days and
N such changes.

# For 8 cells, the ends are vacant after the first day so there are at most 2**6 = 64
# python_1_to_1000/956_Tallest_Billboard.py - h possible states.
# After at most 64 days there will be a cycle in the pattern of cells. Evolve the cells
_author_ = 'jake' until a repeated state is
_project_ = 'leetcode' # found. Subtract as many cycles as possible from the remaining days, then evolve to the
final state.
# https://leetcode.com/problems/tallest-billboard/ # Time - O(1)
# You are installing a billboard and want it to have the largest height. # Space - O(1)
# The billboard will have two steel supports, one on each side. Each steel support must
be an equal height. class Solution(object):
# You have a collection of rods which can be welded together. def prisonAfterNDays(self, cells, N):
# For example, if you have rods of lengths 1, 2, and 3, you can weld them together to """
make a support of length 6. :type cells: List[int]
# Return the largest possible height of your billboard installation. If you cannot :type N: int
support the billboard, return 0. :rtype: List[int]
"""
# Maintain a dictionary mapping the difference in side heights to the greatest total day = 0
length used with that difference. state = tuple(cells) # state can be a dict key
# Use only non-negative differences. state_to_day = {}
# 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. def next_state(state):
# Time - O(2 ** n) since 2 ** (n - 1) possible diffs. return tuple([0] + [int(not (state[i - 1] ^ state[i + 1])) for i in range(1,
# Space - O(2 ** (n - 1)) 7)] + [0])

from collections import defaultdict while day < N and state not in state_to_day: # until cycle in states
state_to_day[state] = day
class Solution: day += 1
def tallestBillboard(self, rods): state = next_state(state)
"""
:type rods: List[int] if day < N:
:rtype: int cycle = day - state_to_day[state]
""" remaining = (N - state_to_day[state]) % cycle
diffs = {0 : 0} # key is difference, value is max total length for _ in range(remaining):
state = next_state(state)
for rod in rods:
return list(state)
new_diffs = defaultdict(int, diffs)

for diff, used_len in diffs.items(): # python_1_to_1000/958_Check_Completeness_of_a_Binary_Tree.py - m

new_diffs[diff + rod] = max(used_len + rod, new_diffs[diff + rod]) _author_ = 'jake'


new_diffs[abs(diff - rod)] = max(used_len + rod, new_diffs[abs(diff - _project_ = 'leetcode'
rod)])
# https://leetcode.com/problems/check-completeness-of-a-binary-tree/
diffs = new_diffs # Given a binary tree, determine if it is a complete binary tree.
# Definition of a complete binary tree from Wikipedia:
return diffs[0] // 2 # 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
# python_1_to_1000/957_Prison_Cells_After_N_Days.py - m the last level h.

_author_ = 'jake' # Maintain a queue of nodes discovered. Explore the tree layer by layer (breadth-first
_project_ = 'leetcode' search).
# When the first empty node is found, check if all other nodes are empty. Else add
# https://leetcode.com/problems/prison-cells-after-n-days/ children to the queue.
# There are 8 prison cells in a row, and each cell is either occupied or vacant. # Time - O(n)
# Each day, whether the cell is occupied or vacant changes according to the following # Space - O(n)
rules:
# If a cell has two adjacent neighbors that are both occupied or both vacant, then the from collections import deque
cell becomes occupied.
# Otherwise, it becomes vacant. class Solution:
# Note that because the prison is a row, the first and the last cells in the row can't def isCompleteTree(self, root):
""" union((r, c, DOWN), (r, c, RIGHT))
:type root: TreeNode elif grid[r][c] == "\\":
:rtype: bool union((r, c, UP), (r, c, RIGHT))
""" union((r, c, DOWN), (r, c, LEFT))
queue = deque([root]) else: # connect all edge nodes
union((r, c, UP), (r, c, LEFT))
while True: union((r, c, UP), (r, c, DOWN))
union((r, c, UP), (r, c, RIGHT))
node = queue.popleft()
if not node: return len({find(node) for node in parents.keys()}) # number of ultimate
return all(not nd for nd in queue) parents

queue.append(node.left)
queue.append(node.right)
# python_1_to_1000/960_Delete_Columns_to_Make_Sorted_III.py - h

# python_1_to_1000/959_Regions_Cut_By_Slashes.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/delete-columns-to-make-sorted-iii/
# We are given an array A of N lowercase letter strings, all of the same length.
# https://leetcode.com/problems/regions-cut-by-slashes/ # Now, we may choose any set of deletion indices, and for each string, we delete all the
# In a N x N grid composed of 1 x 1 squares, each 1 x 1 square consists of a /, \, or characters in those indices.
blank space. # For example, if we have an array A = ["babca","bbazb"] and deletion indices {0, 1, 4},
# These characters divide the square into contiguous regions. # then the final array after deletions is ["bc","az"].
# (Note that backslash characters are escaped, so a \ is represented as "\\".) # Suppose we chose a set of deletion indices D such that after deletions, the final array
# Return the number of regions. has every element (row)
# in lexicographic order.
# Create graph where each cell of grid has 4 nodes, one for each edge. # For clarity, A[0] is in lexicographic order (ie. A[0][0] <= A[0][1] <= ... <= A[0]
# Connect edge nodes to neighbouring cells and make connections within a cell's edge [A[0].length - 1]), A[1] is in
nodes according to the slash. # lexicographic order (ie. A[1][0] <= A[1][1] <= ... <= A[1][A[1].length - 1]), and so
# Connections are undirected, hence only one direction of a connection is required. on.
# Union-find each pair of nodes connected by an edge and count the number of ultimate # Return the minimum possible value of D.length.
parents.
# Time - O(n**2 log*n) # Find the maximum length subsequence containing columns which are already sorted.
# Space - O(n**2) # Dynamic programming recording the max_subsequence ending at each index.
# For each ending index, for each other index, update the max_subsequence if the ending
class Solution(object): and other columns are sorted.
def regionsBySlashes(self, grid): # Update is the max of current max_subsequence and 1 + max_subsequence ending at other
""" index.
:type grid: List[str] # Time - O(n**2 m)
:rtype: int # Space - O(n)
"""
n= len(grid) class Solution(object):
UP, RIGHT, DOWN, LEFT = 0, 1, 2, 3 def minDeletionSize(self, A):
"""
parents = {} # map cell (r, c, dirn) to its parent :type A: List[str]
:rtype: int
def find(node): # return ultimate parent of a node """
parents.setdefault(node, node) rows, cols = len(A), len(A[0])
while parents[node] != node: max_subsequence = [1] * cols
parents[node] = parents[parents[node]] # collapse links
node = parents[node] for col_end in range(1, cols):
return node for col in range(col_end):
if all(A[r][col] <= A[r][col_end] for r in range(rows)):
def union(node1, node2): # union ultimate parents max_subsequence[col_end] = max(max_subsequence[col_end],
parent1, parent2 = find(node1), find(node2) max_subsequence[col] + 1)
parents[parent2] = parent1
return cols - max(max_subsequence)
for r in range(n):
for c in range(n):
if r != n - 1: # connect to cell below
union((r, c, DOWN), (r + 1, c, UP)) # python_1_to_1000/961_N-Repeated_Element_in_Size_2N_Array.py
if c != n - 1: # connect to cell to right
union((r, c, RIGHT), (r, c + 1, LEFT)) _author_ = 'jake'
_project_ = 'leetcode'
if grid[r][c] == "/": # connect pairs of edge nodes within
cell if slash # https://leetcode.com/problems/n-repeated-element-in-size-2n-array/
union((r, c, UP), (r, c, LEFT)) # In a array A of size 2N, there are N+1 unique elements, and exactly one of these

elements is repeated N times. _project_ = 'leetcode'


# Return the element repeated N times.
# https://leetcode.com/problems/minimum-area-rectangle-ii/
# Iterate over A, adding elements to set. Return when duplicated element is found. # Given a set of points in the xy-plane, determine the minimum area of any rectangle
# Time - O(n) formed from these points,
# Space - O(n) # with sides not necessarily parallel to the x and y axes.
# If there isn't any rectangle, return 0.
class Solution(object):
def repeatedNTimes(self, A): # Convert points to complex numbers for easier vector operations.
""" # Sort points so directions of vectors are aligned (else opposite directions are double
:type A: List[int] 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
seen = set() vector then a rectangle can
# be formed.
for num in A: # Time - O(n**2)
if num in seen: # Space - O(n**2)
return num
seen.add(num) from collections import defaultdict
from itertools import combinations

class Solution(object):
# python_1_to_1000/962_Maximum_Width_Ramp.py - m def minAreaFreeRect(self, points):
"""
_author_ = 'jake' :type points: List[List[int]]
_project_ = 'leetcode' :rtype: float
"""
# https://leetcode.com/problems/maximum-width-ramp/ min_area = float("inf")
# Given an array A of integers, a ramp is a tuple (i, j) for which i < j and A[i] <=
A[j]. points = [complex(*p) for p in sorted(points)]
# The width of such a ramp is j - i. line_to_mid = defaultdict(list)
# Find the maximum width of a ramp in A. If one doesn't exist, return 0.
for p1, p2 in combinations(points, 2):
# If a later element of A is greater than or equal to an earlier element then the earlier line_to_mid[p2 - p1].append((p1 + p2) / 2)
element makes a wider ramp.
# Hence we find the indices of strictly decreasing elements of A, which are candidates for line1, mid_points in line_to_mid.items():
for the left edges of ramps. for mid1, mid2 in combinations(mid_points, 2):
# Then iterate over A again from the last index to the first, considering each element as
the right edge of a ramp. line2 = mid2 - mid1
# When an element is greater than the top of stack, update max_ramp and pop off top of if line1.real * line2.real + line1.imag * line2.imag == 0:
stack since lower index min_area = min(min_area, abs(line1) * abs(line2))
# elements of A cannot make wider ramps.
# Time - O(n) return min_area if min_area != float("inf") else 0
# Space - O(n)

class Solution(object): # python_1_to_1000/964_Least_Operators_to_Express_Number.py - h


def maxWidthRamp(self, A):
""" _author_ = 'jake'
:type A: List[int] _project_ = 'leetcode'
:rtype: int
""" # https://leetcode.com/problems/least-operators-to-express-number
max_ramp = 0 # Given a single positive integer x, we will write an expression of the form x (op1) x
stack = [] # stack of indices in decreasing value (op2) x (op3) x ... where each
order, left edges of ramps # operator op1, op2, etc. is either addition, subtraction, multiplication, or division
(+, -, *, or /).
for i, num in enumerate(A): # For example, with x = 3, we might write 3 * 3 / 3 + 3 - 3 which is a value of 3.
if not stack or num < A[stack[-1]]: # When writing such an expression, we adhere to the following conventions:
stack.append(i) # The division operator (/) returns rational numbers.
# There are no parentheses placed anywhere.
for i in range(len(A) - 1, -1, -1): # iterate backwards # We use the usual order of operations: multiplication and division happens before
while stack and A[i] >= A[stack[-1]]: addition and subtraction.
max_ramp = max(max_ramp, i - stack.pop()) # It's not allowed to use the unary negation operator (-).
# For example, "x - x" is a valid expression as it only uses subtraction, but "-x + x" is
return max_ramp not because it uses negation.
# Write an expression with the least number of operators such that the expression equals
the given target.
# python_1_to_1000/963_Minimum_Area_Rectangle_II.py - m # Return the least number of operators used.

_author_ = 'jake' # Build the target as a number in base x, starting from the least significant digit.
# For each digit, we can either make the digit as a sum of ones (each one being made from _author_ = 'jake'
x / x), or make the next _project_ = 'leetcode'
# power of x minus the digit.
# Apart from the first digit, subsequent digits are made as a power multiplied by the # https://leetcode.com/problems/vowel-spellchecker/
digits and possibly with an # Given a wordlist, we want to implement a spellchecker that converts a query word into a
# additional factor of power and the previous neg result. correct word.
# Time - O(log n) #
# Space - O(1) # For a given query word, the spell checker handles two categories of spelling mistakes:
#
class Solution(object): # Capitalization: If the query matches a word in the wordlist (case-insensitive), then
def leastOpsExpressTarget(self, x, target): the query word is returned with
""" # the same case as the case in the wordlist.
:type x: int # Example: wordlist = ["yellow"], query = "YellOw": correct = "yellow"
:type target: int # Example: wordlist = ["Yellow"], query = "yellow": correct = "Yellow"
:rtype: int # Example: wordlist = ["yellow"], query = "yellow": correct = "yellow"
""" # Vowel Errors: If after replacing the vowels ('a', 'e', 'i', 'o', 'u') of the query word
pos = neg = powers = 0 with any vowel individually,
# it matches a word in the wordlist (case-insensitive), then the query word is returned
while target: with the same case as the
target, remainder = divmod(target, x) # remainder is the next digit to # match in the wordlist.
be built in base x # Example: wordlist = ["YellOw"], query = "yollow": correct = "YellOw"
# Example: wordlist = ["YellOw"], query = "yeellow": correct = "" (no match)
if powers == 0: # Example: wordlist = ["YellOw"], query = "yllw": correct = "" (no match)
pos, neg = remainder * 2, (x - remainder) * 2 # make digit or x - digit # In addition, the spell checker operates under the following precedence rules:
else: #
pos, neg = min(remainder * powers + pos, (remainder + 1) * powers + neg), # When the query exactly matches a word in the wordlist (case-sensitive), you should
\ return the same word back.
min((x - remainder) * powers + pos, (x - remainder - 1) * # When the query matches a word up to capitlization, you should return the first such
powers + neg) match in the wordlist.
# When the query matches a word up to vowel errors, you should return the first such
powers += 1 match in the wordlist.
# If the query has no matches in the wordlist, you should return the empty string.
return min(pos, powers + neg) - 1 # add the final power to neg, subtract 1 # Given some queries, return a list of words answer, where answer[i] is the correct word
since no final operator for query = queries[i].

# Create a set of the words for O(1) lookup. Map the lower case of each word to the first
# python_1_to_1000/965_Univalued_Binary_Tree.py such word.
# Map the lower case with vowels replaced by underscore to the first such word.
_author_ = 'jake' # Look up each word in the set and both mappings, returning the first hit.
_project_ = 'leetcode' # Time - O(m + n)
# Space - O(m + n)
# https://leetcode.com/problems/univalued-binary-tree/
# A binary tree is univalued if every node in the tree has the same value. from re import sub
# Return true if and only if the given tree is univalued.
class Solution:
# Store root value. Check if each node has the same value and recurse for children. def spellchecker(self, wordlist, queries):
# Time - O(n) """
# Space - O(n) :type wordlist: List[str]
:type queries: List[str]
class Solution: :rtype: List[str]
def isUnivalTree(self, root): """
"""
:type root: TreeNode def replace_vowels(word):
:rtype: bool return sub('[aeiou]', '_', word)
"""
value = root.val # root is guaranteed not to be None wordsset = set(wordlist)

def helper(node): lower_words, vowel_words = {}, {}


if not node: for word in wordlist:
return True lower_words.setdefault(word.lower(), word) # do not overwrite if key already
if node.val != value: exists
return False for word in lower_words.keys():
return helper(node.left) and helper(node.right) replaced = replace_vowels(word)
vowel_words.setdefault(replaced, lower_words[word])
return helper(root)
def check(word):
if word in wordsset:
# python_1_to_1000/966_Vowel_Spellchecker.py - m return word

low = word.lower() # Bottom-up recursion. Helper function returns the number of cameras to cover a subtree,
result = lower_words.get(low, "") # return empty string if not found apart from potentially not
if result == "": # covering the root. Maintain a set of nodes that are covered.
replaced = replace_vowels(low) # After processing child subtrees, if either child is not covered then there must be a
result = vowel_words.get(replaced, "") camera at the node and hence
return result # its parent is also covered.
# Time - O(n)
return [check(query) for query in queries] # Space - O(n)

class Solution(object):
# python_1_to_1000/967_Numbers_With_Same_Consecutive_Differences.py - m def minCameraCover(self, root):
"""
_author_ = 'jake' :type root: TreeNode
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/numbers-with-same-consecutive-differences/ covered = {None} # empty leaves are always covered
# Return all non-negative integers of length N such that the absolute difference between
every two consecutive def helper(node, parent): # returns number of cameras to cover subtree
# digits is K. apart from node
# Note that every number in the answer must not have leading zeros except for the number
0 itself. if not node:
# For example, 01 has one leading zero and is invalid, but 0 is valid. return 0
# You may return the answer in any order.
result = helper(node.left, node) + helper(node.right, node) # recurse for
# Starting from each of the digits apart from zero, repeatedly add and subtract K to the children first (bottom-up)
last_digit of each number to
# build up the results to N digits. if node.left not in covered or node.right not in covered: # must put a
# Time - O(2**n) camera at node
# Space - O(2**n) covered.update({parent, node, node.left, node.right}) # node and
neighbours are now covered
class Solution(object): result += 1
def numsSameConsecDiff(self, N, K):
""" return result
:type N: int
:type K: int cameras = helper(root, None)
:rtype: List[int] return cameras if root in covered else cameras + 1 # potentially
""" add camera at root
partials = [i for i in range(1, 10)]

for _ in range(N - 1):


new_partials = [] # python_1_to_1000/969_Pancake_Sorting.py - m

for p in partials: _author_ = 'jake'


_project_ = 'leetcode'
last_digit = p % 10
if last_digit - K >= 0: # https://leetcode.com/problems/pancake-sorting/
new_partials.append(p * 10 + last_digit - K) # Given an array A, we can perform a pancake flip: We choose some positive integer k <=
if K != 0 and last_digit + K < 10: A.length,
new_partials.append(p * 10 + last_digit + K) # then reverse the order of the first k elements of A.
# We want to perform zero or more pancake flips (doing them one after another in
partials = new_partials succession) to sort the array A.
# Return the k-values corresponding to a sequence of pancake flips that sort A.
if N == 1: # Any valid answer that sorts the array within 10 * A.length flips will be judged as
partials.append(0) correct.

return partials # For each number descending from the largest, find the index of the number. Flip the
list up to and including that
# number to move it to the beginning. Then flip the list up to the end of the already
sorted part, to add the
# python_1_to_1000/968_Binary_Tree_Cameras.py - h # number to the sorted part. The two flips combine to shift A[:i + 1] next to the already
sort part and move the
_author_ = 'jake' # reversed A[i + 1:unsorted] to the beginning.
_project_ = 'leetcode' # Time - O(n**2)
# Space - O(n)
# https://leetcode.com/problems/binary-tree-cameras/
# Given a binary tree, we install cameras on the nodes of the tree. class Solution:
# Each camera at a node can monitor its parent, itself, and its immediate children. def pancakeSort(self, A):
# Calculate the minimum number of cameras needed to monitor all nodes of the tree. """
:type A: List[int]
:rtype: List[int] # 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}.
flips = [] # A node in this binary tree can be flipped by swapping the left child and the right
child of that node.
for unsorted in range(len(A), 0, -1): # each unsorted number in decresing # Consider the sequence of N values reported by a preorder traversal starting from the
order root.
# Call such a sequence of N values the voyage of the tree.
i = A.index(unsorted) # Recall that a preorder traversal of a node means we report the current node's value,
if i == unsorted - 1: # already in correct position then preorder-traverse the
continue # left child, then preorder-traverse the right child.
# Our goal is to flip the least number of nodes so that the voyage of the tree matches
A = A[unsorted - 1:i:-1] + A[:i + 1] + A[unsorted:] the voyage we are given.
flips += [i + 1, unsorted] # If we can do so, then return a list of the values of all nodes flipped. You may return
the answer in any order.
return flips # If we cannot do so, then return the list [-1].

# Recursive helper function returns whether subtree can be flipped to match voyage and
increments index of next
# python_1_to_1000/970_Powerful_Integers.py - m # element of voyage to be tested. Note that voyage is the same length as the number of
nodes in the tree.
_author_ = 'jake' # After checking the root against voyage, if there is a left child that doesn't match the
_project_ = 'leetcode' next element of voyage
# then there must be a flip. If no left child, the next element of voyage must match the
# https://leetcode.com/problems/powerful-integers/ right child (if any).
# Given two non-negative integers x and y, an integer is powerful if it is equal to x^i + # Time - O(n)
y^j for some integers # Space - O(n)
# i >= 0 and j >= 0.
# Return a list of all powerful integers that have value less than or equal to bound. class Solution(object):
# You may return the answer in any order. In your answer, each value should occur at def flipMatchVoyage(self, root, voyage):
most once. """
:type root: TreeNode
# Create lists of all powers of x and y less than bound. :type voyage: List[int]
# Time - O((log b)**2) where b is the bound :rtype: List[int]
# Space - O((log b)**2) """
flipped = []
class Solution(object): self.i = 0 # index of next node in voyage
def powerfulIntegers(self, x, y, bound):
""" def preorder(node): # returns False if voyage cannot be matched by traversal
:type x: int if not node:
:type y: int return True
:type bound: int
:rtype: List[int] if voyage[self.i] != node.val: # must match root
""" return False
result = set() self.i += 1

def make_power_list(val): if node.left:


power_list = [1]
if val != 1: # val == 1 means list of only 1 if node.left.val != voyage[self.i]:
while power_list[-1] <= bound: flipped.append(node.val)
power_list.append(power_list[-1] * val) node.left, node.right = node.right, node.left
power_list.pop() # last value is too large if not preorder(node.left): # recurse with left subtree
return power_list return False

x_list, y_list = make_power_list(x), make_power_list(y) return preorder(node.right)

for x_num in x_list: return flipped if preorder(root) else [-1]


for y_num in y_list:
if x_num + y_num > bound:
break # python_1_to_1000/972_Equal_Rational_Numbers.py - h
result.add(x_num + y_num)
_author_ = 'jake'
return list(result) _project_ = 'leetcode'

# https://leetcode.com/problems/equal-rational-numbers/
# python_1_to_1000/971_Flip_Binary_Tree_To_Match_Preorder_Traversal.py - m # Given two strings S and T, each of which represents a non-negative rational number,
# return True if and only if they represent the same number.
_author_ = 'jake' # The strings may use parentheses to denote the repeating part of the rational number.
_project_ = 'leetcode' # In general a rational number can be represented using up to three parts: an integer
part, a non-repeating part,

# and a repeating part. return heapq.nsmallest(K, points, lambda x, y: x * x + y * y)


# The number will be represented in one of the following three ways:
# <IntegerPart> (e.g. 0, 12, 123)
# <IntegerPart><.><NonRepeatingPart> (e.g. 0.5, 1., 2.12, 2.0001)
# <IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)> (e.g. 0.1(6), 0.9(9), # python_1_to_1000/974_Subarray_Sums_Divisible_by_K.py - m
0.00(1212))
# The repeating portion of a decimal expansion is conventionally denoted within a pair of _author_ = 'jake'
round brackets. For example: _project_ = 'leetcode'
# 1 / 6 = 0.16666666... = 0.1(6) = 0.1666(6) = 0.166(66)
# Both 0.1(6) or 0.1666(6) or 0.166(66) are correct representations of 1 / 6. # https://leetcode.com/problems/subarray-sums-divisible-by-k/
# Given an array A of integers, return the number of (contiguous, non-empty) subarrays
# Convert each string to a fraction. As a fraction, the repeating part is divided by that have a sum divisible by K.
nines.
# For example 0.(52) is 52/99 and 0.1(52) is 1/10 + 52/990 # A sum divisible by K means sum of zero modulo K.
# Time - O(n + m), lengths of input strings # Dictionary counts the number of prefix sums modulo K. For each element, update the
# Space - O(n + m) running sum and add to the result
# the count of prefix sums equal to the running sum (subtracting the prefix from the
from fractions import Fraction running sum makes a subarray of
# sum 0 modulo K). Then update the dictionary.
class Solution: # Time - O(n)
def isRationalEqual(self, S, T): # Space - O(n)
"""
:type S: str from collections import defaultdict
:type T: str
:rtype: bool class Solution:
""" def subarraysDivByK(self, A, K):
def to_numeric(s): """
:type A: List[int]
if not ("(") in s: # no repeating part :type K: int
return Fraction(s) :rtype: int
"""
non_repeat, repeat = s.split("(") result = 0
repeat = repeat[:-1] # remove closing brace running_sum = 0
prefix_sums = defaultdict(int)
_, non_repeat_decimal = non_repeat.split(".") prefix_sums[0] = 1

fract = Fraction(int(repeat), (10 ** len(repeat) - 1) * (10 ** for num in A:


len(non_repeat_decimal))) running_sum = (running_sum + num) % K
result += prefix_sums[running_sum]
return Fraction(non_repeat) + fract prefix_sums[running_sum] += 1

return to_numeric(S) == to_numeric(T) return result

# python_1_to_1000/975_Odd_Even_Jump.py - h
# python_1_to_1000/973_K_Closest_Points_to_Origin.py - m
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/odd-even-jump/
# https://leetcode.com/problems/k-closest-points-to-origin/ # You are given an integer array A. From some starting index, you can make a series of
# We have a list of points on the plane. Find the K closest points to the origin (0, 0). jumps.
# Here, the distance between two points on a plane is the Euclidean distance. # The (1st, 3rd, 5th, ...) jumps in the series are called odd numbered jumps, and the
# You may return the answer in any order. The answer is guaranteed to be unique (except (2nd, 4th, 6th, ...) jumps in
for the order that it is in.) # the series are called even numbered jumps.
#
# Build a heap of the K smallest distances from the origin. # You may from index i jump forward to index j (with i < j) in the following way:
# Time - O(n log k) # During odd numbered jumps (ie. jumps 1, 3, 5, ...), you jump to the index j such that
# Space - O(k) 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
import heapq smallest such index j.
# During even numbered jumps (ie. jumps 2, 4, 6, ...), you jump to the index j such that
class Solution: A[i] >= A[j] and A[j] is the
def kClosest(self, points, K): # largest possible value. If there are multiple such indexes j, you can only jump to the
""" smallest such index j.
:type points: List[List[int]] # (It may be the case that for some index i, there are no legal jumps.)
:type K: int # A starting index is good if, starting from that index, you can reach the end of the
:rtype: List[List[int]] array (index A.length - 1) by
""" # jumping some number of times (possibly 0 or more than once.)
# Return the number of good starting indexes. # When the sides are sorted by decreasing length, the first such triangle has the largest
perimeter.
# Create lists of the next smaller and the next larger element from each element of the # Time - O(n log n)
array. # Space - O(n)
# Lists are made by sorting the indices of A in ascending and descending order of the
values. Indices are popped from class Solution:
# a stack when a next smaller or larger element is found. def largestPerimeter(self, A):
# Then iterate backwards over A, when an index has a next larger element, we can make an """
odd jump to the next larger :type A: List[int]
# element and reach the end if we can make an even jump from there. :rtype: int
# Time - O(n log n) """
# Space - O(n) A.sort(reverse=True)

class Solution: for i, side in enumerate(A[:-2]):


def oddEvenJumps(self, A): if side < A[i + 1] + A[i + 2]:
""" return side + A[i + 1] + A[i + 2]
:type A: List[int]
:rtype: int return 0
"""
n = len(A)
# python_1_to_1000/977_Squares_of_a_Sorted_Array.py
def next_list(): # returns list of index next
larger or smaller element _author_ = 'jake'
result = [None] * n _project_ = 'leetcode'
stack = []
for i in indices: # https://leetcode.com/problems/squares-of-a-sorted-array/
while stack and i > stack[-1]: # i is after top of stack # Given an array of integers A sorted in non-decreasing order, return an array of the
result[stack.pop()] = i # i is index of next larger or squares of each number,
smaller element after stack top # also in sorted non-decreasing order.
stack.append(i)
return result # Left and right pointers mark next elements to be squared. Add the larger square to the
result and move pointers
indices = sorted(range(n), key=lambda x: A[x]) # sort indices of A by increasing # until they cross.
A[x] # Time - O(n)
next_larger = next_list() # Space - O(n)
indices.sort(key=lambda x: -A[x]) # sort indices of A by decreasing
A[x] class Solution:
next_smaller = next_list() def sortedSquares(self, A):
"""
odd = [False] * (n - 1) + [True] # default can reach the end only :type A: List[int]
from last element :rtype: List[int]
even = [False] * (n - 1) + [True] """
left, right = 0, len(A) - 1
for i in range(n - 2, -1, -1): # iterate form back to front result = []
if next_larger[i] is not None:
odd[i] = even[next_larger[i]] while left <= right:
if next_smaller[i] is not None: if abs(A[left]) > abs(A[right]):
even[i] = odd[next_smaller[i]] result.append(A[left] * A[left])
left += 1
return sum(odd) # count of odd indices that can else:
reach end result.append(A[right] * A[right])
right -= 1

return result[::-1] # reverse to decreasing order


# python_1_to_1000/976_Largest_Perimeter_Triangle.py

_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/978_Longest_Turbulent_Subarray.py - m

# https://leetcode.com/problems/largest-perimeter-triangle/ _author_ = 'jake'


# Given an array A of positive lengths, return the largest perimeter of a triangle with _project_ = 'leetcode'
non-zero area,
# formed from 3 of these lengths. # https://leetcode.com/problems/longest-turbulent-subarray/
# If it is impossible to form any triangle of non-zero area, return 0. # A subarray A[i], A[i+1], ..., A[j] of A is said to be turbulent if and only if:
# For i <= k < j, A[k] > A[k+1] when k is odd, and A[k] < A[k+1] when k is even;
# For each side s, if the sum of the next 2 smaller sides is lower then a triangle can be # OR, for i <= k < j, A[k] > A[k+1] when k is even, and A[k] < A[k+1] when k is odd.
formed. # In other words, the subarray is turbulent if the comparison sign flips between each
# If no such triangle can be formed with s as the longest side, then other shorter sides adjacent pair of elements
cannot form a triangle. # in the subarray.

# Return the length of a maximum size turbulent subarray of A. return 0

# Track the longest subarrays where the last move is up and the last move is down. left = helper(node.left, node) # distribute coins evenly in subtrees
# For each difference between elements of the array, extend either the up, the down or right = helper(node.right, node)
neither sequence.
# Swap the up and down counts after every iteration, so the next iteration is opposite. upshift = node.val - 1 # the number of coins to be pushed up
# Time - O(n) to the parent (may be -ve)
# Space - O(1) if upshift != 0: # no parent if node is root
parent.val += upshift
class Solution: node.val = 1 # node is now balanced
def maxTurbulenceSize(self, A): return left + right + abs(upshift) # total coins moved
"""
:type A: List[int] return helper(root, None)
:rtype: int
"""
if len(A) == 1: # special case of single element
return 1 # python_1_to_1000/980_Unique_Paths_III.py - h

result = 0 _author_ = 'jake'


down, up = 0, 0 # longest sequences where last move is up and down _project_ = 'leetcode'

for i in range(1, len(A)): # https://leetcode.com/problems/unique-paths-iii/


# On a 2-dimensional grid, there are 4 types of squares:
if A[i] > A[i - 1]: # extend up sequence, no down sequence # 1 represents the starting square. There is exactly one starting square.
up += 1 # 2 represents the ending square. There is exactly one ending square.
down = 0 # 0 represents empty squares we can walk over.
elif A[i] < A[i - 1]: # extend down sequence, no up sequence # -1 represents obstacles that we cannot walk over.
down += 1 # Return the number of 4-directional walks from the starting square to the ending square,
up = 0 # that walk over every non-obstacle square exactly once.
else: # extend neither sequence
down = 0 # Create a set of cells to visit and identify the start and end cells.
up = 0 # From the start, recursively visit all unvisited neighbours, removing the neighbour from
unvisited before recusing
result = max(result, up, down) # and adding it back after returning.
up, down = down, up # swap so next iteration considers opposite move # Bases cases are end reached with all cells visited or it is impossible to do so.
# Time - O(4**mn)
return result + 1 if result != 0 else 0 # add 1 for final element only if any # Space - O(mn)
sequence found
class Solution:
def uniquePathsIII(self, grid):
"""
# python_1_to_1000/979_Distribute_Coins_in_Binary_Tree.py - m :type grid: List[List[int]]
:rtype: int
_author_ = 'jake' """
_project_ = 'leetcode' rows, cols = len(grid), len(grid[0])
unvisited = set()
# 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, for r in range(rows):
and there are N coins total. for c in range(cols):
# In one move, we may choose two adjacent nodes and move one coin from one node to if grid[r][c] == 1:
another. start = (r, c)
# The move may be from parent to child, or from child to parent. elif grid[r][c] == 2:
# Return the number of moves required to make every node have exactly one coin. end = (r, c)
unvisited.add((r, c))
# Bottom-up recursion. Helper function takes a node and its parent and distributes coins elif grid[r][c] == 0:
evenly in the subtree rooted unvisited.add((r, c))
# at the node, by pushing or pulling excess coins to or from the parent.
# Time - O(n) def make_paths(r, c):
# Space - O(n) if not unvisited and (r, c) == end: # end reached and no more cells to
visit
class Solution: return 1
def distributeCoins(self, root): if not unvisited or (r, c) == end: # end reached with cells to visit or
""" no more cells to visit
:type root: TreeNode return 0
:rtype: int
""" paths = 0
def helper(node, parent): for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
nbor_r, nbor_c = r + dr, c + dc
if not node: if (nbor_r, nbor_c) in unvisited:
unvisited.remove((nbor_r, nbor_c)) pairs to the result.
paths += make_paths(nbor_r, nbor_c) # Time - O(n**2) since the number of pairs is limited by the 2**16 for 16 bit elements of
unvisited.add((nbor_r, nbor_c)) # add back after exploring this path A. Calculation of pairs takes
return paths # O(n**2) but the calculation of result takes O(n).
# Space - O(n**2)
return make_paths(*start)
from collections import defaultdict

# python_1_to_1000/981_Time_Based_Key-Value_Store.py - m class Solution:


def countTriplets(self, A):
_author_ = 'jake' """
_project_ = 'leetcode' :type A: List[int]
:rtype: int
# https://leetcode.com/problems/time-based-key-value-store/ """
# Create a timebased key-value store class TimeMap, that supports two operations. pairs = defaultdict(int)
# 1. set(string key, string value, int timestamp)
# Stores the key and value, along with the given timestamp. for num1 in A:
# 2. get(string key, int timestamp) for num2 in A:
# Returns a value such that set(key, value, timestamp_prev) was called previously, with pairs[num1 & num2] += 1
timestamp_prev <= timestamp.
# If there are multiple such values, it returns the one with the largest timestamp_prev. result = 0
# If there are no values, it returns the empty string (""). for pair, count in pairs.items():
for num3 in A:
# Two dictionaries map keys to a list of values and a list of times. Binary search the if pair & num3 == 0:
list of times to find the result += count
# first index less than or equal to the required timestamp. If an index is found, lookup return result
the value at that index.
# Time - O(1) for set, O(log n) for get
# Space - O(n)
# python_1_to_1000/983_Minimum_Cost_For_Tickets.py - m
from collections import defaultdict
import bisect _author_ = 'jake'
_project_ = 'leetcode'
class TimeMap:
# https://leetcode.com/problems/minimum-cost-for-tickets/
def __init__(self): # In a country popular for train travel, you have planned some train travelling one year
""" in advance.
Initialize your data structure here. # The days of the year that you will travel is given as an array days. Each day is an
""" integer from 1 to 365.
self.key_to_values = defaultdict(list) # Train tickets are sold in 3 different ways:
self.key_to_times = defaultdict(list) # a 1-day pass is sold for costs[0] dollars;
# a 7-day pass is sold for costs[1] dollars;
def set(self, key: 'str', value: 'str', timestamp: 'int') -> 'None': # a 30-day pass is sold for costs[2] dollars.
self.key_to_values[key].append(value) # The passes allow that many days of consecutive travel.
self.key_to_times[key].append(timestamp) # 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.
def get(self, key: 'str', timestamp: 'int') -> 'str': # Return the minimum number of dollars you need to travel every day in the given list of
i = bisect.bisect_right(self.key_to_times[key], timestamp) days.
if i == 0:
return "" # For each travel day, for each pass length, find the next travel day not covered by the
return self.key_to_values[key][i - 1] pass and add the cost of the
# pass to the cost of covering from the next uncovered day onwards. Take the minimum over
the 3 pass lengths.
# Memoize previous results.
# python_1_to_1000/982_Triples_with_Bitwise_AND_Equal_To_Zero.py - h # Time - O(n), length of days
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' from typing import *
from functools import lru_cache
# https://leetcode.com/problems/triples-with-bitwise-and-equal-to-zero/
# Given an array of integers A, find the number of triples of indices (i, j, k) such class Solution:
that: def mincostTickets(self, days: 'List[int]', costs: 'List[int]') -> 'int':
# 0 <= i < A.length
# 0 <= j < A.length PASSES = [1, 7, 30] # days covered
# 0 <= k < A.length
# A[i] & A[j] & A[k] == 0, where & represents the bitwise-AND operator. @lru_cache(None)
def get_min_cost(i): # min cost from days[i] onwards
# Count the numbers of ways to form the AND for all pairs.
# For each number, if the AND with any AND of a pair is zero then add the count of all if i >= len(days):

return 0 _project_ = 'leetcode'

min_cost = float("inf") # https://leetcode.com/problems/sum-of-even-numbers-after-queries/


j = i # We have an array A of integers, and an array queries of queries.
for length, cost in zip(PASSES, costs): # For the i-th query val = queries[i][0], index = queries[i][1], we add val to A[index].
while j < len(days) and days[j] < days[i] + length: # find next # Then, the answer to the i-th query is the sum of the even values of A.
uncovered travel day by this pass # Here, the given index = queries[i][1] is a 0-based index, and each query permanently
j += 1 modifies the array A.
min_cost = min(min_cost, cost + get_min_cost(j)) # Return the answer to all queries. Your answer array should have answer[i] as the
answer to the i-th query.
return min_cost
# Calculate the initial sum of even values. For each query, if the value to be adjusted
return get_min_cost(0) 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.
# Time - O(n)
# python_1_to_1000/984_String_Without_AAA_or_BBB.py - m # Space - O(n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def sumEvenAfterQueries(self, A, queries):
"""
# https://leetcode.com/problems/string-without-aaa-or-bbb/ :type A: List[int]
# Given two integers A and B, return any string S such that: :type queries: List[List[int]]
# S has length A + B and contains exactly A 'a' letters, and exactly B 'b' letters; :rtype: List[int]
# The substring 'aaa' does not occur in S; """
# The substring 'bbb' does not occur in S. sum_even = sum(x for x in A if x % 2 == 0)
result = []
# If A and B are not equal, create as many groups of "xxy" as possible where x is the
letter with the greater count. for val, i in queries:
# Each group reduces the count difference by 1. Then add as many pairs of "ab" as
possible, followed by any if A[i] % 2 == 0:
# remaining single letters. sum_even -= A[i]
# Time - O(a + b) A[i] += val
# Space - O(a + b) if A[i] % 2 == 0:
sum_even += A[i]
class Solution:
def strWithout3a3b(self, a, b): result.append(sum_even)
"""
:type A: int return result
:type B: int
:rtype: str
"""
result = [] # python_1_to_1000/986_Interval_List_Intersections.py
diff = a - b
if diff > 0: _author_ = 'jake'
groups = min(diff, b) _project_ = 'leetcode'
result = ["aab"] * groups # equalize the difference as much as possible
a -= 2 * groups # update remaining required letters # https://leetcode.com/problems/interval-list-intersections/
b -= groups # Given two lists of closed intervals, each list of intervals is pairwise disjoint and in
elif diff < 0: sorted order.
groups = min(-diff, a) # Return the intersection of these two interval lists.
result = ["bba"] * groups # Formally, a closed interval [a, b] (with a <= b) denotes the set of real numbers x with
b -= 2 * groups a <= x <= b.
a -= groups # The intersection of two closed intervals is a set of real numbers that is either empty,
# or can be represented as a closed interval.
pairs = min(a, b) # For example, the intersection of [1, 3] and [2, 4] is [2, 3].)
result += ["ab"] * pairs
a -= pairs # Maintain pointers to the next indices of A and B to be checked for overlap.
b -= pairs # Indices overlap if the greatest starting edge is before or equal to the least ending
edge.
result += ["a"] * a + ["b"] * b # at most one of "a" or "b" # Move the pointer past the interval with the lowest ending edge to the next interval in
that list.
return "".join(result) # Time - O(m + n)
# Space - O(m + n), every interval overlaps at both ends

# Definition for an interval.


# python_1_to_1000/985_Sum_of_Even_Numbers_After_Queries.py - m class Interval(object):
def __init__(self, s=0, e=0):
_author_ = 'jake' self.start = s
self.end = e helper(node.left, x - 1, y - 1)
helper(node.right, x + 1, y - 1)
class Solution(object):
def intervalIntersection(self, A, B): helper(root, 0, 0)
""" result = []
:type A: List[Interval]
:type B: List[Interval] xs = sorted(x_to_y_and_val.keys())
:rtype: List[Interval] for x in xs:
""" x_to_y_and_val[x].sort()
result = [] result.append([val for _, val in x_to_y_and_val[x]])
i, j = 0, 0 # next indices of A and B to be tested
return result
while i < len(A) and j < len(B):

last_start = max(A[i].start, B[j].start)


first_end = min(A[i].end, B[j].end) # python_1_to_1000/988_Smallest_String_Starting_From_Leaf.py - m
if last_start <= first_end: # no overlap if max start is after first end
result.append(Interval(s=last_start, e=first_end)) _author_ = 'jake'
_project_ = 'leetcode'
if A[i].end < B[j].end: # move past interval that ends first
i += 1 # https://leetcode.com/problems/smallest-string-starting-from-leaf/
else: # Given the root of a binary tree, each node has a value from 0 to 25 representing the
j += 1 letters 'a' to 'z':
# a value of 0 represents 'a', a value of 1 represents 'b', and so on.
return result # Find the lexicographically smallest string that starts at a leaf of this tree and ends
at the root.
# As a reminder, any shorter prefix of a string is lexicographically smaller: for
example, "ab" is lexicographically
# python_1_to_1000/987_Vertical_Order_Traversal_of_a_Binary_Tree.py - h # smaller than "aba". A leaf of a node is a node that has no children.

_author_ = 'jake' # Bottom-up recursion. Find the results for left and right children. If either or both
_project_ = 'leetcode' are the empty string, the
# result is the none empty string concatenated to the node letter. Else return the
# https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/ smallest string plus the node letter.
# Given a binary tree, return the vertical order traversal of its nodes values. # The less-than operator "<" finds the smallest string.
# For each node at position (X, Y), its left and right children respectively will be at # Time - O(n**2)
positions # Space - O(n**2)
# (X-1, Y-1) and (X+1, Y-1).
# Running a vertical line from X = -infinity to X = +infinity, whenever the vertical line class Solution(object):
touches some nodes, def smallestFromLeaf(self, root):
# we report the values of the nodes in order from top to bottom (decreasing Y """
coordinates). :type root: TreeNode
# If two nodes have the same position, then the value of the node that is reported first :rtype: str
is the value that is smaller. """
# Return an list of non-empty reports in order of X coordinate. Every report will have a def helper(node):
list of values of nodes.
if not node: # base case
# Traverse the tree, creating a mapping from the x-coordinate of each node to a tuple of return ""
its y-coordinate and value.
# For each x-coordinate sorted in ascending order, sort the nodes by descending y- node_char = chr(node.val + ord("a"))
coordinate and value.
# Time - O(n log n), to sort the x-coord. Sorting the y-coords takes the same or less. left, right = helper(node.left), helper(node.right)
# Space - O(n)
if not left or not right:
from collections import defaultdict return left + right + node_char # only one of left and right are not
""
class Solution(object):
def verticalTraversal(self, root): return left + node_char if left < right else right + node_char
"""
:type root: TreeNode return helper(root)
:rtype: List[List[int]]
"""
x_to_y_and_val = defaultdict(list)
# python_1_to_1000/989_Add_to_Array-Form_of_Integer.py
def helper(node, x, y):
if not node: _author_ = 'jake'
return _project_ = 'leetcode'
x_to_y_and_val[x].append((-y, node.val)) # negative y-coordinate to later
sort descending # https://leetcode.com/problems/add-to-array-form-of-integer/

# For a non-negative integer X, the array-form of X is an array of its digits in left to


right order. groups = [None] * 26 # group index of equal variables
# For example, if X = 1231, then the array form is [1,2,3,1].
# Given the array-form A of a non-negative integer X, return the array-form of the def dfs(node, group):
integer X+K. if groups[node] is None:
groups[node] = group
# Treat K as the carry. Add carry to the least significant digit then divide by 10 to get for nbor in graph[node]:
the new carry, with the dfs(nbor, group)
# remainder being the new digit.
# Time - O(max(log K, n)) where n is the length of A for i in range(26): # if not already set, set connected
# Space - O(max(log K, n)) variable group index
dfs(i, i)
class Solution(object):
def addToArrayForm(self, A, K): for first, second in not_equal:
""" if groups[first] == groups[second]:
:type A: List[int] return False
:type K: int
:rtype: List[int] return True
"""
for i in range(len(A) - 1, -1, -1): # iterate from least significant digit
A[i] += K
K, A[i] = divmod(A[i], 10) # python_1_to_1000/991_Broken_Calculator.py - m

return [int(c) for c in str(K)] + A if K else A # append remaining carry if _author_ = 'jake'
any _project_ = 'leetcode'

# https://leetcode.com/problems/broken-calculator/
# On a broken calculator that has a number showing on its display, we can perform two
# python_1_to_1000/990_Satisfiability_of_Equality_Equations.py - m operations:
# Double: Multiply the number on the display by 2, or;
_author_ = 'jake' # Decrement: Subtract 1 from the number on the display.
_project_ = 'leetcode' # Initially, the calculator is displaying the number X.
# Return the minimum number of operations needed to display the number Y.
# https://leetcode.com/problems/satisfiability-of-equality-equations/
# Given an array equations of strings that represent relationships between variables, # If X > Y then we never multiply, just repeatedly subtract 1.
each string equations[i] has # Otherwise reduce Y to X. Division reduces Y and addition increases Y.
# length 4 and takes one of two different forms: "a==b" or "a!=b". # Greedily divide whenever possible, since it is optimal to divide a smaller number
# Here, a and b are lowercase letters (not necessarily different) that represent one- before adding, rather than add
letter variable names. # then divide a larger number.
# Return true if and only if it is possible to assign integers to variable names to # Time - O(log Y)
satisfy all the given equations. # Space - O(1)

# Create an undirected graph mapping each variable to the list of variables it is equal class Solution(object):
to. def brokenCalc(self, X, Y):
# Mark all connected variables as belonging to the same group. """
# Return false if any pair of not equal variables belong to the same group. :type X: int
# Alternatively, union-find. :type Y: int
# Time - O(n) :rtype: int
# Space - O(n) """
operations = 0
class Solution(object):
def equationsPossible(self, equations): while Y > X:
""" operations += 1
:type equations: List[str] if Y % 2 == 0:
:rtype: bool Y //= 2
""" else:
graph = [[] for _ in range(26)] # map of variable to equal variables Y += 1
not_equal = [] # tuples of not equal variables
return X - Y + operations
for eqn in equations:
first, op, second = eqn[0], eqn[1], eqn[3]
first, second = ord(first) - ord("a"), ord(second) - ord("a") # convert
letter variables to integers # python_1_to_1000/992_Subarrays_with_K_Different_Integers.py - h

if op == "=": _author_ = 'jake'


graph[first].append(second) _project_ = 'leetcode'
graph[second].append(first)
else: # https://leetcode.com/problems/subarrays-with-k-different-integers/
not_equal.append((first, second)) # Given an array A of positive integers, call a (contiguous, not necessarily distinct)
subarray of A good if the # parent. If only one of x and y is mapped to a node, they are not at the same depth so
# number of different integers in that subarray is exactly K. are not cousins.
# For example, [1,2,3,1,2] has 3 different integers: 1, 2, and 3. # Add the children of each node to the mapping.
# Return the number of good subarrays of A. # Time - O(n)
# Space - O(n)
# For each ending index of a subarray, find the starting index such that all subarrays
contains at most K distinct class Solution(object):
# elements. The difference between the at_most_k(K) and at_most_k(K - 1) is the number of def isCousins(self, root, x, y):
subarrays with exactly K. """
# A counter tracks the numbers in the sliding window, adding each element and :type root: TreeNode
decrementing the required distinct if :type x: int
# the new element is not already in the window. Then while there are too many distinct :type y: int
elements, move the start index :rtype: bool
# forward and remove elements from the window. Result is incremented by all subarrays of """
length <= end - start + 1. val_to_node = {root.val: root} # value to nodes at current depth
# Time - O(n) node_to_parent = {root: None}
# Space - O(n)
while True:
from collections import Counter
x_node = val_to_node.get(x, None)
class Solution(object): y_node = val_to_node.get(y, None)
def subarraysWithKDistinct(self, A, K): if x_node is not None and y_node is not None:
""" return node_to_parent[x_node] != node_to_parent[y_node]
:type A: List[int] if x_node is not None or y_node is not None:
:type K: int return False
:rtype: int
""" new_val_to_node = {}
def at_most_k(distinct): for node in val_to_node.values():
if node.left:
count = Counter() node_to_parent[node.left] = node
subarrays = 0 new_val_to_node[node.left.val] = node.left
start = 0 if node.right:
node_to_parent[node.right] = node
for end, num in enumerate(A): new_val_to_node[node.right.val] = node.right
val_to_node = new_val_to_node
if count[num] == 0:
distinct -= 1
count[num] += 1
# python_1_to_1000/994_Rotting_Oranges.py - m
while distinct < 0: # too many distinct elements
count[A[start]] -= 1 _author_ = 'jake'
if count[A[start]] == 0: _project_ = 'leetcode'
distinct += 1
start += 1 # move start of window forwards # https://leetcode.com/problems/rotting-oranges/
# In a given grid, each cell can have one of three values:
subarrays += end - start + 1 # the value 0 representing an empty cell;
# the value 1 representing a fresh orange;
return subarrays # the value 2 representing a rotten orange.
# Every minute, any fresh orange that is adjacent (4-directionally) to a rotten orange
return at_most_k(K) - at_most_k(K - 1) becomes rotten.
# Return the minimum number of minutes that must elapse until no cell has a fresh orange.
# If this is impossible, return -1 instead.

# python_1_to_1000/993_Cousins_in_Binary_Tree.py # Breadth-first search. Create sets of coordinates of fresh and rotted oranges. While
there are still some fresh,
_author_ = 'jake' # for each rotten orange, add any fresh neighbours to the set to be updated and add the
_project_ = 'leetcode' rotten orange to the set of
# already checked oranges.
# https://leetcode.com/problems/cousins-in-binary-tree/ # For each minute, if there are no new rotten oranges and some fresh then not all oranges
# In a binary tree, the root node is at depth 0, and children of each depth k node are at can be rotten.
depth k+1. # Else remove the checked oranges from rotten and convert newly rotted oranges from fresh
# Two nodes of a binary tree are cousins if they have the same depth, but have different to rotten.
parents. # Time - O(mn)
# We are given the root of a binary tree with unique values, and the values x and y of # Space - O(mn)
two different nodes in the tree.
# Return true if and only if the nodes corresponding to the values x and y are cousins. class Solution(object):
def orangesRotting(self, grid):
# 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 :type grid: List[List[int]]

:rtype: int
""" if (A[i] + len(flip_i)) % 2 == 0: # A[i] must be flipped
rows, cols = len(grid), len(grid[0]) if i > len(A) - K:
fresh, rotten = set(), set() return -1 # cannot flip last K elements
flips += 1
for r in range(rows): flip_i.append(i)
for c in range(cols):
if grid[r][c] == 1: return flips
fresh.add((r, c))
if grid[r][c] == 2:
rotten.add((r, c))
# python_1_to_1000/996_Number_of_Squareful_Arrays.py - h
mins = 0
while fresh: _author_ = 'jake'
mins += 1 _project_ = 'leetcode'
new_rotten = set()
# https://leetcode.com/problems/number-of-squareful-arrays/
for r, c in rotten: # Given an array A of non-negative integers, the array is squareful if for every pair of
for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]: # check all adjacent elements,
neighbours # their sum is a perfect square.
if (r + dr, c + dc) in fresh: # Return the number of permutations of A that are squareful.
new_rotten.add((r + dr, c + dc)) # Two permutations A1 and A2 differ if and only if there is some index i such that A1[i]
!= A2[i].
if not new_rotten:
return -1 # Create a mapping from each number to all numbers that sum to a square.
rotten = new_rotten # Start the permutation with any element. For each next element that can sum to a square,
fresh -= new_rotten if the count of that element
# is not zero, use the element and recurse. Add the element back to the count when
return mins backtracking.
# Time - O(n**n)
# Space - O(n)

# python_1_to_1000/995_Minimum_Number_of_K_Consecutive_Bit_Flips.py - h from collections import defaultdict, Counter

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def numSquarefulPerms(self, A):
"""
# https://leetcode.com/problems/minimum-number-of-k-consecutive-bit-flips/ :type A: List[int]
# In an array A containing only 0s and 1s, a K-bit flip consists of choosing a :rtype: int
(contiguous) subarray of length K and """
# simultaneously changing every 0 in the subarray to 1, and every 1 in the subarray to 0. freq = Counter(A) # counts of each element of A
# Return the minimum number of K-bit flips required so that there is no 0 in the array. pairs = defaultdict(set) # map element to the set of elements that sum to
# If it is not possible, return -1. a square
unique = list(freq.keys())
# Add flips to a queue. Iterate over A, first removing from the queue all earlier flips pairs[None] = unique # any element can start an empty permutation
that impact elements before
# A[i]. Check the bit A[i], adding all the flips in the current window to the initial for i, num1 in enumerate(unique): # create pairs mapping
bit. Take modulo 2 to find the for num2 in unique[i:]:
# updated bit. If bit is 0, make a new flip. if int((num1 + num2) ** 0.5) ** 2 == num1 + num2:
# Time - O(n) pairs[num1].add(num2)
# Space - O(K) pairs[num2].add(num1)

from collections import deque def helper(num, length): # returns the nb permutations given previous num
and permutation length
class Solution(object):
def minKBitFlips(self, A, K): if length == len(A): # used all elements successfully
""" return 1
:type A: List[int]
:type K: int count = 0
:rtype: int for next_num in pairs[num]: # for each next num that makes a square sum
""" if freq[next_num] > 0: # must have some elements remaining
flips = 0 freq[next_num] -= 1 # decrement count
flip_i = deque() # sliding window of indices of flips count += helper(next_num, length + 1)
freq[next_num] += 1 # increment count
for i in range(len(A)):
return count
while flip_i and flip_i[0] + K <= i: # remove flips that do not affect
A[i] return helper(None, 0)
flip_i.popleft()
list.
# Move along the path of right children until there are no more right children or the
# python_1_to_1000/997_Find_the_Town_Judge.py node val is less than the new val.
# Add the new node as a right child. The old right subtree is the new left subtree of the
_author_ = 'jake' new node, since all its
_project_ = 'leetcode' # elements are to the left of the new node in the list.
# Create a dummy root with infinite value to ensure the new node is always a child of
# https://leetcode.com/problems/find-the-town-judge/ some node.
# In a town, there are N people labelled from 1 to N. # Time - O(n)
# There is a rumor that one of these people is secretly the town judge. # Space - O(1)
# If the town judge exists, then:
# The town judge trusts nobody. class Solution(object):
# Everybody (except for the town judge) trusts the town judge. def insertIntoMaxTree(self, root, val):
# There is exactly one person that satisfies properties 1 and 2. """
# You are given trust, an array of pairs trust[i] = [a, b] representing that person :type root: TreeNode
labelled a trusts person labelled b. :type val: int
# If the town judge exists and can be identified, return the label of the town judge. :rtype: TreeNode
Otherwise, return -1. """
new_root = TreeNode(float("inf")) # new root to handle special case of val >
# Count the net balance of the number of people trusting each person. If person A trusts root.val
person B, increment the count new_root.right = root
# of B and decrement the count of A. The judge must be trusted by everybody and trust node = new_root
nobody, so has a count of N - 1.
# Time - O(n**2) for n people while node.right and node.right.val > val:
# Space - O(n) node = node.right

class Solution(object): right_subtree = node.right


def findJudge(self, N, trust): node.right = TreeNode(val)
""" node.right.left = right_subtree
:type N: int
:type trust: List[List[int]] return new_root.right
:rtype: int
"""
trust_count = [0] * (N + 1)
# python_1_to_1000/999_Available_Captures_for_Rook.py
for trustee, trusted in trust:
trust_count[trusted] += 1 _author_ = 'jake'
trust_count[trustee] -= 1 _project_ = 'leetcode'

for person in range(1, N + 1): # https://leetcode.com/problems/available-captures-for-rook/


if trust_count[person] == N - 1: # On an 8 x 8 chessboard, there is one white rook. There also may be empty squares, white
return person bishops, and black pawns.
# These are given as characters 'R', '.', 'B', and 'p' respectively.
return -1 # Uppercase characters represent white pieces, and lowercase characters represent black
pieces.
# The rook moves as in the rules of Chess: it chooses one of four cardinal directions
(north, east, west, and south),
# python_1_to_1000/998_Maximum_Binary_Tree_II.py - m # then moves in that direction until it chooses to stop, reaches the edge of the board,
# or captures an opposite colored pawn by moving to the same square it occupies.
_author_ = 'jake' # Also, rooks cannot move into the same square as other friendly bishops.
_project_ = 'leetcode' # Return the number of pawns the rook can capture in one move.

# https://leetcode.com/problems/maximum-binary-tree-ii/ # Find the coordinates of the rook. For each of the 4 directions, move until the edge of
# We are given the root node of a maximum tree: a tree where every node has a value the board is reached, or a
greater than any other value in # bishop, or a pawn. If a pawn is found first, increment the count of pawns that can be
# its subtree. captured.
# The given tree was constructed from an list A (root = Construct(A)) recursively with # Time - O(n**2) for board of size n
the following Construct(A) fn: # Space - O(1)
# If A is empty, return null.
# Otherwise, let A[i] be the largest element of A. Create a root node with value A[i]. class Solution(object):
# The left child of root will be Construct([A[0], A[1], ..., A[i-1]]) def numRookCaptures(self, board):
# The right child of root will be Construct([A[i+1], A[i+2], ..., A[A.length - 1]]) """
# Return root. :type board: List[List[str]]
# Note that we were not given A directly, only a root node root = Construct(A). :rtype: int
# Suppose B is a copy of A with the value val appended to it. It is guaranteed that B """
has unique values. SIZE = 8
# Return Construct(B).
for r in range(SIZE):
# The new value will always be a right child, since it is the last element of the input for c in range(SIZE):

if board[r][c] == "R": return helper(0, n - 1)


start_r, start_c = r, c
break
# python_1001_to_2000/1001_Grid_Illumination.py - h
pawns = 0
for dr, dc in [(1, 0), (0, 1), (-1, 0), (0, -1)]: _author_ = 'jake'
row, col = start_r, start_c _project_ = 'leetcode'
while True:
row += dr # https://leetcode.com/problems/grid-illumination/
col += dc # On a N x N grid of cells, each cell (x, y) with 0 <= x < N and 0 <= y < N has a lamp.
if row < 0 or row >= SIZE or col < 0 or col >= SIZE: # Initially, some number of lamps are on. lamps[i] tells us the location of the i-th lamp
break that is on.
if board[row][col] == "B": # Each lamp that is on illuminates every square on its x-axis, y-axis, and both diagonals
break (similar to a Queen in chess).
if board[row][col] == "p": # For the i-th query queries[i] = (x, y), the answer to the query is 1 if the cell (x, y)
pawns += 1 is illuminated, else 0.
break # After each query (x, y) [in the order given by queries], we turn off any lamps that are
at cell (x, y) or are
return pawns # adjacent 8-directionally (ie., share a corner or edge with cell (x, y).)
# Return an array of answers. Each value answer[i] should be equal to the answer of the
i-th query queries[i].
# python_1_to_1000/1000_Minimum_Cost_to_Merge_Stones.py - h
# For each of the 4 directions (horizontal, vertical and 2 diagonals) count the number of
_author_ = 'jake' lamps in each line.
_project_ = 'leetcode' # For each query call, sum the number of lamps shining on that cell across all 4
directions.
# https://leetcode.com/problems/minimum-cost-to-merge-stones/ # If there is at least one lamp shining on the query cell, check the 9 cells in and
# There are N piles of stones arranged in a row. The i-th pile has stones[i] stones. around the query for lamps and
# A move consists of merging exactly K consecutive piles into one pile, and the cost of # decrement the count in each direction for each lamp found.
this move is equal to the # Time - O(m + n), nb lamps + nb queries
# total number of stones in these K piles. # Space - O(m)
# Find the minimum cost to merge all piles of stones into one pile. If it is impossible,
return -1. from collections import defaultdict

# Return -1 if repeated merges will not leave one stone. class Solution(object):
# For a given subarray, try all possible splits into a prefix and a suffix, which are def gridIllumination(self, N, lamps, queries):
separately merged. """
# The prefix may be a single pile (which ensures that there is some value passed to the :type N: int
min function) or any prefixe of :type lamps: List[List[int]]
# a length that can be merged. :type queries: List[List[int]]
# If the subarray is of the correct length to be merged, each pile is counted once. :rtype: List[int]
# Time - O(n**3) """
# Space - O(n**2) lamps = {tuple(lamp) for lamp in lamps} # convert to set of O(1)
lookup
import functools x_lamps, y_lamps = defaultdict(int), defaultdict(int) # x_lamps[i] is the count
of lamps with x-value of i
class Solution: up_diag_lamps, down_diag_lamps = defaultdict(int), defaultdict(int)
def mergeStones(self, stones, K):
for x, y in lamps:
n = len(stones) x_lamps[x] += 1
if (n - 1) % (K - 1) != 0: # each merge removes K - 1 and must leave 1 remaining y_lamps[y] += 1
return -1 up_diag_lamps[x - y] += 1
down_diag_lamps[x + y] += 1
prefix_sum = [0] * (n + 1) # prefix_sum allows calculation of the sum of stones
in a subarray result = []
for i in range(n): for x, y in queries:
prefix_sum[i + 1] = prefix_sum[i] + stones[i] illuminated = x_lamps[x] + y_lamps[y] + up_diag_lamps[x - y] +
down_diag_lamps[x + y]
@functools.lru_cache(None) result.append(min(illuminated, 1)) # result of 1 if at least
def helper(i, j): # merge stones[i:j + 1] one lamp illuminating x, y

if j - i + 1 < K: # cannot merge length less than K if illuminated != 0:


return 0 for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
res = min(helper(i, mid) + helper(mid + 1, j) for mid in range(i, j, K - 1)) if (x + dx, y + dy) in lamps:
if (j - i) % (K - 1) == 0: lamps.discard((x + dx, y + dy))
res += prefix_sum[j + 1] - prefix_sum[i] x_lamps[x + dx] -= 1
return res y_lamps[y + dy] -= 1
up_diag_lamps[x + dx - y - dy] -= 1
down_diag_lamps[x + dx + y + dy] -= 1 # Space - O(n)

return result class Solution:


def isValid(self, S: str) -> bool:

if len(S) % 3 != 0: # S must consist of an integer number of "abc" strings


# python_1001_to_2000/1002_Find_Common_Characters.py return False

_author_ = 'jake' stack = []


_project_ = 'leetcode'
for c in S:
# https://leetcode.com/problems/find-common-characters/ if c == "a":
# Given an array A of strings made only from lowercase letters, return a list of all stack.append(c)
characters that show up in elif c == "b":
# all strings within the list (including duplicates). if stack and stack[-1] == "a":
# For example, if a character occurs 3 times in all strings but not 4 times, you need to stack.append(c)
include that character three else:
# times in the final answer. return False
# You may return the answer in any order. elif c == "c":
if len(stack) >= 2 and stack[-2:] == ["a", "b"]:
# Count the frequency of each character in the first word. For each other word, set the stack.pop() # match with "a" and "b"
count of each character to the stack.pop()
# lower of the existing character count and count in the other word. else:
# Time - O(mn) for m words of length n return False
# Space - O(mn)
return not stack # all chars must be matched
from collections import Counter

class Solution(object):
def commonChars(self, A): # python_1001_to_2000/1004_Max_Consecutive_Ones_III.py - m
"""
:type A: List[str] _author_ = 'jake'
:rtype: List[str] _project_ = 'leetcode'
"""
counts = Counter(A[0]) # 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.
for word in A[1:]: # Return the length of the longest (contiguous) subarray that contains only 1s.
word_count = Counter(word)
for c in counts: # Maintain a sliding window of length the maximum contiguous subarray. Iterate over A. If
counts[c] = min(counts[c], word_count[c]) we have a zero, decrement
# the balance of additional ones we can add. If the balance becomes negative, we have
result = [] used too many ones so move the
for char, count in counts.items(): # start of the window forward, which increases the balance of additional ones if the
result += [char] * count # append count copies of each char element at the start of window
return result # was zero.
# Time - O(n)
# Space - O(1)

# python_1001_to_2000/1003_Check_If_Word_Is_Valid_After_Substitutions.py - m class Solution(object):


def longestOnes(self, A, K):
_author_ = 'jake' """
_project_ = 'leetcode' :type A: List[int]
:type K: int
# https://leetcode.com/problems/check-if-word-is-valid-after-substitutions/ :rtype: int
# 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 i = 0 # index of start of window
concatenated with Y) is equal to V.
# (X or Y may be empty.) Then, X + "abc" + Y is also valid. for j in range(len(A)): # index of end of window
# If for example S = "abc", then examples of valid strings are: "abc", "aabcbc",
"abcabc", "abcabcababcc". K -= 1 - A[j]
# Examples of invalid strings are: "abccba", "ab", "cababc", "bac". if K < 0: # length of window only increases if K >= 0
# Return true if and only if the given string S is valid. K += 1 - A[i]
i += 1
# Maintain a stack of characters seen but are not part of "abc". Iterate over S. When "a"
is encountered, add it to the return len(A) - i
# stack. For "b", the previous unmatched char must be "a". For "c", there must be "a" and
"b" on the stack or else it
# cannot be matched.
# Time - O(n) # python_1001_to_2000/1005_Maximize_Sum_Of_Array_After_K_Negations.py

.... =
_author_ = 'jake' # (N + 1) + (N - 3) - (N - 4) * (N - 5) // (N - 6) + (N - 7) - (N - 8) * .... =
_project_ = 'leetcode' # (N + 1) + (N - 3) - (N - 3) + (N - 7) - (N - 8) * .... =
# (N + 1) + (N - 3) - (N - 3) + (N - 7) - (N - 7) * .... =
# https://leetcode.com/problems/maximize-sum-of-array-after-k-negations/ # (N + 1) + ...
# Given an array A of integers, we must modify the array in the following way: we choose # Time - O(1)
an i and # Space - O(1)
# replace A[i] with -A[i], and we repeat this process K times in total.
# We may choose the same index i multiple times. class Solution(object):
# Return the largest possible sum of the array after modifying it in this way. def clumsy(self, N):
"""
# Sort the array in ascending order. Iterate along the array flipping all negative :type N: int
elements to positive until no more :rtype: int
# flips are required or there are no more negatives. If there are an odd number of flips """
remaining, flip the smallest if N <= 2:
# element, which is either the last element flipped (if any) or the next element. return N
# Time - O(n log n) if N <= 4:
# Space - O(n) return N + 3

class Solution(object): if (N - 4) % 4 == 0: # (N+1) + ... + 5 - (4*3/2) + 1


def largestSumAfterKNegations(self, A, K): return N + 1
""" if (N - 4) % 4 <= 2: # (N+1) + ... + 6 - (5*4/3) + 2 - 1 or (N+1) + ... + 7 -
:type A: List[int] (6*5/4) + 3 - 2 * 1
:type K: int return N + 2
:rtype: int
""" return N - 1 # (N+1) + ... + 8 - (7*6/5) + 4 - 3 * 2 / 1
A.sort()

i = 0
while K > 0 > A[i]: # K positive and A[i] negative # python_1001_to_2000/1007_Minimum_Domino_Rotations_For_Equal_Row.py - m
A[i] = -A[i]
i += 1 _author_ = 'jake'
K -= 1 _project_ = 'leetcode'

result = sum(A) # https://leetcode.com/problems/minimum-domino-rotations-for-equal-row/


if K % 2 == 1: # In a row of dominoes, A[i] and B[i] represent the top and bottom halves of the i-th
result -= 2 * min(A[i], float("inf") if i == 0 else A[i - 1]) domino.
# A domino is a tile with two numbers from 1 to 6 - one on each half of the tile.
return result # We may rotate the i-th domino, so that A[i] and B[i] swap values.
# 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.
# python_1001_to_2000/1006_Clumsy_Factorial.py - m # If it cannot be done, return -1.

_author_ = 'jake' # For each number from 1 to 6 inclusive, check if each domino has that number. There can
_project_ = 'leetcode' be only one such number, or
# 2 numbers with an identical number of rotations, so we take the first such number
# https://leetcode.com/problems/clumsy-factorial/ found.
# Normally, the factorial of a positive integer n is the product of all positive integers # For that number, either rotate for every A that is not the number, or every B that is
less than or equal to n. not the number.
# For example, factorial(10) = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1. # Time - O(n)
# We instead make a clumsy factorial: using the integers in decreasing order, we swap out # Space - O(1)
the multiply operations
# for a fixed rotation of operations: multiply (*), divide (/), add (+) and subtract (-) class Solution(object):
in this order. def minDominoRotations(self, A, B):
# 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 :type A: List[int]
arithmetic: we do all :type B: List[int]
# multiplication and division steps before any addition or subtraction steps, and :rtype: int
multiplication and division steps """
# are processed left to right. n = len(A)
# Additionally, the division that we use is floor division such that 10 * 9 / 8 equals
11. for num in range(1, 7):
# This guarantees the result is an integer. if all(a == num or b == num for a, b in zip(A, B)):
# Implement the clumsy function as defined above: given an integer N, it returns the return min(n - A.count(num), n - B.count(num))
clumsy factorial of N.
return -1
# For N from 1 to 4 the results are 1, 2 * 1 = 2, 3 * 2 // 1 = 6 and 4 * 3 // 2 + 1 = 7.
# 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)
# python_1001_to_2000/1008_Construct_Binary_Search_Tree_from_Preorder_Traversal.py - m :rtype: int
"""
_author_ = 'jake' if N == 0: # special case because 0 has bit_length of 1
_project_ = 'leetcode' return 1
return (2**N.bit_length() - 1) - N
# 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.
# Recall that a binary search tree is a binary tree where for every node, any descendant
of node.left has a # python_1001_to_2000/1010_Pairs_of_Songs_With_Total_Durations_Divisible_by_60.py - m
# 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 _author_ = 'jake'
traverses node.left, _project_ = 'leetcode'
# then traverses node.right.
# https://leetcode.com/problems/pairs-of-songs-with-total-durations-divisible-by-60/
# Helper function builds tree, provided the next value is below max_value. # In a list of songs, the i-th song has a duration of time[i] seconds.
# Create the subtree root and increment the next index of preorder. Then build the left # Return the number of pairs of songs for which their total duration in seconds is
subtree from elements < root, divisible by 60.
# then build the right subtree from elements < max_value (value of parent of root). # Formally, we want the number of indices i < j with (time[i] + time[j]) % 60 == 0.
# Time - O(n)
# Space - O(n) # 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
class Solution(object): # each song and each other song with the same time.
def bstFromPreorder(self, preorder): # For other times, we can form pairs of songs with time t and time 60 - t.
""" # Time - O(n)
:type preorder: List[int] # Space - O(1)
:rtype: TreeNode
""" from collections import defaultdict
self.i = 0 # index of next element to be added to tree
class Solution(object):
def helper(max_value=float("inf")): def numPairsDivisibleBy60(self, time):
if self.i >= len(preorder) or preorder[self.i] > max_value: """
return None :type time: List[int]
:rtype: int
root = TreeNode(preorder[self.i]) """
self.i += 1 mod_count = defaultdict(int)
root.left = helper(root.val) # left subtree uses elements < root.val
root.right = helper(max_value) # right subtree uses elements < max_value for t in time:
return root mod_count[t % 60] += 1

return helper() pairs = mod_count[0] * (mod_count[0] - 1) // 2


pairs += mod_count[30] * (mod_count[30] - 1) // 2
for t in range(1, 30): # do not count to 60 to avoid double-counting
pairs += mod_count[t] * mod_count[60 - t]
# python_1001_to_2000/1009_Complement_of_Base_10_Integer.py
return pairs
_author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/complement-of-base-10-integer/ # python_1001_to_2000/1011_Capacity_To_Ship_Packages_Within_D_Days.py - m
# Every non-negative integer N has a binary representation.
# For example, 5 can be represented as "101" in binary, 11 as "1011" in binary, and so _author_ = 'jake'
on. _project_ = 'leetcode'
# Note that except for N = 0, there are no leading zeroes in any binary representation.
# The complement of a binary representation is the number in binary you get when changing # https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/
every 1 to a 0 and 0 to a 1. # A conveyor belt has packages that must be shipped from one port to another within D
# For example, the complement of "101" in binary is "010" in binary. days.
# For a given number N in base-10, return the complement of it's binary representation as # The i-th package on the conveyor belt has a weight of weights[i].
a base-10 integer. # Each day, we load the ship with packages on the conveyor belt (in the order given by
weights).
# Flip the sign of a bit by subtracting the bit from 1. Do this for all bits # We may not load more weight than the maximum weight capacity of the ship.
simultaneously by creating a mask with # Return the least weight capacity of the ship that will result in all the packages being
# all bits set. The mask is 2**bit_length - 1. shipped within D days.
# Time - O(log n)
# Space - O(1) # Binary search the range of possible capacities. Lowest possible capacity is the max
weight of any item.
class Solution(object): # Greatest possible capacity is the sum of all items, which can be shipped in one day.
def bitwiseComplement(self, N): # Time - O(n log nm) for n weights of max weight m
""" # Space - O(1)
:type N: int

class Solution(object): if length == 0:


def shipWithinDays(self, weights, D): return 1
""" # all perms of shorter length, extended by any unused digit
:type weights: List[int] return permutations(num_digits, length - 1) * (num_digits - length + 1)
:type D: int
:rtype: int for i in range(1, n): # count not_dup for powers of 10 less
""" than N
def can_ship(capacity): # determine whether weights can be shipped given a # 9 possible leading digits (not zero) then permutations of the other 9
capacity digits (including zero)
days = D not_dup += 9 * permutations(9, i - 1)
load = 0
seen = set() # previously fixed digits
for weight in weights: for i, max_digit in enumerate(digits): # max_digit is the most significant
if weight + load > capacity: # use a new ship unfixed digit of N+1
days -= 1 for digit in range(0 if i else 1, max_digit): # possible range of leading
load = 0 unfixed digit
load += weight if digit not in seen: # cannot use if digit has been fixed
if days == 0: # all days have been used and some weight remains earlier
return False not_dup += permutations(9 - i, n - i - 1) # perms of unused digit
for shorter length
return True if max_digit in seen: # all future numbers will contain
repeated max_digit
min_capacity = max(weights) break
max_capacity = sum(weights) seen.add(max_digit) # fix this digit

while min_capacity < max_capacity: return N - not_dup

mid_capacity = (min_capacity + max_capacity) // 2


if can_ship(mid_capacity):
max_capacity = mid_capacity # above mid_capacity is not the # python_1001_to_2000/1013_Partition_Array_Into_Three_Parts_With_Equal_Sum.py
lowest possible capacity
else: _author_ = 'jake'
min_capacity = mid_capacity + 1 # range of capacities is above _project_ = 'leetcode'
mid_capacity
# https://leetcode.com/problems/partition-array-into-three-parts-with-equal-sum/
return min_capacity # 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.
# Formally, we can partition the array if we can find indexes i+1 < j with (A[0] + A[1] +
# python_1001_to_2000/1012_Numbers_With_Repeated_Digits.py - h ... + A[i] ==
# A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + A[A.length - 1])
_author_ = 'jake'
_project_ = 'leetcode' # Check if the total is divisible by 3. If so, iterate along the array counting the
subarrays with sum of one third
# https://leetcode.com/problems/numbers-with-repeated-digits/ # of the total sum.
# Given a positive integer N, return the number of positive integers less than or equal # Time - O(n)
to N that have at # Space - O(1)
# least 1 repeated digit.
class Solution(object):
# Count the numbers with repeated digits and subtract from N. def canThreePartsEqualSum(self, A):
# 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 :type A: List[int]
numbers with fixed prefixes. :rtype: bool
# Time - O(log n) """
# Space - O(log n) partition, remainder = divmod(sum(A), 3)
if remainder != 0:
class Solution(object): return False
def numDupDigitsAtMostN(self, N):
""" subarray = 0 # sum of subarray
:type N: int partitions = 0 # number of partitions found
:rtype: int
""" for num in A:
digits = [int(c) for c in str(N + 1)] # convert N+1 to a list of digits subarray += num
n = len(digits) # length of N+1 if subarray == partition:
not_dup = 0 # count of numbers without repeated partitions += 1
digits subarray = 0 # reset the subarray sum

# returns the number of permutations of length digits out of num_digits return partitions >= 3 # ok if more than 3 partitions
def permutations(num_digits, length):
return -1

# python_1001_to_2000/1014_Best_Sightseeing_Pair.py - m mod_N, mod_set = 0, set()

_author_ = 'jake' for length in range(1, K + 1): # iterate the length of N upto K
_project_ = 'leetcode' mod_N = (10 * mod_N + 1) % K
if mod_N == 0:
# https://leetcode.com/problems/best-sightseeing-pair/ return length
# Given an array A of positive integers, A[i] represents the value of the i-th if mod_N in mod_set: # mod_N has been seen before
sightseeing spot, and two sightseeing return -1
# spots i and j have distance j - i between them. mod_set.add(mod_N)
# 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 -1
# spots, minus the distance between them.
# Return the maximum score of a pair of sightseeing spots.

# Iterate along the array, tracking the best previous (value - distance). # python_1001_to_2000/1016_Binary_String_With_Substrings_Representing_1_To_N.py - m
# For each element, update the result with the element value + best_minus_dist if it is
greater than the current _author_ = 'jake'
# result. Also update best_minus_dist if it increases and decrement due to the increased _project_ = 'leetcode'
distance.
# Time - O(n) # https://leetcode.com/problems/binary-string-with-substrings-representing-1-to-n/
# Space - O(1) # Given a binary string S (a string consisting only of '0' and '1's) and a positive
integer N,
class Solution(object): # return true if and only if for every integer X from 1 to N, the binary representation
def maxScoreSightseeingPair(self, A): of X is a substring of S.
"""
:type A: List[int] # Brute force check of all numbers from N to 1. Check numbers in descending order because
:rtype: int failure is more likely for
""" # large numbers than smaller numbers and if there is no solution we will return False
best_minus_dist = 0 sooner.
result = 0 # The concatenation of the binary strings of all integers from 1 to N is of length O(N
log N). If S is significantly
for num in A: # shorter than this number then it is unlikely to be able to include all bit strings
result = max(result, num + best_minus_dist) (despite the fact that some bit
best_minus_dist = max(best_minus_dist - 1, num - 1) # strings will overlap).
# Time - O(n log n)
return result # Space - O(log n)

class Solution(object):
def queryString(self, S, N):
# python_1001_to_2000/1015_Smallest_Integer_Divisible_by_K.py - m """
:type S: str
_author_ = 'jake' :type N: int
_project_ = 'leetcode' :rtype: bool
"""
# https://leetcode.com/problems/smallest-integer-divisible-by-k/ for num in range(N, 0, -1):
# Given a positive integer K, you need find the smallest positive integer N such that N if bin(num)[2:] not in S: # ignore "0b" prefix of bin()
is divisible by K, return False
# and N only contains the digit 1.
# Return the length of N. If there is no such N, return -1. return True

# 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.
# Try all possible N in the sequence 1, 11, 111, 1111, ... testing whether there is no # python_1001_to_2000/1017_Convert_to_Base_-2.py - m
remainder from N // K.
# If no remainder, return the length of N. Else retain the remainder and add to set of _author_ = 'jake'
remainders seen. _project_ = 'leetcode'
# 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 # https://leetcode.com/problems/convert-to-base-2/
# Space - O(K) # Given a number N, return a string consisting of "0"s and "1"s that represents its value
in base -2 (negative two).
class Solution(object): # The returned string must have no leading zeroes, unless the string is "0".
def smallestRepunitDivByK(self, K):
""" # In base -2 a number is expressed as a + -2*b + 4*c + -8*d + 16*e + ... for some bits a,
:type K: int b, c, d, e ...
:rtype: int # Repeatedly divide by 2 to determine if the least significant bit should be set. Flip
""" the sign of the number after
if K % 10 not in {1, 3, 7, 9}: # each division so the next number becomes b + -2*c + 4*d + -8*e + ... and repeat until

zero. # node_j.val > node_i.val, and j is the smallest possible choice.


# Bits are found in order from least to most significant, so reverse the result. # If such a j does not exist, the next larger value is 0.
# Time - O(log n) # Return an array of integers answer, where answer[i] = next_larger(node_{i+1}).
# Space - O(log n)
# Iterate along the list, maintaining a stack of nodes without greater elements. Stack
class Solution(object): contains nodes in descending
def baseNeg2(self, N): # order (otherwise next greater value would be known), and node indices.
""" # For each node, pop all smaller values off the stack and update their next greater
:type N: int values with the
:rtype: str # current node value.
""" # Time - O(n)
if N == 0: # Space - O(n)
return "0"
result = [] class Solution(object):
def nextLargerNodes(self, head):
while N != 0: """
N, bit = divmod(N, 2) :type head: ListNode
N *= -1 :rtype: List[int]
result.append(str(bit)) """
result = []
return "".join(reversed(result)) stack = [] # (index, val) tuples of nodes without next greater,
ordered by decreasing val
node = head
i = 0 # index of node in list
# python_1001_to_2000/1018_Binary_Prefix_Divisible_By_5.py
while node:
_author_ = 'jake'
_project_ = 'leetcode' result.append(0) # add a new entry to result with default of 0 if no
greater node
# https://leetcode.com/problems/binary-prefix-divisible-by-5/
# Given an array A of 0s and 1s, consider N_i: the i-th subarray from A[0] to A[i] while stack and stack[-1][1] < node.val: # all smaller vals have the current
interpreted as a binary number, node as the next greater
# from most-significant-bit to least-significant-bit. j, _ = stack.pop()
# Return a list of booleans answer, where answer[i] is true if and only if N_i is result[j] = node.val
divisible by 5.
stack.append((i, node.val))
# Iterate over A. For each bit, multiply the existing num by 2 (bit shift left) and add i += 1
the bit. Take modulo 5, since node = node.next
# mod is preserved under multiplication and addition.
# Time - O(n) return result
# Space - O(n)

class Solution(object):
def prefixesDivBy5(self, A): # python_1001_to_2000/1020_Number_of_Enclaves.py - m
"""
:type A: List[int] _author_ = 'jake'
:rtype: List[bool] _project_ = 'leetcode'
"""
result = [] # https://leetcode.com/problems/number-of-enclaves/
num = 0 # Given a 2D array A, each cell is 0 (representing sea) or 1 (representing land)
# A move consists of walking from one land square 4-directionally to another land square,
for bit in A: # or off the boundary of the grid.
num = (num * 2 + bit) % 5 # Return the number of land squares in the grid for which we cannot walk off the boundary
result.append(num == 0) of the grid
# in any number of moves.
return result
# For each cell of the grid, explore the connected (land) cells with depth-first search.
# A flag indicates whether any connected cell touches the edge of the grid, so the island
is not an enclave.
# python_1001_to_2000/1019_Next_Greater_Node_In_Linked_List.py - m # Set the value of each cell visited to zero to avoid repetition.
# Time - O(mn)
_author_ = 'jake' # Space - O(mn)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/next-greater-node-in-linked-list/ def numEnclaves(self, A):
# 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. :type A: List[List[int]]
# Each node may have a next larger value: for node_i, next_larger(node_i) is the :rtype: int
node_j.val such that j > i, """
rows, cols = len(A), len(A[0]) for c in S:
result = 0
self.edge = False # flag indicating whether current group of cells touches if balance != 0: # do not add opening bracket if all pairs are matched
an edge of the grid result.append(c)

def enclave(r, c): # return count of enclave cells, or zero if not an change = 1 if c == "(" else -1
enclave balance += change
if r < 0 or c < 0 or r >= rows or c >= cols:
return 0 if balance == 0: # remove closing bracket if all pairs are matched
if A[r][c] != 1: result.pop()
return 0
return "".join(result)
if r == 0 or c == 0 or r == rows - 1 or c == cols - 1:
self.edge = True
A[r][c] = 0
count = 1 # python_1001_to_2000/1022_Sum_of_Root_To_Leaf_Binary_Numbers.py
for dr, dc in [(0, 1), (1, 0), (-1, 0), (0, -1)]: # recursively add all
neighbours _author_ = 'jake'
count += enclave(r + dr, c + dc) _project_ = 'leetcode'
return count if not self.edge else 0 # return 0 if not an
enclave # https://leetcode.com/problems/sum-of-root-to-leaf-binary-numbers/
# Given a binary tree, each node has value 0 or 1.
for r in range(rows): # Each root-to-leaf path represents a binary number starting with the most significant
for c in range(cols): bit.
self.edge = False # reset flag for each # For example, if the path is 0 -> 1 -> 1 -> 0 -> 1, then this could represent 01101 in
cell binary, which is 13.
result += enclave(r, c) # For all leaves in the tree, consider the numbers represented by the path from the root
to that leaf.
return result # Return the sum of these numbers.

# For each node, update the previous value by multiplying by 2 (left bit shift) and
adding the new bit.
# python_1001_to_2000/1021_Remove_Outermost_Parentheses.py # If the node is a leaf, return the updated value. Else recurse and sum the leaves in the
left and right subtrees.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(n)

# https://leetcode.com/problems/remove-outermost-parentheses/ class Solution(object):


# A valid parentheses string is either empty (""), "(" + A + ")", or A + B, where A and B def sumRootToLeaf(self, root):
are valid parentheses strings, """
# and + represents string concatenation. :type root: TreeNode
# For example, "", "()", "(())()", and "(()(()))" are all valid parentheses strings. :rtype: int
# 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, def helper(node, running):
# with A and B nonempty valid parentheses strings.
# Given a valid parentheses string S, consider its primitive decomposition: S = P_1 + P_2 if not node:
+ ... + P_k, return 0
# where P_i are primitive valid parentheses strings.
# Return S after removing the outermost parentheses of every primitive string in the running = running * 2 + node.val
primitive decomposition of S. if not node.left and not node.right:
return running
# Maintain the net balance of opening - closing brackets. Iterate over S.
# If the balance is zero, we must have an opening bracket of a primitie string which is return helper(node.left, running) + helper(node.right, running)
not added to the result.
# Update the balance and add the char to the result. return helper(root, 0) % (10 ** 9 + 7)
# Then if the balance is zero, we have a closing bracket of a primitive string, which is
removed from the result.
# Time - O(n)
# Space - O(n) # python_1001_to_2000/1023_Camelcase_Matching.py - m

class Solution(object): _author_ = 'jake'


def removeOuterParentheses(self, S): _project_ = 'leetcode'
"""
:type S: str # https://leetcode.com/problems/camelcase-matching/
:rtype: str # A query word matches a given pattern if we can insert lowercase letters to the pattern
""" so that it equals the query.
result = [] # We may insert each character at any position, and may insert 0 characters.
balance = 0 # Given a list of queries, and a pattern, return an answer list of booleans,
# where answer[i] is true if and only if queries[i] matches the pattern.

# will later be replaced.


# For each query, iterate over the pattern and track the index of the next char of query # Time - O(n log n)
to be matched. # Space - O(1)
# If the query is upper case and does not match the pattern then they cannot match.
# Move past all the chars in the query that are lower case and do not match the pattern, class Solution(object):
since they can be inserted. def videoStitching(self, clips, T):
# If the query ends before all the pattern is matched, return False. Else there is a """
match. :type clips: List[List[int]]
# Return False if there are any unmatched upper case chars in the pattern after all the :type T: int
query is matched. :rtype: int
# Repeat for each query. """
# Time - O(nm) for n queries of length m. prev_stitch_end, stitch_end = -1, 0 # two greatest ends of used clips
# Space - O(m) result = 0 # count of used clips

class Solution(object): for start, end in sorted(clips):


def camelMatch(self, queries, pattern): if start > stitch_end or stitch_end >= T:
""" break
:type queries: List[str]
:type pattern: str if start > prev_stitch_end:
:rtype: List[bool] result += 1
""" prev_stitch_end = stitch_end
def can_match(query):
i = 0 # index of next char to match in stitch_end = max(stitch_end, end)
query
for c in pattern: return -1 if stitch_end < T else result

while i < len(query) and c != query[i]:


if query[i].isupper():
return False # python_1001_to_2000/1025_Divisor_Game.py
i += 1
_author_ = 'jake'
if i == len(query): # reached end of query with some _project_ = 'leetcode'
pattern remaining
return False # https://leetcode.com/problems/divisor-game/
i += 1 # Alice and Bob take turns playing a game, with Alice starting first.
# Initially, there is a number N on the chalkboard. On each player's turn, that player
return query[i:] == query[i:].lower() # remainder is all lower case makes a move consisting of:
# Choosing any x with 0 < x < N and N % x == 0.
return [can_match(query) for query in queries] # Replacing the number N on the chalkboard with N - x.
# Also, if a player cannot make a move, they lose the game.
# Return True if and only if Alice wins the game, assuming both players play optimally.

# python_1001_to_2000/1024_Video_Stitching.py - m # If N is even, Alice can always subtract 1 and make N - x odd for Bob.
# If N is odd, then it only has odd factors so N - x will always be even or no move is
_author_ = 'jake' possible if N == 1.
_project_ = 'leetcode' # Thus N will alternate between even and odd and the person with the even numbers will
always be able to make a move.
# https://leetcode.com/problems/video-stitching/ # The person with odd numbers will eventually have 1 and lose.
# You are given a series of video clips from a sporting event that lasted T seconds. # Time - O(1)
# These video clips can be overlapping with each other and have varied lengths. # Space - O(1)
# Each video clip clips[i] is an interval: it starts at time clips[i][0] and ends at time
clips[i][1]. class Solution:
# We can cut these clips into segments freely: def divisorGame(self, N: int) -> bool:
# for example, a clip [0, 7] can be cut into segments [0, 1] + [1, 3] + [3, 7]. return N % 2 == 0
# Return the minimum number of clips needed so that we can cut the clips into segments
that cover the entire
# sporting event ([0, T]). If the task is impossible, return -1.
# python_1001_to_2000/1026_Maximum_Difference_Between_Node_and_Ancestor.py - m
# 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 _author_ = 'jake'
2 used clips). _project_ = 'leetcode'
# Iterate over the clips, breaking if there is a gap between the start of the clip and
the previous end or we have # https://leetcode.com/problems/maximum-difference-between-node-and-ancestor/
# reached the required length. # Given the root of a binary tree, find the maximum value V for which there exists
# If the start is greater than the prev_stitch_end then we must add another clip different
(otherwise we can replace the # nodes A and B where V = |A.val - B.val| and A is an ancestor of B.
# previous clip). # A node A is an ancestor of B if either: any child of A is equal to B, or any child of A
# Note that if end < stitch_end we may still increment the count and set prev_stitch_end is an ancestor of B.
= stitch_end and the clip
# Recursive helper function tracks the max and min values seen along the current path sequences[i][diff] = max(sequences[j][diff] + 1, sequences[i][diff])
from the root.
# The max and min values are updated at each node, returning the max difference after any return max(max(mapping.values()) for mapping in sequences[1:]) + 1
leaf.
# Recurse left and right with the updated max and min and return the biggest difference
from either subtree.
# Time - O(n) # python_1001_to_2000/1028_Recover_a_Tree_From_Preorder_Traversal.py - h
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def maxAncestorDiff(self, root):
""" # https://leetcode.com/problems/recover-a-tree-from-preorder-traversal/
:type root: TreeNode # We run a preorder depth first search on the root of a binary tree.
:rtype: int # 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.
def helper(node, min_val, max_val): # If the depth of a node is D, the depth of its immediate child is D+1. The depth of the
if not node: root node is 0.
return max_val - min_val # 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.
min_val = min(node.val, min_val)
max_val = max(node.val, max_val) # Recursive helper function takes the required depth for a node to be added (initially
zero for the root).
return max(helper(node.left, min_val, max_val), helper(node.right, min_val, # The depth of the current node is found from the count of "-" and None is returned if
max_val)) this does not match the
# required depth.
return helper(root, float("inf"), float("-inf")) # 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.
# Time - O(n)
# python_1001_to_2000/1027_Longest_Arithmetic_Sequence.py - m # Space - O(n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def recoverFromPreorder(self, S):
"""
# https://leetcode.com/problems/longest-arithmetic-sequence/ :type S: str
# Given an array A of integers, return the length of the longest arithmetic subsequence :rtype: TreeNode
in A. """
# Recall that a subsequence of A is a list A[i_1], A[i_2], ..., A[i_k] with 0 <= i_1 < self.i = 0 # index of next char of S
i_2 < ... < i_k <= A.length - 1,
# and that a sequence B is arithmetic if B[i+1] - B[i] are all the same value (for 0 <= i def helper(required_depth): # return subtree if root is at required_depth
< B.length - 1).
depth = 0
# For each element of the array, maintain a mapping from a subsequence difference to the while self.i + depth < len(S) and S[self.i + depth] == "-":
length of the subsequence. depth += 1
# For each pair of elements, calculate the difference between their values.
# Update the mapping for the later element with the greater of its current length and 1 + if depth != required_depth:
the length of the return None # self.i is not incremented if depth is not as required
# subsequence ending at the earlier element.
# The result is the maximum length from all sequences, plus one since we have counted the self.i += depth # increment self.i
number of difference in a val = 0
# subsequence and require the number of elements. while self.i < len(S) and S[self.i] != "-":
# Time - O(n**2) val = val * 10 + int(S[self.i])
# Space - O(n**2) self.i += 1
node = TreeNode(val)
from collections import defaultdict
node.left = helper(required_depth + 1)
class Solution(object): node.right = helper(required_depth + 1)
def longestArithSeqLength(self, A):
""" return node
:type A: List[int]
:rtype: int return helper(0)
"""
# map sequence difference to its length for each element of A
sequences = [defaultdict(int) for _ in range(len(A))]
# python_1001_to_2000/1029_Two_City_Scheduling.py - m
for i in range(1, len(A)):
for j in range(i): _author_ = 'jake'
diff = A[i] - A[j] # difference between successive elements of the _project_ = 'leetcode'
subsequence

# https://leetcode.com/problems/two-city-scheduling/
# There are 2N people a company is planning to interview. while queue:
# The cost of flying the i-th person to city A is costs[i][0],
# and the cost of flying the i-th person to city B is costs[i][1]. r, c = queue.popleft()
# Return the minimum cost to fly every person to a city such that exactly N people arrive if r < 0 or r >= R or c < 0 or c >= C:
in each city. continue
if (r, c) in visited:
# Sort the costs by the difference between flying to city A and city B. continue
# Fly the first half of the sorted list to city A and the second half to city B.
# Time - O(n log n) result.append((r, c))
# Space - O(n) visited.add((r, c))

class Solution(object): for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
def twoCitySchedCost(self, costs): queue.append((r + dr, c + dc))
"""
:type costs: List[List[int]] return result
:rtype: int
"""
costs.sort(key = lambda x: x[0] - x[1])
n = len(costs) // 2 # python_1001_to_2000/1031_Maximum_Sum_of_Two_Non-Overlapping_Subarrays.py - m
return sum(a for a, _ in costs[:n]) + sum(b for _, b in costs[n:])
_author_ = 'jake'
_project_ = 'leetcode'

# python_1001_to_2000/1030_Matrix_Cells_in_Distance_Order.py # https://leetcode.com/problems/maximum-sum-of-two-non-overlapping-subarrays/
# Given an array A of non-negative integers, return the maximum sum of elements in two
_author_ = 'jake' 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
# https://leetcode.com/problems/matrix-cells-in-distance-order/ subarray.
# We are given a matrix with R rows and C columns has cells with integer coordinates (r, # Formally, return the largest V for which V = (A[i] + A[i+1] + ... + A[i+L-1]) +
c), # (A[j] + A[j+1] + ... + A[j+M-1]) and either:
# where 0 <= r < R and 0 <= c < C. # 0 <= i < i + L - 1 < j < j + M - 1 < A.length, or
# Additionally, we are given a cell in that matrix with coordinates (r0, c0). # 0 <= j < j + M - 1 < i < i + L - 1 < A.length.
# Return the coordinates of all cells in the matrix,
# sorted by their distance from (r0, c0) from smallest distance to largest distance. # Iterate over A. At each index we check the 2 cases of either L or M ending at that
# Here, the distance between two cells (r1, c1) and (r2, c2) is the Manhattan distance, index.
|r1 - r2| + |c1 - c2|. # Update the sum of L by adding the latest element and subtracting the element leaving L.
# You may return the answer in any order that satisfies this condition. # Update the sum of M ending immediately before L by adding and subtracting elements,
then update the maximum seen
# List all cells and sort by Manhattan distance from (r0, c0). # sum of M ending before L.
# Alternatively, breadth-first search maintaining a queue and ignoring cells outside # Update the result if the sum of L plus any earlier M array sum is greater than seen
matrix or already found. already.
# Time - O(mn log mn) # Check the second case by reversing the roles of L and M.
# Space - O(mn) # Time - O(n)
# Space - O(1)
class Solution(object):
def allCellsDistOrder(self, R, C, r0, c0): class Solution(object):
""" def maxSumTwoNoOverlap(self, A, L, M):
:type R: int """
:type C: int :type A: List[int]
:type r0: int :type L: int
:type c0: int :type M: int
:rtype: List[List[int]] :rtype: int
""" """
result = [] L_sum, M_sum = sum(A[M:L + M]), sum(A[L:L + M]) # sums of L
for r in range(R): and M ending at current index
for c in range(C): L_before_M_sum, M_before_L_sum = sum(A[:L]), sum(A[:M]) # sum of L
result.append((r, c)) ending before current M
L_before_M_best, M_before_L_best = L_before_M_sum, M_before_L_sum # max seen of
return sorted(result, key=lambda x: abs(x[0] - r0) + abs(x[1] - c0)) above

result = sum(A[:L + M]) # start from index L + M


class Solution2(object):
def allCellsDistOrder(self, R, C, r0, c0): for i in range(L + M, len(A)):
queue = deque() L_sum = L_sum + A[i] - A[i - L]
queue.append((r0, c0)) M_before_L_sum = M_before_L_sum + A[i - L] - A[i - L - M]
result = [] M_before_L_best = max(M_before_L_best, M_before_L_sum)
visited = set() result = max(result, L_sum + M_before_L_best)
return True
M_sum = M_sum + A[i] - A[i - M]
L_before_M_sum = L_before_M_sum + A[i - M] - A[i - M - L] return False # end of queries reached without matching a word
L_before_M_best = max(L_before_M_best, L_before_M_sum)
result = max(result, M_sum + L_before_M_best)

return result # python_1001_to_2000/1033_Moving_Stones_Until_Consecutive.py - m

_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1032_Stream_of_Characters.py - h
# https://leetcode.com/problems/moving-stones-until-consecutive/
_author_ = 'jake' # Three stones are on a number line at positions a, b, and c.
_project_ = 'leetcode' # Each turn, you pick up a stone at an endpoint (ie., either the lowest or highest
position stone),
# https://leetcode.com/problems/stream-of-characters/ # and move it to an unoccupied position between those endpoints.
# Implement the StreamChecker class as follows: # Formally, let's say the stones are currently at positions x, y, z with x < y < z.
# StreamChecker(words): Constructor, init the data structure with the given words. # You pick up the stone at either position x or position z, and move that stone to an
# query(letter): returns true if and only if for some k >= 1, the last k characters integer position k,
queried # with x < k < z and k != y.
# (in order from oldest to newest, including this letter just queried) spell one of the # The game ends when you cannot make any more moves, ie. the stones are in consecutive
words in the given list. positions.
# When the game ends, what is the minimum and maximum number of moves that you could have
# Query is true if some word ends with the most recent query. made?
# Store the reversed words in a trie. Each node of the trie is a dictionary keyed by # Return the answer as an length 2 array: answer = [minimum_moves, maximum_moves]
characters and with values of
# the child node corresponding to that character. The presence of a character of "#" # Sort the stones and calculate the length of the 2 gaps between stones.
indicates that a word terminates # If either gap is 1 then the minimum moves if 1 since a stone can fill the gap. Else
# at that node. Also store the list of query characters. move each outer stone next to
# Add each query to list of previous query characters. Starting from the root of the # the middle stone if there is a gap.
trie, iterate backwards along the # The maximum number of moves happens when the outer stones are moved in 1 place every
# list of queries. turn.
# If a character is not found, there is no word with the previous queries as a suffix. # Time - O(1)
# Return True if a complete word is found. # Space - O(1)
# 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. class Solution(object):
# Space - O(m + n) def numMovesStones(self, a, b, c):
"""
class StreamChecker(object): :type a: int
:type b: int
def __init__(self, words): :type c: int
""" :rtype: List[int]
:type words: List[str] """
""" stones = sorted([a, b, c])
self.root = {} # Trie root, each node maps char to next node 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)
for word in words: max_moves = gap1 + gap2
node = self.root return [min_moves, max_moves]
for c in reversed(word):
if c not in node:
node[c] = {}
node = node[c] # python_1001_to_2000/1034_Coloring_A_Border.py - m
node["#"] = True # "#" signifies complete word
_author_ = 'jake'
self.queries = [] _project_ = 'leetcode'

def query(self, letter): # https://leetcode.com/problems/coloring-a-border/


""" # Given a 2-dimensional grid of integers, each value in the grid represents the color of
:type letter: str # the grid square at that location.
:rtype: bool # Two squares belong to the same connected component if and only if they have the same
""" color and
self.queries.append(letter) # are next to each other in any of the 4 directions.
node = self.root # The border of a connected component is all the squares in the connected component that
are either
for c in reversed(self.queries): # 4-directionally adjacent to a square not in the component, or on the boundary of the
if c not in node: grid
return False # (the first or last row or column).
node = node[c] # Given a square at location (r0, c0) in the grid and a color, color the border of the
if "#" in node: connected component of

# that square with the given color, and return the final grid. :type B: List[int]
:rtype: int
# Depth-first search helper function return True if a cell is part of the connected """
component. if len(A) < len(B): # ensure B is shorter to use less space
# If a cell is outside the grid or no the the colour of grid[r0][c0] return False. A, B = B, A
# Recurse in all 4 directions and if not all neighbours are connected then this cell is max_uncrossed = [0] * (len(B) + 1)
on the border.
# Important to recurse in all directions and not check for any not connected (stopping for i in range(len(A)):
for the first found) because new_max_uncrossed = [0]
# the border colour can only be set when the cell will not be checked again. for j in range(len(B)):
# Time - O(mn) new_max_uncrossed.append(max(max_uncrossed[j] + int(A[i] == B[j]),
# Space - O(mn) max_uncrossed[j + 1],
new_max_uncrossed[-1]))
class Solution(object): max_uncrossed = new_max_uncrossed
def colorBorder(self, grid, r0, c0, color):
""" return max_uncrossed[-1]
:type grid: List[List[int]]
:type r0: int
:type c0: int
:type color: int # python_1001_to_2000/1036_Escape_a_Large_Maze.py - h
:rtype: List[List[int]]
""" _author_ = 'jake'
original = grid[r0][c0] _project_ = 'leetcode'
rows, cols = len(grid), len(grid[0])
connected = set() # https://leetcode.com/problems/escape-a-large-maze/
# In a 1 million by 1 million grid, the coordinates of each grid square are (x, y) with 0
def dfs(r, c): <= x, y < 10^6.
if (r, c) in connected: # already known to be connected, do not # We start at the source square and want to reach the target square.
explore again # Each move, we can walk to a 4-directionally adjacent square in the grid that isn't in
return True the list of blocked squares.
if r < 0 or c < 0 or r >= rows or c >= cols or grid[r][c] != original: # Return true if and only if it is possible to reach the target square through a sequence
return False of moves.
connected.add((r, c)) # 0 <= blocked.length <= 200
if not sum(dfs(r + dr, c + dc) for dr, dc in [[1, 0], [0, 1], [-1, 0], [0,
-1]]) == 4: # Compress the grid so that gaps between populated rows and columns are at most one
grid[r][c] = color square wide.
return True # Then perform breadth-first search.
# Time - O(1) since there are at most 200 blocked squares.
dfs(r0, c0) # Space - O(1)
return grid
class Solution(object):
def isEscapePossible(self, blocked, source, target):
"""
# python_1001_to_2000/1035_Uncrossed_Lines.py - m :type blocked: List[List[int]]
:type source: List[int]
_author_ = 'jake' :type target: List[int]
_project_ = 'leetcode' :rtype: bool
"""
# https://leetcode.com/problems/uncrossed-lines/ # make sorted lists of all rows and cols used in blocked, source or target
# We write the integers of A and B (in the order they are given) on two separate rows, cols = set(), set()
horizontal lines. for r, c in blocked + [source, target]:
# Now, we may draw a straight line connecting two numbers A[i] and B[j] as long as A[i] rows.add(r)
== B[j], cols.add(c)
# and the line we draw does not intersect any other connecting (non-horizontal) line. rows, cols = sorted(list(rows)), sorted(list(cols))
# Return the maximum number of connecting lines we can draw in this way.
# map original rows and cols to compressed values that reduce gaps to 1 element
# Dynamic programming. For each i element of the first list, find the maximum uncrossed row_to_compressed, col_to_compressed = {}, {}
lines we can draw for each new_row, new_col = int(rows[0] != 0), int(cols[0] != 0) # add a gap if not
# element j of the second list. starting at row or col zero
# 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 for i, r in enumerate(rows):
# and take the result for i, j - 1 or i - 1, j. if i != 0 and rows[i - 1] != r - 1: # not consecutive, add a gap of a single
# Time - O(mn) row
# Space - O(min(m, n) new_row += 1
row_to_compressed[r] = new_row
class Solution(object): new_row += 1
def maxUncrossedLines(self, A, B):
""" for i, c in enumerate(cols):
:type A: List[int] if i != 0 and cols[i - 1] != c - 1: # not consecutive, add a gap of a single
col dy_1 = points[1][1] - points[0][1]
new_col += 1 dx_2 = points[2][0] - points[0][0]
col_to_compressed[c] = new_col dy_2 = points[2][1] - points[0][1]
new_col += 1 return dy_1 * dx_2 != dy_2 * dx_1

# map the original inputs to their compressed values


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]]) # python_1001_to_2000/1038_Binary_Search_Tree_to_Greater_Sum_Tree.py - m
target = (row_to_compressed[target[0]], col_to_compressed[target[1]])
_author_ = 'jake'
# set an extra row or col if we are not at the edege of the original grid _project_ = 'leetcode'
if new_row != 10 ** 6 + 1:
new_row += 1 # https://leetcode.com/problems/binary-search-tree-to-greater-sum-tree/
if new_col != 10 ** 6 + 1: # Given the root of a binary search tree with distinct values, modify it so that every
new_col += 1 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.
# breadth first search # As a reminder, a binary search tree is a tree that satisfies these constraints:
frontier, back, visited = {source, }, {target, }, set() # The left subtree of a node contains only nodes with keys less than the node's key.
while frontier and back: # 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.
if frontier & back - blocked: # overlap between back and frontier that is
not blocked # Perform a reversed inorder traversal, visiting nodes from highest to lowest value.
return True # For each node, add its value to the running sum then update its value.
if len(frontier) > len(back): # expand smaller of frontier and back # Time - O(n)
frontier, back = back, frontier # Space - O(n)
new_frontier = set()
class Solution(object):
for r, c in frontier: def bstToGst(self, root):
if (r, c) in blocked or (r, c) in visited: """
continue :type root: TreeNode
if r < 0 or r >= new_row or c < 0 or c >= new_col: :rtype: TreeNode
continue """
self.running = 0
visited.add((r, c))
for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]: def inorder(node):
new_frontier.add((r + dr, c + dc)) if not node:
return
frontier = new_frontier inorder(node.right)
self.running += node.val
return False node.val = self.running
inorder(node.left)

inorder(root)
# python_1001_to_2000/1037_Valid_Boomerang.py return root

_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1039_Minimum_Score_Triangulation_of_Polygon.py - m
# https://leetcode.com/problems/valid-boomerang/
# A boomerang is a set of 3 points that are all distinct and not in a straight line. _author_ = 'jake'
# Given a list of three points in the plane, return whether these points are a boomerang. _project_ = 'leetcode'

# Check if points are unique by calculating the length of the set of points. # https://leetcode.com/problems/minimum-score-triangulation-of-polygon/
# Points are a boomerang if the slopes between any 2 pairs of points are not equal. # Given N, consider a convex N-sided polygon with vertices labelled A[0], A[i], ..., A[N-
# dx_1 / dy_1 != dx_2 / dy_2 but we multiply by dy_1 * dy_2 to avoid division by zero. 1] in clockwise order.
# Time - O(1) # Suppose you triangulate the polygon into N-2 triangles.
# Space - O(1) # For each triangle, the value of that triangle is the product of the labels of the
vertices,
class Solution(object): # and the total score of the triangulation is the sum of these values over all N-2
def isBoomerang(self, points): triangles in the triangulation.
""" # Return the smallest possible total score that you can achieve with some triangulation
:type points: List[List[int]] of the polygon.
:rtype: bool
""" # Each edge forms a triangle with another vertex not along the edge.
if len({tuple(point) for point in points}) != 3: # convert to tuple to allow # Recursively choose any edge (last vertex to first vertex) and build triangles with all
use of set other vertices. Add the
return False # product of the triangle vertices from the recursive results of the smaller left and
right polygons. Memoize.
dx_1 = points[1][0] - points[0][0] # Time - O(n**3)

# Space - O(n**2) window = deque() # stones in the sliding window


min_moves = n
from functools import lru_cache
for stone in stones:
class Solution(object): window.append(stone)
def minScoreTriangulation(self, A): while stone - window[0] >= n: # remove stones before start of
""" window
:type A: List[int] window.popleft()
:rtype: int
""" moves = n - len(window) # move all stones into window
@lru_cache(None) if moves == 1 and window[0] != stone - n + 1: # additional move if only
def helper(i, j): first position of window is empty
if j - i <= 1: moves = 2
return 0 min_moves = min(min_moves, moves)
return min(helper(i, k) + A[i] * A[k] * A[j] + helper(k, j) for k in range(i
+ 1, j)) return [min_moves, max_moves]

return helper(0, len(A) - 1)

# python_1001_to_2000/1041_Robot_Bounded_In_Circle.py - m

# python_1001_to_2000/1040_Moving_Stones_Until_Consecutive_II.py - m _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/robot-bounded-in-circle/
# On an infinite plane, a robot initially stands at (0, 0) and faces north.
# https://leetcode.com/problems/moving-stones-until-consecutive-ii/ # The robot can receive one of three instructions:
# On an infinite number line, the position of the i-th stone is given by stones[i]. # "G": go straight 1 unit;
# Call a stone an endpoint stone if it has the smallest or largest position. # "L": turn 90 degrees to the left;
# Each turn, pick up an endpoint stone and move it to an unoccupied position so that it # "R": turn 90 degress to the right.
is no longer an endpoint stone. # The robot performs the instructions given in order, and repeats them forever.
# In particular, if the stones are at say, stones = [1,2,5], you cannot move the endpoint # Return true if and only if there exists a circle in the plane such that the robot never
stone at position 5, leaves the circle.
# since moving it to any position (such as 0, or 3) will still keep that stone as an
endpoint stone. # Track the robot's position and direction, updating after every move.
# The game ends when you cannot make any more moves, ie. the stones are in consecutive # If the direction is changed after all moves then the position will return to the origin
positions. after 2 or 4 repeats of the
# When the game ends, what is the minimum and maximum number of moves that you could have # instructions. If the direction is unchanged then the position must also be unchanged.
made? # Time - O(n)
# Return the answer as an length 2 array: answer = [minimum_moves, maximum_moves] # Space - O(1)

# The maximum moves happens when we move either the laft or right stone first then class Solution(object):
gradually fill all the gaps def isRobotBounded(self, instructions):
# between stones, apart from the first or last gap depending on which stone moves first. """
# To find the minimum gap, consider a sliding window of length n where n is the number of :type instructions: str
stones. :rtype: bool
# Find the number of moves required to fill each window for each stone at the right end """
of the window. r, c = 0, 0
# The number of moves is the number of stones outside the window, plus one if only the dr, dc = 1, 0
first position of the window
# is unoccupied (because we cannot move a stone to an endpoint). for instruction in instructions:
# Time - O(n) if instruction == "G":
# Space - O(n) r += dr
c += dc
from collections import deque elif instruction == "L":
dr, dc = -dc, dr
class Solution(object): else:
def numMovesStonesII(self, stones): dr, dc = dc, -dr
"""
:type stones: List[int] return (dr, dc) != (1, 0) or (r, c) == (0, 0)
:rtype: List[int]
"""
n = len(stones)
stones.sort() # python_1001_to_2000/1042_Flower_Planting_With_No_Adjacent.py - m

sum_gaps = stones[-1] - stones[0] - n + 1 # all gaps between stones _author_ = 'jake'


max_moves = sum_gaps - min(stones[1] - stones[0] - 1, stones[-1] - stones[-2] - _project_ = 'leetcode'
1)
# https://leetcode.com/problems/flower-planting-with-no-adjacent/
# You have N gardens, labelled 1 to N. In each garden, you want to plant one of 4 types :rtype: int
of flowers. """
# paths[i] = [x, y] describes the existence of a bidirectional path from garden x to results = [0] # results[i] for array A[:i] (of length i)
garden y.
# Also, there is no garden that has more than 3 paths coming into or leaving it. for i in range(len(A)):
# Your task is to choose a flower type for each garden such that, for any two gardens
connected by a path, subarray_max, max_result = 0, 0
# they have different types of flowers.
# Return any such a choice as an array answer, where answer[i] is the type of flower for j in range(i, max(-1, i - K), -1): # first element of new subarray
planted in the (i+1)-th garden. subarray_max = max(subarray_max, A[j])
# The flower types are denoted 1, 2, 3, or 4. It is guaranteed an answer exists. max_result = max(max_result, subarray_max * (i - j + 1) + results[j])
results.append(max_result)
# For each garden, plant a flower randomly chosen from the set of flowers that are not
# planted in any neighbouring garden. return results[-1]
# Time - O(n) since there are at most 3 paths for each garden.
# Space - O(n)

from collections import defaultdict # python_1001_to_2000/1044_Longest_Duplicate_Substring.py - h

class Solution(object): _author_ = 'jake'


def gardenNoAdj(self, N, paths): _project_ = 'leetcode'
"""
:type N: int # https://leetcode.com/problems/longest-duplicate-substring/
:type paths: List[List[int]] # Given a string S, consider all duplicated substrings: (contiguous) substrings of S that
:rtype: List[int] occur 2 or more times.
""" # The occurrences may overlap.
edges = defaultdict(set) # convert to map from garden to set of # Return any duplicated substring that has the longest possible length.
neighbouring gardens # If S does not have a duplicated substring, the answer is "".
for i, j in paths:
edges[i].add(j) # Binary search for the length of the longest repeated substring.
edges[j].add(i) # For a given length guess, a repeated substring is found by taking the rolling hash of
substrings of length guess.
flowers = [None] * (N + 1) # flowers[0] is not used # Rolling hash is calculated as C0 + C1 * MULTIPLIER + C2 * MULTIPLIER**2 + ... for
characters C0, C1, ...
for garden in range(1, N + 1): # Hash is also modulo MOD. Calculation of next hash as substring slides over S is O(1).
# Time - O(n log n)
if flowers[garden]: # Space - O(n)
continue
possible_flowers = {1, 2, 3, 4} - {flowers[nbor] for nbor in edges[garden]} class Solution(object):
flowers[garden] = possible_flowers.pop() def longestDupSubstring(self, S):
"""
return flowers[1:] :type S: str
:rtype: str
"""
MOD = 2 ** 63 - 1
# python_1001_to_2000/1043_Partition_Array_for_Maximum_Sum.py - m MULTIPLIER = 26
s = [ord(c) - ord("a") for c in S] # convert char to integer
_author_ = 'jake'
_project_ = 'leetcode' def test(guess): # return index or None if no repeat
hash_value = 0
# https://leetcode.com/problems/partition-array-for-maximum-sum/ for i in range(guess):
# Given an integer array A, you partition the array into (contiguous) subarrays of length hash_value = (hash_value * MULTIPLIER + s[i]) % MOD
at most K.
# After partitioning, each subarray has their values changed to become the maximum value val = (MULTIPLIER ** guess) % MOD
of that subarray. seen = {hash_value}
# Return the largest sum of the given array after partitioning.
for i in range(guess, len(S)):
# For each index i of A, create new subarrays of lengths 1, 2... K ending with A[i]. hash_value = (hash_value * MULTIPLIER + s[i] - s[i - guess] * val) % MOD
Track the maximum value in the if hash_value in seen:
# subarray and add the maximum value * subarray length to the result for A ending before return i - guess + 1 # start index of duplicate
the subarray. seen.add(hash_value)
# Time - O(nK)
# Space - O(n) result, low, high = 0, 0, len(S)
while low < high:
class Solution(object): mid = (low + high + 1) // 2 # if high - low == 1, choose high
def maxSumAfterPartitioning(self, A, K): index = test(mid)
""" if index: # longest duplicate length is mid or greater
:type A: List[int] low = mid
:type K: int result = index

else: # longest duplicate length is less than mid def removeDuplicates(self, S):
high = mid - 1 """
:type S: str
return S[result:result + low] :rtype: str
"""
result = []
for c in S:
# python_1001_to_2000/1046_Last_Stone_Weight.py if result and result[-1] == c:
result.pop()
_author_ = 'jake' else:
_project_ = 'leetcode' result.append(c)

# https://leetcode.com/problems/last-stone-weight/ return "".join(result)


# 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.
# Suppose the stones have weights x and y with x <= y.
# The result of this smash is: # python_1001_to_2000/1048_Longest_String_Chain.py - m
# 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 _author_ = 'jake'
new weight y-x. _project_ = 'leetcode'
# At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if
there are no stones left.) # https://leetcode.com/problems/longest-string-chain/
# Given a list of words, each word consists of English lowercase letters.
# Create a heap of the stones. While the are at least 2 stones, pop off the largest 2 # Let's say word1 is a predecessor of word2 if and only if we can add exactly one letter
weights and smash them. anywhere in word1 to make
# Add the resulting stone back to the heap if it has non-zero weight. # it equal to word2. For example, "abc" is a predecessor of "abac".
# Time - O(n log n) # A word chain is a sequence of words [word_1, word_2, ..., word_k] with k >= 1, where
# Space - O(n) word_1 is a predecessor
# of word_2, word_2 is a predecessor of word_3, and so on.
import heapq # Return the longest possible length of a word chain with words chosen from the given
list of words.
class Solution(object):
def lastStoneWeight(self, stones): # Sort the words in increasing order of length. For each word, make all shorter words by
""" removing one char.
:type stones: List[int] # If a shorter word is valid, we can extend its chain by adding this word.
:rtype: int # Save the best result from all shorter words.
""" # Time - O(n k**2) for n words of maximum length k
stones = [-stone for stone in stones] # negative so largest values are # Space - O(n)
popped first
heapq.heapify(stones) from collections import defaultdict

while len(stones) > 1: class Solution(object):


new = heapq.heappop(stones) - heapq.heappop(stones) def longestStrChain(self, words):
if new != 0: """
heapq.heappush(stones, new) :type words: List[str]
:rtype: int
return -stones[0] if stones else 0 """
longest = defaultdict(int)

for word in sorted(words, key=len):


# python_1001_to_2000/1047_Remove_All_Adjacent_Duplicates_In_String.py for i in range(len(word)):
prev = longest[word[:i] + word[i + 1:]] # result for word with
_author_ = 'jake' word[i] removed
_project_ = 'leetcode' longest[word] = max(longest[word], prev + 1)

# https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/ return max(longest.values())


# Given a string S of lowercase letters, a duplicate removal consists of choosing two
adjacent and equal letters,
# and removing them.
# We repeatedly make duplicate removals on S until we no longer can. # python_1001_to_2000/1049_Last_Stone_Weight_II.py - m
# Return the final string after all such duplicate removals have been made. It is
guaranteed the answer is unique. _author_ = 'jake'
_project_ = 'leetcode'
# Iterate over s. When a char matches the previous retained char, discard the both. Else
retain the char. # https://leetcode.com/problems/last-stone-weight-ii/
# Time - O(n) # We have a collection of rocks, each rock has a positive integer weight.
# Space - O(n) # 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:
class Solution(object): # 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 = 0.
new weight y-x. # When the bookstore owner is grumpy, the customers of that minute are not satisfied,
# At the end, there is at most 1 stone left. otherwise they are satisfied.
# Return the smallest possible weight of this stone (the weight is 0 if there are no # The bookstore owner knows a secret technique to keep themselves not grumpy for X
stones left.) minutes, but can only use it once.
# Return the maximum number of customers that can be satisfied throughout the day.
# We need to partition the stones into two disjoint sets where the difference between the
sums of the sets is as # Count the base case number of satisfied customers if the special technique is not used.
# small as possible. # Then for a sliding window of length X minutes, count the additional number of customers
# Make the set of all possible sums by including or excluding each stone. that can be satisfied.
# Return the minimum of the absolute difference between any s sum and its compliment # Time - O(n)
(sum(stones) - s). # Space - O(1)
# Time - O(2**n)
# Space - O(2**n) class Solution(object):
def maxSatisfied(self, customers, grumpy, X):
class Solution(object): """
def lastStoneWeightII(self, stones): :type customers: List[int]
""" :type grumpy: List[int]
:type stones: List[int] :type X: int
:rtype: int :rtype: int
""" """
all_sums = {0} base_satisfied = 0
window, best_window = 0, 0
for stone in stones: # add stone to all previous sums, also retain all
previous sums for i in range(len(customers)):
all_sums |= {stone + prev_sum for prev_sum in all_sums} if grumpy[i] == 1:
window += customers[i] # add additional customers to window
return min(abs(sum(stones) - s - s) for s in all_sums) else:
base_satisfied += customers[i]

if i - X >= 0 and grumpy[i - X] == 1:


# python_1001_to_2000/1051_Height_Checker.py window -= customers[i - X] # remove customers from window

_author_ = 'jake' best_window = max(best_window, window)


_project_ = 'leetcode'
return base_satisfied + best_window
# https://leetcode.com/problems/height-checker/
# Students are asked to stand in non-decreasing order of heights for an annual photo.
# Return the minimum number of students not standing in the right positions.
# This is the number of students that must move in order for all students to be standing # python_1001_to_2000/1053_Previous_Permutation_With_One_Swap.py - m
in non-decreasing
# order of height. _author_ = 'jake'
_project_ = 'leetcode'
# Compare the sorted ordering with the original ordering.
# Time - O(n log n) # https://leetcode.com/problems/previous-permutation-with-one-swap/
# Space - O(n) # Given an array A of positive integers (not necessarily distinct),
# return the lexicographically largest permutation that is smaller than A, that can be
class Solution(object): made with one swap.
def heightChecker(self, heights): # A swap exchanges the positions of two numbers A[i] and A[j]).
""" # If it cannot be done, then return the same array.
:type heights: 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
return sum(h1 != h2 for h1, h2 in zip(heights, sorted(heights))) A[i] with the next smallest
# digit. Search for the next smallest digit, taking the most significant in the event of
a tie.
# Time - O(n)
# python_1001_to_2000/1052_Grumpy_Bookstore_Owner.py - m # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def prevPermOpt1(self, A):
"""
# https://leetcode.com/problems/grumpy-bookstore-owner/ :type A: List[int]
# Today, the bookstore owner has a store open for customers.length minutes. :rtype: List[int]
# Every minute, some number of customers (customers[i]) enter the store, and all those """
customers for i in range(len(A) - 2, -1, -1):
# leave after the end of that minute.
# On some minutes, the bookstore owner is grumpy. if A[i] > A[i + 1]: # A can be made smaller by swapping a smaller
# If the bookstore owner is grumpy on the i-th minute, grumpy[i] = 1, otherwise grumpy[i] digit to A[i]

# If the task is impossible, return -1.


max_seen = -1
for j in range(len(A) - 1, i, -1): # Create mapping from each source char to the indices in source of that char.
if A[j] >= max_seen and A[j] < A[i]: # Iterate over target, searching for the next index in source of each char. Return -1 if
max_seen = A[j] not found.
max_seen_index = j # Search is by binary search of the list of indices in source of char.
# If the next index in source requires wrapping around to the start of source, increment
A[i], A[max_seen_index] = A[max_seen_index], A[i] # swap result count.
break # Time - O(n log m) for source of length m and target of length n.
# Space - O(m)
return A
from collections import defaultdict
import bisect

# python_1001_to_2000/1054_Distant_Barcodes.py - m class Solution(object):


def shortestWay(self, source, target):
_author_ = 'jake' """
_project_ = 'leetcode' :type source: str
:type target: str
# https://leetcode.com/problems/distant-barcodes/ :rtype: int
# In a warehouse, there is a row of barcodes, where the i-th barcode is barcodes[i]. """
# Rearrange the barcodes so that no two adjacent barcodes are equal. char_indices = defaultdict(list)
# You may return any answer, and it is guaranteed an answer exists. for i, c in enumerate(source):
char_indices[c].append(i)
# 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 result = 0
places to fill the even indices. i = 0 # next index of source to check
# When we reach the end of the result, move back to index 1 to fill the odd indices.
# Time - O(n log n) for c in target:
# Space - O(n) if c not in char_indices: # cannot make target if char not in
source
from collections import Counter return -1

class Solution(object): j = bisect.bisect_left(char_indices[c], i) # index in char_indices[c] that


def rearrangeBarcodes(self, barcodes): is >= i
""" if j == len(char_indices[c]): # wrap around to beginning of source
:type barcodes: List[int] result += 1
:rtype: List[int] j = 0
""" i = char_indices[c][j] + 1 # next index in source
n = len(barcodes)
freq = Counter(barcodes) return result if i == 0 else result + 1 # add 1 for partial source
freq = sorted([(count, num) for num, count in freq.items()], reverse=True)

result = [0] * n
i = 0 # next index of result to be updated # python_1001_to_2000/1056_Confusing_Number.py

for count, num in freq: # from most to least frequent _author_ = 'jake'
for _ in range(count): # use all occurrences of num _project_ = 'leetcode'
result[i] = num
i += 2 # https://leetcode.com/problems/confusing-number/
if i >= n: # Given a number N, return true if and only if it is a confusing number, which satisfies
i = 1 the following condition:
# We can rotate digits by 180 degrees to form new digits.
return result # 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.
# A confusing number is a number that when rotated 180 degrees becomes a different number
with each digit valid.
# python_1001_to_2000/1055_Shortest_Way_to_Form_String.py - m
# Iterate along the digits of S in reverse.
_author_ = 'jake' # If any digit cannot be rotated, return False. Else add the rotated digit to the result.
_project_ = 'leetcode' # Finally check if the result is different from the original number.
# Time - O(n)
# https://leetcode.com/problems/shortest-way-to-form-string/ # Space - O(n)
# From any string, we can form a subsequence of that string by deleting some number of
characters class Solution(object):
# (possibly no deletions). def confusingNumber(self, N):
# Given two strings source and target, return the minimum number of subsequences of """
source such that :type N: int
# their concatenation equals target. :rtype: bool
"""
S = str(N) while len(used_bikes) < len(workers):
rotation = {"0": "0", "1": "1", "6": "9", "8": "8", "9": "6"} _, worker, bike = heapq.heappop(queue)
result = [] if bike not in used_bikes:
result[worker] = bike
for c in S[::-1]: # iterate in reverse used_bikes.add(bike)
if c not in rotation: else:
return False heapq.heappush(queue, distances[worker].pop()) # bike used, add next
result.append(rotation[c]) closest bike

return "".join(result) != S return result

# python_1001_to_2000/1057_Campus_Bikes.py - m # python_1001_to_2000/1058_Minimize_Rounding_Error_to_Meet_Target.py - m

_author_ = 'jake' _author_ = 'jake'


_project_ = 'leetcode' _project_ = 'leetcode'

# https://leetcode.com/problems/campus-bikes/ # https://leetcode.com/problems/minimize-rounding-error-to-meet-target/
# On a campus represented as a 2D grid, there are N workers and M bikes, # Given an array of prices [p1,p2...,pn] and a target, round each price pi to Roundi(pi)
# with N <= M. Each worker and bike is a 2D coordinate on this grid. so that the rounded array
# Our goal is to assign a bike to each worker. # [Round1(p1),Round2(p2)...,Roundn(pn)] sums to the given target.
# Among the available bikes and workers, we choose the (worker, bike) pair with the # Each operation Roundi(pi) could be either Floor(pi) or Ceil(pi).
shortest Manhattan distance # Return the string "-1" if the rounded array is impossible to sum to target.
# between each other, and assign the bike to that worker. # Otherwise, return the smallest rounding error, which is defined as Σ |Roundi(pi) -
# If there are multiple (worker, bike) pairs with the same shortest Manhattan distance, (pi)| for i from 1 to n,
we choose the pair with the # as a string with three places after the decimal.
# smallest worker index; if there are multiple ways to do that, we choose the pair with
the smallest bike index. # For each price, add the floor to the base and record the remaining decimal digits.
# We repeat this process until there are no available workers. # If the target is below the base or above the total ceiling, return "-1".
# The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x - # Sort the remainders then iterate along, rounding up the largest remainders until the
p2.x| + |p1.y - p2.y|. target is reached.
# Return a vector ans of length N, where ans[i] is the index of the bike that the i-th # Round down all reaminders not rounded up and add to result.
worker is assigned to. # Time - O(n log n)
# Space - O(n)
# For each worker, create a sorted list of distances to each bike.
# The elements of the list are tuples (distance, worker, bike). class Solution(object):
# For each worker, add the tuple with the shortest distance to the heap. def minimizeError(self, prices, target):
# Until each worker has a bike, pop the smallest distance from the heap. """
# If this bike is not used, update the result for this worker, :type prices: List[str]
# else add the next closest tuple for this worker to the heap. :type target: int
# Time - O(mn log mn) for m workers and n bikes. :rtype: str
# Space - O(mn) """
base = 0 # sum of price floors
import heapq remainders = [] # decimal places, ints between 0 and 1000

class Solution(object): for price in prices:


def assignBikes(self, workers, bikes): integer, remainder = price.split(".")
""" base += int(integer)
:type workers: List[List[int]] if remainder != "000":
:type bikes: List[List[int]] remainders.append(int(remainder))
:rtype: List[int]
""" if target < base or target > base + len(remainders):
distances = [] # distances[worker] is list of [distance, worker, bike] for return "-1"
each bike
for i, (x, y) in enumerate(workers): remainders.sort(reverse=True)
distances.append([]) result = 0
for j, (x_b, y_b) in enumerate(bikes): i = 0
distance = abs(x - x_b) + abs(y - y_b)
distances[-1].append([distance, i, j]) while i < len(remainders) and base + i < target:
distances[-1].sort(reverse=True) # reverse so we pop the smallest distance result += 1000 - remainders[i] # round up largest remainders first
first i += 1

result = [None] * len(workers) result += sum(remainders[i:]) # round down the rest of remainders
used_bikes = set() return "{:.3f}".format(result / 1000)
queue = [distances[i].pop() for i in range(len(workers))] # smallest distance
for each worker
heapq.heapify(queue)

# python_1001_to_2000/1059_All_Paths_from_Source_Lead_to_Destination.py - m # Iterate along nums, subtracting the number of missing elements from k until no more
missing elements are required.
_author_ = 'jake' # Time - O(n)
_project_ = 'leetcode' # Space - O(1)

# https://leetcode.com/problems/all-paths-from-source-lead-to-destination/ class Solution(object):


# Given the edges of a directed graph, and two nodes source and destination of this def missingElement(self, nums, k):
graph, """
# determine whether or not all paths starting from source eventually end at destination, :type nums: List[int]
that is: :type k: int
# At least one path exists from the source node to the destination node :rtype: int
# If a path exists from the source node to a node with no outgoing edges, then that node """
is equal to destination. nums.append(float("inf")) # add infinity so we check after the final
# The number of possible paths from source to destination is a finite number. element of nums
# Return true if and only if all roads from source lead to destination. prev = nums[0]

# Build a map from each node to the set of nodes connected by an edge. for num in nums[1:]:
# From the source node, recursively explore all neighbours adding them to the visited set missing = num - prev - 1 # count of missing elements between num and prec
and testing whether all if k - missing <= 0: # missing element is between num and prev
# paths lead to the destination. Remove nodes from visited set when returning from return prev + k
recursion. k -= missing
# Time - O(m + n), nodes + edges prev = num
# Space - O(m + n)

from collections import defaultdict


# python_1001_to_2000/1061_Lexicographically_Smallest_Equivalent_String.py - m
class Solution(object):
def leadsToDestination(self, n, edges, source, destination): _author_ = 'jake'
""" _project_ = 'leetcode'
:type n: int
:type edges: List[List[int]] # https://leetcode.com/problems/lexicographically-smallest-equivalent-string/
:type source: int # Given strings A and B of the same length, we say A[i] and B[i] are equivalent
:type destination: int characters.
:rtype: bool # For example, if A = "abc" and B = "cde", then we have 'a' == 'c', 'b' == 'd', 'c' ==
""" 'e'.
visited = set() # Equivalent characters follow the usual rules of any equivalence relation:
edge_dict = defaultdict(set) # Reflexivity: 'a' == 'a'
for start, end in edges: # Symmetry: 'a' == 'b' implies 'b' == 'a'
edge_dict[start].add(end) # Transitivity: 'a' == 'b' and 'b' == 'c' implies 'a' == 'c'
# For example, given the equivalency information from A and B above, S = "eed", "acd",
def can_reach_dest(node): and "aab" are equivalent strings,
if node == destination and len(edge_dict[node]) == 0: # destination reached # and "aab" is the lexicographically smallest equivalent string of S.
and no neighbours # Return the lexicographically smallest equivalent string of S by using the equivalency
return True information from A and B.
if node == destination or len(edge_dict[node]) == 0: # destination has
neighbours or terminal node # Create a mapping from each char to its direct equivalents.
return False # that is not # For each char of S, explore the map of all equivalents and set the minimum equivalent
destination of all chars visited.
# Memoize the minimum equivalents.
if node in visited: # Time - O(n)
return False # Space - O(n)
visited.add(node)
result = all(can_reach_dest(nbor) for nbor in edge_dict[node]) from collections import defaultdict
visited.remove(node)
return result class Solution(object):
def smallestEquivalentString(self, A, B, S):
return can_reach_dest(source) """
:type A: str
:type B: str
:type S: str
# python_1001_to_2000/1060_Missing_Element_in_Sorted_Array.py - m :rtype: str
"""
_author_ = 'jake' equivalents = defaultdict(set) # map char to its directly connected equivalents
_project_ = 'leetcode' for a, b in zip(A, B):
equivalents[a].add(b)
# https://leetcode.com/problems/missing-element-in-sorted-array/ equivalents[b].add(a)
# Given a sorted array A of unique numbers, find the K-th missing number starting from
the leftmost number of the array. minimum = {} # map char to its minimum equivalent
def get_minimum(char): # return the minimum equivalent class Solution2(object):
if char in minimum: def longestRepeatingSubstring(self, S):
return minimum[char] n = len(S)
result = 0
result = char
visited = set() for offset in range(1, n): # compare S[:-i] to S[i:]
queue = {char} if result >= n - offset:
break
while queue:
c = queue.pop() sequence = 0
if c in visited: for i in range(n - offset):
continue if S[i] == S[i + offset]:
visited.add(c) sequence += 1
result = min(result, c) result = max(result, sequence)
queue |= equivalents[c] # add all equivalents to the queue else:
sequence = 0
for v in visited: # minimum equivalent for all visited is set to result
minimum[v] = result return result
return result

return "".join(get_minimum(c) for c in S)


# python_1001_to_2000/1063_Number_of_Valid_Subarrays.py - h

_author_ = 'jake'
# python_1001_to_2000/1062_Longest_Repeating_Substring.py - m _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/number-of-valid-subarrays/


_project_ = 'leetcode' # Given an array A of integers, return the number of non-empty continuous subarrays that
satisfy the following:
# https://leetcode.com/problems/longest-repeating-substring/ # The leftmost element of the subarray is not larger than other elements in the subarray.
# Given a string S, find out the length of the longest repeating substring(s).
# Return 0 if no repeating substring exists. # Maintain a stack of leftmost elements in increasing order.
# Iterate along nums, popping from the stack all leftmost elements that are greater than
# Binary search the range of possible lengths of repeated substring. the current element.
# Helper function checks all substrings of a given length. # Add the current element and increment the result by the count of leftmost elements on
# Alternatively, for a pair of strings of the same length we can check if there is a the stack.
repeated substring starting and # Time - O(n)
# ending at the same indices in O(n) time. Compare S against itself with an offset for # Space - O(n)
all possible offsets.
# Time - O(n**2 log n) class Solution(object):
# Space - O(n**2) def validSubarrays(self, nums):
"""
class Solution(object): :type nums: List[int]
def longestRepeatingSubstring(self, S): :rtype: int
""" """
:type S: str result = 0
:rtype: int stack = [] # leftmost elements
"""
def helper(guess): for num in nums:
seen = set()
for i in range(n - guess + 1): while stack and stack[-1] > num: # remove elements from stack
substring = S[i:i + guess] stack.pop()
if substring in seen: stack.append(num)
return True
seen.add(substring) result += len(stack)
return False
return result
n = len(S)
low, high = 0, n

while low <= high: # until low > high # python_1001_to_2000/1064_Fixed_Point.py


mid = (low + high) // 2
if helper(mid): _author_ = 'jake'
low = mid + 1 _project_ = 'leetcode'
else:
high = mid - 1 # https://leetcode.com/problems/fixed-point/
# Given an array A of distinct integers sorted in ascending order,
return low - 1 # return the smallest index i that satisfies A[i] == i. Return -1 if no such i exists.

# Binary search the indices of the array. # On a campus represented as a 2D grid, there are N workers and M bikes, with N <= M.
# If a A[i] is greater than i then the fixed point must be to the left, so decrease right # Each worker and bike is a 2D coordinate on this grid.
to i - 1. # We assign one unique bike to each worker so that the sum of the Manhattan distances
# If a A[i] is leff than i then the fixed point must be to the right, so increase left to between each worker
i + 1. # and their assigned bike is minimized.
# Time - O(log n) # The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x -
# Space - O(1) p2.x| + |p1.y - p2.y|.
# Return the minimum possible sum of Manhattan distances between each worker and their
class Solution(object): assigned bike.
def fixedPoint(self, A):
""" # Maintain a heap of the smallest total distance for each number of workers and some set
:type A: List[int] of used bikes.
:rtype: int # Workers are allocated to bikes in their order in the initial list.
""" # The set of used bikes ir represented by an integer with a set bit indicating bikes that
left, right = 0, len(A) - 1 are used.
# Until all workers have a bike, pop the smallest distance and allocate all available
while left <= right: (unused) bikes to the next worker.
mid = (left + right) // 2 # Do not repeat cases where the same bikes are allocated.
if A[mid] == mid: # Time - O(X log X) where X = b! / (b - w)!.
return mid # Space - O(b! / (b - w)!), the number of ways to choose w from b.
if A[mid] > mid:
right = mid - 1 import heapq
else:
left = mid + 1 class Solution(object):
def assignBikes(self, workers, bikes):
return -1 """
:type workers: List[List[int]]
:type bikes: List[List[int]]
:rtype: int
# python_1001_to_2000/1065_Index_Pairs_of_a_String.py """
distance = []
_author_ = 'jake' for worker in workers:
_project_ = 'leetcode' distance.append([])
for bike in bikes:
# https://leetcode.com/problems/index-pairs-of-a-string/ distance[-1].append(abs(worker[0] - bike[0]) + abs(worker[1] - bike[1]))
# Given a text string and words (a list of strings), return all index pairs [i, j]
# so that the substring text[i]...text[j] is in the list of words. heap = [(0, 0, 0)] # heap of (total distance, used bike flags, workers with
bikes)
# Repeatedly find each word in text until it is not found. heapq.heapify(heap)
# Start each find from the character after the previous find. seen = set()
# Time - O(mn log mn) for m words in text of length n
# Space - O(mn) while True:
dist, used, count = heapq.heappop(heap)
class Solution(object): if count == len(workers):
def indexPairs(self, text, words): return dist
""" if used in seen:
:type text: str continue
:type words: List[str] seen.add(used)
:rtype: List[List[int]]
""" for i in range(len(bikes)):
result = [] if not used & (1 << i):
for word in words: heapq.heappush(heap, (dist + distance[count][i], used | (1 << i),
i = -1 count + 1))
while True:
i = text.find(word, i + 1)
if i == -1:
break # python_1001_to_2000/1067_Digit_Count_in_Range.py - h
result.append([i, i + len(word) - 1])
_author_ = 'jake'
return sorted(result) _project_ = 'leetcode'

# https://leetcode.com/problems/digit-count-in-range/
# Given an integer d between 0 and 9, and two positive integers low and high as lower and
# python_1001_to_2000/1066_Campus_Bikes_II.py - m upper bounds, respectively.
# Return the number of times that d occurs as a digit in all integers between low and
_author_ = 'jake' high,
_project_ = 'leetcode' # including the bounds low and high.

# https://leetcode.com/problems/campus-bikes-ii/ # Helper function count_digits(n) recursively counts d in all integers less than n.
# Separate n into prefix (dividing by 0) and units (modulo 0). return candidate if str1 == candidate * (len(str1) // a) and str2 == candidate *
# The 4 components to the count are: (len(str2) // a) else ""
# - fix prefix count d in units, provided d < units.
# - count of d in fixed prefix, followed by all units < d.
# - any int < prefix, followed by fixed d (not 0 prefix and 0 units).
# - result from prefix, followed by any digit 0 to 9. # python_1001_to_2000/1072_Flip_Columns_For_Maximum_Number_of_Equal_Rows.py - m
# Time - O(log n)
# Space - O(log n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def digitsCount(self, d, low, high): # https://leetcode.com/problems/flip-columns-for-maximum-number-of-equal-rows/
""" # Given a matrix consisting of 0s and 1s, we may choose any number of columns in the
:type d: int matrix
:type low: int # and flip every cell in that column.
:type high: int # Flipping a cell changes the value of that cell from 0 to 1 or from 1 to 0.
:rtype: int # Return the maximum number of rows that have all values equal after some number of
""" flips.
def count_digits(n): # return count of d in integers less than n
if n == 0 or (d == 0 and n <= 10): # For 2 rows to have all cells the same after some column flips, they must have either
return 0 the same pattern of
# 0 and 1 or the opposite pattern.
result = 0 # For each row, if the first column is not zero flip all values of that row by taking XOR
prefix, units = divmod(n, 10) # assume n = ppppu for prefix with first value.
pppp and units u # Convert the row to a tuple and count the number of each tuple.
if units > d: # count the d in ppppd # The largest tuple count is the most rows that can be all equal.
result += 1 # Time - O(mn)
if prefix > 0: # count of d in prefix, followed # Space - O(mn)
by any units < d
result += str(prefix).count(str(d)) * units from collections import defaultdict
result += prefix if d else prefix - 1 # any int < prefix, followed by d
(exclude 0 then 0) class Solution(object):
result += count_digits(prefix) * 10 # count of any int < prefix, def maxEqualRowsAfterFlips(self, matrix):
followed by any digit """
return result :type matrix: List[List[int]]
:rtype: int
return count_digits(high + 1) - count_digits(low) """
row_counter = defaultdict(int)
for row in matrix:
row_counter[tuple(x ^ row[0] for x in row)] += 1
# python_1001_to_2000/1071_Greatest_Common_Divisor_of_Strings.py
return max(row_counter.values())
_author_ = 'jake'
_project_ = 'leetcode'

# https://leetcode.com/problems/greatest-common-divisor-of-strings/ # python_1001_to_2000/1073_Adding_Two_Negabinary_Numbers.py - m
# 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) _author_ = 'jake'
# Return the largest string X such that X divides str1 and X divides str2. _project_ = 'leetcode'

# Find the GCD of the lengths of the strings. # https://leetcode.com/problems/adding-two-negabinary-numbers/


# Check whether both strings consist of repeated prefix of GCD length. # Given two numbers arr1 and arr2 in base -2, return the result of adding them together.
# Time - O(m + n) # Each number is given in array format:
# Space - O(1) # as an array of 0s and 1s, from most significant bit to least significant bit.
# For example, arr = [1,1,0,1] represents the number (-2)^3 + (-2)^2 + (-2)^0 = -3.
class Solution(object): # A number arr in array format is also guaranteed to have no leading zeros: either arr ==
def gcdOfStrings(self, str1, str2): [0] or arr[0] == 1.
""" # Return the result of adding arr1 and arr2 in the same format: as an array of 0s and 1s
:type str1: str with no leading zeros.
:type str2: str
:rtype: str # Iterate over arrays from least to most significant digits.
""" # Add digits from both arrays to carry.
a, b = len(str1), len(str2) # If sum of digits and carry is 1 or 0, append that to result.
if a < b: # If sum of digits and carry is 2, append 0, increment carry and next carry since 2**
a, b = b, a (n+2) - 2**(n+1) = 2*2**n.
# If sum of digits and carry is 3, append 1, increment carry and next carry since 2**
while b != 0: (n+2) - 2**(n+1) = 2*2**n.
a, b = b, a % b # If next carry is 1 and carry is 2 then these are netted to zero.

candidate = str1[:a] # Time - O(max(m, n))

# Space - O(max(m, n)) matrix = zip(*matrix[::-1])


rows, cols = cols, rows
class Solution(object):
def addNegabinary(self, arr1, arr2): cumulative_rows = [] # sum along each row
""" for row in range(rows):
:type arr1: List[int] cumulative_rows.append([matrix[row][0]])
:type arr2: List[int] for col in range(1, cols):
:rtype: List[int] cumulative_rows[-1].append(matrix[row][col] + cumulative_rows[-1][-1])
"""
carry, next_carry = 0, 0 # carry over to the following 2 digits result = 0
result = []
for col_start in range(cols):
while arr1 or arr2 or carry or next_carry: for col_end in range(col_start, cols): # each pair of columns
digit = carry seen = defaultdict(int, {0: 1}) # count submatrix sums between there
if arr1: columns
digit += arr1.pop() submatrix = 0
if arr2: for row in range(rows):
digit += arr2.pop() submatrix += cumulative_rows[row][col_end] # add new row upto
sol_end
carry, next_carry = next_carry, 0 if col_start != 0:
result.append(digit % 2) submatrix -= cumulative_rows[row][col_start - 1] # subtract
if digit == 2 or digit == 3: row before col_start
carry += 1
if digit >= 2: if submatrix - target in seen:
if carry >= 2: result += seen[submatrix - target]
carry -= 2 seen[submatrix] += 1
else:
next_carry += 1 return result

while result[-1] == 0 and len(result) > 1: # remove leading zeros


result.pop()
return result[::-1] # put most significant digit # python_1001_to_2000/1078_Occurrences_After_Bigram.py
first
_author_ = 'jake'
_project_ = 'leetcode'

# python_1001_to_2000/1074_Number_of_Submatrices_That_Sum_to_Target.py - h # https://leetcode.com/problems/occurrences-after-bigram/
# Given words first and second, consider occurrences in some text of the form "first
_author_ = 'jake' second third",
_project_ = 'leetcode' # where second comes immediately after first, and third comes immediately after second.
# For each such occurrence, add "third" to the answer, and return the answer.
# https://leetcode.com/problems/number-of-submatrices-that-sum-to-target/
# Given a matrix, and a target, return the number of non-empty submatrices that sum to # Split text by space and check for consecutive appearances of first and second.
target. # Time - O(n)
# A submatrix x1, y1, x2, y2 is the set of all cells matrix[x][y] with x1 <= x <= x2 and # Space - O(n)
y1 <= y <= y2.
# Two submatrices (x1, y1, x2, y2) and (x1', y1', x2', y2') are different if they have class Solution(object):
some different coordinate def findOcurrences(self, text, first, second):
# for example, if x1 != x1'. """
:type text: str
# Calculate the cumulative sums along each row. :type first: str
# For each pair of columns, calculate the sumbmatrix sum between those columns from row 0 :type second: str
to each row. :rtype: List[str]
# Check if any other submatrix sum can be subtracted from the current sum to reach """
target. result = []
# Time - O(m**2 * n) s = text.split()
# Space - O(mn)
for i in range(2, len(s)):
from collections import defaultdict if s[i - 2] == first and s[i - 1] == second:
result.append(s[i])
class Solution(object):
def numSubmatrixSumTarget(self, matrix, target): return result
"""
:type matrix: List[List[int]]
:type target: int
:rtype: int # python_1001_to_2000/1079_Letter_Tile_Possibilities.py - m
"""
rows, cols = len(matrix), len(matrix[0]) _author_ = 'jake'
if rows < cols: # swap rows and cols if more cols _project_ = 'leetcode'
:type limit: int
# https://leetcode.com/problems/letter-tile-possibilities/ :rtype: TreeNode
# You have a set of tiles, where each tile has one letter tiles[i] printed on it. """
# Return the number of possible non-empty sequences of letters you can make. if root.left is None and root.right is None:
return None if root.val < limit else root
# Count the number of tiles of each type.
# Depth-first search for all possible sequences. if root.left:
# Use each tile with a non-zero count and increment the number of sequences. root.left = self.sufficientSubset(root.left, limit - root.val)
# Decrement the count of the used tile, then recurse. Increment the count back after if root.right:
recursion. root.right = self.sufficientSubset(root.right, limit - root.val)
# Return when all tiles are used.
# Time - O(n!) return root if root.right or root.left else None
# Space - O(n!)

from collections import Counter


# python_1001_to_2000/1081_Smallest_Subsequence_of_Distinct_Characters.py - m
class Solution(object):
def numTilePossibilities(self, tiles): _author_ = 'jake'
""" _project_ = 'leetcode'
:type tiles: str
:rtype: int # https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/
""" # Return the lexicographically smallest subsequence of text that contains all the
self.total = 0 distinct characters
freq = Counter(tiles) # of text exactly once.

def helper(remaining): # Map each char to its last index in text.


# Iterate over text. For each char, if it's in the text then ignore it.
if remaining == 0: # While the char is lexicographically after the top of stack and top of stack char also
return occurs later in text,
# then pop top of stack. Append char to stack and convert to string before returning.
for tile, count in freq.items(): # Time - O(n)
if count != 0: # Space - O(1) since alphabet size is limited.
freq[tile] -= 1
self.total += 1 class Solution(object):
helper(remaining - 1) def smallestSubsequence(self, text):
freq[tile] += 1 """
:type text: str
helper(len(tiles)) :rtype: str
return self.total """
last_index = {c: i for i, c in enumerate(text)}
stack = []

# python_1001_to_2000/1080_Insufficient_Nodes_in_Root_to_Leaf_Paths.py - m for i, c in enumerate(text):


if c in stack:
_author_ = 'jake' continue
_project_ = 'leetcode' while stack and stack[-1] > c and last_index[stack[-1]] > i:
stack.pop()
# https://leetcode.com/problems/insufficient-nodes-in-root-to-leaf-paths/ stack.append(c)
# Given the root of a binary tree, consider all root to leaf paths: paths from the root
to any leaf. return "".join(stack)
# A leaf is a node with no children.
# A node is insufficient if every such root to leaf path intersecting this node has sum
strictly less than limit.
# Delete all insufficient nodes simultaneously, and return the root of the resulting # python_1001_to_2000/1085_Sum_of_Digits_in_the_Minimum_Number.py
binary tree.
_author_ = 'jake'
# Move down the tree, subtracting each node's value form the limit. _project_ = 'leetcode'
# 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. # https://leetcode.com/problems/sum-of-digits-in-the-minimum-number/
# If either subtree is not removed then there is a path through a node greater than or # Given an array A of positive integers, let S be the sum of the digits of the minimal
equal to the limit, element of A.
# so retain the node, else remove it. # Return 0 if S is odd, otherwise return 1.
# Time - O(n)
# Space - O(n) # Find the minimum and sum the digits.
# Time - O(n + log m) where n is the length of A and m is the minimum value.
class Solution(object): # Space - O(1)
def sufficientSubset(self, root, limit):
""" class Solution(object):
:type root: TreeNode def sumOfDigits(self, A):

"""
:type A: List[int] # Create a list of lists where each inner list is a sorted group of words.
:rtype: int # Then depth-first search. For each group, add all words to the current partial result
""" and recurse to the next group.
minimum = min(A) # Time - O(g**2 * n**g) - as space complexity below except each result is built by adding
digit_sum = 0 individual chars.
while minimum: # Space - O(g * n**g) for g groups of length n since each result is of length g and there
digit_sum += minimum % 10 are n possibilities for
minimum //= 10 # each char.
return int(digit_sum % 2 == 0)
class Solution(object):
def expand(self, S):
"""
# python_1001_to_2000/1086_High_Five.py :type S: str
:rtype: List[str]
_author_ = 'jake' """
_project_ = 'leetcode' group_start = 0
groups = []
# https://leetcode.com/problems/high-five/
# Given a list of scores of different students, return the average score of each while group_start < len(S):
student's top five scores while S[group_start] in "}{": # ignore previous closing or current
# in the order of each student's id. opening braces
# Each entry items[i] has items[i][0] the student's id, and items[i][1] the student's group_start += 1
score. group_end = group_start
# The average score is calculated using integer division. while group_end < len(S) and S[group_end] not in "{}": # find end of
current group
# For each id, maintain a heap of the top 5 scores. group_end += 1
# Add each result to its heap, popping off a value if the heap has more 3 elements. groups.append(sorted(S[group_start:group_end].split(","))) # sort words in
# Then take the average of each heap and sort by id. group
# Time - O(n log n) since heap is of fixed size. group_start = group_end + 1
# Space - O(n)
results = []
from collections import defaultdict def expand(group, partial):
import heapq if group == len(groups):
results.append(partial)
class Solution(object): return
def highFive(self, items): for c in groups[group]:
""" expand(group + 1, partial + c)
:type items: List[List[int]]
:rtype: List[List[int]] expand(0, "")
""" return results
TOP_SCORES = 5
heaps = defaultdict(list)

for id, score in items: # python_1001_to_2000/1088_Confusing_Number_II.py - h


if len(heaps[id]) < TOP_SCORES:
heapq.heappush(heaps[id], score) _author_ = 'jake'
else: _project_ = 'leetcode'
heapq.heappushpop(heaps[id], score)
# https://leetcode.com/problems/confusing-number-ii/
result = [[id, sum(scores) // 5] for id, scores in heaps.items()] # We can rotate digits by 180 degrees to form new digits.
return sorted(result) # 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.
# A confusing number is a number that when rotated 180 degrees becomes a different number
with each digit valid.
# python_1001_to_2000/1087_Brace_Expansion.py - m # Note that the rotated number can be greater than the original number.
# Given a positive integer N, return the number of confusing numbers between 1 and N
_author_ = 'jake' inclusive.
_project_ = 'leetcode'
# Helper function take a number and its rotation and updates count for number and all
# https://leetcode.com/problems/brace-expansion/ greater confusing numbers <= N.
# A string S represents a list of words. # Update result if confusing, then recurse for all 5 valid digits appended to number.
# Each letter in the word has 1 or more options. # Time - O(5 ** log n), where log is base 10
# If there is one option, the letter is represented as is. # Space - O(5 ** log n)
# If there is more than one option, then curly braces delimit the options.
# For example, "{a,b,c}" represents options ["a", "b", "c"]. class Solution(object):
# For example, "{a,b,c}d{e,f}" represents the list ["ade", "adf", "bde", "bdf", "cde", def confusingNumberII(self, N):
"cdf"]. """
# Return all words that can be formed in this manner, in lexicographical order. :type N: int
:rtype: int # python_1001_to_2000/1090_Largest_Values_From_Labels.py - m
"""
valid = [0, 1, 6, 8, 9] _author_ = 'jake'
rotations = {0: 0, 1: 1, 6: 9, 8: 8, 9: 6} _project_ = 'leetcode'

self.count = 0 # https://leetcode.com/problems/largest-values-from-labels/
# We have a set of items: the i-th item has value values[i] and label labels[i].
def helper(num, rotation): # Then, we choose a subset S of these items, such that:
length = len(str(num)) # |S| <= num_wanted
if num != rotation: # For every label L, the number of items in S with label L is <= use_limit.
self.count += 1 # Return the largest possible sum of the subset S.
for i in valid:
if num * 10 + i > N: # Sort tuples of (value, label) in descending order.
return # Greedily add each value to the result, provided do not add more than use_limit of each
helper(num * 10 + i, rotations[i] * 10 ** length + rotation) item.
# Track the remaining allowed number of each label in a dictionary.
for num in valid[1:]: # do not start with zero # Return when we have added num_wanted values.
helper(num, rotations[num]) # Time - O(n log n)
# Space - O(n)
return self.count
class Solution(object):
def largestValsFromLabels(self, values, labels, num_wanted, use_limit):
"""
# python_1001_to_2000/1089_Duplicate_Zeros.py :type values: List[int]
:type labels: List[int]
_author_ = 'jake' :type num_wanted: int
_project_ = 'leetcode' :type use_limit: int
:rtype: int
# https://leetcode.com/problems/duplicate-zeros/ """
# Given a fixed length array arr of integers, duplicate each occurrence of zero, result, used = 0, 0
# shifting the remaining elements to the right. remaining = {} # map label to remaining number we can choose
# Note that elements beyond the length of the original array are not written.
# Do the above modifications to the input array in place, do not return anything from for value, label in sorted(zip(values, labels), reverse=True):
your function. remain = remaining.get(label, use_limit) # default use_limit if not found
if remain > 0:
# Iterate along arr, updating the new length after duplicating zeros. result += value
# Find the index i in arr when the array with duplicates is full. remaining[label] = remain - 1
# Then iterate backwards from i, moving each element to its new index and duplicating used += 1
zeros. if used == num_wanted:
# Time - O(n) break
# Space - O(1)
return result
class Solution(object):
def duplicateZeros(self, arr):
"""
:type arr: List[int] # python_1001_to_2000/1091_Shortest_Path_in_Binary_Matrix.py - m
:rtype: None Do not return anything, modify arr in-place instead.
""" _author_ = 'jake'
length = 0 # length of arr after duplicating zeros _project_ = 'leetcode'
for i, num in enumerate(arr):
length += 2 if num == 0 else 1 # https://leetcode.com/problems/shortest-path-in-binary-matrix/
if length >= len(arr): # In an N by N square grid, each cell is either empty (0) or blocked (1).
break # A clear path from top-left to bottom-right has length k if and only if it is composed
of
next_fill = len(arr) - 1 # cells C_1, C_2, ..., C_k such that:
if length > len(arr): # only one of the duplicate zero fits in arr # Adjacent cells C_i and C_{i+1} are connected 8-directionally (ie., they are different
arr[-1] = 0 and share an edge or corner)
i -= 1 # C_1 is at location (0, 0) (ie. has value grid[0][0])
next_fill -= 1 # C_k is at location (N-1, N-1) (ie. has value grid[N-1][N-1])
# If C_i is located at (r, c), then grid[r][c] is empty (ie. grid[r][c] == 0).
for j in range(i, -1, -1): # Return the length of the shortest such clear path from top-left to bottom-right.
arr[next_fill] = arr[j] # If such a path does not exist, return -1.
next_fill -= 1
if arr[j] == 0: # Bidirectional breadth-first search.
arr[next_fill] = arr[j] # Maintain frontiers of valid (within grid), empty cells.
next_fill -= 1 # Expand the smaller frontier by visiting all neighbours.
# Time - O(mn)
# Space - O(mn)

class Solution(object): :rtype: str


def shortestPathBinaryMatrix(self, grid): """
""" m, n = len(str1), len(str2)
:type grid: List[List[int]] lcs = [["" for _ in range(n + 1)] for _ in range(m + 1)]
:rtype: int for i in range(m):
""" for j in range(n):
n = len(grid) if str1[i] == str2[j]:
if grid[0][0] == 1 or grid[n - 1][n - 1] == 1: # front and back frontiers only lcs[i + 1][j + 1] = lcs[i][j] + str1[i]
contain empty cells else:
return -1 lcs[i + 1][j + 1] = max(lcs[i + 1][j], lcs[i][j + 1], key=len)
front, back = {(0, 0)}, {(n - 1, n - 1)}
visited = set() result = []
path = 0 i, j = 0, 0
for c in lcs[-1][-1]:
while front and back: while str1[i] != c:
path += 1 result.append(str1[i])
if front & back: # frontiers intersect i += 1
return path while str2[j] != c:
if len(front) > len(back): result.append(str2[j])
front, back = back, front j += 1
new_front = set() result.append(c) # add the lcs char
i += 1
for r, c in front: j += 1
for dr in (-1, 0, 1):
for dc in (-1, 0, 1): # dr == dc == 0 is visited return "".join(result) + str1[i:] + str2[j:] # add remainders of str and str2
if r + dr < 0 or r + dr >= n:
continue
if c + dc < 0 or c + dc >= n:
continue # python_1001_to_2000/1093_Statistics_from_a_Large_Sample.py - m
if grid[r + dr][c + dc] == 1:
continue _author_ = 'jake'
new_front.add((r + dr, c + dc)) _project_ = 'leetcode'

visited |= front # https://leetcode.com/problems/statistics-from-a-large-sample/


new_front -= visited # We sampled integers between 0 and 255, and stored the results in an array count:
front = new_front # count[k] is the number of integers we sampled equal to k.
# Return the minimum, maximum, mean, median, and mode of the sample respectively, as an
return -1 array of floating point numbers.
# The mode is guaranteed to be unique.
# Recall that the median of a sample is:
# The middle element, if the elements of the sample were sorted and the number of
# python_1001_to_2000/1092_Shortest_Common_Supersequence.py - h elements is odd;
# The average of the middle two elements, if the elements of the sample were sorted and
_author_ = 'jake' the number of elements is even.
_project_ = 'leetcode'
# Iterate along count, updating the count of samples_seen.
# https://leetcode.com/problems/shortest-common-supersequence/ # Find the index or indices of the median element(s).
# Given two strings str1 and str2, return the shortest string that has both str1 and str2 # If 2 median elements, find their sum.
as subsequences. # Time - O(n)
# If multiple answers exist, you may return any of them. # Space - O(1)
# A string S is a subsequence of string T if deleting some number of characters from T
# (possibly 0, and the characters are chosen anywhere from T) results in the string S. class Solution(object):
def sampleStats(self, count):
# Find the longest common supersequence by dynamic programming. """
# For each pair of prefixes str1[:i] and str2 [:j], extend the result for i - 1, j - 1 if :type count: List[int]
end chars are the same. :rtype: List[float]
# Else take the larger result of i - 1, j and i, j - 1. """
# Make the shortest common supersequence by iterating over the LCS. minimum = None
# Add all chars of str1 to the result until we match a char in LCS. Do the same for str2, sample_count = sum(count)
then add the matching char. sum_samples, samples_seen = 0, 0
# Time - O(mn * min(m, n)) since there are O(mn) entries in the lcs matrix and each takes mode, mode_count = 0, 0
min(m, n) to build.
# Space - O(mn) median_sum = 0
median_indices = [sample_count // 2]
class Solution(object): if sample_count % 2 == 0:
def shortestCommonSupersequence(self, str1, str2): median_indices.append(median_indices[-1] - 1)
"""
:type str1: str for num, freq in enumerate(count):
:type str2: str if freq == 0:
continue heapq.heappush(dropoff, (end, pickup))

if minimum is None: return True


minimum = num
maximum = num

samples_seen += freq # python_1001_to_2000/1095_Find_in_Mountain_Array.py - h


sum_samples += freq * num
_author_ = 'jake'
if freq > mode_count: _project_ = 'leetcode'
mode_count = freq
mode = num # https://leetcode.com/problems/find-in-mountain-array/
# You may recall that an array A is a mountain array if and only if:
while median_indices and samples_seen > median_indices[-1]: # A.length >= 3
median_sum += num # There exists some i with 0 < i < A.length - 1 such that:
median_indices.pop() # A[0] < A[1] < ... A[i-1] < A[i]
# A[i] > A[i+1] > ... > A[A.length - 1]
mean = sum_samples / float(sample_count) # Given a mountain array mountainArr, return the minimum index such that
median = median_sum / float(2 if sample_count % 2 == 0 else 1) mountainArr.get(index) == target.
return [minimum, maximum, mean, median, mode] # If such an index doesn't exist, return -1.
# You can't access the mountain array directly. You may only access the array using a
MountainArray interface:
# MountainArray.get(k) returns the element of the array at index k (0-indexed).
# python_1001_to_2000/1094_Car_Pooling.py - m # MountainArray.length() returns the length of the array.
# Submissions making more than 100 calls to MountainArray.get will be judged Wrong
_author_ = 'jake' Answer.
_project_ = 'leetcode' # Also, any solutions that attempt to circumvent the judge will result in
disqualification.
# https://leetcode.com/problems/car-pooling/
# You are driving a vehicle that has capacity empty seats initially available for # Find the peak of the mountain by binary search.
passengers. # Binary search the left side of the peak, and if the target is not found then search the
# The vehicle only drives east (ie. it cannot turn around and drive west.) right side.
# Given a list of trips, trip[i] = [num_passengers, start_location, end_location] # Time - O(log n)
# contains information about the i-th trip: the number of passengers that must be picked # Space - O(1)
up,
# and the locations to pick them up and drop them off. class Solution(object):
# The locations are given as the number of kilometers due east from your vehicle's def findInMountainArray(self, target, mountain_arr):
initial location. """
# Return true if and only if it is possible to pick up and drop off all passengers for :type target: integer
all the given trips. :type mountain_arr: MountainArray
:rtype: integer
# Sort by ascending start location. """
# Iterate over trips, removing from heap all passengers dropped off before the current n = mountain_arr.length()
start location. left, right = 0, n - 1
# Reduce capacity by the picked up passengers and check if car is too full.
# Else add the end location and number of passengers to the dropoff heap. while left < right:
# Time - O(n log n) mid = (left + right) // 2
# Space - O(n) val = mountain_arr.get(mid)
next_val = mountain_arr.get(mid + 1)
import heapq if next_val < val: # slope down
right = mid
class Solution(object): else: # slope up
def carPooling(self, trips, capacity): left = mid + 1
"""
:type trips: List[List[int]] mountain = left
:type capacity: int
:rtype: bool left, right = 0, mountain
""" while left <= right:
trips.sort(key=lambda x: x[1]) mid = (left + right) // 2
dropoff = [] # heap of (location, nb passengers) val = mountain_arr.get(mid)
if val == target:
for pickup, start, end in trips: return mid
while dropoff and dropoff[0][0] <= start: if val > target:
_, dropped = heapq.heappop(dropoff) right = mid - 1
capacity += dropped else:
left = mid + 1
capacity -= pickup
if capacity < 0: left, right = mountain, n - 1
return False while left <= right:

mid = (left + right) // 2 elif c == "}":


val = mountain_arr.get(mid) while stack[-2] == ",": # combine all sets to a single set
if val == target: stack[-3] |= stack[-1]
return mid stack.pop() # remove combined set and comma
if val > target: stack.pop()
left = mid + 1 del stack[-2] # remove the opening bracket
else: else:
right = mid - 1 stack.append(set(c)) # push char in its own set

return -1 while len(stack) > 1 and isinstance(stack[-1], set) and isinstance(stack[-2],


set):
second = stack.pop() # pop sets off in reverse order
first = stack.pop()
# python_1001_to_2000/1096_Brace_Expansion_II.py - m stack.append(set(w1 + w2 for w1 in first for w2 in second))

_author_ = 'jake' return list(sorted(stack[-1]))


_project_ = 'leetcode'

# https://leetcode.com/problems/brace-expansion-ii/
# Under a grammar given below, strings can represent a set of lowercase words. # python_1001_to_2000/1099_Two_Sum_Less_Than_K.py
# Let's use R(expr) to denote the set of words the expression represents.
# Grammar can best be understood through simple examples: _author_ = 'jake'
# Single letters represent a singleton set containing that word. _project_ = 'leetcode'
# R("a") = {"a"}
# R("w") = {"w"} # https://leetcode.com/problems/two-sum-less-than-k/
# When we take a comma delimited list of 2 or more expressions, we take the union of # Given an array A of integers and integer K,
possibilities. # return the maximum S such that there exists i < j with A[i] + A[j] = S and S < K.
# R("{a,b,c}") = {"a","b","c"} # If no i, j exist satisfying this equation, return -1.
# R("{{a,b},{b,c}}") = {"a","b","c"} (notice the final set only contains each word at
most once) # Sort and start 2 pointers at both ends of A.
# When we concatenate two expressions, we take the set of possible concatenations between # If the sum of values at the pointers is less than K, update the best result and
two words increment the left pointer so the
# where the first word comes from the first expression and the second word comes from the # sum of values increases.
second expression. # If the sum of values at the pointers is greater than or equal to K, decrement the right
# R("{a,b}{c,d}") = {"ac","ad","bc","bd"} pointer so the sum of values
# R("a{b,c}{d,e}f{g,h}") = {"abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", # decreases.
"acefg", "acefh"} # Time - O(n log n)
# Formally, the 3 rules for our grammar: # Space - O(n)
# For every lowercase letter x, we have R(x) = {x}
# For expressions e_1, e_2, ... , e_k with k >= 2, we have R({e_1,e_2,...}) = R(e_1) ∪ class Solution(object):
R(e_2) ∪ ... def twoSumLessThanK(self, A, K):
# 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)}, :type A: List[int]
# where + denotes concatenation, and × denotes the cartesian product. :type K: int
# Given an expression representing a set of words under the given grammar, :rtype: int
# return the sorted list of words that the expression represents. """
result = -1
# Maintain a stack of sets of words, commas and opening braces. A.sort()
# Add opening braces and commas to the stack. Add words in their own set. left, right = 0, len(A) - 1
# When there is a closing brace, combine all comma-separated sets into a single set and while left < right:
pop off opening bracket. if A[left] + A[right] < K:
# When 2 sets are at the top of the stack, remove them and append a new set of all the result = max(result, A[left] + A[right])
concatenations. left += 1
# Time - O(n**2 * 2**n), as per space with additional time to construct each intermediate else:
result. right -= 1
# Space - O(n 2**n), consider pairs e.g.(a,b)(c,d)(e,f) .... leading to an exponential return result
number of results.

class Solution(object):
def braceExpansionII(self, exp): # python_1001_to_2000/1100_Find_K-Length_Substrings_With_No_Repeated_Characters.py - m
"""
:type expression: str _author_ = 'jake'
:rtype: List[str] _project_ = 'leetcode'
"""
stack = [] # https://leetcode.com/problems/find-k-length-substrings-with-no-repeated-characters/
# Given a string S, return the number of substrings of length K with no repeated
for c in exp: characters.
if c == "{" or c == ",":
stack.append(c) # Maintain a sliding window of length K over S.
# Count the instances of all chars in the window. """
# Increment the count for each new char and decrement for chars leaving the window. logs.sort() # sort by ascending time
# Maintain a count of repeated chars, to avoid checking all chars for every iteration. friend = {i: i for i in range(N)} # map person to a friend
# Time - O(n) groups = N
# Space - O(1) for fixed size alphabet.
def leader(i): # find exemplar amongst a group of friends
from collections import defaultdict while friend[i] != i:
i = friend[i]
class Solution(object): return i
def numKLenSubstrNoRepeats(self, S, K):
""" for time, A, B in logs:
:type S: str a, b = leader(A), leader(B)
:type K: int if a != b:
:rtype: int friend[a] = b # join the groups and decrement the group
""" count
if K > 26 or K > len(S): # must have repeats if more than alphabet size groups -= 1
return 0 if groups == 1: # everybody is friends
return time
counts = defaultdict(int)
repeated, result = 0, 0 return -1

for i, c in enumerate(S):
counts[c] += 1
if counts[c] == 2: # new repeated char # python_1001_to_2000/1102_Path_With_Maximum_Minimum_Value.py - m
repeated += 1
if i >= K: _author_ = 'jake'
counts[S[i - K]] -= 1 _project_ = 'leetcode'
if counts[S[i - K]] == 1:
repeated -= 1 # https://leetcode.com/problems/path-with-maximum-minimum-value/
# Given a matrix of integers A with R rows and C columns,
if i >= K - 1: # from i = K - 1 onwards # find the maximum score of a path starting at [0,0] and ending at [R-1,C-1].
result += repeated == 0 # increment result if no repeated # 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.
return result # A path moves some number of times from one visited cell to any neighbouring unvisited
cell in one of
# the 4 cardinal directions (north, east, west, south).

# python_1001_to_2000/1101_The_Earliest_Moment_When_Everyone_Become_Friends.py - m # Maintain heap of (-score, row, column).


# Each cell is popped the heap and visited when it has its largest score.
_author_ = 'jake' # Add all neighbours within the grid bounds to the heap.
_project_ = 'leetcode' # Starting from [R-1, C-1] is faster than starting from [0, 0] because equal score ties
are broken by lower row,
# https://leetcode.com/problems/the-earliest-moment-when-everyone-become-friends/ # which is closer to [0, 0].
# In a social group, there are N people, with unique integer ids from 0 to N-1. # Time - O(mn log mn)
# We have a list of logs, where each logs[i] = [timestamp, id_A, id_B] contains a non- # Space - O(mn)
negative integer timestamp,
# and the ids of two different people. import heapq
# 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. class Solution(object):
# Let's say that person A is acquainted with person B if A is friends with B, def maximumMinimumPath(self, A):
# or A is a friend of someone acquainted with B. """
# Return the earliest time for which every person became acquainted with every other :type A: List[List[int]]
person. :rtype: int
# Return -1 if there is no such earliest time. """
rows, cols = len(A), len(A[0])
# Sort by time. Union-find groups of friends. heap = [(-A[rows - 1][cols - 1], rows - 1, cols - 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 while True:
join the groups. neg_max, r, c = heapq.heappop(heap)
# Keep count of the number of groups. if A[r][c] == - 1: # -1 signifies visited
# Time - O(n**2) continue
# Space - O(n) A[r][c] = -1
if r == c == 0:
class Solution(object): return -neg_max
def earliestAcq(self, logs, N): for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
""" if r + dr < 0 or r + dr >= rows or c + dc < 0 or c + dc >= cols:
:type logs: List[List[int]] continue
:type N: int heapq.heappush(heap, (max(-A[r + dr][c + dc], neg_max), r + dr, c + dc))
:rtype: int

# https://leetcode.com/problems/path-in-zigzag-labelled-binary-tree/
# python_1001_to_2000/1103_Distribute_Candies_to_People.py # In an infinite binary tree where every node has two children, the nodes are labelled in
row order.
_author_ = 'jake' # In the odd numbered rows (ie., the first, third, fifth,...), the labelling is left to
_project_ = 'leetcode' right,
# while in the even numbered rows (second, fourth, sixth,...), the labelling is right to
# https://leetcode.com/problems/distribute-candies-to-people/ left.
# We distribute some number of candies, to a row of n = num_people people in the
following way: # We can mive up the tree to each parent by dividing by 2.
# We then give 1 candy to the first person, 2 candies to the second person, # But because alternate rows are reversed, this will give the correect answer for every
# and so on until we give n candies to the last person. other row.
# Then, we go back to the start of the row, giving n + 1 candies to the first person, # So find the position of the label if the row of the label is reversed and move up the
# n + 2 candies to the second person, and so on until we give 2 * n candies to the last tree alternately using
person. # the original and reversed labels.
# This process repeats (with us giving one more candy each time, and moving to the start # Time - O(log n)
of the row # Space - O(log n)
# after we reach the end) until we run out of candies.
# The last person will receive all of our remaining candies (not necessarily one more class Solution(object):
than the previous gift). def pathInZigZagTree(self, label):
# Return an array (of length num_people and sum candies) that represents the final """
distribution of candies. :type label: int
:rtype: List[int]
# The total number of candies distributed for n people = n * (n + 1) // 2. """
# Invert this to find the number of people served given the candies (ignoring cycle back power_of_2 = 1
to beginning). while power_of_2 <= label:
# The first person gets 1 + (1 + num_people) + (1 + 2 * num_people) + .... where the sum power_of_2 *= 2
of the num_people
# series is a base amount which is the same for every person. a = label
# After adding candies for the completed cycles, add candies until one remain. b = power_of_2 - label - 1 + power_of_2 // 2 # equivalent label in reversed
# Time - O(n) row
# Space - O(n)
result = []
class Solution(object): while a != 1: # until root
def distributeCandies(self, candies, num_people): result.append(a)
""" a //= 2 # up to parents
:type candies: int b //= 2
:type num_people: int a, b = b, a # alternate reversed and not
:rtype: List[int]
""" result.append(1)
people_served = int(((1 + 8 * candies) ** 0.5 - 1) / 2) # people who get return result[::-1] # start from root
their full portion
cycles = people_served // num_people # complete cycles of
num_people
# python_1001_to_2000/1105_Filling_Bookcase_Shelves.py - m
result = [0] * num_people
if cycles != 0: _author_ = 'jake'
base = num_people * (cycles - 1) * cycles // 2 # same for every _project_ = 'leetcode'
person
for i in range(num_people): # https://leetcode.com/problems/filling-bookcase-shelves/
result[i] += base + cycles * (i + 1) # for each cycle, add # We have a sequence of books: the i-th book has thickness books[i][0] and height
index + 1 books[i][1].
# We want to place these books in order onto bookcase shelves that have total width
last_candies = cycles * num_people shelf_width.
candies -= sum(result) # We choose some of the books to place on this shelf (such that the sum of their
for i in range(num_people): # incomplete final thickness is <= shelf_width),
cycle # then build another level of shelf of the bookcase so that the total height of the
if candies <= 0: bookcase has increased by
break # the maximum height of the books we just put down.
result[i] += min(candies, last_candies + i + 1) # We repeat this process until there are no more books to place.
candies -= last_candies + i + 1 # Note again that at each step of the above process,
# the order of the books we place is the same order as the given sequence of books.
return result # 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.
# python_1001_to_2000/1104_Path_In_Zigzag_Labelled_Binary_Tree.py - m # Return the minimum possible height that the total bookshelf can be after placing
shelves in this manner.
_author_ = 'jake'
_project_ = 'leetcode' # Dynamic programming. Find the result for all books up to and including each book.
# For each end book, make a new shelf and repeatedly add books to that shelf until it has stack.append(True)
no remaining width. elif c == "f":
# While the next book to be moved fits on the shelf, decrease the remaining width and stack.append(False)
update the height on the shelf. elif c == ")":
# Update the total height result with the latest shelf + result up to the last book not booleans = set()
moved. while stack[-1] != "(":
booleans.add(stack.pop())
# Time - O(n**2), since we may need to look at all previous books for each book. stack.pop() # discard opening bracket
# Space - O(n) operator = stack.pop()
if operator == "&":
class Solution(object): stack.append(all(booleans))
def minHeightShelves(self, books, shelf_width): elif operator == "|":
""" stack.append(any(booleans))
:type books: List[List[int]] else:
:type shelf_width: int stack.append(not booleans.pop())
:rtype: int elif c != ",":
""" stack.append(c)
results = [0] # no height for no books
return stack[-1]
for i in range(len(books)):
width = shelf_width # last shelf has no books initially
shelf_height = 0
results.append(float("inf")) # python_1001_to_2000/1108_Defanging_an_IP_Address.py
j = i # index of next book to be moved to last shelf
_author_ = 'jake'
while j >= 0 and width >= books[j][0]: _project_ = 'leetcode'
shelf_height = max(shelf_height, books[j][1])
width -= books[j][0] # https://leetcode.com/problems/defanging-an-ip-address/
results[-1] = min(results[-1], shelf_height + results[j]) # Given a valid (IPv4) IP address, return a defanged version of that IP address.
j -= 1 # A defanged IP address replaces every period "." with "[.]".

return results[-1] # String replace.


# Time - O(n)
# Space - O(n)

class Solution(object):
# python_1001_to_2000/1106_Parsing_A_Boolean_Expression.py - h def defangIPaddr(self, address):
"""
_author_ = 'jake' :type address: str
_project_ = 'leetcode' :rtype: str
"""
# https://leetcode.com/problems/parsing-a-boolean-expression/ return address.replace(".", "[.]")
# Return the result of evaluating a given boolean expression, represented as a string.
# An expression can either be:
# "t", evaluating to True;
# "f", evaluating to False; # python_1001_to_2000/1109_Corporate_Flight_Bookings.py - m
# "!(expr)", evaluating to the logical NOT of the inner expression expr;
# "&(expr1,expr2,...)", evaluating to the logical AND of 2 or more inner expressions _author_ = 'jake'
expr1, expr2, ...; _project_ = 'leetcode'
# "|(expr1,expr2,...)", evaluating to the logical OR of 2 or more inner expressions
expr1, expr2, ... # https://leetcode.com/problems/corporate-flight-bookings/
# There are n flights, and they are labeled from 1 to n.
# Iterate over the expression. # We have a list of flight bookings.
# Add opening braces, booleans and operators to the stack, ignore commas. # A booking [i, j, k] means that we booked k seats from flights labeled i to j inclusive.
# For closing braces, pop all booleans off and add to a set. # Return an array answer of length n, representing the number of seats booked on each
# Apply the operator to the set and push the result back onto the stack. flight in order of their label.
# Time - O(n)
# Space - O(n) # Create the result with the changes of seats,
# i.e. increment result[start - 1] by seats and decrement result[end] by seats.
class Solution(object): # Then update the result by iterating and summing the cumulative changes.
def parseBoolExpr(self, expression): # Time - O(m + n), number of bookings + number of flights
""" # Space - O(n)
:type expression: str
:rtype: bool class Solution(object):
""" def corpFlightBookings(self, bookings, n):
stack = [] """
:type bookings: List[List[int]]
for c in expression: :type n: int
if c == "t": :rtype: List[int]

""" # It can be written as (A), where A is a VPS.


result = [0] * (n + 1) # We can similarly define the nesting depth depth(S) of any VPS S as follows:
for start, end, seats in bookings: # depth("") = 0
result[start - 1] += seats # depth(A + B) = max(depth(A), depth(B)), where A and B are VPS's
result[end] -= seats # depth("(" + A + ")") = 1 + depth(A), where A is a VPS.
# For example, "", "()()", and "()(()())" are VPS's (with nesting depths 0, 1, and 2),
seats = 0 # and ")(" and "(()" are not VPS's.
for i, change in enumerate(result): # Given a VPS seq, split it into two disjoint subsequences A and B,
seats += change # such that A and B are VPS's (and A.length + B.length = seq.length).
result[i] = seats # Now choose any such A and B such that max(depth(A), depth(B)) is the minimum possible
value.
return result[:-1] # remove any change after final flight # 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.
# Note that even though multiple answers may exist, you may return any of them.

# python_1001_to_2000/1110_Delete_Nodes_And_Return_Forest.py - m # Track the nesting depth.


# Iterate over seq. A closing bracket causes the depth to decrease, an opening bracket
_author_ = 'jake' increases depth.
_project_ = 'leetcode' # When depth is even, the bracket is part of sunbsequence A (result is 0), else part of B
(result is 1).
# https://leetcode.com/problems/delete-nodes-and-return-forest/ # Update result after processing closing brackets and before processing opening brackets.
# Given the root of a binary tree, each node in the tree has a distinct value. # Time - O(n)
# After deleting all nodes with a value in to_delete, we are left with a forest (a # Space - O(1)
disjoint union of trees).
# Return the roots of the trees in the remaining forest. You may return the result in class Solution(object):
any order. def maxDepthAfterSplit(self, seq):
"""
# Recursive helper function returns a node if it is not deleted, else None. :type seq: str
# If a node has no parent and is not deleted, add it to the result list. :rtype: List[int]
# Set the left and right subtrees by recursion. """
result = []
# Time - O(n) depth = 0
# Space - O(n)
for c in seq:
class Solution(object): if c == ")": # decrement before c
def delNodes(self, root, to_delete): depth -= 1
""" result.append(depth % 2)
:type root: TreeNode if c == "(": # increment after c
:type to_delete: List[int] depth += 1
:rtype: List[TreeNode]
""" return result
to_delete = set(to_delete) # convert to set for O(1) lookup
result = []

def helper(node, has_parent): # python_1001_to_2000/1118_Number_of_Days_in_a_Month.py


if not node:
return None _author_ = 'jake'
delete = node.val in to_delete _project_ = 'leetcode'
if not has_parent and not delete:
result.append(node) # https://leetcode.com/problems/number-of-days-in-a-month/
node.left = helper(node.left, not delete) # Given a year Y and a month M, return how many days there are in that month.
node.right = helper(node.right, not delete)
return None if delete else node # 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.
helper(root, False) # Time - O(1)
return result # Space - O(1)

class Solution(object):
def numberOfDays(self, Y, M):
# python_1001_to_2000/1111_Maximum_Nesting_Depth_of_Two_Valid_Parentheses_Strings.py - m """
:type Y: int
_author_ = 'jake' :type M: int
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/maximum-nesting-depth-of-two-valid-parentheses-strings/ if M == 2: # February
# A string is a valid parentheses string (denoted VPS) if and only if it consists of "(" if Y % 4 != 0: # not a leap year if not divisible by 4
and ")" characters only, and: return 28
# It is the empty string, or if Y % 400 == 0: # leap year if divisible by 400
# It can be written as AB (A concatenated with B), where A and B are VPS's, or return 29
if Y % 100 == 0: # not a leap year if not divisible by 100 but not
400, e.g. 1900 helper(root)
return 28 return self.result
return 29

if M in [4, 6, 9, 11]: # not February


return 30 # python_1001_to_2000/1121_Divide_Array_Into_Increasing_Sequences.py - h
return 31
_author_ = 'jake'
_project_ = 'leetcode'

# python_1001_to_2000/1119_Remove_Vowels_from_a_String.py # https://leetcode.com/problems/divide-array-into-increasing-sequences/
# Given a non-decreasing array of positive integers nums and an integer K,
_author_ = 'jake' # find out if this array can be divided into one or more disjoint increasing subsequences
_project_ = 'leetcode' of length at least K.

# https://leetcode.com/problems/remove-vowels-from-a-string/ # There are at most n // K subsequences for an array of length n.


# Given a string S, remove the vowels 'a', 'e', 'i', 'o', and 'u' from it, and return the # If any element occurs more frequently than the most number of subsequences then we
new string. cannot make that many increasing
# subsequences, because the element must be duplicated in at least one subsequence.
# Create a set of vowels and return the join of all chars of S that are not in the set. # Else we can always take elements to make increasing subsequences.
# Time - O(n) # Time - O(n)
# Space - O(n) # Space - O(n)

class Solution(object): from collections import Counter


def removeVowels(self, S):
""" class Solution(object):
:type S: str def canDivideIntoSubsequences(self, nums, K):
:rtype: str """
""" :type nums: List[int]
vowels = set("aeiou") :type K: int
return "".join(c for c in S if c not in vowels) :rtype: bool
"""
return max(Counter(nums).values()) <= len(nums) // K

# python_1001_to_2000/1120_Maximum_Average_Subtree.py - m

_author_ = 'jake' # python_1001_to_2000/1122_Relative_Sort_Array.py


_project_ = 'leetcode'
_author_ = 'jake'
# https://leetcode.com/problems/maximum-average-subtree/ _project_ = 'leetcode'
# Share
# Given the root of a binary tree, find the maximum average value of any subtree of that # https://leetcode.com/problems/relative-sort-array/
tree. # Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all elements in
# A subtree of a tree is any node of that tree plus all its descendants. arr2 are also in arr1.
# The average value of a tree is the sum of its values, divided by the number of nodes. # Sort the elements of arr1 such that the relative ordering of items in arr1 are the same
as in arr2.
# Helper function returns the count of nodes and their sum for subtree. # Elements that don't appear in arr2 should be placed at the end of arr1 in ascending
# Recurse left and right, updating the result from the subtree results. order.
# Time - O(n)
# Space - O(n) # Count each element of arr1.
# Iterate over arr2. If an element is in arr1 then add all instances from r1 to the
class Solution(object): result and delete from the count.
def maximumAverageSubtree(self, root): # Sort all remaining elements from arr1 that not in arr2 and all their instances to the
""" result in sorted order.
:type root: TreeNode # Time - O(m)
:rtype: float # Space - O(m log m + n)
"""
self.result = 0 from collections import Counter

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


if not node: def relativeSortArray(self, arr1, arr2):
return 0, 0 """
left_nodes, left_sum = helper(node.left) :type arr1: List[int]
right_nodes, right_sum = helper(node.right) :type arr2: List[int]
total_nodes = 1 + left_nodes + right_nodes :rtype: List[int]
total_sum = node.val + left_sum + right_sum """
self.result = max(self.result, total_sum / float(total_nodes)) arr1_counts = Counter(arr1)
return total_nodes, total_sum result = []

# than the number of non-tiring days.


for val in arr2: # Return the length of the longest well-performing interval.
if val in arr1_counts:
result += [val] * arr1_counts[val] # Iterate over hours, updating the net balance of tiring days.
del arr1_counts[val] # If the net balance is positive, the array so far is the longest well-performing
interval.
for val in sorted(arr1_counts.keys()): # If there is a prefix array such that an intermediate array has a net balance of 1
result += [val] * arr1_counts[val] tiring day, then update the result
# if this is an improvement.
return result # Update the mapping from index to the first occurrence of a net tiring balance.
# Time - O(n)
# Space - O(n)

# python_1001_to_2000/1123_Lowest_Common_Ancestor_of_Deepest_Leaves.py - m class Solution(object):


def longestWPI(self, hours):
_author_ = 'jake' """
_project_ = 'leetcode' :type hours: List[int]
:rtype: int
# https://leetcode.com/problems/lowest-common-ancestor-of-deepest-leaves/ """
# Given a rooted binary tree, return the lowest common ancestor of its deepest leaves. TIRING = 8
# Recall that:
# The node of a binary tree is a leaf if and only if it has no children result = 0
# The depth of the root of the tree is 0, and if the depth of a node is d, the depth of net_tiring = 0 # balance of tiring - non-tiring days
each of its children is d+1. first_net_tiring = {} # map the first occurrence of each net_tiring to its
# The lowest common ancestor of a set S of nodes is the node A with the largest depth, index in hours
# such that every node in S is in the subtree with root A.
for i, day in enumerate(hours):
# Helper function returns lca of deepest leaves and deepest leaf depth. net_tiring += 1 if day > TIRING else -1
# Recurse to left and right subtrees. if net_tiring > 0: # hours[:i + 1] is well-performing, must be best result
# If depths are equal, current node is the lowest common ancestor. result = i + 1
# Else return the lca with the deepest depth and increment the depth.
# Time - O(n) if net_tiring - 1 in first_net_tiring: # removing some prefix of hours
# Space - O(n) leaves a net_tiring of 1
result = max(result, i - first_net_tiring[net_tiring - 1])
class Solution(object):
def lcaDeepestLeaves(self, root): if net_tiring not in first_net_tiring:
""" first_net_tiring[net_tiring] = i
:type root: TreeNode
:rtype: TreeNode return result
"""
def helper(node):
if not node:
return None, 0 # python_1001_to_2000/1125_Smallest_Sufficient_Team.py - h

left_lca, left_depth = helper(node.left) _author_ = 'jake'


right_lca, right_depth = helper(node.right) _project_ = 'leetcode'
if left_depth == right_depth:
return node, left_depth + 1 # https://leetcode.com/problems/smallest-sufficient-team/
# In a project, you have a list of required skills req_skills, and a list of people.
if left_depth > right_depth: # The i-th person people[i] contains a list of skills that person has.
return left_lca, left_depth + 1 # Consider a sufficient team: a set of people such that for every required skill in
return right_lca, right_depth + 1 req_skills,
# there is at least one person in the team who has that skill.
result, _ = helper(root) # We can represent these teams by the index of each person:
return result # for example, team = [0, 1, 3] represents the people with skills people[0], people[1],
and people[3].
# Return any sufficient team of the smallest possible size, represented by the index of
each person.
# python_1001_to_2000/1124_Longest_Well-Performing_Interval.py - m # You may return the answer in any order. It is guaranteed an answer exists.

_author_ = 'jake' # Represent the skills of each person as an int, with a bit set for each required skill.
_project_ = 'leetcode' # For each required skill, if we already have that skill then move to the next skill.
# Else for each person who has that skill, add their skill to the current skills and
# https://leetcode.com/problems/longest-well-performing-interval/ recurse for the next skill.
# We are given hours, a list of the number of hours worked per day for a given employee. # When returning form recursion, reset the team and current skills.
# A day is considered to be a tiring day if and only if the number of hours worked is # Time - O(m ** n) for m people and n required skills.
(strictly) greater than 8. # Space - O(m ** n)
# A well-performing interval is an interval of days for which the number of tiring days
is strictly larger class Solution(object):
def smallestSufficientTeam(self, req_skills, people): :rtype: int
""" """
:type req_skills: List[str] seen = defaultdict(int) # map canonical dominoe to its count
:type people: List[List[str]] result = 0
:rtype: List[int]
""" for domino in dominoes:
skill_to_int = {skill: i for i, skill in enumerate(req_skills)} if domino[0] > domino[1]: # put greatest first
people_skills = [0] * len(people) # skills per person represented as an int domino = domino[::-1]
for i, person in enumerate(people):
for skill in person: domino_tuple = tuple(domino)
people_skills[i] |= 1 << skill_to_int[skill] result += seen[domino_tuple] # add pairs with all equivalent
seen[domino_tuple] += 1
self.has_skills = 0 # current skills, represented as an int
self.smallest_team = list(range(len(req_skills) + 1)) return result
team = [] # current team

def helper(next_skill):
if len(team) >= len(self.smallest_team): # early return is cannot improve # python_1001_to_2000/1129_Shortest_Path_with_Alternating_Colors.py - m
on result
return _author_ = 'jake'
if next_skill == len(req_skills): _project_ = 'leetcode'
self.smallest_team = team[:]
return # https://leetcode.com/problems/shortest-path-with-alternating-colors/
# Consider a directed graph, with nodes labelled 0, 1, ..., n-1.
if self.has_skills & (1 << next_skill): # In this graph, each edge is either red or blue, and there could be self-edges or
helper(next_skill + 1) parallel edges.
else: # Each [i, j] in red_edges denotes a red directed edge from node i to node j.
for i, person_skills in enumerate(people_skills): # Similarly, each [i, j] in blue_edges denotes a blue directed edge from node i to node
if person_skills & (1 << next_skill): j.
copy_skills = self.has_skills # save so can be reset after # Return an array answer of length n, where each answer[X] is the length of the shortest
recursion path from node 0 to node X
self.has_skills |= person_skills # such that the edge colors alternate along the path (or -1 if such a path doesn't
team.append(i) exist).
helper(next_skill + 1)
team.pop() # revert team and skills before # Breadth-first search the graph of (node, next colour).
next person # Expand all neighbours of frontier, ignoring (node, colour) seen before.
self.has_skills = copy_skills # Update result on first instance of visiting a node.
# Time - O(m + n)
helper(0) # Space - O(m + n)
return self.smallest_team
from collections import defaultdict

class Solution(object):
# python_1001_to_2000/1128_Number_of_Equivalent_Domino_Pairs.py def shortestAlternatingPaths(self, n, red_edges, blue_edges):
"""
_author_ = 'jake' :type n: int
_project_ = 'leetcode' :type red_edges: List[List[int]]
:type blue_edges: List[List[int]]
# https://leetcode.com/problems/number-of-equivalent-domino-pairs/ :rtype: List[int]
# Given a list of dominoes, dominoes[i] = [a, b] is equivalent to dominoes[j] = [c, d] if """
and only if red, blue = defaultdict(list), defaultdict(list) # convert edges to maps from
# either (a==c and b==d), or (a==d and b==c) - that is, one domino can be rotated to be node to neighbours
equal to another domino. for start, end in red_edges:
# Return the number of pairs (i, j) for which 0 <= i < j < dominoes.length, red[start].append(end)
# and dominoes[i] is equivalent to dominoes[j]. for start, end in blue_edges:
blue[start].append(end)
# Dictionary counts previously seen dominoes.
# Iterate over dominoes, rotating each so the greatest number is first. result = [-1] * n # default to -1
# Convert to tuple so they can be added to dictionary. frontier = [(0, True), (0, False)] # list of (node, is_red) to explore
# Add to the result all pairs formed with equivalent dominoes. steps = 0
# Time - O(n) visited = set()
# Space - O(1)
while frontier:
from collections import defaultdict new_frontier = []
for node, is_red in frontier:
class Solution(object): if (node, is_red) in visited: # visited this node, colour combination
def numEquivDominoPairs(self, dominoes): already
""" continue
:type dominoes: List[List[int]] visited.add((node, is_red))

if result[node] == -1: # first visit to this node # https://leetcode.com/problems/maximum-of-absolute-value-expression/


result[node] = steps # Given two arrays of integers with equal lengths, return the maximum value of:
# |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
nbors = red[node] if is_red else blue[node] # where the maximum is taken over all 0 <= i, j < arr1.length.
new_frontier += [(nbor, not is_red) for nbor in nbors]
# Each of arr1[i], arr2[i] and i can be positive or negative.
frontier = new_frontier # So there are 2**3 == 8 ways to combine those three values.
steps += 1 # Some combinations are the negative of other, so there are actually 4 ways ignoring
sign.
return result # Calculate the 4 ways, then return the maximum of the greatest range of each way.
# Time - O(n)
# Space - O(n)

# python_1001_to_2000/1130_Minimum_Cost_Tree_From_Leaf_Values.py - m class Solution(object):


def maxAbsValExpr(self, arr1, arr2):
_author_ = 'jake' """
_project_ = 'leetcode' :type arr1: List[int]
:type arr2: List[int]
# https://leetcode.com/problems/minimum-cost-tree-from-leaf-values/ :rtype: int
# Given an array arr of positive integers, consider all binary trees such that: """
# Each node has either 0 or 2 children; temp1, temp2, temp3, temp4 = [], [], [], []
# The values of arr correspond to the values of each leaf in an in-order traversal of the for i, (a1, a2) in enumerate(zip(arr1, arr2)):
tree. temp1.append(a1 + a2 + i)
# Recall that a node is a leaf if and only if it has 0 children. temp2.append(a1 + a2 - i)
# The value of each non-leaf node is equal to the product of the largest leaf value in temp3.append(a1 - a2 + i)
its left and temp4.append(a1 - a2 - i)
# right subtree respectively.
# Among all possible binary trees considered, return the smallest possible sum of the return max(max(temp) - min(temp) for temp in [temp1, temp2, temp3, temp4])
values of each non-leaf node.
# It is guaranteed this sum fits into a 32-bit integer.

# Maintain a stack of leaves in descending order. Iterate over the list of leaves. # python_1001_to_2000/1133_Largest_Unique_Number.py
# While the top of the stack is less than or equal to a leaf, the top of the stack is the
smallest leaf. _author_ = 'jake'
# Pop off the top of the stack and add to the result the top of stack multiplied by its _project_ = 'leetcode'
smallest neighbour,
# (combining the smallest with another leaf). The smallest is no longer used. Add the # https://leetcode.com/problems/largest-unique-number/
current leaf to the stack. # Given an array of integers A, return the largest integer that only occurs once.
# After iterting over leaves, add to the result the product of each remaining pair. # If no integer occurs once, return -1.
# Time - O(n)
# Space - O(n) # Count the frequency of each number and return the maximum of numbers with a count of 1.
# Time - O(n)
class Solution(object): # Space - O(n)
def mctFromLeafValues(self, arr):
""" from collections import Counter
:type arr: List[int]
:rtype: int class Solution(object):
""" def largestUniqueNumber(self, A):
result = 0 """
stack = [float('inf')] # nodes by descending value :type A: List[int]
:rtype: int
for a in arr: """
while stack[-1] <= a: freq = Counter(A)
smallest = stack.pop() unique = [key for key, val in freq.items() if val == 1]
result += smallest * min(stack[-1], a) if not unique: # no number has a count of 1
stack.append(a) return -1
return max(unique)
while len(stack) > 2: # until root and sentinel
result += stack.pop() * stack[-1]

return result # python_1001_to_2000/1134_Armstrong_Number.py

_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1131_Maximum_of_Absolute_Value_Expression.py - m
# https://leetcode.com/problems/armstrong-number/
_author_ = 'jake' # The k-digit number N is an Armstrong number if and only if the k-th power of each digit
_project_ = 'leetcode' sums to N.
# Given a positive integer N, return true if and only if it is an Armstrong number.
if not connections:
# Remove digits by dividing by 10. Add each digit ** length to the result. return -1
# Compare result to original number.
# Time - O(log n) cost, nbor = heapq.heappop(connections) # cheapest cost
# Space - O(log n) if nbor in connected:
continue
class Solution(object): connected.add(nbor)
def isArmstrong(self, N): result += cost
""" for edge in edges[nbor]:
:type N: int if edge[1] not in connected: # only add if not already connected
:rtype: bool heapq.heappush(connections, edge)
"""
digits = len(str(N)) return result
result, n = 0, N

while n > 0:
n, digit = divmod(n, 10) # python_1001_to_2000/1136_Parallel_Courses.py - m
result += digit ** digits
_author_ = 'jake'
return result == N _project_ = 'leetcode'

# https://leetcode.com/problems/parallel-courses/
# There are N courses, labelled from 1 to N.
# python_1001_to_2000/1135_Connecting_Cities_With_Minimum_Cost.py - m # We are given relations[i] = [X, Y], representing a prerequisite relationship between
course X and course Y:
_author_ = 'jake' # course X has to be studied before course Y.
_project_ = 'leetcode' # In one semester you can study any number of courses as long as you have studied all the
prerequisites
# https://leetcode.com/problems/connecting-cities-with-minimum-cost/ # for the course you are studying.
# There are N cities numbered from 1 to N. # Return the minimum number of semesters needed to study all courses.
# You are given connections, where each connections[i] = [city1, city2, cost] # If there is no way to study all the courses, return -1.
# represents the cost to connect city1 and city2 together.
# A connection is bidirectional: connecting city1 and city2 is the same as connecting # Map each course to the list of next courses, and to a count of its prerequisites.
city2 and city1. # Repeatedly take all courses with no prerequisites and decreases the prerequisite counts
# Return the minimum cost so that for every pair of cities, there exists a path of of all courses that they
connections (possibly of length 1) # are prerequisites for. Update the courses that now have all their prerequisites taken.
# that connects those two cities together. # Time - O(m + n)
# The cost is the sum of the connection costs used. If the task is impossible, return -1. # Space - O(m + n)

# Convert connections to map from a city to a list of neighbours connected by an edge. from collections import defaultdict
# Start from any city, city 1 is chosen arbitrarily.
# Add all edges from the starting city to the heap in the form (cost, neighbour). class Solution(object):
# Repeatedly pop off the neighbour with the lowest cost. def minimumSemesters(self, N, relations):
# If neighbour is not already connected, update the total cost and add its unconnected """
neighbours to the heap. :type N: int
# Time - O(n log n) for n connections. :type relations: List[List[int]]
# Space - O(n) :rtype: int
"""
from collections import defaultdict course_to_next = defaultdict(list) # map course to list of next courses
import heapq prerequisite_count = defaultdict(int) # map course to count of prerequisites
for pre, post in relations:
class Solution(object): course_to_next[pre].append(post)
def minimumCost(self, N, connections): prerequisite_count[post] += 1
"""
:type N: int # initilaize list of courses with no prerequisites
:type connections: List[List[int]] no_preresquisites = [course for course in range(1, N + 1) if
:rtype: int prerequisite_count[course] == 0]
""" taken, semesters = 0, 0 # counts of courses take and semesters
edges = defaultdict(list)
for a, b, cost in connections: while no_preresquisites: # some course has no prerequisites
edges[a].append((cost, b)) new_no_preresquisites = []
edges[b].append((cost, a)) for course in no_preresquisites:
for next_course in course_to_next[course]:
connected = {1} # set of connected cities prerequisite_count[next_course] -= 1 # take course, so decrease
connections = list(edges[1]) # unexplored edges from connected cities prerequisites of next
heapq.heapify(connections) if prerequisite_count[next_course] == 0:
result = 0 new_no_preresquisites.append(next_course)

while len(connected) < N: semesters += 1

taken += len(no_preresquisites) class Solution(object):


if taken == N: def alphabetBoardPath(self, target):
return semesters """
no_preresquisites = new_no_preresquisites :type target: str
:rtype: str
return -1 """
def location(char): # return (row, col) of cher on the board.
val = ord(char) - ord("a")
return divmod(val, 5)
# python_1001_to_2000/1137_N-th_Tribonacci_Number.py
result = []
_author_ = 'jake' row, col = 0, 0
_project_ = 'leetcode' for char in target:
r, c = location(char)
# https://leetcode.com/problems/n-th-tribonacci-number/ if c < col:
# The Tribonacci sequence Tn is defined as follows: result += ["L"] * (col - c)
# T0 = 0, T1 = 1, T2 = 1, and Tn+3 = Tn + Tn+1 + Tn+2 for n >= 0. if r < row:
# Given n, return the value of Tn. result += ["U"] * (row - r)
if c > col:
# Repeatedly make the next elements of the sequence from the sum of the last 3 elements. result += ["R"] * (c - col)
# Alternatively, use a queue and retain only 3 elements to resuce space to O(1). if r > row:
# Time - O(n) result += ["D"] * (r - row)
# Space - O(n)
row, col = r, c
class Solution(object): result.append("!")
def tribonacci(self, n):
""" return "".join(result)
:type n: int
:rtype: int
"""
nums = [0, 1, 1] # python_1001_to_2000/1139_Largest_1-Bordered_Square.py - m
while len(nums) <= n:
nums.append(sum(nums[-3:])) _author_ = 'jake'
_project_ = 'leetcode'
return nums[n]
# 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
# python_1001_to_2000/1138_Alphabet_Board_Path.py - m # on its border, or 0 if such a subgrid doesn't exist in the grid.

_author_ = 'jake' # Iterate along each row, counting the continuous sequence of ones.
_project_ = 'leetcode' # For each side length from the sequence down to the current best side length + 1,
# check if the other 3 edges of the square are all ones.
# https://leetcode.com/problems/alphabet-board-path/ # Return early or continue if the current best cannot be improved.
# On an alphabet board, we start at position (0, 0), corresponding to character board[0] # Time - O(mn * (m + n)) since for each cell of the grid, explore up to side lengths of
[0]. the grid.
# Here, board = ["abcde", # Space - O(1)
# "fghij",
# "klmno", class Solution(object):
# "pqrst", def largest1BorderedSquare(self, grid):
# "uvwxy", """
# "z"]. :type grid: List[List[int]]
# We may make the following moves: :rtype: int
# '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; rows, cols = len(grid), len(grid[0])
# 'L' moves our position left one column, if the position exists on the board; best = 0
# '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. for row in range(rows):
# (Here, the only positions that exist on the board are positions with letters on them.) sequence = 0
# Return a sequence of moves that makes our answer equal to target in the minimum number for col in range(cols):
of moves. if best >= rows - row: # insufficient rows to make a bigger square
# You may return any path that does so. return best * best

# Track the current location and for each char, find the target location. if grid[row][col] == 1:
# Move left and up before right and down so we do not visit any other columns on the last sequence += 1
row. else:
# Time - O(n) sequence = 0
# Space - O(n) if best >= sequence : # insufficient sequence to make a bigger square
continue
# python_1001_to_2000/1143_Longest_Common_Subsequence.py - m
for side in range(min(sequence, rows - row), best, -1): # check
decreasing side from largest possible _author_ = 'jake'
if not all(grid[r][col] and grid[r][col - side + 1] for r in _project_ = 'leetcode'
range(row + 1, row + side)):
continue # left and right edges must be populated # https://leetcode.com/problems/longest-common-subsequence/
if not all(grid[row + side - 1][col - side + 1:col + 1]): # Given two strings text1 and text2, return the length of their longest common
continue # bottom edge must be populated subsequence.
best = side # A subsequence of a string is a new string generated from the original string with some
break # no need to check smaller sides characters (can be none)
# deleted without changing the relative order of the remaining characters.
return best * best # 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.
# If there is no common subsequence, return 0.

# Dynamic programming.
# python_1001_to_2000/1140_Stone_Game_II.py - m # For each prefix of text1, find the lcs with each prefix of text2.
# If the end characters of each prefix are equal, we can extend the lcs of the prefixes
_author_ = 'jake' without the end characters.
_project_ = 'leetcode' # Else we take the longest lcs ignoring the last character from one prefix.
# Time - O(mn)
# https://leetcode.com/problems/stone-game-ii/ # Space - O(n)
# Alex and Lee continue their games with piles of stones.
# There are a number of piles arranged in a row, and each pile has a positive integer class Solution(object):
number of stones piles[i]. def longestCommonSubsequence(self, text1, text2):
# The objective of the game is to end with the most stones. """
# Alex and Lee take turns, with Alex starting first. Initially, M = 1. :type text1: str
# On each player's turn, that player can take all the stones in the first X remaining :type text2: str
piles, :rtype: int
# where 1 <= X <= 2M. Then, we set M = max(M, X). """
# The game continues until all the stones have been taken. m, n = len(text1), len(text2)
# Assuming Alex and Lee play optimally, return the maximum number of stones Alex can get. lcs = [0 for _ in range(n + 1)]

# Convert the array so piles[i] is the sum of all remaining piles. for c1 in text1: # for prefix of text1 up to and including c1
# Recursive helper function calculates the result from pile i for a given value of M. new_lcs = [0]
# Return the best result for each value of x of taking the remaining piles minus the best for j, c2 in enumerate(text2): # for prefix of text2 up to and including c2
case for the next player. if c1 == c2:
# Memoize to avoid repetition. new_lcs.append(1 + lcs[j])
# Time - O(n**3) since there are O(n**2) states, each taking O(n) to compute. else:
# Space - O(n**2) new_lcs.append(max(new_lcs[-1], lcs[j + 1]))
lcs = new_lcs
class Solution(object):
def stoneGameII(self, piles): return lcs[-1]
"""
:type piles: List[int]
:rtype: int
"""
n = len(piles) # python_1001_to_2000/1144_Decrease_Elements_To_Make_Array_Zigzag.py - m
for i in range(n - 2, -1, -1):
piles[i] += piles[i + 1] # convert to cumulative sum from end _author_ = 'jake'
memo = {} _project_ = 'leetcode'

def helper(i, M): # https://leetcode.com/problems/decrease-elements-to-make-array-zigzag/


if i + 2 * M >= n: # take all remaining piles # Given an array nums of integers, a move consists of choosing any element and decreasing
return piles[i] it by 1.
if (i, M) in memo: # An array A is a zigzag array if either:
return memo[(i, M)] # Every even-indexed element is greater than adjacent elements, ie. A[0] > A[1] < A[2] >
A[3] < A[4] > ...
best = 0 # OR, every odd-indexed element is greater than adjacent elements, ie. A[0] < A[1] > A[2]
for x in range(1, 2 * M + 1): # try all valid values of x < A[3] > A[4] < ...
best = max(best, piles[i] - helper(i + x, max(M, x))) # Return the minimum number of moves to transform the given array nums into a zigzag
array.
memo[(i, M)] = best
return best # Iterate over array, calculating the cost of making each element lower than its lowest
neighbour.
return helper(0, 1) # Add the cost to the total cost of even or odd indices.
# Return the minimum total cost.
# Time - O(n)
# Space - O(n)

return 0
class Solution(object):
def movesToMakeZigzag(self, nums): if node.val == x: # count child subtrees
""" self.left = count(node.left)
:type nums: List[int] self.right = count(node.right)
:rtype: int return 0
"""
nums = [float('inf')] + nums + [float('inf')] return 1 + count(node.left) + count(node.right)
even_low, odd_low = 0, 0 # moves to make the even and odd indices low
parent = count(root)
for i in range(1, len(nums) - 1): results = sorted([parent, self.left, self.right])
# decrease nums[i] to 1 less than the lowest neighbour
cost = max(0, nums[i] - min(nums[i - 1], nums[i + 1]) + 1) return results[-1] > sum(results[:2]) + 1
if i % 2 == 0:
even_low += cost
else:
odd_low += cost # python_1001_to_2000/1146_Snapshot_Array.py - m

return min(even_low, odd_low) _author_ = 'jake'


_project_ = 'leetcode'

# https://leetcode.com/problems/snapshot-array/
# python_1001_to_2000/1145_Binary_Tree_Coloring_Game.py - m # Implement a SnapshotArray that supports the following interface:
#
_author_ = 'jake' # SnapshotArray(int length) initializes an array-like data structure with the given
_project_ = 'leetcode' length.
# Initially, each element equals 0.
# https://leetcode.com/problems/binary-tree-coloring-game/ # void set(index, val) sets the element at the given index to be equal to val.
# Two players play a turn based game on a binary tree. # int snap() takes a snapshot of the array and returns the snap_id: the total number of
# We are given the root of this binary tree, and the number of nodes n in the tree. times we called snap() minus 1.
# n is odd, and each node has a distinct value from 1 to n. # int get(index, snap_id) returns the value at the given index, at the time we took the
# Initially, the first player names a value x with 1 <= x <= n, snapshot with the given snap_id
# and the second player names a value y with 1 <= y <= n and y != x.
# The first player colors the node with value x red, and the second player colors the # For each index of the array, store the historical values as [snap_id, value].
node with value y blue. # When setting a value, append a new [snap_id, value] if the value and id has changed.
# Then, the players take turns starting with the first player. # Binary search the history to find a value at a previous snap.
# In each turn, that player chooses any node of their color (red if player 1, blue if # Time - O(n) for __init__ when n is the array length.
player 2) # O(1) for set and snap. O(m) for get for m snap operations.
# and colors an uncolored neighbor of the chosen node (either the left child, right # Space - O(mn)
child, or parent of the node.)
# If (and only if) a player cannot choose such a node in this way, they must pass their import bisect
turn.
# If both players pass their turn, the game ends, and the winner is the player that class SnapshotArray(object):
colored more nodes.
# You are the second player. def __init__(self, length):
# 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 length: int
"""
# Count the nodes from the root excluding those after the red node. self.history = [[[-1, 0]] for _ in range(length)]
# Also count the left and right subtrees of the red node. self.id = 0 # next snap id
# The second player should colour the parent, left child or right child of the red node.
# If the most nodes controlled from any of those locations is greater than the nodes in def set(self, index, val):
the other locations + the """
# initial red node, then the second player can win. :type index: int
# Time - O(n) :type val: int
# Space - O(n) :rtype: None
"""
class Solution(object): if val == self.history[index][-1][1]: # do nothing if value unchanged
def btreeGameWinningMove(self, root, n, x): return
""" if self.history[index][-1][0] == self.id: # update value only if id is
:type root: TreeNode unchanged
:type n: int self.history[index][-1][1] = val
:type x: int return
:rtype: bool
""" self.history[index].append([self.id, val])
self.left, self.right = 0, 0
def snap(self):
def count(node): """
if not node: :rtype: int
""" N.
self.id += 1
return self.id - 1 # Use binary search to find the first instance of target in nums.
# If target is not in nums, return False.
def get(self, index, snap_id): # Check if
""" # Time - O(log n)
:type index: int # Space - O(1)
:type snap_id: int
:rtype: int import bisect
"""
# binary search for inf value to always return the index after the snap_id class Solution(object):
i = bisect.bisect_left(self.history[index], [snap_id, float("inf")]) def isMajorityElement(self, nums, target):
return self.history[index][i - 1][1] """
:type nums: List[int]
:type target: int
:rtype: bool
# python_1001_to_2000/1147_Longest_Chunked_Palindrome_Decomposition.py - m """
n = len(nums)
_author_ = 'jake' i = bisect.bisect_left(nums, target)
_project_ = 'leetcode' if i == n or nums[i] != target:
return False
# https://leetcode.com/problems/longest-chunked-palindrome-decomposition/
# Return the largest possible k such that there exists a_1, a_2, ..., a_k such that: return nums[(i + n // 2) % n] == target
# Each a_i is a non-empty string;
# Their concatenation a_1 + a_2 + ... + a_k is equal to text;
# For all 1 <= i <= k, a_i = a_{k+1 - i}.
# python_1001_to_2000/1151_Minimum_Swaps_to_Group_All_1's_Together.py - m
# Find a prefix of text that matches a suffix, then remove the prefix and the suffix and
repeat. _author_ = 'jake'
# Continue until all the text is used or we are half way through and the middle is not a _project_ = 'leetcode'
palindrome.
# Time - O(n**2) # 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
class Solution(object): together in any place in the array.
def longestDecomposition(self, text):
""" # Count the number of ones.
:type text: str # Iterate along the data with a sliding window of length of the number of ones.
:rtype: int # 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
n = len(text) to group the ones together.
start_prefix = 0 # Time - O(n)
result = 0 # Space - O(1)

while start_prefix <= (n - 1) // 2: # until half of text class Solution(object):


for length in range(1, ((n - 2 * start_prefix) // 2) + 1): def minSwaps(self, data):
prefix = text[start_prefix:start_prefix + length] """
suffix = text[n - start_prefix - length:n - start_prefix] :type data: List[int]
if prefix == suffix: :rtype: int
result += 2 # prefix and suffix are removed """
start_prefix += length # start of next prefix ones = sum(data)
break window_sum = sum(data[:ones]) # initial sliding window
else: # middle of text, not a palindrome result = ones - window_sum # count of ones to move inside window
result += 1
break for i in range(len(data) - ones):
window_sum -= data[i]
return result window_sum += data[i + ones]
result = min(result, ones - window_sum)

return result
# python_1001_to_2000/1150_Check_If_a_Number_Is_Majority_Element_in_a_Sorted_Array.py

_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1152_Analyze_User_Website_Visit_Pattern.py - m

# https://leetcode.com/problems/check-if-a-number-is-majority-element-in-a-sorted-array/ _author_ = 'jake'


# Given an array nums sorted in non-decreasing order, and a number target, _project_ = 'leetcode'
# return True if and only if target is a majority element.
# A majority element is an element that appears more than N/2 times in an array of length # https://leetcode.com/problems/analyze-user-website-visit-pattern/

# We are given some website visits: the user with name username[i] visited the website
website[i] at time timestamp[i]. from collections import defaultdict
# A 3-sequence is a list of websites of length 3 sorted in ascending order by the time of
their visits. class Solution(object):
# The websites in a 3-sequence are not necessarily distinct. def canConvert(self, str1, str2):
# Find the 3-sequence visited by the largest number of users. If there is more than one """
solution, :type str1: str
# return the lexicographically smallest such 3-sequence. :type str2: str
:rtype: bool
# Make a time-ordered list of sites for each user. """
# For each list, find all patterns of 3 ordered sites. if len(set(str2)) == 26 and str1 != str2:
# Map each pattern to all users with that pattern. return False
# Find the pattern with the most users.
# Time - O(n**3) for n visits. char1_indices = defaultdict(list)
# Space - O(n**3) for i, c in enumerate(str1):
char1_indices[c].append(i)
from collections import defaultdict
for c, indices in char1_indices.items():
class Solution(object): if len({str2[i] for i in indices}) != 1:
def mostVisitedPattern(self, username, timestamp, website): return False
"""
:type username: List[str] return True
:type timestamp: List[int]
:type website: List[str]
:rtype: List[str]
""" # python_1001_to_2000/1154_Day_of_the_Year.py
user_sites = defaultdict(list) # user mapped to list of sites in time
order. _author_ = 'jake'
for _, user, site in sorted(zip(timestamp, username, website)): _project_ = 'leetcode'
user_sites[user].append(site)
# https://leetcode.com/problems/day-of-the-year/
pattern_to_count = defaultdict(set) # map 3-sequence to users with that 3- # Given a string date representing a Gregorian calendar date formatted as YYYY-MM-DD,
sequence # return the day number of the year.
for user, sites in user_sites.items():
n = len(sites) # Find the number of day in the whole months completed, assuming not a leap year.
for i in range(n - 2): # Add 29th February if in March or later and a leap year.
for j in range(i + 1, n - 1): # Time - O(n)
for k in range(j + 1, n): # Space - O(n)
pattern_to_count[(sites[i], sites[j], sites[k])].add(user)
class Solution(object):
max_count = len(max(pattern_to_count.values(), key=len)) # count of mos def dayOfYear(self, date):
popular 3-sequence """
return min(key for key, value in pattern_to_count.items() if len(value) == :type date: str
max_count) :rtype: int
"""
cumulative_days = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

# python_1001_to_2000/1153_String_Transforms_Into_Another_String.py - h year, month, day = [int(x) for x in date.split("-")]


result = cumulative_days[month - 1] + day
_author_ = 'jake'
_project_ = 'leetcode' if month >= 3 and year % 4 == 0 and year != 1900: # 1900 was not a leap year
result += 1
# https://leetcode.com/problems/string-transforms-into-another-string/ return result
# Given two strings str1 and str2 of the same length,
# determine whether you can transform str1 into str2 by doing zero or more conversions.
# In one conversion you can convert all occurrences of one character in str1 to any other
lowercase English character. # python_1001_to_2000/1155_Number_of_Dice_Rolls_With_Target_Sum.py - m
# Return true if and only if you can transform str1 into str2.
_author_ = 'jake'
# If the stings are not identical and str2 uses all 26 possible characters, then changing _project_ = 'leetcode'
any character of str1
# would make it the same as some other character in str2, which means we cannot perform # https://leetcode.com/problems/number-of-dice-rolls-with-target-sum/
the transformation. # You have d dice, and each die has f faces numbered 1, 2, ..., f.
# Else find all indices in str1 of each char. Find the chars in str2 at the indices of # Return the number of possible ways (out of f**d total ways) modulo 10^9 + 7
each char in str1. # to roll the dice so the sum of the face up numbers equals target.
# If a char of str1 maps to more than one char of str2,
# then we cannot transform it into those 2 or more different chars. # Dynamic programming.
# Time - O(n) # For each dice roll, each total can be achieved by adding any score s from 1 to f
# Space - O(n) (inclusive)
# to total - s for the previous dice roll. prev_length = substrings[i - 1][1] - substrings[i - 1][0] + 1
# Time - O(mnk) for target of m, n dice with k sides. # move a char from another substring to fill the gap, else move from
# Space - O(mn) for target of m and n dice. the end of one substring
result = max(result, length + prev_length + int(len(substrings) >=
class Solution(object): 3))
def numRollsToTarget(self, d, f, target):
""" return result
:type d: int
:type f: int
:type target: int
:rtype: int # python_1001_to_2000/1157_Online_Majority_Element_In_Subarray.py - h
"""
MOD = 10 ** 9 + 7 _author_ = 'jake'
dp = [[0 for _ in range(target + 1)] for _ in range(d + 1)] _project_ = 'leetcode'
dp[0][0] = 1 # 1 way to make 0 with 0 dice
# https://leetcode.com/problems/online-majority-element-in-subarray/
for die in range(1, d + 1): # Implementing the class MajorityChecker, which has the following API:
for total in range(die, target + 1): # make each possible score # MajorityChecker(int[] arr) constructs an instance of MajorityChecker with the given
dp[die][total] = sum(dp[die - 1][max(total - f, 0):total]) % MOD array arr;
# int query(int left, int right, int threshold) has arguments such that:
return dp[-1][-1] # 0 <= left <= right < arr.length representing a subarray of arr;
# 2 * threshold > right - left + 1, ie. the threshold is always a strict majority of the
length of the subarray
# Each query(...) returns the element in arr[left], arr[left+1], ..., arr[right]
# python_1001_to_2000/1156_Swap_For_Longest_Repeated_Character_Substring.py - m # that occurs at least threshold times, or -1 if no such element exists.

_author_ = 'jake' # Create a map from each val of arr to an ordered list of indices with that val.
_project_ = 'leetcode' # Create a list of unique vals, in descending order of number of occurrences in arr.
# To query, start with the the num with the most indices and binary search for the left
# https://leetcode.com/problems/swap-for-longest-repeated-character-substring/ and right indices.
# Given a string text, we are allowed to swap two of the characters in the string. # Repeat with the next num, until a result or the num has fewer than threshold indices in
# Find the length of the longest substring with repeated characters. arr.
# Time - O(n log n) for __init__ and O(n log n) for query.
# For each char, make a list of the start and end indices of substrings containing only # Space - O(n)
that char.
# For each list of substrings, we can update the result with: from collections import defaultdict
# - the substring length (no swap) if there are no other substrings with this char import bisect
# - the length + 1, if there is another substring
# - the sum of adjacent substrings, if the gap between them is one char class MajorityChecker(object):
# - the sum of adjacent substrings + 1, if the gap between them is one char and there is
at least one other substring def __init__(self, arr):
# Time - O(n) """
# Space - O(n) :type arr: List[int]
"""
from collections import defaultdict self.val_to_indices = defaultdict(list)
for i, val in enumerate(arr):
class Solution(object): self.val_to_indices[val].append(i)
def maxRepOpt1(self, text):
""" self.vals = sorted(self.val_to_indices.keys(), key=lambda x:
:type text: str len(self.val_to_indices[x]), reverse=True)
:rtype: int
""" def query(self, left, right, threshold):
char_substrings = defaultdict(list) # map char to list of [start, end] """
substrings :type left: int
for i, c in enumerate(text): :type right: int
if i == 0 or c != text[i - 1]: :type threshold: int
char_substrings[c].append([i, i]) :rtype: int
else: """
char_substrings[c][-1][1] = i for val in self.vals:
if len(self.val_to_indices[val]) < threshold:
result = 0 break
for substrings in char_substrings.values(): left_i = bisect.bisect_left(self.val_to_indices[val], left)
for i, (start, end) in enumerate(substrings): right_i = bisect.bisect_right(self.val_to_indices[val], right)
length = end - start + 1 if right_i - left_i >= threshold:
# add 1 to length if there is at least one other substring return val
result = max(length + int(len(substrings) >= 2), result)
return -1
if i != 0 and substrings[i - 1][1] == start - 2: # gap of 1 char to
previous substring

if not node:
# python_1001_to_2000/1160_Find_Words_That_Can_Be_Formed_by_Characters.py return

_author_ = 'jake' level_sums[level] += node.val


_project_ = 'leetcode' helper(node.left, level + 1)
helper(node.right, level + 1)
# https://leetcode.com/problems/find-words-that-can-be-formed-by-characters/
# You are given an array of strings words and a string chars. helper(root, 1)
# A string is good if it can be formed by characters from chars (each character can only max_level_sum = max(level_sums.values())
be used once). return min(level for level, level_sum in level_sums.items() if level_sum ==
# Return the sum of lengths of all good strings in words. max_level_sum)

# Count the chars.


# For each char of each word, if there are more instances of that char in the word than
in chars, # python_1001_to_2000/1162_As_Far_from_Land_as_Possible.py - m
# we cannot make the word.
# Time - O(m + n), length of chars + lengths of all words _author_ = 'jake'
# Space - O(m) _project_ = 'leetcode'

from collections import Counter # https://leetcode.com/problems/as-far-from-land-as-possible/


# Given an N x N grid containing only values 0 and 1, where 0 represents water and 1
class Solution(object): represents land,
def countCharacters(self, words, chars): # find a water cell such that its distance to the nearest land cell is maximized and
""" return the distance.
:type words: List[str] # The distance used in this problem is the Manhattan distance:
:type chars: str # the distance between two cells (x0, y0) and (x1, y1) is |x0 - x1| + |y0 - y1|.
:rtype: int # If no land or water exists in the grid, return -1.
"""
chars_count = Counter(chars) # Breadth-first search.
result = 0 # Maintain a count of frontier cells to explore, initially all the land cells.
# Maintain a count of cells reached, initially all the land cells.
for word in words: # For each cell of the frontier, add all neighbours to visited count and to new frontier.
for c in set(word): # each unique char in word Set value to 1 to avoid
if word.count(c) > chars_count[c]: # repeated visits to the same cell.
break # Stop when the whole grid has been counted.
else: # Time - O(mn)
result += len(word) # Space - O(mn)

return result class Solution(object):


def maxDistance(self, grid):
"""
:type grid: List[List[int]]
# python_1001_to_2000/1161_Maximum_Level_Sum_of_a_Binary_Tree.py - m :rtype: int
"""
_author_ = 'jake' rows, cols = len(grid), len(grid[0])
_project_ = 'leetcode' visited = 0
frontier = {(r, c) for r in range(rows) for c in range(cols) if grid[r][c] == 1}
# 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 visited += len(frontier)
is 2, and so on. if not frontier or visited == rows * cols: # all water or all land
# Return the smallest level X such that the sum of all the values of nodes at level X is return -1
maximal.
neighbours = [(1, 0), (-1, 0), (0, 1), (0, -1)]
# Traverse the tree with depth-first search, updating the sum of values at each level. distance = 0
# Find the greatest sum of levels, then return the lowest level with that sum.
# Time - O(n) while visited < rows * cols: # until all grid visited
# Space - O(n) new_frontier = set()

from collections import defaultdict for r, c in frontier:


for dr, dc in neighbours:
class Solution(object): if r + dr < 0 or r + dr >= rows:
def maxLevelSum(self, root): continue
""" if c + dc < 0 or c + dc >= cols:
:type root: TreeNode continue
:rtype: int if grid[r + dr][c + dc] == 0:
""" visited += 1
level_sums = defaultdict(int) # map level to sum of node values grid[r + dr][c + dc] = 1
new_frontier.add((r + dr, c + dc))
def helper(node, level):
frontier = new_frontier # You want to type a string word. Write a function to calculate how much time it takes to
distance += 1 type it with one finger.

return distance # Map each char of keyboard to its index.


# For each char of word, find the distance from the current index to that char.
# The update the total distance moved and index.
# Time - O(n)
# python_1001_to_2000/1163_Last_Substring_in_Lexicographical_Order.py - h # Space - O(1)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def calculateTime(self, keyboard, word):
"""
# https://leetcode.com/problems/last-substring-in-lexicographical-order/ :type keyboard: str
# Given a string s, return the last substring of s in lexicographical order. :type word: str
:rtype: int
# Find all indices in s of the greatest char (lexicographically last). """
# These are the stating indices of candidate substrings. char_to_index = {c : i for i, c in enumerate(keyboard)}
# While there is more than one candidate, find the next char and index of each candidate
substring. result, index = 0, 0
# Form the next chars, retain on the substrings with the greatest char. for c in word:
# If the end of one candidate runs into the start of another candidate, reject the next_index = char_to_index[c]
shorter candidate. result += abs(next_index - index)
# Return the substring from the last remaining candidate to the end of s. index = next_index
# Time - O(n)
# Space - O(n) return result

from collections import defaultdict

class Solution(object): # python_1001_to_2000/1166_Design_File_System.py - m


def lastSubstring(self, s):
""" _author_ = 'jake'
:type s: str _project_ = 'leetcode'
:rtype: str
""" # https://leetcode.com/problems/design-file-system/
n = len(s) # You are asked to design a file system which provides two functions:
max_char = max(s) # createPath(path, value): Creates a new path and associates a value to it if possible
candidates = {i for i in range(n) if s[i] == max_char} # indices of max_char and returns True.
length = 0 # 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
while len(candidates) > 1: exist.
char_indices = defaultdict(set) # The format of a path is one or more concatenated strings of the form:
for i in candidates: # / followed by one or more lowercase English letters.
if i == n - 1: # For example, /leetcode and /leetcode/problems are valid paths while an empty string and
continue / are not.
if i - length - 1 in candidates: # another candidate runs into this # Implement the two functions.
candidate
continue # Build a tree of folders in the file system.
char_indices[s[i + 1]].add(i + 1) # Each node of the tree has a value and a map to child folders.
# To createPath, break the path into a list of folders and find the node of the
candidates = char_indices[max(char_indices.keys())] penultimate folder. If the path is
length += 1 # valid, insert the value in a new child node.
# To get, follow the folders down the tree, returning the final value if the path is
return s[candidates.pop() - length:] # suffix of s valid.
# Time - O(n) for createPath and get where n is the number of previous createPath.
# Space - O(n)

# python_1001_to_2000/1165_Single-Row_Keyboard.py class Node(object):


def __init__(self, value):
_author_ = 'jake' self.children = {}
_project_ = 'leetcode' self.value = value

# https://leetcode.com/problems/single-row-keyboard/ class FileSystem(object):


# There is a special keyboard with all keys in a single row.
# Given a string keyboard of length 26 indicating the layout of the keyboard (indexed def __init__(self):
from 0 to 25), self.root = Node(None)
# initially your finger is at index 0.
# To type a character, you have to move your finger to the index of the desired # helper function, returns the last node from a path of folders or None
character. def traverse(self, folders):
# The time taken to move your finger from index i to index j is |i - j|. node = self.root

for folder in folders[1:]:


if folder not in node.children:
return None # python_1001_to_2000/1168_Optimize_Water_Distribution_in_a_Village.py - h
node = node.children[folder]
return node _author_ = 'jake'
_project_ = 'leetcode'
def createPath(self, path, value):
""" # https://leetcode.com/problems/optimize-water-distribution-in-a-village/
:type path: str # There are n houses in a village. We want to supply water for all the houses by building
:type value: int wells and laying pipes.
:rtype: bool # For each house i, we can either build a well inside it directly with cost wells[i],
""" # or pipe in water from another well to it.
folders = path.split("/") # The costs to lay pipes between houses are given by the array pipes,
node = self.traverse(folders[:-1]) # find the node of parent of last # where each pipes[i] = [house1, house2, cost] represents the cost to connect house1 and
folder house2 together using a pipe.
if node is None or folders[-1] in node.children: # Connections are bidirectional.
return False # Find the minimum total cost to supply water to all houses.
node.children[folders[-1]] = Node(value) # insert the value
return True # Maintain a heap of accessible sources of water, by (cost, house).
# Initial heap consists of all wells. Repeatedly use the least cost from the heap to
def get(self, path): connect an unconnected house.
""" # Add all pipes to neighbours to the heap. Repeat until all houses are connected.
:type path: str # Time - O(m log(m + n)) for m pipes and n wells, since each pipe is added to heap of all
:rtype: int pipes and wells.
""" # Space - O(m + n)
node = self.traverse(path.split("/"))
if not node: from collections import defaultdict
return -1 import heapq
return node.value
class Solution(object):
def minCostToSupplyWater(self, n, wells, pipes):
"""
# python_1001_to_2000/1167_Minimum_Cost_to_Connect_Sticks.py - m :type n: int
:type wells: List[int]
_author_ = 'jake' :type pipes: List[List[int]]
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/minimum-cost-to-connect-sticks/ neighbours = defaultdict(list) # map each house to list of
# You have some sticks with positive integer lengths. connected (nbor, cost)
# You can connect any two sticks of lengths X and Y into one stick by paying a cost of X for house1, house2, cost in pipes:
+ Y. neighbours[house1].append((house2, cost))
# You perform this action until there is one stick remaining. neighbours[house2].append((house1, cost))
# Return the minimum cost of connecting all the given sticks into one stick in this way.
heap = [(cost, i + 1) for i, cost in enumerate(wells)] # each house can be
# Since the cost is proportional to the lengths of sticks connected, we want to connect connected by a well
the shortest sticks. heapq.heapify(heap)
# Maintain a heap and repeatedly connect the shortest 2 sticks, putting the connected
stick back on the heap. supplied = set() # houses that are connected
# Time - O(n log n) result = 0
# Space - O(n)
while len(supplied) < n:
import heapq cost, house = heapq.heappop(heap) # smallest cost connection
if house in supplied:
class Solution(object): continue
def connectSticks(self, sticks): supplied.add(house)
""" result += cost
:type sticks: List[int] for nbor, nbor_cost in neighbours[house]: # add all unconnected
:rtype: int neighbours to the heap
""" if nbor not in supplied:
cost = 0 heapq.heappush(heap, (nbor_cost, nbor))
heapq.heapify(sticks)
return result
while len(sticks) > 1:
x, y = heapq.heappop(sticks), heapq.heappop(sticks)
cost += x + y
heapq.heappush(sticks, x + y) # python_1001_to_2000/1169_Invalid_Transactions.py - m

return cost _author_ = 'jake'


_project_ = 'leetcode'
# For example, if s = "dcce" then f(s) = 2 because the smallest character is "c" and its
# https://leetcode.com/problems/invalid-transactions/ frequency is 2.
# A transaction is possibly invalid if: # Now, given string arrays queries and words, return an integer array answer,
# the amount exceeds $1000, or; # where each answer[i] is the number of words such that f(queries[i]) < f(W), where W is
# if it occurs within (and including) 60 minutes of another transaction with the same a word in words.
name in a different city.
# Each transaction string transactions[i] consists of comma separated values # Create a list to count the number of words with each f(word).
representing: # Populate the list for each word, then iterate over the list in reverse order so it
# the name, time (in minutes), amount, and city of the transaction. contains the cumulative count
# Given a list of transactions, return a list of transactions that are possibly invalid. # of words with the same or greater f(word).
# You may return the answer in any order. # For each query, lookup f(query) + 1 in the cumulative frequency list, to return the
number of words with a
# Sort all transactions by ascending time. # greater f(word).
# For user, maintain an ordered list of previous transactions. # Time - O(m + n), the number of chars in words + the number of chars in queries
# For each transactions, add to result if cost > 1000. # Space - O(1), since words have at most 10 chars
# Iterate backwards through the previous transactions for that user, while they are
within 60 minutes. class Solution(object):
# If a previous transaction is in a different city, add both current and previous to the def numSmallerByFrequency(self, queries, words):
invalid set. """
# Time - O(n**2) since for each transaction we may iterate through all previous :type queries: List[str]
transactions. :type words: List[str]
# Space - O(n) :rtype: List[int]
"""
from collections import defaultdict word_freq = [0] * 12 # word_freq[i] is count of words with f(word) ==
i
class Solution(object): for word in words:
def invalidTransactions(self, transactions): word_freq[word.count(min(word))] += 1
"""
:type transactions: List[str] for i in range(10, 0, -1): # update word_freq[i] to be the count of words
:rtype: List[str] with f(word) >= i
""" word_freq[i] += word_freq[i + 1]
elements = [transaction.split(",") + [i] for i, transaction in
enumerate(transactions)] # look up the count of words with f(word) > f(query)
elements.sort(key=lambda x: int(x[1])) # sort by ascending time return [word_freq[query.count(min(query)) + 1] for query in queries]

user_transactions = defaultdict(list) # map user to list of transactions


ordered by time
invalid = set() # remove duplicates by using set # python_1001_to_2000/1171_Remove_Zero_Sum_Consecutive_Nodes_from_Linked_List.py - m

for transaction in elements: _author_ = 'jake'


name, time, cost, city, i = transaction _project_ = 'leetcode'
time = int(time)
# https://leetcode.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list/
if int(cost) > 1000: # Given the head of a linked list,
invalid.add(transactions[i]) # we repeatedly delete consecutive sequences of nodes that sum to 0 until there are no
such sequences.
j = len(user_transactions[name]) - 1 # After doing so, return the head of the final linked list. You may return any such
while j >= 0 and time - user_transactions[name][j][0] <= 60: # while answer.
within 60 minutes
if user_transactions[name][j][1] != city: # Iterate along the list, updating a running sum of node values.
invalid.add(transactions[i]) # If we have running sum that has been seen before, connect the previous node with the
invalid.add(transactions[user_transactions[name][j][2]]) running sum to the next node,
j -= 1 # thereby removing the zero sum sequence from the list.
# Use an OrderedDict so we can pop all the eliminated nodes off the dictionary.
user_transactions[name].append([time, city, i]) # update previous # Alternatively, when a zero sum sequence is found eliminate those nodes and start from
transactions for this person the head again.
# So the dictionary does not have to be cleared.
return list(invalid) # Time - O(n)
# Space - O(n)

from collections import OrderedDict


# python_1001_to_2000/1170_Compare Strings_by_Frequency_of_the_Smallest_Character.py - m
class Solution(object):
_author_ = 'jake' def removeZeroSumSublists(self, head):
_project_ = 'leetcode' """
:type head: ListNode
# https://leetcode.com/problems/compare-strings-by-frequency-of-the-smallest-character/ :rtype: ListNode
# Let's define a function f(s) over a non-empty string s, """
# which calculates the frequency of the smallest character in s. dummy = ListNode(0) # create a new dummy head, in case the head is

removed :type val: int


dummy.next = head :rtype: None
node = dummy """
running_sum = 0 # sum of all node vals seen while self.incomplete_stacks: # check or discard all incomplete_stacks in order
sum_to_node = OrderedDict() # map running_sum to ListNode i = heapq.heappop(self.incomplete_stacks)
if i >= len(self.stacks):
while node: continue
running_sum += node.val self.stacks[i].append(val)
to_connect = sum_to_node.get(running_sum, node) # node to be connected to return
node.next
if not self.stacks or len(self.stacks[-1]) == self.capacity:
while running_sum in sum_to_node: # remove eliminated nodes self.stacks.append([]) # start a new stack
sum_to_node.popitem() self.stacks[-1].append(val)
sum_to_node[running_sum] = to_connect
def pop(self):
node = to_connect.next = node.next """
:rtype: int
return dummy.next """
if not self.stacks:
return -1
val = self.stacks[-1].pop()
# python_1001_to_2000/1172_Dinner_Plate_Stacks.py - h while self.stacks and not self.stacks[-1]: # discard all empty stacks
self.stacks.pop()
_author_ = 'jake' return val
_project_ = 'leetcode'
def popAtStack(self, index):
# https://leetcode.com/problems/dinner-plate-stacks/ """
# You have an infinite number of stacks arranged in a row and numbered (left to right) :type index: int
from 0, :rtype: int
# each of the stacks has the same maximum capacity. """
# Implement the DinnerPlates class: if index >= len(self.stacks) or len(self.stacks[index]) == 0:
# DinnerPlates(int capacity) Initializes the object with the maximum capacity of the return -1
stacks.
# void push(int val) pushes the given positive integer val into the leftmost stack with if index == len(self.stacks) - 1: # do not need incomplete_stacks for
size less than capacity. final stack
# int pop() returns the value at the top of the rightmost non-empty stack and removes it return self.pop()
from that stack,
# and returns -1 if all stacks are empty. heapq.heappush(self.incomplete_stacks, index)
# int popAtStack(int index) returns the value at the top of the stack with the given return self.stacks[index].pop()
index and removes it
# from that stack, and returns -1 if the stack with that given index is empty.

# Maintain a list of stacks, where the last stack cannot be empty. # python_1001_to_2000/1175_Prime_Arrangements.py
# Also maintain a heap of indices of stacks which are incomplete due to popAtStack(),
i.e. not including the last stack. _author_ = 'jake'
# Push onto the first available incomplete stack, or the final stack (adding a new one if _project_ = 'leetcode'
final stack is at capacity).
# When popping, remove all empty stacks (which may be more than 1 due to popAtStack). # https://leetcode.com/problems/prime-arrangements/
# For popAtStack, use pop if popping from the final stack, else add to the incomplete # Return the number of permutations of 1 to n so that prime numbers are at prime indices
stacks heap. (1-indexed.)
# Time - O(n log n) for n operations of push and popAtStack since all existing stacks # Recall that an integer is prime if and only if it is greater than 1,
could be touched. O(n) for pop. # and cannot be written as a product of two positive integers both smaller than it.
# Space - O(n) # Since the answer may be large, return the answer modulo 10^9 + 7.

import heapq # Binary search the list of prines to find how many primes are <= n.
# Multiply the number of permutations of primes (primes!) by the number of permutations
class DinnerPlates(object): of non-primes.
# Time - O(1)
def __init__(self, capacity): # Space - O(1)
"""
:type capacity: int import bisect, math
"""
self.capacity = capacity class Solution(object):
self.stacks = [] def numPrimeArrangements(self, n):
self.incomplete_stacks = [] # heap of indices of stacks that have had """
pop_index :type n: int
:rtype: int
def push(self, val): """
""" 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]
prime_count = bisect.bisect_right(primes, n) # Return an array answer[], where answer[i] is the result of the i-th query queries[i].
return (math.factorial(prime_count) * math.factorial(n - prime_count)) % (10 ** # Note that: Each letter is counted individually for replacement so if for example
9 + 7) 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/1176_Diet_Plan_Performance.py # For each prefix of s, create an integer with a bit set for every char in the prefix
that has an odd count.
_author_ = 'jake' # For each query, find the integers for the left and right + 1 prefixes.
_project_ = 'leetcode' # Count the number of chars in the query that have an odd number of bits set. These chars
need to be changed to
# https://leetcode.com/problems/diet-plan-performance/ # make a palindrome, apart from the central char if the query is of odd length.
# A dieter consumes calories[i] calories on the i-th day. # Time - O(m + n) where m is len(s) and there are n queries.
# Given an integer k, for every consecutive sequence of k days # Space - O(n)
# (calories[i], calories[i+1], ..., calories[i+k-1] for all 0 <= i <= n-k), they look at
T, class Solution(object):
# the total calories consumed during that sequence of k days (calories[i] + calories[i+1] def canMakePaliQueries(self, s, queries):
+ ... + calories[i+k-1]): """
# If T < lower, they performed poorly on their diet and lose 1 point; :type s: str
# If T > upper, they performed well on their diet and gain 1 point; :type queries: List[List[int]]
# Otherwise, they performed normally and there is no change in points. :rtype: List[bool]
# Initially, the dieter has zero points. """
# Return the total number of points the dieter has after dieting for calories.length char_odd_bits = [0]
days. for c in s:
# Note that the total points can be negative. char_odd_bits.append(char_odd_bits[-1] ^ (1 << ord(c) - ord("a")))

# Sliding window of the calories consumed over k days. result = []


# For each day after the end of a window, update points then update window calories. for left, right, k in queries:
# Time - O(n) left_odd_bits = char_odd_bits[left]
# Space - O(1) right_odd_bits = char_odd_bits[right + 1]
odd_chars = bin(left_odd_bits ^ right_odd_bits).count("1") # XOR to count
class Solution(object): different bits in left and right
def dietPlanPerformance(self, calories, k, lower, upper):
""" odd_chars -= (right - left + 1) % 2 # use an odd char for the middle if
:type calories: List[int] substring length is odd
:type k: int odd_chars -= 2 * k # change each odd char to match
:type lower: int another odd char
:type upper: int result.append(odd_chars <= 0)
:rtype: int
""" return result
calories.append(0) # append extra dummy element
window = sum(calories[:k])
points = 0
# python_1001_to_2000/1178_Number_of_Valid_Words_for_Each_Puzzle.py - h
for i in range(k, len(calories)):
if window < lower: _author_ = 'jake'
points -= 1 _project_ = 'leetcode'
elif window > upper:
points += 1 # https://leetcode.com/problems/number-of-valid-words-for-each-puzzle/
window += calories[i] # With respect to a given puzzle string, a word is valid if both the following conditions
window -= calories[i - k] are satisfied:
# word contains the first letter of puzzle.
return points # For each letter in word, that letter is in puzzle.
# For example, if the puzzle is "abcdefg", then valid words are "faced", "cabbage", and
"baggage";
# while invalid words are "beefed" (doesn't include "a") and "based" (includes "s" which
# python_1001_to_2000/1177_Can_Make_Palindrome_from_Substring.py - m isn't in the puzzle).
# Return an array answer, where answer[i] is the number of words in the given word list
_author_ = 'jake' words that are valid
_project_ = 'leetcode' # with respect to the puzzle puzzles[i].

# https://leetcode.com/problems/can-make-palindrome-from-substring/ # Convert each word to an integer, where a set bit indicates the presence of of a
# Given a string s, we make queries on substrings of s. character.
# For each query queries[i] = [left, right, k], we may rearrange the substring s[left], # Count the frequency of each such integer.
..., s[right], # For each puzzle, form all combinations of integers from characters of the puzzle.
# and then choose up to k of them to replace with any lowercase English letter. Always include the first
# If the substring is possible to be a palindrome string after the operations above, the # character + any number of other character. Add to the result the count of words with
result of the query is true. each combination.
# Otherwise, the result is false. # Time - O(mk + n * 2**p) for m words of length k, and n puzzles of length p.

# Space - O(mk + n)

from collections import Counter


from itertools import combinations # python_1001_to_2000/1181_Before_and_After_Puzzle.py - m

class Solution(object): _author_ = 'jake'


def findNumOfValidWords(self, words, puzzles): _project_ = 'leetcode'
"""
:type words: List[str] # https://leetcode.com/problems/before-and-after-puzzle/
:type puzzles: List[str] # Given a list of phrases, generate a list of Before and After puzzles.
:rtype: List[int] # A phrase is a string that consists of lowercase English letters and spaces only.
""" # No space appears in the start or the end of a phrase. There are no consecutive spaces
def word_to_int(s): in a phrase.
bits = 0 # Before and After puzzles are phrases that are formed by merging two phrases where the
for c in s: last word of
bits |= (1 << (ord(c) - ord("a"))) # the first phrase is the same as the first word of the second phrase.
return bits # Return the Before and After puzzles that can be formed by every two phrases phrases[i]
and phrases[j] where i != j.
word_bits_counter = Counter(word_to_int(w) for w in words) # Note that the order of matching two phrases matters, we want to consider both orders.
# You should return a list of distinct strings sorted lexicographically.
result = []
# Split all phrases by space.
for puzzle in puzzles: # For each pair of split phrases, add to the result the concatenation if the last and
first_char_bit = word_to_int(puzzle[0]) # this bit is always first words are the same.
set # Sort the result.
other_char_bits = [word_to_int(c) for c in puzzle[1:]] # check all # Time - O(n**2 log n)
combinations of these bits # Space - O(n**2)
valid = 0
for k in range(7): # 0 to 6 other bits class Solution(object):
for combination in combinations(other_char_bits, k): def beforeAndAfterPuzzles(self, phrases):
valid += word_bits_counter[first_char_bit + sum(combination)] """
result.append(valid) :type phrases: List[str]
:rtype: List[str]
return result """
split_phrases = [phrase.split(" ") for phrase in phrases]
result = set() # eliminates duplicates

for i, split_phrase1 in enumerate(split_phrases):


for j, split_phrase2 in enumerate(split_phrases):
# python_1001_to_2000/1180_Count_Substrings_with_Only_One_Distinct_Letter.py if i != j and split_phrase1[-1] == split_phrase2[0]:
joined = " ".join(split_phrase1 + split_phrase2[1:])
_author_ = 'jake' result.add(joined)
_project_ = 'leetcode'
return sorted(result)
# https://leetcode.com/problems/count-substrings-with-only-one-distinct-letter/
# Given a string S, return the number of substrings that have only one distinct letter.

# Iterate along S, tracking the start of the current sequence of identical letters. # python_1001_to_2000/1182_Shortest_Distance_to_Target_Color.py - m
# If a char if different from the previous, then update the previous and the start.
# Time - O(n) _author_ = 'jake'
# Space - O(1) _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/shortest-distance-to-target-color/


def countLetters(self, S): # You are given an array colors, in which there are three colors: 1, 2 and 3.
""" # You are also given some queries.
:type S: str # Each query consists of two integers i and c,
:rtype: int # return the shortest distance between the given index i and the target color c.
""" # If there is no solution return -1.
previous = "#"
start = 0 # For each element of the array, find the distance to the closest element of each color
substrings = 0 to the left.
# Then update the closest distance to each color for each index, with any closer indices
for end, c in enumerate(S): on the right.
if c != previous: # For each query index, lookup the closest distance to the required color.
start = end # Time - O(m + n) for array of length m and n queries.
previous = c # Space - O(m + n)
substrings += end - start + 1 # add all substrings with current end
class Solution(object):
return substrings def shortestDistanceColor(self, colors, queries):
""" int(c < remainder_height))
:type colors: List[int] matrix.append(repeats)
:type queries: List[List[int]]
:rtype: List[int] return sum(sorted(matrix, reverse=True)[:maxOnes])
"""
shortest = []
distances = [float("inf")] * 3 # to next element of each color
on left # python_1001_to_2000/1184_Distance_Between_Bus_Stops.py
for color in colors:
distances = [d + 1 for d in distances] # add 1 to distance for each _author_ = 'jake'
color _project_ = 'leetcode'
distances[color - 1] = 0 # zero distance to thie color
shortest.append(list(distances)) # https://leetcode.com/problems/distance-between-bus-stops/
# A bus has n stops numbered from 0 to n - 1 that form a circle.
for i in range(len(colors) - 2, -1, -1): # update with closest color on # We know the distance between all pairs of neighboring stops where distance[i] is the
right, if smaller distance between the
distances = [d + 1 for d in shortest[i + 1]] # stops number i and (i + 1) % n.
for color in range(3): # The bus goes along both directions i.e. clockwise and counterclockwise.
shortest[i][color] = min(shortest[i][color], distances[color]) # Return the shortest distance between the given start and destination stops.

result = [] # Ensure destination stop is not before start stop by swapping if necessary.
for i, color in queries: # Find the sum of the distances from start to destination.
shortest_dist = shortest[i][color - 1] # Also find the sum of the distances round a complete circuit of all stops.
result.append(-1 if shortest_dist == float("inf") else shortest_dist) # Return the minimum of the direct distance and the distance in the reverse direction.
# Time - O(n)
return result # Space - O(1)

class Solution(object):
def distanceBetweenBusStops(self, distance, start, destination):
# python_1001_to_2000/1183_Maximum_Number_of_Ones.py - h """
:type distance: List[int]
_author_ = 'jake' :type start: int
_project_ = 'leetcode' :type destination: int
:rtype: int
# https://leetcode.com/problems/maximum-number-of-ones/ """
# Consider a matrix M with dimensions width * height, such that every cell has value 0 or if destination < start:
1, start, destination = destination, start
# and any square sub-matrix of M of size sideLength * sideLength has at most maxOnes
ones. start_to_dest = sum(distance[start:destination])
# Return the maximum possible number of ones that the matrix M can have. circuit = sum(distance) # distance of complete circuit
return min(start_to_dest, circuit - start_to_dest)
# 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. # python_1001_to_2000/1185_Day_of_the_Week.py
# 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 _author_ = 'jake'
# the remaining rows. _project_ = 'leetcode'
# Sort the number of times each cell appears, add ones to the maxOnes most frequent
cells. # https://leetcode.com/problems/day-of-the-week/
# Time - O(n**2 log n) for sideLength n # Given a date, return the corresponding day of the week for that date.
# Space - O(n**2) # The input is given as three integers representing the day, month and year respectively.
# Return the answer as one of the following values {"Sunday", "Monday", "Tuesday",
class Solution(object): "Wednesday",
def maximumNumberOfOnes(self, width, height, sideLength, maxOnes): # "Thursday", "Friday", "Saturday"}.
"""
:type width: int # Find the number of days since 1 Jan 1971.
:type height: int # Sum the day of the month + days in previous months + 365 * years since 1971.
:type sideLength: int # Add an offset of 4 since 1/1/71 was Friday.
:type maxOnes: int # Add extra days for any previous leap yeas and current leap year.
:rtype: int # Time - O(1)
""" # Space - O(1)
whole_width, remainder_width = divmod(width, sideLength)
whole_height, remainder_height = divmod(height, sideLength) class Solution(object):
def dayOfTheWeek(self, day, month, year):
matrix = [] """
for r in range(sideLength): :type day: int
for c in range(sideLength): :type month: int
repeats = (whole_width + int(r < remainder_width)) * (whole_height + :type year: int

:rtype: str # https://leetcode.com/problems/make-array-strictly-increasing/


""" # Given two integer arrays arr1 and arr2,
weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", # return the minimum number of operations (possibly zero) needed to make arr1 strictly
"Saturday"] increasing.
cumulative_days = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] # In one operation, you can choose two indices 0 <= i < arr1.length and 0 <= j <
arr2.length
days = 4 + day + cumulative_days[month - 1] + 365 * (year - 1971) # 4 for # and do the assignment arr1[i] = arr2[j].
offset from 1/1/1974 # If there is no way to make arr1 strictly increasing, return -1.

leap_days = (year - 1969) // 4 # number of completed leap years # Maintain a mapping from the last num of the array so far and the number of operations
print(leap_days) to make this array.
if year % 4 == 0 and month >= 3: # include 29th February in current year # For each num of arr1, create a new mapping with default value of infinity.
leap_days += 1 # For each ending num of previous arrays,
days += leap_days # If num > prev_num then we can make an array ending num with the same operations as
made prev_num
return weekdays[days % 7] # Find the next number in arr2 greater than prev_num. if num <= prev_num then we can
make an array ending in arr2[i]
# with an extra operation. Similarly we can use the extra operation if num > prev_num
only if arr2[i] < num (else we
# python_1001_to_2000/1186_Maximum_Subarray_Sum_with_One_Deletion.py - m # are better extending with no additional operation).
# Time - O(n**2)
_author_ = 'jake' # Space - O(n)
_project_ = 'leetcode'
from collections import defaultdict
# https://leetcode.com/problems/maximum-subarray-sum-with-one-deletion/ import bisect
# Given an array of integers,
# return the maximum sum for a non-empty subarray (contiguous elements) with at most one class Solution(object):
element deletion. def makeArrayIncreasing(self, arr1, arr2):
# In other words, you want to choose a subarray and optionally delete one element from it """
so that there is still :type arr1: List[int]
# at least one element left and the sum of the remaining elements is maximum possible. :type arr2: List[int]
# Note that the subarray needs to be non-empty after deleting one element. :rtype: int
"""
# Iterate over the array, tracking the max sum ending at each index and the max sum arr2.sort()
ending at each index with one num_to_ops = {-1: 0} # map last number of array to number of ops to make array
# deletion. increasing
# 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, for num in arr1:
# or the previous max with deletion and adds the current num. new_num_to_ops = defaultdict(lambda: float("inf"))
# Time - O(n)
# Space - O(1) for prev_num in num_to_ops:
if num > prev_num: # same nb ops to extend with num
class Solution(object): new_num_to_ops[num] = min(new_num_to_ops[num], num_to_ops[prev_num])
def maximumSum(self, arr):
""" i = bisect.bisect_right(arr2, prev_num)
:type arr: List[int] if i < len(arr2) and (num <= prev_num or arr2[i] < num):
:rtype: int new_num_to_ops[arr2[i]] = min(new_num_to_ops[arr2[i]],
""" num_to_ops[prev_num] + 1)
if all(a <= 0 for a in arr): # no positive, return largest value
return max(arr) num_to_ops = new_num_to_ops

overall_max_deleted = 0 if num_to_ops:
max_here, max_here_deleted = 0, 0 return min(num_to_ops.values())
return -1
for a in arr:
max_here_deleted = max(max_here_deleted + a, max_here)
max_here = max(max_here, 0) + a
# python_1001_to_2000/1189_Maximum_Number_of_Balloons.py
overall_max_deleted = max(overall_max_deleted, max_here_deleted, max_here)
_author_ = 'jake'
return overall_max_deleted _project_ = 'leetcode'

# https://leetcode.com/problems/maximum-number-of-balloons/
# Given a string text, you want to use the characters of text to form as many instances
# python_1001_to_2000/1187_Make_Array_Strictly_Increasing.py - h # of the word "balloon" as possible.
# You can use each character in text at most once. Return the maximum number of instances
_author_ = 'jake' that can be formed.
_project_ = 'leetcode'
# 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 _author_ = 'jake'
# letter in text divided by the count in "balloons". _project_ = 'leetcode'
# Time - O(n)
# Space - O(1) # https://leetcode.com/problems/k-concatenation-maximum-sum/
# Given an integer array arr and an integer k, modify the array by repeating it k times.
from collections import Counter # For example, if arr = [1, 2] and k = 3 then the modified array will be [1, 2, 1, 2, 1,
2].
class Solution(object): # Return the maximum sub-array sum in the modified array.
def maxNumberOfBalloons(self, text): # Note that the length of the sub-array can be 0 and its sum in that case is 0.
""" # As the answer can be very large, return the answer modulo 10^9 + 7.
:type text: str
:rtype: int # Iterate along the array, finding the maximum sum prefix and the maximum sum subarray.
""" # Iterate along the array in reverse, finding the maximum sum suffix.
counts = Counter(text) # If k == 1, return the maximum sum subarray.
result = float("inf") # 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
for c, count in Counter("balloon").items(): suffix and prefix.
result = min(result, counts[c] // count) # integer division # Time - O(n)
# Space - O(1)
return result
class Solution(object):
def kConcatenationMaxSum(self, arr, k):
"""
# python_1001_to_2000/1190_Reverse_Substrings_Between_Each_Pair_of_Parentheses.py - m :type arr: List[int]
:type k: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
MOD = 10 ** 9 + 7
# https://leetcode.com/problems/reverse-substrings-between-each-pair-of-parentheses/ total = sum(arr)
# You are given a string s that consists of lower case English letters and brackets.
# Reverse the strings in each pair of matching parentheses, starting from the innermost max_prefix, max_end_here, max_subarray = 0, 0, 0
one. cumulative = 0
# Your result should not contain any brackets. for a in arr:
cumulative += a
# Iterate along s, maintaining a stack of text at each depth of open braces. max_prefix = max(max_prefix, cumulative)
# For an opening brace, add the text since the previous brace to the current stack top max_end_here = max(max_end_here, 0) + a
and start a new stack level. max_subarray = max(max_subarray, max_end_here)
# For a closing brace, add the text since the previous brace to the current stack top,
then pop the top, reverse it max_suffix = 0
# and add to the new stack top. cumulative = 0
# Time - O(n**2) for a in arr[::-1]:
# Space - O(n) cumulative += a
max_suffix = max(max_suffix, cumulative)
class Solution(object):
def reverseParentheses(self, s): if k == 1:
""" return max_subarray % MOD
:type s: str return max(max_subarray, max_prefix + max_suffix + max(total, 0) * (k - 2)) % MOD
:rtype: str
"""
stack = [""]
# python_1001_to_2000/1192_Critical_Connections_in_a_Network.py - h
start = 0
for i, c in enumerate(s): _author_ = 'jake'
if c == "(": # add substring to top of stack and start a new empty _project_ = 'leetcode'
substring
stack[-1] += s[start:i] # https://leetcode.com/problems/critical-connections-in-a-network/
stack.append("") # There are n servers numbered from 0 to n-1 connected by undirected server-to-server
start = i + 1 connections forming a network
elif c == ")": # where connections[i] = [a, b] represents a connection between servers a and b.
stack[-1] += s[start:i] # Any server can reach any other server directly or indirectly through the network.
stack[-1] += stack.pop()[::-1] # A critical connection is a connection that, if removed, will make some server unable to
start = i + 1 reach some other server.
# Return all critical connections in the network in any order.
return stack[0] + s[start:] # add remaining text
# A connection is critical if and only if it is not in any cycle in the network.
# Convert the connections to an adjacency list for each node.
# Create a set of all edges (as ordered pairs of nodes).
# python_1001_to_2000/1191_K-Concatenation_Maximum_Sum.py - m # Set the rank of a node as its depth when it is visited, or n when all paths have been

fully explored. import heapq


# Depth-first search the graph.
# Helper function returns the rank of a node if node has already been seen, else the class Solution(object):
minimum rank of any node that def maxNumberOfApples(self, arr):
# can be reached. """
# For each unvisited node, set rank to depth then recurse to neighbours apart from :type arr: List[int]
parent. :rtype: int
# If any neighbour leads to a node with lower depth then we have seen that node on the """
current path and the edge capacity = 5000
# between nodes is in a cycle. apples = 0
# Time - O(m + n) for m edges and n nodes heapq.heapify(arr)
# Space - O(m + n) while arr and capacity - arr[0] >= 0:
capacity -= heapq.heappop(arr)
from collections import defaultdict apples += 1

class Solution(object): return apples


def criticalConnections(self, n, connections):
"""
:type n: int
:type connections: List[List[int]] # python_1001_to_2000/1197_Minimum_Knight_Moves.py - m
:rtype: List[List[int]]
""" _author_ = 'jake'
node_to_nbors = defaultdict(list) _project_ = 'leetcode'
for connection in connections:
node_to_nbors[connection[0]].append(connection[1]) # https://leetcode.com/problems/minimum-knight-moves/
node_to_nbors[connection[1]].append(connection[0]) # In an infinite chess board with coordinates from -infinity to +infinity, you have a
knight at square [0, 0].
connections = {tuple(sorted(connection)) for connection in connections} # A knight has 8 possible moves it can make.
rank = [-float("inf")] * n # Each move is two squares in a cardinal direction, then one square in an orthogonal
direction.
def helper(node, depth): # Return the minimum number of steps needed to move the knight to the square [x, y].
if rank[node] >= 0: # visiting (0 <= rank < n), or visited (rank == n) # It is guaranteed the answer exists.
return rank[node]
# A-star search the board.
rank[node] = depth # new node on current path # Maintain a heap of positions, repeatedly expanding the position with the lowest
min_nbor_path_depth = n possible result.
for nbor in node_to_nbors[node]: # Use a heuristic of the minimum possible moves to reach the target.
if rank[nbor] == depth - 1: # don't go back to parent # If the distance in the smallest dimension (x or y) is less than twice the distance in
continue the largest dimension,
# then we can potentially reach target in (largest dimension + 1) // 2 steps. Else we
nbor_path_depth = helper(nbor, depth + 1) need to add additional steps
if nbor_path_depth <= depth: # edge forms a cycle # to reach the target in the smallest dimension.
connections.discard(tuple(sorted((node, nbor)))) # Time - O(d**8) where d is the number of moves to reach the target.
min_nbor_path_depth = min(min_nbor_path_depth, nbor_path_depth) # Space - O(d**8)
rank[node] = n # node fully explored
return min_nbor_path_depth import heapq

helper(0, 0) # start from any arbitrary node since connected graph class Solution(object):
return list(connections) def minKnightMoves(self, x, y):
"""
:type x: int
:type y: int
# python_1001_to_2000/1196_How_Many_Apples_Can_You_Put_into_the_Basket.py :rtype: int
"""
_author_ = 'jake' def heuristic(cell):
_project_ = 'leetcode' dx, dy = abs(cell[0] - x), abs(cell[1] - y)
min_d, max_d = sorted([dx, dy])
# https://leetcode.com/problems/how-many-apples-can-you-put-into-the-basket/ max_moves = (max_d + 1) // 2
# You have some apples, where arr[i] is the weight of the i-th apple. return max_moves + max(0, (min_d - max_moves + 1) // 2)
# You also have a basket that can carry up to 5000 units of weight.
# Return the maximum number of apples you can put in the basket. queue = [[heuristic((0, 0)), 0, (0, 0)]] # [min total moves possible, moves so
far, cell]
# Form a heap of the apples. seen = set()
# Remove apples from the heap by increasing weight,
# until there are no more apples or there is insufficient capacity to fit the next apple while True:
in the basket. _, moves, cell = heapq.heappop(queue)
# Time - O(n log n) if cell == (x, y):
# Space - O(n) return moves
if cell in seen: # ignore cells already reached import heapq
continue
seen.add(cell) class Solution(object):
def minBuildTime(self, blocks, split):
for dx, dy in [(2, 1), (2, -1), (-2, -1), (-2, 1), (1, 2), (-1, 2), (-1, -2), """
(1, -2)]: # 8 moves :type blocks: List[int]
new_cell = (cell[0] + dx, cell[1] + dy) :type split: int
if new_cell not in seen: :rtype: int
heapq.heappush(queue, [heuristic(new_cell) + moves + 1, moves + 1, """
new_cell]) heapq.heapify(blocks)

while len(blocks) > 1: # combine the smallest 2 blocks


heapq.heappop(blocks)
# python_1001_to_2000/1198_Find_Smallest_Common_Element_in_All_Rows.py - m heapq.heappush(blocks, split + heapq.heappop(blocks))

_author_ = 'jake' return blocks[0]


_project_ = 'leetcode'

# 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 # python_1001_to_2000/1200_Minimum_Absolute_Difference.py
common element in all rows.
# If there is no common element, return -1. _author_ = 'jake'
_project_ = 'leetcode'
# Create a set of all elements from the first row.
# For each other row, retain common elements from that row and all previous rows. # https://leetcode.com/problems/minimum-absolute-difference/
# Time - O(mn) # Given an array of distinct integers arr, find all pairs of elements with the minimum
# Space - O(m) absolute
# difference of any two elements.
class Solution(object): # Return a list of pairs in ascending order(with respect to pairs), each pair [a, b]
def smallestCommonElement(self, mat): follows
""" # a, b are from arr
:type mat: List[List[int]] # a < b
:rtype: int # b - a equals to the minimum absolute difference of any two elements in arr
"""
candidates = set(mat[0]) # Sort the array and iterate along, calculating the difference between each pair.
# If the difference is less than the minimum distance, update the minimum and clear the
for row in mat[1:]: previous results.
candidates &= set(row) # Then if the difference is less than the minimum distance, append the pair to the
results.
return min(candidates) if candidates else -1 # Time - O(n log n)
# Space - O(n)

class Solution(object):
# python_1001_to_2000/1199_Minimum_Time_to_Build_Blocks.py - h def minimumAbsDifference(self, arr):
"""
_author_ = 'jake' :type arr: List[int]
_project_ = 'leetcode' :rtype: List[List[int]]
"""
# https://leetcode.com/problems/minimum-time-to-build-blocks/ arr.sort()
# You are given a list of blocks, where blocks[i] = t means that the i-th block needs t results = []
units of time to be built. min_diff = float("inf")
# 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 for i in range(1, len(arr)):
build a block then go home. diff = arr[i] - arr[i - 1]
# Both decisions cost some time. if diff < min_diff:
# The time cost of spliting one worker into two workers is given as an integer split. min_diff = diff
# Note that if two workers split at the same time, they split in parallel so the cost results = [] # clear previous results
would be split.
# Output the minimum time needed to build all blocks. if diff == min_diff:
# Initially, there is only one worker. results.append([arr[i - 1], arr[i]])

# Create a heap of the time to mine each block. return results


# Repeatedly pop off the smallest 2 blocks and combine them into a single block.
# Add the combined block back to the heap, with its time of split + max time to mine
underlying blocks.
# Continue until only one block remains. # python_1001_to_2000/1201_Ugly_Number_III.py - m
# Time - O(n log n)
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'

# Then create a mapping of each ultimate parent to all children (including the parent
# https://leetcode.com/problems/ugly-number-iii/ itself).
# Write a program to find the n-th ugly number. # For each connected group, place the sorted the characters in the sorted indices.
# Ugly numbers are positive integers which are divisible by a or b or c. # Time - O(m log* m + n log n) for string length n and m pairs
# Space - O(n)
# Given a guess for the nth ugly number, we can count the ugly numbers <= guess.
# Count all the numbers divisible by a, b and c. Subtract the numbers divisible by the from collections import defaultdict
lowest common multiple of
# each pair from a, b and c. Add back numbers divisible by the lowest common multiple of class Solution(object):
a, b and c. def smallestStringWithSwaps(self, s, pairs):
# Binary search the range of possible results. """
# Time - O(log n) :type s: str
# Space - O(1) :type pairs: List[List[int]]
:rtype: str
class Solution(object): """
def nthUglyNumber(self, n, a, b, c): n = len(s)
""" parents = {i: i for i in range(n)}
:type n: int
:type a: int def find(i):
:type b: int while parents[i] != i:
:type c: int parents[i] = parents[parents[i]] # collapse the grandparent to parent
:rtype: int i = parents[i]
""" return i
def gcd(x, y): # x >= y
while y != 0: for a, b in pairs:
x, y = y, x % y parents[find(a)] = find(b)
return x
parent_to_children = defaultdict(list)
def lcm(x, y): for i in range(n):
return (x * y) // gcd(x, y) parent_to_children[find(i)].append(i)

a, b, c = sorted([a, b, c]) result = [None] * n


ab, ac, bc = lcm(b, a), lcm(c, a), lcm(c, b) for children in parent_to_children.values(): # children indices are sorted
abc = lcm(bc, a) chars = sorted(s[i] for i in children)
for child, char in zip(children, chars):
def ugly_less_or_equal(x): # count ugly <= x result[child] = char
result = (x // a) + (x // b) + (x // c)
result -= (x // ab) + (x // ac) + (x // bc) return "".join(result)
result += x // abc
return result

lower, upper = 1, 2 * 10 ** 9 # python_1001_to_2000/1203_Sort_Items_by_Groups_Respecting_Dependencies.py - h

while lower < upper: _author_ = 'jake'


mid = (lower + upper) // 2 _project_ = 'leetcode'
if ugly_less_or_equal(mid) >= n: # mid or lower is potentially correct
upper = mid # https://leetcode.com/problems/sort-items-by-groups-respecting-dependencies/
else: # result must be above lower # There are n items each belonging to zero or one of m groups where group[i] is the group
lower = mid + 1 that the i-th item belongs
# to and it's equal to -1 if the i-th item belongs to no group.
return lower # The items and the groups are zero indexed.
# A group can have no item belonging to it.
# Return a sorted list of the items such that:
# The items that belong to the same group are next to each other in the sorted list.
# python_1001_to_2000/1202_Smallest_String_With_Swaps.py - m # There are some relations between these items where beforeItems[i] is a list containing
all the items that
_author_ = 'jake' # should come before the i-th item in the sorted array (to the left of the i-th item).
_project_ = 'leetcode' # Return any solution if there is more than one solution and return an empty list if
there is no solution.
# https://leetcode.com/problems/smallest-string-with-swaps/
# You are given a string s, and an array of pairs of indices in the string pairs where # Topologically sort the items in each group and topologically sort the groups.
pairs[i] = [a, b] # Topologically sort by repeatedly adding items with nothing before to the result. Then
# indicates 2 indices(0-indexed) of the string. reducing the count of items
# You can swap the characters at any pair of indices in the given pairs any number of # before any items the must go after the added item, and adding it to the set of items
times. with nothing before if the
# Return the lexicographically smallest string that s can be changed to after using the # count is zero.
swaps. # Time - O(m + n) for m beforeItems and n items
# Space - O(m + n)
# Union-find to connect the sets of connected indices.
from collections import defaultdict for gp in group_ordering:
if gp in ordered_groups: # ignore group with no items
class Solution(object): result += ordered_groups[gp]
def sortItems(self, n, m, group, beforeItems): return result
"""
:type n: int
:type m: int
:type group: List[int] # python_1001_to_2000/1207_Unique_Number_of_Occurrences.py
:type beforeItems: List[List[int]]
:rtype: List[int] _author_ = 'jake'
""" _project_ = 'leetcode'

def top_sort(map_to_after, before_count): # https://leetcode.com/problems/unique-number-of-occurrences/


no_before = {i for i, count in before_count.items() if count == 0} # items # Given an array of integers arr, write a function that returns true if and only if the
with nothing before number of
result = [] # occurrences of each value in the array is unique.
while no_before:
i = no_before.pop() # Count the occurrences of each value and check whether the set of counts is the same
result.append(i) size as the number of counts,
for after in map_to_after[i]: # i.e. no count is duplicated.
before_count[after] -= 1 # Time - O(n)
if before_count[after] == 0: # Space - O(n)
no_before.add(after)
from collections import Counter
return result if len(result) == len(before_count) else []
class Solution(object):
for i in range(n): def uniqueOccurrences(self, arr):
if group[i] == -1: # make a new group for this item only """
group[i] = m :type arr: List[int]
m += 1 :rtype: bool
"""
group_items = defaultdict(set) counts = Counter(arr)
for item, gp in enumerate(group): return len(set(counts.values())) == len(counts.values())
group_items[gp].add(item)

between_groups_after = defaultdict(set) # group to set of groups


before group # python_1001_to_2000/1208_Get_Equal_Substrings_Within_Budget.py - m
groups_before_count = {gp: 0 for gp in range(m)} # group to count of groups
before _author_ = 'jake'
ordered_groups = {} # map group to list of sorted _project_ = 'leetcode'
items
# https://leetcode.com/problems/get-equal-substrings-within-budget/
for gp, items in group_items.items(): # You are given two strings s and t of the same length.
within_group_after = defaultdict(set) # item to set of items # You want to change s to t.
after item # Changing the i-th character of s to i-th character of t costs |s[i] - t[i]| that is,
items_before_count = {item: 0 for item in items} # item to count of items # the absolute difference between the ASCII values of the characters.
before # You are also given an integer maxCost.
# Return the maximum length of a substring of s that can be changed to be the same as the
for item in items: corresponding substring
for before_item in beforeItems[item]: # of t with a cost less than or equal to maxCost.
if before_item in items: # If there is no substring from s that can be changed to its corresponding substring from
within_group_after[before_item].add(item) t, return 0.
items_before_count[item] += 1
else: # Maintain a sliding window of a substring with cost < maxCost.
if group[item] not in between_groups_after[group[before_item]]: # # Iterate along the strings, adding the cost of changing the current character to the
do not double count window cost.
groups_before_count[group[item]] += 1 # While the window cost is more than maxCost, remove characters from the front of the
between_groups_after[group[before_item]].add(group[item]) window.
# Time - O(n)
ordered_items = top_sort(within_group_after, items_before_count) # Space - O(1)
if not ordered_items:
return [] class Solution(object):
ordered_groups[gp] = ordered_items def equalSubstring(self, s, t, maxCost):
"""
group_ordering = top_sort(between_groups_after, groups_before_count) :type s: str
if not group_ordering: :type t: str
return [] :type maxCost: int
:rtype: int
result = [] """

start = 0 # The snake wants to reach the lower right corner at (n-1, n-2) and (n-1, n-1).
cost, result = 0, 0 # In one move the snake can:
# Move one cell to the right if there are no blocked cells there.
for i, (c1, c2) in enumerate(zip(s, t)): # This move keeps the horizontal/vertical position of the snake as it is.
cost += abs(ord(c1) - ord(c2)) # Move down one cell if there are no blocked cells there.
while cost > maxCost: # This move keeps the horizontal/vertical position of the snake as it is.
cost -= abs(ord(s[start]) - ord(t[start])) # Rotate clockwise if it's in a horizontal position and the two cells under it are both
start += 1 empty.
result = max(result, i - start + 1) # In that case the snake moves from (r, c) and (r, c+1) to (r, c) and (r+1, c).
# Rotate counterclockwise if it's in a vertical position and the two cells to its right
return result are both empty.
# In that case the snake moves from (r, c) and (r+1, c) to (r, c) and (r, c+1).
# Return the minimum number of moves to reach the target.
# If there is no way to reach the target, return -1.
# python_1001_to_2000/1209_Remove_All_Adjacent_Duplicates_in_String_II.py - m
# Breadth-first search.
_author_ = 'jake' # Frontier consists of a set of states signifying the head position and whether the snake
_project_ = 'leetcode' is horizontal.
# For each move, update the frontier with all possible next states depending on the
# https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/ orientation and whether
# Given a string s, a k duplicate removal consists of choosing k adjacent and equal # neighbouring cells are in the grid and unoccupied.
letters from s # Set of seen states avoids repetition.
# and removing them causing the left and the right side of the deleted substring to # Time - O(mn)
concatenate together. # Space - O(mn)
# We repeatedly make k duplicate removals on s until we no longer can.
# Return the final string after all such duplicate removals have been made. class Solution(object):
# It is guaranteed that the answer is unique. def minimumMoves(self, grid):
"""
# Maintain a stack of [char, count of identical chars in sequence]. :type grid: List[List[int]]
# Iterate over s, updating the count of the top of stack if it's the same as the current :rtype: int
char. """
# If k chars are in sequence, pop them off the stack. rows, cols = len(grid), len(grid[0])
# If the current char is different from the top of stack, add the new char to stack with moves = 0
count of 1. seen = set()
# Time - O(n) frontier = {(0, 1, True)} # (row of head, col of head, is horizontal)
# Space - O(n)
while frontier:
class Solution(object): if (rows - 1, cols - 1, True) in frontier:
def removeDuplicates(self, s, k): return moves
"""
:type s: str new_frontier = set()
:type k: int for r, c, horizontal in frontier:
:rtype: str if (r, c, horizontal) in seen:
""" continue
stack = [] # stack of [char, sequence length]
if horizontal and c != cols - 1 and grid[r][c + 1] == 0:
for c in s: new_frontier.add((r, c + 1, True))
if stack and stack[-1][0] == c: # extend sequence of same char if not horizontal and r != rows - 1 and grid[r + 1][c] == 0:
if stack[-1][1] == k - 1: # remove sequence of k chars new_frontier.add((r + 1, c, False))
stack.pop()
else: if horizontal and r != rows - 1 and grid[r + 1][c] == 0 and grid[r + 1][c
stack[-1][1] += 1 - 1] == 0:
else: new_frontier.add((r + 1, c, True)) # down
stack.append([c, 1]) new_frontier.add((r + 1, c - 1, False)) # clockwise rotation

return "".join(c * count for c, count in stack) # join remaining stack if not horizontal and c != cols - 1 and grid[r][c + 1] == 0 and grid[r -
1][c + 1] == 0:
new_frontier.add((r, c + 1, False)) # right
new_frontier.add((r - 1, c + 1, True)) # anti-clockwise rotation

# python_1001_to_2000/1210_Minimum_Moves_to_Reach_Target_with_Rotations.py - h seen |= frontier


frontier = new_frontier
_author_ = 'jake' moves += 1
_project_ = 'leetcode'
return -1
# 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/1213_Intersection_of_Three_Sorted_Arrays.py
if target - node.val in seen:
_author_ = 'jake' return True
_project_ = 'leetcode' return find(node.left) or find(node.right)

# https://leetcode.com/problems/intersection-of-three-sorted-arrays/ return find(root2)


# Given three integer arrays arr1, arr2 and arr3 sorted in strictly increasing order,
# return a sorted array of only the integers that appeared in all three arrays.

# Count the frequency across all arrays. # python_1001_to_2000/1215_Stepping_Numbers.py - m


# Return the items that occur 3 times.
# This works because the arrays are strictly increasing, i.e. no duplicates. _author_ = 'jake'
# Also works if the arrays are not sorted. _project_ = 'leetcode'
# Time - O(n)
# Space - O(n) # https://leetcode.com/problems/stepping-numbers/
# A Stepping Number is an integer such that all of its adjacent digits have an absolute
from collections import Counter difference of exactly 1.
# For example, 321 is a Stepping Number while 421 is not.
class Solution(object): # Given two integers low and high,
def arraysIntersection(self, arr1, arr2, arr3): # find and return a sorted list of all the Stepping Numbers in the range [low, high]
""" inclusive.
:type arr1: List[int]
:type arr2: List[int] # Breadth-first search, starting with single digit integers.
:type arr3: List[int] # For each number in the frontier, reject if greater than high and add to result if
:rtype: List[int] greater than or equal to low.
""" # Extend the number with its final digit - 1 and final digit + 1, unless this would be <
return [i for i, count in Counter(arr1 + arr2 + arr3).items() if count == 3] 0 or > 9.
# Repeat until there are no more numbers to extend.
# Time - O(n)
# Space - O(n)
# python_1001_to_2000/1214_Two_Sum_BSTs.py - m
class Solution(object):
_author_ = 'jake' def countSteppingNumbers(self, low, high):
_project_ = 'leetcode' """
:type low: int
# https://leetcode.com/problems/two-sum-bsts/ :type high: int
# Given two binary search trees, return True if and only if there is a node in the first :rtype: List[int]
tree and a node in """
# the second tree whose values sum up to a given integer target. result = []
if low == 0: # do not add zero unless low is 0, since we cannot start
# Explore the first tree by depth-first search, adding all values to a set. other integers with 0
# Explore the second tree by depth-first search, checking for each node if its complement result.append(0)
to sum to target is in the
# set of values from the first tree. nums = [i for i in range(1, 10)]
# 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. while nums:
# Space - O(m + n) new_nums = []
for num in nums:
class Solution(object): if num > high:
def twoSumBSTs(self, root1, root2, target): continue
""" if num >= low:
:type root1: TreeNode result.append(num)
:type root2: TreeNode last_digit = num % 10
:type target: int if last_digit != 0:
:rtype: bool new_nums.append(num * 10 + last_digit - 1)
""" if last_digit != 9:
seen = set() new_nums.append(num * 10 + last_digit + 1)

def explore(node): nums = new_nums


if not node:
return return result
seen.add(node.val)
explore(node.left)
explore(node.right)

explore(root1) # python_1001_to_2000/1216_Valid_Palindrome_III.py - h

def find(node): _author_ = 'jake'


if not node: _project_ = 'leetcode'
return False

# https://leetcode.com/problems/valid-palindrome-iii/ for chip in chips:


# Given a string s and an integer k, find out if the given string is a K-Palindrome or if chip % 2 == 0:
not. evens += 1
# A string is K-Palindrome if it can be transformed into a palindrome by removing at most else:
k characters from it. odds += 1

# Helper function returns the number of removals to transform the string between s[start] return min(evens, odds)
and s[end], inclusive.
# If s[start] is the same as s[end], recurse without both ends.
# Else take the best case of removing either start or end.
# Memoize to avoid repetition. # python_1001_to_2000/1218_Longest_Arithmetic_Subsequence_of_Given_Difference.py - m
# Time - O(n**2)
# Space - O(n**2) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def isValidPalindrome(self, s, k): # https://leetcode.com/problems/longest-arithmetic-subsequence-of-given-difference/
""" # Given an integer array arr and an integer difference,
:type s: str # return the length of the longest subsequence in arr which is an arithmetic sequence
:type k: int such that
:rtype: bool # the difference between adjacent elements in the subsequence equals difference.
"""
memo = {} # Create a map from each number in the array to the maximum length of any subsequence
ending with that number.
def helper(start, end): # Iterate over the array, updating the map by extending the sequence ending with num -
if start >= end: # <= 1 char is a palindrome difference.
return 0 # If num - difference is not in the map then we start a new sequence of length 1.
if (start, end) in memo: # Return the greatest length.
return memo[(start, end)] # Time - O(n)
# Space - O(n)
if s[start] == s[end]:
result = helper(start + 1, end - 1) from collections import defaultdict
else:
result = 1 + min(helper(start + 1, end), helper(start, end - 1)) class Solution(object):
def longestSubsequence(self, arr, difference):
memo[(start, end)] = result """
return result :type arr: List[int]
:type difference: int
return helper(0, len(s) - 1) <= k :rtype: int
"""
num_to_length = defaultdict(int)

# python_1001_to_2000/1217_Play_with_Chips.py for num in arr:


num_to_length[num] = num_to_length[num - difference] + 1
_author_ = 'jake'
_project_ = 'leetcode' return max(num_to_length.values())

# https://leetcode.com/problems/play-with-chips/
# There are some chips, and the i-th chip is at position chips[i].
# You can perform any of the two following types of moves any number of times (possibly # python_1001_to_2000/1219_Path_with_Maximum_Gold.py - m
zero) on any chip:
# Move the i-th chip by 2 units to the left or to the right with a cost of 0. _author_ = 'jake'
# Move the i-th chip by 1 unit to the left or to the right with a cost of 1. _project_ = 'leetcode'
# There can be two or more chips at the same position initially.
# Return the minimum cost needed to move all the chips to the same position (any # https://leetcode.com/problems/path-with-maximum-gold/
position). # 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
# Count the number of chips at odd and even positions. if it is empty.
# All chips within each group can be moved to the same position at no cost. # Return the maximum amount of gold you can collect under the conditions:
# Move the smaller group to the larger group, costing the size of the smaller group. # Every time you are located in a cell you will collect all the gold in that cell.
# Time - O(n) # From your position you can walk one step to the left, right, up or down.
# Space - O(1) # You can't visit the same cell more than once.
# Never visit a cell with 0 gold.
class Solution(object): # You can start and stop collecting gold from any position in the grid that has some
def minCostToMoveChips(self, chips): gold.
"""
:type chips: List[int] # For each starting position, perform depth-first search to find the maximum gold.
:rtype: int # 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.
evens, odds = 0, 0 # Return the best result from all 4 neighbours and reset the gold in the visited cell.
# Time - O(m**2 * n**2) new_counts["i"] = counts["e"] + counts["o"]
# Space - O(mn) new_counts["o"] = counts["i"]
new_counts["u"] = counts["i"] + counts["o"]
class Solution(object): counts = new_counts
def getMaximumGold(self, grid):
""" return sum(counts.values()) % (10 ** 9 + 7)
:type grid: List[List[int]]
:rtype: int
"""
rows, cols = len(grid), len(grid[0]) # python_1001_to_2000/1221_Split_a_String_in_Balanced_Strings.py
neighbours = [[1, 0], [0, 1], [-1, 0], [0, -1]]
_author_ = 'jake'
def helper(r, c): _project_ = 'leetcode'
if r < 0 or r >= rows or c < 0 or c >= cols:
return 0 # https://leetcode.com/problems/split-a-string-in-balanced-strings/
if grid[r][c] == 0: # Balanced strings are those who have equal quantity of 'L' and 'R' characters.
return 0 # Given a balanced string s split it in the maximum amount of balanced strings.
# Return the maximum amount of splitted balanced strings.
gold = best = grid[r][c]
grid[r][c] = 0 # delete gold from visited cell # Keep a running net balance of "L" - "R" when iterating over s.
for dr, dc in neighbours: # Update the result whenever the balance is zero.
best = max(best, gold + helper(r + dr, c + dc)) # Time - O(n)
# Space - O(1)
grid[r][c] = gold # reset the gold in this cell
return best class Solution(object):
def balancedStringSplit(self, s):
result = 0 """
for r in range(rows): :type s: str
for c in range(cols): :rtype: int
result = max(result, helper(r, c)) """
balance = 0
return result result = 0

for c in s:
balance += 1 if c == "L" else -1
# python_1001_to_2000/1220_Count_Vowels_Permutation.py - h if balance == 0:
result += 1
_author_ = 'jake'
_project_ = 'leetcode' return result

# https://leetcode.com/problems/count-vowels-permutation/
# Given an integer n, your task is to count how many strings of length n can be formed
under the following rules: # python_1001_to_2000/1222_Queens_That_Can_Attack_the_King.py - m
# Each character is a lower case vowel ('a', 'e', 'i', 'o', 'u')
# Each vowel 'a' may only be followed by an 'e'. _author_ = 'jake'
# Each vowel 'e' may only be followed by an 'a' or an 'i'. _project_ = 'leetcode'
# Each vowel 'i' may not be followed by another 'i'.
# Each vowel 'o' may only be followed by an 'i' or a 'u'. # https://leetcode.com/problems/queens-that-can-attack-the-king/
# Each vowel 'u' may only be followed by an 'a'. # On an 8x8 chessboard, there can be multiple Black Queens and one White King.
# Since the answer may be too large, return it modulo 10^9 + 7. # Given an array of integer coordinates queens that represents the positions of the Black
Queens,
# Create a mapping from each vowel to the number of permutations ending with that vowel. # and a pair of coordinates king that represent the position of the White King,
# For each new letter, update the permutations from all previous vowels that can be # return the coordinates of all the queens (in any order) that can attack the King.
followed by the new vowel.
# Time - O(n) # For each of the 8 directions outwards from the king, move until a queen is reaches or
# Space - O(1) the edge of the board.
# Time - O(1), since board is 8 x 8
class Solution(object): # Space - O(1)
def countVowelPermutation(self, n):
""" class Solution(object):
:type n: int def queensAttacktheKing(self, queens, king):
:rtype: int """
""" :type queens: List[List[int]]
counts = {vowel: 1 for vowel in "aeiou"} # 1 permutation for each letter :type king: List[int]
:rtype: List[List[int]]
for _ in range(n - 1): """
new_counts = {} queen_set = {tuple(queen) for queen in queens}
new_counts["a"] = counts["e"] + counts["i"] + counts["u"]
new_counts["e"] = counts["a"] + counts["i"] result = []

for dr, dc in [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, _author_ = 'jake'
-1]]: _project_ = 'leetcode'
r, c = king
while 0 <= r + dr < 8 and 0 <= c + dc < 8: # https://leetcode.com/problems/maximum-equal-frequency/
r += dr # Given an array nums of positive integers, return the longest possible length of an
c += dc array prefix of nums,
if (r, c) in queen_set: # such that it is possible to remove exactly one element from this prefix so that every
result.append([r, c]) number that has
break # appeared in it will have the same number of occurrences.
# If after removing one element there are no remaining elements,
return result # it's still considered that every appeared number has the same number of ocurrences (0).

# Iterate over nums, counting the occurrences of each num amd tracking the maximum count
of any num.
# python_1001_to_2000/1223_Dice_Roll_Simulation.py - h # Also maintain a mapping from the count of a num to the number of different nums with
that count.
_author_ = 'jake' # If the maximum count is 1, we can remove any num and all others appear once.
_project_ = 'leetcode' # 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
# https://leetcode.com/problems/dice-roll-simulation/ # then all numbers appear max_count - 1 times.
# A die simulator generates a random number from 1 to 6 for each roll. # If all numbers apart from one have have a count of max_count and the pther number has a
# You introduced a constraint to the generator such that it cannot roll the number i more count of 1, we can remove
than rollMax[i] # the other number so all have counts of max_count.
# (1-indexed) consecutive times. # Time - O(n)
# Given an array of integers rollMax and an integer n, # Space - O(n)
# return the number of distinct sequences that can be obtained with exact n rolls.
# Two sequences are considered different if at least one element differs from each other. from collections import defaultdict
# Since the answer may be too large, return it modulo 10^9 + 7.
class Solution(object):
# Dynamic programming. Find the number of sequences for each number of rolls and each def maxEqualFreq(self, nums):
final number. """
# A sequence ending in j after i rolls can end in any number of j from 1 to rollMax[j]. :type nums: List[int]
# For each number k of sequence ending j, we can append [j] * k to any sequence of length :rtype: int
i - k that does not end in j. """
# Time - O(m n**2), for m sides and n rolls. num_to_count, count_of_counts = defaultdict(int), defaultdict(int)
# Space - O(mn)
result = 0
class Solution(object): max_count = 0
def dieSimulator(self, n, rollMax):
""" for i, num in enumerate(nums):
:type n: int count = num_to_count[num] + 1
:type rollMax: List[int] num_to_count[num] = count
:rtype: int max_count = max(max_count, count)
"""
sides = len(rollMax) if count != 1:
# dp[i][j] is the number of ways we can end with a roll of j + 1 after i rolls count_of_counts[count - 1] -= 1 # remove previous count_of_counts
dp = [[0 for j in range(sides)] for i in range(n + 1)] count_of_counts[count] += 1
dp_total = [0] * (n + 1) # dp_total[i] is the sum over j of dp[i][j]
if max_count == 1:
dp_total[0], dp_total[1] = 1, 6 result = i + 1
for j in range(sides): elif count_of_counts[max_count - 1] == len(num_to_count) - 1:
dp[1][j] = 1 result = i + 1
elif count_of_counts[max_count] == len(num_to_count) - 1 and
for i in range(2, n + 1): count_of_counts[1] == 1:
for j in range(sides): result = i + 1
for k in range(1, rollMax[j] + 1): # number of consecutive rolls of j at
end of sequence return result
if i - k < 0:
break
dp[i][j] += dp_total[i - k] - dp[i - k][j] # sequences of length i -
k that do not end in k # python_1001_to_2000/1227_Airplane_Seat_Assignment_Probability.py - m
dp_total[i] = sum(dp[i])
_author_ = 'jake'
return dp_total[n] % (10 ** 9 + 7) _project_ = 'leetcode'

# https://leetcode.com/problems/airplane-seat-assignment-probability/
# n passengers board an airplane with exactly n seats.
# python_1001_to_2000/1224_Maximum_Equal_Frequency.py - h # The first passenger has lost the ticket and picks a seat randomly.
# But after that, the rest of passengers will: # It is guaranteed that no two availability slots of the same person intersect with each
# Take their own seat if it is still available, other.
# Pick other seats randomly when they find their seat occupied # That is, for any two time slots [start1, end1] and [start2, end2] of the same person,
# What is the probability that the n-th person can get his own seat? # either start1 > end2 or start2 > end1.

# For n > 1, the first person chooses their own seat with probability 1 / n, # Sort both lists by ascending start time.
# in which case everybody gets their own seat. # Use pointers i and j to the next slot in each list.
# Else the next person chooses the first person's seat with probability 1 /(n - 1) and # While neither pointer is at the end, find the overlapping time of the current slots.
# everybody else gets their own seat. Summing the series results in 0.5. # If this is long enough, return the meeting.
# Time - O(1) # Else move the pointer forward for the slot with the earlier start.
# Space - O(1) # Time - O(m log m + n log n)
# Space - O(m + n)
class Solution(object):
def nthPersonGetsNthSeat(self, n): class Solution(object):
""" def minAvailableDuration(self, slots1, slots2, duration):
:type n: int """
:rtype: float :type slots1: List[List[int]]
""" :type slots2: List[List[int]]
return 1 if n == 1 else 0.5 :type duration: int
:rtype: List[int]
"""
i, j = 0, 0
# python_1001_to_2000/1228_Missing_Number_In_Arithmetic_Progression.py m, n = len(slots1), len(slots2)
slots1.sort()
_author_ = 'jake' slots2.sort()
_project_ = 'leetcode'
while i < m and j < n:
# https://leetcode.com/problems/missing-number-in-arithmetic-progression/ # earliest finish - latest start
# In some array arr, the values were in arithmetic progression: latest_start = max(slots1[i][0], slots2[j][0])
# the values arr[i+1] - arr[i] are all equal for every 0 <= i < arr.length - 1. overlap = min(slots1[i][1], slots2[j][1]) - latest_start
# Then, a value from arr was removed that was not the first or last value in the array. if overlap >= duration:
# Return the removed value. return [latest_start, latest_start + duration]

# If the first difference is twice the second difference, then the missing value should if slots1[i][0] <= slots2[j][0]:
be second. i += 1
# Else if any difference is twice the first difference, the missing value is between the else:
current values. j += 1
# Time - O(n)
# Space - O(1) return []

class Solution(object):
def missingNumber(self, arr):
""" # python_1001_to_2000/1230_Toss_Strange_Coins.py - m
:type arr: List[int]
:rtype: int _author_ = 'jake'
""" _project_ = 'leetcode'
first_diff = arr[1] - arr[0]
if first_diff == 2 * (arr[2] - arr[1]): # https://leetcode.com/problems/toss-strange-coins/
return arr[0] + first_diff // 2 # You have some coins. The i-th coin has a probability prob[i] of facing heads when
tossed.
for i in range(1, len(arr) - 1): # Return the probability that the number of coins facing heads equals target if you toss
if (arr[i + 1] - arr[i]) == first_diff * 2: every coin exactly once.
return arr[i] + first_diff
# Dynamic programming. Given the probability of each number of heads from n - 1 tosses,
# we calculate the probability of each number of heads from n tosses.
# 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.
# python_1001_to_2000/1229_Meeting_Scheduler.py - m # Time - O(n**2)
# Space - O(n)
_author_ = 'jake'
_project_ = 'leetcode' class Solution(object):
def probabilityOfHeads(self, prob, target):
# https://leetcode.com/problems/meeting-scheduler/ """
# Given the availability time slots arrays slots1 and slots2 of two people and a meeting :type prob: List[float]
duration duration, :type target: int
# return the earliest time slot that works for both of them and is of duration duration. :rtype: float
# 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] probs = [1] # probs[i] is probability of i heads, initially from 0 tosses
# representing an inclusive time range from start to end.

for coin in prob: # python_1001_to_2000/1232_Check_If_It_Is_a_Straight_Line.py


new_probs = [0] * (len(probs) + 1)
for heads, p in enumerate(probs[:target + 1]): _author_ = 'jake'
new_probs[heads] += p * (1 - coin) _project_ = 'leetcode'
new_probs[heads + 1] += p * coin
# https://leetcode.com/problems/check-if-it-is-a-straight-line/
probs = new_probs # You are given an array coordinates, coordinates[i] = [x, y], where [x, y] represents
the coordinate of a point.
return probs[target] # Check if these points make a straight line in the XY plane.

# Find the initial slope between the first 2 points.


# If the slopes between the first point and all other points are the same as the initial
# python_1001_to_2000/1231_Divide_Chocolate.py - h slope, return True.
# Time - O(n)
_author_ = 'jake' # Space - O(1)
_project_ = 'leetcode'
class Solution(object):
# https://leetcode.com/problems/divide-chocolate/ def checkStraightLine(self, coordinates):
# You have one chocolate bar that consists of some chunks. """
# Each chunk has its own sweetness given by the array sweetness. :type coordinates: List[List[int]]
# You want to share the chocolate with your K friends so you start cutting the chocolate :rtype: bool
bar into K+1 """
# pieces using K cuts, each piece consists of some consecutive chunks. if len(coordinates) < 3: # 1 or 2 points are always on a line.
# Being generous, you will eat the piece with the minimum total sweetness and give the return True
other pieces to your friends.
# Find the maximum total sweetness of the piece you can get by cutting the chocolate bar x_diff = coordinates[1][0] - coordinates[0][0] # keep diffs since gradient is a
optimally. float
y_diff = coordinates[1][1] - coordinates[0][1]
# Binary search the range of possible results.
# For each guess, check whether it is possible to split the bar into at least K pieces for x, y in coordinates[2:]:
with each piece having at dx = x - coordinates[0][0]
# least guess sweetness. dy = y - coordinates[0][1]
# If it is possible, the guess is the new lower bound, ele the new upper bound is less if x_diff * dy != y_diff * dx:
than guess. return False
# Time - O(n log m) for n pieces and m total sweetness
# Space - O(1) return True

class Solution(object):
def maximizeSweetness(self, sweetness, K):
""" # python_1001_to_2000/1233_Remove_Sub-Folders_from the_Filesystem.py - m
:type sweetness: List[int]
:type K: int _author_ = 'jake'
:rtype: int _project_ = 'leetcode'
"""
K += 1 # add piece for myself # https://leetcode.com/problems/remove-sub-folders-from-the-filesystem/
left, right = 1, sum(sweetness) // K # possible result bounds (inclusive) # Given a list of folders, remove all sub-folders in those folders and return in any
order the folders after removing.
def can_split(x): # can split into >= K pieces with at least x # If a folder[i] is located within another folder[j], it is called a sub-folder of it.
sweetness per piece? # The format of a path is one or more concatenated strings of the form:
piece, count = 0, 0 # / followed by one or more lowercase English letters.
for sweet in sweetness: # For example, /leetcode and /leetcode/problems are valid paths while an empty string and
piece += sweet / are not.
if piece >= x:
count += 1 # Insert the paths in a trie in order of increasing length.
piece = 0 # Signify the terminal node when a path is fully inserted.
# If a path reaches a node that is already terminal, it is a subfolder.
return count >= K # Time - O(n log n) for n folders.
# Space - O(n)
while left < right:
mid = (left + right + 1) // 2 class Solution(object):
if can_split(mid): def removeSubfolders(self, folder):
left = mid """
else: :type folder: List[str]
right = mid - 1 :rtype: List[str]
"""
return left paths = [f.split("/") for f in folder]
paths.sort(key=len)
result = []
root = {}
start += 1
for i, path in enumerate(paths):
return result
node = root
for level in path[1:]: # path[0] is empty due to leading "/"
if level not in node: # make a new node
node[level] = {} # python_1001_to_2000/1235_Maximum_Profit_in_Job_Scheduling.py - h
node = node[level]
if "TERMINAL" in node: # subfolder, do not add to result _author_ = 'jake'
break _project_ = 'leetcode'
else:
node["TERMINAL"] = {} # https://leetcode.com/problems/maximum-profit-in-job-scheduling/
result.append("/".join(path)) # We have n jobs, where every job is scheduled to be done from startTime[i] to
endTime[i],
return result # obtaining a profit of profit[i].
# You're given the startTime , endTime and profit arrays, you need to output the maximum
profit you
# can take such that there are no 2 jobs in the subset with overlapping time range.
# python_1001_to_2000/1234_Replace_the_Substring_for_Balanced_String.py - m # If you choose a job that ends at time X you will be able to start another job that
starts at time X.
_author_ = 'jake'
_project_ = 'leetcode' # Dynamic programming. Build a list of [end_time, max_profit] for the profit that can be
made by end_time,
# https://leetcode.com/problems/replace-the-substring-for-balanced-string/ # where profit is strictly ascending.
# You are given a string containing only 4 kinds of characters 'Q', 'W', 'E' and 'R'. # Zip the end, start and profits together into tuples and sort by ascending end time.
# A string is said to be balanced if each of its characters appears n/4 times where n is # For each start time, find the max profit that can be made for all previous jobs
the length of the string. finishing at or before that end time.
# Return the minimum length of the substring that can be replaced with any other string # If that previous profit + the job profit is more than the best profit, append
of the same [end_time, max_profit] to the
# length to make the original string s balanced. # dynamic programming list.
# Return 0 if the string is already balanced. # Time - O(n log n)
# Space - O(n)
# For each char of s, count the excess chars above the balanced expectation (n / 4).
# Then iterate over s. import bisect
# If a char has an excess count, decrement the excess count since it is now in the
replacement substring. class Solution(object):
# If/while there are no excess chars, update the result, move the start of the subtring def jobScheduling(self, startTime, endTime, profit):
forwards and increment any """
# excess chars that are no longer in the substring. :type startTime: List[int]
# Time - O(n), since to check all values of excess is O(1) because it has at most 26 :type endTime: List[int]
elements. :type profit: List[int]
# Space - O(1) :rtype: int
"""
from collections import Counter dp = [[0, 0]] # list of [end_time, max_profit] with ascending max_profit

class Solution(object): jobs = sorted(zip(endTime, startTime, profit))


def balancedString(self, s):
""" for end, start, gain in jobs:
:type s: str i = bisect.bisect_right(dp, [start, float("inf")])
:rtype: int if gain + dp[i - 1][1] > dp[-1][1]:
""" dp.append([end, gain + dp[i - 1][1]])
balance = len(s) // 4
excess = {} return dp[-1][1]
for c, count in Counter(s).items():
if count - balance > 0:
excess[c] = count - balance
if not excess: # python_1001_to_2000/1236_Web_Crawler.py
return 0
_author_ = 'jake'
start = 0 _project_ = 'leetcode'
result = len(s)
# https://leetcode.com/problems/web-crawler/
for end, c in enumerate(s): # Given a url startUrl and an interface HtmlParser,
if c in excess: # implement a web crawler to crawl all links that are under the same hostname as
excess[c] -= 1 startUrl.
while all(v <= 0 for v in excess.values()): # Return all urls obtained by your web crawler in any order.
result = min(result, end - start + 1) # Your crawler should:
if s[start] in excess: # Start from the page: startUrl
excess[s[start]] += 1 # Call HtmlParser.getUrls(url) to get all urls from a webpage of given url.

# Do not crawl the same link twice. # You may return the solutions in any order.
# Explore only the links that are under the same hostname as startUrl.
# For each value of x, try all values of y until the function returns more than z.
# Find the hostname from startUrl. # When it returns more than z, increment x and again try all values of y.
# Depth-first search the web by checking is a url has not been seen and had the correct # Repeat for all values of x.
hostname. # Time - O(mn)
# If so, add it to the result and recurse for all links. # Space - O(1)
# Time - O(m + n) for m links and n urls.
# Space - O(m + n) class Solution(object):
def findSolution(self, customfunction, z):
class Solution(object): """
def crawl(self, startUrl, htmlParser): :type num: int
""" :type z: int
:type startUrl: str :rtype: List[List[int]]
:type htmlParser: HtmlParser """
:rtype: List[str] result = []
"""
PREFIX = "http://" for i in range(1, 101):
n = len(PREFIX) for j in range(1, 101):
temp = customfunction.f(i, j)
def get_host_and_path(url): if temp == z:
suffix = url[n:] result.append([i, j])
if "/" not in suffix: elif temp > z:
return [suffix, ""] break
return suffix.split("/", 1)
return result
start_host, _ = get_host_and_path(startUrl)
results = set()

def dfs(url): # python_1001_to_2000/1238_Circular_Permutation_in_Binary_Representation.py - m


if url in results:
return _author_ = 'jake'
_project_ = 'leetcode'
host, path = get_host_and_path(url)
if host != start_host: # https://leetcode.com/problems/circular-permutation-in-binary-representation/
return # Given 2 integers n and start. Your task is return any permutation p of (0,1,2.....,2^n
-1) such that :
results.add(url) # p[0] = start
for next_url in htmlParser.getUrls(url): # p[i] and p[i+1] differ by only one bit in their binary representation.
dfs(next_url) # p[0] and p[2^n -1] must also differ by only one bit in their binary representation.

dfs(startUrl) # Find a permutation starting from 0, then move the part from start to the front.
return list(results) # 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.
# Time - O(2 ** n)
# Space - O(2 ** n)

class Solution(object):
# python_1001_to_2000/1237_Find_Positive_Integer_Solution_for_a_Given_Equation.py - m def circularPermutation(self, n, start):
"""
_author_ = 'jake' :type n: int
_project_ = 'leetcode' :type start: int
:rtype: List[int]
# https://leetcode.com/problems/find-positive-integer-solution-for-a-given-equation/ """
# Given a function f(x, y) and a value z, return all positive integer pairs x and y def helper(i):
where f(x,y) == z. if i == 1:
# The function is constantly increasing, i.e.: return [0, 1]
# f(x, y) < f(x + 1, y) temp = helper(i - 1)
# f(x, y) < f(x, y + 1) power = 2 ** (i - 1)
# The function interface is defined like this: return temp + [power + t for t in temp[::-1]]
# interface CustomFunction {
# public: perms = helper(n)
# // Returns positive integer f(x, y) for any given positive integer x and y. i = perms.index(start)
# int f(int x, int y); return perms[i:] + perms[:i]
# };
# For custom testing purposes you're given an integer function_id and a target z as
input,
# where function_id represent one function from an secret internal list. #
python_1001_to_2000/1239_Maximum_Length_of_a_Concatenated_String_with_Unique_Characters.p if state in memo:
y - m return memo[state]

_author_ = 'jake' min_height = min(state)


_project_ = 'leetcode' start = state.index(min_height)
result = cols * rows
# https://leetcode.com/problems/maximum-length-of-a-concatenated-string-with-unique-
characters/ state_list = list(state)
# Given an array of strings arr. for end in range(start, cols):
# String s is a concatenation of a sub-sequence of arr which have unique characters. if state[end] != min_height:
# Return the maximum possible length of s. break
side = end - start + 1
# Remove all words with duplicated letters and convert words to sets of letters. if min_height + side > rows: # insufficient height
# For each set of chars, check overlap with each previous result. break
# If there is no overlap, append the combined char set to the previous results. state_list[start: end + 1] = [min_height + side] * side
# Time - O(mn) for n words of length m, since length of dp is bounded by alphabet size. result = min(result, dp(tuple(state_list)))
# Space - O(n)
memo[state] = result + 1
class Solution(object): return result + 1
def maxLength(self, arr):
""" return dp(tuple([0] * cols))
:type arr: List[str]
:rtype: int
""" # python_1001_to_2000/1243_Array_Transformation.py
char_sets = [set(s) for s in arr if len(s) == len(set(s))]
dp = [set()] # candidate resulting sets of chars after using each word _author_ = 'jake'
_project_ = 'leetcode'
for char_set in char_sets:
for prev_char_set in dp[:]: # https://leetcode.com/problems/array-transformation/
combo = char_set | prev_char_set # Given an initial array arr, every day you produce a new array using the array of the
if len(combo) == len(char_set) + len(prev_char_set): previous day.
dp.append(combo) # On the i-th day, you do the following operations on the array of day i-1 to produce the
array of day i:
return max(len(char_set) for char_set in dp) # If an element is smaller than both its left neighbor and its right neighbor, then this
element is incremented.
# If an element is bigger than both its left neighbor and its right neighbor, then this
element is decremented.
# The first and last elements never change.
# python_1001_to_2000/1240_Tiling_a_Rectangle_with_the_Fewest_Squares.py - h # After some days, the array does not change. Return that final array.

_author_ = 'jake' # While the previous array was modified, decrement any peaks and increment any troughs.
_project_ = 'leetcode' # If any element was changed, update the flag so we check again until nothing is changed.
# Time - O(mn) for max value m of n elements
# https://leetcode.com/problems/tiling-a-rectangle-with-the-fewest-squares/ # Space - O(n)
# Given a rectangle of size n x m, find the minimum number of integer-sided squares that
tile the rectangle. class Solution(object):
def transformArray(self, arr):
# State consists of the height of each column already tiled. """
# Given a state, find the lowest column and its index. :type arr: List[int]
# For each adjacent column with the height of the lowest column, add a square and :rtype: List[int]
recurse. """
# Time - O(m**3 n), mn possible states each taking O(m ** 2) to construct changed = True # flag, true so we enter the while loop at least once
# Space - O(m**2 n)
while changed:
class Solution(object): new_arr = arr[:]
def tilingRectangle(self, rows, cols): changed = False # reset
""" for i in range(1, len(arr) - 1):
:type n: int if arr[i] < arr[i - 1] and arr[i] < arr[i + 1]:
:type m: int new_arr[i] += 1
:rtype: int changed = True
""" elif arr[i] > arr[i - 1] and arr[i] > arr[i + 1]:
if cols > rows: # swap so cols <= rows new_arr[i] -= 1
cols, rows = rows, cols changed = True

memo = {} arr = new_arr

def dp(state): return arr


if min(state) == rows: # each col has height of rows
return 0

leaf or leaves.
# For each leaf removed, add new leaves if the neighbour then has only one neighbour.
# python_1001_to_2000/1244_Design_A_Leaderboard.py - m # Repeat until no leaves remain (even result) or a final pair of leaves (odd result).
# Time - O(m + n)
_author_ = 'jake' # Space - O(m + n)
_project_ = 'leetcode'
from collections import defaultdict
# https://leetcode.com/problems/design-a-leaderboard/
# Design a Leaderboard class, which has 3 functions: class Solution(object):
# addScore(playerId, score): Update the leaderboard by adding score to the given player's def treeDiameter(self, edges):
score. """
# If there is no player with such id in the leaderboard, add him to the leaderboard with :type edges: List[List[int]]
the given score. :rtype: int
# 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. node_to_nbors = defaultdict(set)
# It is guaranteed that the player was added to the leaderboard before calling this for a, b in edges:
function. node_to_nbors[a].add(b)
# Initially, the leaderboard is empty. node_to_nbors[b].add(a)

# Map the user to a score. leaves = {node for node, nbors in node_to_nbors.items() if len(nbors) == 1}
# Make a heap of the K largest values for top.
# Time - O(1) for addScore and reset, O(n log n) for top result = 0
# Space - O(n) while len(leaves) > 1:
new_leaves = set()
from collections import defaultdict for leaf in leaves:
import heapq nbor = node_to_nbors[leaf].pop()
if nbor in leaves: # node, nbor are final pair remaining
class Leaderboard(object): result += 1
break
def __init__(self):
self.user_score = defaultdict(int) node_to_nbors[nbor].remove(leaf)
if len(node_to_nbors[nbor]) == 1:
def addScore(self, playerId, score): new_leaves.add(nbor)
""" else:
:type playerId: int result += 2 # path extends in both directions
:type score: int
:rtype: None leaves = new_leaves
"""
self.user_score[playerId] += score return result

def top(self, K):


"""
:type K: int
:rtype: int # python_1001_to_2000/1246_Palindrome_Removal.py - h
"""
return sum(heapq.nlargest(K, self.user_score.values())) _author_ = 'jake'
_project_ = 'leetcode'
def reset(self, playerId):
""" # https://leetcode.com/problems/palindrome-removal/
:type playerId: int # Given an integer array arr, in one move you can select a palindromic subarray
:rtype: None # arr[i], arr[i+1], ..., arr[j] where i <= j, and remove that subarray from the given
""" array.
del self.user_score[playerId] # Note that after removing a subarray, the elements on the left and on the right of that
subarray move
# to fill the gap left by the removal.
# Return the minimum number of moves needed to remove all numbers from the array.
# python_1001_to_2000/1245_Tree_Diameter.py - m
# For each subarray there are 3 cases:
_author_ = 'jake' # 1) We can always remove each integer individually.
_project_ = 'leetcode' # 2) If the last 2 integers are the same, we can remove them together and then find the
result from the remainder.
# https://leetcode.com/problems/tree-diameter/ # 3) If any other integer is the same as the last integer, we can remove them and all the
# Given an undirected tree, return its diameter: the number of edges in a longest path in integers between for the same
that tree. # cost of removing all integers between.
# The tree is given as an array of edges where edges[i] = [u, v] is a bidirectional edge # Time - O(n**3)
between nodes u and v. # Space - O(n**2)
# Each node has labels in the set {0, 1, ..., edges.length}.
class Solution(object):
# Repeatedly remove leaves (nodes with one neighbour) from the tree to find the centroid def minimumMoves(self, arr):
""" s1_excess_x = not s1_excess_x # toggle flag
:type arr: List[int] else:
:rtype: int if s1_excess_y:
""" result += 1
memo = {} # memo[(i, j)] is the result for arr[i:j + 1] s1_excess_y = not s1_excess_y

def dp(i, j): if s1_excess_x ^ s1_excess_y: # cannot equalize if only x or y are in excess
if i > j: return -1
return 0 return result + int(s1_excess_x) + int(s1_excess_y) # swap "xy" and "yx" to "xy"
if (i, j) in memo: and "xy" in 2 moves
return memo[(i, j)]

result = dp(i, j - 1) + 1 # remove each number individually # python_1001_to_2000/1248_Count_Number_of_Nice_Subarrays.py - m

if arr[j] == arr[j - 1]: _author_ = 'jake'


result = min(result, dp(i, j - 2) + 1) _project_ = 'leetcode'

for k in range(i, j - 1): # https://leetcode.com/problems/count-number-of-nice-subarrays/


if arr[j] == arr[k]: # Given an array of integers nums and an integer k.
# cost of dp(k + 1, j - 1) is the same as dp(k, j) # A subarray is called nice if there are k odd numbers on it.
result = min(result, dp(i, k - 1) + dp(k + 1, j - 1)) # Return the number of nice sub-arrays.

memo[(i, j)] = result # Find the indices of odd numbers.


return result # For each block of consecutive k indices, find the number of even indices before and
after this block.
return dp(0, len(arr) - 1) # Multiple the even indices before and after, since for each starting index we can
construct a valid subarray with
# any odd index.
# Time - O(n)
# python_1001_to_2000/1247_Minimum_Swaps_to_Make_Strings_Equal.py - m # Space - O(n)

_author_ = 'jake' class Solution(object):


_project_ = 'leetcode' def numberOfSubarrays(self, nums, k):
"""
# https://leetcode.com/problems/minimum-swaps-to-make-strings-equal/ :type nums: List[int]
# You are given two strings s1 and s2 of equal length consisting of letters "x" and "y" :type k: int
only. :rtype: int
# Your task is to make these two strings equal to each other. """
# You can swap any two characters that belong to different strings, which means: swap odds = [-1] + [i for i, num in enumerate(nums) if num % 2 == 1] + [len(nums)]
s1[i] and s2[j]. result = 0
# Return the minimum number of swaps required to make s1 and s2 equal, or return -1 if it
is impossible to do so. for j, end in enumerate(odds[k:-1], k): # ending indices of each
consecutive k odd numbers
# Iterate along the strings together, flagging when s1 contains an additional x or y ends = odds[j + 1] - end # array can end from end to
compared to s2. (excluding) next odd
# If we find an x in s1 and there is already an additional x, we can swap woth an starts = odds[j - k + 1] - odds[j - k]
additional y in s2. result += starts * ends
# Similarly if there is a y in s1 and already an additional y. return result
# Fail if only x or y has an excess at the end, else perfoma a final double swap.
# Time - O(n)
# Space - O(1)
# python_1001_to_2000/1249_Minimum_Remove_to_Make_Valid_Parentheses.py - m
class Solution(object):
def minimumSwap(self, s1, s2): _author_ = 'jake'
""" _project_ = 'leetcode'
:type s1: str
:type s2: str # https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/
:rtype: int # Given a string s of '(' , ')' and lowercase English characters.
""" # Your task is to remove the minimum number of parentheses ( '(' or ')',
s1_excess_x, s1_excess_y = False, False # in any positions ) so that the resulting parentheses string is valid and return any
result = 0 valid string.
# Formally, a parentheses string is valid if and only if:
for c1, c2 in zip(s1, s2): # It is the empty string, contains only lowercase characters, or
if c1 == c2: # It can be written as AB (A concatenated with B), where A and B are valid strings, or
continue # It can be written as (A), where A is a valid string.

if c1 == "x": # Iterate along s, adding opening brackets to a list.


if s1_excess_x: # convert "xx" and "yy" to "xy" in both strings # If we see a closing bracket without any opening bracket, it must be removed.
result += 1 # If we see a closing bracket with unmatched opening brackets, discard the matching

opening bracket.
# Finally, discard any unmatched opening brackets before reconstructing s without
discarded indices.
# Time - O(n) # python_1001_to_2000/1252_Cells_with_Odd_Values_in_a_Matrix.py
# Space - O(n)
_author_ = 'jake'
class Solution(object): _project_ = 'leetcode'
def minRemoveToMakeValid(self, s):
""" # https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/
:type s: str # Given n and m which are the dimensions of a matrix initialized by zeros and given an
:rtype: str array indices
""" # where indices[i] = [ri, ci].
opening = [] # indices of opening brackets # For each pair of [ri, ci] you have to increment all cells in row ri and column ci by 1.
removals = set() # indices of removed brackets # Return the number of cells with odd values in the matrix after applying the increment
to all indices.
for i, c in enumerate(s):
if c == "(": # Count whether the number of increments of each row and column is even or odd.
opening.append(i) # For each cell, if the XOR of the row and column increments is odd then the value is
elif c == ")": odd.
if not opening: # no matching opening # Time - O(k + mn) for k increments
removals.add(i) # Space - O(m + n)
else: # match with opening
opening.pop() class Solution(object):
def oddCells(self, n, m, indices):
removals.update(opening) # add all open but not closed brackets """
return "".join(c for i, c in enumerate(s) if i not in removals) :type n: int
:type m: int
:type indices: List[List[int]]
:rtype: int
# python_1001_to_2000/1250_Check_If_It_Is_a_Good_Array.py - h """
rows = [True] * n # True if even increments for each row
_author_ = 'jake' cols = [True] * m # True if even increments for each col
_project_ = 'leetcode'
for r, c in indices:
# https://leetcode.com/problems/check-if-it-is-a-good-array/ rows[r] = not rows[r]
# Given an array nums of positive integers. cols[c] = not cols[c]
# Your task is to select some subset of nums, multiply each element by an integer and add
all these numbers. result = 0
# The array is said to be good if you can obtain a sum of 1 from the array by any for r in range(n):
possible subset and multiplicand. for c in range(m):
# Return True if the array is good otherwise return False. result += int(rows[r] ^ cols[c])

# If 2 numbers have a common denominator greater than 1, they can only combine to make return result
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/1253_Reconstruct_a_2-Row_Binary_Matrix.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/reconstruct-a-2-row-binary-matrix/
""" # Given the following details of a matrix with n columns and 2 rows :
:type nums: List[int] # The matrix is a binary matrix, which means each element in the matrix can be 0 or 1.
:rtype: bool # 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.
def calc_gcd(a, b): # The sum of elements in the i-th column(0-indexed) is colsum[i],
while a > 0: # where colsum is given as an integer array with length n.
a, b = b % a, a # Your task is to reconstruct the matrix with upper, lower and colsum.
return b # Return it as a 2-D integer array.
# If there are more than one valid solution, any of them will be accepted.
gcd = nums[0] # If no valid solution exists, return an empty 2-D array.

for num in nums: # Iterate along colsum.


gcd = calc_gcd(num, gcd) # If colsum is 2, set both the upper and lower rows to 1 and decrement their required
if gcd == 1: counts.
return True # If colsum is 1, set the row with the greatest required count to 1.
# If we have to set more than upper or lower, or have not set all required upper or lower
return False at the end, return [].
# Time - O(n)
# Space - O(n) is_closed = 0 < r < rows - 1 and 0 < c < cols - 1 # closed if not edge of
grid
class Solution(object): grid[r][c] = 1 # set visited land to water to avoid revisiting
def reconstructMatrix(self, upper, lower, colsum): for dr, dc in nbors:
""" is_closed = closed(r + dr, c + dc) and is_closed # recurse before and
:type upper: int to ensure exploration
:type lower: int return is_closed
:type colsum: List[int]
:rtype: List[List[int]] islands = 0
""" for r in range(rows):
n = len(colsum) for c in range(cols):
upper_row, lower_row = [0] * n, [0] * n # default zeros if grid[r][c] == 0: # only explore land
islands += int(closed(r, c))
for i, col in enumerate(colsum):
return islands
if col == 2:
lower -= 1
upper -= 1
upper_row[i] = lower_row[i] = 1 # python_1001_to_2000/1255_Maximum_Score_Words_Formed_by_Letters.py - h
elif col == 1 and upper > lower: # set 1 in row with greatest required
upper -= 1 _author_ = 'jake'
upper_row[i] = 1 _project_ = 'leetcode'
elif col == 1 and upper <= lower:
lower -= 1 # https://leetcode.com/problems/maximum-score-words-formed-by-letters/
lower_row[i] = 1 # Given a list of words, list of single letters (might be repeating) and score of every
character.
if upper < 0 or lower < 0: # Return the maximum score of any valid set of words formed by using
return [] # the given letters (words[i] cannot be used two or more times).
# It is not necessary to use all characters in letters and each letter can only be used
if upper > 0 or lower > 0: once.
return [] # Score of letters 'a', 'b', 'c', ... ,'z' is given by score[0], score[1], ... ,
return [upper_row, lower_row] score[25] respectively.

# Convert each word to a score.


# If we have insufficient letters to make the word, we can only get the score from the
# python_1001_to_2000/1254_Number_of_Closed_Islands.py - m next word onwards.
# Else we can either make the word or not.
_author_ = 'jake' # If we make the word, reduce the counts of all letters in the word and recurse,
_project_ = 'leetcode' # then increment the counts after returning from recursion.
# Time - O(2 ** n)
# https://leetcode.com/problems/number-of-closed-islands/ # Space - O(n)
# Given a 2D grid consists of 0s (land) and 1s (water).
# An island is a maximal 4-directionally connected group of 0s and a closed island from collections import Counter
# is an island totally (all left, top, right, bottom) surrounded by 1s.
# Return the number of closed islands. class Solution(object):
def maxScoreWords(self, words, letters, score):
# Depth first search each land square. """
# Return boolean whether the island is closed or not. :type words: List[str]
# Base cases of water and off grid are True. :type letters: List[str]
# Explore all neighbours recursively, setting explored land to water to avoid cycles. :type score: List[int]
# Time - O(mn) :rtype: int
# Space - O(mn) """
char_counts = Counter(letters) # counts of letters that can be used
class Solution(object):
def closedIsland(self, grid): word_scores = []
""" a = ord("a")
:type grid: List[List[int]] for word in words:
:rtype: int word_scores.append(sum(score[ord(c) - a] for c in word))
"""
rows, cols = len(grid), len(grid[0]) def can_make(word_counts): # is there sufficient remaining count to make
nbors = [[1, 0], [0, 1], [-1, 0], [0, - 1]] a word?
for c, count in word_counts.items():
def closed(r, c): # explore an island and return whether it is if c not in char_counts or char_counts[c] < count:
closed return False
if r < 0 or r >= rows or c < 0 or c >= cols: return True
return True # stop exploration if off grid or water
if grid[r][c] == 1: def helper(i):
return True if i == len(words):

return 0 # 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.
not_use = helper(i + 1) # score if we do not use words[i], try i + 1 # Starting from region 1, recursively move up the tree creating the set of parents.
# Then starting from region2, recursively find each parent and if it is in region1's
word_counts = Counter(words[i]) path,
if not can_make(word_counts): # this is the smallest common region.
return not_use # cannot make this word # Time - O(n) for n regions.
# Space - O(n)
for c, count in word_counts.items():
char_counts[c] -= count # decrement counts before recurse class Solution(object):
use = word_scores[i] + helper(i + 1) def findSmallestRegion(self, regions, region1, region2):
for c, count in word_counts.items(): """
char_counts[c] += count # increment counts after recurse :type regions: List[List[str]]
:type region1: str
return max(use, not_use) :type region2: str
:rtype: str
return helper(0) """
region_to_parent = {}

for region_list in regions:


# python_1001_to_2000/1256_Encode_Number.py - m parent = region_list[0]
for region in region_list[1:]:
_author_ = 'jake' region_to_parent[region] = parent
_project_ = 'leetcode'
region1_parents = [region1]
# https://leetcode.com/problems/encode-number/ while region1_parents[-1] in region_to_parent:
# Given a non-negative integer num, Return its encoding string. region1_parents.append(region_to_parent[region1_parents[-1]]) # parent of
# The encoding is done by converting the integer to a string using a secret function last member of list
# that you should deduce from the following table:
# num encoding region1_parents = set(region1_parents)
# 0 ""
# 1 "0" while region2 not in region1_parents:
# 2 "1" region2 = region_to_parent[region2]
# 3 "00"
# 4 "01" return region2
# 5 "10"
# 6 "11"
# 7 "000"
# python_1001_to_2000/1258_Synonymous_Sentences.py - m
# Encoding is the binary representation of num + 1 without the first digit.
# Time - O(log n) _author_ = 'jake'
# Space - O(log n) _project_ = 'leetcode'

class Solution(object): # https://leetcode.com/problems/synonymous-sentences/


def encode(self, num): # Given a list of pairs of equivalent words synonyms and a sentence text,
""" # return all possible synonymous sentences sorted lexicographically.
:type num: int
:rtype: str # Group synonyms together with union-find.
""" # Each synonym is mapped to a parent. The ultimate parent is a group exemplar.
return bin(num + 1)[3:] # For each pair of synonymous words, find their parents and join their parent's groups.
# Then map each ultimate parent to all synonyms.
# For each word in the text, extend each previous result with each synonym.
# Alternatively, breadth-first search the graph of synonyms.
# python_1001_to_2000/1257_Smallest_Common_Region.py - m # Time - O(s log* m + n**2 * k**n) where s log* m is for s synonym pairs and m synonym
words and
_author_ = 'jake' # n**2 * k**n is for n words in text each with k synonyms.
_project_ = 'leetcode' # Space - O(s + n * k**n)

# https://leetcode.com/problems/smallest-common-region/ from collections import defaultdict


# You are given some lists of regions where the first region of each list includes all
other regions in that list. class Solution(object):
# Naturally, if a region X contains another region Y then X is bigger than Y. def generateSentences(self, synonyms, text):
# Also by definition a region X contains itself. """
# Given two regions region1, region2, find out the smallest region that contains both of :type synonyms: List[List[str]]
them. :type text: str
# If you are given regions r1, r2 and r3 such that r1 includes r3, :rtype: List[str]
# it is guaranteed there is no r2 such that r2 includes r3. """
# It's guaranteed the smallest region exists. parents = {} # map node to parent (map to self if no parent)
def find(s): # find ultimate parent (could also collapse)
if s not in parents:
parents[s] = s
while parents[s] != s: # python_1001_to_2000/1260_Shift_2D_Grid.py
s = parents[s]
return s _author_ = 'jake'
_project_ = 'leetcode'
for a, b in synonyms: # join groups of ultimate parents
parents[find(a)] = find(b) # https://leetcode.com/problems/shift-2d-grid/
# Given a 2D grid of size n * m and an integer k. You need to shift the grid k times.
parent_to_synonyms = defaultdict(list) # map each parent to all synonyms # In one shift operation:
for word in parents: # Element at grid[i][j] becomes at grid[i][j + 1].
parent_to_synonyms[find(word)].append(word) # Element at grid[i][m - 1] becomes at grid[i + 1][0].
# Element at grid[n - 1][m - 1] becomes at grid[0][0].
results = [[""]] # Return the 2D grid after applying shift operation k times.

for word in text.split(): # Build a new array by iterating over the indices of the existing array.
new_results = [] # Indices are from 0 to rows * cols - 1.
synonyms = parent_to_synonyms.get(find(word), [word]) # default to word of # For each index, find the shifted index - k modulo the number of indices.
no synonyms # Convert that index to a row and column to find the value to append to the new array.
for synonym in synonyms: # Time - O(mn)
for result in results: # Space - O(mn)
new_results.append(result[:] + [synonym])
results = new_results class Solution(object):
def shiftGrid(self, grid, k):
return [" ".join(result[1:]) for result in sorted(results)] # sort """
lexicographically :type grid: List[List[int]]
:type k: int
:rtype: List[List[int]]
"""
# python_1001_to_2000/1259_Handshakes_That_Don't_Cross.py - h rows, cols = len(grid), len(grid[0])
n = rows * cols
_author_ = 'jake'
_project_ = 'leetcode' result = [[]]
for i in range(n): # iterate over all indices of grid
# https://leetcode.com/problems/handshakes-that-dont-cross/ if len(result[-1]) == cols: # make a new empty row
# You are given an even number of people num_people that stand around a circle and result.append([])
# each person shakes hands with someone else, so that there are num_people / 2 handshakes prev = (i - k) % n # index of element to move here
total. r, c = divmod(prev, cols) # convert index in n to row and col
# Return the number of ways these handshakes could occur such that none of the handshakes result[-1].append(grid[r][c])
cross.
# Since this number could be very big, return the answer mod 10^9 + 7 return result

# Dynamic programming.
# For each even number of people, choose one arbitrary person and handshake with each
other person so there is an # python_1001_to_2000/1261_Find_Elements_in_a_Contaminated_Binary_Tree.py - m
# even number of people on both sides of the handshake pair.
# Sum the results for each other person, which is the product of the results for the two _author_ = 'jake'
groups on both sides _project_ = 'leetcode'
# of the handshaking pair.
# Time - O(n**2) # https://leetcode.com/problems/find-elements-in-a-contaminated-binary-tree/
# Space - O(n) # Given a binary tree with the following rules:
# root.val == 0
class Solution(object): # If treeNode.val == x and treeNode.left != null, then treeNode.left.val == 2 * x + 1
def numberOfWays(self, num_people): # If treeNode.val == x and treeNode.right != null, then treeNode.right.val == 2 * x + 2
""" # Now the binary tree is contaminated, which means all treeNode.val have been changed to
:type num_people: int -1.
:rtype: int # You need to first recover the binary tree and then implement the FindElements class:
""" # FindElements(TreeNode* root) Initializes the object with a canotaminated binary tree,
dp = [1] # dp[i] is the result for i // 2 people you need to recover it first.
# bool find(int target) Return if the target value exists in the recovered binary tree.
for people in range(2, num_people + 1, 2):
result = 0 # Recursively explore the tree by depth-first search, adding all values to a set.
for left in range(0, people - 1, 2): # number of people on the left of the # Then lookup each value.
handshake pair # Time - O(n) for __init__ and O(1) for find
result += dp[left // 2] * dp[(people - left - 2) // 2] # Space - O(n)
dp.append(result)
class FindElements(object):
return dp[-1] % (10 ** 9 + 7) def __init__(self, root):

""" candidates.append(total - rem_2[0])


:type root: TreeNode if len(rem_1) >= 2:
""" candidates.append(total - sum(rem_1[:2]))
self.elements = set()
return max(candidates)
def helper(node, val): # explore tree from node with correct value val
if not node:
return
self.elements.add(val) # python_1001_to_2000/1263_Minimum_Moves_to_Move_a_Box_to_Their_Target_Location.py - h
helper(node.left, 2 * val + 1)
helper(node.right, 2 * val + 2) _author_ = 'jake'
_project_ = 'leetcode'
helper(root, 0)
# https://leetcode.com/problems/minimum-moves-to-move-a-box-to-their-target-location/
def find(self, target): # Storekeeper is a game in which the player pushes boxes around in a warehouse trying to
""" get them to target locations.
:type target: int # The game is represented by a grid of size n*m, where each element is a wall, floor, or
:rtype: bool a box.
""" # Your task is move the box 'B' to the target position 'T' under the following rules:
return target in self.elements # Player is represented by character 'S' and can move up, down, left, right in the grid
if it is a floor (empty cell).
# Floor is represented by character '.' that means free cell to walk.
# python_1001_to_2000/1262_Greatest_Sum_Divisible_by_Three.py - m # Wall is represented by character '#' that means obstacle (impossible to walk there).
# There is only one box 'B' and one target cell 'T' in the grid.
_author_ = 'jake' # The box can be moved to an adjacent free cell by standing next to the box and
_project_ = 'leetcode' # then moving in the direction of the box. This is a push.
# The player cannot walk through the box.
# https://leetcode.com/problems/greatest-sum-divisible-by-three/ # Return the minimum number of pushes to move the box to the target.
# Given an array nums of integers, # If there is no way to reach the target, return -1.
# we need to find the maximum possible sum of elements of the array such that it is
divisible by three. # A-star search.
# Maintain a heap of states where a state consists of box and person locations together.
# If the sum of elements is divisible by 3, return that sum. # Heap is ordered by the number of moves so far to reach a state + heuristic estimate of
# Else make sorted lists of the elements divisible by 1 and 2. remaining moves.
# If the remainder of the sum after dividing by 3 is 1, we can subtract the smallest # Heuristic (an under-estimate of the remaining moves required) is the Manhattan distance
element divisible by 1, between box and target.
# or subtract the 2 smallest elements divisible by 2. # Repeatedly pop the state with the lowest heuristic + previous moves off the heap.
# If the remainder of the sum after dividing by 3 is 2, we can subtract the smallest # Attempt to move the person in all 4 directions.
element divisible by 2, # If any direction moves the person to the box, check if the box can move to the next
# or subtract the 2 smallest elements divisible by 1. position in the grid.
# Return the maximum candidate. # Time - O(log(mn) * m**2 * n**2) since there are m**2 * n**2 states.
# Time - O(n log n) # Space - O(m**2 * n**2)
# Space - O(n)
import heapq
class Solution(object):
def maxSumDivThree(self, nums): class Solution(object):
""" def minPushBox(self, grid):
:type nums: List[int] """
:rtype: int :type grid: List[List[str]]
""" :rtype: int
total = sum(nums) """
rem = total % 3 rows, cols = len(grid), len(grid[0])
for r in range(rows):
if rem == 0: for c in range(cols):
return total if grid[r][c] == "T":
target = (r, c)
rem_1 = [num for num in nums if num % 3 == 1] if grid[r][c] == "B":
rem_2 = [num for num in nums if num % 3 == 2] start_box = (r, c)
rem_1.sort() if grid[r][c] == "S":
rem_2.sort() start_person = (r, c)

candidates = [0] # default 0 def heuristic(box):


if rem == 1: return abs(target[0] - box[0]) + abs(target[1] - box[1])
if rem_1:
candidates.append(total - rem_1[0]) def out_bounds(location): # return whether the location is in the grid and not a
if len(rem_2) >= 2: wall
candidates.append(total - sum(rem_2[:2])) r, c = location
elif rem == 2: if r < 0 or r >= rows:
if rem_2: return True
if c < 0 or c >= cols: if not head.getNext():
return True head.printValue()
return grid[r][c] == "#" return

heap = [[heuristic(start_box), 0, start_person, start_box]] self.printLinkedListInReverse(head.getNext())


visited = set() head.printValue()

while heap: class Solution2(object):


_, moves, person, box = heapq.heappop(heap) def printLinkedListInReverse(self, head):
if box == target: node = head
return moves length = 0
if (person, box) in visited: # do not visit same state again while node:
continue length += 1
visited.add((person, box)) node = node.getNext()

for dr, dc in [[0, 1], [1, 0], [-1, 0], [0, -1]]: for i in range(length - 1, -1, -1): # get each value in reverse order
new_person = (person[0] + dr, person[1] + dc) node = head
if out_bounds(new_person): for _ in range(i):
continue node = node.getNext()
node.printValue()
if new_person == box:
new_box = (box[0] + dr, box[1] + dc) class Solution3(object):
if out_bounds(new_box): def printLinkedListInReverse(self, head):
continue node = head
heapq.heappush(heap, [heuristic(new_box) + moves + 1, moves + 1, length = 0
new_person, new_box]) while node:
else: length += 1
heapq.heappush(heap, [heuristic(box) + moves, moves, new_person, node = node.getNext()
box]) # box remains same
interval = int(length ** 0.5)
return -1
node = head
counter = 0
# python_1001_to_2000/1265_Print_Immutable_Linked_List_in_Reverse.py - m partition_nodes = [] # nodes at start of each interval
while node:
_author_ = 'jake' if counter % interval == 0:
_project_ = 'leetcode' partition_nodes.append(node)
counter += 1
# https://leetcode.com/problems/print-immutable-linked-list-in-reverse/ node = node.getNext()
# You are given an immutable linked list,
# print out all values of each node in reverse with the help of the following interface: for i in range(len(partition_nodes) - 1, -1, -1):
# ImmutableListNode: An interface of immutable linked list, you are given the head of the node = partition_nodes[i]
list. interval_end = partition_nodes[i + 1] if i != len(partition_nodes) - 1 else
# You need to use the following functions to access the linked list (you can't access the None
ImmutableListNode directly): interval_nodes = []
# ImmutableListNode.printValue(): Print value of the current node. while node != interval_end:
# ImmutableListNode.getNext(): Return the next node. interval_nodes.append(node)
# The input is only given to initialize the linked list internally. node = node.getNext()
# You must solve this problem without modifying the linked list.
# In other words, you must operate the linked list using only the mentioned APIs. for print_node in interval_nodes[::-1]:
print_node.printValue()
# If last node of the list, print it and return.
# Else recurse for the next node, printing it out after the recursion returns.
# Time - O(n) # python_1001_to_2000/1266_Minimum_Time_Visiting_All_Points.py
# Space - O(n), call stack of n functions.
# Alternatively, find the length of the list and iterate to each node in reverse order, _author_ = 'jake'
# which is O(n**2) time but O(1) space. _project_ = 'leetcode'
# Alternatively, divide the list into intervals of length sqrt(n).
# Make a list of nodes at the start of each interval. # https://leetcode.com/problems/minimum-time-visiting-all-points/
# For the start interval nodes in reverse, find all nodes to end interval then print in # On a plane there are n points with integer coordinates points[i] = [xi, yi].
reverse. # Your task is to find the minimum time in seconds to visit all points.
# This is O(n) time and O(sqrt(n)) space. # You can move according to the next rules:
# In one second always you can either move vertically, horizontally by one unit or
class Solution(object): diagonally
def printLinkedListInReverse(self, head): # (which means to move one unit vertically and one unit horizontally in one second).
""" # You have to visit the points in the same order as they appear in the array.
:type head: ImmutableListNode
:rtype: None # To move between points take the maximum of the move in the x direction and the move in
""" the y direction.

# This is because we can move diagonally to cover the move in the shorter direction, row_servers, cols_servers = [0] * rows, [0] * cols
# while also moving in the longer direction. servers = set()
# Time - O(n)
# Space - O(1) for r in range(rows):
for c in range(cols):
class Solution(object): if grid[r][c] == 1:
def minTimeToVisitAllPoints(self, points): row_servers[r] += 1
""" cols_servers[c] += 1
:type points: List[List[int]] servers.add((r, c))
:rtype: int
""" return sum(1 for r, c in servers if row_servers[r] > 1 or cols_servers[c] > 1)
x1, y1 = points[0] # current point
time = 0
# python_1001_to_2000/1268_Search_Suggestions_System.py - m
for x2, y2 in points[1:]:
dx, dy = abs(x1 - x2), abs(y1 - y2) _author_ = 'jake'
time += max(dx, dy) _project_ = 'leetcode'
x1, y1 = x2, y2 # update current point
# https://leetcode.com/problems/search-suggestions-system/
return time # Given an array of strings products and a string searchWord.
# We want to design a system that suggests at most three product names from products
# after each character of searchWord is typed.
# Suggested products should have common prefix with the searchWord.
# python_1001_to_2000/1267_Count_Servers_that_Communicate.py - m # If there are more than three products with a common prefix return the three
lexicographically minimums products.
_author_ = 'jake' # Return list of lists of the suggested products after each character of searchWord is
_project_ = 'leetcode' typed.

# https://leetcode.com/problems/count-servers-that-communicate/ # Sort the list of products.


# You are given a map of a server center, represented as a m * n integer matrix grid, # For each prefix of searchWord, binary search the list of products
# where 1 means that on that cell there is a server and 0 means that it is no server. # and add the list of the next 3 with the same prefix to the result.
# Two servers are said to communicate if they are on the same row or on the same column. # Time - O(n log n + k log n) for n products and searchWord of length k
# Return the number of servers that communicate with any other server. # Space - O(n)

# Iterate over grid, counting the number of servers in each row and each column. import bisect
# The iterate over grid again, incrementing the result for each server that has another
server on the same class Solution(object):
# row or column. def suggestedProducts(self, products, searchWord):
# Alternatively, store all servers in first loop to avoid iterateing over entire grid """
twice but use more space. :type products: List[str]
# Time - O(mn) :type searchWord: str
# Space - O(m + n) :rtype: List[List[str]]
"""
class Solution(object): products.sort()
def countServers(self, grid): results = []
"""
:type grid: List[List[int]] for length in range(1, len(searchWord) + 1):
:rtype: int prefix = searchWord[:length]
""" i = bisect.bisect_left(products, prefix)
rows, cols = len(grid), len(grid[0]) results.append([p for p in products[i: i + 3] if p[:length] == prefix])
row_servers, cols_servers = [0] * rows, [0] * cols
return results
for r in range(rows):
for c in range(cols):
if grid[r][c] == 1:
row_servers[r] += 1 # python_1001_to_2000/1269_Number_of_Ways_to_Stay_in_the_Same_Place_After_Some_Steps.py -
cols_servers[c] += 1 h

result = 0 _author_ = 'jake'


for r in range(rows): _project_ = 'leetcode'
for c in range(cols):
if grid[r][c] == 1 and (row_servers[r] > 1 or cols_servers[c] > 1): # https://leetcode.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-
result += 1 steps/
# You have a pointer at index 0 in an array of size arrLen.
return result # 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.
class Solution2(object): # The pointer should not be placed outside the array at any time.
def countServers(self, grid): # Given two integers steps and arrLen,
rows, cols = len(grid), len(grid[0]) # return the number of ways such that your pointer still at index 0 after exactly steps
steps. :type num: str
# Since the answer may be too large, return it modulo 10^9 + 7. :rtype: str
"""
# Count the number of way to reach each index. s = format(int(num), "X") # upper case hex without 0X prefix.
# Do not count all indices of the array, since initially most are zero and if the array if any(str(i) in s for i in range(3, 10)):
is much longer than return "ERROR"
# the number of steps, we cannot return to index zero from all indices. s = s.replace("0", "O")
# For each step, iterate over the existing array elements that can reach index zero in return s.replace("1", "I")
the remaining steps.
# 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,
# provided those new indices are within the bounds of the array. # python_1001_to_2000/1272_Remove_Interval.py - m
# Time - O(n**2) for n steps
# Space - O(n) _author_ = 'jake'
_project_ = 'leetcode'
class Solution(object):
def numWays(self, steps, arrLen): # https://leetcode.com/problems/remove-interval/
""" # Given a sorted list of disjoint intervals, each interval intervals[i] = [a, b]
:type steps: int # represents the set of real numbers x such that a <= x < b.
:type arrLen: int # We remove the intersections between any interval in intervals and the interval
:rtype: int toBeRemoved.
""" # Return a sorted list of intervals after all such removals.
i_to_count = [1] # i_to_count[i] is the number of ways to reach index
i # Iterate over intervals.
# If remove_start is after the interval end, there is no overlap so append the interval
for step in range(steps): to the result.
new_i_to_count = [0] * (len(i_to_count) + 1) # extend length by 1 since we # If remove_end is before the interval start, there is no overlap and all other intervals
may move +1 index will not overlap.
# Else if the start or end parts of the interval do not overlap, append them (possibly
for i, count in enumerate(i_to_count[:steps - step + 1]): # only consider both) to the result.
indices where we can move # Time - O(n)
if i + 1 < arrLen: # back to index 0 # Space - O(n)
in remaining steps
new_i_to_count[i + 1] += count class Solution(object):
new_i_to_count[i] += count def removeInterval(self, intervals, toBeRemoved):
if i - 1 >= 0: """
new_i_to_count[i - 1] += count :type intervals: List[List[int]]
:type toBeRemoved: List[int]
i_to_count = new_i_to_count :rtype: List[List[int]]
"""
return i_to_count[0] % (10 ** 9 + 7) remove_start, remove_end = toBeRemoved
result = []

for i, (start, end) in enumerate(intervals):


# python_1001_to_2000/1271_Hexspeak.py if remove_start >= end:
result.append([start, end])
_author_ = 'jake' elif remove_end <= start: # all remaining intervals will not overlap
_project_ = 'leetcode' result += intervals[i:]
break
# https://leetcode.com/problems/hexspeak/ else:
# A decimal number can be converted to its Hexspeak representation if remove_start > start:
# by first converting it to an uppercase hexadecimal string, result.append([start, remove_start])
# then replacing all occurrences of the digit 0 with the letter O, and the digit 1 with if remove_end < end:
the letter I. result.append([remove_end, end])
# Such a representation is valid if and only if it consists only of the letters in the
set return result
# {"A", "B", "C", "D", "E", "F", "I", "O"}.
# Given a string num representing a decimal integer N,
# return the Hexspeak representation of N if it is valid, otherwise return "ERROR".
# python_1001_to_2000/1273_Delete_Tree_Nodes.py - m
# Convert to hex.
# Return ERROR if any digit apart from 0 or 1 remains. _author_ = 'jake'
# Replace 0 with O and replace 1 with I. _project_ = 'leetcode'
# Time - O(n)
# Space - O(n) # https://leetcode.com/problems/delete-tree-nodes/
# A tree rooted at node 0 is given as follows:
class Solution(object): # The number of nodes is nodes;
def toHexspeak(self, num): # 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. # Space - O(mn)
# After doing so, return the number of nodes remaining in the tree.
class Solution(object):
# Map each node to its children (note this is not a binary tree, there can be any number def countShips(self, sea, topRight, bottomLeft):
of children). """
# Recursive helper function sums all the subtrees including the node itself, and counts :type sea: Sea
the nodes. :type topRight: Point
# If the sum is zero, delete the subtree by setting the node count to zero. :type bottomLeft: Point
# Time - O(n) :rtype: integer
# Space - O(n) """
def counter(top_right, bottom_left):
from collections import defaultdict if not sea.hasShips(top_right, bottom_left):
return 0 # no need to keep exploring
class Solution(object): x_dist = top_right.x - bottom_left.x
def deleteTreeNodes(self, nodes, parents, values): y_dist = top_right.y - bottom_left.y
""" if x_dist == 0 and y_dist == 0: # rectangle is a point containing a
:type nodes: int ship
:type parents: List[int] return 1
:type values: List[int]
:rtype: int if x_dist > y_dist: # split along x
""" x_mid = bottom_left.x + x_dist // 2
node_children = defaultdict(list) return counter(Point(x_mid, top_right.y), bottom_left) +
for child, parent in enumerate(parents): counter(top_right,
node_children[parent].append(child)
Point(x_mid + 1, bottom_left.y))
def helper(node): # return (sum, node count) of subtree from node else: # split along y
subtree_sum = values[node] y_mid = bottom_left.y + y_dist // 2
subtree_count = 1 return counter(Point(top_right.x, y_mid), bottom_left) +
counter(top_right,
for child in node_children[node]: # sum and count all subtrees
child_sum, child_count = helper(child) Point(bottom_left.x, y_mid + 1))
subtree_sum += child_sum
subtree_count += child_count return counter(topRight, bottomLeft)

if subtree_sum == 0: # reset count to zero since subtree is deleted


subtree_count = 0

return (subtree_sum, subtree_count) # python_1001_to_2000/1275_Find_Winner_on_a_Tic_Tac_Toe_Game.py

_, result = helper(0) _author_ = 'jake'


return result _project_ = 'leetcode'

# https://leetcode.com/problems/find-winner-on-a-tic-tac-toe-game/
# python_1001_to_2000/1274_Number_of_Ships_in_a_Rectangle.py - h # 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:
_author_ = 'jake' # Players take turns placing characters into empty squares (" ").
_project_ = 'leetcode' # The first player A always places "X" characters, while the second player B always
places "O" characters.
# https://leetcode.com/problems/number-of-ships-in-a-rectangle/ # "X" and "O" characters are always placed into empty squares, never on filled ones.
# This problem is an interactive problem. # The game ends when there are 3 of the same (non-empty) character filling any row,
# On the sea represented by a cartesian plane, column, or diagonal.
# each ship is located at an integer point, and each integer point may contain at most 1 # The game also ends if all squares are non-empty.
ship. # No more moves can be played if the game is over.
# You have a function Sea.hasShips(topRight, bottomLeft) which takes two points as # Given an array moves where each element is another array of size 2 corresponding to the
arguments # row and column of the grid where they mark their respective character in the order in
# and returns true if and only if there is at least one ship in the rectangle represented which A and B play.
by the two points, # Return the winner of the game if it exists (A or B),
# including on the boundary. # in case the game ends in a draw return "Draw",
# Given two points, which are the top right and bottom left corners of a rectangle, # if there are still movements to play return "Pending".
# return the number of ships present in that rectangle. # You can assume that moves is valid (It follows the rules of Tic-Tac-Toe),
# It is guaranteed that there are at most 10 ships in that rectangle. # the grid is initially empty and A will play first.
# Submissions making more than 400 calls to hasShips will be judged Wrong Answer.
# Also, any solutions that attempt to circumvent the judge will result in # Denominate player A as 1 and player B as -1.
disqualification. # Find the sum of move for each row, column and diagonal.
# If any line sums to 3 times the value of a player, that player wins.
# Split any rectangle with either non-zero side length containing a ship into 2 sections # Else there is a draw if all squares are full, else pending.
along the longest axis. # Time - O(1)
# Repeat until rectangle is empty or is a single point with a ship. # Space - O(1)
# Time - O(mn), may split to each point of initial rectangle.
class Solution(object):
def tictactoe(self, moves):
"""
:type moves: List[List[int]] # python_1001_to_2000/1277_Count_Square_Submatrices_with_All_Ones.py - m
:rtype: str
""" _author_ = 'jake'
A, B = 1, -1 _project_ = 'leetcode'
player = A
row_sums, col_sums = [0 for _ in range(3)], [0 for _ in range(3)] # https://leetcode.com/problems/count-square-submatrices-with-all-ones/
up_diag, down_diag = 0, 0 # sums of moves along diagonals # Given a m * n matrix of ones and zeros, return how many square submatrices have all
ones.
for r, c in moves: # add move to sums for each line
row_sums[r] += player # Iterate ove the matrix apart from the first row and column.
col_sums[c] += player # Update each cell to the maximum side square with this cell in the top right corner.
if r == c: # The maximum side is 0 if the cell is 0,
up_diag += player # else we can extend the smallest side square to the left, down or down and left by 1.
if r + c == 2: # Sum the resulting matrix, since a cell with value x has square submatrices of side
down_diag += player lengths 1, 2 ... x ending
# with the cell in the top right corner.
player = -player # change player # Time - O(mn)
# Space - O(Tmn)
lines = row_sums + col_sums + [up_diag, down_diag]
if any(line == 3 * A for line in lines): class Solution(object):
return "A" def countSquares(self, matrix):
if any(line == 3 * B for line in lines): """
return "B" :type matrix: List[List[int]]
return "Draw" if len(moves) == 9 else "Pending" :rtype: int
"""
rows, cols = len(matrix), len(matrix[0])

for r in range(1, rows):


# python_1001_to_2000/1276_Number_of_Burgers_with_No_Waste_of_Ingredients.py - m for c in range(1, cols):
matrix[r][c] *= 1 + min(matrix[r - 1][c], matrix[r][c - 1], matrix[r - 1]
_author_ = 'jake' [c - 1])
_project_ = 'leetcode'
return sum(map(sum, matrix)) # map sums each row, then sum row sums
# https://leetcode.com/problems/number-of-burgers-with-no-waste-of-ingredients/
# Given two integers tomatoSlices and cheeseSlices. The ingredients of different burgers
are as follows:
# Jumbo Burger: 4 tomato slices and 1 cheese slice.
# Small Burger: 2 Tomato slices and 1 cheese slice. # python_1001_to_2000/1278_Palindrome_Partitioning_III.py - h
# Return [total_jumbo, total_small] so that the number of remaining tomatoSlices equal to
0 _author_ = 'jake'
# and the number of remaining cheeseSlices equal to 0. _project_ = 'leetcode'
# If it is not possible to make the remaining tomatoSlices and cheeseSlices equal to 0
return []. # https://leetcode.com/problems/palindrome-partitioning-iii/
# You are given a string s containing lowercase letters and an integer k. You need to :
# We cannot reach a solution for an odd number of tomato or tomato less than 2 * cheese # First, change some characters of s to other lowercase English letters.
or tomato more than 4 * cheese. # Then divide s into k non-empty disjoint substrings such that each substring is
# Else solve the linear equations: palindrome.
# jumbo + small = cheese # Return the minimal number of characters that you need to change to divide the string.
# 4 * jumbo + 2 * small = tomato
# Time - O(1) # Helper function returns the minimum chars to change to make k palindromes from a suffix
# Space - O(1) of s.
# If the length of the suffix is the same as k, each char can be a palindrome and no
class Solution(object): changes are needed.
def numOfBurgers(self, tomatoSlices, cheeseSlices): # If k == 1, the suffix must be changed to a single palindrome.
""" # Else convert the substring s[i:j + 1] to a palindrome and recurse for k - 1 remaining
:type tomatoSlices: int substrings.
:type cheeseSlices: int # Time - O(n ** 3 * k) since O(nk) calls to helper, each with O(n) iterations over j,
:rtype: List[int] each taking O(n) for cost().
""" # Space - O(nk)
if tomatoSlices % 2 == 1 or tomatoSlices < 2 * cheeseSlices or tomatoSlices > 4 *
cheeseSlices: class Solution(object):
return [] def palindromePartition(self, s, k):
"""
jumbo = (tomatoSlices - 2 * cheeseSlices) // 2 :type s: str
small = cheeseSlices - jumbo :type k: int
return [jumbo, small] :rtype: int

""" # There are n people whose IDs go from 0 to n - 1 and each person belongs exactly to one
n = len(s) group.
# Given the array groupSizes of length n telling the group size each person belongs to,
def cost(left, right): # cost to change s[i:j + 1] into a palindrome # return the groups there are and the people's IDs each group includes.
result = 0 # You can return any solution in any order and the same applies for IDs.
while left < right: # Also, it is guaranteed that there exists at least one solution.
if s[left] != s[right]:
result += 1 # Create a mapping of group size to its members.
left += 1 # Iterate over the group sizes, adding each member to a group of the corresponding size.
right -= 1 # A new group is started if there is no group of the correct size.
return result # When a group has the correct number of members, add it to result and start a new empty
group.
memo = {} # Time - O(n)
# Space - O(n)
def helper(i, k): # chars to change s[i:] into k palindromes
if k >= n - i: from collections import defaultdict
return 0
if k == 1: class Solution(object):
return cost(i, n - 1) def groupThePeople(self, groupSizes):
if (i, k) in memo: """
return memo[(i, k)] :type groupSizes: List[int]
:rtype: List[List[int]]
chars_changed = float("inf") """
for j in range(i, n - k + 1): # until k - 1 == remaining string length size_to_group = defaultdict(list)
chars_changed = min(chars_changed, cost(i, j) + helper(j + 1, k - 1)) result = []

memo[(i, k)] = chars_changed for i, size in enumerate(groupSizes):


return chars_changed size_to_group[size].append(i)

return helper(0, k) if len(size_to_group[size]) == size: # group is full


result.append(size_to_group[size])
size_to_group[size] = [] # start a new group

# python_1001_to_2000/1281_Subtract_the_Product_and_Sum_of_Digits_of_an_Integer.py return result

_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1283_Find_the_Smallest_Divisor_Given_a_Threshold.py - m
# 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 _author_ = 'jake'
the sum of its digits. _project_ = 'leetcode'

# Repeatedly remove each digit and update the product and total sum. # https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/
# Time - O(log n) # Given an array of integers nums and an integer threshold,
# Space - O(1) # we will choose a positive integer divisor and divide all the array by it and sum the
result of the division.
class Solution(object): # Find the smallest divisor such that the result mentioned above is less than or equal to
def subtractProductAndSum(self, n): threshold.
""" # Each result of division is rounded to the nearest integer greater than or equal to that
:type n: int element.
:rtype: int # For example: 7/3 = 3 and 10/2 = 5.
""" # It is guaranteed that there will be an answer.
product, total = 1, 0
# Binary search for the divisor.
while n > 0: # note n can be positive only # The divisor is between 1 and max(num), inclusive.
n, digit = divmod(n, 10) # Search this range by guessing the mid and checking if the sum of divided num is <=
product *= digit threshold.
total += digit # 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 product - total # Space - O(1)

class Solution(object):
def smallestDivisor(self, nums, threshold):
# python_1001_to_2000/1282_Group_the_People_Given_the_Group_Size_They_Belong_To.py - m """
:type nums: List[int]
_author_ = 'jake' :type threshold: int
_project_ = 'leetcode' :rtype: int
"""
# https://leetcode.com/problems/group-the-people-given-the-group-size-they-belong-to/ def le_threshold(divisor): # check if sum of (nums divided by divisor) is <=
threshold new_frontier = set()
return sum((num + divisor - 1) // divisor for num in nums) <= threshold
for state in frontier:
low, high = 1, max(nums) if all(not v for v in state): # found result
while low < high: return steps
guess = (low + high) // 2
if le_threshold(guess): if state in seen:
high = guess continue
else: seen.add(state)
low = guess + 1
for i in range(rows * cols):
return low new_state = list(state)
for nbor in linear_nbors[i]:
new_state[nbor] = not (new_state[nbor])
# new_frontier.add((tuple(new_state)))
python_1001_to_2000/1284_Minimum_Number_of_Flips_to_Convert_Binary_Matrix_to_Zero_Matrix.
py - h steps += 1
frontier = new_frontier
_author_ = 'jake'
_project_ = 'leetcode' return -1 # no result

# https://leetcode.com/problems/minimum-number-of-flips-to-convert-binary-matrix-to-zero-
matrix/
# Given a m x n binary matrix mat. # python_1001_to_2000/1286_Iterator_for_Combination.py - m
# In one step, you can choose one cell and flip it and all the four neighbours of it if
they exist _author_ = 'jake'
# Flip is changing 1 to 0 and 0 to 1. _project_ = 'leetcode'
# A pair of cells are called neighboors if they share one edge.
# Return the minimum number of steps required to convert mat to a zero matrix or -1 if # https://leetcode.com/problems/iterator-for-combination/
you cannot. # Design an Iterator class, which has:
# Binary matrix is a matrix with all cells equal to 0 or 1 only. # A constructor that takes a string characters of sorted distinct lowercase English
# Zero matrix is a matrix with all cells equal to 0. letters
# and a number combinationLength as arguments.
# Convert the matrix to a linear list of bool, by row. # A function next() that returns the next combination of length combinationLength in
# Create a mapping from each linear index to its neighbours in the matrix. lexicographical order.
# Breadth-first search the matrix states. # A function hasNext() that returns True if and only if there exists a next combination.
# Frontier consists of reachable states.
# For each state in frontier, flip each cell and its neighbours to create a new state. # Maintain a combination, which is a list of indices of characters of the next
# Time - O(mn * 2 ** mn), since there are 2 ** mn states combination.
# Space - O(mn * 2 ** mn) # Also set the final combination as combinationLength indices ending with the last index
of characters.
from collections import defaultdict # Find the next combination by iterating backwards to find an index that is less than its
final index.
class Solution(object): # Increment the index and set all later indices in ascending order.
def minFlips(self, mat): # Time - O(1) for init and hasNext, O(n) for next
""" # Space - O(n)
:type mat: List[List[int]]
:rtype: int class CombinationIterator(object):
"""
rows, cols = len(mat), len(mat[0]) def __init__(self, characters, combinationLength):
linear = [] """
for row in mat: :type characters: str
linear += [bool(cell) for cell in row] :type combinationLength: int
"""
linear_nbors = defaultdict(list) # map linear index to nbors self.chars = characters
for r in range(rows): self.combination = list(range(combinationLength)) # the previous combination of
for c in range(cols): indices of characters
i = r * cols + c self.combination[-1] -= 1 # set to combination before
linear_nbors[i].append(i) the first
for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]: n = len(characters)
if 0 <= r + dr < rows and 0 <= c + dc < cols: # within matrix only self.final = list(range(n - combinationLength, n)) # the final combination of
j = (r + dr) * cols + (c + dc) indices of characters
linear_nbors[i].append(j)
def next(self):
frontier = {tuple(linear)} # immutable tuple can be added to set """
steps = 0 :rtype: str
seen = set() # avoid repeating states """
i = len(self.combination) - 1
while frontier: while self.combination[i] == self.final[i]: # first index that can be

incremented class Solution(object):


i -= 1 def removeCoveredIntervals(self, intervals):
"""
self.combination[i] += 1 :type intervals: List[List[int]]
for j in range(i + 1, len(self.combination)): :rtype: int
self.combination[j] = self.combination[j - 1] + 1 # set all next indices in """
ascending order stack = []
intervals.sort(key=lambda x:[x[0], -x[1]])
return "".join(self.chars[i] for i in self.combination)
for interval in intervals:
def hasNext(self): if not stack or stack[-1][1] < interval[1]: # keep if not covered
""" stack.append(interval)
:rtype: bool
""" return len(stack)
return self.combination != self.final

# python_1001_to_2000/1289_Minimum_Falling_Path_Sum_II.py - h
# python_1001_to_2000/1287_Element_Appearing_More_Than_25%_In_Sorted_Array.py
_author_ = 'jake'
_author_ = 'jake' _project_ = 'leetcode'
_project_ = 'leetcode'
# https://leetcode.com/problems/minimum-falling-path-sum-ii/
# https://leetcode.com/problems/element-appearing-more-than-25-in-sorted-array/ # Given a square grid of integers arr,
# Given an integer array sorted in non-decreasing order, # a falling path with non-zero shifts is a choice of exactly one element from each row of
# there is exactly one integer in the array that occurs more than 25% of the time. arr,
# Return that integer. # such that no two elements chosen in adjacent rows are in the same column.
# Return the minimum sum of a falling path with non-zero shifts.
# 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 # For each row, only the smallest and second smallest paths are used.
first and last occurences. # Iterate over the rows, updating each element with the minimum sum path.
# Time - O(n) # For each row, each column is incremented by the smallest path from the previous row if
# Space - O(n) the smallest path from
# the previous row is not the smallest, else is incremented by the second smallest path
from collections import defaultdict from the previous row.
# Time - O(mn)
class Solution(object): # Space - O(mn)
def findSpecialInteger(self, arr):
""" import heapq
:type arr: List[int]
:rtype: int class Solution(object):
""" def minFallingPathSum(self, arr):
target = len(arr) // 4 + 1 """
counts = defaultdict(int) :type arr: List[List[int]]
for num in arr: :rtype: int
counts[num] += 1 """
if counts[num] == target: n = len(arr)
return num
for row in range(1, n):
smallest, second = heapq.nsmallest(2, arr[row - 1])
for col in range(n):
# python_1001_to_2000/1288_Remove_Covered_Intervals.py - m arr[row][col] += second if arr[row - 1][col] == smallest else smallest

_author_ = 'jake' return min(arr[-1])


_project_ = 'leetcode'

# https://leetcode.com/problems/remove-covered-intervals/
# Given a list of intervals, remove all intervals that are covered by another interval in # python_1001_to_2000/1290_Convert_Binary_Number_in_a_Linked_List_to_Integer.py
the list.
# Interval [a,b) is covered by interval [c,d) if and only if c <= a and b <= d. _author_ = 'jake'
# After doing so, return the number of remaining intervals. _project_ = 'leetcode'

# Sort the intervals and iterate over them. # https://leetcode.com/problems/convert-binary-number-in-a-linked-list-to-integer/


# Maintain a stack of intervals that are not covered. # Given head which is a reference node to a singly-linked list.
# For each new interval, if the to of stack interval ends before the interval ends it is # The value of each node in the linked list is either 0 or 1.
not covered. # The linked list holds the binary representation of a number.
# Time - O(n log n) # Return the decimal value of the number in the linked list.
# Space - O(n)
# Iterate along the linked list.
# For each node, multiply the previous result by 2 (left bit shift) and add the bit from
the current node. _author_ = 'jake'
# Time - O(n) _project_ = 'leetcode'
# Space - O(n)
# https://leetcode.com/problems/maximum-side-length-of-a-square-with-sum-less-than-or-
class Solution(object): equal-to-threshold/
def getDecimalValue(self, head): # Given a m x n matrix mat and an integer threshold.
""" # Return the maximum side-length of a square with a sum less than or equal to threshold
:type head: ListNode # or return 0 if there is no such square.
:rtype: int
""" # Iterate over matrix, converting each cell to the cumulative sum from (0, 0) to the
result = 0 cell.
# For each cell, if there is sufficient space to create a square of side length max_side
while head: + 1,
result = result * 2 + head.val # find the sum of the square and increment max_side if the sum is <= threshold.
head = head.next # Time - O(mn)
# Space - O(mn)
return result
class Solution(object):
def maxSideLength(self, mat, threshold):
"""
# python_1001_to_2000/1291_Sequential_Digits.py - m :type mat: List[List[int]]
:type threshold: int
_author_ = 'jake' :rtype: int
_project_ = 'leetcode' """
rows, cols = len(mat), len(mat[0])
# https://leetcode.com/problems/sequential-digits/ max_side = 0
# An integer has sequential digits if and only if each digit in the number is one more
than the previous digit. def val_or_zero(row, col): # return matrix value or 0 if not in matrix
# Return a sorted list of all the integers in the range [low, high] inclusive that have return mat[row][col] if row >= 0 and col >= 0 else 0
sequential digits.
for r in range(rows):
# Starting from the digits from 1 to 9, extend each number by the next greater digit. for c in range(cols):
# If a number is more than high, return the result since all later numbers are greater. mat[r][c] += val_or_zero(r - 1, c) + val_or_zero(r, c - 1) -
# If a number is greater than or equal to low, append it to the result. val_or_zero(r - 1, c - 1)
# Time - O(log n)
# Space - O(log n) if r >= max_side and c >= max_side:
next_side_square = val_or_zero(r, c)
class Solution(object): next_side_square -= val_or_zero(r - max_side - 1, c)
def sequentialDigits(self, low, high): 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)
:type low: int if next_side_square <= threshold:
:type high: int max_side += 1
:rtype: List[int]
""" return max_side
nums = list(range(1, 10))
result = []

while nums: # python_1001_to_2000/1293_Shortest_Path_in_a_Grid_with_Obstacles_Elimination.py - h


new_nums = []
_author_ = 'jake'
for num in nums: _project_ = 'leetcode'
if num > high:
break # https://leetcode.com/problems/shortest-path-in-a-grid-with-obstacles-elimination/
if num >= low: # Given a m * n grid, where each cell is either 0 (empty) or 1 (obstacle).
result.append(num) # In one step, you can move up, down, left or right from and to an empty cell.
last_digit = num % 10 # Return the minimum number of steps to walk from the upper left corner (0, 0) to
if last_digit != 9: # extend with next greater digit # the lower right corner (m-1, n-1) given that you can eliminate at most k obstacles.
new_nums.append(num * 10 + last_digit + 1) # If it is not possible to find such walk return -1.

nums = new_nums # A-star search with heuristic of Manhattan distance.


# Repeatedly visit the state with the lowest heuristic + steps taken, ties broken by most
return result remaining eliminations.
# 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.
# Space - O(mnk)
#
python_1001_to_2000/1292_Maximum_Side_Length_of_a_Square_with_Sum_Less_than_or_Equal_to_T import heapq
hreshold.py - m

class Solution(object): # https://leetcode.com/problems/divide-array-in-sets-of-k-consecutive-numbers/


def shortestPath(self, grid, k): # Given an array of integers nums and a positive integer k,
""" # find whether it's possible to divide this array into sets of k consecutive numbers
:type grid: List[List[int]] # Return True if its possible otherwise return False.
:type k: int
:rtype: int # Count each num.
""" # Find the count of each num in sorted order,
rows, cols = len(grid), len(grid[0]) # and check if there are at least as many of each k - 1 subsequent digits.
# Time - O(n log n)
def heuristic(r, c): # Space - O(n)
return abs(rows - 1 - r) + abs(cols - 1 - c)
from collections import Counter
queue = [(heuristic(0, 0), -k + grid[0][0], 0, 0, 0)] # h + steps, neg_elims,
steps, r, c class Solution(object):
def isPossibleDivide(self, nums, k):
visited = {} # map cell to most eliminations remaining when cell visited """
:type nums: List[int]
while queue: :type k: int
_, neg_elims, steps, r, c = heapq.heappop(queue) :rtype: bool
"""
if neg_elims > 0: # too many eliminations used if len(nums) % k != 0: # check if nums can be divided into groups of k
continue return False
if r == rows - 1 and c == cols - 1:
return steps counts = Counter(nums)

if (r, c) in visited and neg_elims >= visited[(r, c)]: # have visited with for start_num in sorted(counts.keys()):
same or more eliminations count = counts[start_num]
continue if count == 0: # num has already been used in other sequences
visited[(r, c)] = neg_elims continue

for dr, dc in [[1, 0], [0, 1], [-1, 0], [0, -1]]: for num in range(start_num, start_num + k):
r2, c2 = r + dr, c + dc if num not in counts or counts[num] < count:
if r2 < 0 or r2 >= rows or c2 < 0 or c2 >= cols: return False
continue counts[num] -= count # decrement so count nums are not reused
heapq.heappush(queue, (heuristic(r2, c2) + steps + 1, neg_elims +
grid[r2][c2], steps + 1, r2, c2)) return True

return -1

# python_1001_to_2000/1297_Maximum_Number_of_Occurrences_of_a_Substring.py - m

# python_1001_to_2000/1295_Find_Numbers_with_Even_Number_of_Digits.py _author_ = 'jake'


_project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # https://leetcode.com/problems/maximum-number-of-occurrences-of-a-substring/
# Given a string s, return the maximum number of occurrences of any substring under the
# https://leetcode.com/problems/find-numbers-with-even-number-of-digits/ following rules:
# Given an array nums of integers, return how many of them contain an even number of # The number of unique characters in the substring must be less than or equal to
digits. maxLetters.
# The substring size must be between minSize and maxSize inclusive.
# Convert each num to string and check if length is divisible by 2.
# Time - O(n log k) for k numbers of max value k # Ignore maxSize since there will be most substrings of length minSize.
# Space - O(log k) # Maintain a sliding window of length minSize, counting the frequency of each letter in
the window.
class Solution(object): # Update the window with each end letter.
def findNumbers(self, nums): # If window is of length >= minSise then check if window has <= maxLetters, then remove
""" start letter.
:type nums: List[int] # Time - O(n)
:rtype: int # Space - O(n)
"""
return sum(len(str(num)) % 2 == 0 for num in nums) from collections import defaultdict

class Solution(object):
def maxFreq(self, s, maxLetters, minSize, maxSize):
# python_1001_to_2000/1296_Divide_Array_in_Sets_of_K_Consecutive_Numbers.py - m """
:type s: str
_author_ = 'jake' :type maxLetters: int
_project_ = 'leetcode' :type minSize: int
:type maxSize: int
:rtype: int if status[open_box] == VISITED: # avoid re-vistiing
""" continue
substrings = defaultdict(int) # map substring to its count in s status[open_box] = VISITED
letters = defaultdict(int) # map letter to its count in sliding window
result += candies[open_box]
for end in range(len(s)): for key in keys[open_box]: # open when box is reached, no need
letters[s[end]] += 1 # add letter to window count before checking to retain key
substring status[key] = OPEN
start = end - minSize + 1 closed_boxes.update(containedBoxes[open_box])
if start >= 0:
if len(letters) <= maxLetters: # increment substring count if <= open_boxes = {box for box in closed_boxes if status[box] == OPEN}
maxLetters in window closed_boxes -= open_boxes
substrings[s[start:end + 1]] += 1
letters[s[start]] -= 1 # remove letter from window count after checking return result
substring
if letters[s[start]] == 0:
del letters[s[start]]

return 0 if not substrings else max(substrings.values())


# python_1001_to_2000/1299_Replace_Elements_with_Greatest_Element_on_Right_Side.py

_author_ = 'jake'
# python_1001_to_2000/1298_Maximum_Candies_You_Can_Get_from_Boxes.py - h _project_ = 'leetcode'

_author_ = 'jake' # https://leetcode.com/problems/replace-elements-with-greatest-element-on-right-side/


_project_ = 'leetcode' # Given an array arr,
# replace every element in that array with the greatest element among the elements to its
# https://leetcode.com/problems/maximum-candies-you-can-get-from-boxes/ right,
# Given n boxes, each box is given in the format [status, candies, keys, containedBoxes] # and replace the last element with -1.
where: # After doing so, return the array.
# status[i]: an integer which is 1 if box[i] is open and 0 if box[i] is closed.
# candies[i]: an integer representing the number of candies in box[i]. # Iterate over the array from right to left.
# keys[i]: an array contains the indices of the boxes you can open with the key in # Simultaneously update the greatest value seen and replace the value with the greatest.
box[i]. # Time - O(n)
# containedBoxes[i]: an array contains the indices of the boxes found in box[i]. # Space - O(n)
# You will start with some boxes given in initialBoxes array.
# You can take all the candies in any open box and you can use the keys in it to class Solution(object):
# open new boxes and you also can use the boxes you find in it. def replaceElements(self, arr):
# Return the maximum number of candies you can get following the rules above. """
:type arr: List[int]
# Breadth first search. :rtype: List[int]
# 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 greatest = -1
update set of unopened boxes.
# After visiting each opened box, update the opened boxes. for i in range(len(arr) - 1, -1, -1):
# Time - O(n + m) for n boxes and m total keys (same key may be in multiple boxes). arr[i], greatest = greatest, max(greatest, arr[i])
# Space - O(n)
return arr
class Solution(object):
def maxCandies(self, status, candies, keys, containedBoxes, initialBoxes):
"""
:type status: List[int] # python_1001_to_2000/1300_Sum_of_Mutated_Array_Closest_to_Target.py - m
:type candies: List[int]
:type keys: List[List[int]] _author_ = 'jake'
:type containedBoxes: List[List[int]] _project_ = 'leetcode'
:type initialBoxes: List[int]
:rtype: int # https://leetcode.com/problems/sum-of-mutated-array-closest-to-target/
""" # Given an integer array arr and a target value target,
OPEN, VISITED = 1, 2 # return the integer value such that when we change all the integers larger than value
# in the given array to be equal to value,
result = 0 # the sum of the array gets as close as possible (in absolute difference) to target.
open_boxes, closed_boxes = set(), set() # In case of a tie, return the minimum such integer.
for initial_box in initialBoxes: # put in either opened or unopened set # Notice that the answer is not necessarily a number from arr.
container = open_boxes if status[initial_box] == OPEN else closed_boxes
container.add(initial_box) # Binary search for the first integer ceiling that makes the array sum >= target.
# Then check if integer - 1 ceiling can make the array sum closer to the target.
while open_boxes: # Time - O(n log k) where k is the range of values in arr
# Space - O(1)
for open_box in open_boxes:

class Solution(object): if (r, c) in visited:


def findBestValue(self, arr, target): return visited[(r, c)]
""" if r == 0 and c == 0: # "E" end cell
:type arr: List[int] return [0, 1]
:type target: int
:rtype: int # 3 possible moves
""" up_max, up_paths = helper(r - 1, c)
low, high = 0, max(arr) left_max, left_paths = helper(r, c - 1)
up_left_max, up_left_paths = helper(r - 1, c - 1)
def ceiling(x): max_value, max_count_paths = 0, 0
return sum(min(a, x) for a in arr)
if up_paths + left_paths + up_left_paths > 0: # no max_count_paths if no
while low < high: paths for any move
mid = (low + high) // 2 max_value = max(up_max, left_max, up_left_max)
value = ceiling(mid) - target if up_max == max_value:
if value >= 0: max_count_paths += up_paths
high = mid if left_max == max_value:
else: max_count_paths += left_paths
low = mid + 1 if up_left_max == max_value:
max_count_paths += up_left_paths
value = ceiling(low) - target max_value += int(board[r][c]) if r < rows - 1 or c < cols - 1 else 0 #
lower = ceiling(low - 1) - target handle "S" start cell
return low - 1 if abs(lower) <= abs(value) else low # return low - 1 if
closer or same diff to target visited[(r, c)] = [max_value, max_count_paths]
return [max_value, max_count_paths % MOD]

return helper(rows - 1, cols - 1)


# python_1001_to_2000/1301_Number_of_Paths_with_Max_Score.py - h

_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1302_Deepest_Leaves_Sum.py - m

# https://leetcode.com/problems/number-of-paths-with-max-score/ _author_ = 'jake'


# You are given a square board of characters. _project_ = 'leetcode'
# You can move on the board starting at the bottom right square marked with the character
'S'. # https://leetcode.com/problems/deepest-leaves-sum/
# You need to reach the top left square marked with the character 'E'. # Given a binary tree, return the sum of values of its deepest leaves.
# The rest of the squares are labeled either with a numeric character 1, 2, ..., 9 or
with an obstacle 'X'. # Breadth-first search.
# In one move you can go up, left or up-left (diagonally) only if there is no obstacle # For each layer, sum all the node values and find all nodes in the next layer.
there. # Repeat until the layer is empty and return the sum of nodes in the previous layer.
# Return a list of two integers: the first integer is the maximum sum of numeric # Time - O(n)
characters you can collect, # Space - O(n)
# and the second is the number of such paths that you can take to get that maximum sum,
taken modulo 10^9 + 7. class Solution(object):
# In case there is no path, return [0, 0]. def deepestLeavesSum(self, root):
"""
# Recursive helper function finds result from any cell. :type root: TreeNode
# Base cases of outside board and "X" return no paths. :rtype: int
# Base case of "E" returns one path with maximum value zero. """
# Recurse for the 3 possible moves. If all moves have no paths, return no paths. nodes = [root]
# Else find the max value and sum all paths with that value.
# Memoize to avoid repetition. while nodes:
# Time - O(mn) level_sum = 0
# Space - O(mn) new_nodes = []

class Solution(object): for node in nodes:


def pathsWithMaxScore(self, board): level_sum += node.val
""" if node.left:
:type board: List[str] new_nodes.append(node.left)
:rtype: List[int] if node.right:
""" new_nodes.append(node.right)
MOD = 10 ** 9 + 7
rows, cols = len(board), len(board[0]) nodes = new_nodes
visited = {}
return level_sum
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/1304_Find_N_Unique_Integers_Sum_up_to_Zero.py return result + tree1[i:] + tree2[j:] # append remaining nodes

_author_ = 'jake'
_project_ = 'leetcode'
# python_1001_to_2000/1306_Jump_Game_III.py - m
# https://leetcode.com/problems/find-n-unique-integers-sum-up-to-zero/
# Given an integer n, return any array containing n unique integers such that they add up _author_ = 'jake'
to 0. _project_ = 'leetcode'

# Use integers 1, 2, ... n // 2 and their negatives. # https://leetcode.com/problems/jump-game-iii/


# If n is odd, also append zero. # Given an array of non-negative integers arr, you are initially positioned at start
# Time - O(n) index of the array.
# Space - O(n) # 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.
class Solution(object): # Notice that you can not jump outside of the array at any time.
def sumZero(self, n):
""" # Recursive helper returns False if index is outside array and True if value is zero.
:type n: int # Else recurse jumping by +/- arr[i].
:rtype: List[int] # Record visited indices to avois loops.
""" # Time - O(n)
ints = [i for i in range(1, (n // 2) + 1)] # Space - O(n)
ints += [-i for i in ints]
return ints if n % 2 == 0 else ints + [0] class Solution(object):
def canReach(self, arr, start):
"""
:type arr: List[int]
# python_1001_to_2000/1305_All_Elements_in_Two_Binary_Search_Trees.py - m :type start: int
:rtype: bool
_author_ = 'jake' """
_project_ = 'leetcode' n = len(arr)
visited = set()
# https://leetcode.com/problems/all-elements-in-two-binary-search-trees/
# Given two binary search trees root1 and root2. def helper(i):
# Return a list containing all the integers from both trees sorted in ascending order. if i < 0 or i >= n:
return False
# Perform inorder traversals on each tree to get the node in ascending value order. if arr[i] == 0:
# Then iterate along the sorted lists to merge them. return True
# Alternatively, sort tree1 and tree2 instead of merging. if i in visited:
# Time - O(n) return False
# Space - O(n) visited.add(i)

class Solution(object): return helper(i + arr[i]) or helper(i - arr[i])


def getAllElements(self, root1, root2):
""" return helper(start)
:type root1: TreeNode
:type root2: TreeNode
:rtype: List[int]
""" # python_1001_to_2000/1309_Decrypt_String_from_Alphabet_to_Integer_Mapping.py
def inorder(node, ascending):
if not node: _author_ = 'jake'
return _project_ = 'leetcode'
inorder(node.left, ascending)
ascending.append(node.val) # https://leetcode.com/problems/decrypt-string-from-alphabet-to-integer-mapping/
inorder(node.right, ascending) # Given a string s formed by digits ('0' - '9') and '#' . We want to map s to English
lowercase characters as follows:
tree1, tree2 = [], [] # Characters ('a' to 'i') are represented by ('1' to '9') respectively.
inorder(root1, tree1) # Characters ('j' to 'z') are represented by ('10#' to '26#') respectively.
inorder(root2, tree2) # Return the string formed after mapping.
# It's guaranteed that a unique mapping will always exist.
result = []
i, j = 0, 0 # indices of next elements to merge # Iterate along s. If the char at position i + 2 is "#" then convert s[i:i + 2] to an
while i < len(tree1) and j < len(tree2): # until one list is exhausted integer.
if tree1[i] <= tree2[j]: # Else convert s[i] to an integer.
result.append(tree1[i]) # Time - O(n)
i += 1 # Space - O(n)
else:
result.append(tree2[j]) class Solution(object):
j += 1 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