N-IO-all Flashcards

1
Q

Given an integer n, return all the structurally unique BST’s (binary search trees), which has exactly n nodes of unique values from 1 to n. Return the answer in any order.

Input: n = 3
Output: [[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def generateTrees(self, n: int) -> List[Optional[TreeNode]]:
        dp = {} #(left, right) -> the list of trees in left -> right
        def generate(left, right):
            res = []
            if left == right:
                return [TreeNode(left)]
            if left > right:
                #Needs to be [None], because for [1, 2, 3] and at 1, left should be None. But iterating [] in the for loop will cause nothing to happen!
                return [None]
            if (left, right) in dp:
                return dp[(left, right)]
            for val in range(left, right + 1):
                for leftTree in generate(left, val - 1):
                    for rightTree in generate(val + 1, right):
                        root = TreeNode(val, leftTree, rightTree)
                        res.append(root)
            dp[(left, right)] = res
            return res
        return generate(1, n)
        #Runtime: O(4^n/ sqrt n). Nth Catalan Number, also say exponential
        #Space: O(4^n/ sqrt n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Minimize the Maximum Difference of Pairs
You are given a 0-indexed integer array nums and an integer p. Find p pairs of indices of nums such that the maximum difference amongst all the pairs is minimized. Also, ensure no index appears more than once amongst the p pairs.

Note that for a pair of elements at the index i and j, the difference of this pair is |nums[i] - nums[j]|, where |x| represents the absolute value of x.

Return the minimum maximum difference among all p pairs. We define the maximum of an empty set to be zero.

Input: nums = [10,1,2,7,1,3], p = 2
Output: 1
Explanation: The first pair is formed from the indices 1 and 4, and the second pair is formed from the indices 2 and 5.
The maximum difference is max(|nums[1] - nums[4]|, |nums[2] - nums[5]|) = max(0, 1) = 1. Therefore, we return 1.

A
class Solution:
    def minimizeMax(self, nums: List[int], p: int) -> int:
        def isValid(threshold):
            #count # of pairs that fall <= threshold
            i, count = 0, 0
            while i < len(nums) - 1:
                if nums[i + 1] - nums[i] <= threshold:
                    count += 1
                    i += 2
                else:
                    i += 1
                if count == p:
                    return True
            return False
        
        if p == 0:
            return 0
        
        nums.sort()
        #Look at problem constraints
        l, r = 0, 10 ** 9
        
        res = 10 ** 9 #the difference is at least 10 ** 9
        while l <= r:
            m = l + (r - l) // 2
            if isValid(m):
                res = min(m, res)
                r = m - 1
            else:
                l = m + 1
        return res

        #O(n log n + n * log 10 ** 9) 
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Search in Rotated Sorted Array (Revamped)

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.

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

A
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        l, r = 0, len(nums) - 1
        while l <= r:
            m = l + (r - l) // 2
            if nums[m] == target:
                return m
            #in left partition
            elif nums[m] >= nums[l]:
                #Go left
                if nums[l] <= target < nums[m]:
                    r = m - 1
                else:
                    l = m + 1
            else: #In right partition
                #Go right
                if nums[m] < target <= nums[r]:
                    l = m + 1
                else:
                    r = m - 1
        return -1
        #O(log n)
        #O(1)
                
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Search in Rotated Sorted Array II
There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).

Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= 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,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].

Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.

You must decrease the overall operation steps as much as possible.
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true

A
class Solution:
    def search(self, nums: List[int], target: int) -> bool:
        l, r = 0, len(nums) - 1
        while l <= r:
            m = l + (r - l) // 2
            if nums[m] == target:
                return True
            
            #in left partition
            if nums[l] < nums[m]:
                #Go left
                if nums[l] <= target < nums[m]:
                    r = m - 1
                else:
                    l = m + 1

            #in right partition
            elif nums[m] < nums[l]:
                #Go right
                if nums[m] < target <= nums[r]:
                    l = m + 1
                else:
                    r = m - 1
            
            #unclear. this is because nums[m] is EQUAL to nums[l]
            #But at this point, we know nums[l] isn't the target either! So l += 1
            else:
                l += 1
        return False
        #O(log n) or O(n) worst case if all values are equal
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Delete and Earn
You are given an integer array nums. You want to maximize the number of points you get by performing the following operation any number of times:

Pick any nums[i] and delete it to earn nums[i] points. Afterwards, you must delete every element equal to nums[i] - 1 and every element equal to nums[i] + 1.
Return the maximum number of points you can earn by applying the above operation some number of times.
Input: nums = [3,4,2]
Output: 6
Explanation: You can perform the following operations:
- Delete 4 to earn 4 points. Consequently, 3 is also deleted. nums = [2].
- Delete 2 to earn 2 points. nums = [].
You earn a total of 6 points.

A
class Solution:
    def deleteAndEarn(self, nums: List[int]) -> int:
        counts = {}
        for n in nums:
            counts[n] = counts.get(n, 0) + 1
        
        nums = sorted(list(set(nums)))

        earn1, earn2 = 0, 0
        for i in range(len(nums)):
            curEarn = nums[i] * counts[nums[i]]

            #If adjacent to elt nums[i - 1]
            if i > 0 and nums[i] == nums[i - 1] + 1:
                tmp = max(earn1 + curEarn, earn2)
                earn1 = earn2 
                earn2 = tmp
            #not adjacent, so feel free to just add to earn2
            else:
                tmp = earn2 + curEarn
                earn1 = earn2
                earn2 = tmp
        return earn2
        #O(n log n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Check if There is a Valid Partition For The Array
You are given a 0-indexed integer array nums. You have to partition the array into one or more contiguous subarrays.

We call a partition of the array valid if each of the obtained subarrays satisfies one of the following conditions:

The subarray consists of exactly 2 equal elements. For example, the subarray [2,2] is good.
The subarray consists of exactly 3 equal elements. For example, the subarray [4,4,4] is good.
The subarray consists of exactly 3 consecutive increasing elements, that is, the difference between adjacent elements is 1. For example, the subarray [3,4,5] is good, but the subarray [1,3,5] is not.
Return true if the array has at least one valid partition. Otherwise, return false.

Input: nums = [4,4,4,5,6]
Output: true
Explanation: The array can be partitioned into the subarrays [4,4] and [4,5,6].
This partition is valid, so we return true.

A
class Solution:
    def validPartition(self, nums: List[int]) -> bool:
        dp = {}
        def dfs(i):
            if i == len(nums):
                return True
            if i in dp:
                return dp[i]
            res = False
            if i + 1 <= len(nums) - 1 and nums[i] == nums[i + 1]:
                res = dfs(i + 2)
            
            if i + 2 <= len(nums) - 1:
                if (nums[i] == nums[i + 1] == nums[i + 2]) or (nums[i] == nums[i + 1] - 1 == nums[i + 2] - 2):
                    res = res or dfs(i + 3)

            dp[i] = res
            return res
        return dfs(0)
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Write a solution to find the second highest salary from the Employee table. If there is no second highest salary, return null (return None in Pandas).

The result format is in the following example.
Input:
Employee table:
+—-+——–+
| id | salary |
+—-+——–+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+—-+——–+
Output:
+———————+
| SecondHighestSalary |
+———————+
| 200 |
+———————+
Input:
Employee table:
+—-+——–+
| id | salary |
+—-+——–+
| 1 | 100 |
+—-+——–+
Output:
+———————+
| SecondHighestSalary |
+———————+
| null |

A
# Write your MySQL query statement below
SELECT 
    IFNULL(
        (SELECT DISTINCT SALARY 
        FROM EMPLOYEE
        ORDER BY SALARY DESC
        LIMIT 1 OFFSET 1),
        NULL
    ) AS SECONDHIGHESTSALARY
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Repeated Substring Pattern
Given a string s, check if it can be constructed by taking a substring of it and appending multiple copies of the substring together.

Input: s = “abab”
Output: true
Explanation: It is the substring “ab” twice.

A
class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        #max it can be split up is halfway
        for i in range(1, len(s) // 2 + 1):
            if len(s) % i == 0:
                copies = len(s) // i
                subs = s[: i]
                candidate = subs * copies
                if candidate == s:
                    return True
        return False
        #O(n * n)) #O(n // 2 substrings, each costs O(n // 2) time ish to create substring and checking.
        #O(n) candidate is built up
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Excel Sheet Column Title
Given an integer columnNumber, return its corresponding column title as it appears in an Excel sheet.

A -> 1
B -> 2
C -> 3

Z -> 26
AA -> 27
AB -> 28

Input: columnNumber = 28
Output: “AB”

Input: columnNumber = 701
Output: “ZY”

A
class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        res = []
        #The minus ones are due to "1" indexing
        #Example: 27. 
        #offset is 26 % 26 -> 0, which is A+0 -> A
        #next digit is (27/26 - 1) % 26 in second run of loop, which is 0. A + 0 -> A
        while columnNumber > 0: 
            offset = (columnNumber - 1) % 26
            res.append(chr(ord('A') + offset))
            columnNumber = (columnNumber - 1) // 26
        return "".join(res[::-1])
        #O(log_26 n)
        #O(n) for res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Text Justification

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.

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

A
class Solution:
    def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
        res = []
        line, length = [], 0
        #each element of line is a word. so len(line) gives the number of words
        #length: the number of characters in words.
        i = 0
        while i < len(words):
            #If attempting to add a space after the prev word, and the new word to this line exceeds the max width, meaning line is complete.
            if length + len(line) + len(words[i]) > maxWidth:
                #total number of extra spaces that should exist in this line
                extraSpaces = maxWidth - length
                #Spaces that should go in between. If 1 word, then we div we avoid div by 0
                spaces = extraSpaces // max(1, (len(line) - 1))
                #Total number of spaces that should greedily be distributed. 1 space distributed after each word.
                remainder = extraSpaces % max(1, (len(line) - 1))

                #Add spaces after each word, except final word.
                #If single word, we need to make sure we add spaces at the end ALSO (edge case). Hence max(1, len(line) - 1).
                for j in range(max(1, len(line) - 1)):
                    line[j] += " " * spaces
                    if remainder:
                        line[j] += " "
                        remainder -= 1
                res.append("".join(line)) 

                #Reset the current line and length
                line, length = [], 0
            
            #Line is incomplete, so we just add a word to it.
            line.append(words[i])
            length += len(words[i])
            i += 1
        #add the last line to res
        lastLine = " ".join(line) #get the line, with the spaces inserted in between already 
        trailingSpaces = maxWidth - len(lastLine)
        res.append(lastLine + " " * trailingSpaces)
        return res
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Maximum Length of Pair Chain

You are given an array of n pairs pairs where pairs[i] = [lefti, righti] and lefti < righti.

A pair p2 = [c, d] follows a pair p1 = [a, b] if b < c. A chain of pairs can be formed in this fashion.

Return the length longest chain which can be formed.

You do not need to use up all the given intervals. You can select pairs in any order.

Input: pairs = [[1,2],[2,3],[3,4]]
Output: 2
Explanation: The longest chain is [1,2] -> [3,4].

A
class Solution:
    def findLongestChain(self, pairs: List[List[int]]) -> int:
        pairs.sort(key = lambda p: p[1]) #sort by end time since that's the limiting factor
        res = 1
        prevEnd = pairs[0][1]
        
        for start, end in pairs[1:]:
            if start > prevEnd:
                res += 1
                prevEnd = end
        return res
        #O(n log n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Minimum Penalty for a Shop
You are given the customer visit log of a shop represented by a 0-indexed string customers consisting only of characters ‘N’ and ‘Y’:

if the ith character is ‘Y’, it means that customers come at the ith hour
whereas ‘N’ indicates that no customers come at the ith hour.
If the shop closes at the jth hour (0 <= j <= n), the penalty is calculated as follows:

For every hour when the shop is open and no customers come, the penalty increases by 1.
For every hour when the shop is closed and customers come, the penalty increases by 1.
Return the earliest hour at which the shop must be closed to incur a minimum penalty.

Note that if a shop closes at the jth hour, it means the shop is closed at the hour j

Input: customers = “YYNY”
Output: 2
Explanation:
- Closing the shop at the 0th hour incurs in 1+1+0+1 = 3 penalty.
- Closing the shop at the 1st hour incurs in 0+1+0+1 = 2 penalty.
- Closing the shop at the 2nd hour incurs in 0+0+0+1 = 1 penalty.
- Closing the shop at the 3rd hour incurs in 0+0+1+1 = 2 penalty.
- Closing the shop at the 4th hour incurs in 0+0+1+0 = 1 penalty.
Closing the shop at 2nd or 4th hour gives a minimum penalty. Since 2 is earlier, the optimal closing time is 2.

A
class Solution:
    def bestClosingTime(self, customers: str) -> int:
        n = len(customers)
        prefixes = [0] * (n + 1) #number of "N" before this point
        suffixes = [0] * (n + 1) #number of "Y" after and including this point

        #The n + 1, as well as the weird n + 1 and n - 1, is due to 
        #penalty for a shop that is out of bounds is included!
        #So after the array.
        for i in range(1, n + 1):
            prefixes[i] = prefixes[i - 1] 
            if customers[i - 1] == "N":
                prefixes[i] += 1
        
        for i in range(n - 1, -1, -1):
            suffixes[i] = suffixes[i + 1]
            if customers[i] == "Y":
                suffixes[i] += 1
        
        res = 0
        minPenalty = float('inf')

        for i in range(n + 1):
            penalty = prefixes[i] + suffixes[i]
            if penalty < minPenalty:
                minPenalty = penalty
                res = i
        return res
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Given n orders, each order consist in pickup and delivery services.

Count all valid pickup/delivery possible sequences such that delivery(i) is always after of pickup(i).

Since the answer may be too large, return it modulo 10^9 + 7.

Input: n = 2
Output: 6
Explanation: All possible orders:
(P1,P2,D1,D2), (P1,P2,D2,D1), (P1,D1,P2,D2), (P2,P1,D1,D2), (P2,P1,D2,D1) and (P2,D2,P1,D1).
This is an invalid order (P1,D2,P2,D1) because Pickup 2 is after of Delivery 2.

A
class Solution:
    def countOrders(self, n: int) -> int:
        slots = 2 * n
        res = 1
        while slots > 0:
            #Consider one pair P1 D1, and X slots
            #There are X choices for P, then X - 1 for D
            #But half of these will place D before P
            #So we divide by 2
            count = slots * (slots - 1) // 2
            res *= count
            slots -= 2 #we used up two slots 
            #Now let while loop iterate and do the rest of the packages
        return res % (10 ** 9 + 7)
        #O(n) #basically O(X), which is 2 * n 
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Minimum Deletions to Make Character Frequencies Unique

A string s is called good if there are no two different characters in s that have the same frequency.

Given a string s, return the minimum number of characters you need to delete to make s good.

The frequency of a character in a string is the number of times it appears in the string. For example, in the string “aab”, the frequency of ‘a’ is 2, while the frequency of ‘b’ is 1.

Input: s = “aaabbbcc”
Output: 2
Explanation: You can delete two ‘b’s resulting in the good string “aaabcc”.
Another way it to delete one ‘b’ and one ‘c’ resulting in the good string “aaabbc”.

A
class Solution:
    def minDeletions(self, s: str) -> int:
        counts = {}
        for c in s:
            counts[c] = counts.get(c, 0) + 1
        
        usedFreqs = set()
        res = 0
        for c in counts:
            freq = counts[c]
            while freq > 0 and freq in usedFreqs:
                freq -= 1
                res += 1
            usedFreqs.add(freq)
            #We don't care if freq is zero, so if it is zero, we don't increment res
        return res
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

There are n children standing in a line. Each child is assigned a rating value given in the integer array ratings.

You are giving candies to these children subjected to the following requirements:

Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.
Return the minimum number of candies you need to have to distribute the candies to the children.

Input: ratings = [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
The third child gets 1 candy because it satisfies the above two conditions.

A
class Solution:
    def candy(self, ratings: List[int]) -> int:
        res = [1] * len(ratings)

        #Figure out increasing cases' candies. [1 2 3 4]....
        for i in range(1, len(ratings)):
            if ratings[i] > ratings[i - 1]:
                res[i] = res[i - 1] + 1

        #Figure out decreasing cases' candies [5 4 3 2], iterating from back to front
        for i in range(len(ratings) - 2, -1, -1):
            if ratings[i] > ratings[i + 1]:
                #Max because if the first increasing case necesitated some value,
                #we CANNOT have 1 + res[i + 1] be less than the value.
                res[i] = max(res[i], 1 + res[i + 1])   
        return sum(res)
        #O(n)
        #O(n)             
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Path With Minimum Effort

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.

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
class Solution:
    def minimumEffortPath(self, heights: List[List[int]]) -> int:
        ROWS, COLS = len(heights), len(heights[0])

        #0 effort to reach topleft
        minHeap = [(0, 0, 0)] #(effort so far to reach this cell, r, c)
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

        visit = set()
        #Dijkstra's
        while minHeap:
            effort, r, c = heapq.heappop(minHeap)
            if r == ROWS - 1 and c == COLS - 1:
                return effort
            
            if (r, c) in visit:
                continue
                
            visit.add((r, c))

            for dr, dc in directions:
                neiR, neiC = r + dr, c + dc
                if neiR < 0 or neiR == ROWS or neiC < 0 or neiC == COLS or (neiR, neiC) in visit:
                    continue
                difference = abs(heights[neiR][neiC] - heights[r][c])
                newEffort = max(effort, difference)
                heapq.heappush(minHeap, (newEffort, neiR, neiC))
        #O(V ^ 2 log V)
        #O(V + E)        
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Minimum Operations to Reduce X to Zero

You are given an integer array nums and an integer x. In one operation, you can either remove the leftmost or the rightmost element from the array nums and subtract its value from x. Note that this modifies the array for future operations.

Return the minimum number of operations to reduce x to exactly 0 if it is possible, otherwise, return -1.

Input: nums = [1,1,4,2,3], x = 5
Output: 2
Explanation: The optimal solution is to remove the last two elements to reduce x to zero.

A
class Solution:
    def minOperations(self, nums: List[int], x: int) -> int:
        target = sum(nums) - x 

        l = 0
        maxWindow = -1
        curSum = 0
        for r in range(len(nums)):
            curSum += nums[r] #always add to start
            while l <= r and curSum > target:
                curSum -= nums[l]
                l += 1
            if curSum == target:
                maxWindow = max(maxWindow, r - l + 1)
        return -1 if maxWindow == -1 else len(nums) - maxWindow
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Implement Dijkstra’s shortest path algorithm.

Given a weighted, directed graph, and a starting vertex, return the shortest distance from the starting vertex to every vertex in the graph.

Input:

n - the number of vertices in the graph, where (2 <= n <= 100). Each vertex is labeled from 0 to n - 1.
edges - a list of tuples, each representing a directed edge in the form (u, v, w), where u is the source vertex, v is the destination vertex, and w is the weight of the edge, where (1 <= w <= 10).
src - the source vertex from which to start the algorithm, where (0 <= src < n).
Note: If a vertex is unreachable from the source vertex, the shortest path distance for the unreachable vertex should be -1.

Input:
n = 5
edges = [[0,1,10], [0,2,3], [1,3,2], [2,1,4], [2,3,8], [2,4,2], [3,4,5]]
src = 0

Output:
{{0:0}, {1:7}, {2:3}, {3:9}, {4:5}}

A
import collections
class Solution:
    def shortestPath(self, n: int, edges: List[List[int]], src: int) -> Dict[int, int]:
        adj = collections.defaultdict(list)
        for u, v, w in edges:
            adj[u].append((v, w))
        res = {}

        minHeap = [(0, src)] #0 cost to reach src, and start at src

        while minHeap:
            w1, n1 = heapq.heappop(minHeap)
            if n1 in res:
                continue
            res[n1] = w1

            for neiNode, neiW in adj[n1]:
                if neiNode not in res:
                    heapq.heappush(minHeap, (w1 + neiW, neiNode))
        
        for i in range(n):
            if i not in res:
                res[i] = -1
        return res
        #O(V ^ 2 log V) -> O(E log V)
        #O(V + E) -> O(E)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Longest String Chain

You are given an array of words where each word consists of lowercase English letters.

wordA is a predecessor of wordB if and only if we can insert exactly one letter anywhere in wordA without changing the order of the other characters to make it equal to wordB.

For example, “abc” is a predecessor of “abac”, while “cba” is not a predecessor of “bcad”.
A word chain is a sequence of words [word1, word2, …, wordk] with k >= 1, where word1 is a predecessor of word2, word2 is a predecessor of word3, and so on. A single word is trivially a word chain with k == 1.

Return the length of the longest possible word chain with words chosen from the given list of words.

Input: words = [“a”,”b”,”ba”,”bca”,”bda”,”bdca”]
Output: 4
Explanation: One of the longest word chains is [“a”,”ba”,”bda”,”bdca”].
Example 2:

A
class Solution:
    def longestStrChain(self, words: List[str]) -> int:
        dp = {} #index of the word: max length of chain starting from that as the LONGEST word of that chain
        #reverse thinking: we start with longest word then shrink it down.
        wordMap = {} #map each word to the index of that word in words
        words.sort(key = lambda x: -len(x)) #sort by length of longest word
        for i, w in enumerate(words):
            wordMap[w] = i
        #index of the word
        def dfs(i):
            #this base case isn't needed since the conditional in for loop
            #will filter out, but sure have this here it's ok.
            if i >= len(words):
                return 0
            if i in dp:
                return dp[i]
            res = 1
            #try deleting a word anywhere in the current word and see what happens
            word = words[i]
            for j in range(len(word)):
                newWord = word[:j] + word[j + 1:]
                if newWord in wordMap:
                    res = max(res, 1 + dfs(wordMap[newWord]))
            dp[i] = res
            return res
        for i in range(len(words)):
            dfs(i)
        return max(dp.values())
        #O(n log n + n * l ^ 2)
        #O(n)

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

Find the Difference
You are given two strings s and t.

String t is generated by random shuffling string s and then add one more letter at a random position.

Return the letter that was added to t.

Input: s = “abcd”, t = “abcde”
Output: “e”
Explanation: ‘e’ is the letter that was added.

A
class Solution:
    def findTheDifference(self, s: str, t: str) -> str:
        countS = {}
        countT = {}
        for c in s:
            countS[c] = countS.get(c, 0) + 1
        
        for c in t:
            countT[c] = countT.get(c, 0) + 1
        for c in t:
            if c not in countS or countS[c] < countT[c]:
                return c
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Champagne Tower

We stack glasses in a pyramid, where the first row has 1 glass, the second row has 2 glasses, and so on until the 100th row. Each glass holds one cup of champagne.

Then, some champagne is poured into the first glass at the top. When the topmost glass is full, any excess liquid poured will fall equally to the glass immediately to the left and right of it. When those glasses become full, any excess champagne will fall equally to the left and right of those glasses, and so on. (A glass at the bottom row has its excess champagne fall on the floor.)

For example, after one cup of champagne is poured, the top most glass is full. After two cups of champagne are poured, the two glasses on the second row are half full. After three cups of champagne are poured, those two cups become full - there are 3 full glasses total now. After four cups of champagne are poured, the third row has the middle glass half full, and the two outside glasses are a quarter full, as pictured below.

Input: poured = 2, query_row = 1, query_glass = 1
Output: 0.50000
Explanation: We poured 2 cups of champange to the top glass of the tower (which is indexed as (0, 0)). There is one cup of excess liquid. The glass indexed as (1, 0) and the glass indexed as (1, 1) will share the excess liquid equally, and each will get half cup of champange.

A
class Solution:
    def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
        flow = [poured]
        for row in range(1, query_row + 1):
            curFlow = [0] * (row + 1)
            for i in range(len(flow)):
                extra = flow[i] - 1
                if extra > 0:
                    curFlow[i] += extra / 2
                    curFlow[i + 1] += extra / 2
            flow = curFlow
        #If the flow is > 1, then we take 1 as the amount in this glass
        #If the flow is < 1, then the flow is the amount of liquid in this glass.
        return min(1, flow[query_glass])
        #O(n ^ 2) where n is the size of the query row
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Sort Array By Parity

Given an integer array nums, move all the even integers at the beginning of the array followed by all the odd integers.

Return any array that satisfies this condition.

Input: nums = [3,1,2,4]
Output: [2,4,3,1]
Explanation: The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted.

A
class Solution:
    def sortArrayByParity(self, nums: List[int]) -> List[int]:
        l = 0
        for r in range(len(nums)):
            if nums[r] % 2 == 0:
                nums[l], nums[r] = nums[r], nums[l]
                l += 1
        return nums
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Monotonic Array

An array is monotonic if it is either monotone increasing or monotone decreasing.

An array nums is monotone increasing if for all i <= j, nums[i] <= nums[j]. An array nums is monotone decreasing if for all i <= j, nums[i] >= nums[j].

Given an integer array nums, return true if the given array is monotonic, or false otherwise.

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

Input: nums = [6,5,4,4]
Output: true

A
class Solution:
    def isMonotonic(self, nums: List[int]) -> bool:
        increasing, decreasing = True, True #Assume inc and dec both true
        for i in range(len(nums) - 1):
            if not(nums[i + 1] >= nums[i]):
                increasing = False
            if not(nums[i + 1] <= nums[i]):
                decreasing = False
        return increasing or decreasing #either inc, or dec, or both if all equal elts
        #O(n)
        #O(1)
24
Q

remove-colored-pieces-if-both-neighbors-are-the-same-color

There are n pieces arranged in a line, and each piece is colored either by ‘A’ or by ‘B’. You are given a string colors of length n where colors[i] is the color of the ith piece.

Alice and Bob are playing a game where they take alternating turns removing pieces from the line. In this game, Alice moves first.

Alice is only allowed to remove a piece colored ‘A’ if both its neighbors are also colored ‘A’. She is not allowed to remove pieces that are colored ‘B’.
Bob is only allowed to remove a piece colored ‘B’ if both its neighbors are also colored ‘B’. He is not allowed to remove pieces that are colored ‘A’.
Alice and Bob cannot remove pieces from the edge of the line.
If a player cannot make a move on their turn, that player loses and the other player wins.
Assuming Alice and Bob play optimally, return true if Alice wins, or return false if Bob wins.

Input: colors = “AAABABB”
Output: true
Explanation:
AAABABB -> AABABB
Alice moves first.
She removes the second ‘A’ from the left since that is the only ‘A’ whose neighbors are both ‘A’.

Now it’s Bob’s turn.
Bob cannot make a move on his turn since there are no ‘B’s whose neighbors are both ‘B’.
Thus, Alice wins, so return true.

A
class Solution:
    def winnerOfGame(self, colors: str) -> bool:
        alice = 0
        bob = 0
        #Can only remove an "A" if chain of 3 As or more, same for Bob.

        for i in range(1, len(colors) - 1):
            if colors[i] == colors[i - 1] == colors[i + 1]:
                if colors[i] == "A":
                    alice += 1
                else:
                    bob += 1
        return alice > bob #if equal, bob wins since alice goes first.
        #O(n) #sliding window of size 3
        #O(1)
25
Q

Number of Good Pairs

Given an array of integers nums, return the number of good pairs.

A pair (i, j) is called good if nums[i] == nums[j] and i < j.

Input: nums = [1,2,3,1,1,3]
Output: 4
Explanation: There are 4 good pairs (0,3), (0,4), (3,4), (2,5) 0-indexed.

A
class Solution:
    def numIdenticalPairs(self, nums: List[int]) -> int:
        #Math solution
        # counts = {}
        # for n in nums:
        #     counts[n] = counts.get(n, 0) + 1
        # res = 0
        # for n, c in counts.items():
        #     res += c * (c - 1) // 2
        # return res
        #Normal Solution:
        res = 0
        counts = {} #maps n to the count of that
        for n in nums:
            if n in counts:
                res += counts[n]
            #1 if new elt, otherwise increment
            counts[n] = counts.get(n, 0) + 1
        return res
        #O(n)
        #O(n)
26
Q

Majority Element II

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

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

A
class Solution:
    def majorityElement(self, nums: List[int]) -> List[int]:
        #n/c times, maintain a hashmap of size c - 1.
        #if exceeds size c - 1, then we delete from it

        counts = defaultdict(int)
        for n in nums:
            counts[n] += 1
            if len(counts) <= 2:
                continue
            newCounts = defaultdict(int)
            for n, c in counts.items():
                if c > 1: #it's about to be decremented, so has to be > 1 to persist
                    newCounts[n] = c - 1
            counts = newCounts
        res = []
        #everything in counts is a potential candidate. Need to actually check by counting
        for n in counts:
            if nums.count(n) > len(nums) // 3:
                res.append(n)
        return res
        #O(n)
        #O(1)                
        
27
Q

Pascal’s Triangle II

Given an integer rowIndex, return the rowIndexth (0-indexed) row of the Pascal’s triangle.

In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:

Input: rowIndex = 3
Output: [1,3,3,1]

A
class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        res = [1]
        for i in range(1, rowIndex + 1):
            nextRow = [0] * (len(res) + 1)
            for j in range(len(res)):
                nextRow[j] += res[j]
                nextRow[j + 1] += res[j]
            res = nextRow
        return res
        #O(n ** 2) #n rows, n time to go through each
        #O(n)
        
28
Q

Pascal’s Triangle (propagate approach)

Given an integer numRows, return the first numRows of Pascal’s triangle.

In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:

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

A
class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = [[1]]
        #think in terms of indices
        #numRows 5 means we want indexes 0 to 4, so we do range(1, 5)
        for r in range(1, numRows): 
            curRow = res[-1]
            newRow = [0] * (len(curRow) + 1)
            for j in range(len(curRow)):
                newRow[j] += curRow[j]
                newRow[j + 1] += curRow[j]
            res.append(newRow)
        return res
        #O(n ** 2)
        #O(n ** 2) for res
29
Q

Number of Flowers in Full Bloom

You are given a 0-indexed 2D integer array flowers, where flowers[i] = [starti, endi] means the ith flower will be in full bloom from starti to endi (inclusive). You are also given a 0-indexed integer array people of size n, where people[i] is the time that the ith person will arrive to see the flowers.

Return an integer array answer of size n, where answer[i] is the number of flowers that are in full bloom when the ith person arrives.

Input: flowers = [[1,6],[3,7],[9,12],[4,13]], people = [2,3,7,11]
Output: [1,2,2,2]
Explanation: The figure above shows the times when the flowers are in full bloom and when the people arrive.
For each person, we return the number of flowers in full bloom during their arrival.

A
class Solution:
    def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]:
        sortedPeople = [(p, i) for i, p in enumerate(people)]
        sortedPeople.sort()

        starts = [f[0] for f in flowers]
        ends = [f[1] for f in flowers]
        heapq.heapify(starts)
        heapq.heapify(ends)

        res = [0] * len(people)

        count = 0
        for p, i in sortedPeople:
            while starts and starts[0] <= p:
                heapq.heappop(starts)
                count += 1
            while ends and ends[0] < p:
                heapq.heappop(ends)
                count -= 1
            res[i] = count
        return res
        # O(p log p + f log f). Sorting people. heap operations on flowers
        # O(p + f)
        
30
Q

Find in Mountain Array

You may recall that an array arr is a mountain array if and only if:

arr.length >= 3
There exists some i with 0 < i < arr.length - 1 such that:
arr[0] < arr[1] < … < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > … > arr[arr.length - 1]
Given a mountain array mountainArr, return the minimum index such that mountainArr.get(index) == target. If such an index does not exist, return -1.

You cannot access the mountain array directly. You may only access the array using a MountainArray interface:

MountainArray.get(k) returns the element of the array at index k (0-indexed).
MountainArray.length() returns the length of the array.
Submissions making more than 100 calls to MountainArray.get will be judged Wrong Answer. Also, any solutions that attempt to circumvent the judge will result in disqualification.

Input: array = [1,2,3,4,5,3,1], target = 3
Output: 2
Explanation: 3 exists in the array, at index=2 and index=5. Return the minimum index, which is 2.

A
# """
# This is MountainArray's API interface.
# You should not implement it, or speculate about its implementation
# """
#class MountainArray:
#    def get(self, index: int) -> int:
#    def length(self) -> int:

class Solution:
    def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int:

        length = mountain_arr.length()
        #Find the peak element
        l, r = 1, length - 2
        peakIndex = -1
        while l <= r:
            m = l + (r - l) // 2
            left, mid, right = mountain_arr.get(m - 1), mountain_arr.get(m), mountain_arr.get(m + 1)
            
            if left < mid and mid > right:
                peakIndex = m
                break
            elif left < mid < right:
                l = m + 1
            else:
                r = m - 1
        
        #Find elt on the left partition
        l, r = 0, peakIndex
        while l <= r:
            m = l + (r - l) // 2
            mid = mountain_arr.get(m)
            if mid < target:
                l = m + 1
            elif mid > target:
                r = m - 1
            else:
                return m
        
        #Find elt on right partition
        l, r = peakIndex, length - 1
        while l <= r:
            m = l + (r - l) // 2
            mid = mountain_arr.get(m)
            if mid < target:
                r = m - 1
            elif mid > target:
                l = m + 1
            else:
                return m
        return -1
        #O(log n)
        #O(1)      
31
Q

Power of Four

Given an integer n, return true if it is a power of four. Otherwise, return false.

An integer n is a power of four, if there exists an integer x such that n == 4^x

Example 1:

Input: n = 16
Output: true
Example 2:

Input: n = 5
Output: false

A
class Solution:
    def isPowerOfFour(self, n: int) -> bool:
        """
        n = 4^x
        log_4(n) = x * log_4(4)
        x = log_4(n)
        so if x is a positive integer, then can return True
        """
        return n > 0 and log(n, 4) % 1 == 0
        #O(log_4 {n})
        #O(1)

        
32
Q

Backspace String Compare

Given two strings s and t, return true if they are equal when both are typed into empty text editors. ‘#’ means a backspace character.

Note that after backspacing an empty text, the text will continue empty.

Input: s = “ab#c”, t = “ad#c”
Output: true
Explanation: Both s and t become “ac”.

A
class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        def nextValidIndex(str, index):
            backspaces = 0
            while index >= 0:
                if str[index] != "#" and backspaces == 0:
                    break
                elif str[index] == "#":
                    backspaces += 1
                else:
                    backspaces -= 1
                index -= 1
            return index #can be -1 if keeps going
        indexS, indexT = len(s) - 1, len(t) - 1
        while indexS >= 0 or indexT >= 0:
            indexS = nextValidIndex(s, indexS)
            indexT = nextValidIndex(t, indexT)
            charS = s[indexS] if indexS >= 0 else ""
            charT = t[indexT] if indexT >= 0 else ""
            if charS != charT:
                return False
            indexS -= 1
            indexT -= 1
        return True
        """
        stackS, stackT = [], []
        for i in range(len(s)):
            if s[i] == "#":
                if stackS:
                    stackS.pop()
            else:
                stackS.append(s[i])
        for i in range(len(t)):
            if t[i] == "#":
                if stackT:
                    stackT.pop()
            else:
                stackT.append(t[i])
        return stackS == stackT
        """
        #O(n)
        #O(1)
        
33
Q

Number of Ways to Stay in the Same Place After Some Steps

You have a pointer at index 0 in an array of size arrLen. At each step, you can move 1 position to the left, 1 position to the right in the array, or stay in the same place (The pointer should not be placed outside the array at any time).

Given two integers steps and arrLen, return the number of ways such that your pointer is still at index 0 after exactly steps steps. Since the answer may be too large, return it modulo 10^9 + 7.

Input: steps = 3, arrLen = 2
Output: 4
Explanation: There are 4 differents ways to stay at index 0 after 3 steps.
Right, Left, Stay
Stay, Right, Left
Right, Stay, Left
Stay, Stay, Stay

A
class Solution:
    def numWays(self, steps: int, arrLen: int) -> int:
        dp = {} #(i, remainingSteps) -> number of ways
        def dfs(i, remainingSteps):
            if remainingSteps == 0:
                return i == 0
            if (i, remainingSteps) in dp:
                return dp[(i, remainingSteps)]
            res = dfs(i, remainingSteps - 1) % (10 ** 9 + 7)
            if i + 1 < arrLen:
                res = (res + dfs(i + 1, remainingSteps - 1)) % (10 ** 9 + 7)
            if i - 1 >= 0:
                res = (res + dfs(i - 1, remainingSteps - 1)) % (10 ** 9 + 7)
            dp[(i, remainingSteps)] = res
            return res
        return dfs(0, steps)
        #n number of steps, m length of array
        #O(n * min(n, m)) #the range index i traverses is minimum of
        #(length of array, number of steps)
        #O(n * min(n, m))

            
34
Q

Parallel Courses III
You are given an integer n, which indicates that there are n courses labeled from 1 to n. You are also given a 2D integer array relations where relations[j] = [prevCoursej, nextCoursej] denotes that course prevCoursej has to be completed before course nextCoursej (prerequisite relationship). Furthermore, you are given a 0-indexed integer array time where time[i] denotes how many months it takes to complete the (i+1)th course.

You must find the minimum number of months needed to complete all the courses following these rules:

You may start taking a course at any time if the prerequisites are met.
Any number of courses can be taken at the same time.
Return the minimum number of months needed to complete all the courses.

Note: The test cases are generated such that it is possible to complete every course (i.e., the graph is a directed acyclic graph).

Input: n = 3, relations = [[1,3],[2,3]], time = [3,2,5]
Output: 8
Explanation: The figure above represents the given graph and the time required to complete each course.
We start course 1 and course 2 simultaneously at month 0.
Course 1 takes 3 months and course 2 takes 2 months to complete respectively.
Thus, the earliest time we can start course 3 is at month 3, and the total time required is 3 + 5 = 8 months.

A
class Solution:
    def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int:
        dp = {} #node:min # of months needed for to complete that course
        adj = defaultdict(list) #node to directed neighbor
        for cur, nei in relations:
            adj[cur].append(nei)
        def dfs(i):
            if i in dp:
                return dp[i]
            res = time[i - 1] #this current node at least takes some time
            for nei in adj[i]:
                res = max(res, time[i - 1] + dfs(nei))
            dp[i] = res
            return res
        for i in range(1, n + 1):
            dfs(i)
        return max(dp.values())
        #O(V + E)
        #O(V + E)
        
            
        
35
Q

Validate Binary Tree Nodes
You have n binary tree nodes numbered from 0 to n - 1 where node i has two children leftChild[i] and rightChild[i], return true if and only if all the given nodes form exactly one valid binary tree.

If node i has no left child then leftChild[i] will equal -1, similarly for the right child.

Note that the nodes have no values and that we only use the node numbers in this problem.

Input: n = 4, leftChild = [1,-1,3,-1], rightChild = [2,-1,-1,-1]
Output: true

A
class Solution:
    def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool:
        hasParent = set(leftChild + rightChild) #all of the children
        hasParent.discard(-1) #join all the nodes that have a parent

        #if every node has a parent, then it's not a valid tree since there's no root
        if len(hasParent) == n:
            return False
        #Find the root
        root = -1
        for i in range(n):
            if i not in hasParent:
                root = i
                break
        visit = set()
        def dfs(i):
            if i == -1: #reached a None
                return True 
            if i in visit:
                return False
            visit.add(i)
            return dfs(leftChild[i]) and dfs(rightChild[i])
        #Validate no cycles and visited every node
        return dfs(root) and len(visit) == n
        #O(V + E)
        #O(V + E)
36
Q

Painting the Walls

You are given two 0-indexed integer arrays, cost and time, of size n representing the costs and the time taken to paint n different walls respectively. There are two painters available:

A paid painter that paints the ith wall in time[i] units of time and takes cost[i] units of money.
A free painter that paints any wall in 1 unit of time at a cost of 0. But the free painter can only be used if the paid painter is already occupied.
Return the minimum amount of money required to paint the n walls.

Input: cost = [1,2,3,2], time = [1,2,3,2]
Output: 3
Explanation: The walls at index 0 and 1 will be painted by the paid painter, and it will take 3 units of time; meanwhile, the free painter will paint the walls at index 2 and 3, free of cost in 2 units of time. Thus, the total cost is 1 + 2 = 3.

A
class Solution:
    def paintWalls(self, cost: List[int], time: List[int]) -> int:
        dp = {} #(index, number of remaining walls for paid painter) -> cost required
        def dfs(i, remain):
            if remain <= 0:
                return 0
            #Reached end of array but still have walls remaining
            if i == len(cost):
                return float('inf')
            if (i, remain) in dp:
                return dp[(i, remain)]
            #minus 1 for current way. In time[i], free painters can paint those walls, so remain drops by time[i]
            paint = cost[i] + dfs(i + 1, remain - time[i] - 1)
            skip = dfs(i + 1, remain)
            dp[(i, remain)] = min(paint, skip)
            return dp[(i, remain)]
        return dfs(0, len(cost))
        #O(n * n)
        #O(n * n)
37
Q

Flatten Nested List Iterator
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<NestedInteger> 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:</NestedInteger>

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

A

”””
# This is the interface that allows for creating nested lists.
# You should not im``plement it, or speculate about its implementation
# “””
#class NestedInteger:
# def isInteger(self) -> bool:
# “””
# @return True if this NestedInteger holds a single integer, rather than a nested list.
# “””
#
# def getInteger(self) -> int:
# “””
# @return the single integer that this NestedInteger holds, if it holds a single integer
# Return None if this NestedInteger holds a nested list
# “””
#
# def getList(self) -> [NestedInteger]:
# “””
# @return the nested list that this NestedInteger holds, if it holds a nested list
# Return None if this NestedInteger holds a single integer
# “””

class NestedIterator:
def dfs(self, nested):
for n in nested:
if n.isInteger():
self.q.append(n.getInteger())
else:
self.dfs(n.getList())
def __init__(self, nestedList: [NestedInteger]):
self.q = deque()
self.dfs(nestedList)

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

def hasNext(self) -> bool:
    return len(self.q) > 0
#O(n)
#O(n)

Your NestedIterator object will be instantiated and called as such:
# i, v = NestedIterator(nestedList), []
# while i.hasNext(): v.append(i.next())

38
Q

Minimum Number of Operations to Make Array Continuous

You are given an integer array nums. In one operation, you can replace any element in nums with any integer.

nums is considered continuous if both of the following conditions are fulfilled:

All elements in nums are unique.
The difference between the maximum element and the minimum element in nums equals nums.length - 1.
For example, nums = [4, 2, 5, 3] is continuous, but nums = [1, 2, 3, 5, 6] is not continuous.

Return the minimum number of operations to make nums continuous.

Input: nums = [1,2,3,5,6]
Output: 1
Explanation: One possible solution is to change the last element to 4.
The resulting array is [1,2,3,5,4], which is continuous.

A
class Solution:
    def minOperations(self, nums: List[int]) -> int:
        length = len(nums)
        nums = sorted(set(nums))
        res = length

        r = 0
        for l in range(len(nums)):
            #Valid range of numbers is [nums[l], nums[l] + length - 1]
            #Have right pointer exceed that
            while r < len(nums) and nums[r] < nums[l] + length:
                r += 1
            window = r - l #no +1 since right exceeds window
            res = min(res, length - window)
        return res
        #O(n log n)
        #O(n) for set of nums
39
Q

Maximum Score of a Good Subarray
You are given an array of integers nums (0-indexed) and an integer k.

The score of a subarray (i, j) is defined as min(nums[i], nums[i+1], …, nums[j]) * (j - i + 1). A good subarray is a subarray where i <= k <= j.

Return the maximum possible score of a good subarray.

Input: nums = [1,4,3,7,4,5], k = 3
Output: 15
Explanation: The optimal subarray is (1, 5) with a score of min(4,3,7,4,5) * (5-1+1) = 3 * 5 = 15.

A
class Solution:
    def maximumScore(self, nums: List[int], k: int) -> int:
        res = nums[k]
        curMin = nums[k]
        l, r = k, k
        #Keep going until both pointers finally at edges
        while l > 0 or r < len(nums) - 1:
            left = nums[l - 1] if l - 1 >= 0 else 0
            right = nums[r + 1] if r + 1 < len(nums) else 0

            if left > right:
                l -= 1
                curMin = min(curMin, nums[l])
            else:
                r += 1
                curMin = min(curMin, nums[r])
            res = max(res, curMin * (r - l + 1))
        return res
        #O(n)
        #O(1)
40
Q

Find Largest Value in Each Tree Row

Given the root of a binary tree, return an array of the largest value in each row of the tree (0-indexed).

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

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        q = deque([root])
        res = []
        while q:
            curMax = q[0].val
            for _ in range(len(q)):
                cur = q.popleft()
                curMax = max(curMax, cur.val)

                if cur.left:
                    q.append(cur.left)
                if cur.right:
                    q.append(cur.right)
            res.append(curMax)
        return res
        #O(n)
        #O(n)
        
41
Q

K-th Symbol in Grammar

We build a table of n rows (1-indexed). We start by writing 0 in the 1st row. Now in every subsequent row, we look at the previous row and replace each occurrence of 0 with 01, and each occurrence of 1 with 10.

For example, for n = 3, the 1st row is 0, the 2nd row is 01, and the 3rd row is 0110.
Given two integer n and k, return the kth (1-indexed) symbol in the nth row of a table of n rows.

Input: n = 2, k = 2
Output: 1
Explanation:
row 1: 0
row 2: 01

A
class Solution:
    def kthGrammar(self, n: int, k: int) -> int:
        l, r = 1, 2 ** (n - 1)
        cur = 0
        #0
        #01
        #1
        #10
        for _ in range(2, n + 1):
            m = l + (r - l) // 2
            if k <= m:
                r = m
            else:
                cur = 0 if cur else 1
                l = m + 1
        return cur
        #O(log 2**(n - 1)) since the range is 1 to 2^ (n- 1)
        #O(1)
42
Q

Constrained Subsequence Sum

Given an integer array nums and an integer k, return the maximum sum of a non-empty subsequence of that array such that for every two consecutive integers in the subsequence, nums[i] and nums[j], where i < j, the condition j - i <= k is satisfied.

A subsequence of an array is obtained by deleting some number of elements (can be zero) from the array, leaving the remaining elements in their original order.

Input: nums = [10,2,-10,5,20], k = 2
Output: 37
Explanation: The subsequence is [10, 2, 5, 20].

A
class Solution:
    def constrainedSubsetSum(self, nums: List[int], k: int) -> int:
        maxHeap = [[-nums[0], 0]] #(maxSumIncludingEltAtIndexI, i)
        res = nums[0]
        for i in range(1, len(nums)):
            while maxHeap and i - maxHeap[0][1] > k:
                heapq.heappop(maxHeap)

            #maxSum can just be the element itself if stuff before is negative
            #Otherwise, we try to sum it up with something before that's valid in the heap
            maxSum = max(nums[i], nums[i] - maxHeap[0][0])
            res = max(res, maxSum)
            heapq.heappush(maxHeap, [-maxSum, i])
        return res
        #O(n log n) #heap size n, log n per heap op
        #O(n) #for heap
        
43
Q

Largest 3-Same-Digit Number in String

You are given a string num representing a large integer. An integer is good if it meets the following conditions:

It is a substring of num with length 3.
It consists of only one unique digit.
Return the maximum good integer as a string or an empty string “” if no such integer exists.

Note:

A substring is a contiguous sequence of characters within a string.
There may be leading zeroes in num or a good integer.

Input: num = “6777133339”
Output: “777”
Explanation: There are two distinct good integers: “777” and “333”.
“777” is the largest, so we return “777”.

A
class Solution:
    def largestGoodInteger(self, num: str) -> str:
        res = "0"
        for i in range(len(num) - 2):
            if num[i] == num[i + 1] == num[i + 2]:
                res = max(res, num[i: i + 3])
        return res if res != "0" else ""
        #O(n)
        #O(1)
44
Q

Find Words That Can Be Formed by Characters

You are given an array of strings words and a string chars.

A string is good if it can be formed by characters from chars (each character can only be used once).

Return the sum of lengths of all good strings in words.

Input: words = [“cat”,”bt”,”hat”,”tree”], chars = “atach”
Output: 6
Explanation: The strings that can be formed are “cat” and “hat” so the answer is 3 + 3 = 6.

A
class Solution:
    def countCharacters(self, words: List[str], chars: str) -> int:
        charCount = Counter(chars)
        res = 0
        for w in words:
            wordCount = defaultdict(int)
            good = True
            for c in w:
                wordCount[c] += 1
                if c not in charCount or wordCount[c] > charCount[c]:
                    good = False
                    break
            if good:
                res += len(w)
        return res
        #O(n + m * avg length of words) #m number of words. n number of chars
        #O(26) -> O(1)
45
Q

maximum-element-after-decreasing-and-rearranging/

You are given an array of positive integers arr. Perform some operations (possibly none) on arr so that it satisfies these conditions:

The value of the first element in arr must be 1.
The absolute difference between any 2 adjacent elements must be less than or equal to 1. In other words, abs(arr[i] - arr[i - 1]) <= 1 for each i where 1 <= i < arr.length (0-indexed). abs(x) is the absolute value of x.
There are 2 types of operations that you can perform any number of times:

Decrease the value of any element of arr to a smaller positive integer.
Rearrange the elements of arr to be in any order.
Return the maximum possible value of an element in arr after performing the operations to satisfy the conditions.

Input: arr = [2,2,1,2,1]
Output: 2
Explanation:
We can satisfy the conditions by rearranging arr so it becomes [1,2,2,2,1].
The largest element in arr is 2.

A
class Solution:
    def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int:
        arr.sort()
        res = 0

        for n in arr:
            res = min(res + 1, n) 
        return res
        #O(n log n)
        #O(1)
46
Q

Count of Matches in Tournament
You are given an integer n, the number of teams in a tournament that has strange rules:

If the current number of teams is even, each team gets paired with another team. A total of n / 2 matches are played, and n / 2 teams advance to the next round.
If the current number of teams is odd, one team randomly advances in the tournament, and the rest gets paired. A total of (n - 1) / 2 matches are played, and (n - 1) / 2 + 1 teams advance to the next round.
Return the number of matches played in the tournament until a winner is decided.

Input: n = 7
Output: 6
Explanation: Details of the tournament:
- 1st Round: Teams = 7, Matches = 3, and 4 teams advance.
- 2nd Round: Teams = 4, Matches = 2, and 2 teams advance.
- 3rd Round: Teams = 2, Matches = 1, and 1 team is declared the winner.
Total number of matches = 3 + 2 + 1 = 6.

A

class Solution:
def numberOfMatches(self, n: int) -> int:
res = 0
while n > 1:
res += n // 2
n = ceil(n / 2)
return res
#O(log n)
#O(1)

    # Solution 2:
    # #Because n - 1 teams get eliminated, and each match only eliminates 1 person.
    # #Example: 2 teams -> 1 match, 3 teams -> 2 matches.
    # return n - 1
47
Q

Calculate Money in Leetcode Bank (simulation)

Hercy wants to save money for his first car. He puts money in the Leetcode bank every day.

He starts by putting in $1 on Monday, the first day. Every day from Tuesday to Sunday, he will put in $1 more than the day before. On every subsequent Monday, he will put in $1 more than the previous Monday.
Given n, return the total amount of money he will have in the Leetcode bank at the end of the nth day.

Input: n = 10
Output: 37
Explanation: After the 10th day, the total is (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4) = 37. Notice that on the 2nd Monday, Hercy only puts in $2.

A
class Solution:
    def totalMoney(self, n: int) -> int:
      #end of week 1: 28
      #end of week 2: 35
      #end of week 3: etc.
      #Gauss Sum: so do (low + high) * (# elts in sequence) // 2
      #In this case, # elts is #of full weeks.
      weeks = n // 7 #full weeks
      low = 28
      high = 28 + 7 * (weeks - 1)

      res = ((low + high) * weeks) // 2

      days = n % 7
      deposit = 1 + weeks #so if 2 full weeks, then start of week 3 is 1 + 2 = 3 as initial deposit 
      for i in range(days):
        res += deposit
        deposit += 1
      return res
      #O(1)
      #O(1)

        # deposit = 1
        # res = 0
        # days = 0

        # while days < n:
        #     res += deposit
        #     deposit += 1
        #     days += 1
        #     if days % 7 == 0: #reached a new week
        #         deposit = days // 7 + 1
        # return res
        #O(n)
        #O(1)
48
Q

Knight Dialer

The chess knight has a unique movement, it may move two squares vertically and one square horizontally, or two squares horizontally and one square vertically (with both forming the shape of an L). The possible movements of chess knight are shown in this diagaram:

A chess knight can move as indicated in the chess diagram below:

Given an integer n, return how many distinct phone numbers of length n we can dial.

You are allowed to place the knight on any numeric cell initially and then you should perform n - 1 jumps to dial a number of length n. All jumps should be valid knight jumps.

As the answer may be very large, return the answer modulo 109 + 7.

Input: n = 2
Output: 20
Explanation: All the valid number we can dial are [04, 06, 16, 18, 27, 29, 34, 38, 40, 43, 49, 60, 61, 67, 72, 76, 81, 83, 92, 94]
Example 3:

A
class Solution:
    def knightDialer(self, n: int) -> int:
        if n == 1:
            return 10

        mod = 10 ** 9 + 7

        neighbors = {0: [4, 6], 1: [6, 8], 2: [7, 9], 3: [4, 8], 4: [0, 3, 9], 5: [], 6: [0, 1, 7], 
        7: [2, 6], 8: [1, 3], 9: [2, 4]}
        # neighbors = [[4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], [], [0, 1, 7], 
        # [2, 6], [1, 3], [2, 4]]

        dp = [1] * 10 #i: number of times land on this digit. At least one way to start

        #if n = 2, we're just going 1 more (0, 1)
        #This is number of iterations
        for i in range(n - 1):
            nextDP = [0] * 10
            for start in range(10): #0 to 9
                for nei in neighbors[start]:
                    #The number of ways to reach neighbor is number of ways to reach neighbor currently + the number of ways to reach start
                    #we use nextDP for neighbor since it could have changed. dp[n] won't change from previous iteration
                    nextDP[nei] = (nextDP[nei] + dp[start]) % mod
            dp = nextDP
        res = 0
        for n in dp:
          res = (res + n) % mod
        return res 
        #O(10 * n) -> O(n) #n as number of digits
        #O(10) -> O(1)
            
49
Q

Number of Ways to Divide a Long Corridor

Along a long library corridor, there is a line of seats and decorative plants. You are given a 0-indexed string corridor of length n consisting of letters ‘S’ and ‘P’ where each ‘S’ represents a seat and each ‘P’ represents a plant.

One room divider has already been installed to the left of index 0, and another to the right of index n - 1. Additional room dividers can be installed. For each position between indices i - 1 and i (1 <= i <= n - 1), at most one divider can be installed.

Divide the corridor into non-overlapping sections, where each section has exactly two seats with any number of plants. There may be multiple ways to perform the division. Two ways are different if there is a position with a room divider installed in the first way but not in the second way.

Return the number of ways to divide the corridor. Since the answer may be very large, return it modulo 109 + 7. If there is no way, return 0.

Input: corridor = “SSPPSPS”
Output: 3
Explanation: There are 3 different ways to divide the corridor.
The black bars in the above image indicate the two room dividers already installed.
Note that in each of the ways, each section has exactly two seats.

A
class Solution:
    def numberOfWays(self, corridor: str) -> int:
        #We use cache here to avoid memory limit exceed leetcode, but the idea is basically a dp cache with 
        #dp = {} (i, seats) -> number of ways
        cache = [[-1] * 3 for i in range(len(corridor))]
        mod = 10 ** 9 + 7
        def dfs(i, seats):
            if i == len(corridor):
                return 1 if seats == 2 else 0
            
            if cache[i][seats] != -1:
              return cache[i][seats]
            # if (i, seats) in dp:
            #     return dp[(i, seats)]
            
            res = 0
            if seats == 2:
                if corridor[i] == "S":
                    #We have to take this divider, and this new seat is part of the seats count as 1
                    res = dfs(i + 1, 1)
                else:
                    #This one is not a seat. So we can choose to put a divider here, or not,
                    res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % mod
            else:
                if corridor[i] == "S":
                    res = dfs(i + 1, seats + 1)
                else:
                    res = dfs(i + 1, seats)
            cache[i][seats] = res
            #dp[(i, seats)] = res
            # return dp[(i, seats)]
            return res
        return dfs(0, 0)
        #O(2 * n) -> O(n)
        #O(2 * n) -> O(n)
50
Q

Check If Two String Arrays are Equivalent

Given two string arrays word1 and word2, return true if the two arrays represent the same string, and false otherwise.

A string is represented by an array if the array elements concatenated in order forms the string.

Input: word1 = [“ab”, “c”], word2 = [“a”, “bc”]
Output: true
Explanation:
word1 represents string “ab” + “c” -> “abc”
word2 represents string “a” + “bc” -> “abc”
The strings are the same, so return true.

A
class Solution:
    def arrayStringsAreEqual(self, word1: List[str], word2: List[str]) -> bool:
        w1Index, w2Index = 0, 0
        i, j = 0, 0
        
        while w1Index < len(word1) and w2Index < len(word2):
            if word1[w1Index][i] != word2[w2Index][j]:
                return False
            i += 1
            j += 1
            if i == len(word1[w1Index]):
                w1Index += 1
                i = 0
            if j == len(word2[w2Index]):
                w2Index += 1
                j = 0
        if w1Index == len(word1) and w2Index == len(word2):
            return True
        return False
        #O(w1 + w2)
        #O(1)        
51
Q

Implement the Adapter design pattern.

The Adapter is a structural design pattern that allows incompatible interfaces to work together. It wraps an existing class with a new interface so that it becomes compatible with the client’s interface.

You are given completed SquareHole, Square and Circle classes. A Square fits into a SquareHole if the Square’s side length is less than or equal to the SquareHole’s length. A Circle has a radius and a Circle fits into a SquareHole if the Circle’s diameter is less than or equal to the SquareHole’s length.

Complete the implementation of the CircleToSquareAdapter class such that it adapts a Circle to a Square.

SquareHole squareHole = new SquareHole(5);

Square square = new Square(5);
squareHole.canFit(square); // true

Circle circle = new Circle(5);
CircleToSquareAdapter circleAdapter = new CircleToSquareAdapter(circle);
squareHole.canFit(circleAdapter); // false

A
class Square:
    def \_\_init\_\_(self, sideLength=0.0):
        self.sideLength = sideLength

    def getSideLength(self) -> float:
        return self.sideLength
    
class SquareHole:
    def \_\_init\_\_(self, sideLength: float):
        self.sideLength = sideLength

    def canFit(self, square: Square):
        return self.sideLength >= square.getSideLength()

class Circle:
    def \_\_init\_\_(self, radius: float):
        self.radius = radius

    def getRadius(self):
        return self.radius

#This is the implemented class
#The idea is that we can try to fit a circle into a SquareHole, since circle doesn't have concept of side length.
#So basically define it with class Square's methods.

class CircleToSquareAdapter(Square):
    def \_\_init\_\_(self, circle: Circle):
        self.circle = circle
    def getSideLength(self) -> float:
        return 2 * self.circle.getRadius()
52
Q

Implement the Factory Method design pattern.

The Factory Method is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created.

You are given code that includes a few vehicles types and their respective factories. Complete the factory method implementation such that each factory returns the correct vehicle.

VehicleFactory carFactory = new CarFactory();
VehicleFactory truckFactory = new TruckFactory();
VehicleFactory bikeFactory = new BikeFactory();

Vehicle myCar = carFactory.createVehicle();
Vehicle myTruck = truckFactory.createVehicle();
Vehicle myBike = bikeFactory.createVehicle();

myCar.getType(); // “Car”
myTruck.getType(); // “Truck”
myBike.getType(); // “Bike”

A
class Vehicle(ABC):
    @abstractmethod
    def getType(self) -> str:
        pass

class Car(Vehicle):
    def getType(self) -> str:
        return "Car"

class Bike(Vehicle):
    def getType(self) -> str:
        return "Bike"

class Truck(Vehicle):
    def getType(self) -> str:
        return "Truck"

class VehicleFactory(ABC):
    @abstractmethod
    def createVehicle(self) -> Vehicle:
        pass
#Implemented the createVehicle()
#Buttons of all these factories
class CarFactory(VehicleFactory):
    # Write your code here
    def createVehicle(self):
        return Car()

class BikeFactory(VehicleFactory):
    # Write your code here
    def createVehicle(self):
        return Bike()

class TruckFactory(VehicleFactory):
    # Write your code here
    def createVehicle(self):
        return Truck()
52
Q

Sum of Absolute Differences in a Sorted Array

You are given an integer array nums sorted in non-decreasing order.

Build and return an integer array result with the same length as nums such that result[i] is equal to the summation of absolute differences between nums[i] and all the other elements in the array.

In other words, result[i] is equal to sum(|nums[i]-nums[j]|) where 0 <= j < nums.length and j != i (0-indexed).

Input: nums = [2,3,5]
Output: [4,3,5]
Explanation: Assuming the arrays are 0-indexed, then
result[0] = |2-2| + |2-3| + |2-5| = 0 + 1 + 3 = 4,
result[1] = |3-2| + |3-3| + |3-5| = 1 + 0 + 2 = 3,
result[2] = |5-2| + |5-3| + |5-5| = 3 + 2 + 0 = 5.

A
class Solution:
    def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]:
        total = sum(nums)
        leftSum = 0
        res = []
        for i, n in enumerate(nums):
            leftSize = i
            rightSize = len(nums) - 1 - i
            rightSum = total - leftSum - n
            res.append(n * leftSize - leftSum + rightSum - n * rightSize)
            #Basically think: What is "bigger?"
            # n * leftSize will be bigger than leftSum since array is non-decreasing.
            # rightSum will be bigger than n * rightSize since array is non-decreasing, and n is something in the middle.
            #The differences are the gaps that we sum up.
            leftSum += n
        return res
53
Q

Maximum Product Difference Between Two Pairs
The product difference between two pairs (a, b) and (c, d) is defined as (a * b) - (c * d).

For example, the product difference between (5, 6) and (2, 7) is (5 * 6) - (2 * 7) = 16.
Given an integer array nums, choose four distinct indices w, x, y, and z such that the product difference between pairs (nums[w], nums[x]) and (nums[y], nums[z]) is maximized.

Return the maximum such product difference.
Input: nums = [5,6,2,7,4]
Output: 34
Explanation: We can choose indices 1 and 3 for the first pair (6, 7) and indices 2 and 4 for the second pair (2, 4).
The product difference is (6 * 7) - (2 * 4) = 34.

A
class Solution:
    def maxProductDifference(self, nums: List[int]) -> int:
        max1, max2 = 0, 0
        min1, min2 = float('inf'), float('inf')
        for n in nums:
            if n > max2:
                if n > max1:
                    max2 = max1
                    max1 = n
                else:
                    max2 = n
            if n < min2:
                if n < min1:
                    min2 = min1
                    min1 = n
                else:
                    min2 = n
        return max2 * max1 - min2 * min1
        #O(n)
        #O(1)
54
Q
A
55
Q
A