Own-YT Flashcards

1
Q

LCA binary tree III. Given binary tree with references to left, right, and parents, find LCA of the two given nodes in binary tree

(similar solution to intersection of two linked lists)

A
def lowestCommonAncestor(self, a: 'Node', b: 'Node') -> 'Node':
    pointerA, pointerB = a, b
        
    while pointerA != pointerB:
        pointerA = pointerA.parent if pointerA else b
        pointerB = pointerB.parent if pointerA else a
            
    return pointerA
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Find the Celebrity
Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them.

Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: “Hi, A. Do you know B?” to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense).

You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n), your function should minimize the number of calls to knows.

Input:
2 // next n * (n - 1) lines
0 knows 1
1 does not know 0
Output: 1
Explanation:
Everyone knows 1,and 1 knows no one.

A
"""
The knows API is already defined for you.
@param a, person a
@param b, person b
@return a boolean, whether a knows b
you can call Celebrity.knows(a, b)
"""

class Solution:
    # @param {int} n a party with n people
    # @return {int} the celebrity's label or -1
    def findCelebrity(self, n):
        candidate = 0

        #Step 1: Find the potential candidate as celebrity
        for i in range(1, n):
            #If knows, no longer can be candidate, so update new potential candidate
            if Celebrity.knows(candidate, i):
                candidate = i
    
        #Step 2: Check that the candidate doesn't know anyone, and that everyone knows this candidate
            #So if candidate knows someone, OR somehow doesn't know this candidate, then return -1
        for i in range(n):
            if i == candidate:
                continue
            if Celebrity.knows(candidate, i) or not Celebrity.knows(i, candidate):
                return -1
        return candidate
        #O(n)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Buildings With an Ocean View

Given an array of integers heights of length n, indicating that there are n buildings, heights[i] represents the height of the building at the corresponding position.

To the right of a building is the ocean, and for each building, if all buildings to the right of that building are strictly lower than it, then that building has a view of the ocean.

Returns a list of indexed subscripts of all buildings with an ocean view, in ascending order, with index subscripts starting at 0.

Input:
heights = [5, 2, 3, 4]
Output:
[0, 3]
Explanation:
Building No.1 is 2 in height and Building No.2 is 3 in height and is not strictly higher than the building to its right

A
from typing import (
    List,
)

class Solution:
    """
    @param heights: An integer array
    @return: Indexs of buildings with sea view
    """
    def find_buildings(self, heights: List[int]) -> List[int]:
        # write your code here
        res = []
        maxHeight = -1 
        for i in range(len(heights) -1, -1, -1):
            if heights[i] > maxHeight:
                res.append(i)
                maxHeight = heights[i]
        return res[::-1]
        #O(n)
        #O(n) #res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Number of Visible People in a Queue

There are n people standing in a queue, and they numbered from 0 to n - 1 in left to right order. You are given an array heights of distinct integers where heights[i] represents the height of the ith person.

A person can see another person to their right in the queue if everybody in between is shorter than both of them. More formally, the ith person can see the jth person if i < j and min(heights[i], heights[j]) > max(heights[i+1], heights[i+2], …, heights[j-1]).

Return an array answer of length n where answer[i] is the number of people the ith person can see to their right in the queue.

Input: heights = [10,6,8,5,11,9]
Output: [3,1,2,1,1,0]
Explanation:
Person 0 can see person 1, 2, and 4.
Person 1 can see person 2.
Person 2 can see person 3 and 4.
Person 3 can see person 4.
Person 4 can see person 5.
Person 5 can see no one since nobody is to the right of them.

A
class Solution:
    def canSeePersonsCount(self, heights: List[int]) -> List[int]:
        res = [0] * len(heights)

        stack = [] 
        #stack will always include current height
        #as long as I am taller than the people in the stack, I will pop and increment visible
        #stack is thus monotonically increasing. we always pop smaller heights away,
        #so each time we push onto stack it gets larger.
        visible = 0
        for i in range(len(heights) - 1, -1, -1):
            while stack and heights[i] > stack[-1]:
                stack.pop()
                visible += 1
            
            #Can see the last person who's taller than me
            if stack:
                visible += 1
            res[i] = visible
            stack.append(heights[i])
            
            visible = 0 #reset visible
        return res
        #O(n)
        #O(n)

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

Range Sum of BST

Given the root node of a binary search tree and two integers low and high, return the sum of values of all nodes with a value in the inclusive range [low, high].

Input: root = [10,5,15,3,7,null,18], low = 7, high = 15
Output: 32
Explanation: Nodes 7, 10, and 15 are in the range [7, 15]. 7 + 10 + 15 = 32.

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 rangeSumBST(self, root: Optional[TreeNode], low: int, high: int) -> int:
        res = 0

        def dfs(root):
            nonlocal res
            if not root:
                return
            
            if low <= root.val <= high:
                res += root.val
            
            dfs(root.left)
            dfs(root.right)
            
        dfs(root)
        return res
        #O(n)
        #O(h)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Custom Sort String

You are given two strings order and s. All the characters of order are unique and were sorted in some custom order previously.

Permute the characters of s so that they match the order that order was sorted. More specifically, if a character x occurs before a character y in order, then x should occur before y in the permuted string.

Return any permutation of s that satisfies this property.

Input: order = “cba”, s = “abcd”
Output: “cbad”
Explanation:
“a”, “b”, “c” appear in order, so the order of “a”, “b”, “c” should be “c”, “b”, and “a”.
Since “d” does not appear in order, it can be at any position in the returned string. “dcba”, “cdba”, “cbda” are also valid outputs.

A
class Solution:
    def customSortString(self, order: str, s: str) -> str:
        counts = Counter(s)
        res = []
        for c in order:
            if c in counts:
                res.append(counts[c] * c)
                del counts[c]
        for c, count in counts.items():
            res.append(c * count)
        return "".join(res)
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Transpose Matrix

Given a 2D integer array matrix, return the transpose of matrix.

The transpose of a matrix is the matrix flipped over its main diagonal, switching the matrix’s row and column indices.

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

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

        res = [[0] * ROWS for r in range(COLS)]
        for r in range(ROWS):
            for c in range(COLS):
                res[c][r] = matrix[r][c]
        return res
        #O(mn)
        #O(mn)

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

Lowest Common Ancestor V

Given a binary tree with a root node root and an array nodes of objects of class TreeNode, you need to find the Lowest Common Ancestor (LCA, Lowest Common Ancestor) of all nodes in nodes and return it.

Where all the nodes in nodes exist in that binary tree and all the nodes in the binary tree have different values from each other.

root = {3,5,1,6,2,0,8,#,#,7,4}
nodes = [4,7]

2

A
from typing import (
    List,
)
from lintcode import (
    TreeNode,
)

"""
Definition of TreeNode:
class TreeNode:
    def \_\_init\_\_(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: The root node of a binary tree.
    @param nodes: An array of objects of class TreeNode.
    @return: The lowest common ancestor of nodes.
    """
    def lowest_common_ancestor(self, root: TreeNode, nodes: List[TreeNode]) -> TreeNode:
        # --- write your code here ---
        nodeSet = set(nodes)
        def dfs(root):
            if not root:
                return
            if root in nodeSet:
                return root
            leftSubtree = dfs(root.left)
            rightSubtree = dfs(root.right)
            if leftSubtree and rightSubtree:
                return root
            return leftSubtree or rightSubtree
        return dfs(root)
        #O(n)
        #O(n) #for nodeSet
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Diagonal Traverse

Given an m x n matrix mat, return an array of all the elements of the array in a diagonal order.

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

A
class Solution:
    def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:
        ROWS, COLS = len(mat), len(mat[0])
        up = True

        res = []
        curR, curC = 0, 0
        while len(res) < ROWS * COLS:
            if up:
                while curR >= 0 and curC < COLS:
                    res.append(mat[curR][curC])
                    curR -= 1
                    curC += 1
                
                if curC == COLS:
                    curR += 2
                    curC -= 1
                else:
                    curR += 1
                up = False
            else:
                while curR < ROWS and curC >= 0:
                    res.append(mat[curR][curC])
                    curR += 1
                    curC -= 1
                if curR == ROWS:
                    curR -= 1
                    curC += 2
                else:
                    curC += 1
                up = True
        return res
        #O(mn)
        #O(mn) or O(1) if not count result
            
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Angle Between Hands of a Clock

Given two numbers, hour and minutes, return the smaller angle (in degrees) formed between the hour and the minute hand.

Answers within 10-5 of the actual value will be accepted as correct.

Input: hour = 12, minutes = 30
Output: 165

A
class Solution:
    def angleClock(self, hour: int, minutes: int) -> float:
        #360 degrees / 60 minutes * m minutes -> degrees in minutes
        #Hours: base hour hand + how much we move between the hour hands
        #360 degrees / 12 hours * h hours + (30 degrees / 1 hour) * (1 hour / 60 minutes) * (m minutes)
        minutesDeg = 360 / 60 * minutes
        hoursDeg = (360 / 12) * hour + (30 / 60) * minutes
        diff = abs(hoursDeg - minutesDeg)
        return min(diff, 360 - diff)
        #O(1)
        #O(1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Binary Tree Vertical Order Traversal

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

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

For each node at position (row, col), its left and right children will be at positions (row + 1, col - 1) and (row + 1, col + 1) respectively. The root of the tree is at (0, 0).

Input: {3,9,8,4,0,1,7}
Output: [[4],[9],[3,0,1],[8],[7]]

A
from typing import (
    List, collections
)
from lintcode import (
    TreeNode
)

"""
Definition of TreeNode:
class TreeNode:
    def \_\_init\_\_(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: the root of tree
    @return: the vertical order traversal
    """
    def vertical_order(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        # write your code here
        minX, maxX = float('inf'), -float('inf')

        q = collections.deque() #node, X value
        q.append([root, 0])
        xMap = collections.defaultdict(list) #maps x value to the nodes that fall under it
        while q:
            curNode, curX = q.popleft()
            xMap[curX].append(curNode.val)
            minX = min(minX, curX)
            maxX = max(maxX, curX)
            if curNode.left:
                q.append([curNode.left, curX - 1])
            if curNode.right:
                q.append([curNode.right, curX + 1])
        res = []
        for x in range(minX, maxX + 1):
            res.append(xMap[x])
        return res
        #O(n)
        #O(n)
            
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Find Leaves of Binary Tree
Given a binary tree, collect a tree’s nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.

Input: {1,2,3,4,5}
Output: [[4, 5, 3], [2], [1]].
Explanation:

A
import collections
"""
Definition of TreeNode:
class TreeNode:
    def \_\_init\_\_(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param: root: the root of binary tree
    @return: collect and remove all leaves
    """
    def findLeaves(self, root):
        #returns the layer that should be the parent's layer. 
        #If null, will return 0
        #If leaf node, will PROCESS nodes at layer 0 (stores as layer 0) which is the max 
        #of children max(0, 0)
        #THEN, returns to parent as layer 1. This means parent will process at layer 1
        res = collections.defaultdict(list)
        def dfs(root, layer):
            if not root:
                return 0
            leftLayer = dfs(root.left, layer)
            rightLayer = dfs(root.right, layer)

            #Max: see the node example. Want the 1 to be layer 3
            layer = max(leftLayer, rightLayer)
            res[layer].append(root.val)
            return layer + 1
        dfs(root, 0)
        #Lintcode weird stuff. Normally return res.values() works.
        finalRes = []
        for k, v in res.items():
            finalRes.append(v)
        return finalRes
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Add Bold Tag in String

Given a string s and a list of strings dict, you need to add a closed pair of bold tag and to wrap the substrings in s that exist in dict. If two such substrings overlap, you need to wrap them together by only one pair of closed bold tag. Also, if two substrings wrapped by bold tags are consecutive, you need to combine them.

Input:
s = “abcxyz123”
dict = [“abc”,”123”]
Output:
“<b>abc</b>xyz<b>123</b>”

A
from typing import (
    List,
)

class Solution:
    """
    @param s: a string
    @param dict: a list of strings
    @return: return a string
    """
    def add_bold_tag(self, s: str, dict: List[str]) -> str:
        # write your code here
        boldStatus = [False] * len(s)
        for word in dict:
            for i in range(0, len(s) - len(word) + 1): #Python exclusion
                if s[i: i + len(word)] == word:
                    for j in range(i, i + len(word)):
                        boldStatus[j] = True
        res = []
        i = 0
        while i < len(s):
            if boldStatus[i]:
                res.append("<b>")
                while i < len(s) and boldStatus[i]:
                    res.append(s[i])
                    i += 1
                res.append("</b>")
            else:
                res.append(s[i])
                i += 1
        return "".join(res)
        #O(n * w * avg length of w)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Closest Binary Search Tree Value II
Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.

Input:
{3,1,4,#,2}
0.275000
2
Output:
[1,2]
Explanation:
Binary tree {3,1,4,#,2}, denote the following structure:
3
/ \
1 4
\
2

A
from typing import (
    List,
)
from lintcode import (
    TreeNode,
)
import collections

"""
Definition of TreeNode:
class TreeNode:
    def \_\_init\_\_(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: the given BST
    @param target: the given target
    @param k: the given k
    @return: k values in the BST that are closest to the target
             we will sort your return value in output
    """
    def closest_k_values(self, root: TreeNode, target: float, k: int) -> List[int]:
        # write your code here
        q = collections.deque([])

        def dfs(root):
            if not root:
                return
            dfs(root.left)

            #middle stuff
            if len(q) < k:
                q.append(root.val)
            else:
                if abs(q[0] - target) >= abs(target - root.val):
                    q.popleft()
                    q.append(root.val)
                else:
                    return

            dfs(root.right)
        dfs(root)
        #Lintcode stuff.. should be able to return q normally
        res = []
        for val in q:
            res.append(val)
        return res
        #O(n)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Minimum Area Rectangle
You are given an array of points in the X-Y plane points where points[i] = [xi, yi].

Return the minimum area of a rectangle formed from these points, with sides parallel to the X and Y axes. If there is not any such rectangle, return 0.

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

A
class Solution:
    def minAreaRect(self, points: List[List[int]]) -> int:
        pointSet = set()
        for x, y in points:
            pointSet.add((x, y))
        res = float('inf')
        for i in range(len(points)):
            x1, y1 = points[i]
            for j in range(i + 1, len(points)):
                x2, y2 = points[j]
                if x1 != x2 and y1 != y2 and (x2, y1) in pointSet and (x1, y2) in pointSet:
                    res = min(res, abs((x2 - x1) * (y2 - y1)))
        return res if res != float('inf') else 0
        #O(n ** 2)
        #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Minimum Time Difference
Given a list of 24-hour clock time points in “HH:MM” format, return the minimum minutes difference between any two time-points in the list.

Input: timePoints = [“23:59”,”00:00”]
Output: 1

A
class Solution:
    def findMinDifference(self, timePoints: List[str]) -> int:
        minutesSinceMidnight = []
        for timeStr in timePoints:
            hours, minutes = timeStr.split(":")
            minutesSinceMidnight.append(int(hours) * 60 + int(minutes))
        minutesSinceMidnight.sort()
        #In the case of 00:00 and 23:59, we need to compare 24:00 and 23:59.
        #Therefore, 1440 + min[0] - min[-1]. 1440 is 24*60
        res = 24 * 60 + minutesSinceMidnight[0] - minutesSinceMidnight[-1]
        for i in range(1, len(minutesSinceMidnight)):
            res = min(res, minutesSinceMidnight[i] - minutesSinceMidnight[i - 1])
        return res
        #O(n log n)
        #O(n)
15
Q

Minimum Add to Make Parentheses Valid

A parentheses string is valid if and only if:

It is the empty string,
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.
You are given a parentheses string s. In one move, you can insert a parenthesis at any position of the string.

For example, if s = “()))”, you can insert an opening parenthesis to be “(()))” or a closing parenthesis to be “())))”.
Return the minimum number of moves required to make s valid.

Input: s = “())”
Output: 1

A
class Solution:
    def minAddToMakeValid(self, s: str) -> int:
        lCount, rCount = 0, 0
        res = 0
        for c in s:
            if c == "(":
                lCount += 1
            else:
                if rCount >= lCount:
                    res += 1
                else:
                    rCount += 1
        res += lCount - rCount
        return res
        #O(n)
        #O(1)
            
16
Q

Minimum Remove to Make Valid Parentheses

Given a string s of ‘(‘ , ‘)’ and lowercase English characters.

Your task is to remove the minimum number of parentheses ( ‘(‘ or ‘)’, in any positions ) so that the resulting parentheses string is valid and return any valid string.

Formally, a parentheses string is valid if and only if:

It is the empty string, contains only lowercase characters, or
It can be written as AB (A concatenated with B), where A and B are valid strings, or
It can be written as (A), where A is a valid string.

Input: s = “lee(t(c)o)de)”
Output: “lee(t(c)o)de”
Explanation: “lee(t(co)de)” , “lee(t(c)ode)” would also be accepted.

A
class Solution:
    def minRemoveToMakeValid(self, s: str) -> str:
        lCount, rCount = 0, 0
        sb = []
        for c in s:
            if c == "(":
                sb.append("(")
                lCount += 1
            elif c == ")":
                if lCount > rCount:
                    sb.append(")")
                    rCount += 1
                    #Otherwise, skip over.
            else:
                sb.append(c)
        if lCount == rCount:
            return "".join(sb)
        res = []
        for i in range(len(sb) - 1, -1, -1):
            if sb[i] == "(":
                if lCount > rCount:
                    lCount -= 1
                    #Remove excess left parentheses.
                else:
                    res.append("(")
            else:
                res.append(sb[i])
                #on the first pass we verified that right parentheses are OK.
        return "".join(res[::-1])
        #O(n)
        #O(n)
        
17
Q

Maximum Subarray Sum with One Deletion

Given an array of integers, return the maximum sum for a non-empty subarray (contiguous elements) with at most one element deletion. In other words, you want to choose a subarray and optionally delete one element from it so that there is still at least one element left and the sum of the remaining elements is maximum possible.

Note that the subarray needs to be non-empty after deleting one element.

Input: arr = [-1,-1,-1,-1]
Output: -1
Explanation: The final subarray needs to be non-empty. You can’t choose [-1] and delete -1 from it, then get an empty subarray to make the sum equals to 0.

A
class Solution:
    def maximumSum(self, arr: List[int]) -> int:
        curSumWithoutDel = curSumWithDel = res = arr[0]
        for n in arr[1:]:
            #extend delSum with cur num, delete n now, or start new subarray at n
            curSumWithDel = max(curSumWithDel + n, curSumWithoutDel, n)

            #If we aren't deleting already.. continue not deleting, or start subarray at n
            curSumWithoutDel = max(curSumWithoutDel + n, n)
            res = max(res, curSumWithDel, curSumWithoutDel)
        return res
        #O(n)
        #O(1)
18
Q

Interval List Intersections
You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [starti, endi] and secondList[j] = [startj, endj]. Each list of intervals is pairwise disjoint and in sorted order.

Return the intersection of these two interval lists.

A closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b.

The intersection of two closed intervals is a set of real numbers that are either empty or represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].

Input: firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

A
class Solution:
    def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]:
        res = []
        i, j = 0, 0
        while i < len(firstList) and j < len(secondList):
            start1, end1 = firstList[i]
            start2, end2 = secondList[j]

            if end1 < start2:
                i += 1
            elif end2 < start1:
                j += 1
            else:
                res.append([max(start1, start2), min(end1, end2)])
                #if second interval is longer, other things in first list can still intersect
                if end1 < end2:
                    i += 1
                else:
                    j += 1
        return res
        #O(n + m)
        #O(n + m)
19
Q

Random Pick Index

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

Implement the Solution class:

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

Input
[“Solution”, “pick”, “pick”, “pick”]
[[[1, 2, 3, 3, 3]], [3], [1], [3]]
Output
[null, 4, 0, 2]

Explanation
Solution solution = new Solution([1, 2, 3, 3, 3]);
solution.pick(3); // It should return either index 2, 3, or 4 randomly. Each index should have equal probability of returning.
solution.pick(1); // It should return 0. Since in the array only nums[0] is equal to 1.
solution.pick(3); // It should return either index 2, 3, or 4 randomly. Each index should have equal probability of returning.

A
class Solution:

    # def \_\_init\_\_(self, nums: List[int]):
    #     self.nums = nums

    # def pick(self, target: int) -> int:
    #     count = 0
    #     pickIndex = 0
    #     for i, n in enumerate(self.nums):
    #         if n == target:
    #             count += 1
    #             if randint(1, count) == count:
    #                 pickIndex = i
    #     return pickIndex
    #Reservoir sampling solution
    #O(n)
    #O(1)

    #O(1) time O(n) space solution is the simpler one with hashing.
    def \_\_init\_\_(self, nums: List[int]):
        self.countIndex = defaultdict(list)
        for i, n in enumerate(nums):
            self.countIndex[n].append(i)

    def pick(self, target: int) -> int:
        return random.choice(self.countIndex[target])

Your Solution object will be instantiated and called as such:
# obj = Solution(nums)
# param_1 = obj.pick(target)
20
Q

You are controlling a robot that is located somewhere in a room. The room is modeled as an m x n binary grid, where 0 represents a wall and 1 represents an empty slot.

The robot starts at an unknown location in the room that is guaranteed to be empty, and you do not have access to the grid, but you can move the robot using the given API Robot.

You are tasked to use the robot to clean the entire room (i.e., clean every empty cell in the room). The robot with the four given APIs can move forward, turn left, or turn right. Each turn is 90 degrees.

When the robot tries to move into a wall cell, its bumper sensor detects the obstacle, and it stays on the current cell.

Design an algorithm to clean the entire room using the following APIs:

move(): #true if next cell is open and robot moves into cell. False if next cell is obstacle and robot stays current cell

turnLeft()
turnRight()
clean()

A
def cleanRoom(robot):
    #Since robot faces down initially
    directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
    visited = set()
    def goBack():
        robot.turnRight()
        robot.turnRight()
        robot.move()
        robot.turnRight()
        robot.turnRight()
        
    def dfs(r, c, dirIndex):
        visited.add((r, c))
        robot.clean()
        
        for i in range(4): #Each loop, the robot will be turned
            newDirIndex = (dirIndex + i) % 4
            dr, dc = directions[newDirIndex]
            neiR, neiC = r + dr, c + dc
            
            if (neiR, neiC) not in visited and robot.move():
                dfs(neiR, neiC, newDirIndex)
                goBack()
            robot.turn() #before going into the new direction, make sure robot actually turns in that direction
    dfs(0, 0, 0)
#O(N - M) #O(N) number of tiles in room, M number of obstacles
#O(N - M)
21
Q

Making A Large Island
You are given an n x n binary matrix grid. You are allowed to change at most one 0 to be 1.

Return the size of the largest island in grid after applying this operation.

An island is a 4-directionally connected group of 1s.
Input: grid = [[1,1],[1,0]]
Output: 4
Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4.

A
class Solution:
    def largestIsland(self, grid: List[List[int]]) -> int:
        ROWS, COLS = len(grid), len(grid[0])
        islandId = -1
        islandAreas = {} #id: area
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        def dfs(r, c):
            nonlocal islandId
            #Need to write it like this because we can only perform this when grid[r][c] is 1
            if r >= 0 and r < ROWS and c >= 0 and c < COLS and grid[r][c] == 1:
                grid[r][c] = islandId
                area = 1
                for dr, dc in directions:
                    neiR, neiC = r + dr, c + dc
                    area += dfs(neiR, neiC)
                return area
            else:
                return 0
        #Step 1: compute all the islands and their islandIds
        for r in range(ROWS):
            for c in range(COLS):
                if grid[r][c] == 1:
                    islandArea = dfs(r, c)
                    islandAreas[islandId] = islandArea
                    islandId -= 1
        
        maxArea = 0
        #Step 2: compute max area assuming can flip one 0 to a 1
        for r in range(ROWS):
            for c in range(COLS):
                if not grid[r][c]:
                    area = 1
                    #Get all adjacent unique Ids bordering this 0 flipping to a 1
                    surrounding = set()
                    for dr, dc in directions:
                        neiR, neiC = r + dr, c + dc
                        if (neiR >= 0 and neiR < ROWS and neiC >= 0 and neiC < COLS and grid[neiR][neiC] != 0):
                            #These are the islandId-fied values
                            surrounding.add(grid[neiR][neiC])
                    
                    for neiID in surrounding:
                        area += islandAreas[neiID]
                    maxArea = max(maxArea, area)
        #Because we only compute maxArea assuming there is a 0 to flip. If none, it's all 1.
        return maxArea if maxArea != 0 else ROWS * COLS
        #O(MN) first pass through for populating islandIDs, then potentially try flipping all values
        #O(MN) assume around MN distinct islands in this map
22
Q

In this problem, we are given a nestedList consisting of integers that might be wrapped in multiple layers of lists. An integer’s depth is determined by how many lists contain it. For instance, in the list [1,[2,2],[[3],2],1], the number 1 is at depth 1 (since it’s not within any nested list), the number 2 is at depth 2 (as it is in one nested list), and the number 3 is at depth 3 (as it’s in two nested lists).

Our goal is to compute the sum of all integers in nestedList each weighted by its depth. In simple terms, we multiply each integer by the number of lists it is inside and then sum these products together.
nestedList1 = [[1, 1], 2, [1, 1]] -> 10
nestedList2 = [1, [4, [6]]] -> 27

A
import collections
nestedList1 = [[1, 1], 2, [1, 1]]
nestedList2 = [1, [4, [6]]]
def depthSumBFS(nestedList):
    depth = 1
    res = 0
    q = collections.deque(nestedList)
    while q:
        for _ in range(len(q)):
            cur = q.popleft()
            if isinstance(cur, int):
                res += depth * cur
            else:
                q.extend(cur)
        depth += 1
    return res
print(depthSumBFS(nestedList1))
print(depthSumBFS(nestedList2))

#Time: O(N) where N is the total amount of elements
#Space: O(N) for the queue
        
def depthSumDFS(nestedList):
    def dfs(cur, depth):
        if isinstance(cur, int):
            return cur * depth
        res = 0
        for elt in cur:
            res += dfs(elt, depth + 1)
        return res
    return dfs(nestedList, 0) # the initial list is depth as starters. Example [5]
print(depthSumDFS(nestedList1))
print(depthSumDFS(nestedList2))\

#Time: O(N) where N is the total amount of elements
#Space: O(D) for the max dpeth of the nested list
23
Q

Cutting Ribbons

Given an array of positive integers ribbons and an integer k, where the array element ribbons[i] represents the length of the



i
th
rope. For each rope, you can cut any rope into a series of positive integer parts of length, or choose not to cut it.

For example, given a rope of length 4, you can choose to do the following:

Do not cut the rope, keeping it at length 4
Cut the rope into one rope of length 3 and one rope of length 1
Cut the rope into two ropes of length 2
Cut the rope into one length of 2 and two lengths of 1
Cut the rope into four lengths of 1
Now you need to cut the ropes in ribbons into k ropes of the same length, and if there are any ropes left over after cutting, you can just discard the excess.

Returns the maximum length of rope that can be cut into k pieces, or 0 if it is not possible to cut k pieces of rope of the same length.

A
from typing import (
    List,
)

class Solution:
    """
    @param ribbons: An integer array
    @param k: Number of ribbons of the same length
    @return: Maximum length of ribbons
    """
    def max_length(self, ribbons: List[int], k: int) -> int:
        # write your code here
        l, r = 1, max(ribbons)
        res = 0 #even though ribbons are at least length 1, potentially asked to [1, 2, 3], 7. More pieces than possible.
        def canCut(m):
            count = 0
            for length in ribbons:
						   count += length // m
            return count >= k

        while l <= r:
            m = l + (r - l) // 2
            if canCut(m):
                res = m
                l = m + 1
            else:
                r = m - 1
        return res
        #O(N * log (max(ribbons))) #each can cut check iterates through all the ribbons.
        #O(1)
24
Q

Given a string, we can “shift” each of its letter to its successive letter, for example: “abc” -> “bcd”. We can keep “shifting” which forms the sequence:

“abc” -> “bcd” -> … -> “xyz”
Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence.
Input: [“abc”, “bcd”, “acef”, “xyz”, “az”, “ba”, “a”, “z”],
Output:
[
[“abc”,”bcd”,”xyz”],
[“az”,”ba”],
[“acef”],
[“a”,”z”]
]

A
strings = ["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"]
# Given a string, we can "shift" each of its letter to its successive letter, for example: "abc" -> "bcd". We can keep "shifting" which forms the sequence:

"abc" -> "bcd" -> ... -> "xyz"
# Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence.
# Input: ["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"],
# Output:
# [
#   ["abc","bcd","xyz"],
#   ["az","ba"],
#   ["acef"],
#   ["a","z"]
# ]

import collections
def groupShiftedStrings(strings):
    groupDiffs = collections.defaultdict(list)
    for s in strings:
        if len(s) == 1:
            groupDiffs[(-1)].append(s)
        else:
            diffList = []
            for i in range(len(s) - 1):
                diff = (ord(s[i + 1]) - ord(s[i])) % 26
                diffList.append(diff)
            groupDiffs[tuple(diffList)].append(s)
    return groupDiffs.values()
    #O(NM) number of words * avg length of each word
    #O(MN) same for space
print(groupShiftedStrings(strings))
25
Q

Find All People With Secret

You are given an integer n indicating there are n people numbered from 0 to n - 1. You are also given a 0-indexed 2D integer array meetings where meetings[i] = [xi, yi, timei] indicates that person xi and person yi have a meeting at timei. A person may attend multiple meetings at the same time. Finally, you are given an integer firstPerson.

Person 0 has a secret and initially shares the secret with a person firstPerson at time 0. This secret is then shared every time a meeting takes place with a person that has the secret. More formally, for every meeting, if a person xi has the secret at timei, then they will share the secret with person yi, and vice versa.

The secrets are shared instantaneously. That is, a person may receive the secret and share it with people in other meetings within the same time frame.

Return a list of all the people that have the secret after all the meetings have taken place. You may return the answer in any order.

Input: n = 6, meetings = [[1,2,5],[2,3,8],[1,5,10]], firstPerson = 1
Output: [0,1,2,3,5]
Explanation:
At time 0, person 0 shares the secret with person 1.
At time 5, person 1 shares the secret with person 2.
At time 8, person 2 shares the secret with person 3.
At time 10, person 1 shares the secret with person 5.​​​​
Thus, people 0, 1, 2, 3, and 5 know the secret after all the meetings.

A
class Solution:
    def findAllPeople(self, n: int, meetings: List[List[int]], firstPerson: int) -> List[int]:
        meetings.sort(key = lambda x: x[2])
        knowSecrets = set()
        knowSecrets.add(0)
        knowSecrets.add(firstPerson)

        meetingsMap = collections.defaultdict(list) #time -> list of meetings that fall under that time
        for person1, person2, time in meetings:
            meetingsMap[time].append([person1, person2])
        
        for time, meetingsDuringTime in meetingsMap.items():
            graph = collections.defaultdict(list)
            curSecrets = set()
            for person1, person2 in meetingsDuringTime:
                graph[person1].append(person2)
                graph[person2].append(person1)

                if person1 in knowSecrets:
                    curSecrets.add(person1)
                
                if person2 in knowSecrets:
                    curSecrets.add(person2)
            
            #all people who know the secrets and spreading in this iteration
            #all people in this queue, at the start, are around in knowSecrets
            q = deque(curSecrets)
            while q:
                for _ in range(len(q)):
                    person = q.popleft()
                    #If hasn't 
                    for nei in graph[person]:
                        if nei not in knowSecrets:
                            knowSecrets.add(nei)
                            q.append(nei)
        return knowSecrets
        #O(n log n + n) #sort all the meetings, then each person touched at most once to get them into knowSecrets.
        #O(n) space for storage of all the meetings
                
            
            

        
26
Q

Given a string s and an integer k, find out if the given string is a K-Palindrome or not.

A string is K-Palindrome if it can be transformed into a palindrome by removing at most k characters from it.

Input: s = “abcdeca”, k = 2
Output: true
Explanation: Remove ‘b’ and ‘e’ characters.

A
# Given a string s and an integer k, find out if the given string is a K-Palindrome or not.

A string is K-Palindrome if it can be transformed into a palindrome by removing at most k characters from it.
# Input: s = "abcdeca", k = 2
# Output: true
# Explanation: Remove 'b' and 'e' characters.
def main(s, k):
    def lcs(s1, s2):
        dp = [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)]
        for i in range(len(s1) - 1, -1, -1):
            for j in range(len(s2) - 1, -1, -1):
                if s1[i] == s2[j]:
                    dp[i][j] = 1 + dp[i + 1][j + 1]
                else:
                    dp[i][j] = max(dp[i + 1][j], dp[i][j + 1])
        return dp[0][0]
    return len(s) - lcs(s, s[::-1]) <= k
    #O(n ** 2)
    #O(n ** 2)
print(main("abcdeca", 2))
print(main("abbababa", 1))
print(main("abba", 2))
print(main("abcca", 1))
print(main("abcca", 0))
27
Q

Next Permutation

Given a list of integers, which denote a permutation.Find the next permutation in ascending order.

array = [1,3,2,3]
[1,3,3,2]

A
from typing import (
    List,
)

class Solution:
    """
    @param nums: A list of integers
    @return: A list of integers
    """
    def next_permutation(self, nums: List[int]) -> List[int]:
        # write your code here
        #From right to left, make sure values are increasing. Since 321 -> 123 is easy
        pivot = None

        for i in range(len(nums) - 1, 0, -1):
            if nums[i - 1] < nums[i]:
                pivot = i - 1
                break 
        if pivot == None:
            return nums[::-1]
        #Find the first value to the right that is larger than the pivot
        i = len(nums) - 1
        while i >= 0:
            if nums[i] > nums[pivot]:
                nums[pivot], nums[i] = nums[i], nums[pivot]
                break
            i -= 1
        #1 3 2 6 5
        #1 3 5 6 2
        #becomes 1 3 5 2 6
        #reverse everything after 
        nums[pivot + 1:] = nums[pivot+1:][::-1]
        return nums
        #O(n)
        #O(1) #constant space
28
Q

Valid Word Abbreviation

Given a non-empty string word and an abbreviation abbr, return whether the string matches with the given abbreviation.

A string such as “word” contains only the following valid abbreviations:
Input : s = “internationalization”, abbr = “i12iz4n”
Output : true

Input : s = “apple”, abbr = “a2e”
Output : false

A
class Solution:
    """
    @param word: a non-empty string
    @param abbr: an abbreviation
    @return: true if string matches with the given abbr or false
    """
    def valid_word_abbreviation(self, word: str, abbr: str) -> bool:
        # write your code here
        wordPtr, abbrPtr = 0, 0
        while wordPtr < len(word) and abbrPtr < len(abbr):
            if abbr[abbrPtr].isdigit():
                if abbr[abbrPtr] == "0":
                    return False
                count = 0 
                
                while abbrPtr < len(abbr) and abbr[abbrPtr].isdigit():
                    count = count * 10 + int(abbr[abbrPtr])
                    abbrPtr += 1
                wordPtr += count
            else:
                if word[wordPtr] != abbr[abbrPtr]:
                    return False
                wordPtr += 1
                abbrPtr += 1
        return wordPtr == len(word) and abbrPtr == len(abbr)
        #O(w + a)
        #O(1)
29
Q

All Nodes Distance K in Binary Tree

Given the root of a binary tree, the value of a target node target, and an integer k, return an array of the values of all nodes that have a distance k from the target node.

You can return the answer in any order.

Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2
Output: [7,4,1]
Explanation: The nodes that are a distance 2 from the target node (with value 5) have values 7, 4, and 1.

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def distanceK(self, root: TreeNode, target: TreeNode, k: int) -> List[int]:
        if not k:
            return [target.val]
        graph = defaultdict(list)
        #BFS (or DFS) to transform the tree into a graph
        q = deque([root])
        while q:
            for _ in range(len(q)):
                cur = q.popleft()
                if cur.left:
                    graph[cur].append(cur.left)
                    graph[cur.left].append(cur)
                    q.append(cur.left)
                if cur.right:
                    graph[cur].append(cur.right)
                    graph[cur.right].append(cur)
                    q.append(cur.right)
        res = []

        #BFS to find all nodes distance K from target.
        q = deque([(target, 0)])
        visited = set()
        visited.add(target)

        while q:
            for _ in range(len(q)):
                cur, distance = q.popleft()
                if distance == k:
                    res.append(cur.val)
                else:
                    for nei in graph[cur]:
                        if nei not in visited:
                            visited.add(nei)
                            q.append((nei, distance + 1))
        return res
        #O(n)
        #O(n)
30
Q

Dot Product of Two Sparse Vectors
Given two sparse vectors, compute the product of their quantities (dot product).

Implements class SparseVector:

SparseVector(nums) initializes the object with the vector nums
dotProduct(vec) computes the product of this vector and the vec vector
Sparse vectors are vectors that have a majority of components 0 and are stored efficiently by designing the SparseVector class.

Input:
nums1 = [0,0,1,2,0,3]
nums2 = [4,0,1,0,0,3]
Output:
10
Explanation:
v1 = SparseVector(nums1), v2 = SparseVector(nums2)
v1.dotProduct(v2) = 04 + 00 + 11 + 20 + 00 + 33 = 10

A
from typing import (
    List,
)

class SparseVector:
    # Your SparseVector object will be instantiated and called as such:
    # v1 = SparseVector(nums1)
    # v2 = SparseVector(nums2)
    # ans = v1.dot_product(v2)
    def \_\_init\_\_(self, nums: List[int]):
        # do intialization here
        self.v = [] #index, num
        for i, n in enumerate(nums):
            if n != 0:
                self.v.append((i, n))

    # Return the dotProduct of two sparse vectors
    def dot_product(self, vec: "SparseVector") -> int:
        v1 = self.v
        v2 = vec.v

        i, j = 0, 0
        res = 0
        while i < len(v1) and j < len(v2):
            idx1, num1 = v1[i]
            idx2, num2 = v2[j]
            if idx1 == idx2:
                res += num1 * num2
                i += 1
                j += 1
            elif idx1 < idx2:
                i += 1
            else:
                j += 1
        return res
    #O(n)
    #O(n)
    #Better than hashing solution. Because hash function can be very bad and have many collisions (chaining) etc
31
Q

Add One Row to Tree

Given the root of a binary tree and two integers val and depth, add a row of nodes with value val at the given depth depth.

Note that the root node is at depth 1.

The adding rule is:

Given the integer depth, for each not null tree node cur at the depth depth - 1, create two tree nodes with value val as cur’s left subtree root and right subtree root.
cur’s original left subtree should be the left subtree of the new left subtree root.
cur’s original right subtree should be the right subtree of the new right subtree root.
If depth == 1 that means there is no depth depth - 1 at all, then create a tree node with value val as the new root of the whole original tree, and the original tree is the new root’s left subtree.

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

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 addOneRow(self, root: Optional[TreeNode], val: int, depth: int) -> Optional[TreeNode]:
        if depth == 1:
            newRoot = TreeNode(val)
            newRoot.left = root
            return newRoot
        q = deque([root])
        curDepth = 1
        while q:
            if curDepth == depth - 1:
                break #these check is placed here so that we break out of while, not the for
            for _ in range(len(q)):
                cur = q.popleft()
                if cur.left:
                    q.append(cur.left)
                if cur.right:
                    q.append(cur.right)
            curDepth += 1
        #Everything in queue is depth - 1.
        for cur in q:
            curLeft, curRight = cur.left, cur.right
            cur.left = TreeNode(val)
            cur.left.left = curLeft

            cur.right = TreeNode(val)
            cur.right.right = curRight
        return root
        #O(n) go through all ndoes
        #O(n) for the queue
32
Q

Max Consecutive Ones III

Given a binary array nums and an integer k, return the maximum number of consecutive 1’s in the array if you can flip at most k 0’s.

Input: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
Output: 6
Explanation: [1,1,1,0,0,1,1,1,1,1,1]
Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.

A
class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        l = 0
        res = 0
        curK = k
        for r in range(len(nums)):
            curK -= 1 if nums[r] == 0 else 0
            while curK < 0:
                curK += 1 if nums[l] == 0 else 0
                l += 1
            res = max(res, r - l + 1)
        return res
        #O(n)
        #O(1)
33
Q

Word Break II

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

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

Input: s = “pineapplepenapple”, wordDict = [“apple”,”pen”,”applepen”,”pine”,”pineapple”]
Output: [“pine apple pen apple”,”pineapple pen apple”,”pine applepen apple”]
Explanation: Note that you are allowed to reuse a dictionary word.

A
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        dp = [False for i in range(len(s) + 1)]
        dp[len(s)] = True
        res = defaultdict(list) #Tracks each index i to a list of words that can be broken down i onwards.

        for i in range(len(s) - 1, -1, -1):
            for w in wordDict:
                if i + len(w) <= len(s) and s[i: i + len(w)] == w and dp[i + len(w)]:
                    dp[i] = True
                    if res[i + len(w)] != []:
                        for oldWords in res[i + len(w)]:
                            #oldWords are built from back to front.
                            cur = w + ' ' + oldWords
                            res[i].append(cur)
                    else:
                        res[i].append(w)
        return res[0]
        #Example outputs:
#         dp: [True, False, False, True, True, False, False, True, False, False, True]
# res: {0: ['cat sand dog', 'cats and dog'], 1: [], 2: [], 3: ['sand dog'], 4: ['and dog'], 5: [], 6: [], 7: ['dog'], 8: [], 9: [], 10: []}
        #O(sw * avg length of each word) #s outer loop, w words, avg length of each word
        #O(sw * avg length of each word) #for each index i in s, we potentially store w words, each of avg length w.
34
Q
Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree with largest number of nodes in it.

Input: [10,5,15,1,8,null,7]

   10
   / \
  5  15
 / \   \
1   8   7

Output: 3
Explanation: The Largest BST Subtree in this case is the highlighted one.
             The return value is the subtree's size, which is 3.
A
class TreeNode :
    def \_\_init\_\_(self, data) :
        self.data = data
        self.left = None
        self.right = None
def largestBST(root):
    res = 0
    def dfs(node):
        nonlocal res
        if not node:
            return False, 0, -float('inf'), float('inf')
        if not node.left and not node.right:
            return True, 1, node.data, node.data
        leftIsBst, leftSize, leftMin, leftMax = dfs(node.left)
        rightIsBst, rightSize, rightMin, rightMax = dfs(node.right)

        if leftIsBst and rightIsBst and leftMax < node.data < rightMin:
            curSize = 1 + leftSize + rightSize
            res = max(res, curSize)
            return True, curSize, leftMin, rightMax
        elif leftIsBst and not node.right and leftMax < node.data:
            curSize = 1 + leftSize
            res = max(res, curSize)
            return True, curSize, leftMin, node.data
        elif rightIsBst and not node.left and node.data < rightMin:
            curSize = 1 + rightSize
            res = max(res, curSize)
            return True, curSize, node.data, rightMax
        else:
            return False, 0, -float('inf'), float('inf')
    dfs(root)
    return res
    #O(n)
    #O(h)
root = TreeNode(10)
fiveNode = TreeNode(5)
fifteen = TreeNode(15)
one = TreeNode(1)
eight = TreeNode(8)
seven = TreeNode(7)

root.left = fiveNode
root.right = fifteen
fiveNode.left = one
fiveNode.right = eight
fifteen.right = seven
print(largestBST(root))
35
Q

Find All People With Secret
You are given an integer n indicating there are n people numbered from 0 to n - 1. You are also given a 0-indexed 2D integer array meetings where meetings[i] = [xi, yi, timei] indicates that person xi and person yi have a meeting at timei. A person may attend multiple meetings at the same time. Finally, you are given an integer firstPerson.

Person 0 has a secret and initially shares the secret with a person firstPerson at time 0. This secret is then shared every time a meeting takes place with a person that has the secret. More formally, for every meeting, if a person xi has the secret at timei, then they will share the secret with person yi, and vice versa.

The secrets are shared instantaneously. That is, a person may receive the secret and share it with people in other meetings within the same time frame.

Return a list of all the people that have the secret after all the meetings have taken place. You may return the answer in any order.

Input: n = 6, meetings = [[1,2,5],[2,3,8],[1,5,10]], firstPerson = 1
Output: [0,1,2,3,5]
Explanation:
At time 0, person 0 shares the secret with person 1.
At time 5, person 1 shares the secret with person 2.
At time 8, person 2 shares the secret with person 3.
At time 10, person 1 shares the secret with person 5.​​​​
Thus, people 0, 1, 2, 3, and 5 know the secret after all the meetings.

A
class Solution:
    def findAllPeople(self, n: int, meetings: List[List[int]], firstPerson: int) -> List[int]:
        timeMap = {} #time -> defaultdict list

        for src, dst, time in meetings:
            if time not in timeMap:
                timeMap[time] = defaultdict(list)
            timeMap[time][src].append(dst)
            timeMap[time][dst].append(src)
        
        secrets = set([0, firstPerson])

        def dfs(src, adj):
            #Need a visit set here not secrets set. Since src is in secrets initially when run dfs on line 25
            if src in visit:
                return
            visit.add(src)
            secrets.add(src)
            for nei in adj[src]:
                dfs(nei, adj)
        for time in sorted(timeMap.keys()):
            adj = timeMap[time]
            visit = set()
            for src in adj:
                #do dfs starting from the person who knows secret
                if src in secrets:
                    dfs(src, adj)
        return list(secrets)
        #O(m log m + n) #sorting, and going through each person once.
        #O(m + n) #number of meetings and number of people (approx the same)
36
Q

Excel Sheet Column Number

Given a string columnTitle that represents the column title as appears in an Excel sheet, return its corresponding column number.

For example:

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

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

Example 1:

Input: columnTitle = “A”
Output: 1

A
class Solution:
    def titleToNumber(self, columnTitle: str) -> int:
        res = 0
        for c in columnTitle:
            res = res * 26 + ord(c) - ord('A') + 1
        return res
        #O(n)
        #O(1)
        #Think of this as like if you have a string "21",
        #you would do res = 0 * 10 + 2 = 2
        #Then res = 2 * 10 + 1 = 21. 
        #same concept!
37
Q
A