N-IO-part2 Flashcards

1
Q

Given n points on a 2D plane where points[i] = [xi, yi], Return the widest vertical area between two points such that no points are inside the area.

A vertical area is an area of fixed-width extending infinitely along the y-axis (i.e., infinite height). The widest vertical area is the one with the maximum width.

Note that points on the edge of a vertical area are not considered included in the area.

Input: points = [[8,7],[9,9],[7,4],[9,7]]
Output: 1
Explanation: Both the red and the blue area are optimal.

A
class Solution:
    def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int:
        res = 0
        points.sort()
        for i in range(len(points) - 1):
            res = max(res, points[i + 1][0] - points[i][0])
        return res
        #O(n log n)
        #O(1)
        
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Buy Two Chocolates

You are given an integer array prices representing the prices of various chocolates in a store. You are also given a single integer money, which represents your initial amount of money.

You must buy exactly two chocolates in such a way that you still have some non-negative leftover money. You would like to minimize the sum of the prices of the two chocolates you buy.

Return the amount of money you will have leftover after buying the two chocolates. If there is no way for you to buy two chocolates without ending up in debt, return money. Note that the leftover must be non-negative.

Input: prices = [1,2,2], money = 3
Output: 0
Explanation: Purchase the chocolates priced at 1 and 2 units respectively. You will have 3 - 3 = 0 units of money afterwards. Thus, we return 0.

A
class Solution:
    def buyChoco(self, prices: List[int], money: int) -> int:
        min1, min2 = float('inf'), float('inf')
        for p in prices:
            if p < min2:
                if p < min1:
                    min2 = min1
                    min1 = p
                else:
                    min2 = p
        remaining = money - (min1 + min2)
        return remaining if remaining >= 0 else money
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Path Crossing

Given a string path, where path[i] = ‘N’, ‘S’, ‘E’ or ‘W’, each representing moving one unit north, south, east, or west, respectively. You start at the origin (0, 0) on a 2D plane and walk on the path specified by path.

Return true if the path crosses itself at any point, that is, if at any time you are on a location you have previously visited. Return false otherwise.

Input: path = “NESWW”
Output: true
Explanation: Notice that the path visits the origin twice.

A
class Solution:
    def isPathCrossing(self, path: str) -> bool:
        directions = {"N": (0, 1), "S": (0, -1), "E": (1, 0), "W": (-1, 0)}
        visit = set()
        visit.add((0, 0))
        x, y = 0, 0

        for letter in path:
            dx, dy = directions[letter]
            x, y = x + dx, y + dy
            if (x, y) in visit:
                return True
            visit.add((x, y))
        return False
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Destination City

You are given the array paths, where paths[i] = [cityAi, cityBi] means there exists a direct path going from cityAi to cityBi. Return the destination city, that is, the city without any path outgoing to another city.

It is guaranteed that the graph of paths forms a line without any loop, therefore, there will be exactly one destination city.

Input: paths = [[“London”,”New York”],[“New York”,”Lima”],[“Lima”,”Sao Paulo”]]
Output: “Sao Paulo”
Explanation: Starting at “London” city you will reach “Sao Paulo” city which is the destination city. Your trip consist of: “London” -> “New York” -> “Lima” -> “Sao Paulo”.

A
class Solution:
    def destCity(self, paths: List[List[str]]) -> str:
        allCities = set([source for source, dest in paths])
        for source, dest in paths:
            if dest not in allCities:
                return dest
        #O(n)
        #O(n)
        #The idea is that collecting all the source nodes will give all cities that lead SOMEWHERE.
        #Then check destination nodes. If a destination node is not in allCities, then it is a terminal.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Minimum Changes To Make Alternating Binary String

You are given a string s consisting only of the characters ‘0’ and ‘1’. In one operation, you can change any ‘0’ to ‘1’ or vice versa.

The string is called alternating if no two adjacent characters are equal. For example, the string “010” is alternating, while the string “0100” is not.

Return the minimum number of operations needed to make s alternating.

Input: s = “0100”
Output: 1
Explanation: If you change the last character to ‘1’, s will be “0101”, which is alternating.

A
class Solution:
    def minOperations(self, s: str) -> int:
        res = 0 #number of changes needed assuming string starts at 0
        for i in range(len(s)):
            expected = str(i % 2)
            if s[i] != expected:
                res += 1
        return min(res, len(s) - res)
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Largest Substring Between Two Equal Characters

Given a string s, return the length of the longest substring between two equal characters, excluding the two characters. If there is no such substring return -1.

A substring is a contiguous sequence of characters within a string.

Input: s = “abca”
Output: 2
Explanation: The optimal substring here is “bc”.

A
class Solution:
    def maxLengthBetweenEqualCharacters(self, s: str) -> int:
        firstIndex = {}
        res = -1
        for i, c in enumerate(s):
            if c in firstIndex:
                res = max(res, i - firstIndex[c] - 1)
            else:
                firstIndex[c] = i
        return res
        #O(n)
        #O(26) -> O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Convert an Array Into a 2D Array With Conditions

You are given an integer array nums. You need to create a 2D array from nums satisfying the following conditions:

The 2D array should contain only the elements of the array nums.
Each row in the 2D array contains distinct integers.
The number of rows in the 2D array should be minimal.
Return the resulting array. If there are multiple answers, return any of them.

Note that the 2D array can have a different number of elements on each row.

Input: nums = [1,3,4,1,2,3,1]
Output: [[1,3,4,2],[1,3],[1]]
Explanation: We can create a 2D array that contains the following rows:
- 1,3,4,2
- 1,3
- 1
All elements of nums were used, and each row of the 2D array contains distinct integers, so it is a valid answer.
It can be shown that we cannot have less than 3 rows in a valid array.

A
class Solution:
    def findMatrix(self, nums: List[int]) -> List[List[int]]:
        counts = defaultdict(int)
        res = []
        for n in nums:
            row = counts[n]
            if row == len(res):
                res.append([])
            res[row].append(n)
            counts[n] += 1
        return res
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Number of Laser Beams in a Bank

Anti-theft security devices are activated inside a bank. You are given a 0-indexed binary string array bank representing the floor plan of the bank, which is an m x n 2D matrix. bank[i] represents the ith row, consisting of ‘0’s and ‘1’s. ‘0’ means the cell is empty, while’1’ means the cell has a security device.

There is one laser beam between any two security devices if both conditions are met:

The two devices are located on two different rows: r1 and r2, where r1 < r2.
For each row i where r1 < i < r2, there are no security devices in the ith row.
Laser beams are independent, i.e., one beam does not interfere nor join with another.

Return the total number of laser beams in the bank.

Input: bank = [“011001”,”000000”,”010100”,”001000”]
Output: 8
Explanation: Between each of the following device pairs, there is one beam. In total, there are 8 beams:
* bank[0][1] – bank[2][1]
* bank[0][1] – bank[2][3]
* bank[0][2] – bank[2][1]
* bank[0][2] – bank[2][3]
* bank[0][5] – bank[2][1]
* bank[0][5] – bank[2][3]
* bank[2][1] – bank[3][2]
* bank[2][3] – bank[3][2]
Note that there is no beam between any device on the 0th row with any on the 3rd row.
This is because the 2nd row contains security devices, which breaks the second condition.

A
class Solution:
    def numberOfBeams(self, bank: List[str]) -> int:
        prev = bank[0].count("1")
        res = 0
        for r in range(1, len(bank)):
            cur = bank[r].count("1")
            if cur:
                res += (prev * cur)
                prev = cur
        return res
        #O(mn)
        #O(n)
        #2 Rows. prev and current

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

Assign Cookies

Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie.

Each child i has a greed factor g[i], which is the minimum size of a cookie that the child will be content with; and each cookie j has a size s[j]. If s[j] >= g[i], we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.

Input: g = [1,2,3], s = [1,1]
Output: 1
Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3.
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.

A
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g.sort()
        s.sort()
        l, r = 0, 0
        res = 0
        while l < len(g) and r < len(s):
            if g[l] <= s[r]:
                res += 1
                l += 1
                r += 1
            else:
                r += 1
        return res
        #O(n log n + m log m + n + m)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Minimum Number of Operations to Make Array Empty

You are given a 0-indexed array nums consisting of positive integers.

There are two types of operations that you can apply on the array any number of times:

Choose two elements with equal values and delete them from the array.
Choose three elements with equal values and delete them from the array.
Return the minimum number of operations required to make the array empty, or -1 if it is not possible.

Input: nums = [2,3,3,2,2,4,2,3,4]
Output: 4
Explanation: We can apply the following operations to make the array empty:
- Apply the first operation on the elements at indices 0 and 3. The resulting array is nums = [3,3,2,4,2,3,4].
- Apply the first operation on the elements at indices 2 and 4. The resulting array is nums = [3,3,4,3,4].
- Apply the second operation on the elements at indices 0, 1, and 3. The resulting array is nums = [4,4].
- Apply the first operation on the elements at indices 0 and 1. The resulting array is nums = [].
It can be shown that we cannot make the array empty in less than 4 operations.

A
class Solution:
    def minOperations(self, nums: List[int]) -> int:
        """
        1: -1
        2: 1
        3: 1
        4: 2 ops (2 + 2)
        5: 2 ops (2 + 3)
        6: 2 ops (3 + 3)
        7; 3 ops (2 + 2 + 3)
        8: 3 ops (3 + 3 + 2)
        so the formula is simply ceil(n / 3)
        """

        counts = Counter(nums)
        res = 0
        for n, c in counts.items():
            if c == 1: #impossible if any are -1
                return -1
            res += ceil(c / 3)
        return res
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Minimum Falling Path Sum
Given an n x n array of integers matrix, return the minimum sum of any falling path through matrix.

A falling path starts at any element in the first row and chooses the element in the next row that is either directly below or diagonally left/right. Specifically, the next element from position (row, col) will be (row + 1, col - 1), (row + 1, col), or (row + 1, col + 1).

Input: matrix = [[2,1,3],[6,5,4],[7,8,9]]
Output: 13
Explanation: There are two falling paths with a minimum sum as shown.

A
class Solution:
    def minFallingPathSum(self, matrix: List[List[int]]) -> int:
        ROWS, COLS = len(matrix), len(matrix[0])

        #We do top down since we have to start at the very top
        #dp[c] is for some given row. It stores the min result so far 
        #We start at row #1. Row #0 is just the previous dp result (the first row of matrix)
        #left is matrix[r-1][c]. This means... what is the minimum sum so far up until topleft cell?
        #etc.
        for r in range(1, ROWS):
            for c in range(COLS):
                left = matrix[r - 1][c - 1] if c - 1 >= 0 else float('inf')
                mid = matrix[r - 1][c]
                right = matrix[r - 1][c + 1] if c + 1 < COLS else float('inf')
                matrix[r][c] += min(left, mid, right)
        return min(matrix[-1])
        #O(n ** 2)
        #O(1) #since overwrite input. O(N) if dp array.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Sum of Subarray Minimums

Given an array of integers arr, find the sum of min(b), where b ranges over every (contiguous) subarray of arr. Since the answer may be large, return the answer modulo 109 + 7.

Input: arr = [3,1,2,4]
Output: 17
Explanation:
Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4].
Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1.
Sum is 17.

A
class Solution:
    def sumSubarrayMins(self, arr: List[int]) -> int:
        MOD = 10 ** 9 + 7
        stack = [] #(index, num)
        res = 0

        #EXAMPLE:
        #     s[-1][0]  j i
        # 1 2 3         4 1
        # left is 3 - 2
        # right is 4 - 3
        # etc
        for i, n in enumerate(arr):
            while stack and n < stack[-1][1]:
                j, m = stack.pop()
                left = j - stack[-1][0] if stack else j + 1
                right = i - j
                res = (res + m * left * right) % MOD
            stack.append((i, n))
        #PHASE 2: stack is monotonically increasing
        #[(1, 1), (2, 2), (3, 4)]
        #In this case, go through the stack, then check the distance between
        #current elt and previous elt on stack if present, Otherwise, goes all the way
        #Until the front of array
        for i in range(len(stack)):
            j, n = stack[i]
            left = j - stack[i - 1][0] if i > 0 else j + 1
            right = len(arr) - j
            res = (res + n * left * right) % MOD
        return res
        #O(N)
        #O(N)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Pseudo-Palindromic Paths in a Binary Tree

Given a binary tree where node values are digits from 1 to 9. A path in the binary tree is said to be pseudo-palindromic if at least one permutation of the node values in the path is a palindrome.

Return the number of pseudo-palindromic paths going from the root node to leaf nodes.

Input: root = [2,3,1,3,1,null,1]
Output: 2
Explanation: The figure above represents the given binary tree. There are three paths going from the root node to leaf nodes: the red path [2,3,3], the green path [2,1,1], and the path [2,3,1]. Among these paths only red path and green path are pseudo-palindromic paths since the red path [2,3,3] can be rearranged in [3,2,3] (palindrome) and the green path [2,1,1] can be rearranged in [1,2,1] (palindrome).

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 pseudoPalindromicPaths (self, root: Optional[TreeNode]) -> int:
        counts = defaultdict(int)
        oddCount = 0
        #Palindromes have at most one odd value.
        #PREORDER TRAVERSAL.
        def dfs(root):
            nonlocal oddCount
            if not root:
                return 0

            #What to do when hit a non-null value. PROCESS CURRENT
            counts[root.val] += 1
            change = 1 if counts[root.val] % 2 else -1
            oddCount += change
            res = 0
            #if it's a leaf do this. This is part of "process current" - no need to go left and right.
            if not root.left and not root.right:
                res = 1 if oddCount <= 1 else 0
            else: #RECURSE LEFT AND PROCESS RIGHT
                res = dfs(root.left) + dfs(root.right)
            #Once if we have computed the left and right children, let's clean up the current value before popping up to parent
            #Backtrack furrent
            counts[root.val] -= 1 #clean up counts hashmap
            oddCount -= change #clean up parity
            return res
        return dfs(root)
        #O(N)
        #O(H)
        
        
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

There is an m x n grid with a ball. The ball is initially at the position [startRow, startColumn]. You are allowed to move the ball to one of the four adjacent cells in the grid (possibly out of the grid crossing the grid boundary). You can apply at most maxMove moves to the ball.

Given the five integers m, n, maxMove, startRow, startColumn, return the number of paths to move the ball out of the grid boundary. Since the answer can be very large, return it modulo 109 + 7.

Input: m = 2, n = 2, maxMove = 2, startRow = 0, startColumn = 0
Output: 6

A
class Solution:
    def findPaths(self, m: int, n: int, maxMove: int, startRow: int, startColumn: int) -> int:
        """
        # dp = [[-1] * n for r in range(m)] #(m, n): max number of ways to get outside from that location
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        dp = {}
        def dfs(r, c, numMoves):
            if r < 0 or r == m or c < 0 or c == n:
                return 1
            if numMoves == 0: #if 0 moves left and still not at boundary, return 0
                return 0
            if (r, c, numMoves) in dp:
                return dp[(r, c, numMoves)]
            res = 0
            for dr, dc in directions:
                neiR, neiC = r + dr, c + dc
                res = (res + dfs(neiR, neiC, numMoves - 1)) % (10 ** 9 + 7)
            dp[(r, c, numMoves)] = res
            return res
        return dfs(startRow, startColumn, maxMove)
        #O(mn*M) #max moves M, multiplied by dimensions of grid
        #O(mn*M)
        """
        ROWS, COLS = m, n
        dp = [[0] * COLS for r in range(ROWS)]
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        MOD = 10 ** 9 + 7
        for move in range(1, maxMove + 1):
            tmp = [[0] * COLS for r in range(ROWS)]
            for r in range(ROWS):
                for c in range(COLS):
                    for dr, dc in directions:
                        neiR, neiC = r + dr, c + dc
                        if (0 <= neiR < ROWS and 0 <= neiC < COLS):
                            tmp[r][c] = (tmp[r][c] + dp[neiR][neiC]) % MOD
                        else:
                            tmp[r][c] = (tmp[r][c] + 1) % MOD
            dp = tmp
        return dp[startRow][startColumn]
        #Runtime: O(mn*M)
        #Space: O(mn) we only need the dp grid for previous move - 1, and current move.

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

Number of Submatrices That Sum to Target

Given a matrix and a target, return the number of non-empty submatrices that sum to target.

A submatrix x1, y1, x2, y2 is the set of all cells matrix[x][y] with x1 <= x <= x2 and y1 <= y <= y2.

Two submatrices (x1, y1, x2, y2) and (x1’, y1’, x2’, y2’) are different if they have some coordinate that is different: for example, if x1 != x1’.

Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
Output: 4
Explanation: The four 1x1 submatrices that only contain 0.

A
class Solution:
    def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
        ROWS, COLS = len(matrix), len(matrix[0])

        sub_sum = [[0] * COLS for r in range(ROWS)]

        #Compute submatrix sums
        for r in range(ROWS):
            for c in range(COLS):
                top = sub_sum[r - 1][c] if r > 0 else 0
                left = sub_sum[r][c - 1] if c > 0 else 0
                top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0
                sub_sum[r][c] = matrix[r][c] + top + left - top_left
        
        res = 0
        for r1 in range(ROWS):
            for r2 in range(r1, ROWS):
                count = defaultdict(int)
                count[0] = 1
                for c in range(COLS):
                    cur_sum = sub_sum[r2][c] - (
                        sub_sum[r1 - 1][c] if r1 > 0 else 0
                    )
                    diff = cur_sum - target
                    res += count[diff]
                    count[cur_sum] += 1
        return res
        #Similar to prefix sum equals K
        #O(R ** 2 * C)
        #O(RC)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Range Sum Query 2D - Immutable

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.

Input
[“NumMatrix”, “sumRegion”, “sumRegion”, “sumRegion”]
[[[[3, 0, 1, 4, 2], [5, 6, 3, 2, 1], [1, 2, 0, 1, 5], [4, 1, 0, 1, 7], [1, 0, 3, 0, 5]]], [2, 1, 4, 3], [1, 1, 2, 2], [1, 2, 2, 4]]
Output
[null, 8, 11, 12]

A
class NumMatrix:

    def \_\_init\_\_(self, matrix: List[List[int]]):
        ROWS, COLS = len(matrix), len(matrix[0])
        self.prefixSums = [[0] * (COLS) for _ in range(ROWS)]
        for r in range(ROWS):
            for c in range(COLS):
                top = self.prefixSums[r - 1][c] if r > 0 else 0
                left = self.prefixSums[r][c - 1] if c > 0 else 0
                topLeft = self.prefixSums[r - 1][c - 1] if min(r, c) > 0 else 0
                self.prefixSums[r][c] = matrix[r][c] + top + left - topLeft

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        #Need to specify these conditionals in ternary operators, otherwise will loop around and go to -1 and do incorrect indexing.
        botRight = self.prefixSums[row2][col2]
        top = self.prefixSums[row1 - 1][col2] if row1 > 0 else 0
        left = self.prefixSums[row2][col1 - 1] if col1 > 0 else 0
        topLeft = self.prefixSums[row1 - 1][col1 - 1] if min(row1, col1) > 0 else 0
        return botRight - top - left + topLeft
    #O(mn) init, O(1) for subsequent ops
    #O(mn)

Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)
17
Q

Sequential Digits

An integer has sequential digits if and only if each digit in the number is one more than the previous digit.

Return a sorted list of all the integers in the range [low, high] inclusive that have sequential digits.

Input: low = 1000, high = 13000
Output: [1234,2345,3456,4567,5678,6789,12345]

A
class Solution:
    def sequentialDigits(self, low: int, high: int) -> List[int]:
        q = deque(range(1, 10))

        res = []
        while q:
            for _ in range(len(q)):
                cur = q.popleft()
                if low <= cur <= high:
                    res.append(cur)
                nextDigit = cur % 10 + 1
                if nextDigit < 10:
                    cur = cur * 10 + nextDigit
                    q.append(cur)
        return res
        #O(1) constant number of values. Specifically, it's 9 * max number of digits
        #Why this complexity? 1, 12, 123. If max num of digits is 3, it's 3 numbers for starting 1.
        #There are 9 starting digits.
        #O(1) constant number of valuees
18
Q

Partition Array for Maximum Sum

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.
Input: arr = [1,15,7,9,2,5,10], k = 3
Output: 84
Explanation: arr becomes [15,15,15,9,10,10,10]

A
class Solution:
    def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int:
        dp = {}
        def dfs(i):
            if i >= len(arr):
                return 0
            if i in dp:
                return dp[i]
            curMax = 0
            res = 0
            for j in range(i, min(i + k, len(arr))):
                curMax = max(curMax, arr[j])
                res = max(res, dfs(j + 1) + curMax * (j - i + 1))
            dp[i] = res
            return res
        return dfs(0)
        #O(n * k) #n values for i, each operation takes k time
        #O(n) for the dp cache
19
Q

Intersection of Two Arrays
Given two integer arrays nums1 and nums2, return an array of their intersection. Each element in the result must be unique and you may return the result in any order.

Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2]

A
class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        seen = set(nums1)
        res = []
        for n in nums2:
            if n in seen:
                res.append(n)
                seen.remove(n)
        return res
        #O(n + m)
        #O(n) where n is len(nums1)
20
Q

Bag of Tokens
You start with an initial power of power, an initial score of 0, and a bag of tokens given as an integer array tokens, where each tokens[i] denotes the value of tokeni.

Your goal is to maximize the total score by strategically playing these tokens. In one move, you can play an unplayed token in one of the two ways (but not both for the same token):

Face-up: If your current power is at least tokens[i], you may play tokeni, losing tokens[i] power and gaining 1 score.
Face-down: If your current score is at least 1, you may play tokeni, gaining tokens[i] power and losing 1 score.
Return the maximum possible score you can achieve after playing any number of tokens.

Input: tokens = [100,200,300,400], power = 200

Output: 2

Explanation: Play the tokens in this order to get a score of 2:

Play token0 (100) face-up, reducing power to 100 and increasing score to 1.
Play token3 (400) face-down, increasing power to 500 and reducing score to 0.
Play token1 (200) face-up, reducing power to 300 and increasing score to 1.
Play token2 (300) face-up, reducing power to 0 and increasing score to 2.
The maximum score achievable is 2.

A
class Solution:
    def bagOfTokensScore(self, tokens: List[int], power: int) -> int:
        tokens.sort()

        res = 0
        score = 0
        l, r = 0, len(tokens) - 1
        while l <= r:
            if power >= tokens[l]:
                power -= tokens[l]
                score += 1
                res = max(res, score)
                l += 1
            elif score > 0:
                score -= 1
                power += tokens[r]
                r -= 1
            else: #if score is 0 and power is 0
                break
        return res
        #O(n log n)
        #O(1)
        #Greedy
21
Q

Binary Subarrays With Sum
Given a binary array nums and an integer goal, return the number of non-empty subarrays with a sum goal.

A subarray is a contiguous part of the array.
Example 1:

Input: nums = [1,0,1,0,1], goal = 2
Output: 4
Explanation: The 4 subarrays are bolded and underlined below:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
Example 2:

Input: nums = [0,0,0,0,0], goal = 0
Output: 15

A
class Solution:
    def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
        def helper(x):
            if x < 0:
                return 0
            l = 0
            res = 0
            curSum = 0
            for r in range(len(nums)):
                curSum += nums[r]
                while curSum > x:
                    curSum -= nums[l]
                    l += 1
                #At this point, curSum <= goal. The number of 
                #subarrays <= goal so far is the size of the window.
                res += r - l + 1
                
            return res
        #The reason we do it this way is that for goal = 0, we miss subarrays of size
        #0. Therefore, to get # subarrays that sum to goal, we take 
        # (<= goal) - (<= goal-1)
        return helper(goal) - helper(goal - 1)
        #O(n)
        #O(1)
22
Q

Contiguous Array

Given a binary array nums, return the maximum length of a contiguous subarray with an equal number of 0 and 1.

Input: nums = [0,1,0]
Output: 2
Explanation: [0, 1] (or [1, 0]) is a longest contiguous subarray with equal number of 0 and 1.

A
class Solution:
    def findMaxLength(self, nums: List[int]) -> int:
        res = 0
        zero, one = 0, 0
        diffIndex = {}
        for i, n in enumerate(nums):
            if n == 0:
                zero += 1
            else:
                one += 1
            if one - zero not in diffIndex:
                diffIndex[one - zero] = i
            
            if one == zero:
                res = one + zero
            else:
                res = max(res, i - diffIndex[one - zero])
        return res
        #O(n)
        #O(n)
23
Q

Minimum Number of Arrows to Burst Balloons

here are some spherical balloons taped onto a flat wall that represents the XY-plane. The balloons are represented as a 2D integer array points where points[i] = [xstart, xend] denotes a balloon whose horizontal diameter stretches between xstart and xend. You do not know the exact y-coordinates of the balloons.

Arrows can be shot up directly vertically (in the positive y-direction) from different points along the x-axis. A balloon with xstart and xend is burst by an arrow shot at x if xstart <= x <= xend. There is no limit to the number of arrows that can be shot. A shot arrow keeps traveling up infinitely, bursting any balloons in its path.

Given the array points, return the minimum number of arrows that must be shot to burst all balloons.

Input: points = [[10,16],[2,8],[1,6],[7,12]]
Output: 2
Explanation: The balloons can be burst by 2 arrows:
- Shoot an arrow at x = 6, bursting the balloons [2,8] and [1,6].
- Shoot an arrow at x = 11, bursting the balloons [10,16] and [7,12].

A
class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        points.sort()
        res = len(points)
        prevEnd = points[0][1]
        for i in range(1, len(points)):
            start, end = points[i]
            #See what the overlapping section is. In next iteration, overlapping 
            #section is what we compare against for the interval after that
            if start <= prevEnd:
                res -= 1
                prevEnd = min(prevEnd, end)
            else:
                prevEnd = end
        return res
        #O(n log n)
        #O(1)
24
Q

Find All Duplicates in an Array

Given an integer array nums of length n where all the integers of nums are in the range [1, n] and each integer appears once or twice, return an array of all the integers that appears twice.

You must write an algorithm that runs in O(n) time and uses only constant extra space.
Input: nums = [4,3,2,7,8,2,3,1]
Output: [2,3]
Example 2:

A
class Solution:
    def findDuplicates(self, nums: List[int]) -> List[int]:
        #Mark value at index elt - 1 with a negative to indicate seen before
        res = []
        for n in nums:
            idx = abs(n) - 1
            if nums[idx] < 0:
                res.append(abs(n))
            nums[idx] = -abs(nums[idx])
        return res
        #O(n)
        #O(1) #res doesn't count as extra space
25
Q

First Missing Positive

Given an unsorted integer array nums. Return the smallest positive integer that is not present in nums.

You must implement an algorithm that runs in O(n) time and uses O(1) auxiliary space.

Input: nums = [1,2,0]
Output: 3
Explanation: The numbers in the range [1,2] are all in the array.

A
class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        #Phase 1: Cross out neg values by setting them to 0
        for i in range(len(nums)):
            if nums[i] < 0:
                nums[i] = 0
        #Bounds possible: values are within [1, len(nums)]
        #[0, 1, 2] -> 3, which is len(nums)

        #Phase 2: Mark presence of values by setting value at index val - 1 to 
        #negative. If it's a zero we're trying to mark, mark it with -(len(nums) + 1)
        #since that's a safe value out of bounds
        for i in range(len(nums)):
            idx = abs(nums[i]) - 1
            if idx >= 0 and idx < len(nums):
                if nums[idx] == 0:
                    nums[idx] = -(len(nums) + 1)
                else:
                    nums[idx] = -abs(nums[idx])
        
        #Phase 3. Check each value if the [1, len(nums)] range. If it's >= 0, it hasn't been visited
        #Note that equal to zero is in the condition because for example, [1, 2, 0] becomes [-1, -2, 0] 
        #meaning that zero was a natural zero not due to crossing out values. When do idx = 3 - 1 = 2, 
        #nums[2] = 0 is not a negative value, so 3 is missing.
        
        for i in range(1, len(nums) + 1):
            idx = i - 1
            if nums[idx] >= 0:
                return i
        return len(nums) + 1 #If everything here is valid (such as [1]), then 2 is the answer
        #O(n)
        #O(1)
26
Q

Make The String Great

Given a string s of lower and upper case English letters.

A good string is a string which doesn’t have two adjacent characters s[i] and s[i + 1] where:

0 <= i <= s.length - 2
s[i] is a lower-case letter and s[i + 1] is the same letter but in upper-case or vice-versa.
To make the string good, you can choose two adjacent characters that make the string bad and remove them. You can keep doing this until the string becomes good.

Return the string after making it good. The answer is guaranteed to be unique under the given constraints.

Notice that an empty string is also good.

Input: s = “leEeetcode”
Output: “leetcode”
Explanation: In the first step, either you choose i = 1 or i = 2, both will result “leEeetcode” to be reduced to “leetcode”.

Input: s = “abBAcC”
Output: “”
Explanation: We have many possible scenarios, and all lead to the same answer. For example:
“abBAcC” –> “aAcC” –> “cC” –> “”
“abBAcC” –> “abBA” –> “aA” –> “”

A
class Solution:
    def makeGood(self, s: str) -> str:
        stack = []
        for c in s:
            if stack and c != stack[-1] and c.lower() == stack[-1].lower():
                stack.pop()
            else:
                stack.append(c)
        return "".join(stack)
        #O(n)
        #O(n)
27
Q
A