github_jakehoare_leetcode_4splits_100scale_with_difficulty
github_jakehoare_leetcode_4splits_100scale_with_difficulty
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
# 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:
# 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
# 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
# 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.
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
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:
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:
_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
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
# 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
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'
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
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
# 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)
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
# 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)
max_index = 0
steps = 1
# 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
# 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))
# 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 []
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])
# python_1_to_1000/056_Merge_Intervals.py - m
# 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
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)
# python_1_to_1000/066_Plus_One.py
# 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
if colour < 2:
nums[next_white] = 1
next_white += 1 # python_1_to_1000/077_Combinations.py - m
# 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):
# 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)
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
# 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 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)
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
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)
# 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
self.val = x
_author_ = 'jake' self.left = None
_project_ = 'leetcode' self.right = None
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)
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):
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([])
# 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)
# 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)
# 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
# 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).
# 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)
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)
: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())
_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)
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]]
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
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))]
copy.next = next
# python_1_to_1000/137_Single_Number_II.py - m node = next
# 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:
# 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
# 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)
# 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.
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
# 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 = []
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
# 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
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.
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
# 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
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('-')
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
return candidate
# python_1_to_1000/168_Excel_Sheet_Column_Title.py
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()
# 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
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
# 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
# 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
# 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
# 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'
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
# 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)
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
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)
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
# 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)
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
_author_ = 'jake'
# python_1_to_1000/224_Basic_Calculator.py - h _project_ = 'leetcode'
class Solution(object):
def invertTree(self, root): # python_1_to_1000/228_Summary_Ranges.py
# 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))):
# 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 """
# 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 = []
# 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
_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
_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
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
# 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
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)
# 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 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'
"""
# 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
# 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
# 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):
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
# 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' """
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'
# 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
_author_ = 'jake'
# python_1_to_1000/291_Word_Pattern_II.py - m _project_ = 'leetcode'
_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
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'
# 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'
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])
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):
# 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'
# 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/
# 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
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
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)
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'
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)
# 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]))
# 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):
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:
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)
# 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)
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'
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)
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 = {}
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)]
# 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):
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/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 []
# 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):
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/381_Insert_Delete_GetRandom_O(1)_Duplicates_Allowed.py - h
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 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
# 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
return nested
class Solution(object):
# 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)
# 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):
# 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)
# 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
# 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
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):
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))
# 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.
# 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
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
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
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
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)
# 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
_author_ = 'jake'
# python_1_to_1000/441_Arranging_Coins.py _project_ = 'leetcode'
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))
# 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)
# 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
# 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
# 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 = []
# python_1_to_1000/463_Island_Perimeter.py
# 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
# 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
# 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
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
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):
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)
_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)):
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
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):
# 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
# 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]
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'
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])
if nm == -1:
# python_1_to_1000/499_The_Maze_III.py - h return "".join(moves)
# 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))
# 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'
# 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
"""
# 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)
# 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)
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)
# 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)]
# python_1_to_1000/527_Word_Abbreviation.py - h # python_1_to_1000/528_Random_Pick_with_Weight.py - m
# 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
# 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)
# 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)
# 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))
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
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
# 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'
# 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
# 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
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/561_Array_Partition_I.py
# 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
# 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
# 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 (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.
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)
# 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
# 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
# else if most significant bit of prefix is "0" then count is unchanged _author_ = 'jake'
# but no incermentail new integers are valid _project_ = 'leetcode'
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)
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)
_author_ = 'jake'
_project_ = 'leetcode' result += digit * tens
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]
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
# 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
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
# 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
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
"""
# 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)
# 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)
# 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'
# 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)
# 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)]
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):
# 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
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):
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
# 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)
while i < n // 2:
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))
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]
improvement
best_two = best_one + two_sum _author_ = 'jake'
best_two_i = [best_one_i, two_i] _project_ = 'leetcode'
# 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
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))
while n: # python_1_to_1000/695_Max_Area_of_Island.py - m
# 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
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)]
# 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 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
# 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
return target
# python_1_to_1000/716_Max_Stack.py - h
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 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
# 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 ""
# 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)
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)
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)
return True
# python_1_to_1000/732_My_Calendar_III.py - h # python_1_to_1000/733_Flood_Fill.py
# 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):
# 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)
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])
# 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'
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
# 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
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()
# 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:
# 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
# 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:
# 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)
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)
_author_ = 'jake'
# python_1_to_1000/764_Largest_Plus_Sign.py - m _project_ = 'leetcode'
# 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
# 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):
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)
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:
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):
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)
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'
# 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)
# 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
# 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
# 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
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
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)
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)
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
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 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
# 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
# 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
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'
# 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):
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
subarrays
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
_author_ = 'jake'
# python_1_to_1000/816_Ambiguous_Coordinates.py - m _project_ = 'leetcode'
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)
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)
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
# 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)
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
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
_author_ = 'jake'
# python_1_to_1000/835_Image_Overlap.py - m _project_ = 'leetcode'
return "".join(dominos)
# python_1_to_1000/838_Push_Dominoes.py - m
# 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
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
_author_ = 'jake' # Iterate backwards over shifts. Maintain the cumulative_shift, adding each shift and
_project_ = 'leetcode' shifting the char by the
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
# 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'
# Space - O(n) i += 1
_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
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
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]
# 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
_author_ = 'jake' # Find the index of S where the decoded string is of length at least K. Iterate backwards
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 = (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):
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
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)
# 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)
# 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)
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):
# python_1_to_1000/904_Fruit_Into_Baskets.py - m # python_1_to_1000/905_Sort_Array_By_Parity.py
# 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'
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 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
# 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
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)
# 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:
# 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
if A[first_start:first_end + 1] != A[second_start:second_start + length]: def infected(): # return number of infected nodes, starting
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)
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
# 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()
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
return 0 < left == right < n - 1 overlaps = [[0] * N for _ in range(N)] # overlaps[i][j] is nb chars overlapping
between x and y
# 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()
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/947_Most_Stones_Removed_with_Same_Row_or_Column.py - m
# 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:])
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
# 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)
_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
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)
_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)
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)]
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
# 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,
# 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)
_author_ = 'jake'
_project_ = 'leetcode' # python_1_to_1000/978_Longest_Turbulent_Subarray.py - m
# 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
_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/
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
# 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)
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
# 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):
# 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
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)
.... =
_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
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'
_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
# 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
# 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
_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
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)
# 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)
# 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
_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'
# 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
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)
# python_1001_to_2000/1041_Robot_Bounded_In_Circle.py - m
# 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
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)
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
# python_1001_to_2000/1057_Campus_Bikes.py - m # python_1001_to_2000/1058_Minimize_Rounding_Error_to_Meet_Target.py - m
# 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
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)
# 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)
_author_ = 'jake'
# python_1001_to_2000/1062_Longest_Repeating_Substring.py - m _project_ = 'leetcode'
# 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'
# 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!)
"""
: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)
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)
# 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).
# 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 "[.]".
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]
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
# 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.
# python_1001_to_2000/1120_Maximum_Average_Subtree.py - m
_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))
# 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]
_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)
_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'
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
# 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)
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
# 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]
_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
# 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")))
# 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)
# 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'
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
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
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)
# 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]])
# 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)
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
explore(root1) # python_1001_to_2000/1216_Valid_Palindrome_III.py - h
# 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)
# 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.
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
# 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()
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' # 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
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 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)]
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.
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 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):
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.
# 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
# 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)
# 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])
""" # 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 = []
_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
# 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
# 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'
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
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]]
_author_ = 'jake'
# python_1001_to_2000/1298_Maximum_Candies_You_Can_Get_from_Boxes.py - h _project_ = 'leetcode'
_author_ = 'jake'
_project_ = 'leetcode' # python_1001_to_2000/1302_Deepest_Leaves_Sum.py - m
_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'
:type s: str
:rtype: str
"""
result = []
n = len(s)
i = 0
while i < n:
if i + 2 < n and s[i + 2] == "#":
result.append(chr(int(s[i:i + 2]) + ord("a") - 1))
i += 3
else:
result.append(chr(int(s[i]) + ord("a") - 1))
i += 1
return "".join(result)
# python_1001_to_2000/1310_XOR_Queries_of_a_Subarray.py - m
_author_ = 'jake'
_project_ = 'leetcode'
# https://leetcode.com/problems/xor-queries-of-a-subarray/
# Given the array arr of positive integers and the array queries where queries[i] = [Li,
Ri],
# for each query i compute the XOR of elements from Li to Ri (that is, arr[Li] xor
arr[Li+1] xor ... xor arr[Ri] ).
# Return an array containing the result for the given queries.
class Solution(object):
def xorQueries(self, arr, queries):
"""
:type arr: List[int]
:type queries: List[List[int]]
:rtype: List[int]
"""
xor = [0]
for num in arr:
xor.append(xor[-1] ^ num)
result = []
for start, end in queries:
result.append(xor[end + 1] ^ xor[start])
return result