Meta Flashcards

1
Q

Description

A

Notes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q
  1. Add Two Numbers
    Medium

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example 1:

Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.

A
  1. carry or l1 or l2
  2. carry,value = divmod(carry, 10)

T: O(n)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q
  1. Longest Substring Without Repeating Characters
    Medium

Given a string s, find the length of the longest substring without repeating characters.

Example 1:

Input: s = “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.
Example 2:

Input: s = “bbbbb”
Output: 1
Explanation: The answer is “b”, with the length of 1.

A
  1. Sliding window
  2. while counter[swe]>1:
    counter[s[ws]]-=1
    ws+=1
    maxi=max(maxi, we-ws+1))def lengthOfLongestSubstring(self, s: str) -> int:
    ws=0
    counter=defaultdict(int)
     maxi=0
     for we, swe in enumerate(s):
         counter[swe]+=1
            
         while counter[swe]>1:
             counter[s[ws]]-=1
             #if counter[s[ws]]==0:
             #    del counter[s[ws]]
             ws+=1
            
         maxi=max(maxi, we-ws+1)
            
     return maxi

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q
  1. Median of Two Sorted Arrays
    Hard

Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.

The overall run time complexity should be O(log (m+n)).

Example 1:

Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: merged array = [1,2,3] and median is 2.
Example 2:

Input: nums1 = [1,2], nums2 = [3,4]
Output: 2.50000
Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.

A
  1. Right array must be longer (take left and right of N1). Half is (N1+N2+1)//2
  2. Binary search (while left<=right)
  3. i=(left+right)//2, j=half -i
  4. aleft=A[i-1] if A[i-1]>0 else float(‘-inf’), bleft=B[j-1]….
  5. aright = A[i] if ibright: right=i-1. Else left=i+1

Super weird. Need to figure out how to explain this logic.

def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    A = nums1
    B = nums2
    if len(A) > len(B):
        A, B = B, A

    N1 = len(A)
    N2 = len(B)
    left = 0
    half = (N1 + N2 + 1) // 2
    right = N1

    while left <= right:
        i = (left + right) // 2
        j = half - i

        aleft = A[i - 1] if i - 1 >= 0 else float('-inf')
        bleft = B[j - 1] if j - 1 >= 0 else float('-inf')
        aright = A[i] if i < N1 else float('inf')
        bright = B[j] if j < N2 else float('inf')

        if aleft <= bright and bleft <= aright:
            if (N1 + N2) % 2 != 0:
                return max(aleft, bleft)
            else:
                return (max(aleft, bleft) + min(aright, bright)) / 2.0
        elif aleft > bright:
            right = i - 1
        else:
            left = i + 1
    return -1

T: O(log(min(m,n))
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q
  1. Longest Palindromic Substring
    Medium

Given a string s, return the longest palindromic substring in s.

Example 1:

Input: s = “babad”
Output: “bab”
Explanation: “aba” is also a valid answer.
Example 2:

Input: s = “cbbd”
Output: “bb”

A
  1. Expand from middle
  2. is_odd=is_palin(s, i, i)
  3. is_even=is_palin(s, i, i+1)
  4. longest = max(longest, odd, even, key=len)
  5. within is_palin,
    while low>=0 and high str:
    longest=””
    for i in range(len(s)):
    odd=self.is_palin(s, i, i)
    even=self.is_palin(s, i, i+1)
    longest=max(longest, odd, even, key=len)
    return longestdef is_palin(self, s, low, high):
    while low>=0 and high
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q
  1. Zigzag Conversion
    Medium

The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

P A H N
A P L S I I G
Y I R
And then read line by line: “PAHNAPLSIIGYIR”

Write the code that will take a string and make this conversion given a number of rows:

string convert(string s, int numRows);

Example 1:

Input: s = “PAYPALISHIRING”, numRows = 3
Output: “PAHNAPLSIIGYIR”
Example 2:

Input: s = “PAYPALISHIRING”, numRows = 4
Output: “PINALSIGYAHRPI”
Explanation:
P I N
A L S I G
Y A H R
P I

A
  1. Tricky. Maintain a defaultdict(list)
  2. index=1, up=False
  3. Iterate through s and append to result[index]
  4. if up, index-=1, else index+=1
  5. if index==numRows or index==1: up = not updef convert(self, s: str, numRows: int) -> str:
    if numRows==1:
    return s
     result=defaultdict(list)
        
     index=1
     up=False
        
     for c in s:
         result[index].append(c)
            
         if up:
             index-=1
         else:
             index+=1
                
         if index==numRows or index==1:
             up=not up
        
     ret_result=""
     for i in range(1, numRows+1):
         ret_result+=''.join(result[i])
        
     return ret_result

T: O(n)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q
  1. Reverse Integer
    Medium

Given a signed 32-bit integer x, return x with its digits reversed. If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], then return 0.

Assume the environment does not allow you to store 64-bit integers (signed or unsigned).

Example 1:

Input: x = 123
Output: 321
Example 2:

Input: x = -123
Output: -321

A
  1. divmoddef reverse(self, x: int) -> int:
    sign=1
     if x<0:
         sign=-1
         x*=-1
        
     cx=0
     while x:
         x,value = divmod(x, 10)
         cx=cx*10+value
        
     cx=sign*cx
     return cx if -2**31 <=cx <=2**31-1 else 0

T: O(log(x)), logx is the number of digits in x (log10)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q
  1. String to Integer (atoi)
    Medium

Implement the myAtoi(string s) function, which converts a string to a 32-bit signed integer.

The algorithm for myAtoi(string s) is as follows:

Whitespace: Ignore any leading whitespace (“ “).
Signedness: Determine the sign by checking if the next character is ‘-‘ or ‘+’, assuming positivity is neither present.
Conversion: Read the integer by skipping leading zeros until a non-digit character is encountered or the end of the string is reached. If no digits were read, then the result is 0.
Rounding: If the integer is out of the 32-bit signed integer range [-231, 231 - 1], then round the integer to remain in the range. Specifically, integers less than -231 should be rounded to -231, and integers greater than 231 - 1 should be rounded to 231 - 1.
Return the integer as the final result.

Example 1:

Input: s = “42”

Output: 42

Explanation:

The underlined characters are what is read in and the caret is the current reader position.
Step 1: “42” (no characters read because there is no leading whitespace)
^
Step 2: “42” (no characters read because there is neither a ‘-‘ nor ‘+’)
^
Step 3: “42” (“42” is read in)
^

A
  1. Strip and see if there’s no string. Else, return
  2. Convert it to a list.
  3. Check sign and set sign variable to be 1 or -1. Delete the first item after sign is gotten (if +/-).
  4. While i int:
    if not s.strip():
    return 0
     slist=list(s.strip())
        
     sign=1
     if slist[0]=='-':
         sign=-1
            
     if slist[0] in '+-':
         del slist[0]
        
     num=0
     i=0
        
     while i
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q
  1. Regular Expression Matching
    Hard

Given an input string s and a pattern p, implement regular expression matching with support for ‘.’ and ‘*’ where:

’.’ Matches any single character.​​​​
‘*’ Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).

Example 1:

Input: s = “aa”, p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.
Example 2:

Input: s = “aa”, p = “a
Output: true
Explanation: ‘
’ means zero or more of the preceding element, ‘a’. Therefore, by repeating ‘a’ once, it becomes “aa”.
Example 3:

Input: s = “ab”, p = “.
Output: true
Explanation: “.
” means “zero or more (*) of any character (.)”.

A
  1. Backtracking, helper with s, p, i and j
  2. if j==len(p) return i==len(s)
  3. first condition is to check the non character match. Then character match
  4. if j+1 bool:
    return self.is_match(s, p, 0,0)@lru_cache
    def is_match(self, s, p, i, j):
    if j==len(p):
    return i==len(s)
     if j+1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q
  1. Container With Most Water
    Medium

You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).

Find two lines that together with the x-axis form a container, such that the container contains the most water.

Return the maximum amount of water a container can store.

Notice that you may not slant the container.

Example 1:

Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example 2:

Input: height = [1,1]
Output: 1

A
  1. left, right=N-1
  2. basic two pointerdef maxArea(self, heights: List[int]) -> int:
    left=0
    right=len(heights)-1
     max_area=0
        
     while left
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q
  1. 3Sum
    Medium

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Notice that the solution set must not contain duplicate triplets.

Example 1:

Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].
Notice that the order of the output and the order of the triplets does not matter.

A
  1. sort the nums
  2. for each num, take the current num and convert into -target. Call two_sum
  3. In order to avoid duplicates (if i>0 and nums[i]==nums[i-1] continue)
  4. Within two_sum, if result is found, add (-target, nums[i], nums[j].
  5. Also for next num, increment i+1 and j+1 and then do a while loop to compare:
    while i List[List[int]]:
    nums.sort()
    result=[]
    for i, num in enumerate(nums):
    if i>0 and nums[i]==nums[i-1]:
    continue
    self.two_sum(-num, nums, i, result)
    return resultdef two_sum(self, target, nums, ti, result):
    i=ti+1
    j=len(nums)-1
     while itarget:
             j-=1
         else:
             result.append([-target, nums[i], nums[j]])
             i+=1
             j-=1
             while i
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q
  1. 3Sum Closest
    Medium

Given an integer array nums of length n and an integer target, find three integers in nums such that the sum is closest to target.

Return the sum of the three integers.

You may assume that each input would have exactly one solution.

Example 1:

Input: nums = [-1,2,1,-4], target = 1
Output: 2
Explanation: The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

A
  1. Sort the nums
  2. initialize closest to sum(nums[:3])
  3. for loop through 0 to N-2 and then while loop (ii=i+1, j=N-1)
  4. csum = i+ii+jj
  5. if csum==target, return
  6. if csum-target int:
    if len(nums)<=3:
    return sum(nums)
     nums.sort()
     N=len(nums)
        
     closest=sum(nums[:3])
     for i in range(N-2):
         ii=i+1
         jj=N-1
         while ii
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q
  1. Letter Combinations of a Phone Number
    Medium

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.

A mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

Example 1:

Input: digits = “23”
Output: [“ad”,”ae”,”af”,”bd”,”be”,”bf”,”cd”,”ce”,”cf”]

A
  1. Backtracking. Contruct a map of integer to keys- {2:”abc”….}
  2. helper with index, curr, result and map
  3. if len(curr)==len(digits), result.append(curr) and return
  4. if index>len(digits), return
  5. for c in mapp[digits[index]]:
    bt(curr+c, digits, index+1, mapp)def letterCombinations(self, digits: str) -> List[str]:
    if not digits:
    return None
    result=[]
    mapp = {“2”: “abc”, “3”: “def”, “4”: “ghi”, “5”: “jkl”, “6”: “mno”, “7”: “pqrs”, “8”: “tuv”, “9”: “wxyz”}
    self.bt(digits, 0, result, ‘’, mapp)
    return resultdef bt(self, digits, i, result, curr, mapp):
    if len(curr)==len(digits):
    result.append(curr)
    return
     if i>=len(digits):
         return
        
     for c in mapp[digits[i]]:
         self.bt(digits, i+1, result, curr+c, mapp)

T: O(4^n)
S: O(n) - not counting the result space, stack space is N. Goes to the depth of the number of digits, since when we reach the number of digits, we return.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q
  1. 4Sum
    Medium

Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:

0 <= a, b, c, d < n
a, b, c, and d are distinct.
nums[a] + nums[b] + nums[c] + nums[d] == target
You may return the answer in any order.

Example 1:

Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
Example 2:

Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]

A
  1. N^3 solution
  2. for i in range(N), j in range(i+1, N), ii=j+1, jj=N-1
  3. Do a two_sum for ii and jjdef fourSum(self, nums: List[int], target: int) -> List[List[int]]:
    N = len(nums)
    nums.sort()
    result = set()
    for i in range(N):
    for j in range(i + 1, N):
    itarget = target - (nums[i] + nums[j])
    ii = j + 1
    jj = N - 1
    while ii < jj:
    csum = nums[ii] + nums[jj]
    if csum < itarget:
    ii += 1
    elif csum > itarget:
    jj -= 1
    else:
    result.add((nums[i], nums[j], nums[ii], nums[jj]))
    ii += 1
    jj -= 1
    return result

T: O(n^3)
S: O(n) - for sorting

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q
  1. Remove Nth Node From End of List
    Medium

Given the head of a linked list, remove the nth node from the end of the list and return its head.

Example 1:

Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

A
  1. Two pointer. Move fast to n
  2. Move slow and fast together
  3. if not fast, return head.nextdef removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
    fast=head
     for i in range(n):
         fast=fast.next
            
     if not fast:
         return head.next
    
     slow=head
        
     while fast.next:
         fast=fast.next
         slow=slow.next
            
     slow.next=slow.next.next
        
     return head

T: O(n)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q
  1. Generate Parentheses
    Medium

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

Example 1:

Input: n = 3
Output: [”((()))”,”(()())”,”(())()”,”()(())”,”()()()”]

A
  1. Use helper - n, curr, result, open, close
  2. if open List[str]:
    result = []
    self.generate_parenthesis(n, “”, result, 0, 0)
    return resultdef generate_parenthesis(self, n, curr, result, open, close):
    if len(curr) == n * 2:
    result.append(curr)
    return
    if open < n:
    self.generate_parenthesis(n, curr + ‘(‘, result, open + 1, close)
     if close < open:
         self.generate_parenthesis(n, curr + ')', result, open, close + 1)

T: O(2^2n) - O(4^n) - The tree can potentially have 2^{2n} nodes because at each step (with up to 2n steps), it can choose to add an opening or closing parenthesis. nth catalan number is 4^n….
S: O(n) - stack until twice the depth of n

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q
  1. Merge k Sorted Lists
    Hard

You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.

Merge all the linked-lists into one sorted linked-list and return it.

Example 1:

Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
1->4->5,
1->3->4,
2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6

A
  1. Use heap. Iterate through each list and append first item of the list and list (if list exists)
  2. construct a new LinkedList
  3. Pop from heap, create new node with value and append to the list
  4. If popped list.next, then add to heapdef mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
    pq=[]
     for i, each in enumerate(lists):
         if each:
             heapq.heappush(pq, (each.val, i, each))
            
     head=sent=ListNode(0)
     while pq:
         val, idx, lst = heapq.heappop(pq)
         head.next=ListNode(val)
         head=head.next
            
         if lst.next:
             heapq.heappush(pq, (lst.next.val, idx, lst.next))
            
            
     return sent.next

T: O(nlogm) - m size of the LL and n is the total size of all LL together
S: O(m) - maximum of 3 nodes is kept in the heap (result is not counted)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q
  1. Swap Nodes in Pairs
    Medium

Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list’s nodes (i.e., only nodes themselves may be changed.)

Example 1:

Input: head = [1,2,3,4]
Output: [2,1,4,3]

A
  1. Hard, honestly. Recursive is easier.def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
    if not head or not head.next:
    return head
     second = head.next
     prev = ListNode(0)
     while head and head.next:
         nxt = head.next
         head.next = nxt.next
         nxt.next = head
    
         prev.next = nxt
         head = head.next
         prev = nxt.next
     return second
    
     # if head and head.next:
     #     temp=head.next
     #     head.next=self.swapPairs(temp.next)
     #     temp.next=head
     #     return temp
     # return head

T: O(n)
S: O(n) - stack used for recursion

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q
  1. Next Permutation
    Medium

A permutation of an array of integers is an arrangement of its members into a sequence or linear order.

For example, for arr = [1,2,3], the following are all the permutations of arr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].
The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).

For example, the next permutation of arr = [1,2,3] is [1,3,2].
Similarly, the next permutation of arr = [2,3,1] is [3,1,2].
While the next permutation of arr = [3,2,1] is [1,2,3] because [3,2,1] does not have a lexicographical larger rearrangement.
Given an array of integers nums, find the next permutation of nums.

The replacement must be in place and use only constant extra memory.

Example 1:

Input: nums = [1,2,3]
Output: [1,3,2]

A

[12431]->[13124]
1. From the last identify the first drop from an increase (target=N-1, while i>0 and nums[target-1]>nums[target], target-=1
2. if target==0, then reverse and return (since the sub permutation is already done)
3. target-=1 (to be swapped, since we are breaking when target-1 None:
target=len(nums)-1

    while target>0 and nums[target-1]>=nums[target]:
        target-=1
        
    if target==0:
        nums.reverse()
        return
    
    target-=1
    
    source=len(nums)-1
    
    while nums[source]<=nums[target]:
        source-=1
    
    nums[source], nums[target]=nums[target], nums[source]
    
    left=target+1
    right=len(nums)-1
    
    while left
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q
  1. Search in Rotated Sorted Array
    Medium

There is an integer array nums sorted in ascending order (with distinct values).

Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].

Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.

You must write an algorithm with O(log n) runtime complexity.

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

A
  1. Binary search with a twist.
  2. if nums[mid]==target: return mid
  3. if nums[low]<=nums[mid]:
    if nums[low]<=target int:
    low=0
    high=len(nums)-1
     while low<=high:
         mid=(low+high)//2
         if nums[mid]==target:
             return mid
         elif nums[low]<=nums[mid]:
             if nums[low]<=target
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q
  1. Find First and Last Position of Element in Sorted Array
    Medium

Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value.

If target is not found in the array, return [-1, -1].

You must write an algorithm with O(log n) runtime complexity.

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
Example 3:

Input: nums = [], target = 0
Output: [-1,-1]

A
  1. Binary search - bisect_left and bisect_right
  2. bisect_left: if arr[mid] List[int]:
    left=self.bisect_left(nums, target)dd
    right=self.bisect_right(nums, target)
     if left==right:
         return [-1,-1]
     else:
         return [left, right-1]
    def bisect_left(self, nums, target):
    left=0
    right=len(nums)-1
     while left<=right:
         mid=(left+right)//2
            
         if nums[mid]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q
  1. Valid Sudoku
    Medium

Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:

Each row must contain the digits 1-9 without repetition.
Each column must contain the digits 1-9 without repetition.
Each of the nine 3 x 3 sub-boxes of the grid must contain the digits 1-9 without repetition.
Note:

A Sudoku board (partially filled) could be valid but is not necessarily solvable.
Only the filled cells need to be validated according to the mentioned rules.

Example 1:

Input: board =
[[“5”,”3”,”.”,”.”,”7”,”.”,”.”,”.”,”.”]
,[“6”,”.”,”.”,”1”,”9”,”5”,”.”,”.”,”.”]
,[”.”,”9”,”8”,”.”,”.”,”.”,”.”,”6”,”.”]
,[“8”,”.”,”.”,”.”,”6”,”.”,”.”,”.”,”3”]
,[“4”,”.”,”.”,”8”,”.”,”3”,”.”,”.”,”1”]
,[“7”,”.”,”.”,”.”,”2”,”.”,”.”,”.”,”6”]
,[”.”,”6”,”.”,”.”,”.”,”.”,”2”,”8”,”.”]
,[”.”,”.”,”.”,”4”,”1”,”9”,”.”,”.”,”5”]
,[”.”,”.”,”.”,”.”,”8”,”.”,”.”,”7”,”9”]]
Output: true

A
  1. defaultdict(set) for rows, cols and boxes
  2. box formula is (r//3)*3+(c//3)def isValidSudoku(self, board: List[List[str]]) -> bool:
    rows = defaultdict(set)
    cols = defaultdict(set)
    boxes = defaultdict(set)
     R = len(board)
     C = len(board[0])
    
     for r in range(R):
         for c in range(C):
             if board[r][c] == '.':
                 continue
             if board[r][c] in rows[r]:
                 return False
             rows[r].add(board[r][c])
             if board[r][c] in cols[c]:
                 return False
             cols[c].add(board[r][c])
    
             box = (r // 3) * 3 + (c // 3)
             if board[r][c] in boxes[box]:
                 return False
             boxes[box].add(board[r][c])
     return True

T: O(MN) - 99 - O(81) - O(1)
S: O(9+9+9) - O(27) - O(1) - 9 rows, 9 cols and 9 boxes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q
  1. Count and Say
    Medium

The count-and-say sequence is a sequence of digit strings defined by the recursive formula:

countAndSay(1) = “1”
countAndSay(n) is the run-length encoding of countAndSay(n - 1).
Run-length encoding (RLE) is a string compression method that works by replacing consecutive identical characters (repeated 2 or more times) with the concatenation of the character and the number marking the count of the characters (length of the run). For example, to compress the string “3322251” we replace “33” with “23”, replace “222” with “32”, replace “5” with “15” and replace “1” with “11”. Thus the compressed string becomes “23321511”.

Given a positive integer n, return the nth element of the count-and-say sequence.

Example 1:

Input: n = 4

Output: “1211”

Explanation:

countAndSay(1) = “1”
countAndSay(2) = RLE of “1” = “11”
countAndSay(3) = RLE of “11” = “21”
countAndSay(4) = RLE of “21” = “1211”

A
  1. Tricky. Initialize s=”1”
  2. Iterate until n-1 (since 1 is already the first iteration)
  3. count=0, start=s[0], temp=’’
  4. for l in s:
    if start==l:
    increment count
    else:
    append str(count) + start to temp
    reset count=1 and start=l
  5. As a cleanup, append to temp the last iteration
  6. s=tempdef countAndSay(self, n: int) -> str:
    s=”1”
     for _ in range(n-1):
         count=0
         temp=''
         start=s[0]
            
         for l in s:
             if start==l:
                 count+=1
             else:
                 temp+=str(count)+start
                 start=l
                 count=1
         temp+=str(count)+start
         s=temp
     return s

T: O(2^n) - For every iteration, the s approximately doubles
S: O(2^n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q
  1. Combination Sum II
    Medium

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target.

Each number in candidates may only be used once in the combination.

Note: The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8
Output:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

A
  1. Call helper with result, curr, target
  2. Skipping duplicates : if i!=index and candidates[i]==candidates[i-1]: continuedef combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
    result = []
    candidates.sort()
    self.combination_sum(candidates, target, 0, [], result)
    return resultdef combination_sum(self, candidates, target, index, curr, result):
    if target == 0:
    result.append(curr.copy())
    return
    if target < 0:
    return
     for i in range(index, len(candidates)):
         if i != index and i > 0 and candidates[i] == candidates[i - 1]:
             continue
         self.combination_sum(candidates, target - candidates[i], i + 1, curr + [candidates[i]], result)

T: O(2^n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q
  1. Trapping Rain Water
    Hard

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

Example 1:

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.

A
  1. Two pointers
  2. Fast forward left and right until they are 0
  3. If left>right: return 0
  4. lmax=heights[0], rmax=heights[-1]
  5. while left<=right,
    if current left is greater than right, then
    1. set lmax
    2. trapped+= lmax-hleft
    3. left+=1
  6. Do reverse for rightdef trap(self, heights: List[int]) -> int:
    if len(heights)==1:
    return 0
     left = 0
     while heights[left] == 0:
         left += 1
    
     right = len(heights) - 1
     while heights[right] == 0:
         right -= 1
    
     if left > right:
         return 0
    
     lmax = heights[0]
     rmax = heights[-1]
    
     trapped = 0
     while left <= right:
         hleft = heights[left]
         hright = heights[right]
         if hleft < hright:
             lmax = max(hleft, lmax)
             trapped += lmax - hleft
             left += 1
         else:
             rmax = max(rmax, hright)
             trapped += rmax - hright
             right -= 1
     return trapped

T: O(n)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q
  1. Multiply Strings
    Medium

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.

Note: You must not use any built-in BigInteger library or convert the inputs to integer directly.

Example 1:

Input: num1 = “2”, num2 = “3”
Output: “6”
Example 2:

Input: num1 = “123”, num2 = “456”
Output: “56088”

A
  1. Regular multiplication. Initialize result to [0]* (N1+N2)
  2. Outer loop is reversed(num1) and inner loop is reversed(num2)
  3. Initialize temp=pos (which was originally len(result)-1
  4. During each iteration,
    result[temp]+= n1*n2
    result[temp-1]+= result[temp]//10
    result[temp]%=10
    temp-=1 (for inner loop)
  5. pos-=1 for outer loop
  6. Finally, we need to skip off all the leading zeroes and return the string

class Solution:
def multiply(self, num1: str, num2: str) -> str:
N1=len(num1)
N2=len(num2)

    result=[0]*(N1+N2)
    pos=len(result)-1
    
    for n1 in reversed(num1):
        temp=pos
        for n2 in reversed(num2):
            result[temp]+=int(n1)*int(n2)
            result[temp-1]+=result[temp]//10
            result[temp]%=10
            temp-=1
        pos-=1

    pt=0
    while pt
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q
  1. Next Permutation
    Medium

A permutation of an array of integers is an arrangement of its members into a sequence or linear order.

For example, for arr = [1,2,3], the following are all the permutations of arr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].
The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).

For example, the next permutation of arr = [1,2,3] is [1,3,2].
Similarly, the next permutation of arr = [2,3,1] is [3,1,2].
While the next permutation of arr = [3,2,1] is [1,2,3] because [3,2,1] does not have a lexicographical larger rearrangement.
Given an array of integers nums, find the next permutation of nums.

The replacement must be in place and use only constant extra memory.

Example 1:

Input: nums = [1,2,3]
Output: [1,3,2]

A
  1. Use a maskdef permuteUnique(self, nums: List[int]) -> List[List[int]]:
    nums.sort()
    mask=0
    result=[]
    self.helper(nums, [], result, mask)
    return resultdef helper(self, nums, curr, result, mask):
    if mask ==(1<0 and nums[i]==nums[i-1] and not mask&(1«(i-1)):
    continue
    self.helper(nums, curr+[nums[i]], result, (mask | (1«i></i>
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q
  1. Permutations II
    Medium

Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

Example 1:

Input: nums = [1,1,2]
Output:
[[1,1,2],
[1,2,1],
[2,1,1]]
Example 2:

Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

A
  1. Call helper with curr, and result
  2. Iterate through i, len(nums) and invoke helper.
  3. Add nums[i] to curr but pass nums[:i]+nums[i+1:] to helper

self.helper(nums[:i]+nums[i+1:], curr=[nums[i]], result)

T: N! (n steps for each permutation)
S: O(N) not counting the result

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q
  1. Rotate Image
    Medium

You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise).

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Example 1:

Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [[7,4,1],[8,5,2],[9,6,3]]

A
  1. Flip and reverse
  2. While flipping range(R) but C=range(r)def rotate(self, matrix: List[List[int]]) -> None:
    R=len(matrix)
    C=len(matrix[0])
     for r in range(R):
         for c in range(r):
             matrix[r][c], matrix[c][r]=matrix[c][r], matrix[r][c]
            
     for r in range(R):
         matrix[r].reverse()

T: O(n*m)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q
  1. Group Anagrams
    Medium

Share
Given an array of strings strs, group the anagrams together. You can return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Example 1:

Input: strs = [“eat”,”tea”,”tan”,”ate”,”nat”,”bat”]
Output: [[“bat”],[“nat”,”tan”],[“ate”,”eat”,”tea”]]

A

def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
mapp = defaultdict(list)
for st in strs:
mapp[tuple(sorted(st))].append(st)

    return [v for k,v in mapp.items()]

T: O(N*KlogK)
S: O(NK)

K = maximum length of the string in strs

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q
  1. Pow(x, n)
    Medium

Implement pow(x, n), which calculates x raised to the power n (i.e., xn).

Example 1:

Input: x = 2.00000, n = 10
Output: 1024.00000
Example 2:

Input: x = 2.10000, n = 3
Output: 9.26100

A
  1. If negative, make it positive and x=1/x
  2. Loop until x and divide n//2 and xx. But before that, if odd, append to result (result=resultx), n-=1def myPow(self, x: float, n: int) -> float:
    result=1
     if n<0:
         n=-n
         x=1/x
            
     while n:
         if n%2!=0:
             result=result*x
             n-=1
         x*=x
         n//=2
     return result

T: O(logn)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q
  1. N-Queens
    Hard

The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.

Each solution contains a distinct board configuration of the n-queens’ placement, where ‘Q’ and ‘.’ both indicate a queen and an empty space, respectively.

Example 1:

Input: n = 4
Output: [[“.Q..”,”…Q”,”Q…”,”..Q.”],[”..Q.”,”Q…”,”…Q”,”.Q..”]]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above

A
  1. Backtracking and post processing is slightly tricky.
  2. p=len(curr) and p+q in anti_diag and p-q in diag and q not in curr
  3. remaining dot is n-p-1def solveNQueens(self, n: int) -> List[List[str]]:
    res=[]
    self.solve_n_queens(n, [], [], [], res)
     result=[]
        
     for r in res:
         curr=[]
         for pos in r:
             st=('.'*pos) + 'Q' + '.'*(n-pos-1)
             curr.append(st)
         result.append(curr)
     return result
    def solve_n_queens(self, n, curr, diag, anti_diag, result):
    p=len(curr)
    if p==n:
    result.append(curr.copy())
    return
     for q in range(n):
         if q not in curr and (p+q) not in anti_diag and (p-q) not in diag:
             self.solve_n_queens(n, curr+[q], diag+[p-q], anti_diag +[p+q], result)

T: O(n!)
S: O(n^2) - board is of size N*N

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q
  1. Jump Game
    Medium

You are given an integer array nums. You are initially positioned at the array’s first index, and each element in the array represents your maximum jump length at that position.

Return true if you can reach the last index, or false otherwise.

Example 1:

Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:

Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.

A
  1. if i>max_reach (initialized to 0), return False
  2. max_reach=max(max_reach, i+num)def canJump(self, nums: List[int]) -> bool:
     max_reach=0
        
     for i, num in enumerate(nums):
         if i>max_reach:
             return False
            
         max_reach=max(max_reach, i+num)
     return True

T: O(n)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q
  1. Merge Intervals
    Medium

Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.

Example 1:

Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlap, merge them into [1,6].

A
  1. set start interval to be mstart and mend
  2. Iterate through intervals[1:]
  3. If mstartmend, then
    1. add old mstart and mend to result
    2. mstart,mend=cstart,cend
  4. Finally before exiting, add mstart, mend to result to capture dangling onedef merge(self, intervals: List[List[int]]) -> List[List[int]]:
    if not intervals:
    return None
     intervals.sort(key=lambda x: x[0])
        
     mstart,mend=intervals[0]
     result=[]
     for cstart, cend in intervals[1:]:
         if cstart<=mend and mstart<=cend:
             mstart=min(cstart, mstart)
             mend=max(cend, mend)
         elif cstart>mend:
             result.append([mstart, mend])
             mstart, mend=cstart, cend
     result.append([mstart, mend])
    
     return result

T:O(nlogn)
S:O(n) - for sorting

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q
  1. Insert Interval
    Medium

You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.

Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if necessary).

Return intervals after the insertion.

Note that you don’t need to modify intervals in-place. You can make a new array and return it.

Example 1:

Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]

A
  1. Three conditions.
  2. if cendnend: #the new interval has passed
    result.append(nstart,nend)
    result.extend(intervals[i:])
    return result
  3. else: #overlap
    nstart=min(nstart, cstart)
    nend =max(nend,cend)
  4. finally, add residual - result.append(nstart,nend)def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
    nstart, nend=newInterval
     result=[]
     for i,interval in enumerate(intervals):
         cstart, cend=interval
            
         if cendnend:
             result.append([nstart, nend])
             result.extend(intervals[i:])
             return result
         else:
             nstart=min(nstart, cstart)
             nend=max(nend, cend)
     result.append([nstart, nend])
     return result

T:O(n)
S:O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q
  1. Unique Paths
    Medium

There is a robot on an m x n grid. The robot is initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot can only move either down or right at any point in time.

Given the two integers m and n, return the number of possible unique paths that the robot can take to reach the bottom-right corner.

The test cases are generated so that the answer will be less than or equal to 2 * 109.

Input: m = 3, n = 7
Output: 28

A
  1. DP - recursive and tabulation.
  2. For tabulation, populate a m*n dp with 1 and start R,C loop with 1,R and 1,C
  3. For recursion, the way to think about is a tree.
  4. base case is (r,c)=(R-1, C-1): return 1
  5. if r=R or c==C: return 0
  6. counts=self.helper(R, C, r+1, c) + self.helper(R, C, r, c+1)def uniquePaths(self, m: int, n: int) -> int:
    return self.helper(m, n, 0,0, {})def helper(self, R, C, r, c, memo):
    if (r,c) in memo:
    return memo[(r,c)]
     if (r,c) == (R-1, C-1):
         return 1
        
     if r==R or c==C:
         return 0
        
     counts=self.helper(R, C, r+1, c, memo)
     counts+=self.helper(R, C, r, c+1, memo)
     memo[(r,c)]=counts
     return counts
    def uniquePaths(self, m: int, n: int) -> int:
    R = m
    C = n
    dp = [[1] * C for _ in range(R)]
    for r in range(1, R):
    for c in range(1, C):
    dp[r][c] = (dp[r - 1][c] + dp[r][c - 1])
    return dp[-1][-1]

T: O(nm)
S: O(n
m)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q
  1. Valid Number
    Hard

Given a string s, return whether s is a valid number.

For example, all the following are valid numbers: “2”, “0089”, “-0.1”, “+3.14”, “4.”, “-.9”, “2e10”, “-90E3”, “3e+7”, “+6e-1”, “53.5e93”, “-123.456e789”, while the following are not valid numbers: “abc”, “1a”, “1e”, “e3”, “99e2.5”, “–6”, “-+3”, “95a54e53”.

Formally, a valid number is defined using one of the following definitions:

An integer number followed by an optional exponent.
A decimal number followed by an optional exponent.
An integer number is defined with an optional sign ‘-‘ or ‘+’ followed by digits.

A decimal number is defined with an optional sign ‘-‘ or ‘+’ followed by one of the following definitions:

Digits followed by a dot ‘.’.
Digits followed by a dot ‘.’ followed by digits.
A dot ‘.’ followed by digits.
An exponent is defined with an exponent notation ‘e’ or ‘E’ followed by an integer number.

The digits are defined as one or more digits.

Example 1:

Input: s = “0”

Output: true

A
  1. Key principles:
    1. Dot cannot come after e
    2. Sign has to be [0] or just after e [i-1]. If i>0 and s[i-1].lower()!=e: return False
    3. If e seen, then number must be seen after that. So, return number_seen
  2. Four variables: is_e_seen, is_number_seen, is_dot_seen and is_sign_seen
  3. If digit faced, number_seen=True
  4. If dot seen and (dot already seen or e_seen), return False. Else, set the var
  5. If e_seen and (e already seen or not number_seen) (first e), return False. Else set var and number_seen=False
  6. else, return False
  7. return number_seendef isNumber(self, s: str) -> bool:
    s=s.strip()
     is_dot_seen=False
     is_e_seen=False
     is_number_seen=False
     is_sign_seen=False
        
        
     for i,c in enumerate(s):
         if c in '1234567890':
             is_number_seen=True
         elif c=='.':
             if is_dot_seen or is_e_seen:
                 return False
             is_dot_seen=True
         elif c in '+-':
             if i>0 and s[i-1].lower()!='e':
                 return False
             is_sign_seen=True
         elif c in 'eE':
             if is_e_seen or not is_number_seen:
                 return False
             is_e_seen=True
             is_number_seen=False
         else:
             return False
     return is_number_seen

T: O(N)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
38
Q
  1. Text Justification
    Hard

Given an array of strings words and a width maxWidth, format the text such that each line has exactly maxWidth characters and is fully (left and right) justified.

You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ‘ ‘ when necessary so that each line has exactly maxWidth characters.

Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line does not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right.

For the last line of text, it should be left-justified, and no extra space is inserted between words.

Note:

A word is defined as a character sequence consisting of non-space characters only.
Each word’s length is guaranteed to be greater than 0 and not exceed maxWidth.
The input array words contains at least one word.

Example 1:

Input: words = [“This”, “is”, “an”, “example”, “of”, “text”, “justification.”], maxWidth = 16
Output:
[
“This is an”,
“example of text”,
“justification. “
]
Example 2:

Input: words = [“What”,”must”,”be”,”acknowledgment”,”shall”,”be”], maxWidth = 16
Output:
[
“What must be”,
“acknowledgment “,
“shall be “
]
Explanation: Note that the last line is “shall be “ instead of “shall be”, because the last line must be left-justified instead of fully-justified.
Note that the second line is also left-justified because it contains only one word.
Example 3:

Input: words = [“Science”,”is”,”what”,”we”,”understand”,”well”,”enough”,”to”,”explain”,”to”,”a”,”computer.”,”Art”,”is”,”everything”,”else”,”we”,”do”], maxWidth = 20
Output:
[
“Science is what we”,
“understand well”,
“enough to explain to”,
“a computer. Art is”,
“everything else we”,
“do “
]

A
  1. Very hard problemdef fullJustify(self, words, maxWidth):
    N = len(words)
    L = maxWidth
    i = 0
    result = []
     def get_kwords(i):
         curr_len = len(words[i])
         k = 1
         while i + k < N:
             next_len = len(words[i + k]) + 1
             if curr_len + next_len <= L:
                 k += 1
                 curr_len += next_len
             else:
                 break
         return k
    
     def insert_space(i, k):
         line = ' '.join(words[i:i + k])
         if k == 1 or i + k == N:
             spaces = L - len(line)
             line += ' ' * spaces
             return line
         else:
             spaces = L - len(line) + (k - 1)
             space = spaces // (k - 1)
             left_words = spaces % (k - 1)
             if left_words > 0:
                 line = (" " * (space + 1)).join(words[i:i + left_words])
                 line += (" " * (space + 1))
                 line += (" " * space).join(words[i + left_words: i + k])
             else:
                 line = (" " * space).join(words[i:i + k])
         return line
        
     i = 0
     while i < N:
         word_count = get_kwords(i)
         line = insert_space(i, word_count)
         result.append(line)
         i += word_count
     return result

T: O(n) - length of words*average length of the word
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
39
Q
  1. Simplify Path
    Medium

Given an absolute path for a Unix-style file system, which begins with a slash ‘/’, transform this path into its simplified canonical path.

In Unix-style file system context, a single period ‘.’ signifies the current directory, a double period “..” denotes moving up one directory level, and multiple slashes such as “//” are interpreted as a single slash. In this problem, treat sequences of periods not covered by the previous rules (like “…”) as valid names for files or directories.

The simplified canonical path should adhere to the following rules:

It must start with a single slash ‘/’.
Directories within the path should be separated by only one slash ‘/’.
It should not end with a slash ‘/’, unless it’s the root directory.
It should exclude any single or double periods used to denote current or parent directories.
Return the new path.

A
  1. Stack
  2. Split on ‘/’ and iterate
  3. If c in [’’, ‘ ‘, ‘.’] - single space, no space or dot, then continue
  4. If c==’..’ and stack, pop()
  5. Else append to stack
  6. return ‘/’+’/’.join(stack)def simplifyPath(self, path: str) -> str:
    path=path.split(‘/’)
     stack=[]
     for p in path:
         if p in ['.', ' ', '']:
             continue
         elif p=='..':
             if stack:
                 stack.pop()
         else:
             stack.append(p)
     return '/'+'/'.join(stack)

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
40
Q
  1. Edit Distance
    Medium

Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.

You have the following three operations permitted on a word:

Insert a character
Delete a character
Replace a character

Example 1:

Input: word1 = “horse”, word2 = “ros”
Output: 3
Explanation:
horse -> rorse (replace ‘h’ with ‘r’)
rorse -> rose (remove ‘r’)
rose -> ros (remove ‘e’)

A
  1. dp = [0]* C+1*R+1
  2. dp[r][0]=r, dp[0][c]=cdef minDistance(self, word1: str, word2: str) -> int:
    R=len(word1)
    C=len(word2)
    dp=[[0] * (C+1) for _ in range(R+1)]
    for r in range(R+1):
    dp[r][0]=r
     for c in range(C+1):
         dp[0][c]=c
            
        
     for r in range(1, R+1):
         for c in range(1, C+1):
             if word1[r-1]==word2[c-1]:
                 dp[r][c]=dp[r-1][c-1]
             else:
                 dp[r][c]=1+min(dp[r-1][c-1], dp[r][c-1], dp[r-1][c])
     return dp[-1][-1]

T: O(MN)
S: O(M
N)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
41
Q
  1. Sort Colors
    Medium

Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.

We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.

You must solve this problem without using the library’s sort function.

Example 1:

Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
Example 2:

Input: nums = [2,0,1]
Output: [0,1,2]

A
  1. left, right, one_start
  2. If 1, just increment left
  3. if 2, swap with right and decrement right
  4. if 0, swap os with left and increment osdef sortColors(self, nums: List[int]) -> None:
    left=0
    right=len(nums)-1
    ostart=0
     while left<=right:
         if nums[left]==2:
             nums[left],nums[right]=nums[right],nums[left]
             right-=1
         elif nums[left]==0:
             nums[left], nums[ostart]= nums[ostart], nums[left]
             ostart+=1
             left+=1
         elif nums[left]==1:
             left+=1

T: O(n)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
42
Q
  1. Minimum Window Substring
    Hard

Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string “”.

The testcases will be generated such that the answer is unique.

Example 1:

Input: s = “ADOBECODEBANC”, t = “ABC”
Output: “BANC”
Explanation: The minimum window substring “BANC” includes ‘A’, ‘B’, and ‘C’ from string t.
Example 2:

Input: s = “a”, t = “a”
Output: “a”
Explanation: The entire string s is the minimum window.
Example 3:

Input: s = “a”, t = “aa”
Output: “”
Explanation: Both ‘a’s from t must be included in the window.
Since the largest window of s only has one ‘a’, return empty string.

A
  1. Sliding window.

class Solution:
def minWindow(self, s: str, t: str) -> str:
if len(t)>len(s):
return “”

    counter=Counter(t)
    ws=0
    
    matches=0
    min_window=float('inf')
    min_string=""
    
    for we, swe in enumerate(s):
        if swe in counter:
            counter[swe]-=1
            if counter[swe]==0:
                matches+=1
            
        while matches ==len(counter):
            sws=s[ws]
            
            if we-ws+10:
                    matches-=1

            
            ws+=1
            
    return min_string

T: O(S+T)
S: O(S+T)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
43
Q
  1. Subsets
    Medium

Given an integer array nums of unique elements, return all possible subsets (the power set).

The solution set must not contain duplicate subsets. Return the solution in any order.

Example 1:

Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

A
  1. Backtracking - Skip, Pick
  2. helper has index and current
  3. if index==len(nums), then add to result and return
  4. skip: self.bt(nums, result, index+1, curr)
  5. pick: self.bt(nums, result, index+1, curr+[nums[index]])def subsets(self, nums: List[int]) -> List[List[int]]:
    result=[]
    self.bt(nums, 0, [], result)
    return resultdef bt(self, nums, index, curr, result):
    if index==len(nums):
    result.append(curr.copy())
    return
     self.bt(nums, index+1, curr, result)
     self.bt(nums, index+1, curr+[nums[index]], result)

T: O(N* 2^n) - Copying is another N
S:O(n) - Curr space

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
44
Q
  1. Largest Rectangle in Histogram
    Hard

Given an array of integers heights representing the histogram’s bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.

Example 1:

Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.

A
  1. Monotonic increasing stack
  2. append 0 to heights so that it pops off based on the last element
  3. initialize stack to -1 because it makes it easier for calculating the width (W=i-stack[-1]-1)def largestRectangleArea(self, heights: List[int]) -> int:
    heights.append(0)
    stack = [-1]
    max_area = 0
    for i, height in enumerate(heights):
    while stack and heights[stack[-1]] > height:
    ii = stack.pop()
    H = heights[ii]
    W = i - stack[-1]-1
    max_area = max(max_area, H * W)
    stack.append(i)
    return max_area

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
45
Q
  1. Validate Binary Search Tree
    Medium

Given the root of a binary tree, determine if it is a valid binary search tree (BST).

A valid BST is defined as follows:

The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

Example 1:

Input: root = [2,1,3]
Output: true

A
  1. Helper with -sys.maxsize and sys.maxsize as mini and maxi
  2. Validate left and right

class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
return self.is_valid(root, -sys.maxsize, sys.maxsize)

def is_valid(self, node, mini, maxi):
    if not node:
        return True
    
    if not mini bool:
    stack=[]
    node=root
    
    prev=float('-inf')
    while node or stack:
        if node:
            stack.append(node)
            node=node.left
        elif stack:
            node=stack.pop()
            if prev>=node.val:
                return False
            prev=node.val
            node=node.right
    return True

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
46
Q
  1. Binary Tree Level Order Traversal
    Medium

Given the root of a binary tree, return the level order traversal of its nodes’ values. (i.e., from left to right, level by level).

Example 1:

Input: root = [3,9,20,null,null,15,7]
Output: [[3],[9,20],[15,7]]

A
  1. Generic level order traversal
  2. for _ in range(len(queue)def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
    if not root:
    return None
    node=root
     queue=deque([root])
        
     result=[]
        
     while queue:
         level=[]
         for _ in range(len(queue)):
             node=queue.popleft()
                
             level.append(node.val)
                
             if node.left:
                 queue.append(node.left)
                
             if node.right:
                 queue.append(node.right)
         result.append(level)
     return result

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
47
Q
  1. Binary Tree Zigzag Level Order Traversal
    Medium

Given the root of a binary tree, return the zigzag level order traversal of its nodes’ values. (i.e., from left to right, then right to left for the next level and alternate between).

Example 1:

Input: root = [3,9,20,null,null,15,7]
Output: [[3],[20,9],[15,7]]

A
  1. Level order traversal. But for level use deque (append and appendleft)def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
    if not root:
    return []
     node=root
     queue=deque([root])
        
     left_to_right=True
     result=[]
        
     while queue:
         level=deque([])
         for _ in range(len(queue)):
             node=queue.popleft()
                
             if left_to_right:
                 level.append(node.val)
             else:
                 level.appendleft(node.val)
                    
             if node.left:
                 queue.append(node.left)
                
             if node.right:
                 queue.append(node.right)
         left_to_right=not left_to_right
         result.append(level)
     return result

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
48
Q
  1. Path Sum II
    Medium

Given the root of a binary tree and an integer targetSum, return all root-to-leaf paths where the sum of the node values in the path equals targetSum. Each path should be returned as a list of the node values, not node references.

A root-to-leaf path is a path starting from the root and ending at any leaf node. A leaf is a node with no children.

Example 1:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: [[5,4,11,2],[5,8,4,5]]
Explanation: There are two paths whose sum equals targetSum:
5 + 4 + 11 + 2 = 22
5 + 8 + 4 + 5 = 22

A
  1. Root to leaf with a target_sum - DFS (track target_sum, curr)
  2. In the helper, if node.val==target_sum and not node.left and not node.right: result.add(curr.copy())
  3. if not node: return
  4. if node.left:
    self.dfs(node.left, target_sum-node.val, curr+[node.val], result)
  5. same with node.right

class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root:
return None
result=[]
self.path_sum(root, targetSum, [], result)
return result

def path_sum(self, node, target, curr, result):
    if not node.left and not node.right and target==node.val:
        curr+=[node.val]
        result.append(curr.copy())
        return
    
    if node.left:
        self.path_sum(node.left, target-node.val, curr+[node.val], result)
    if node.right:
        self.path_sum(node.right, target-node.val, curr+[node.val], result)

BFS has a lot of space overhead, since we need to maintain all the paths in the queue

T: O(n^2) - Worst case, if it is a complete binary tree, we need to traverse through N/2 leaves.
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
49
Q
  1. Populating Next Right Pointers in Each Node
    Medium

You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition:

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Example 1:

Input: root = [1,2,3,4,5,6,7]
Output: [1,#,2,3,#,4,5,6,7,#]
Explanation: Given the above perfect binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with ‘#’ signifying the end of each level.

A
  1. Level order traversal
  2. prev = None
  3. If prev, prev.next=node
  4. prev=nodedef connect(self, root: ‘Optional[Node]’) -> ‘Optional[Node]’:
    if not root:
    return root
    queue = deque([root])
    while queue:
    prev = None
    for _ in range(len(queue)):
    node = queue.popleft()
    if not prev:
    prev = node
    else:
    prev.next = node
    prev = node
    if node.left:
    queue.append(node.left)
    if node.right:
    queue.append(node.right)
    return root

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
50
Q
  1. Best Time to Buy and Sell Stock II
    Medium

You are given an integer array prices where prices[i] is the price of a given stock on the ith day.

On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. However, you can buy it then immediately sell it on the same day.

Find and return the maximum profit you can achieve.

Example 1:

Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Total profit is 4 + 3 = 7.
Example 2:

Input: prices = [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Total profit is 4.

A
  1. Just keep comparing current price to previous price and accumulate them into profitdef maxProfit(self, prices: List[int]) -> int:
    profit=0
    for i in range(1, len(prices)):
    if prices[i-1]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

COVERED

A

COVERED

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
52
Q
  1. Longest Consecutive Sequence
    Medium

Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.

You must write an algorithm that runs in O(n) time.

Example 1:

Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
Example 2:

Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9

A
  1. Hold all the nums in a set
  2. Entry when num-1 is not in set (least number)
  3. count=1, while count+num is not in set: count+=1
  4. set max_countdef longestConsecutive(self, nums: List[int]) -> int:
    hset=set(nums)
     max_count=0
     for num in nums:
         if num-1 not in hset:
             count=1
             while num+count in hset:
                 count+=1
             max_count=max(count, max_count)
     return max_count

T:O(n)
S:O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q
  1. Sum Root to Leaf Numbers
    Medium

You are given the root of a binary tree containing digits from 0 to 9 only.

Each root-to-leaf path in the tree represents a number.

For example, the root-to-leaf path 1 -> 2 -> 3 represents the number 123.
Return the total sum of all root-to-leaf numbers. Test cases are generated so that the answer will fit in a 32-bit integer.

A leaf node is a node with no children.

A
  1. BFS - queue.append((root, str(root.val))
  2. Keep adding to the str. If not node.left and not node.right, total+=int(str_val)def sumNumbers(self, root: Optional[TreeNode]) -> int:
    if not root:
    return 0
     queue=deque([(root, str(root.val))])
        
     result=0
        
     while queue:
         node, sval=queue.popleft()
            
         if not node.left and not node.right:
             result+=int(sval)
             continue
         if node.left:
             queue.append((node.left, sval+str(node.left.val)))
         if node.right:
             queue.append((node.right, sval+str(node.right.val)))
     return result

T:O(n)
S:O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q
  1. Palindrome Partitioning
    Medium

Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s.

Example 1:

Input: s = “aab”
Output: [[“a”,”a”,”b”],[“aa”,”b”]]
Example 2:

Input: s = “a”
Output: [[“a”]]

A
  1. Simple BT recursion (helper has curr and result)
  2. At each level iterate from 1, len(s)+1 and check if s[:i] is palindrome.
  3. If yes, then call the helper recursively with s[i:], curr=[s[:i]]

S: O(N2^N) - 2N - there could be 2N possible substrings in the worst case
T: N
2^N

N=3, aaa, the first level of the tree is [a]aa, [aa][a], [aaa]

Essentially, there are 8 nodes in the tree, which is 2^3

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q
  1. Clone Graph
    Medium

Given a reference of a node in a connected undirected graph.

Return a deep copy (clone) of the graph.

Each node in the graph contains a value (int) and a list (List[Node]) of its neighbors.

class Node {
public int val;
public List neighbors;
}

Test case format:

For simplicity, each node’s value is the same as the node’s index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is represented in the test case using an adjacency list.

An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.

The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.

A
  1. BFS
  2. Keep a copy dictionary, copy={root:Node(root.val)}
  3. Upon popping, iterate through neis,
    if nei not in copy:
    copy[nei]=Node(nei.val)
    queue.append(nei)
    copy[node].neighbours.append(copy[nei])
  4. return copy[root]

from typing import Optional
class Solution:
def cloneGraph(self, root: Optional[‘Node’]) -> Optional[‘Node’]:
if not root:
return root

    queue=deque([root])
    copy={root: Node(root.val)}
    
    while queue:
        node=queue.popleft()
        
        for nei in node.neighbors:
            if nei not in copy:
                copy[nei]=Node(nei.val)
                queue.append(nei)
            copy[node].neighbors.append(copy[nei])
    return copy[root]

T: O(V+E)
S: O(V)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
56
Q
  1. Copy List with Random Pointer
    Medium

A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.

Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list.

For example, if there are two nodes X and Y in the original list, where X.random –> Y, then for the corresponding two nodes x and y in the copied list, x.random –> y.

Return the head of the copied linked list.

The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:

val: an integer representing Node.val
random_index: the index of the node (range from 0 to n-1) that the random pointer points to, or null if it does not point to any node.
Your code will only be given the head of the original linked list.

A
  1. Have a copy map and do two traversals.
  2. First time copy[node]=Node(node.val)
  3. Next time, copy[node].next=copy.get(node.next) & copy[node].random=copy.get(node.random)
  4. return copy[head]def copyRandomList(self, head: ‘Optional[Node]’) -> ‘Optional[Node]’:
    if not head:
    return None
    copy={head:Node(head.val)}
     node=head
    
     while node:
         if node not in copy:
             copy[node]=Node(node.val)
         node=node.next
        
        
     node=head
        
     while node:
         copy[node].next=copy.get(node.next)
         copy[node].random=copy.get(node.random)
         node=node.next
            
     return copy[head]

T: O(N)
S: O(N)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
57
Q
  1. Word Break II
    Hard

Share
Given a string s and a dictionary of strings wordDict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences in any order.

Note that the same word in the dictionary may be reused multiple times in the segmentation.

Example 1:

Input: s = “catsanddog”, wordDict = [“cat”,”cats”,”and”,”sand”,”dog”]
Output: [“cats and dog”,”cat sand dog”]

A
  1. DP. Recursion
  2. Helper has curr and result
  3. if not s: result.append(curr.copy())
  4. for i in range(len(s)), call helper by skipping i (s[:i]+s[i+1:])def wordBreak(self, s: str, wordDict: List[str]) -> bool:
    words=set(wordDict)
    N=len(s)
    dp=[False]*(N+1)
    dp[0]=True
     for i in range(N+1):
         for j in range(i):
             word=s[j:i]
             if word in words and dp[j]==True:
                 dp[i]=True
     return dp[-1]

T: O(nmk), n being the size of the string, m is the length of the worddict and k is the average length of the word in the worddict
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
58
Q
  1. Word Break II
    Hard

Share
Given a string s and a dictionary of strings wordDict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences in any order.

Note that the same word in the dictionary may be reused multiple times in the segmentation.

Example 1:

Input: s = “catsanddog”, wordDict = [“cat”,”cats”,”and”,”sand”,”dog”]
Output: [“cats and dog”,”cat sand dog”]

A
  1. DP. Recursion
  2. Helper has curr and result
  3. if not s: result.append(curr.copy())
  4. for i in range(len(s)+1). Remember to loop until len(s)+1def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
    result=[]
    self.helper(s, 0, set(wordDict), [], result)
    return resultdef helper(self, s, index, words, curr, result):
    if not s:
    result.append(‘ ‘.join(curr))
    return
     for i in range(len(s)+1):
         if s[:i] in words:
             self.helper(s[i:], i, words, curr+[s[:i]], result)

T: O(2^n) - Worst case, every letter is a word. String concat O(n), since for each recursive call n/k (k=average length of a valid word) = O(2^n*n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
59
Q
  1. Reorder List
    Medium

You are given the head of a singly linked-list. The list can be represented as:

L0 → L1 → … → Ln - 1 → Ln
Reorder the list to be on the following form:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
You may not modify the values in the list’s nodes. Only nodes themselves may be changed.

Example 1:

Input: head = [1,2,3,4]
Output: [1,4,2,3]
Example 2:

Input: head = [1,2,3,4,5]
Output: [1,5,2,4,3]

A
  1. Find mid
  2. Reverse the second half
  3. Merge both lists.def reorderList(self, head: Optional[ListNode]) -> None:
    fast=head
    slow=head
     while fast.next and fast.next.next:
         slow=slow.next
         fast=fast.next.next
            
     second=slow.next
     slow.next=None
        
     #reverse mid
     prev=None
     while second:
         nxt=second.next
         second.next=prev
         prev=second
         second=nxt
            
     #merge
     head1=head
     head2=prev
                
     while head2:
         nxt=head1.next
         head1.next=head2
         head1=head2
         head2=nxt

T: O(n)
S: (1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
60
Q
  1. LRU Cache
    Medium

Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.

Implement the LRUCache class:

LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
int get(int key) Return the value of the key if the key exists, otherwise return -1.
void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.
The functions get and put must each run in O(1) average time complexity.

Example 1:

Input
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]

A
  1. init - head.next=tail, tail.prev=head, self.mapp={}
  2. get - if not key in self.mapp, return -1
    else:
    ret_node=self.mapp[key],
    self.remove_node(ret_node)
    del self.mapp[key]
    self.move_to_first(ret_node)
    self.mapp[key]=ret_node
  3. put - nnode=Node(key,val)
    if key in self.mapp:
    per_node=self.mapp[key]
    self.remove_node(per_node)
    del self.mapp[key]
    self.move_to_first(nnode)
    self.mapp[key]=nnode
          if len(self.mapp)>self.capacity:
               last_node=self.tail.prev
               self.remove_node(last_node)
                del self.mapp[last_node.key]
  4. move_to_first
    nxt=self.head.next
    self.head.next=node
    node.prev=self.head
    node.next=nxt
    next.prev=node
  5. remove_node
    prev=node.prev
    node.prev.next=node.next
    node.next.prev=prev

class Node:
def __init__(self, key, val, prev=None, next=None):
self.key=key
self.val=val
self.prev=prev
self.next=next

class LRUCache:

def \_\_init\_\_(self, capacity: int):
    self.capacity=capacity
    self.head=Node(0,0)
    self.tail=Node(0,0)
    self.head.next=self.tail
    self.tail.prev=self.head
    self.mapp={}
    

def get(self, key: int) -> int:
    if key not in self.mapp:
        return -1
    node=self.mapp[key]
    self.remove_node(node)
    self.add_to_front(node)
    return node.val

def put(self, key: int, value: int) -> None:
    if key in self.mapp:
        node=self.mapp[key]
        node.val=value
        self.remove_node(node)
        self.add_to_front(node)
    else:
        node=Node(key, value)
        self.add_to_front(node)
        self.mapp[key]=node
        
        if len(self.mapp)>self.capacity:
            last_node=self.tail.prev
            self.remove_node(last_node)
            del self.mapp[last_node.key]
    
def remove_node(self, node):
    prev=node.prev
    node.prev.next=node.next
    node.next.prev=prev
    
def add_to_front(self, node):
    pnext= self.head.next
    self.head.next=node
    node.prev=self.head
    
    pnext.prev=node
    node.next=pnext

T: O(1)
S: O(capacity)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
61
Q
  1. Min Stack
    Medium

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

Implement the MinStack class:

MinStack() initializes the stack object.
void push(int val) pushes the element val onto the stack.
void pop() removes the element on the top of the stack.
int top() gets the top element of the stack.
int getMin() retrieves the minimum element in the stack.
You must implement a solution with O(1) time complexity for each function.

Example 1:

Input
[“MinStack”,”push”,”push”,”push”,”getMin”,”pop”,”top”,”getMin”]
[[],[-2],[0],[-3],[],[],[],[]]

Output
[null,null,null,null,-3,null,0,-2]

Explanation
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top(); // return 0
minStack.getMin(); // return -2

A
  1. Unlike assumption, we have to maintain two stacks - one for values and the other one for min so far.
  2. While adding a value, check if the current value is lesser than the top most value on the min_stack
  3. Add the minimum of the top value, incoming value to the top of the min_stack.

class MinStack:

def \_\_init\_\_(self):
    self.stack=[]
    self.min_stack=[]
    

def push(self, val: int) -> None:
    self.stack.append(val)
    if not self.min_stack:
        self.min_stack.append(val)
    else:
        mini=min(val, self.min_stack[-1])
        self.min_stack.append(mini)
    

def pop(self) -> None:
    self.stack.pop()
    self.min_stack.pop()
    

def top(self) -> int:
    return self.stack[-1]
    

def getMin(self) -> int:
    return self.min_stack[-1]

T: O(1)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
62
Q
  1. Find Peak Element
    Medium

A peak element is an element that is strictly greater than its neighbors.

Given a 0-indexed integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.

You may imagine that nums[-1] = nums[n] = -∞. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.

You must write an algorithm that runs in O(log n) time.

Example 1:

Input: nums = [1,2,3,1]
Output: 2
Explanation: 3 is a peak element and your function should return the index number 2.

A
  1. Binary search.
  2. if (mid==0 or nums[mid]>nums[mid-1]) and (mid==N-1 or nums[mid]>nums[mid+1], return mid
  3. elif nums[low]<=nums[mid]: low+=1 (too far - we need mid-1, so moving left ahead)
  4. else, high-=1

Remember that unlike binary search, we aren’t doing low=mid+1, It’s just low+=1

def findPeakElement(self, nums: List[int]) -> int:
    N=len(nums)
    left=0
    right=N-1
    
    while left<=right:
        mid=(left+right)//2
        if (mid==0 or nums[mid]>nums[mid-1]) and (mid==N-1 or nums[mid]>nums[mid+1]):
            return mid
        elif nums[left]<=nums[mid]:
            left+=1
        else:
            right-=1

Alternative:

def findPeakElement(self, nums: List[int]) -> int:
    N=len(nums)
    left=0
    right=N-1
    
    if left==right:
        return left
    
    while left
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
63
Q
  1. Binary Search Tree Iterator
    Medium

Implement the BSTIterator class that represents an iterator over the in-order traversal of a binary search tree (BST):

BSTIterator(TreeNode root) Initializes an object of the BSTIterator class. The root of the BST is given as part of the constructor. The pointer should be initialized to a non-existent number smaller than any element in the BST.
boolean hasNext() Returns true if there exists a number in the traversal to the right of the pointer, otherwise returns false.
int next() Moves the pointer to the right, then returns the number at the pointer.
Notice that by initializing the pointer to a non-existent smallest number, the first call to next() will return the smallest element in the BST.

You may assume that next() calls will always be valid. That is, there will be at least a next number in the in-order traversal when next() is called.

A

Do an inorder traversal

  1. init - set node=root and stack=[]
  2. next - modified inorder.(ensure that stack is always populated)
    while node:
    stack.append(node)
    node=node.left
    nxt=stack.pop()
    return_val=nxt.val
    node=node.right
    return return_val
  3. has_next:
    return stack or node

class BSTIterator:

def \_\_init\_\_(self, root: Optional[TreeNode]):
    self.stack=[]
    self.node=root
    

def next(self) -> int:
    while self.node:
        self.stack.append(self.node)
        self.node=self.node.left
    
    nxt=self.stack.pop()
    ret_val=nxt.val
    self.node=nxt.right
    return ret_val
        
def hasNext(self) -> bool:
    return self.stack or self.node

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
64
Q
  1. Consecutive Numbers
    Medium

SQL Schema
Table: Logs

+————-+———+
| Column Name | Type |
+————-+———+
| id | int |
| num | varchar |
+————-+———+
In SQL, id is the primary key for this table.
id is an autoincrement column.

Find all numbers that appear at least three times consecutively.

Return the result table in any order.

The result format is in the following example.

Example 1:

Input:
Logs table:
+—-+—–+
| id | num |
+—-+—–+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+—-+—–+
Output:
+—————–+
| ConsecutiveNums |
+—————–+
| 1 |
+—————–+
Explanation: 1 is the only number that appears consecutively for at least three times.

A

select
distinct l1.num as ConsecutiveNums
from
Logs l1
join
Logs l2
on
l2.id=l1.id+1
join
Logs l3
on
l3.id=l2.id+1
where
l1.num=l2.num and l2.num=l3.num

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
65
Q
  1. House Robber
    Medium

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.

A
  1. DP - initialize to N+1
  2. dp[1]=nums[0
  3. Iterate from 1 to N and
    dp[i+1]=max(dp[i-1]+nums[i], dp[i])def rob(self, nums: List[int]) -> int:
    dp=[0]*(len(nums)+1)
    dp[1]=nums[0]
     for i in range(1, len(nums)):
         dp[i+1]=max(dp[i-1]+nums[i], dp[i])
        
     return dp[-1]

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
66
Q
  1. Binary Tree Right Side View
    Medium

Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

A
  1. Level order traversal
  2. if i==level-1 (N-1), add to resultdef rightSideView(self, root: Optional[TreeNode]) -> List[int]:
     if not root:
         return None
     queue=deque([root])
        
     result=[]
        
     while queue:
         level=len(queue)
         for i in range(level):
             node=queue.popleft()
             if i==level-1:
                 result.append(node.val)
                
             if node.left:
                 queue.append(node.left)
                
             if node.right:
                 queue.append(node.right)
     return result

T: O(n)
S: O(d) - tree diameter

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
67
Q
  1. Number of Islands
    Medium

Given an m x n 2D binary grid grid which represents a map of ‘1’s (land) and ‘0’s (water), return the number of islands.

An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input: grid = [
[“1”,”1”,”1”,”1”,”0”],
[“1”,”1”,”0”,”1”,”0”],
[“1”,”1”,”0”,”0”,”0”],
[“0”,”0”,”0”,”0”,”0”]
]
Output: 1

A

DFS

class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
R=len(grid)
C=len(grid[0])

    count=0
    for r in range(R):
        for c in range(C):
            if grid[r][c]=='1':
                self.dfs(grid, r, c, R, C)
                count+=1
    return count


def dfs(self, grid, r, c, R, C):
    grid[r][c]='0'
    
    neis = [(r+1, c), (r-1, c), (r, c+1), (r, c-1)]
    
    for nr, nc in neis:
        if -1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
68
Q
  1. Course Schedule
    Medium

There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course bi first if you want to take course ai.

For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1.
Return true if you can finish all courses. Otherwise, return false.

Example 1:

Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.

A
  1. BFS and check if cycle exists

WHITE, GRAY, BLACK = 0,1,2
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
graph=defaultdict(list)

    for u,v in prerequisites:
        graph[u].append(v)

    
    colors=defaultdict(int)
    
    for u in range(numCourses):
        if colors[u]==WHITE and self.has_cycle(u, graph, colors):
            return False
        
    return True


def has_cycle(self, node, graph, colors):
    colors[node] = GRAY
    
    for nei in graph[node]:
        if colors[nei]==GRAY:
            return True
        elif colors[nei]==WHITE:
            if self.has_cycle(nei, graph, colors):
                return True
        else:
            continue
    colors[node]=BLACK
    return False

T: O(V+E)
S: O(V+E)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
69
Q
  1. Course Schedule II
    Medium

There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course bi first if you want to take course ai.

For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1.
Return the ordering of courses you should take to finish all courses. If there are many valid answers, return any of them. If it is impossible to finish all courses, return an empty array.

Example 1:

Input: numCourses = 2, prerequisites = [[1,0]]
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1].

A
  1. Topsort while checking is there’s no cycle

WHITE,GRAY,BLACK=0,1,2
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
graph=defaultdict(list)

    for u,v in prerequisites:
        graph[u].append(v)
    
    
    colors=defaultdict(int)
    
    tops=[]
    
    for node in range(numCourses):
        if colors[node]==WHITE:
            if self.has_cycle(node, colors, graph, tops):
                return []
            
    return tops if len(tops)==numCourses else []


def has_cycle(self, node, colors, graph, tops):
    colors[node]=GRAY
    for nei in graph[node]:
        if colors[nei]==GRAY:
            return True
        elif colors[nei]==WHITE:
            if self.has_cycle(nei, colors, graph, tops):
                return True
        else:
            continue
    tops.append(node)
    colors[node]=BLACK
    return False

T: O(V+E)
S: O(V+E)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
70
Q

N/A

A
  1. Construct a Trie and add all words
  2. Do a dfs on Trie.

class TrieNode:
def __init__(self, val=None):
self.val = val
self.children = {}
self.end_node = False

class Trie:
def __init__(self):
self.root = TrieNode()

def add_word(self, word):
    node = self.root
    for c in word:
        if c not in node.children:
            nnode = TrieNode(c)
            node.children[c] = nnode
        node = node.children[c]
    node.end_node = True
#
# def search(self, word):
#     node = self.root
#     for c in word:
#         if c not in node.children:
#             return False
#         node = node.children[c]
#     return node.end_node

class WordSearch:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
R = len(board)
C = len(board[0])

    trie = Trie()
    for word in words:
        trie.add_word(word)
    # print(trie)

    result = []
    self.num_words = len(words)
    for r in range(R):
        for c in range(C):
            if board[r][c] in trie.root.children:
                self.dfs(board, r, c, R, C, trie.root, result, "")

    return result

def dfs(self, board, r, c, R, C, troot, result, curr):
    if self.num_words == 0:
        return

    if troot.end_node:
        result.append(curr)
        troot.end_node = False
        self.num_words -= 1

    neis = [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]
    for nr, nc in neis:
        if -1 < nr < R and -1 < nc < C and board[nr][nc] in troot.children:
            self.dfs(board, nr, nc, R, C, troot.children[board[nr][nc]], result, curr + board[nr][nc])

T: O(n4^L) - L is the length of the word in the dictionary
S: O(k
L) - k number of words in the dictionary and L average length of the words

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
71
Q
  1. House Robber II
    Medium

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: nums = [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses.
Example 2:

Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.

A
  1. Do houserobber twice (once with nums[1:] and second with nums[:-1]def rob(self, nums: List[int]) -> int:
    if not nums: return 0
    if len(nums)==1: return nums[0]
     skip_first=self.helper(nums[1:])
     skip_last=self.helper(nums[:-1])
     return max(skip_first, skip_last)
    def helper(self, nums):
    N=len(nums)
    dp=[0]*(N+1)
    dp[1]=nums[0]
     for i in range(1, N):
         dp[i+1]=max(dp[i-1]+nums[i], dp[i])
     return dp[-1]

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
72
Q
  1. Kth Largest Element in an Array
    Medium

Given an integer array nums and an integer k, return the kth largest element in the array.

Note that it is the kth largest element in the sorted order, not the kth distinct element.

Can you solve it without sorting?

Example 1:

Input: nums = [3,2,1,5,6,4], k = 2
Output: 5

A
  1. For finding largest, create min_heap
  2. Keep pushing to heap. If len(heap)>k, pop
  3. return pq[0]

T: O(NlogK)
S: O(k)

(Also consider quickselect)

def findKthLargest(self, nums: List[int], k: int) -> int:
    if not nums:
        return -1
    pivot=random.choice(nums)
    left=[num for num in nums if num>pivot]
    mid=[num for num in nums if num==pivot]
    right=[num for num in nums if numL+M:
        return self.findKthLargest(right, k-L-M)

    return mid[0]

T: O(n) - average case - balanced partitioning. O(n^2) worst case - when the pivot is always chosen to be the smallest or largest in the array.
S: O(n) - storage of partitioned lists

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
73
Q
  1. Basic Calculator II
    Medium

Given a string s which represents an expression, evaluate this expression and return its value.

The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-231, 231 - 1].

Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().

Example 1:

Input: s = “3+2*2”
Output: 7
Example 2:

Input: s = “ 3/2 “
Output: 1
Example 3:

Input: s = “ 3+5 / 2 “
Output: 5

A
  1. Regular basic calculator
  2. Create an opset
  3. For digit. num*10+int(c)
  4. For open parens, just append op to stack and reset op and num (this is for starting a new context)
  5. For close parens or c in opset:
    self.update()
    set op=c
    num=0
    if c==’)’:
    temp_num and while loop until stack[-1] is in opset
    self.update(temp_num, stack.pop()) - the previous op
  6. for c in s+’+’def calculate(self, s: str) -> int:
    op=’+’
    num=0
    opset={‘+’,’-‘,’*’,’/’}
     stack=[]
        
     for c in s+'+':
         if c.isdigit():
             num=num*10 + int(c)
         elif c==')' or c in opset:
             self.update(num, op, stack)
             op=c
             num=0
                
             if c==')':
                 tmp_num=0
                 while stack[-1] not in opset:
                     tmp_num+=stack.pop()
                 self.update(tmp_num, stack.pop(), stack)
         elif c=='(':
             stack.append(op)
             op='+'
             num=0
     return sum(stack)
    def update(self, num, op, stack):
    if op==’+’:
    stack.append(num)
    elif op==’-‘:
    stack.append(-num)
    elif op==’’:
    prev=stack.pop()
    stack.append(num
    prev)
    elif op==’/’:
    prev=stack.pop()
    stack.append(int(prev/num))

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
74
Q
  1. Basic Calculator II
    Medium

Given a string s which represents an expression, evaluate this expression and return its value.

The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-231, 231 - 1].

Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().

Example 1:

Input: s = “3+2*2”
Output: 7
Example 2:

Input: s = “ 3/2 “
Output: 1
Example 3:

Input: s = “ 3+5 / 2 “
Output: 5

A
  1. op=”+’, num=’0’, stack=[]
  2. Iterate through s and keep accumulating num if digit.
  3. If an operator is faced, call self.update(num, op, stack). Reset num and op to defaults
  4. return sum(stack)def calculate(self, s: str) -> int:
    op=’+’
    num=0
     stack=[]
        
     for c in s+'+':
         if c.isdigit():
             num=num*10 +int(c)
         elif c in '+-/*':
             self.update(num, op, stack)
             op=c
             num=0
     return sum(stack)
    def update(self, num, op, stack):
    if op==’+’:
    stack.append(num)
    elif op==’-‘:
    stack.append(-num)
    elif op==’’:
    prev=stack.pop()
    stack.append(prev
    num)
    elif op==’/’:
    prev=stack.pop()
    stack.append(int(prev/num))

T: O(n)
S:O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
75
Q
  1. Lowest Common Ancestor of a Binary Search Tree
    Medium

Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Example 1:

Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.

A
  1. If p_valnode_val and q_val>node_val: node=node.right
  2. Else, we’ve found the split point, return node

T: O(N)
S: O(N)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
76
Q
  1. Lowest Common Ancestor of a Binary Tree III
    Medium

Given two nodes of a binary tree p and q, return their lowest common ancestor (LCA).

Each node will have a reference to its parent node. The definition for Node is below:

class Node {
public int val;
public Node left;
public Node right;
public Node parent;
}
According to the definition of LCA on Wikipedia: “The lowest common ancestor of two nodes p and q in a tree T is the lowest node that has both p and q as descendants (where we allow a node to be a descendant of itself).”

A
  1. Similar to meeting point of LinkedList
  2. Find depth of both nodes using simple iteration (while node, node=node.parent)
  3. Compare the longest and shortest. Move longest to the level of shortest (for _ in range(ldepth-sdepth), lnode=lnode.parent)
  4. Move both lnode and snode up, lnode=lnode.parent, snode=snode.parent
  5. If they are equal return

T: O(N)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
77
Q
  1. Delete Node in a Linked List
    Medium

There is a singly-linked list head and we want to delete a node node in it.

You are given the node to be deleted node. You will not be given access to the first node of head.

All the values of the linked list are unique, and it is guaranteed that the given node node is not the last node in the linked list.

Delete the given node. Note that by deleting the node, we do not mean removing it from memory. We mean:

The value of the given node should not exist in the linked list.
The number of nodes in the linked list should decrease by one.
All the values before node should be in the same order.
All the values after node should be in the same order.
Custom testing:

For the input, you should provide the entire linked list head and the node to be given node. node should not be the last node of the list and should be an actual node in the list.
We will build the linked list and pass the node to your function.
The output will be the entire list after calling your function.

A

def deleteNode(self, node):
node.val=node.next.val
node.next=node.next.next

T: O(1)
S: O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
78
Q
  1. Product of Array Except Self
    Medium

Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].

The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.

You must write an algorithm that runs in O(n) time and without using the division operation.

Example 1:

Input: nums = [1,2,3,4]
Output: [24,12,8,6]
Example 2:

Input: nums = [-1,1,0,-3,3]
Output: [0,0,9,0,0]

A
  1. left and right =[1]*N
  2. left =(1,N) , right = reversed (range(N-1)
  3. left[i]=left[i-1]*nums[i-1]
  4. right[i]=right[i+1]*nums[i+1]def productExceptSelf(self, nums: List[int]) -> List[int]:
    result = []
    N = len(nums)
     left = [1] * (N)
     right = [1] * (N)
    
     for i in range(1, N):
         left[i] = left[i - 1] * nums[i - 1]
    
     for i in reversed(range(N - 1)):
         right[i] = right[i + 1] * nums[i + 1]
    
     for l, r in zip(left, right):
         result.append(l * r)
    
     return result

T: O(n)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
79
Q
  1. Strobogrammatic Number II
    Medium

Given an integer n, return all the strobogrammatic numbers that are of length n. You may return the answer in any order.

A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).

Example 1:

Input: n = 2
Output: [“11”,”69”,”88”,”96”]
Example 2:

Input: n = 1
Output: [“0”,”1”,”8”]

A
  1. Recursion and build from inside.
  2. if num==0: return [’’]
  3. If num==1: return [‘0’,’1’,’8’]
  4. temp=build_strobogrammatic(num-2)
  5. for l in temp:
    result.append(‘1’+l+’1’) (do for 69, 88, and 96)
  6. if n!=num, result prefix and suffix 0def findStrobogrammatic(self, n: int) -> List[str]:
    if not n:
    return []
    return self.find_stobogrammatic(n, n)def find_stobogrammatic(self, n, num):
    if num == 0:
    return [’’]
    elif num == 1:
    return [‘0’, ‘1’, ‘8’]
    result = []
    temp = self.find_stobogrammatic(n, num - 2)
    for l in temp:
    if num != n:
    result.append(‘0’ + l + ‘0’)
    result.append(‘1’ + l + ‘1’)
    result.append(‘6’ + l + ‘9’)
    result.append(‘8’ + l + ‘8’)
    result.append(‘9’ + l + ‘6’)
    return result

T: O(5^n)
S: O(5^n) - O(n/2) for call stack

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
80
Q
  1. Group Shifted Strings
    Medium

We can shift a string by shifting each of its letters to its successive letter.

For example, “abc” can be shifted to be “bcd”.
We can keep shifting the string to form a sequence.

For example, we can keep shifting “abc” to form the sequence: “abc” -> “bcd” -> … -> “xyz”.
Given an array of strings strings, group all strings[i] that belong to the same shifting sequence. You may return the answer in any order.

Example 1:

Input: strings = [“abc”,”bcd”,”acef”,”xyz”,”az”,”ba”,”a”,”z”]
Output: [[“acef”],[“a”,”z”],[“abc”,”bcd”,”xyz”],[“az”,”ba”]]

A
  1. Maintain result=defaultdict(list)
  2. Iterate through each string. Calculate key for each string and push it to map
  3. Key calculation: Iterate through each s and compare against it’s first character (ord(c)-ord(s[0])) %26. Return a tuple of the ords as key. Note the s[0] instead of the usual ord(‘a’)

If it is not tuple and keep it as just a num string, then there’s no difference between 112 - 11,2 and 1,12

def groupStrings(self, strings: List[str]) -> List[List[str]]:
    mapp=defaultdict(list)
    for s in strings:
        key=self.get_key(s)
        mapp[key].append(s)
    return [v for k,v in mapp.items()]


def get_key(self, s):
    key=[]
    for c in s:
        k=(ord(c)-ord(s[0]))%26
        key.append(k)
    return tuple(key)

T: O(nk) - we iterate over all the characters of all the strings.
S: O(n
k) - we store the string and their hashvalue in the map

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
81
Q
  1. Meeting Rooms II
    Medium

Given an array of meeting time intervals intervals where intervals[i] = [starti, endi], return the minimum number of conference rooms required.

Example 1:

Input: intervals = [[0,30],[5,10],[15,20]]
Output: 2
Example 2:

Input: intervals = [[7,10],[2,4]]
Output: 1

A
  1. Sort the meeting rooms by start time
  2. Add only the end to the pq
  3. if the next meeting has start time which is >= than the end time of the top of the pq, then pop from pq
    4 return size of pqdef minMeetingRooms(self, intervals: List[List[int]]) -> int:
    min_conf=-sys.maxsize
    intervals.sort(key=lambda i: i[0])
     pq=[]
        
     for ms, me in intervals:
         if pq and ms>=pq[0]:
             heapq.heappop(pq)
         heapq.heappush(pq, me)
     return len(pq)

T: O(nlogn)
S: O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
82
Q
  1. Graph Valid Tree
    Medium

You have a graph of n nodes labeled from 0 to n - 1. You are given an integer n and a list of edges where edges[i] = [ai, bi] indicates that there is an undirected edge between nodes ai and bi in the graph.

Return true if the edges of the given graph make up a valid tree, and false otherwise.

Example 1:

Input: n = 5, edges = [[0,1],[0,2],[0,3],[1,4]]
Output: true

A
  1. Undirected graph. Check if there are cycles in the loop.
  2. Also check if len(colors)==len(graph) - disconnected graph. Do DFS only from 0.
  3. Check if gray and nei!=parent: then return False. Else, gray is fine because this is an undirected graph

WHITE,GRAY,BLACK=0,1,2
class Solution:
def validTree(self, n: int, edges: List[List[int]]) -> bool:
if not edges and n == 1:
return True
if not edges and n > 1:
return False

    graph = defaultdict(list)

    for u, v in edges:
        graph[u].append(v)
        graph[v].append(u)

    if len(graph) != n:
        return False

    colors = defaultdict(int)

    if self.has_cycle(0, graph, colors, -1):
        return False

    if len(colors) != len(graph):
        return False

    return True

def has_cycle(self, node, graph, colors, parent):
    colors[node] = GRAY
    for nei in graph[node]:
        if colors[nei] == GRAY and nei != parent:
            return True
        elif colors[nei] == WHITE:
            if self.has_cycle(nei, graph, colors, node):
                return True
    colors[node] = BLACK
    return False

T: O(V+E)
S: O(V+E)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
83
Q
  1. Palindrome Permutation II
    Medium

Given a string s, return all the palindromic permutations (without duplicates) of it.

You may return the answer in any order. If s has no palindromic permutation, return an empty list.

Example 1:

Input: s = “aabb”
Output: [“abba”,”baab”]
Example 2:

Input: s = “abc”
Output: []

A
  1. Calculate mid and more than one mid, return []
  2. Divide into half and ‘join’ them to avoid empty strings
  3. call helper - with half, curr, N, mid, result (N=len(half))
  4. if len(curr)=N, then append to result
  5. for i in range(len(half)), skip for duplicates and call self.def generatePalindromes(self, s: str) -> List[str]:
    counter=Counter(s)
     mid=[k for k,v in counter.items() if v%2==1]
     if len(mid)>1:
         return []
     mid=mid[0] if mid else ''
        
     half = ''.join([k*(v//2) for k,v in counter.items()])
        
        
     result=[]
     self.generate_palins(half, '', mid, len(half), result)
     return result
    def generate_palins(self, half, curr, mid, N, result):
    if len(curr)==N:
    result.append(curr+mid+curr[::-1])
    return
     for i in range(len(half)):
         if i>0 and half[i]==half[i-1]:
             continue
         self.generate_palins(half[:i]+half[i+1:], curr+half[i], mid, N, result)

T: O(N/2!)
S: O(N) - depth of the recursion tree can go upto n/2 in the worst case

84
Q
  1. Verifying an Alien Dictionary
    Easy

In an alien language, surprisingly, they also use English lowercase letters, but possibly in a different order. 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 language.

Example 1:

Input: words = [“hello”,”leetcode”], order = “hlabcdefgijkmnopqrstuvwxyz”
Output: true
Explanation: As ‘h’ comes before ‘l’ in this language, then the sequence is sorted.

A
  1. Graph cycle finding
  2. Iterate through zip(words, words[1:]) and then zip(word1, word2)
  3. short circuit - if len(word1)>len(word2) and word1[:len(word2)]==word2: return False
  4. if c1!=c2, then add to graph and break
  5. Iterate through all the letters {for node in graph for n in node}
  6. find cycle (if colors[n]==WHITE)
  7. Return reverse of result - topsort

WHITE,GRAY,BLACK=0,1,2

class Solution:
def alienOrder(self, words: List[str]) -> str:

    graph=defaultdict(list)
    
    for word1, word2 in zip(words, words[1:]):
        if word1!=word2 and word1[:len(word2)]==word2:
            return ""
        for c1, c2 in zip(word1, word2):
            if c1!=c2:
                graph[c1].append(c2)
                break
            else:
                continue
    
    nodes={c for word in words for c in word}
    
    result=[]
    colors=defaultdict(int)
    for n in nodes:       
        if colors[n]==WHITE:
            if self.has_cycle(n, graph, colors, result):
                return ""
        
    return ''.join(result[::-1])
            
        
def has_cycle(self, n, graph, colors, result):
    colors[n]=GRAY
    for nei in graph[n]:
        if colors[nei]==GRAY:
            return True
        elif colors[nei]==WHITE:
            if self.has_cycle(nei, graph, colors, result):
                return True
        else:
            continue
    colors[n]=BLACK
    result.append(n)
    return False

T: O(C+E) - c is the number of unique characters in both words
S: O(C+E)

85
Q
  1. Encode and Decode Strings
    Medium

Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings.

Machine 1 (sender) has the function:

string encode(vector strs) {
// … your code
return encoded_string;
}
Machine 2 (receiver) has the function:
vector decode(string s) {
//… your code
return strs;
}
So Machine 1 does:

string encoded_string = encode(strs);
and Machine 2 does:

vector strs2 = decode(encoded_string);
strs2 in Machine 2 should be the same as strs in Machine 1.

Implement the encode and decode methods.

You are not allowed to solve the problem using any serialize methods (such as eval).

Example 1:

Input: dummy_input = [“Hello”,”World”]
Output: [“Hello”,”World”]
Explanation:
Machine 1:
Codec encoder = new Codec();
String msg = encoder.encode(strs);
Machine 1 —msg—> Machine 2

Machine 2:
Codec decoder = new Codec();
String[] strs = decoder.decode(msg);

A
  1. Encode & decode
  2. encode : f”{len(s):{s}”
  3. decode:
    i=0
    while i str:
    result=””
    for s in strs:
    result+=f”{len(s)}:{s}”
    return resultdef decode(self, s: str) -> List[str]:
    i=0
    result=[]
     while i
86
Q
  1. Expression Add Operators
    Hard

Given a string num that contains only digits and an integer target, return all possibilities to insert the binary operators ‘+’, ‘-‘, and/or ‘*’ between the digits of num so that the resultant expression evaluates to the target value.

Note that operands in the returned expressions should not contain leading zeros.

Example 1:

Input: num = “123”, target = 6
Output: [“123”,”1+2+3”]
Explanation: Both “123” and “1+2+3” evaluate to 6.
Example 2:

Input: num = “232”, target = 8
Output: [“23+2”,”2+32”]
Explanation: Both “23+2” and “2+32” evaluate to 8.
Example 3:

Input: num = “3456237490”, target = 9191
Output: []
Explanation: There are no expressions that can be created from “3456237490” to evaluate to 9191.

A
  1. Backtracking, helper with i, curr, cstring, prev
  2. In the callee function, loop through from num (1, len(nums)+1) and send to the helper only the remaining string.
  3. The initial parameters are self.helper(nums[i:], target, curr=int(nums[:i]), cstring=nums[:i], prev=int(nums[:i]), result)
  4. Within the helper, if not nums and curr==target, then result.append(cstring)
  5. if not nums: return
  6. Iterate through the remaining num (1, len(nums)-1),
    three branches - one for add, subtraction and multiply (multiply is tricky)
  7. add - params self.helper(nums[i:], target, curr=curr+int(nums[:i]), cstring=cstring+nums[:i], prev=int(nums[:i]), result)
  8. sub - params self.helper(nums[i:], target, curr=curr-int(nums[:i]), cstring=cstring-nums[:i], prev=-int(nums[:i]), result)
  9. mult - params self.helper(nums[i:], target, curr=curr-prev+prevint(nums[:i]), cstring=cstringnums[:i], prev=prev*int(nums[:i]), result)

class Solution:
def addOperators(self, nums: str, target: int) -> List[str]:
result=[]
for i in range(1, len(nums)+1):
if i==1 or (i>1 and nums[0]!=’0’):
self.add_operators(nums[i:], target, int(nums[:i]), int(nums[:i]), nums[:i], result)
return result

def add_operators(self, nums, target, curr, prev, cstring, result):
    if not nums and curr==target:
        result.append(cstring)
    
    if not nums:
        return 
    
    for i in range(1, len(nums)+1):
        if i==1 or (i>1 and nums[0]!='0'):
            num=int(nums[:i])
            self.add_operators(nums[i:], target, curr+num, num, cstring+'+'+str(num), result)
            self.add_operators(nums[i:], target, curr-num, -num, cstring+'-'+str(num), result)
            self.add_operators(nums[i:], target, curr-prev+prev*num, prev*num, cstring+'*'+str(num), result)

T: O(3^n)
S: O(n)

87
Q
  1. Walls and Gates
    Medium

You are given an m x n grid rooms initialized with these three possible values.

-1 A wall or an obstacle.
0 A gate.
INF Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.
Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.

A
  1. BFS - Do a r,c sweep andadd all 0 to the queue
  2. if grid[r][c]==INF, then update grid[r][c]= dist+1def wallsAndGates(self, rooms: List[List[int]]) -> None:
    R = len(rooms)
    C = len(rooms[0])
     INF = 2147483647
    
     queue = deque([])
     for r in range(R):
         for c in range(C):
             if rooms[r][c] == 0:
                 queue.append((r, c, 0))
    
     while queue:
         r, c, dist = queue.popleft()
         neis = [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]
         for nr, nc in neis:
             if -1 < nr < R and -1 < nc < C and rooms[nr][nc] == INF:
                 rooms[nr][nc] = dist + 1
                 queue.append((nr, nc, dist + 1))

T: O(n)
S: O(n)

88
Q
  1. Find the Duplicate Number
    Medium

Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.

There is only one repeated number in nums, return this repeated number.

You must solve the problem without modifying the array nums and uses only constant extra space.

Example 1:

Input: nums = [1,3,4,2,2]
Output: 2
Example 2:

Input: nums = [3,1,3,4,2]
Output: 3
Example 3:

Input: nums = [3,3,3,3,3]
Output: 3

A

store=set()

Floyd’s cycle finding algorithm is fantastic for this.

def findDuplicate(self, nums: List[int]) -> int:
    tortoise=hare=nums[0]
    
    while True:
        tortoise=nums[tortoise]
        hare=nums[nums[hare]]
        if tortoise==hare:
            break
        
    
    tortoise=nums[0]
    
    while tortoise!=hare:
        hare=nums[hare]
        tortoise=nums[tortoise]
    
    return tortoise

T: O(n)
S: O(1)

def findDuplicate(self, nums: List[int]) -> int:
    nums.sort()
    for i in range(1, len(nums)):
        if i>0 and nums[i]==nums[i-1]:
            return nums[i]
    return -1

# for num in nums:
# if num in store:
# return num
# store.add(num)
# return -1

89
Q
  1. Game of Life
    Medium

According to Wikipedia’s article: “The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.”

The board is made up of an m x n grid of cells, where each cell has an initial state: live (represented by a 1) or dead (represented by a 0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):

Any live cell with fewer than two live neighbors dies as if caused by under-population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by over-population.
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously. Given the current state of the m x n grid board, return the next state.

Example 1:

Input: board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
Output: [[0,0,0],[1,0,1],[0,1,1],[0,1,0]]

A

live : <2 - die

    #live : >=2 x <=3 - live
    #live : >3 - die
    #dead : =3 - live
  1. Iterate through R, C and add count if the people are either 1 or -1
  2. Convert living people (1) who are going to die in next cycle as -1
  3. Convert dead people with 3 people living around as 2

During the final sweep, convert -1 to 0 and 2 to 1

def gameOfLife(self, board: List[List[int]]) -> None:
    """
    Do not return anything, modify board in-place instead.
    """
    R=len(board)
    C=len(board[0])
    
    for r in range(R):
        for c in range(C):
            neis = [(r+1, c),(r-1, c), (r, c+1), (r, c-1),
                    (r+1, c+1), (r+1, c-1), (r-1, c+1), (r-1, c-1)
                   ]
            
            count=0
            for nr,nc in neis:
                if -13 or count<2) and board[r][c]==1:
                board[r][c]=-1
            elif count==3 and board[r][c]==0:
                board[r][c]=2
    
    for r in range(R):
        for c in range(C):
            if board[r][c]==2:
                board[r][c]=1
            elif board[r][c]==-1:
                board[r][c]=0

T: O(n*m)
S: O(1)

90
Q
  1. Find Median from Data Stream
    Hard

The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value, and the median is the mean of the two middle values.

For example, for arr = [2,3,4], the median is 3.
For example, for arr = [2,3], the median is (2 + 3) / 2 = 2.5.
Implement the MedianFinder class:

MedianFinder() initializes the MedianFinder object.
void addNum(int num) adds the integer num from the data stream to the data structure.
double findMedian() returns the median of all elements so far. Answers within 10-5 of the actual answer will be accepted.

Example 1:

Input
[“MedianFinder”, “addNum”, “addNum”, “findMedian”, “addNum”, “findMedian”]
[[], [1], [2], [], [3], []]
Output
[null, null, null, 1.5, null, 2.0]

Explanation
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

A
  1. Have two pq, left_max and right_min
  2. Push to left_max if not left_max or incoming num<= - left_max[0]
  3. else, push to right_max
  4. if len(self.left_max)-len(self.right_min)>=2:
    pop from left_max and push to right_min
  5. vice verse
  6. for find median, if both lens are the same, then average. Else, return top

class MedianFinder:

def \_\_init\_\_(self):
    self.left_max=[]
    self.right_min=[]
    

def addNum(self, num: int) -> None:
    if not self.left_max or num<=-self.left_max[0]:
        heapq.heappush(self.left_max, -num)
    else:
        heapq.heappush(self.right_min, num)
    
    if len(self.left_max)-len(self.right_min)>=2:
        popped=heapq.heappop(self.left_max)
        heapq.heappush(self.right_min, -popped)
    elif len(self.right_min)-len(self.left_max)>=2:
        popped=heapq.heappop(self.right_min)
        heapq.heappush(self.left_max, -popped)
        

def findMedian(self) -> float:
    if len(self.left_max)==len(self.right_min):
        return (-self.left_max[0]+self.right_min[0])/2.0
    elif len(self.left_max)>len(self.right_min):
        return -self.left_max[0]
    else:
        return self.right_min[0]

T: O(5logn) - O(logn) - at best there are 3 heap insertions and 2 heap deletions at every iteration
S: O(n)

91
Q
  1. Best Meeting Point
    Hard

Given an m x n binary grid grid where each 1 marks the home of one friend, return the minimal total travel distance.

The total travel distance is the sum of the distances between the houses of the friends and the meeting point.

The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.

Example 1:

Input: grid = [[1,0,0,0,1],[0,0,0,0,0],[0,0,1,0,0]]
Output: 6
Explanation: Given three friends living at (0,0), (0,4), and (2,2).
The point (0,2) is an ideal meeting point, as the total travel distance of 2 + 2 + 2 = 6 is minimal.
So return 6.

A
  1. Simple mid calculation
  2. loop thorugh r and c and append to rows and cols array
  3. sort both rows and cols and find mid point for both
  4. distance=0
  5. Loop through rows and calculate abs(mid_dist-r). Same for cols. distance+=abs(c-mid_c)
92
Q
  1. Serialize and Deserialize Binary Tree
    Hard

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.

Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.

Example 1:

Input: root = [1,2,3,null,null,4,5]
Output: [1,2,3,null,null,4,5]

A
  1. For serialization, BFS.
    1. if popped value is ‘#’, append to result
    2. Else, append node.val
    3. if node.left and right, append to queue. If not append (‘#’)
    4. return ‘,’.join(result)
  2. For deserialization, maintain a queue and an index1 (root = TreeNode(data[0)
    1. Split data[1:] and add to deque.
    2. pop value and see if ‘#’. If not, append to treenode and increment index (also add to the queue)
93
Q
  1. Bulls and Cows
    Medium

You are playing the Bulls and Cows game with your friend.

You write down a secret number and ask your friend to guess what the number is. When your friend makes a guess, you provide a hint with the following info:

The number of “bulls”, which are digits in the guess that are in the correct position.
The number of “cows”, which are digits in the guess that are in your secret number but are located in the wrong position. Specifically, the non-bull digits in the guess that could be rearranged such that they become bulls.
Given the secret number secret and your friend’s guess guess, return the hint for your friend’s guess.

The hint should be formatted as “xAyB”, where x is the number of bulls and y is the number of cows. Note that both secret and guess may contain duplicate digits.

Example 1:

Input: secret = “1807”, guess = “7810”
Output: “1A3B”
Explanation: Bulls are connected with a ‘|’ and cows are underlined:
“1807”
|
“7810”
Example 2:

Input: secret = “1123”, guess = “0111”
Output: “1A1B”
Explanation: Bulls are connected with a ‘|’ and cows are underlined:
“1123” “1123”
| or |
“0111” “0111”
Note that only one of the two unmatched 1s is counted as a cow since the non-bull digits can only be rearranged to allow one 1 to be a bull.

A
  1. Zip and iterate. Maintain two dictionary to keep track of counter for s and g
  2. If they are equal, add to bulls
  3. If they are not, add to s and g counter
  4. In order to calculate cows, loop through the secret dictionary and check if character is in g. If yes, cows+= min(counter in s, counter in g)def getHint(self, secret: str, guess: str) -> str:
    bulls = 0
    cows = 0
    sd = defaultdict(int)
    gd = defaultdict(int)
     for s, g in zip(secret, guess):
         if s == g:
             bulls += 1
         else:
             sd[s] += 1
             gd[g] += 1
    
     for k in sd:
         if k in gd:
             cows += min(sd[k], gd[k])
     return f"{bulls}A{cows}B"

T: O(n)
S: O(n)

94
Q
  1. Remove Invalid Parentheses
    Hard

Given a string s that contains parentheses and letters, remove the minimum number of invalid parentheses to make the input string valid.

Return a list of unique strings that are valid with the minimum number of removals. You may return the answer in any order.

Example 1:

Input: s = “()())()”
Output: [”(())()”,”()()()”]

Example 2:

Input: s = “(a)())()”
Output: [“(a())()”,”(a)()()”]

A
  1. BFS/Level order traversal - because we need to do minimum number of removals
  2. For each popped string in the level, check “is_valid” and add to result and set found=True
  3. if found==True, then stop adding to queue because this level is good enough as shortest (but not before adding the items to the queue)
  4. For each index in the popped string, if they are not () continue. Else, construct s[:i]+s[i+1:] and add to queue (don’t forget the seen because of undirected nature of this/cycle)

T:
On the first level, there’s only one string which is the input string s, let’s say the length of it is n, to check whether it’s valid, we need O(n) time. On the second level, we remove one ( or ) from the first level, so there are C(n, n-1) new strings, each of them has n-1 characters, and for each string, we need to check whether it’s valid or not, thus the total time complexity on this level is (n-1) x C(n, n-1). Come to the third level, total time complexity is (n-2) x C(n, n-2), so on and so forth…

Finally we have this formula:

T(n) = n x C(n, n) + (n-1) x C(n, n-1) + … + 1 x C(n, 1) = n x 2^(n-1).

S: O(n) (????)

95
Q
  1. Range Sum Query 2D - Immutable
    Medium

Given a 2D matrix matrix, handle multiple queries of the following type:

Calculate the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
Implement the NumMatrix class:

NumMatrix(int[][] matrix) Initializes the object with the integer matrix matrix.
int sumRegion(int row1, int col1, int row2, int col2) Returns the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
You must design an algorithm where sumRegion works on O(1) time complexity.

A
  1. Prepare a prefix sum (sums) matrix (R+1, C+1).
  2. for r in range(R+1) and for c in range (C+1), sums[r][c]=sums[r-1][c]+ sums[r][c-1]+matrix[r-1][c-1]-sums[r-1][c-1]
  3. During sum region, the indices are all incremented by 1 (row1+=1, col1+=1, row2+=1, col2+=1)
  4. return sums[row2][col2]-sums[row1-1][col2]-sums[row1][col1-1]+sums[row1-1][col1-1]
96
Q
  1. Binary Tree Vertical Order Traversal
    Medium

Given the root of a binary tree, return the vertical order traversal of its nodes’ values. (i.e., from top to bottom, column by column).

If two nodes are in the same row and column, the order should be from left to right.

https://leetcode.com/problems/binary-tree-vertical-order-traversal/

A
  1. Level order traversal
  2. queue keeps (node, vorder) – (root, 0)
  3. for left, add (node.left, vorder-1) and for right (node.right, vorder+1)
  4. Keep track of maxi and mini for final result consolidation

T: O(n)
S: O(n)

97
Q
  1. Shortest Distance from All Buildings
    Hard

You are given an m x n grid grid of values 0, 1, or 2, where:

each 0 marks an empty land that you can pass by freely,
each 1 marks a building that you cannot pass through, and
each 2 marks an obstacle that you cannot pass through.
You want to build a house on an empty land that reaches all buildings in the shortest total travel distance. You can only move up, down, left, and right.

Return the shortest travel distance for such a house. If it is not possible to build such a house according to the above rules, return -1.

The total travel distance is the sum of the distances between the houses of the friends and the meeting point.

The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.

A
  1. EMPTY_LAND changes every iteration because we want to traverse only through them.
  2. Do a BFS for each EMPTY_LAND and EMPTY_LAND-=1
  3. Return the local_min_dist that we saw during each BFS
  4. Set the result min_dist to this local_min_dist at the end of each iteration. Return
98
Q
  1. Coin Change
    Medium

You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.

Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

You may assume that you have an infinite number of each kind of coin.

Example 1:

Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1

A
  1. DP - initialized dp to float(‘inf’), dp[0]=0def coinChange(self, coins: List[int], amount: int) -> int:
    dp=[float(‘inf’)]*(amount+1)
    dp[0]=0
     for a in range(1, amount+1):
         for coin in coins:
             if a>=coin:
                 dp[a]=min (dp[a], 1+ dp[a-coin])
                    
     return dp[-1] if dp[-1]
99
Q
  1. Largest BST Subtree
    Medium

Given the root of a binary tree, find the largest subtree, which is also a Binary Search Tree (BST), where the largest means subtree has the largest number of nodes.

A Binary Search Tree (BST) is a tree in which all the nodes follow the below-mentioned properties:

The left subtree values are less than the value of their parent (root) node’s value.
The right subtree values are greater than the value of their parent (root) node’s value.
Note: A subtree must include all of its descendants.

Example 1:

Input: root = [10,5,15,1,8,null,7]
Output: 3
Explanation: The Largest BST Subtree in this case is the highlighted one. The return value is the subtree’s size, which is 3.
Example 2:

Input: root = [4,2,7,2,3,5,null,2,null,null,null,null,null,1]
Output: 2

A
  1. DFS and return self.result
  2. Within dfs, if not node, return float(‘inf’), float(‘-inf’), 0 for lmax, rmin, count
  3. lmax, lmin, count=self.dfs(node.left) and (same for right)
  4. count=float(‘-inf’)
  5. if lmax<=node.val<=rmin:
    count=lcount+rcount+1
    update self.result
  6. return min(lmin, node.val), max(rmax, node.val), count

class Solution:
def largestBSTSubtree(self, root: Optional[TreeNode]) -> int:
self.result=0
self.subtree(root)
return self.result

def subtree(self, node):
    if not node:
        return float('inf'), float('-inf'), 0
    
    lmin, lmax, lcount=self.subtree(node.left)
    rmin, rmax, rcount=self.subtree(node.right)
    
    count=float('-inf')
    if node.val>lmax and node.val
100
Q
  1. Increasing Triplet Subsequence
    Medium

Given an integer array nums, return true if there exists a triple of indices (i, j, k) such that i < j < k and nums[i] < nums[j] < nums[k]. If no such indices exists, return false.

Example 1:

Input: nums = [1,2,3,4,5]
Output: true
Explanation: Any triplet where i < j < k is valid.
Example 2:

Input: nums = [5,4,3,2,1]
Output: false
Explanation: No triplet exists.

A
  1. Simple yet tricky.
  2. Initialize first and second to inf
  3. If num<=first, set first to num
  4. If num<=second, second to num
  5. else return truedef increasingTriplet(self, nums: List[int]) -> bool:
    first=second=float(‘inf’)
     for num in nums:
         if num<=first:
             first=num
         elif num<=second:
             second=num
         else:
             return True
     return False
101
Q
  1. Nested List Weight Sum
    Medium

You are given a nested list of integers nestedList. Each element is either an integer or a list whose elements may also be integers or other lists.

The depth of an integer is the number of lists that it is inside of. For example, the nested list [1,[2,2],[[3],2],1] has each integer’s value set to its depth.

Return the sum of each integer in nestedList multiplied by its depth.

Example 1:

Input: nestedList = [[1,1],2,[1,1]]
Output: 10
Explanation: Four 1’s at depth 2, one 2 at depth 1. 12 + 12 + 21 + 12 + 1*2 = 10.

A
  1. BFS
  2. If node.isInteger(), total+=level*each.getInteger()
  3. Else, queue.apepnd(node.getList(), level+1)

T: O(N)
S: O(N)

N=total number of nested elements in the input list

102
Q
  1. Flatten Nested List Iterator
    Medium

You are given a nested list of integers nestedList. Each element is either an integer or a list whose elements may also be integers or other lists. Implement an iterator to flatten it.

Implement the NestedIterator class:

NestedIterator(List nestedList) Initializes the iterator with the nested list nestedList.
int next() Returns the next integer in the nested list.
boolean hasNext() Returns true if there are still some integers in the nested list and false otherwise.
Your code will be tested with the following pseudocode:

initialize iterator with nestedList
res = []
while iterator.hasNext()
append iterator.next() to the end of res
return res
If res matches the expected flattened list, then your code will be judged as correct.

Example 1:

Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].
Example 2:

Input: nestedList = [1,[4,[6]]]
Output: [1,4,6]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6].

A
  1. Create a queue and add the nested iterator to the queue
  2. next: return queue.popleft().getInteger()
  3. hasnext:
    check if the queue is empty or not. If not empty, check if the top is integer - (queue[0].isInteger). If integer, return true
    else: pop off the top (which is a list) and add the elements to the queue (in reverse order) - queue.extendleft(lst.getList()[::-1])

class NestedIterator:
def __init__(self, nestedList: [NestedInteger]):
self.queue=deque(nestedList)

def next(self) -> int:
    return self.queue.popleft().getInteger()
    

def hasNext(self) -> bool:
    while self.queue:
        if self.queue[0].isInteger():
            return True
        else:
            lst=self.queue.popleft()
            self.queue.extendleft(lst.getList()[::-1])

T: O(n)
S: O(n)

103
Q
  1. Top K Frequent Elements
    Medium

Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.

Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

A
  1. Counter and push to heap
  2. If len(pq)>k, heappop()
  3. Iterate through pq and add to result
104
Q
  1. Design Tic-Tac-Toe
    Medium

Assume the following rules are for the tic-tac-toe game on an n x n board between two players:

A move is guaranteed to be valid and is placed on an empty block.
Once a winning condition is reached, no more moves are allowed.
A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game.
Implement the TicTacToe class:

TicTacToe(int n) Initializes the object the size of the board n.
int move(int row, int col, int player) Indicates that the player with id player plays at the cell (row, col) of the board. The move is guaranteed to be a valid move, and the two players alternate in making moves. Return
0 if there is no winner after the move,
1 if player 1 is the winner after the move, or
2 if player 2 is the winner after the move.

A
  1. During the init, hold rows, cols array, self.n
  2. diag and anti_diag int
  3. Upon move (row, col, player),
    1. if r==c, add 1 to self.diag if player 1 or -1 if player 2
    2. if r+c==N-1, then add 1 to self.anti_diag if player 1 else -1
    3. self.rows[row]+=1 if player 1 else -1
    4. self.cols[col]+=1 if player 1 else -1
  4. If rows[r]==n or cols[c]==n or self.diag==n or self.anti_diag==n, then return player
  5. if rows[r]==-n.. return player
105
Q
  1. Kth Smallest Element in a Sorted Matrix
    Medium

Given an n x n matrix where each of the rows and columns is sorted in ascending order, return the kth smallest element in the matrix.

Note that it is the kth smallest element in the sorted order, not the kth distinct element.

You must find a solution with a memory complexity better than O(n2).

Example 1:

Input: matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
Output: 13
Explanation: The elements in the matrix are [1,5,9,10,11,12,13,13,15], and the 8th smallest number is 13

A
  1. Binary search but the search function is to count_values_less_than_mid>=k. If greater, then high=mid-1, result=mid
  2. The result=mid is important so that we capture the value which has greater than of “equal to”. If it is equal to, we move left a little.
  3. in count_values_less_than_mid, c=C-1,
    for r in range R,
    while c>=0 and grid[r][c]>mid:
    c-=1
    count+=c+1 (IMPT)
    return count
106
Q
  1. Insert Delete GetRandom O(1)
    Medium

Implement the RandomizedSet class:

RandomizedSet() Initializes the RandomizedSet object.
bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
int getRandom() Returns a random element from the current set of elements (it’s guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.
You must implement the functions of the class such that each function works in average O(1) time complexity.

Example 1:

Input
[“RandomizedSet”, “insert”, “remove”, “insert”, “getRandom”, “remove”, “insert”, “getRandom”]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]

Explanation
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomizedSet.remove(2); // Returns false as 2 does not exist in the set.
randomizedSet.insert(2); // Inserts 2 to the set, returns true. Set now contains [1,2].
randomizedSet.getRandom(); // getRandom() should return either 1 or 2 randomly.
randomizedSet.remove(1); // Removes 1 from the set, returns true. Set now contains [2].
randomizedSet.insert(2); // 2 was already in the set, so return false.
randomizedSet.getRandom(); // Since 2 is the only number in the set, getRandom() will always return 2.

A
  1. Three functions, insert, remove, getRandom - create vals array and mapp of val to index
  2. Insert:
    1. if val not in map, insert to vals, set map’s index to be N-1.
  3. Remove:
    1. if val in map, get index of the item
    2. Get last value and identify its index from map
    3. swap (overwrite) removable item with last item
    4. Update map’s index for last item with the removable item’s index
    5. remove last item from vals
    6. remove last item from map
  4. getRandom:
    1. random.randomint(0, len(vals)-1)
    2. return self.vals[ri]
107
Q
  1. Insert Delete GetRandom O(1) - Duplicates allowed
    Hard

2284

RandomizedCollection is a data structure that contains a collection of numbers, possibly duplicates (i.e., a multiset). It should support inserting and removing specific elements and also reporting a random element.

Implement the RandomizedCollection class:

RandomizedCollection() Initializes the empty RandomizedCollection object.
bool insert(int val) Inserts an item val into the multiset, even if the item is already present. Returns true if the item is not present, false otherwise.
bool remove(int val) Removes an item val from the multiset if present. Returns true if the item is present, false otherwise. Note that if val has multiple occurrences in the multiset, we only remove one of them.
int getRandom() Returns a random element from the current multiset of elements. The probability of each element being returned is linearly related to the number of the same values the multiset contains.
You must implement the functions of the class such that each function works on average O(1) time complexity.

Note: The test cases are generated such that getRandom will only be called if there is at least one item in the RandomizedCollection.

Example 1:

Input
[“RandomizedCollection”, “insert”, “insert”, “insert”, “getRandom”, “remove”, “getRandom”]
[[], [1], [1], [2], [], [1], []]
Output
[null, true, false, true, 2, true, 1]

Explanation
RandomizedCollection randomizedCollection = new RandomizedCollection();
randomizedCollection.insert(1); // return true since the collection does not contain 1.
// Inserts 1 into the collection.
randomizedCollection.insert(1); // return false since the collection contains 1.
// Inserts another 1 into the collection. Collection now contains [1,1].
randomizedCollection.insert(2); // return true since the collection does not contain 2.
// Inserts 2 into the collection. Collection now contains [1,1,2].
randomizedCollection.getRandom(); // getRandom should:
// - return 1 with probability 2/3, or
// - return 2 with probability 1/3.
randomizedCollection.remove(1); // return true since the collection contains 1.
// Removes 1 from the collection. Collection now contains [1,2].
randomizedCollection.getRandom(); // getRandom should return 1 or 2, both equally likely.

A
  1. Instead of index in the map, maintain a set of indexes.
  2. Set pop (for popping a random element) and discard for removing a specific element from set.

class RandomizedCollection:

def \_\_init\_\_(self):
    self.vals=[]
    self.mapp=defaultdict(set)
    

def insert(self, val: int) -> bool:
    self.vals.append(val)
    self.mapp[val].add(len(self.vals)-1)
    return len(self.mapp[val])==1

def remove(self, val: int) -> bool:
    if self.mapp[val]:
        rmi=self.mapp[val].pop() #fetch one index
        last_val=self.vals[-1]
        self.vals[rmi]=last_val
        self.mapp[last_val].add(rmi)
        self.mapp[last_val].discard(len(self.vals)-1)
        self.vals.pop()
        return True
    return False

def getRandom(self) -> int:
    return random.choice(self.vals)
108
Q
  1. Encode and Decode Strings
    Medium

Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings.

Machine 1 (sender) has the function:

string encode(vector strs) {
// … your code
return encoded_string;
}
Machine 2 (receiver) has the function:
vector decode(string s) {
//… your code
return strs;
}
So Machine 1 does:

string encoded_string = encode(strs);
and Machine 2 does:

vector strs2 = decode(encoded_string);
strs2 in Machine 2 should be the same as strs in Machine 1.

Implement the encode and decode methods.

You are not allowed to solve the problem using any serialize methods (such as eval).

Example 1:

Input: dummy_input = [“Hello”,”World”]
Output: [“Hello”,”World”]
Explanation:
Machine 1:
Codec encoder = new Codec();
String msg = encoder.encode(strs);
Machine 1 —msg—> Machine 2

Machine 2:
Codec decoder = new Codec();
String[] strs = decoder.decode(msg);

A
  1. Encode & decode
  2. encode : f”{len(s):{s}”
  3. decode:
    i=0
    while i str:
    result=””
    for s in strs:
    result+=f”{len(s)}:{s}”
    return resultdef decode(self, s: str) -> List[str]:
    i=0
    result=[]
     while i
109
Q
  1. Random Pick Index
    Medium

Given an integer array nums with possible duplicates, randomly output the index of a given target number. You can assume that the given target number must exist in the array.

Implement the Solution class:

Solution(int[] nums) Initializes the object with the array nums.
int pick(int target) Picks a random index i from nums where nums[i] == target. If there are multiple valid i’s, then each index should have an equal probability of returning.

A
  1. Maintain an index map.
  2. Lookup the target value in the map, which would return a list
  3. random.randint(0, len(ll)-1). Return ll[random_index]
110
Q
  1. Evaluate Division
    Medium

You are given an array of variable pairs equations and an array of real numbers values, where equations[i] = [Ai, Bi] and values[i] represent the equation Ai / Bi = values[i]. Each Ai or Bi is a string that represents a single variable.

You are also given some queries, where queries[j] = [Cj, Dj] represents the jth query where you must find the answer for Cj / Dj = ?.

Return the answers to all queries. If a single answer cannot be determined, return -1.0.

Note: The input is always valid. You may assume that evaluating the queries will not result in division by zero and that there is no contradiction.

Note: The variables that do not occur in the list of equations are undefined, so the answer cannot be determined for them.

Example 1:

Input: equations = [[“a”,”b”],[“b”,”c”]], values = [2.0,3.0], queries = [[“a”,”c”],[“b”,”a”],[“a”,”e”],[“a”,”a”],[“x”,”x”]]
Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000]
Explanation:
Given: a / b = 2.0, b / c = 3.0
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
return: [6.0, 0.5, -1.0, 1.0, -1.0 ]
note: x is undefined => -1.0

A
  1. Construct a graph: graph[u].append((v,val)), graph[v].append((u,1/val))
  2. BFS after that.
111
Q
  1. Partition Equal Subset Sum
    Medium

Given an integer array nums, return true if you can partition the array into two subsets such that the sum of the elements in both subsets is equal or false otherwise.

Example 1:

Input: nums = [1,5,11,5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:

Input: nums = [1,2,3,5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.

A
  1. Halve the sum and do DP
  2. skip or pick - helper must have index, target, nums and memodef canPartition(self, nums: List[int]) -> bool:
    summ = sum(nums)
    if summ & 1:
    return False
    target = summ // 2
     return self.can_partition(nums, target, 0, {})
    def can_partition(self, nums, target, i, memo):
    if (target, i) in memo:
    return memo[(target, i)]
    if target < 0 or i >= len(nums):
    return False
    if target == 0:
    return True
     # skip num
     skip = self.can_partition(nums, target, i + 1, memo)
     # pick num
     pick = self.can_partition(nums, target - nums[i], i + 1, memo)
    
     memo[(target, i)] = skip or pick
     return skip or pick

T: O(MN) - targetindex
S: O(MN) - max memo values is targetindex

112
Q
  1. Pacific Atlantic Water Flow
    Medium

There is an m x n rectangular island that borders both the Pacific Ocean and Atlantic Ocean. The Pacific Ocean touches the island’s left and top edges, and the Atlantic Ocean touches the island’s right and bottom edges.

The island is partitioned into a grid of square cells. You are given an m x n integer matrix heights where heights[r][c] represents the height above sea level of the cell at coordinate (r, c).

The island receives a lot of rain, and the rain water can flow to neighboring cells directly north, south, east, and west if the neighboring cell’s height is less than or equal to the current cell’s height. Water can flow from any cell adjacent to an ocean into the ocean.

Return a 2D list of grid coordinates result where result[i] = [ri, ci] denotes that rain water can flow from cell (ri, ci) to both the Pacific and Atlantic oceans.

Example 1:

Input: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
Output: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
Explanation: The following cells can flow to the Pacific and Atlantic oceans, as shown below:
[0,4]: [0,4] -> Pacific Ocean
[0,4] -> Atlantic Ocean
[1,3]: [1,3] -> [0,3] -> Pacific Ocean
[1,3] -> [1,4] -> Atlantic Ocean
[1,4]: [1,4] -> [1,3] -> [0,3] -> Pacific Ocean
[1,4] -> Atlantic Ocean
[2,2]: [2,2] -> [1,2] -> [0,2] -> Pacific Ocean
[2,2] -> [2,3] -> [2,4] -> Atlantic Ocean
[3,0]: [3,0] -> Pacific Ocean
[3,0] -> [4,0] -> Atlantic Ocean
[3,1]: [3,1] -> [3,0] -> Pacific Ocean
[3,1] -> [4,1] -> Atlantic Ocean
[4,0]: [4,0] -> Pacific Ocean
[4,0] -> Atlantic Ocean
Note that there are other possible paths for these cells to flow to the Pacific and Atlantic oceans.

A
  1. R=0,C=0 is pacific and R-1, C-1 is atlantic - get their starts
  2. Do a bfs to get all the r,c which are higher than the neighbours (heights[nr][nc]>=heights[r][c]
  3. add all astarts to atops and pstarts to ptops
  4. return atops&ptops
113
Q
  1. Battleships in a Board
    Medium

Given an m x n matrix board where each cell is a battleship ‘X’ or empty ‘.’, return the number of the battleships on board.

Battleships can only be placed horizontally or vertically on board. In other words, they can only be made of the shape 1 x k (1 row, k columns) or k x 1 (k rows, 1 column), where k can be of any size. At least one horizontal or vertical cell separates between two battleships (i.e., there are no adjacent battleships).

Example 1:

Input: board = [[“X”,”.”,”.”,”X”],[”.”,”.”,”.”,”X”],[”.”,”.”,”.”,”X”]]
Output: 2

A
  1. Iterate through R and C
  2. if board[r][c]==’X’ and (r==0 or board[r-1][c]==’.’) and (c==0 or board[r][c-1]==’.’): count+=1def countBattleships(self, board: List[List[str]]) -> int:
    R=len(board)
    C=len(board[0])
     count=0
     for r in range(R):
         for c in range(C):
             if board[r][c]=='X' and (r==0 or board[r-1][c]=='.') and (c==0 or board[r][c-1]=='.'):
                 count+=1
     return count

The reason why this works is that since we check only the top and the left, the count will be incremented only for the boundary of the battleship.

T: O(N+M)
S: O(1)

114
Q
  1. Non-overlapping Intervals
    Medium

Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.

Example 1:

Input: intervals = [[1,2],[2,3],[3,4],[1,3]]
Output: 1
Explanation: [1,3] can be removed and the rest of the intervals are non-overlapping.
Example 2:

Input: intervals = [[1,2],[1,2],[1,2]]
Output: 2
Explanation: You need to remove two [1,2] to make the rest of the intervals non-overlapping.
Example 3:

Input: intervals = [[1,2],[2,3]]
Output: 0
Explanation: You don’t need to remove any of the intervals since they’re already non-overlapping.

A
  1. Sort intervals based on end
  2. Initialize previous_end to float(‘-inf’)
  3. Check if current start >= previous_end: If yes, then there is no overlap. So, set the current_end as previous_end
  4. Else, increment the countdef eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
    intervals.sort(key=lambda i: i[1])
    pe = float(‘-inf’)
    count = 0
    for cs, ce in intervals:
    if cs >= pe:
    pe = ce
    else:
    count += 1
    return count

T:O(nlogn)
S: O(1) or O(n) space for sorting

115
Q
  1. Path Sum III
    Medium

Given the root of a binary tree and an integer targetSum, return the number of paths where the sum of the values along the path equals targetSum.

The path does not need to start or end at the root or a leaf, but it must go downwards (i.e., traveling only from parent nodes to child nodes).

Example 1:

Input: root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
Output: 3
Explanation: The paths that sum to 8 are shown.
Example 2:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: 3

A
  1. DFS with prefix sum - with self.result (int)
  2. Call helper with prefix, csumdef pathSum(self, node: Optional[TreeNode], target: int) -> int:
    self.result = 0
    prefix = defaultdict(int)
    prefix[0] = 1
     self.dfs(node, target, prefix, 0)
     return self.result
    def dfs(self, node, target, prefix, csum):
    if not node:
    return
     csum += node.val
     self.result += prefix[csum - target]
     prefix[csum] += 1
    
     self.dfs(node.left, target, prefix, csum)
     self.dfs(node.right, target, prefix, csum)
    
     prefix[csum] -= 1
     csum -= node.val

T:O(n)
S: O(n)

116
Q
  1. Find All Anagrams in a String
    Medium

Given two strings s and p, return an array of all the start indices of p’s anagrams in s. You may return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Example 1:

Input: s = “cbaebabacd”, p = “abc”
Output: [0,6]
Explanation:
The substring with start index = 0 is “cba”, which is an anagram of “abc”.
The substring with start index = 6 is “bac”, which is an anagram of “abc”.

A
  1. Sliding window
  2. counter(p), matches
  3. The while condition is tricky.

class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
counter=Counter(p)

    ws=0
    matches=0
    result=[]
    
    for we, swe in enumerate(s):
        if swe in counter:
            counter[swe]-=1
            
            if counter[swe]==0:
                matches+=1
                
        
        while matches==len(counter):
            if s[ws] in counter:
                counter[s[ws]]+=1
                
                if counter[s[ws]]>0:
                    matches-=1
                
            if we-ws+1==len(p):
                result.append(ws)
            
            ws+=1

        
    return result
117
Q
  1. String Compression
    Medium

Given an array of characters chars, compress it using the following algorithm:

Begin with an empty string s. For each group of consecutive repeating characters in chars:

If the group’s length is 1, append the character to s.
Otherwise, append the character followed by the group’s length.
The compressed string s should not be returned separately, but instead, be stored in the input character array chars. Note that group lengths that are 10 or longer will be split into multiple characters in chars.

After you are done modifying the input array, return the new length of the array.

You must write an algorithm that uses only constant extra space.

Example 1:

Input: chars = [“a”,”a”,”b”,”b”,”c”,”c”,”c”]
Output: Return 6, and the first 6 characters of the input array should be: [“a”,”2”,”b”,”2”,”c”,”3”]
Explanation: The groups are “aa”, “bb”, and “ccc”. This compresses to “a2b2c3”.
Example 2:

Input: chars = [“a”]
Output: Return 1, and the first character of the input array should be: [“a”]
Explanation: The only group is “a”, which remains uncompressed since it’s a single character.
Example 3:

Input: chars = [“a”,”b”,”b”,”b”,”b”,”b”,”b”,”b”,”b”,”b”,”b”,”b”,”b”]
Output: Return 4, and the first 4 characters of the input array should be: [“a”,”b”

A
  1. Very subtle issues can prop up
  2. slow=fast=0
  3. Iterate until fast1, then chars[slow+1]=str(c) iteration
  4. slow+=1, fast+=1
  5. The subtle thing is to set chars[slow]=chars[fast] at the beginning so that the array doesn’t retain the original values.def compress(self, chars: List[str]) -> int:
    slow=fast=0
    N=len(chars)
     while fast1:
             for c in str(count):
                 chars[slow+1]=c
                 slow+=1
            
         slow+=1
         fast+=1
            
     return slow
118
Q
  1. Validate IP Address
    Medium

Given a string queryIP, return “IPv4” if IP is a valid IPv4 address, “IPv6” if IP is a valid IPv6 address or “Neither” if IP is not a correct IP of any type.

A valid IPv4 address is an IP in the form “x1.x2.x3.x4” where 0 <= xi <= 255 and xi cannot contain leading zeros. For example, “192.168.1.1” and “192.168.1.0” are valid IPv4 addresses while “192.168.01.1”, “192.168.1.00”, and “192.168@1.1” are invalid IPv4 addresses.

A valid IPv6 address is an IP in the form “x1:x2:x3:x4:x5:x6:x7:x8” where:

1 <= xi.length <= 4
xi is a hexadecimal string which may contain digits, lowercase English letter (‘a’ to ‘f’) and upper-case English letters (‘A’ to ‘F’).
Leading zeros are allowed in xi.
For example, “2001:0db8:85a3:0000:0000:8a2e:0370:7334” and “2001:db8:85a3:0:0:8A2E:0370:7334” are valid IPv6 addresses, while “2001:0db8:85a3::8A2E:037j:7334” and “02001:0db8:85a3:0000:0000:8a2e:0370:7334” are invalid IPv6 addresses.

A
  1. Key functions - count()
  2. validate ipv4 and ipv6 separately
  3. if ip.count(‘.’)==3, then validate ipv4
  4. if ip.count(‘:’)==7, then validate ip6
  5. ipv4: comps = ip.split(‘.’). For each comp,
    a. if len(comp)==0 or len(comp)>3, then return False
    b. if (comp[0] and len(comp)!=1) or comp is not digit() or int(comp)>255, return False
  6. ipv6: comps=ip.split(‘:’). For each comp,
    a. if len(comp)==0 or len(comp)>4: return False
    b. if not all (c in valids for c in comp): return False
    valids = “1234567890abcdefABCDEF”

So, essentially,
1. do a length check
2. for ipv4, do a digit check and (the digit doesn’t start with 0 or int(comp)>255)
3. for ipv6, check if for all letters in comp, check if each letter is in valids

119
Q
  1. Sliding Window Median
    Hard

The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle values.

For examples, if arr = [2,3,4], the median is 3.
For examples, if arr = [1,2,3,4], the median is (2 + 3) / 2 = 2.5.
You are given an integer array nums and an integer k. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the median array for each window in the original array. Answers within 10-5 of the actual value will be accepted.

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [1.00000,-1.00000,-1.00000,3.00000,5.00000,6.00000]
Explanation:
Window position Median
————— —–
[1 3 -1] -3 5 3 6 7 1
1 [3 -1 -3] 5 3 6 7 -1
1 3 [-1 -3 5] 3 6 7 -1
1 3 -1 [-3 5 3] 6 7 3
1 3 -1 -3 [5 3 6] 7 5
1 3 -1 -3 5 [3 6 7] 6
Example 2:

Input: nums = [1,2,3,4,2,3,1,4,2], k = 3
Output: [2.00000,3.00000,3.00000,3.00000,2.00000,3.00000,2.00000]

A
  1. Give up already. :-)
  2. Just like median in a datastream, use 2 heaps
  3. left_max and right_min. Also maintain an count_dict which keeps track of whether the num to the count that is in the heap that needs to be popped/ignored.
  4. Step 1: Iterate from 0 to k and push to left_max, then pop from left_max and push to right_min. If right_min’s length is greater than left_max (invariant), then pop from right min and push to left max
  5. calculate median for the first three values now.
  6. Step 2: Iterate from k to len(nums).
  7. pick prev_num = nums[i-k] and increment count_dict
  8. if the prev_num0, vice versa
  9. For the final bit, loop until the the top of the left_max values is in count_dict. If yes, pop off and decrement count_dict
  10. Same with right_min
  11. Calculate median and return resultdef medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
    left_max = []
    right_min = []
    result = []
    count_dict = defaultdict(int)
    for i in range(k):
        heappush(left_max, -nums[i])
        heappush(right_min, -heappop(left_max))
        if len(right_min) > len(left_max):
            heappush(left_max, -heappop(right_min))
    
    median = self.find_median(left_max, right_min, k)
    result.append(median)
    
    for i in range(k, len(nums)):
        prev_num = nums[i - k]
        count_dict[prev_num] += 1
    
        balance = -1 if prev_num <= median else 1
    
        if nums[i] <= median:
            balance += 1
            heappush(left_max, -nums[i])
        else:
            balance -= 1
            heappush(right_min, nums[i])
    
        if balance < 0:
            heappush(left_max, -heappop(right_min))
        elif balance > 0:
            heappush(right_min, -heappop(left_max))
    
        while left_max and count_dict[-left_max[0]] > 0:
            count_dict[-left_max[0]] -= 1
            heappop(left_max)
    
        while right_min and count_dict[right_min[0]] > 0:
            count_dict[right_min[0]] -= 1
            heappop(right_min)
    
        median = self.find_median(left_max, right_min, k)
        result.append(median)
    return result
    def find_median(self, max_heap, min_heap, k):
    if k & 1:
    return -max_heap[0]
    else:
    return (-max_heap[0] + min_heap[0]) / 2

T: O(nlogk)
S: O(n)

120
Q
  1. The Maze
    Medium

There is a ball in a maze with empty spaces (represented as 0) and walls (represented as 1). The ball can go through the empty spaces by rolling up, down, left or right, but it won’t stop rolling until hitting a wall. When the ball stops, it could choose the next direction.

Given the m x n maze, the ball’s start position and the destination, where start = [startrow, startcol] and destination = [destinationrow, destinationcol], return true if the ball can stop at the destination, otherwise return false.

You may assume that the borders of the maze are all walls (see examples).

A
  1. BFS but we’ll have to let the path flow until we meet an obstacle
  2. Add start to the queue, hold directions array
  3. for dr, dr in dirs,
    nr,nc=r,c
    while -1
121
Q
  1. Diagonal Traverse
    Medium

Given an m x n matrix mat, return an array of all the elements of the array in a diagonal order.

A
  1. Create a list dictionary
  2. Iterate through R and C and populate result[r+c] and append to the list
  3. For the final result, if the r+c is even (zero index), reverse the list. Else, just append
122
Q
  1. Find Largest Value in Each Tree Row
    Medium

Given the root of a binary tree, return an array of the largest value in each row of the tree (0-indexed).

Example 1:

Input: root = [1,3,2,5,3,null,9]
Output: [1,3,9]
Example 2:

Input: root = [1,2,3]
Output: [1,3]

A
  1. Level order traversal
  2. For each level maintain a curr_max and add to result at the end of level exitdef largestValues(self, root: Optional[TreeNode]) -> List[int]:
    if not root:
    return None
     queue = deque([root])
     result = []
    
     while queue:
         level = len(queue)
         cmax = float('-inf')
         for _ in range(level):
             node = queue.popleft()
             cmax = max(cmax, node.val)
             if node.left:
                 queue.append(node.left)
    
             if node.right:
                 queue.append(node.right)
    
         result.append(cmax)
     return result

T: O(n)
S: O(n) - or O(m) where m = max number of nodes in that level

123
Q
  1. Continuous Subarray Sum
    Medium

Given an integer array nums and an integer k, return true if nums has a good subarray or false otherwise.

A good subarray is a subarray where:

its length is at least two, and
the sum of the elements of the subarray is a multiple of k.
Note that:

A subarray is a contiguous part of the array.
An integer x is a multiple of k if there exists an integer n such that x = n * k. 0 is always a multiple of k.

Example 1:

Input: nums = [23,2,4,6,7], k = 6
Output: true
Explanation: [2, 4] is a continuous subarray of size 2 whose elements sum up to 6.

A
  1. prefix_sum{0:1}
  2. csum=(csum+num)%k
  3. if csum in prefix (which means that if we subtract that prefix, we get a multiple of k), then check if i-prefix[csum]>=2
  4. else, prefix[csum]=i
124
Q
  1. Contiguous Array
    Medium

Given a binary array nums, return the maximum length of a contiguous subarray with an equal number of 0 and 1.

Example 1:

Input: nums = [0,1]
Output: 2
Explanation: [0, 1] is the longest contiguous subarray with an equal number of 0 and 1.

A
  1. Maintain a prefix_sum {0:0}
  2. Enumerate nums starting from 1 (enumerate(nums, 1))
  3. if num==0, sum-=1, else sum+=1
  4. if summ in prefix_sum, max_length = max(max_length, i-prefix_sum[summ])
  5. else prefix_sum[sum]=i
125
Q
  1. Minesweeper
    Medium

Let’s play the minesweeper game (Wikipedia, online game)!

You are given an m x n char matrix board representing the game board where:

‘M’ represents an unrevealed mine,
‘E’ represents an unrevealed empty square,
‘B’ represents a revealed blank square that has no adjacent mines (i.e., above, below, left, right, and all 4 diagonals),
digit (‘1’ to ‘8’) represents how many mines are adjacent to this revealed square, and
‘X’ represents a revealed mine.
You are also given an integer array click where click = [clickr, clickc] represents the next click position among all the unrevealed squares (‘M’ or ‘E’).

Return the board after revealing this position according to the following rules:

If a mine ‘M’ is revealed, then the game is over. You should change it to ‘X’.
If an empty square ‘E’ with no adjacent mines is revealed, then change it to a revealed blank ‘B’ and all of its adjacent unrevealed squares should be revealed recursively.
If an empty square ‘E’ with at least one adjacent mine is revealed, then change it to a digit (‘1’ to ‘8’) representing the number of adjacent mines.
Return the board when no more squares will be revealed.

A
  1. DFS on click
  2. within dfs, if board[r][c] in MX, board[r][c]=’X’ and return (this enables that click does not cover entire board and returns after it sees a mine)
  3. neis - all 4 + diagonal
  4. Traverse through all neis and keep track of the count by counting all the ‘X’ around. This needs to be the value on the grid
  5. if count>0, set the board value (str)
  6. else set board[nr][nc]=’B’ and call dfs for all ‘E’
126
Q
  1. Construct Binary Tree from String
    Medium

You need to construct a binary tree from a string consisting of parenthesis and integers.

The whole input represents a binary tree. It contains an integer followed by zero, one or two pairs of parenthesis. The integer represents the root’s value and a pair of parenthesis contains a child binary tree with the same structure.

You always start to construct the left child node of the parent first if it exists.

Example 1:

Input: s = “4(2(3)(1))(6(5))”
Output: [4,2,6,3,1,5]

A
  1. Use stack
  2. num=’’
  3. if c.isdigit() or c==’-‘: num+=c
  4. if c==’(‘:
    create a node and reset num. Add node to stack (only if num)
  5. if c==’)’:
    if num, then create node and check if stack[-1].left is None. If none append. If right is none, append
    if not num, then pop node from stack and append to left or right to the stack[-1]def str2tree(self, s: str) -> Optional[TreeNode]:
    stack=[]
    num=’’
     for c in s:
         if c.isdigit() or c=='-':
             num+=c
         elif c=='(':
             if num:
                 node=TreeNode(int(num))
                 stack.append(node)
                 num=''
         elif c==')':
             if num:
                 node=TreeNode(int(num))
                 num=''
                 if not stack[-1].left:
                     stack[-1].left=node
                 elif not stack[-1].right:
                     stack[-1].right=node
             else:
                 node=stack.pop()
                 if not stack[-1].left:
                     stack[-1].left=node
                 elif not stack[-1].right:
                     stack[-1].right=node
     return stack[-1] if stack else TreeNode(int(num)) if s else None

T: O(n)
S: O(n)

127
Q
  1. Boundary of Binary Tree
    Medium

The boundary of a binary tree is the concatenation of the root, the left boundary, the leaves ordered from left-to-right, and the reverse order of the right boundary.

The left boundary is the set of nodes defined by the following:

The root node’s left child is in the left boundary. If the root does not have a left child, then the left boundary is empty.
If a node in the left boundary and has a left child, then the left child is in the left boundary.
If a node is in the left boundary, has no left child, but has a right child, then the right child is in the left boundary.
The leftmost leaf is not in the left boundary.
The right boundary is similar to the left boundary, except it is the right side of the root’s right subtree. Again, the leaf is not part of the right boundary, and the right boundary is empty if the root does not have a right child.

The leaves are nodes that do not have any children. For this problem, the root is not a leaf.

Given the root of a binary tree, return the values of its boundary.

Example 1:

Input: root = [1,null,2,3,4]
Output: [1,3,4,2]
Explanation:
- The left boundary is empty because the root does not have a left child.
- The right boundary follows the path starting from the root’s right child 2 -> 4.
4 is a leaf, so the right boundary is [2].
- The leaves from left to right are [3,4].
Concatenating everything results in [1] + [] + [3,4] + [2] = [1,3,4,2].

A
  1. Need to return root + left + leaves + right
  2. left: node=root.left (this ensures that we always to to the left most node. But if there are right nodes, then we go there and then take the left most node in the right branch)
    while node
    left.append(node.val)
    if node.left:
    node=node.left
    else:
    node=node.right
  3. Same for right. But reverse the list since we need to go bottom up while listing
  4. Do DFS for leaves
    if not node:
    return
    if node!=root and not node.left and not node.right:
    leaves.append(node.val)
    dfs(node.left)
    dfs(node.right)
  5. dfs(node)
128
Q
  1. Next Greater Element III
    Medium

Given a positive integer n, find the smallest integer which has exactly the same digits existing in the integer n and is greater in value than n. If no such positive integer exists, return -1.

Note that the returned integer should fit in 32-bit integer, if there is a valid answer but it does not fit in 32-bit integer, return -1.

Example 1:

Input: n = 12
Output: 21
Example 2:

Input: n = 21
Output: -1

A
  1. Like next_permutation
  2. Iterate from the N-1 until the values are increasing. (while nums[target-1]>nums[target]: target-=1)
  3. if target==0, then return -1
  4. Set target=target-1
  5. source=N-1 and loop until you have a digit that is lesser than the source (while nums[source]<=nums[target]: source-=1)
  6. swap both the values
  7. left=target+1, right = len(nums)-1
  8. reverse the values
  9. if not -1<=result<=2**31-1: return -1

class Solution:
def nextGreaterElement(self, n: int) -> int:
nums=list(str(n))

    target=len(nums)-1
    while target>0 and nums[target-1]>=nums[target]:
        target-=1
    
    if target==0:
        return -1
    
    target-=1
    source=len(nums)-1
    
    while nums[source]<=nums[target]:
        source-=1
    
    nums[source], nums[target]=nums[target], nums[source]
    
    left=target+1
    right=len(nums)-1
    while left<=right:
        nums[left], nums[right]=nums[right], nums[left]
        left+=1
        right-=1
    
    ret=int(''.join(nums))
    if not 1<=ret<=2**31-1:
        return -1
    return ret

T: O(n)
S: O(n)

129
Q
  1. Subarray Sum Equals K
    Medium

Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k.

A subarray is a contiguous non-empty sequence of elements within an array.

Example 1:

Input: nums = [1,1,1], k = 2
Output: 2
Example 2:

Input: nums = [1,2,3], k = 3
Output: 2

A
  1. Keep prefix_sum=defaultdict, prefix_sum[0]=1
  2. if csum-k in prefix_sum, result+=prefix_sum[csum-k]
  3. Add prefix_sum[csum]+=1
130
Q

N/A

A
  1. Level order traversal
  2. When the level == depth, then create a left and right node whose left and right is the node.left and node.right
  3. Also, set node.left=new_left and node.right=new_right
  4. Finally add the node.left and node.right to the queue if they aren’t null.def addOneRow(self, root: Optional[TreeNode], val: int, depth: int) -> Optional[TreeNode]:
    clevel = 1
    if depth == 1:
    return TreeNode(val, root, None)
     queue = deque([root])
     while queue:
         clevel += 1
         level = len(queue)
    
         for _ in range(level):
             node = queue.popleft()
             if clevel == depth:
                 left = TreeNode(val)
                 left.left = node.left
                 node.left = left
    
                 right = TreeNode(val)
                 right.right = node.right
                 node.right = right
    
             if node.left:
                 queue.append(node.left)
             if node.right:
                 queue.append(node.right)
     return root

T:O(n)
S:O(n)

131
Q
  1. Exclusive Time of Functions
    Medium

On a single-threaded CPU, we execute a program containing n functions. Each function has a unique ID between 0 and n-1.

Function calls are stored in a call stack: when a function call starts, its ID is pushed onto the stack, and when a function call ends, its ID is popped off the stack. The function whose ID is at the top of the stack is the current function being executed. Each time a function starts or ends, we write a log with the ID, whether it started or ended, and the timestamp.

You are given a list logs, where logs[i] represents the ith log message formatted as a string “{function_id}:{“start” | “end”}:{timestamp}”. For example, “0:start:3” means a function call with function ID 0 started at the beginning of timestamp 3, and “1:end:2” means a function call with function ID 1 ended at the end of timestamp 2. Note that a function can be called multiple times, possibly recursively.

A function’s exclusive time is the sum of execution times for all function calls in the program. For example, if a function is called twice, one call executing for 2 time units and another call executing for 1 time unit, the exclusive time is 2 + 1 = 3.

Return the exclusive time of each function in an array, where the value at the ith index represents the exclusive time for the function with ID i.

Input: n = 2, logs = [“0:start:0”,”1:start:2”,”1:end:5”,”0:end:6”]
Output: [3,4]
Explanation:
Function 0 starts at the beginning of time 0, then it executes 2 for units of time and reaches the end of time 1.
Function 1 starts at the beginning of time 2, executes for 4 units of time, and ends at the end of time 5.
Function 0 resumes execution at the beginning of time 6 and executes for 1 unit of time.
So function 0 spends 2 + 1 = 3 units of total time executing, and function 1 spends 4 units of total time executing.

A
  1. Stack. Also maintain result=[0]*N
  2. If start, then add to stack.
  3. If end, pop from stack and update result[fn]+= diff (end_time-start_time +1 (remember the 1 because of 0 index))
  4. Also peep into the stack and update the result[prev_fn]-= diff
132
Q
  1. Palindromic Substrings
    Medium

Given a string s, return the number of palindromic substrings in it.

A string is a palindrome when it reads the same backward as forward.

A substring is a contiguous sequence of characters within the string.

Example 1:

Input: s = “abc”
Output: 3
Explanation: Three palindromic strings: “a”, “b”, “c”.
Example 2:

Input: s = “aaa”
Output: 6
Explanation: Six palindromic strings: “a”, “a”, “a”, “aa”, “aa”, “aaa”.

A
  1. Expand from center.
  2. Manacher’s algorithm can do O(n)def countSubstrings(self, s: str) -> int:
    result=0
     for i in range(len(s)):
         odd_count=self.expand(s, i, i)
         even_count=self.expand(s, i, i+1)
         result+=(odd_count+even_count)
     return result
    def expand(self, s, left, right):
    count=1
    while left>=0 and right
133
Q
  1. Find K Closest Elements
    Medium

Given a sorted integer array arr, two integers k and x, return the k closest integers to x in the array. The result should also be sorted in ascending order.

An integer a is closer to x than an integer b if:

|a - x| < |b - x|, or
|a - x| == |b - x| and a < b

Example 1:

Input: arr = [1,2,3,4,5], k = 4, x = 3
Output: [1,2,3,4]

A
  1. Binary search
  2. If xarr[mid+k]:
    left=mid+1
    else: #x is in array (not true always)
    ldist=abs(x-arr[mid])
    rdist=abs(x-arr[mid+k])
    if ldist
134
Q
  1. Maximum Swap
    Medium

You are given an integer num. You can swap two digits at most once to get the maximum valued number.

Return the maximum valued number you can get.

Example 1:

Input: num = 2736
Output: 7236
Explanation: Swap the number 2 and the number 7.

A
  1. Convert num to a list of strings
  2. Iterate through i to N-1 and check if there are s[i] int:
    s=list(str(num))
    N=len(s)
     for i in range(N-1):
         if s[i]=max_num:
             max_num=s[j]
             max_index=j
        
     for j in range(min_index, -1, -1):
         if s[j]
135
Q
  1. Valid Parenthesis String
    Medium

Given a string s containing only three types of characters: ‘(‘, ‘)’ and ‘*’, return true if s is valid.

The following rules define a valid string:

Any left parenthesis ‘(‘ must have a corresponding right parenthesis ‘)’.
Any right parenthesis ‘)’ must have a corresponding left parenthesis ‘(‘.
Left parenthesis ‘(‘ must go before the corresponding right parenthesis ‘)’.
‘*’ could be treated as a single right parenthesis ‘)’ or a single left parenthesis ‘(‘ or an empty string “”.

Example 1:

Input: s = “()”
Output: true
Example 2:

Input: s = “(*)”
Output: true

A
  1. Maintain a lmin and lmax
  2. If you meet a ‘(‘, then increment both. If you meet a ‘)’, decrement both
  3. If you meet a ‘*’, you could consider it as a left or right parens. So, decrement lmin and increment lmax
  4. If lmax<0, then exit. Since, even after factoring ‘*’ as left parens, the count is <0. So, it’s not a proper parenthesis string
  5. If lmin<0, reset to 0. Since the minimum parenthesis must be equal to 0
  6. Finally return lmin==0
136
Q
  1. Longest Univalue Path
    Medium

Given the root of a binary tree, return the length of the longest path, where each node in the path has the same value. This path may or may not pass through the root.

The length of the path between two nodes is represented by the number of edges between them.

Example 1:

Input: root = [5,4,5,1,1,null,5]
Output: 2
Explanation: The shown image shows that the longest path of the same value (i.e. 5).
Example 2:

Input: root = [1,4,5,4,4,null,5]
Output: 2
Explanation: The shown image shows that the longest path of the same value (i.e. 4).

A
  1. DFS
  2. if not node, return 0
  3. recurse for left and right and get the left_len and right_len
  4. left_len=(left_len+1) if node.left and node.left.val==node.val else 0
  5. right_len=(right_len+1) if node.right and node.right.val==node.val else 0
  6. update max_length = max (max_length, left_len+right_len)
  7. return max(left_len, right_len)def longestUnivaluePath(self, root: Optional[TreeNode]) -> int:
    if not root:
    return 0
    longest = 0
     def dfs(node):
         nonlocal longest
         if not node:
             return 0
         left_len = dfs(node.left)
         right_len = dfs(node.right)
         left_len = (left_len + 1) if node.left and node.left.val == node.val else 0
         right_len = (right_len + 1) if node.right and node.right.val == node.val else 0
         longest = max(longest, left_len + right_len)
         return max(left_len, right_len)
    
     dfs(root)
     return longest

T: O(n)
S: O(n)

137
Q
  1. Knight Probability in Chessboard
    Medium

On an n x n chessboard, a knight starts at the cell (row, column) and attempts to make exactly k moves. The rows and columns are 0-indexed, so the top-left cell is (0, 0), and the bottom-right cell is (n - 1, n - 1).

A chess knight has eight possible moves it can make, as illustrated below. Each move is two cells in a cardinal direction, then one cell in an orthogonal direction.

Each time the knight is to move, it chooses one of eight possible moves uniformly at random (even if the piece would go off the chessboard) and moves there.

The knight continues moving until it has made exactly k moves or has moved off the chessboard.

Return the probability that the knight remains on the board after it has stopped moving.

Example 1:

Input: n = 3, k = 2, row = 0, column = 0
Output: 0.06250
Explanation: There are two moves (to (1,2), (2,1)) that will keep the knight on the board.
From each of those positions, there are also two moves that will keep the knight on the board.
The total probability the knight stays on the board is 0.0625.
Example 2:

Input: n = 1, k = 0, row = 0, column = 0
Output: 1.00000

A
  1. DFS
  2. The return value from dfs is the probability which is p+=dfs(n,k-1, nr,nc)/8def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
     dirs=[(2,1), (2,-1), (-2,1), (-2,-1),
          (1,2), (1,-2), (-1,2), (-1,-2)]
        
     def dfs(N, k, r, c, memo):
         if k==0:
             return 1
         if (k,r,c) in memo:
             return memo[(k,r,c)]
         p=0
         for dr, dc in dirs:
             nr,nc=r+dr, c+dc
             if -1
138
Q
  1. Maximum Sum of 3 Non-Overlapping Subarrays
    Hard

Given an integer array nums and an integer k, find three non-overlapping subarrays of length k with maximum sum and return them.

Return the result as a list of indices representing the starting position of each interval (0-indexed). If there are multiple answers, return the lexicographically smallest one.

Example 1:

Input: nums = [1,2,1,2,6,7,5,1], k = 2
Output: [0,3,5]
Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.
Example 2:

Input: nums = [1,2,1,2,1,2,1,2,1], k = 2
Output: [0,2,4]

A
  1. Sliding window
  2. first_sum=sum(nums[:k]), second_sum= nums[k:2k]…
  3. Maintain max_first_sum, max_first_and_second_sum, max_total_sum
  4. Also maintain max_first_index, first_and_second_index, total_index
  5. Iterate from 1 to len(nums)-3*k+1
  6. In each iteration, first_sum+=nums[i+k-1]-nums[i-1]
  7. second_sum+=nums[i+2k-1]-nums[i+k-1]def maxSumOfThreeSubarrays(self, nums, k):
    first_sum = sum(nums[:k])
    second_sum = sum(nums[k:2 * k])
    third_sum = sum(nums[2 * k:3 * k])
     max_first_sum = first_sum
     max_first_second_sum = first_sum + second_sum
     max_total_sum = first_sum + second_sum + third_sum
    
     max_first_index = [0]
     max_first_second_index = [0, k]
     max_total_index = [0, k, 2 * k]
    
     for i in range(1, len(nums) - (3 * k) + 1):
         first_sum += nums[i + k - 1] - nums[i - 1]
         second_sum += nums[i + 2 * k - 1] - nums[i + k - 1]
         third_sum += nums[i + 3 * k - 1] - nums[i + 2 * k - 1]
    
         if first_sum > max_first_sum:
             max_first_sum = first_sum
             max_first_index = [i]
         if max_first_sum + second_sum > max_first_second_sum:
             max_first_second_sum = max_first_sum + second_sum
             max_first_second_index = max_first_index + [i + k]
         if max_first_second_sum + third_sum > max_total_sum:
             max_total_sum = max_first_second_sum + third_sum
             max_total_index = max_first_second_index + [i + 2 * k]
     return max_total_index
139
Q
  1. Stickers to Spell Word
    Hard

We are given n different types of stickers. Each sticker has a lowercase English word on it.

You would like to spell out the given string target by cutting individual letters from your collection of stickers and rearranging them. You can use each sticker more than once if you want, and you have infinite quantities of each sticker.

Return the minimum number of stickers that you need to spell out target. If the task is impossible, return -1.

Note: In all test cases, all words were chosen randomly from the 1000 most common US English words, and target was chosen as a concatenation of two random words.

Example 1:

Input: stickers = [“with”,”example”,”science”], target = “thehat”
Output: 3
Explanation:
We can use 2 “with” stickers, and 1 “example” sticker.
After cutting and rearrange the letters of those stickers, we can form the target “thehat”.
Also, this is the minimum number of stickers necessary to form the target string.

A
  1. Create a helper and return value from helper
  2. min_stickers(stickers, target, index) -> int
  3. if not target: return 0
  4. if index==len(stickers), return float(‘inf’)
  5. Skip target, pick target. Skip: result = recursive call, index+1
  6. Pick - new_target=target,
  7. for c in stickers[index], i=find(new_target, c).
  8. if i!=-1, new_target=new_target[:i]+new_target[i+1:]. Also touched=True
  9. if touched, result=min(result, self.min_stickers(stickers, new_target, index+1))
  10. return result
  11. Remember to return 0 if not target
  12. Remember to call self.dfs (with no increment to index) if the sticker is selected.

class Solution:
def minStickers(self, stickers: List[str], target: str) -> int:
result= self.bt(stickers, 0, target, {})
return result if result

140
Q
  1. Max Area of Island
    Medium

You are given an m x n binary matrix grid. An island is a group of 1’s (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.

The area of an island is the number of cells with a value 1 in the island.

Return the maximum area of an island in grid. If there is no island, return 0.

Example 1:

Input: grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
Output: 6
Explanation: The answer is not 11, because the island must be connected 4-directionally.

A
  1. Do a DFS for each ‘1’ and keep track of the area and max_area
  2. Within the dfs.
    if not -1
141
Q
  1. Subarray Product Less Than K
    Medium

Given an array of integers nums and an integer k, return the number of contiguous subarrays where the product of all the elements in the subarray is strictly less than k.

Example 1:

Input: nums = [10,5,2,6], k = 100
Output: 8
Explanation: The 8 subarrays that have product less than 100 are:
[10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

A
  1. Sliding window
  2. while ws<=we and cprod>=k:
    cprod/=nums[ws]
    ws+=1
    maxi=max(maxi, we-ws+1))
142
Q
  1. Accounts Merge
    Medium

Given a list of accounts where each element accounts[i] is a list of strings, where the first element accounts[i][0] is a name, and the rest of the elements are emails representing emails of the account.

Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some common email to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.

After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.

Example 1:

Input: accounts = [[“John”,”johnsmith@mail.com”,”john_newyork@mail.com”],[“John”,”johnsmith@mail.com”,”john00@mail.com”],[“Mary”,”mary@mail.com”],[“John”,”johnnybravo@mail.com”]]
Output: [[“John”,”john00@mail.com”,”john_newyork@mail.com”,”johnsmith@mail.com”],[“Mary”,”mary@mail.com”],[“John”,”johnnybravo@mail.com”]]
Explanation:
The first and second John’s are the same person as they have the common email “johnsmith@mail.com”.
The third John and Mary are different people as none of their email addresses are used by other accounts.
We could return these lists in any order, for example the answer [[‘Mary’, ‘mary@mail.com’], [‘John’, ‘johnnybravo@mail.com’],
[‘John’, ‘john00@mail.com’, ‘john_newyork@mail.com’, ‘johnsmith@mail.com’]] would still be accepted.

A
  1. Graph problem (undirected graph)
  2. Maintain a name dict as well to map name against email id
  3. Iterate through the emails in a list item and map all the candidates [email[i] to email[0]]
  4. Do a dfs on graph while keeping seen (undirected graph)
  5. While doing dfs, for each unseen item, keep an emails set to keep track of all the emails visited.
  6. Add result.append([name]+list(sorted(emails))
143
Q
  1. Minimum Window Subsequence
    Hard

Given strings s1 and s2, return the minimum contiguous substring part of s1, so that s2 is a subsequence of the part.

If there is no such window in s1 that covers all characters in s2, return the empty string “”. If there are multiple such minimum-length windows, return the one with the left-most starting index.

Example 1:

Input: s1 = “abcdebdde”, s2 = “bde”
Output: “bcde”
Explanation:
“bcde” is the answer because it occurs before “bdde” which has the same length.
“deb” is not a smaller window because the elements of s2 in the window must occur in order.
Example 2:

Input: s1 = “jmeqksfrsdcmsiwvaovztaqenprpvnbstl”, s2 = “u”
Output: “”

A
  1. Tough one - DFS
  2. Iterate through s1 and start calling dfs when you match s2[0]
  3. Once you find the first char match, do dfs with i and 1 (j), the start indexes of s1 and s2.
  4. the return from DFS is the max index of s1, which is j. if j-i str:
    min_length=float(‘inf’)
    min_string=””
     for i, c in enumerate(s1):
         if c==s2[0]:
             j=self.dfs(s1, s2, i, 1)
                
             if j-i
144
Q
  1. Asteroid Collision
    Medium

We are given an array asteroids of integers representing asteroids in a row.

For each asteroid, the absolute value represents its size, and the sign represents its direction (positive meaning right, negative meaning left). Each asteroid moves at the same speed.

Find out the state of the asteroids after all collisions. If two asteroids meet, the smaller one will explode. If both are the same size, both will explode. Two asteroids moving in the same direction will never meet.

Example 1:

Input: asteroids = [5,10,-5]
Output: [5,10]
Explanation: The 10 and -5 collide resulting in 10. The 5 and 10 never collide.
Example 2:

Input: asteroids = [8,-8]
Output: []
Explanation: The 8 and -8 collide exploding each other.

A
  1. Iterate through the asteroids.
  2. If positive asteroid, add to the stack (since only negative creates collisions)
  3. If negative,
    while stack and stack[-1]>0 and stack[-1]
145
Q
  1. Daily Temperatures
    Medium

Given an array of integers temperatures represents the daily temperatures, return an array answer such that answer[i] is the number of days you have to wait after the ith day to get a warmer temperature. If there is no future day for which this is possible, keep answer[i] == 0 instead.

Example 1:

Input: temperatures = [73,74,75,71,69,72,76,73]
Output: [1,1,4,2,1,1,0,0]
Example 2:

Input: temperatures = [30,40,50,60]
Output: [1,1,1,0]

A
  1. Monotonically increasing stack (nums[stack[-1]]
146
Q
  1. Convert Binary Search Tree to Sorted Doubly Linked List
    Medium

Convert a Binary Search Tree to a sorted Circular Doubly-Linked List in place.

You can think of the left and right pointers as synonymous to the predecessor and successor pointers in a doubly-linked list. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.

We want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. You should return the pointer to the smallest element of the linked list.

A
  1. In order traversal (while node or stack, if node, add to stack and left, if stack, materialize and right)
  2. During materialization, head.next=node, node.prev=head, head=head.next
  3. Finally, head.right=sent.right, sent.right.left=head
  4. return sent.right
147
Q
  1. Serialize and Deserialize N-ary Tree
    Hard

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a rooted tree in which each node has no more than N children. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that an N-ary tree can be serialized to a string and this string can be deserialized to the original tree structure.

For example, you may serialize the following 3-ary tree

as [1 [3[5 6] 2 4]]. Note that this is just an example, you do not necessarily need to follow this format.

Or you can follow LeetCode’s level order traversal serialization format, where each group of children is separated by the null value.

For example, the above tree may be serialized as [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14].

You do not necessarily need to follow the above-suggested formats, there are many more different formats that work so please be creative and come up with different approaches yourself.

Example 1:

Input: root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
Output: [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
Example 2:

Input: root = [1,null,3,2,4,null,5,6]
Output: [1,null,3,2,4,null,5,6]

A
  1. Both serialize and deserialize has helper functions.
  2. Serialize: preorder - append node.val to result. Iterate through child and recurse for each child. At the end of the iteration, append ‘#’
  3. Deserialize: pop top and create root. Call helper function with queue
  4. while queue[0]!=’#’:
    child=Node(queue.popleft())
    node.children.append(child)
    self.helper(child)
    queue.popleft() #pop off the #

class Codec:
def serialize(self, root: ‘Node’) -> str:
result=[]

    def preorder(node):
        if not node:
            return
        result.append(str(node.val))
        for child in node.children:
            preorder(child)
        result.append('#')
        
    preorder(root)
    return ' '.join(result)
    
    

def deserialize(self, data: str) -> 'Node':
    if not data:
        return None
    
    queue=deque(data.split())
    root=Node(int(queue.popleft()))
    
    def helper(node):
        if not node:
            return
        while queue[0]!='#':
            child=Node(int(queue.popleft()))
            node.children.append(child)
            helper(child)
        queue.popleft() #remove #
            
    helper(root)
    return root

T: O(n)
S: O(n)

148
Q
  1. Flatten a Multilevel Doubly Linked List
    Medium

You are given a doubly linked list, which contains nodes that have a next pointer, a previous pointer, and an additional child pointer. This child pointer may or may not point to a separate doubly linked list, also containing these special nodes. These child lists may have one or more children of their own, and so on, to produce a multilevel data structure as shown in the example below.

Given the head of the first level of the list, flatten the list so that all the nodes appear in a single-level, doubly linked list. Let curr be a node with a child list. The nodes in the child list should appear after curr and before curr.next in the flattened list.

Return the head of the flattened list. The nodes in the list must have all of their child pointers set to null.

Example 1:

Input: head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
Output: [1,2,3,7,8,11,12,9,10,4,5,6]
Explanation: The multilevel linked list in the input is shown.
After flattening the multilevel linked list it becomes:

A
  1. Use stack
  2. prev=None
  3. pop from stack and if prev, prev.next=node, node.prev=prev
  4. At the end prev=node
  5. if node.next: stack.append(node.next)
  6. if node.child: stack.append(node.child) but make the node.child=Nonedef flatten(self, head: ‘Optional[Node]’) -> ‘Optional[Node]’:
    if not head:
    return head
     stack=[head]
        
     prev=None
        
     while stack:
         node=stack.pop()
            
         if prev:
             prev.next=node
             node.prev=prev
                
         if node.next:
             stack.append(node.next)
         if node.child:
             stack.append(node.child)
             node.child=None
         prev=node
     return head

T: O(n)
S: O(n)

149
Q
  1. Reorganize String
    Medium

Given a string s, rearrange the characters of s so that any two adjacent characters are not the same.

Return any possible rearrangement of s or return “” if not possible.

Example 1:

Input: s = “aab”
Output: “aba”
Example 2:

Input: s = “aaab”
Output: “”

A
  1. Counter and add it to the max_heap
  2. Pop from the top and append to the result. We need to hold this popped from temp so that the next time we choose some other string
  3. Before adding the current kv to temp, pop from the previous temp and push it to the heap
  4. if updated_count>0, temp=[old_val, updated_count]
150
Q
  1. Basic Calculator III
    Hard

Implement a basic calculator to evaluate a simple expression string.

The expression string contains only non-negative integers, ‘+’, ‘-‘, ‘*’, ‘/’ operators, and open ‘(‘ and closing parentheses ‘)’. The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-231, 231 - 1].

Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().

Example 1:

Input: s = “1+1”
Output: 2
Example 2:

Input: s = “6-4/2”
Output: 4
Example 3:

Input: s = “2(5+52)/3+(6/2+8)”
Output: 21

A
  1. Particularly tough one.
  2. Regular for digits
  3. for opening brackets, add op to stack and reset op and num
  4. for c in opset or c==’):
    update(op, num, stack)
    op=c
    num=0
    if c==’)’:
    temp_sum=0
    while stack[-1] not in opset: tmp_sum+=stack.pop()
    update(temp_sum, stack.pop(), stack)def calculate(self, s: str) -> int:
    stack = []
    op = ‘+’
    num = 0
    opset = set(‘+-/*’)
     for c in s+'+':
         if c.isdigit():
             num = num*10 + int(c)
         elif c==')' or c in opset:
             self.update(num, op, stack)
             op=c
             num=0
             if c==')':
                 tmp_sum=0
                 while stack[-1] not in opset:
                     tmp_sum+=stack.pop()
                 self.update(tmp_sum, stack.pop(), stack)
         elif c=='(':
             stack.append(op)
             op='+'
             num=0
     return sum(stack)
    def update(self, num, op, stack):
    if op == ‘+’:
    stack.append(num)
    elif op == ‘-‘:
    stack.append(-num)
    elif op == ‘*’:
    stack.append(stack.pop() * num)
    elif op == ‘/’:
    stack.append(int(stack.pop() / num))

T: O(n)
S: O(n)

151
Q
  1. Custom Sort String
    Medium

You are given two strings order and s. All the characters of order are unique and were sorted in some custom order previously.

Permute the characters of s so that they match the order that order was sorted. More specifically, if a character x occurs before a character y in order, then x should occur before y in the permuted string.

Return any permutation of s that satisfies this property.

Example 1:

Input: order = “cba”, s = “abcd”

Output: “cbad”

Explanation: “a”, “b”, “c” appear in order, so the order of “a”, “b”, “c” should be “c”, “b”, and “a”.

Since “d” does not appear in order, it can be at any position in the returned string. “dcba”, “cdba”, “cbda” are also valid outputs.

A
  1. Do a counter on target string (s)
  2. Iterate through the order. If c (each) is in counter, then result+=c*counter[c]
  3. Delete from counter too.
  4. Iterate finally through the counter for lingering k,v and append to the end of the result
152
Q
  1. Insert into a Sorted Circular Linked List
    Medium

Given a Circular Linked List node, which is sorted in non-descending order, write a function to insert a value insertVal into the list such that it remains a sorted circular list. The given node can be a reference to any single node in the list and may not necessarily be the smallest value in the circular list.

If there are multiple suitable places for insertion, you may choose any place to insert the new value. After the insertion, the circular list should remain sorted.

If the list is empty (i.e., the given node is null), you should create a new single circular list and return the reference to that single node. Otherwise, you should return the originally given node.

A
  1. Create a inode in advance with the input value. If not head, just return inode.
  2. Three scenarios
  3. Middle scenario (easy): if node.val<=insert_val<=node.next.val, break
  4. Max and min scenarios: if node.next.val=node.val or insert_val<=node.next.val), break
  5. Single node scenario: if node.next==head, break
  6. nxt=node.next, node.next=inode, inode.next=nxt
153
Q
  1. Friends Of Appropriate Ages
    Medium

There are n persons on a social media website. You are given an integer array ages where ages[i] is the age of the ith person.

A Person x will not send a friend request to a person y (x != y) if any of the following conditions is true:

age[y] <= 0.5 * age[x] + 7
age[y] > age[x]
age[y] > 100 && age[x] < 100
Otherwise, x will send a friend request to y.

Note that if x sends a request to y, y will not necessarily send a request to x. Also, a person will not send a friend request to themself.

Return the total number of friend requests made.

Example 1:

Input: ages = [16,16]
Output: 2
Explanation: 2 people friend request each other.

A
  1. Binary search - sort the ages
  2. for each age, lb=(age//2+7)+1, ub = age
  3. li=bisect_left(ages, lb), ui=bisect_right(ages, ub)
  4. if ui-li<=0: continue
  5. result+=ui-li
  6. exclude current age: if lb<=age<=ub, then result-=1
154
Q
  1. Making A Large Island
    Hard

You are given an n x n binary matrix grid. You are allowed to change at most one 0 to be 1.

Return the size of the largest island in grid after applying this operation.

An island is a 4-directionally connected group of 1s.

Example 1:

Input: grid = [[1,0],[0,1]]
Output: 3
Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3.
Example 2:

Input: grid = [[1,1],[1,0]]
Output: 4
Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4.
Example 3:

Input: grid = [[1,1],[1,1]]
Output: 4
Explanation: Can’t change any 0 to 1, only one island with area = 4.

A
  1. DFS through all 1. Start with island id=2. Mark all islands
  2. Also keep track of the island sizes within the dfs (by passing the island_size dict)
  3. grid[r][c]=island_id
  4. Iterate through the grid and dfs for 0. Look around and fetch unique island_ids (set)
  5. Calculate max size based on island_size. Store the max in result.
155
Q
  1. Robot Room Cleaner
    Hard

You are controlling a robot that is located somewhere in a room. The room is modeled as an m x n binary grid where 0 represents a wall and 1 represents an empty slot.

The robot starts at an unknown location in the room that is guaranteed to be empty, and you do not have access to the grid, but you can move the robot using the given API Robot.

You are tasked to use the robot to clean the entire room (i.e., clean every empty cell in the room). The robot with the four given APIs can move forward, turn left, or turn right. Each turn is 90 degrees.

When the robot tries to move into a wall cell, its bumper sensor detects the obstacle, and it stays on the current cell.

Design an algorithm to clean the entire room using the following APIs:

interface Robot {
// returns true if next cell is open and robot moves into the cell.
// returns false if next cell is obstacle and robot stays on the current cell.
boolean move();

// Robot will stay on the same cell after calling turnLeft/turnRight.
// Each turn will be 90 degrees.
void turnLeft();
void turnRight();

// Clean the current cell.
void clean();
}
Note that the initial direction of the robot will be facing up. You can assume all four edges of the grid are all surrounded by a wall.

Custom testing:

The input is only given to initialize the room and the robot’s position internally. You must solve this problem “blindfolded”. In other words, you must control the robot using only the four mentioned APIs without knowing the room layout and the initial robot’s position.

A
  1. Create goback function with robot.right()*2 with robot.move in middle
  2. Prepare directions with clockwise rotation [(0,-1), (-1,0), (0,1), (1,0)]
  3. Call dfs with visited and r,c as 0,0. direction=0
  4. In the dfs, robot.clean() and add to visited
  5. Loop through range(4), the new_direction would be (direction+i)%4
  6. nr,nc = r+dirs[new_direction][0] and [1] for r and c
  7. If nr,nc not in visited and robot.move(), recurse and goback
  8. outside the if condition, robot.turnRight

class Solution:
def cleanRoom(self, robot):
dirs=[(0,-1), (-1,0), (0,1), (1,0)]
visited=set()
self.dfs(robot, 0, 0, dirs, visited, 0)

def dfs(self, robot, r, c, dirs, visited, direction):
    visited.add((r,c))
    robot.clean()
    
    for i in range(4):
        new_direction=(direction+i)%4
        nr=r+dirs[new_direction][0]
        nc=c+dirs[new_direction][1] 
        
        if (nr,nc) not in visited and robot.move():
            self.dfs(robot, nr, nc, dirs, visited, new_direction)
            self.go_back(robot)
        robot.turnRight()
    
    
def go_back(self, robot):
    robot.turnRight()
    robot.turnRight()
    robot.move()
    robot.turnRight()
    robot.turnRight()

T: O(n)
S: O(1)

156
Q
  1. Minimum Cost to Hire K Workers
    Hard

There are n workers. You are given two integer arrays quality and wage where quality[i] is the quality of the ith worker and wage[i] is the minimum wage expectation for the ith worker.

We want to hire exactly k workers to form a paid group. To hire a group of k workers, we must pay them according to the following rules:

Every worker in the paid group must be paid at least their minimum wage expectation.
In the group, each worker’s pay must be directly proportional to their quality. This means if a worker’s quality is double that of another worker in the group, then they must be paid twice as much as the other worker.
Given the integer k, return the least amount of money needed to form a paid group satisfying the above conditions. Answers within 10-5 of the actual answer will be accepted.

Example 1:

Input: quality = [10,20,5], wage = [70,50,30], k = 2
Output: 105.00000
Explanation: We pay 70 to 0th worker and 35 to 2nd worker.
Example 2:

Input: quality = [3,1,10,10,1], wage = [4,8,2,2,7], k = 3
Output: 30.66667
Explanation: We pay 4 to 0th worker, 13.33333 to 2nd and 3rd workers separately.

A

def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float:
result=float(‘inf’)

    rates=sorted([(w/q, q) for q,w in zip(quality,wage)])
    
    total_quality=0
    pq=[]
    
    for rate, q in rates:
        heapq.heappush(pq, -q)
        total_quality+=q
        
        if len(pq)>k:
            qq=heapq.heappop(pq)
            total_quality-=-qq
        
        if len(pq)==k:
            result=min(result, total_quality*rate)
        
    return result
157
Q
  1. All Nodes Distance K in Binary Tree
    Medium

Given the root of a binary tree, the value of a target node target, and an integer k, return an array of the values of all nodes that have a distance k from the target node.

You can return the answer in any order.

A
  1. Convert tree to undirected graph using BFS.
  2. BFS: Do a BFS on target (target, dist=0), If dist==k: add to result.
  3. If dist==k, add to result. And set touched=True.
  4. If touched, continue (not break), since we need to look at all the other items in the queue
  5. Else, For all other neighbours of the graph, add to queue (provided not seen)

T: O(n)
S: O(n)

158
Q
  1. Smallest Subtree with all the Deepest Nodes
    Medium

Given the root of a binary tree, the depth of each node is the shortest distance to the root.

Return the smallest subtree such that it contains all the deepest nodes in the original tree.

A node is called the deepest if it has the largest depth possible among any node in the entire tree.

The subtree of a node is a tree consisting of that node, plus the set of all descendants of that node.

A
  1. DFS with helper - helper has level
  2. if not node: return (node, level)
  3. left, ldist = self.dfs(node.left, level+1)
  4. right, rdist=self.dfs(node.right, level+1)
  5. if ldist>rdist:
    return left, ldist
    elif rdist>ldist:
    return right, rdist
    else:
    node, ldist
159
Q
  1. Koko Eating Bananas
    Medium

Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours.

Koko can decide her bananas-per-hour eating speed of k. Each hour, she chooses some pile of bananas and eats k bananas from that pile. If the pile has less than k bananas, she eats all of them instead and will not eat any more bananas during this hour.

Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.

Return the minimum integer k such that she can eat all the bananas within h hours.

A
  1. Binary search between 1 and max(piles)
  2. for pile in piles:
    hours+=math.ceil(pile//mid)
  3. if hours<=h: #we are eating faster than required.
    right=mid-1
    else:
    left=mid+1

The reason why we are doing right=mid-1 even when the hours <=h is that, we wanted to increase the number of hours. And the way to increase the number of hours is to reduce the size of the mid (pile being constant). In order to decrease the size of the mid, we do right=mid-1

160
Q
  1. Random Pick with Weight
    Medium

You are given a 0-indexed array of positive integers w where w[i] describes the weight of the ith index.

You need to implement the function pickIndex(), which randomly picks an index in the range [0, w.length - 1] (inclusive) and returns it. The probability of picking an index i is w[i] / sum(w).

For example, if w = [1, 3], the probability of picking index 0 is 1 / (1 + 3) = 0.25 (i.e., 25%), and the probability of picking index 1 is 3 / (1 + 3) = 0.75 (i.e., 75%).

Example 1:

Input
[“Solution”,”pickIndex”]
[[[1]],[]]
Output
[null,0]

Explanation
Solution solution = new Solution([1]);
solution.pickIndex(); // return 0. The only option is to return 0 since there is only one element in w.

A
  1. Calculate prefix sum array and store. Also keep total
  2. Generate a random number between 0 and total (random.random()*self.total)
  3. Binary search on the array and return the value
161
Q
  1. Fruit Into Baskets
    Medium

You are visiting a farm that has a single row of fruit trees arranged from left to right. The trees are represented by an integer array fruits where fruits[i] is the type of fruit the ith tree produces.

You want to collect as much fruit as possible. However, the owner has some strict rules that you must follow:

You only have two baskets, and each basket can only hold a single type of fruit. There is no limit on the amount of fruit each basket can hold.
Starting from any tree of your choice, you must pick exactly one fruit from every tree (including the start tree) while moving to the right. The picked fruits must fit in one of your baskets.
Once you reach a tree with fruit that cannot fit in your baskets, you must stop.
Given the integer array fruits, return the maximum number of fruits you can pick.

Example 1:

Input: fruits = [1,2,1]
Output: 3
Explanation: We can pick from all 3 trees.
Example 2:

Input: fruits = [0,1,2,2]
Output: 3
Explanation: We can pick from trees [1,2,2].
If we had started at the first tree, we would only pick from trees [0,1].
Example 3:

Input: fruits = [1,2,3,2,2]
Output: 4
Explanation: We can pick from trees [2,3,2,2].
If we had started at the first tree, we would only pick from trees [1,2].

A
  1. Sliding window with window being 2 (while len(mapp)>2)

class Solution:
def totalFruit(self, fruits: List[int]) -> int:
ws = 0
max_fruits = 0
mapp = defaultdict(int)

    for we, fwe in enumerate(fruits):
        mapp[fwe] += 1
        while len(mapp) > 2:
            fws = fruits[ws]
            mapp[fws] -= 1
            if mapp[fws] == 0:
                del mapp[fws]
            ws += 1
        max_fruits = max(max_fruits, we - ws + 1)
    return max_fruits

T: O(n)
S: O(n)

162
Q
  1. Complete Binary Tree Inserter
    Medium

A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.

Design an algorithm to insert a new node to a complete binary tree keeping it complete after the insertion.

Implement the CBTInserter class:

CBTInserter(TreeNode root) Initializes the data structure with the root of the complete binary tree.
int insert(int v) Inserts a TreeNode into the tree with value Node.val == val so that the tree remains complete, and returns the value of the parent of the inserted TreeNode.
TreeNode get_root() Returns the root node of the tree.

Example 1:

Input
[“CBTInserter”, “insert”, “insert”, “get_root”]
[[[1, 2]], [3], [4], []]
Output
[null, 1, 2, [1, 2, 3, 4]]

Explanation
CBTInserter cBTInserter = new CBTInserter([1, 2]);
cBTInserter.insert(3); // return 1
cBTInserter.insert(4); // return 2
cBTInserter.get_root(); // return [1, 2, 3, 4]

A
  1. Do a level order traversal and construct a list from a tree, tree=[None]
  2. Return tree[1] for get_tree
  3. For insertion, get the size of the tree before inserting the incoming node
  4. parent=self.tree[N//2]
  5. if N&1, insert to right. Else insert to left

class CBTInserter:

def \_\_init\_\_(self, root: Optional[TreeNode]):
    self.tree=[None]
    self.level_order(root)

def insert(self, val: int) -> int:
    node=TreeNode(val)
    N=len(self.tree)
    self.tree.append(node)
    parent=self.tree[N//2]
    if N&1:
        parent.right=node
    else:
        parent.left=node
    
    return parent.val
    

def get_root(self) -> Optional[TreeNode]:
    return self.tree[1]

def level_order(self, root):
    queue=deque([root])
    
    while queue:
        node=queue.popleft()
        self.tree.append(node)
        if node.left:
            queue.append(node.left)
        if node.right:
            queue.append(node.right)

T: O(1)
S: O(n)

163
Q
  1. Minimum Add to Make Parentheses Valid
    Medium

A parentheses string is valid if and only if:

It is the empty string,
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.
You are given a parentheses string s. In one move, you can insert a parenthesis at any position of the string.

For example, if s = “()))”, you can insert an opening parenthesis to be “(()))” or a closing parenthesis to be “())))”.
Return the minimum number of moves required to make s valid.

Example 1:

Input: s = “())”
Output: 1

A
  1. No need for stack. Two variables can do it.
  2. If ‘(‘, left+=1
  3. if ‘)’ and left>0, left-=1
  4. else, right+=1
  5. return left+right
164
Q
  1. Shortest Bridge
    Medium

You are given an n x n binary matrix grid where 1 represents land and 0 represents water.

An island is a 4-directionally connected group of 1’s not connected to any other 1’s. There are exactly two islands in grid.

You may change 0’s to 1’s to connect the two islands to form one island.

Return the smallest number of 0’s you must flip to connect the two islands.

Example 1:

Input: grid = [[0,1],[1,0]]
Output: 1
Example 2:

Input: grid = [[0,1,0],[0,0,0],[0,0,1]]
Output: 2
Example 3:

Input: grid = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
Output: 1

A
  1. DFS to find all the r,c that constitute one bridge. Exit after finding 1
  2. BFS from all the starting points until we find the next island. return dist-1def shortestBridge(self, grid: List[List[int]]) -> int:
    R = len(grid)
    C = len(grid[0])
    isle_one = []
    found = False
    for r in range(R):
    if not found:
    for c in range(C):
    if grid[r][c] == 1:
    self.dfs(r, c, R, C, isle_one, grid)
    found = True
    break
    return self.bfs(isle_one, grid, R, C)def dfs(self, r, c, R, C, isle_one, grid):
    isle_one.append((r, c, 0))
    grid[r][c] = 0
    neis = [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]
    for nr, nc in neis:
    if -1 < nr < R and -1 < nc < C and grid[nr][nc] == 1:
    self.dfs(nr, nc, R, C, isle_one, grid)def bfs(self, isle_one, grid, R, C):
    queue = deque(isle_one)
    seen = set()
    while queue:
    r, c, dist = queue.popleft()
    seen.add((r, c))
    if grid[r][c] == 1:
    return dist - 1
         neis = [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]
         for nr, nc in neis:
             if -1 < nr < R and -1 < nc < C and (nr, nc) not in seen:
                 queue.append((nr, nc, dist + 1))
                 seen.add((nr, nc))
     return -1

T: O(MN)
S: O(M
N)

165
Q
  1. Check Completeness of a Binary Tree
    Medium

Given the root of a binary tree, determine if it is a complete binary tree.

In a complete binary tree, every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

Example 1:

Input: root = [1,2,3,4,5,6]
Output: true
Explanation: Every level before the last is full (ie. levels with node-values {1} and {2, 3}), and all nodes in the last level ({4, 5, 6}) are as far left as possible.

A
  1. BFS and maintain a is_null boolean
  2. If we meet an empty node, set the is_null to be true
  3. If we meet a node, check if the previous nodes has been null, If yes, return False
  4. Add node.left and node.rightdef isCompleteTree(self, root: Optional[TreeNode]) -> bool:
    queue=deque([root])
     is_null=False
     while queue:
         node=queue.popleft()
         if not node:
             is_null=True
         else:
             if is_null: #some node is not empty in this level
                 return False
    
             queue.append(node.left)
             queue.append(node.right)
     return True
166
Q
  1. K Closest Points to Origin
    Medium

Given an array of points where points[i] = [xi, yi] represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0).

The distance between two points on the X-Y plane is the Euclidean distance (i.e., √(x1 - x2)2 + (y1 - y2)2).

You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).

A
  1. Closest. So, max heap
  2. Add to heap, -(x2+y2), x,y
  3. If len(pq)>k: heappop()
  4. While pq, append (x,y) to result and return
167
Q
  1. Interval List Intersections
    Medium

You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [starti, endi] and secondList[j] = [startj, endj]. Each list of intervals is pairwise disjoint and in sorted order.

Return the intersection of these two interval lists.

A closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b.

The intersection of two closed intervals is a set of real numbers that are either empty or represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].

A
  1. fi=0, si=0, Iterate through firstList and secondList (fi List[List[int]]:
     fi=0
     si=0
        
     M=len(firstList)
     N=len(secondList)
        
     result=[]
        
     while fi
168
Q
  1. Vertical Order Traversal of a Binary Tree
    Hard

Given the root of a binary tree, calculate the vertical order traversal of the binary tree.

For each node at position (row, col), its left and right children will be at positions (row + 1, col - 1) and (row + 1, col + 1) respectively. The root of the tree is at (0, 0).

The vertical order traversal of a binary tree is a list of top-to-bottom orderings for each column index starting from the leftmost column and ending on the rightmost column. There may be multiple nodes in the same row and same column. In such a case, sort these nodes by their values.

Return the vertical order traversal of the binary tree.

A
  1. Level order traversal. Keep track of (node, vorder). Also max_left and max_right
  2. To the result dictionary, add sorted(level_list)
169
Q
  1. Max Consecutive Ones III

Given a binary array nums and an integer k, return the maximum number of consecutive 1’s in the array if you can flip at most k 0’s.

Example 1:

Input: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
Output: 6
Explanation: [1,1,1,0,0,1,1,1,1,1,1]
Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.

A
  1. Sliding window
  2. If you meet a ‘0’, reduce k
  3. while k<0: move ws
  4. At the end of the loop, we-ws+1
170
Q
  1. Capacity To Ship Packages Within D Days
    Medium

A conveyor belt has packages that must be shipped from one port to another within days days.

The ith package on the conveyor belt has a weight of weights[i]. Each day, we load the ship with packages on the conveyor belt (in the order given by weights). We may not load more weight than the maximum weight capacity of the ship.

Return the least weight capacity of the ship that will result in all the packages on the conveyor belt being shipped within days days.

Example 1:

Input: weights = [1,2,3,4,5,6,7,8,9,10], days = 5
Output: 15
Explanation: A ship capacity of 15 is the minimum to ship all the packages in 5 days like this:
1st day: 1, 2, 3, 4, 5
2nd day: 6, 7
3rd day: 8
4th day: 9
5th day: 10

Note that the cargo must be shipped in the order given, so using a ship of capacity 14 and splitting the packages into parts like (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) is not allowed.
Example 2:

Input: weights = [3,2,2,4,1,4], days = 3
Output: 6
Explanation: A ship capacity of 6 is the minimum to ship all the packages in 3 days like this:
1st day: 3, 2
2nd day: 2, 4
3rd day: 1, 4
Example 3:

Input: weights = [1,2,3,1,1], days = 4
Output: 3
Explanation:
1st day: 1
2nd day: 2
3rd day: 3
4th day: 1, 1

A
  1. Binary search with low=max(weights) and high=sum(weights)
  2. Similar to koko eating bananas
  3. Even if the days are found, we’ll have to try and go for the least weight capacity of the ship - which means that the high=mid-1 (because high = sum(weights), meaning all the weights is being carried by one ship).def shipWithinDays(self, weights: List[int], days: int) -> int:
    low=max(weights)
    high=sum(weights)
     while low<=high:
         mid=(low+high)//2
            
         total=0
         pdays=1
         for weight in weights:
             if total+weight>mid:
                 total=weight
                 pdays+=1
             else:
                 total+=weight
            
         if pdays<=days:
             high=mid-1
         else:
             low=mid+1
     return low

T:O(nlogN) - Since within binary search we are traversing through the weights again.
S: O(1)

171
Q
  1. Missing Element in Sorted Array
    Medium

Given an integer array nums which is sorted in ascending order and all of its elements are unique and given also an integer k, return the kth missing number starting from the leftmost number of the array.

Example 1:

Input: nums = [4,7,9,10], k = 1
Output: 5
Explanation: The first missing number is 5.
Example 2:

Input: nums = [4,7,9,10], k = 3
Output: 8
Explanation: The missing numbers are [5,6,8,…], hence the third missing number is 8.
Example 3:

Input: nums = [1,2,4], k = 3
Output: 6
Explanation: The missing numbers are [3,5,6,7,…], hence the third missing number is 6.

A
  1. Linear and binary search solution.
  2. In the linear solution, iterate from 1, N-1
  3. gap = nums[i]-nums[i-1]
  4. if gap int:
     for i in range(1, len(nums)):
         gap=nums[i]-nums[i-1] -1
            
         if gap int:
     N=len(nums)
     if k>self.get_missing_num_counts(nums, N-1):
         return nums[N-1] +k - self.get_missing_num_counts(nums, N-1) 
        
     left=0
     right=N-1
     while left<=right:
         mid=(left+right)//2
         mid_counts=self.get_missing_num_counts(nums, mid)
         if mid_counts
172
Q
  1. Recover a Tree From Preorder Traversal
    Hard

We run a preorder depth-first search (DFS) on the root of a binary tree.

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. If the depth of a node is D, the depth of its immediate child is D + 1. The depth of the root node is 0.

If a node has only one child, that child is guaranteed to be the left child.

Given the output traversal of this traversal, recover the tree and return its root.

Example 1:

Input: traversal = “1-2–3–4-5–6–7”
Output: [1,2,5,3,4,6,7]
Example 2:

Input: traversal = “1-2–3—4-5–6—7”
Output: [1,2,5,3,null,6,null,4,null,7]

A
  1. Hard and tricky
  2. loop for ‘-‘ first and get the level
  3. loop for !=’-‘ to get the value
  4. create a new node with value
  5. if len(stack)>level, pop from stack
  6. if stack and stack[-1].left is not populated, then set the node to the left
  7. else if stack: set node to the right
  8. Finally add the node to the stack.def recoverFromPreorder(self, s: str) -> Optional[TreeNode]:
    i=0
    N=len(s)
    stack=[]
     while ilevel:
             stack.pop()
            
         if stack and not stack[-1].left:
             stack[-1].left=node
         elif stack:
             stack[-1].right=node
            
         stack.append(node)
     return stack[0]

T: O(s)
S: O(s)

173
Q
  1. Partition Array for Maximum Sum
    Medium

Given an integer array arr, partition the array into (contiguous) subarrays of length at most k. After partitioning, each subarray has their values changed to become the maximum value of that subarray.

Return the largest sum of the given array after partitioning. Test cases are generated so that the answer fits in a 32-bit integer.

Example 1:

Input: arr = [1,15,7,9,2,5,10], k = 3
Output: 84
Explanation: arr becomes [15,15,15,9,10,10,10]
Example 2:

Input: arr = [1,4,1,5,7,3,6,1,9,9,3], k = 4
Output: 83
Example 3:

Input: arr = [1], k = 1
Output: 1

A
  1. Backtracking with helper (i=0)
  2. Within the helper, if i>=len(arr): return 0
  3. Iterate j through (i, min(i+k, len(nums)-1)):
    curr_max=max(curr_max, nums[i])
    window=j-i+1
    result=max(result, self.helper(nums, k, j+1) + curr_max*window)

class Solution:
def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int:
return self.max_sum_after_partitioning(arr, k, 0, {})

def max_sum_after_partitioning(self, arr, k, i, memo):
    if i in memo:
        return memo[i]
    if i>=len(arr):
        return 0
    
    result=0
    curr_max=0
    
    for j in range(i, min(i+k, len(arr))):
        curr_max=max(curr_max, arr[j])
        window=j-i+1
        result=max(result, self.max_sum_after_partitioning(arr, k, j+1, memo) + curr_max*window)
    
    memo[i]=result
    return result

T:O(n*k) - since the helper loop has a max of k range
S: O(n)

174
Q
  1. Minimum Knight Moves
    Medium

In an infinite chess board with coordinates from -infinity to +infinity, you have a knight at square [0, 0].

A knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.

Return the minimum number of steps needed to move the knight to the square [x, y]. It is guaranteed the answer exists.

Example 1:

Input: x = 2, y = 1
Output: 1
Explanation: [0, 0] → [2, 1]
Example 2:

Input: x = 5, y = 5
Output: 4
Explanation: [0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5]

A
  1. BFS with chess directions.def minKnightMoves(self, x: int, y: int) -> int:
    dirs = [(2, 1), (-2, 1), (2, -1), (-2, -1),
    (1, 2), (-1, 2), (1, -2), (-1, -2)]
     queue = deque([(0, 0, 0)])
     visited = set()
     while queue:
         r, c, dist = queue.popleft()
         visited.add((r, c))
         if (r, c) == (x, y):
             return dist
         for dr, dc in dirs:
             nr, nc = r + dr, c + dc
             if (nr, nc) not in visited:
                 visited.add((nr, nc))
                 queue.append((nr, nc, dist + 1))
     return -1

T: O(max(x,y)2))
S: O(max(x,y)
2))

175
Q
  1. Product Sales Analysis III
    Medium

SQL Schema
Table: Sales

+————-+——-+
| Column Name | Type |
+————-+——-+
| sale_id | int |
| product_id | int |
| year | int |
| quantity | int |
| price | int |
+————-+——-+
(sale_id, year) is the primary key (combination of columns with unique values) of this table.
product_id is a foreign key (reference column) to Product table.
Each row of this table shows a sale on the product product_id in a certain year.
Note that the price is per unit.

Table: Product

+————–+———+
| Column Name | Type |
+————–+———+
| product_id | int |
| product_name | varchar |
+————–+———+
product_id is the primary key (column with unique values) of this table.
Each row of this table indicates the product name of each product.

A

with product_first_year_cte as (
select
product_id,
year,
quantity,
price,
rank() over (partition by product_id order by year) as rnum
from
Sales s
)

select
product_id,
year as first_year,
quantity,
price
from
product_first_year_cte
where
rnum=1

176
Q
  1. Shortest Path in Binary Matrix
    Medium

Given an n x n binary matrix grid, return the length of the shortest clear path in the matrix. If there is no clear path, return -1.

A clear path in a binary matrix is a path from the top-left cell (i.e., (0, 0)) to the bottom-right cell (i.e., (n - 1, n - 1)) such that:

All the visited cells of the path are 0.
All the adjacent cells of the path are 8-directionally connected (i.e., they are different and they share an edge or a corner).
The length of a clear path is the number of visited cells of this path.

A
  1. BFS. Nothing fancy. Just keep track of the distance
  2. Also keep “seen”
177
Q
  1. Valid Palindrome III
    Hard

Given a string s and an integer k, return true if s is a k-palindrome.

A string is k-palindrome if it can be transformed into a palindrome by removing at most k characters from it.

Example 1:

Input: s = “abcdeca”, k = 2
Output: true
Explanation: Remove ‘b’ and ‘e’ characters.

A
  1. DP, call helper with left and right (0, N-1)
  2. Inside helper - if l==r or l+1==r: return True
  3. if k==0: return False (all k is elapsed)
  4. Pick/skip
  5. Pick: if s[left]==s[right], return self.helper(s,k, left+1, right-1) (no change in k)
  6. Skip: skip_left or skip_right
  7. skip_left = self.helper(s, k+1, left+1, right)
  8. skip_right = self.helper(s, k+1, left, right-1)
  9. return skip_left or skip_right
178
Q
  1. Sum of Nodes with Even-Valued Grandparent
    Medium

Given the root of a binary tree, return the sum of values of nodes with an even-valued grandparent. If there are no nodes with an even-valued grandparent, return 0.

A grandparent of a node is the parent of its parent if it exists.

Example 1:

Input: root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
Output: 18
Explanation: The red nodes are the nodes with even-value grandparent while the blue nodes are the even-value grandparents.
Example 2:

Input: root = [1]
Output: 0

A
  1. Both DFS and BFS can work.
  2. For DFS, use helper with root, parent, gp (root, -1, -1)
  3. if gp%2==0 result +=node.val
  4. result+= dfs(node.left, node.val, parent) and for right
  5. For BFS, start with root and -1 to the queue
  6. If parent%2==0:
    if node.left, then add to result
    if node.right then add to result
  7. if node.left: add to queue
  8. if node.right: add to queuedef sumEvenGrandparent(self, node: TreeNode) -> int:
    return self.dfs(node, -1, -1)def dfs(self, node, parent, gp):
    if not node:
    return 0
    x = 0
    if gp % 2 == 0:
    x += node.val
    x += self.dfs(node.left, node.val, parent)
    x += self.dfs(node.right, node.val, parent)
    return xdef sumEvenGrandparent(self, node: TreeNode) -> int:
    queue = deque([(node, -1)])
    result = 0
     while queue:
         node, parent = queue.popleft()
         if parent % 2 == 0:
             if node.left:
                 result += node.left.val
             if node.right:
                 result += node.right.val
    
         if node.left:
             queue.append((node.left, node.val))
         if node.right:
             queue.append((node.right, node.val))
     return result

T: O(n)
S: O(n)

179
Q
  1. Longest Common Subsequence
    Medium

Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0.

A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.

For example, “ace” is a subsequence of “abcde”.
A common subsequence of two strings is a subsequence that is common to both strings.

Example 1:

Input: text1 = “abcde”, text2 = “ace”
Output: 3
Explanation: The longest common subsequence is “ace” and its length is 3.
Example 2:

Input: text1 = “abc”, text2 = “abc”
Output: 3
Explanation: The longest common subsequence is “abc” and its length is 3.

A
  1. pick_left, pick_right and pick_both
  2. use memodef longestCommonSubsequence(self, text1: str, text2: str) -> int:
    return self.longest_common_subsequence(text1, text2, 0, 0)def longest_common_subsequence(self, text1, text2, i, j):
    if i == len(text1) or j == len(text2):
    return 0
    if text1[i] == text2[j]:
    return 1 + self.longest_common_subsequence(text1, text2, i + 1, j + 1)
    else:
    move_first = self.longest_common_subsequence(text1, text2, i + 1, j)
    move_second = self.longest_common_subsequence(text1, text2, i, j + 1)
    return max(move_first, move_second)
180
Q
  1. Number of Visible People in a Queue
    Hard

There are n people standing in a queue, and they numbered from 0 to n - 1 in left to right order. You are given an array heights of distinct integers where heights[i] represents the height of the ith person.

A person can see another person to their right in the queue if everybody in between is shorter than both of them. More formally, the ith person can see the jth person if i < j and min(heights[i], heights[j]) > max(heights[i+1], heights[i+2], …, heights[j-1]).

Return an array answer of length n where answer[i] is the number of people the ith person can see to their right in the queue.

Example 1:

Input: heights = [10,6,8,5,11,9]
Output: [3,1,2,1,1,0]
Explanation:
Person 0 can see person 1, 2, and 4.
Person 1 can see person 2.
Person 2 can see person 3 and 4.
Person 3 can see person 4.
Person 4 can see person 5.
Person 5 can see no one since nobody is to the right of them.

A
  1. Decreasing mono stack
  2. while nums[stack[-1]] List[int]:
    stack=[]
    result=[0]*len(heights)
    for i, h in enumerate(heights):
    while stack and heights[stack[-1]]
181
Q
  1. Remove All Adjacent Duplicates in String II
    Medium

You are given a string s and an integer k, a k duplicate removal consists of choosing k adjacent and equal letters from s and removing them, causing the left and the right side of the deleted substring to concatenate together.

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. It is guaranteed that the answer is unique.

Example 1:

Input: s = “abcd”, k = 2
Output: “abcd”
Explanation: There’s nothing to delete.
Example 2:

Input: s = “deeedbbcccbdaa”, k = 3
Output: “aa”
Explanation:
First delete “eee” and “ccc”, get “ddbbbdaa”
Then delete “bbb”, get “dddaa”
Finally delete “ddd”, get “aa”
Example 3:

Input: s = “pbbcggttciiippooaais”, k = 2
Output: “ps”

A
  1. Use stack
  2. If not stack or stack[-1][0]!=c, then append to stack
  3. Else, increment to stack count stack[-1][1]. If stack[-1][1]==k: stack.pop()def removeDuplicates(self, s: str, k: int) -> str:
    stack=[]
     for c in s:
         if not stack or stack[-1][0]!=c:
             stack.append([c,1])
         else:
             if stack[-1][0]==c:
                 stack[-1][1]+=1
                 if stack[-1][1]==k:
                     stack.pop()
                
     return ''.join([k*cnt for k,cnt in stack])

T: O(n)
S: O(n)

182
Q
  1. Design Skiplist
    Hard

Design a Skiplist without using any built-in libraries.

A skiplist is a data structure that takes O(log(n)) time to add, erase and search. Comparing with treap and red-black tree which has the same function and performance, the code length of Skiplist can be comparatively short and the idea behind Skiplists is just simple linked lists.

For example, we have a Skiplist containing [30,40,50,60,70,90] and we want to add 80 and 45 into it. The Skiplist works this way:

Artyom Kalinin [CC BY-SA 3.0], via Wikimedia Commons

You can see there are many layers in the Skiplist. Each layer is a sorted linked list. With the help of the top layers, add, erase and search can be faster than O(n). It can be proven that the average time complexity for each operation is O(log(n)) and space complexity is O(n).

See more about Skiplist: https://en.wikipedia.org/wiki/Skip_list

Implement the Skiplist class:

Skiplist() Initializes the object of the skiplist.
bool search(int target) Returns true if the integer target exists in the Skiplist or false otherwise.
void add(int num) Inserts the value num into the SkipList.
bool erase(int num) Removes the value num from the Skiplist and returns true. If num does not exist in the Skiplist, do nothing and return false. If there exist multiple num values, removing any one of them is fine.
Note that duplicates may exist in the Skiplist, your code needs to handle this situation.

Example 1:

Input
[“Skiplist”, “add”, “add”, “add”, “search”, “add”, “search”, “erase”, “erase”, “search”]
[[], [1], [2], [3], [0], [4], [1], [0], [1], [1]]
Output
[null, null, null, null, false, null, true, false, true, false]

Explanation
Skiplist skiplist = new Skiplist();
skiplist.add(1);
skiplist.add(2);
skiplist.add(3);
skiplist.search(0); // return False
skiplist.add(4);
skiplist.search(1); // return True
skiplist.erase(0); // return False, 0 is not in skiplist.
skiplist.erase(1); // return True
skiplist.search(1); // return False, 1 has already been erased.

A
  1. Define an iter function that retrieves all previous nodes for a target. while l.next and l.next.val0.50: break
  2. For erasure, start from top, gather all prevs. For each prevs, if it has next and next.val=target, prevs[i].next=prevs[i].next.next

class Node:
def __init__(self, val):
self.val = val
self.next = None
self.down = None

class Skiplist:

def \_\_init\_\_(self, level_depth=16):
    self.levels = []
    prev = None
    for i in range(level_depth):
        node = Node(float('-inf'))
        self.levels.append(node)
        if prev:
            prev.down = node
        prev = node

def _iter(self, target):
    result = []
    l = self.levels[0]
    while l:
        while l.next and l.next.val < target:
            l = l.next
        result.append(l)
        l = l.down
    return result

def search(self, target: int) -> bool:
    all_prevs = self._iter(target)
    last_row_prev = all_prevs[-1]
    return last_row_prev.next and last_row_prev.next.val == target  # only return if the value is the same as target

def add(self, num: int) -> None:
    all_prevs = self._iter(num)
    prev = None
    for i in range(len(all_prevs) - 1, -1, -1):
        node = Node(num)
        node.next=all_prevs[i].next
        all_prevs[i].next=node
        node.down = prev
        prev = node
        if random.random() > 0.50:
            break

def erase(self, num: int) -> bool:
    all_prevs = self._iter(num)
    found=False
    for prev in all_prevs:
        if prev.next and prev.next.val == num:
            prev.next = prev.next.next
            found = True
    return found
183
Q
  1. Minimum Remove to Make Valid Parentheses
    Medium

Given a string s of ‘(‘ , ‘)’ and lowercase English characters.

Your task is to remove the minimum number of parentheses ( ‘(‘ or ‘)’, in any positions )
so that the resulting parentheses string is valid and return any valid string.

Formally, a parentheses string is valid if and only if:

It is the empty string, contains only lowercase characters, or
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.

Example 1:

Input: s = “lee(t(c)o)de)”
Output: “lee(t(c)o)de”
Explanation: “lee(t(co)de)” , “lee(t(c)ode)” would also be accepted.

A
  1. Convert string to stack and traverse through the string
  2. If open, add index to stack
  3. If close and stack, pop
  4. If no stack, s[i]=’’
  5. Finally, iterate through stack and empty the string with the indexes in the stack.

T: O(n)
S: O(n)

184
Q
  1. Product of the Last K Numbers
    Medium

Design an algorithm that accepts a stream of integers and retrieves the product of the last k integers of the stream.

Implement the ProductOfNumbers class:

ProductOfNumbers() Initializes the object with an empty stream.
void add(int num) Appends the integer num to the stream.
int getProduct(int k) Returns the product of the last k numbers in the current list. You can assume that always the current list has at least k numbers.
The test cases are generated so that, at any time, the product of any contiguous sequence of numbers will fit into a single 32-bit integer without overflowing.

Example:

Input
[“ProductOfNumbers”,”add”,”add”,”add”,”add”,”add”,”getProduct”,”getProduct”,”getProduct”,”add”,”getProduct”]
[[],[3],[0],[2],[5],[4],[2],[3],[4],[8],[2]]

Output
[null,null,null,null,null,null,20,40,0,null,32]

Explanation
ProductOfNumbers productOfNumbers = new ProductOfNumbers();
productOfNumbers.add(3); // [3]
productOfNumbers.add(0); // [3,0]
productOfNumbers.add(2); // [3,0,2]
productOfNumbers.add(5); // [3,0,2,5]
productOfNumbers.add(4); // [3,0,2,5,4]
productOfNumbers.getProduct(2); // return 20. The product of the last 2 numbers is 5 * 4 = 20
productOfNumbers.getProduct(3); // return 40. The product of the last 3 numbers is 2 * 5 * 4 = 40
productOfNumbers.getProduct(4); // return 0. The product of the last 4 numbers is 0 * 2 * 5 * 4 = 0
productOfNumbers.add(8); // [3,0,2,5,4,8]
productOfNumbers.getProduct(2); // return 32. The product of the last 2 numbers is 4 * 8 = 32

A
  1. Maintain a prefix product. Initialize to [1]
  2. If while adding, we meet 0, reset the prefix_product to be [1]
  3. offset = length-k-1

class ProductOfNumbers:

def \_\_init\_\_(self):
    self.prefix_product = [1]

def add(self, num: int) -> None:
    if num == 0:
        self.prefix_product = [1]
    else:
        self.prefix_product.append(self.prefix_product[-1] * num)

def getProduct(self, k: int) -> int:
    length = len(self.prefix_product)
    if k >= length:
        return 0
    else:
        offset = length - k - 1
        return self.prefix_product[-1] // self.prefix_product[offset]

T: O(n) - O(1) each
S: O(n)

185
Q
  1. Diagonal Traverse II
    Medium

Given a 2D integer array nums, return all elements of nums in diagonal order as shown in the below images.

Example 1:

Input: nums = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,4,2,7,5,3,8,6,9]

Input: nums = [[1,2,3,4,5],[6,7],[8],[9,10,11],[12,13,14,15,16]]
Output: [1,6,2,8,7,3,9,4,12,10,5,13,11,14,15,16]

A
  1. The requirement is to always traverse from bottom to top. (Also, the list has uneven sizes)
  2. The trick is for r in range(R-1, -1, -1) and c is len(nums[r])
186
Q
  1. Minimum Time to Collect All Apples in a Tree
    Medium

Given an undirected tree consisting of n vertices numbered from 0 to n-1, which has some apples in their vertices. You spend 1 second to walk over one edge of the tree. Return the minimum time in seconds you have to spend to collect all apples in the tree, starting at vertex 0 and coming back to this vertex.

The edges of the undirected tree are given in the array edges, where edges[i] = [ai, bi] means that exists an edge connecting the vertices ai and bi. Additionally, there is a boolean array hasApple, where hasApple[i] = true means that vertex i has an apple; otherwise, it does not have any apple.

A
  1. Undirected graph problem. DFS.
  2. cost=self.dfs(child, parent, graph, hasApple). return cost
  3. Within dfs, cost=0 and traverse through the neigbours
  4. For each nei, if nei==parent (avoid cycle), continue
  5. if not, child_cost = self.dfs(nei, child, graph, hasapple)
  6. if child_cost>0 or has_apple(nei): then cost=child_cost+2
    7 return cost
187
Q
  1. Minimum Insertions to Balance a Parentheses String
    Medium

Given a parentheses string s containing only the characters ‘(‘ and ‘)’. A parentheses string is balanced if:

Any left parenthesis ‘(‘ must have a corresponding two consecutive right parenthesis ‘))’.
Left parenthesis ‘(‘ must go before the corresponding two consecutive right parenthesis ‘))’.
In other words, we treat ‘(‘ as an opening parenthesis and ‘))’ as a closing parenthesis.

For example, “())”, “())(())))” and “(())())))” are balanced, “)()”, “()))” and “(()))” are not balanced.
You can insert the characters ‘(‘ and ‘)’ at any position of the string to balance it if needed.

Return the minimum number of insertions needed to make s balanced.

Example 1:

Input: s = “(()))”
Output: 1
Explanation: The second ‘(‘ has two matching ‘))’, but the first ‘(‘ has only ‘)’ matching. We need to add one more ‘)’ at the end of the string to be “(())))” which is balanced.

A
  1. Keep track of result and running_sum
  2. If ‘(‘, add running_sum+=2
  3. If ‘)’, running_sum-=1
  4. Return result+running_sum.
  5. During the ‘(‘, if running_sum&1, then it means that we need to add a closing parens (running_sum-=1 but result+=1)
  6. During the ‘)’, if running_sum==0, then there are no open parens and therefore need to insert (running_sum+=2, result+=1)

Result keeps track of the net parens to be added. Running keeps track of the weighted values (+2 for open, -1 for closing)

188
Q
  1. Dot Product of Two Sparse Vectors
    Medium

Given two sparse vectors, compute their dot product.

Implement class SparseVector:

SparseVector(nums) Initializes the object with the vector nums
dotProduct(vec) Compute the dot product between the instance of SparseVector and vec
A sparse vector is a vector that has mostly zero values, you should store the sparse vector efficiently and compute the dot product between two SparseVector.

Follow up: What if only one of the vectors is sparse?

Example 1:

Input: nums1 = [1,0,0,2,3], nums2 = [0,3,0,4,0]
Output: 8
Explanation: v1 = SparseVector(nums1) , v2 = SparseVector(nums2)
v1.dotProduct(v2) = 10 + 03 + 00 + 24 + 3*0 = 8

A
  1. In the init, have a store dictionary which holds just the numbers if it is not 0
  2. In the dotProduct function, iterating through the store of the incoming
  3. If i is in the self.store, then multiply.

T: O(N)
S: O(N)

189
Q
  1. Path With Minimum Effort
    Medium

You are a hiker preparing for an upcoming hike. You are given heights, a 2D array of size rows x columns, where heights[row][col] represents the height of cell (row, col). You are situated in the top-left cell, (0, 0), and you hope to travel to the bottom-right cell, (rows-1, columns-1) (i.e., 0-indexed). You can move up, down, left, or right, and you wish to find a route that requires the minimum effort.

A route’s effort is the maximum absolute difference in heights between two consecutive cells of the route.

Return the minimum effort required to travel from the top-left cell to the bottom-right cell.

Example 1:

Input: heights = [[1,2,2],[3,8,2],[5,3,5]]
Output: 2
Explanation: The route of [1,3,5,3,5] has a maximum absolute difference of 2 in consecutive cells.
This is better than the route of [1,2,2,2,5], where the maximum absolute difference is 3.

A
  1. Dijkstra’s shortest path
  2. PQ and dist=[[float(‘inf’)] *C for _ in range(R)]
  3. Pop from pq, look at the neighbours and compare curr_diff against new_diff
  4. new_diff here is max(curr_diff, abs(heights[nr][nc]-heights[r][c])
  5. If new_diff is less than dist[nr][nc], then add to the queue and update dist

T: O(ElogV) - E = 4MN, V = MN
S: O(M
N)

190
Q
  1. Merge In Between Linked Lists
    Medium

You are given two linked lists: list1 and list2 of sizes n and m respectively.

Remove list1’s nodes from the ath node to the bth node, and put list2 in their place.

The blue edges and nodes in the following figure indicate the result:

Build the result list and return its head.

Example 1:

Input: list1 = [10,1,13,6,9,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]
Output: [10,1,13,1000000,1000001,1000002,5]
Explanation: We remove the nodes 3 and 4 and put the entire list2 in their place. The blue edges and nodes in the above figure indicate the result.

A
  1. a and b are the places to insert and they are given.
  2. while head, if count==a-1, then it’s start. If count==b-1, then it’s end
  3. start.next=list2
  4. while list2.next: forward
  5. list2.next=end
191
Q
  1. Lowest Common Ancestor of a Binary Tree III
    Medium

Given two nodes of a binary tree p and q, return their lowest common ancestor (LCA).

Each node will have a reference to its parent node. The definition for Node is below:

class Node {
public int val;
public Node left;
public Node right;
public Node parent;
}
According to the definition of LCA on Wikipedia: “The lowest common ancestor of two nodes p and q in a tree T is the lowest node that has both p and q as descendants (where we allow a node to be a descendant of itself).”

A
  1. Similar to meeting point of LinkedList
  2. Find depth of both nodes using simple iteration (while node, node=node.parent)
  3. Compare the longest and shortest. Move longest to the level of shortest (for _ in range(ldepth-sdepth), lnode=lnode.parent)
  4. Move both lnode and snode up, lnode=lnode.parent, snode=snode.parent
  5. If they are equal return

T: O(N)
S: O(1)

192
Q
  1. Lowest Common Ancestor of a Binary Tree III
    Medium

Given two nodes of a binary tree p and q, return their lowest common ancestor (LCA).

Each node will have a reference to its parent node. The definition for Node is below:

class Node {
public int val;
public Node left;
public Node right;
public Node parent;
}
According to the definition of LCA on Wikipedia: “The lowest common ancestor of two nodes p and q in a tree T is the lowest node that has both p and q as descendants (where we allow a node to be a descendant of itself).”

A
  1. Similar to meeting point of LinkedList
  2. Find depth of both nodes using simple iteration (while node, node=node.parent)
  3. Compare the longest and shortest. Move longest to the level of shortest (for _ in range(ldepth-sdepth), lnode=lnode.parent)
  4. Move both lnode and snode up, lnode=lnode.parent, snode=snode.parent
  5. If they are equal return

T: O(N)
S: O(1)

193
Q
  1. Buildings With an Ocean View
    Medium

There are n buildings in a line. You are given an integer array heights of size n that represents the heights of the buildings in the line.

The ocean is to the right of the buildings. A building has an ocean view if the building can see the ocean without obstructions. Formally, a building has an ocean view if all the buildings to its right have a smaller height.

Return a list of indices (0-indexed) of buildings that have an ocean view, sorted in increasing order.

Example 1:

Input: heights = [4,2,3,1]
Output: [0,2,3]
Explanation: Building 1 (0-indexed) does not have an ocean view because building 2 is taller.

A
  1. What needs to be build is an array with decreasing values.
  2. Monotonic stack where nums[stack[-1]]<=num
  3. Remember the “while”. while “stack” and nums[stack[-1]]<=num. Not if
194
Q
  1. Shortest Path in a Hidden Grid
    Medium

This is an interactive problem.

There is a robot in a hidden grid, and you are trying to get it from its starting cell to the target cell in this grid. The grid is of size m x n, and each cell in the grid is either empty or blocked. It is guaranteed that the starting cell and the target cell are different, and neither of them is blocked.

You want to find the minimum distance to the target cell. However, you do not know the grid’s dimensions, the starting cell, nor the target cell. You are only allowed to ask queries to the GridMaster object.

Thr GridMaster class has the following functions:

boolean canMove(char direction) Returns true if the robot can move in that direction. Otherwise, it returns false.
void move(char direction) Moves the robot in that direction. If this move would move the robot to a blocked cell or off the grid, the move will be ignored, and the robot will remain in the same position.
boolean isTarget() Returns true if the robot is currently on the target cell. Otherwise, it returns false.
Note that direction in the above functions should be a character from {‘U’,’D’,’L’,’R’}, representing the directions up, down, left, and right, respectively.

Return the minimum distance between the robot’s initial starting cell and the target cell. If there is no valid path between the cells, return -1.

Custom testing:

The test input is read as a 2D matrix grid of size m x n where:

grid[i][j] == -1 indicates that the robot is in cell (i, j) (the starting cell).
grid[i][j] == 0 indicates that the cell (i, j) is blocked.
grid[i][j] == 1 indicates that the cell (i, j) is empty.
grid[i][j] == 2 indicates that the cell (i, j) is the target cell.
There is exactly one -1 and 2 in grid. Remember that you will not have this information in your code.

A
  1. Do a DFS and construct graph at that time. Identify target as well.
  2. Do a BFS and find the shortest path to the target.def findShortestPath(self, master: ‘GridMaster’) -> int:
     start=(0,0)
     directions ={'U': (-1,0), 'D': (1,0), 'L': (0,-1), 'R': (0,1)}
     anti = {'L': 'R', 'R':'L', 'U':'D', 'D':'U'}
     graph=defaultdict(list)
    
     def dfs(r,c):
         nonlocal target
         if not target and master.isTarget():
             target=(r,c)
             return
            
         seen.add((r,c))
                
         for d in directions:
             if master.canMove(d):
                 dr,dc=directions[d]
                 nr,nc = r+dr, c+dc
                 graph[(r,c)].append((nr,nc))
                 graph[(nr,nc)].append((r,c))
                    
                 if (nr,nc) not in seen:
                     master.move(d)
                     dfs(nr,nc)
                     master.move(anti[d])
    
    
     def bfs(start, target):
         queue=deque([(start[0], start[1], 0)])
            
         while queue:
             for _ in range(len(queue)):
                 r,c,dist=queue.popleft()
                 seen.add((r,c))
                 if (r,c)==target:
                     return dist
    
                 for nr,nc in graph[(r,c)]:
                     if (nr,nc) not in seen:
                         seen.add((nr,nc))
                         queue.append((nr,nc, dist+1))
            
         return -1
    
     target=None
     seen=set()
     dfs(0,0)
     seen=set()
     dist=bfs((0,0), target)
     return dist

T: O(MN)
S: O(M
N)

195
Q
  1. Product of Two Run-Length Encoded Arrays
    Medium

Run-length encoding is a compression algorithm that allows for an integer array nums with many segments of consecutive repeated numbers to be represented by a (generally smaller) 2D array encoded. Each encoded[i] = [vali, freqi] describes the ith segment of repeated numbers in nums where vali is the value that is repeated freqi times.

For example, nums = [1,1,1,2,2,2,2,2] is represented by the run-length encoded array encoded = [[1,3],[2,5]]. Another way to read this is “three 1’s followed by five 2’s”.
The product of two run-length encoded arrays encoded1 and encoded2 can be calculated using the following steps:

Expand both encoded1 and encoded2 into the full arrays nums1 and nums2 respectively.
Create a new array prodNums of length nums1.length and set prodNums[i] = nums1[i] * nums2[i].
Compress prodNums into a run-length encoded array and return it.
You are given two run-length encoded arrays encoded1 and encoded2 representing full arrays nums1 and nums2 respectively. Both nums1 and nums2 have the same length. Each encoded1[i] = [vali, freqi] describes the ith segment of nums1, and each encoded2[j] = [valj, freqj] describes the jth segment of nums2.

Return the product of encoded1 and encoded2.

Note: Compression should be done such that the run-length encoded array has the minimum possible length.

A
  1. Instantiate i, j, M, N and also keep fc and sc (tracks counts) outside the loop
  2. Loop through i
196
Q
  1. Number of Wonderful Substrings
    Medium

A wonderful string is a string where at most one letter appears an odd number of times.

For example, “ccjjc” and “abab” are wonderful, but “ab” is not.
Given a string word that consists of the first ten lowercase English letters (‘a’ through ‘j’), return the number of wonderful non-empty substrings in word. If the same substring appears multiple times in word, then count each occurrence separately.

A substring is a contiguous sequence of characters in a string.

Example 1:

Input: word = “aba”
Output: 4
Explanation: The four wonderful substrings are underlined below:
- “aba” -> “a”
- “aba” -> “b”
- “aba” -> “a”
- “aba” -> “aba”
Example 2:

Input: word = “aabb”
Output: 9
Explanation: The nine wonderful substrings are underlined below:
- “aabb” -> “a”
- “aabb” -> “aa”
- “aabb” -> “aab”
- “aabb” -> “aabb”
- “aabb” -> “a”
- “aabb” -> “abb”
- “aabb” -> “b”
- “aabb” -> “bb”
- “aabb” -> “b”
Example 3:

Input: word = “he”
Output: 2
Explanation: The two wonderful substrings are underlined below:
- “he” -> “h”
- “he” -> “e”

A
  1. BIt mask
  2. Maintain a dictionary with count, initiliaze count[0]=1
  3. Iterate each character, convert it to index (based on ord)
  4. mask^=(1< int:
    mask =0
    result=0
    count=defaultdict(int)
    count[0]=1
     for c in word:
         index=ord(c)-ord('a')
         mask^=(1<
197
Q
  1. Confirmation Rate
    Medium

SQL Schema
Table: Signups

+—————-+———-+
| Column Name | Type |
+—————-+———-+
| user_id | int |
| time_stamp | datetime |
+—————-+———-+
user_id is the column of unique values for this table.
Each row contains information about the signup time for the user with ID user_id.

Table: Confirmations

+—————-+———-+
| Column Name | Type |
+—————-+———-+
| user_id | int |
| time_stamp | datetime |
| action | ENUM |
+—————-+———-+
(user_id, time_stamp) is the primary key (combination of columns with unique values) for this table.
user_id is a foreign key (reference column) to the Signups table.
action is an ENUM (category) of the type (‘confirmed’, ‘timeout’)
Each row of this table indicates that the user with ID user_id requested a confirmation message at time_stamp and that confirmation message was either confirmed (‘confirmed’) or expired without confirming (‘timeout’).

The confirmation rate of a user is the number of ‘confirmed’ messages divided by the total number of requested confirmation messages. The confirmation rate of a user that did not request any confirmation messages is 0. Round the confirmation rate to two decimal places.

Write a solution to find the confirmation rate of each user.

Return the result table in any order.

The result format is in the following example.

A

select
s.user_id,
round(avg(case when action=’confirmed’ then 1.00 else 0.00 end), 2) as confirmation_rate
from
signups s
left join
confirmations c
on
s.user_id=c.user_id
group by
s.user_id

198
Q
  1. Find All Groups of Farmland
    Medium

You are given a 0-indexed m x n binary matrix land where a 0 represents a hectare of forested land and a 1 represents a hectare of farmland.

To keep the land organized, there are designated rectangular areas of hectares that consist entirely of farmland. These rectangular areas are called groups. No two groups are adjacent, meaning farmland in one group is not four-directionally adjacent to another farmland in a different group.

land can be represented by a coordinate system where the top left corner of land is (0, 0) and the bottom right corner of land is (m-1, n-1). Find the coordinates of the top left and bottom right corner of each group of farmland. A group of farmland with a top left corner at (r1, c1) and a bottom right corner at (r2, c2) is represented by the 4-length array [r1, c1, r2, c2].

Return a 2D array containing the 4-length arrays described above for each group of farmland in land. If there are no groups of farmland, return an empty array. You may return the answer in any order.

Example 1:

Input: land = [[1,0,0],[0,1,1],[0,1,1]]
Output: [[0,0,0,0],[1,1,2,2]]
Explanation:
The first group has a top left corner at land[0][0] and a bottom right corner at land[0][0].
The second group has a top left corner at land[1][1] and a bottom right corner at land[2][2].
Example 2:

Input: land = [[1,1],[1,1]]
Output: [[0,0,1,1]]
Explanation:
The first group has a top left corner at land[0][0] and a bottom right corner at land[1][1].
Example 3:

Input: land = [[0]]
Output: []
Explanation:
There are no groups of farmland.

A
  1. DFS but keep track of the max_r and max_cdef findFarmland(self, land: List[List[int]]) -> List[List[int]]:
    result = []
    R = len(land)
    C = len(land[0])
     def dfs(r, c):
         land[r][c] = 0
         nonlocal max_r, max_c
    
         neis = [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]
         for nr, nc in neis:
             if -1 < nr < R and -1 < nc < C and land[nr][nc] == 1:
                 dfs(nr, nc)
                 max_r = max(max_r, nr)
                 max_c = max(max_c, nc)
    
     for r in range(R):
         for c in range(C):
             if land[r][c] == 1:
                 max_r = r
                 max_c = c
                 dfs(r, c)
                 result.append([r, c, max_r, max_c])
     return result

T: O(MN)
S: O(M
N)

199
Q
  1. Count Nodes Equal to Average of Subtree
    Medium

Given the root of a binary tree, return the number of nodes where the value of the node is equal to the average of the values in its subtree.

Note:

The average of n elements is the sum of the n elements divided by n and rounded down to the nearest integer.
A subtree of root is a tree consisting of root and all of its descendants.

Example 1:

Input: root = [4,8,5,0,1,null,6]
Output: 5
Explanation:
For the node with value 4: The average of its subtree is (4 + 8 + 5 + 0 + 1 + 6) / 6 = 24 / 6 = 4.
For the node with value 5: The average of its subtree is (5 + 6) / 2 = 11 / 2 = 5.
For the node with value 0: The average of its subtree is 0 / 1 = 0.
For the node with value 1: The average of its subtree is 1 / 1 = 1.
For the node with value 6: The average of its subtree is 6 / 1 = 6.
Example 2:

Input: root = [1]
Output: 1
Explanation: For the node with value 1: The average of its subtree is 1 / 1 = 1.

A
  1. helper with node. return result
  2. if not node: return 0, 0
  3. lsum,lcount = dfs(node.left) – rsum,rcount = dfs(node.right)
  4. summ=node.val+lsum+rsum
  5. count=lcount+rcount+1
  6. if node.val == summ//count: result+=1
  7. return summ, count

class Solution:
def averageOfSubtree(self, root: TreeNode) -> int:
self.result=0
self.helper(root)
return self.result

def helper(self, node):
    if not node:
        return 0,0
    
    lsum, lcount=self.helper(node.left)
    rsum, rcount=self.helper(node.right)
    
    count=1+lcount+rcount
    summ=node.val+lsum+rsum
    
    if node.val==(summ//count):
        self.result+=1
    
    return summ,count

T: O(n)
S: O(n)

200
Q
  1. Task Scheduler II
    Medium

You are given a 0-indexed array of positive integers tasks, representing tasks that need to be completed in order, where tasks[i] represents the type of the ith task.

You are also given a positive integer space, which represents the minimum number of days that must pass after the completion of a task before another task of the same type can be performed.

Each day, until all tasks have been completed, you must either:

Complete the next task from tasks, or
Take a break.
Return the minimum number of days needed to complete all tasks.

Example 1:

Input: tasks = [1,2,1,2,3,1], space = 3
Output: 9
Explanation:
One way to complete all tasks in 9 days is as follows:
Day 1: Complete the 0th task.
Day 2: Complete the 1st task.
Day 3: Take a break.
Day 4: Take a break.
Day 5: Complete the 2nd task.
Day 6: Complete the 3rd task.
Day 7: Take a break.
Day 8: Complete the 4th task.
Day 9: Complete the 5th task.
It can be shown that the tasks cannot be completed in less than 9 days.
Example 2:

Input: tasks = [5,8,8,5], space = 2
Output: 6
Explanation:
One way to complete all tasks in 6 days is as follows:
Day 1: Complete the 0th task.
Day 2: Complete the 1st task.
Day 3: Take a break.
Day 4: Take a break.
Day 5: Complete the 2nd task.
Day 6: Complete the 3rd task.
It can be shown that the tasks cannot be completed in less than 6 days.

A
  1. Maintain a dictionary next_available_day and days variable
  2. Iterate through the dict
  3. Within the iteration,
    days = max(next_available_day[task], days+1) #either next day or next available day. Day starts with 0
    next_available_day[task]=days+1+space #days stores the current day. So, the least next day must be current_day+space + 1
  4. If the task was finished on the first day, the next_available_day for that task must be the 5th day (with 3 spaces). So, 1+3+1def taskSchedulerII(self, tasks: List[int], space: int) -> int:
    next_avbl={}
    days=0
    for task in tasks:
    days=max(next_avbl.get(task, 0), days+1)
    next_avbl[task]=days+1+space
    return days

T: O(n)
S: O(n)

201
Q
  1. Maximum Sum of Distinct Subarrays With Length K
    Medium

You are given an integer array nums and an integer k. Find the maximum subarray sum of all the subarrays of nums that meet the following conditions:

The length of the subarray is k, and
All the elements of the subarray are distinct.
Return the maximum subarray sum of all the subarrays that meet the conditions. If no subarray meets the conditions, return 0.

A subarray is a contiguous non-empty sequence of elements within an array.

Example 1:

Input: nums = [1,5,4,2,9,9,9], k = 3
Output: 15
Explanation: The subarrays of nums with length 3 are:
- [1,5,4] which meets the requirements and has a sum of 10.
- [5,4,2] which meets the requirements and has a sum of 11.
- [4,2,9] which meets the requirements and has a sum of 15.
- [2,9,9] which does not meet the requirements because the element 9 is repeated.
- [9,9,9] which does not meet the requirements because the element 9 is repeated.
We return 15 because it is the maximum subarray sum of all the subarrays that meet the conditions
Example 2:

Input: nums = [4,4,4], k = 3
Output: 0
Explanation: The subarrays of nums with length 3 are:
- [4,4,4] which does not meet the requirements because the element 4 is repeated.
We return 0 because no subarrays meet the conditions.

A
  1. Use a counter to do counting on nums[:k]
  2. Capture csum=sum(nums[:k])
  3. Short circut - if len(counter)==k: result=csum
  4. Iterate from k to len(nums)
  5. add current num to csum and mapp
  6. remove window passed num (nums[i-k]) from csum and mapp
  7. if mapp[nums[i-k]]==0, then delete from mapp
  8. Check if the len(mapp)==k, If yes update result
  9. return resultdef maximumSubarraySum(self, nums: List[int], k: int) -> int:
    mapp = Counter(nums[:k])
    summ = sum(nums[:k])
    result = 0
     if len(mapp) == k:
         result = summ
    
     for i in range(k, len(nums)):
         # add current num
         summ += nums[i]
         mapp[nums[i]] += 1
    
         # subtract num for window passed
         summ -= nums[i - k]
         mapp[nums[i - k]] -= 1
         if mapp[nums[i - k]] == 0:
             del mapp[nums[i - k]]
    
         if len(mapp) == k:
             result = max(result, summ)
     return result

T: O(n)
S: O(k)

202
Q
  1. Mice and Cheese
    Medium

There are two mice and n different types of cheese, each type of cheese should be eaten by exactly one mouse.

A point of the cheese with index i (0-indexed) is:

reward1[i] if the first mouse eats it.
reward2[i] if the second mouse eats it.
You are given a positive integer array reward1, a positive integer array reward2, and a non-negative integer k.

Return the maximum points the mice can achieve if the first mouse eats exactly k types of cheese.

Example 1:

Input: reward1 = [1,1,3,4], reward2 = [4,4,1,1], k = 2
Output: 15
Explanation: In this example, the first mouse eats the 2nd (0-indexed) and the 3rd types of cheese, and the second mouse eats the 0th and the 1st types of cheese.
The total points are 4 + 4 + 3 + 4 = 15.
It can be proven that 15 is the maximum total points that the mice can achieve.
Example 2:

Input: reward1 = [1,1], reward2 = [1,1], k = 2
Output: 2
Explanation: In this example, the first mouse eats the 0th (0-indexed) and 1st types of cheese, and the second mouse does not eat any cheese.
The total points are 1 + 1 = 2.
It can be proven that 2 is the maximum total points that the mice can achieve.

A
  1. Form a min PQ and add reward2-reward1. Since it is a minPQ, all the bigger ones would come up on top.
  2. Iterate until k and add the rewards1[index] to the result
  3. Keep track of the popped index as visited
  4. Iterate through rewards2 and append the ones which is not in visited.def miceAndCheese(self, reward1: List[int], reward2: List[int], k: int) -> int:
    N = len(reward1)
    pq = []
    for i in range(N):
    pq.append((reward2[i] - reward1[i], i))
    heapq.heapify(pq)
    result = 0
    visited = set()
    for _ in range(k):
    r, i = heapq.heappop(pq)
    result += reward1[i]
    visited.add(i)
     for i, r in enumerate(reward2):
         if i in visited:
             continue
         result += reward2[i]
    
     return result

T: O(nlogk)
S: O(n)

203
Q
  1. Count Alternating Subarrays
    Medium

You are given a binary array nums.

We call a subarray alternating if no two adjacent elements in the subarray have the same value.

Return the number of alternating subarrays in nums.

Example 1:

Input: nums = [0,1,1,1]

Output: 5

Explanation:

The following subarrays are alternating: [0], [1], [1], [1], and [0,1].

Example 2:

Input: nums = [1,0,1,0]

Output: 10

Explanation:

Every subarray of the array is alternating. There are 10 possible subarrays that we can choose.

A
  1. DP. Initialize dp=[1]*N
  2. Iterate from 1,N
  3. If nums[i-1]!=nums[i], then dp[i]=dp[i-1]+1def countAlternatingSubarrays(self, nums: List[int]) -> int:
    N = len(nums)
    dp = [1] * N
    for i in range(1, N):
    if nums[i] != nums[i - 1]:
    dp[i] = dp[i - 1] + 1
    return sum(dp)

T:O(N)
S:O(N)

204
Q
  1. Grumpy Bookstore Owner
    Medium

There is a bookstore owner that has a store open for n minutes. Every minute, some number of customers enter the store. You are given an integer array customers of length n where customers[i] is the number of the customer that enters the store at the start of the ith minute and all those customers leave after the end of that minute.

On some minutes, the bookstore owner is grumpy. You are given a binary array grumpy where grumpy[i] is 1 if the bookstore owner is grumpy during the ith minute, and is 0 otherwise.

When the bookstore owner is grumpy, the customers of that minute are not satisfied, otherwise, they are satisfied.

The bookstore owner knows a secret technique to keep themselves not grumpy for minutes consecutive minutes, but can only use it once.

Return the maximum number of customers that can be satisfied throughout the day.

Example 1:

Input: customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], minutes = 3
Output: 16
Explanation: The bookstore owner keeps themselves not grumpy for the last 3 minutes.
The maximum number of customers that can be satisfied = 1 + 1 + 1 + 1 + 7 + 5 = 16.
Example 2:

Input: customers = [1], grumpy = [0], minutes = 1
Output: 1

A
  1. Iterate through the grumpy and add to the result customers where grump=0. Set customers to 0
  2. Iterate through customers again and add to result.
  3. If i>k, then curr_sat = curr_sat-customers[i-k]
  4. set max_sat
  5. Finally return already_sat with max_satdef maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int:
    already_sat=0
     for i,g in enumerate(grumpy):
         if g==0:
             already_sat+=customers[i]
             customers[i]=0
        
     max_sat=0
     curr_sat=0
        
     for i, c in enumerate(customers):
         curr_sat+=c
            
         if i>=minutes:
             curr_sat-=customers[i-minutes]
            
         max_sat=max(max_sat, curr_sat)
        
     return max_sat+already_sat

T: O(n)
S: O(1)

205
Q
  1. Egg Drop With 2 Eggs and N Floors
    Medium

You are given two identical eggs and you have access to a building with n floors labeled from 1 to n.

You know that there exists a floor f where 0 <= f <= n such that any egg dropped at a floor higher than f will break, and any egg dropped at or below floor f will not break.

In each move, you may take an unbroken egg and drop it from any floor x (where 1 <= x <= n). If the egg breaks, you can no longer use it. However, if the egg does not break, you may reuse it in future moves.

Return the minimum number of moves that you need to determine with certainty what the value of f is.

Example 1:

Input: n = 2
Output: 2
Explanation: We can drop the first egg from floor 1 and the second egg from floor 2.
If the first egg breaks, we know that f = 0.
If the second egg breaks but the first egg didn’t, we know that f = 1.
Otherwise, if both eggs survive, we know that f = 2.
Example 2:

Input: n = 100
Output: 14
Explanation: One optimal strategy is:
- Drop the 1st egg at floor 9. If it breaks, we know f is between 0 and 8. Drop the 2nd egg starting from floor 1 and going up one at a time to find f within 8 more drops. Total drops is 1 + 8 = 9.
- If the 1st egg does not break, drop the 1st egg again at floor 22. If it breaks, we know f is between 9 and 21. Drop the 2nd egg starting from floor 10 and going up one at a time to find f within 12 more drops. Total drops is 2 + 12 = 14.
- If the 1st egg does not break again, follow a similar process dropping the 1st egg from floors 34, 45, 55, 64, 72, 79, 85, 90, 94, 97, 99, and 100.
Regardless of the outcome, it takes at most 14 drops to determine f.

A
  1. DP - recursive
  2. Either you break the egg or not.
  3. If you dropped the egg and it broke, the number of eggs gets reduced by 1 and the floor is reduced by 1
  4. If you didn’t break the egg, the numebr of eggs remains the same but the floor is reduced by floors-fdef twoEggDrop(self, floors: int) -> int:
    eggs=2
    return self.two_egg_drop(floors, eggs)@cache
    def two_egg_drop(self, floors, eggs):
    if eggs==1 or floors<=1:
    return floors
     mini=float('inf')
     for f in range(1, floors+1):
         mini=min(mini, 1+max(self.two_egg_drop(f-1, eggs-1), self.two_egg_drop(floors-f, eggs)))
     return mini

T:O(n^2)
S:O(n)

206
Q
  1. Construct Quad Tree
    Medium

Given a n * n matrix grid of 0’s and 1’s only. We want to represent grid with a Quad-Tree.

Return the root of the Quad-Tree representing grid.

A Quad-Tree is a tree data structure in which each internal node has exactly four children. Besides, each node has two attributes:

val: True if the node represents a grid of 1’s or False if the node represents a grid of 0’s. Notice that you can assign the val to True or False when isLeaf is False, and both are accepted in the answer.
isLeaf: True if the node is a leaf node on the tree or False if the node has four children.
class Node {
public boolean val;
public boolean isLeaf;
public Node topLeft;
public Node topRight;
public Node bottomLeft;
public Node bottomRight;
}
We can construct a Quad-Tree from a two-dimensional area using the following steps:

If the current grid has the same value (i.e all 1’s or all 0’s) set isLeaf True and set val to the value of the grid and set the four children to Null and stop.
If the current grid has different values, set isLeaf to False and set val to any value and divide the current grid into four sub-grids as shown in the photo.
Recurse for each of the children with the proper sub-grid.

If you want to know more about the Quad-Tree, you can refer to the wiki.

Quad-Tree format:

You don’t need to read this section for solving the problem. This is only if you want to understand the output format here. The output represents the serialized format of a Quad-Tree using level order traversal, where null signifies a path terminator where no node exists below.

It is very similar to the serialization of the binary tree. The only difference is that the node is represented as a list [isLeaf, val].

If the value of isLeaf or val is True we represent it as 1 in the list [isLeaf, val] and if the value of isLeaf or val is False we represent it as 0.

Example 1:

Input: grid = [[0,1],[1,0]]
Output: [[0,1],[1,0],[1,1],[1,1],[1,0]]
Explanation: The explanation of this example is shown below:
Notice that 0 represents False and 1 represents True in the photo representing the Quad-Tree.

A
  1. Recursive solution.
  2. If not grid, return None.
  3. If leaf (every single element in the grid has the same value), then return the node.
  4. Else, split into 4 recursive calls.def construct(self, grid: List[List[int]]) -> ‘Node’:
    if not grid:
    return None
     if self.is_leaf(grid):
         return Node(grid[0][0] == 1, True, None, None, None, None)
    
     n = len(grid)
     return Node('*',
                 False,
                 self.construct([row[:n // 2] for row in grid[:n // 2]]),
                 self.construct([row[n // 2:] for row in grid[:n // 2]]),
                 self.construct([row[:n // 2] for row in grid[n // 2:]]),
                 self.construct([row[n // 2:] for row in grid[n // 2:]]))
    def is_leaf(self, grid):
    return len(set([cell for row in grid for cell in row])) == 1

T: O(n^2log(n)) - At each iteration we do a (nn)/4 and then do logn for each of them.
S: O(logN) recursive calls.

207
Q
  1. Basic Calculator III
    Hard

Implement a basic calculator to evaluate a simple expression string.

The expression string contains only non-negative integers, ‘+’, ‘-‘, ‘*’, ‘/’ operators, and open ‘(‘ and closing parentheses ‘)’. The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-231, 231 - 1].

Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().

Example 1:

Input: s = “1+1”
Output: 2
Example 2:

Input: s = “6-4/2”
Output: 4
Example 3:

Input: s = “2(5+52)/3+(6/2+8)”
Output: 21

Constraints:

1 <= s <= 104
s consists of digits, ‘+’, ‘-‘, ‘*’, ‘/’, ‘(‘, and ‘)’.
s is a valid expression.

A
  1. Regular basic calculator
  2. Create an opset
  3. For digit. num*10+int(c)
  4. For open parens, just append op to stack and reset op and num (this is for starting a new context)
  5. For close parens or c in opset:
    self.update()
    set op=c
    num=0
    if c==’)’:
    temp_num and while loop until stack[-1] is in opset
    self.update(temp_num, stack.pop()) - the previous op
  6. for c in s+’+’def calculate(self, s: str) -> int:
    op=’+’
    num=0
    opset={‘+’,’-‘,’*’,’/’}
     stack=[]
        
     for c in s+'+':
         if c.isdigit():
             num=num*10 + int(c)
         elif c==')' or c in opset:
             self.update(num, op, stack)
             op=c
             num=0
                
             if c==')':
                 tmp_num=0
                 while stack[-1] not in opset:
                     tmp_num+=stack.pop()
                 self.update(tmp_num, stack.pop(), stack)
         elif c=='(':
             stack.append(op)
             op='+'
             num=0
     return sum(stack)
    def update(self, num, op, stack):
    if op==’+’:
    stack.append(num)
    elif op==’-‘:
    stack.append(-num)
    elif op==’’:
    prev=stack.pop()
    stack.append(num
    prev)
    elif op==’/’:
    prev=stack.pop()
    stack.append(int(prev/num))

T: O(n)
S: O(n)