Medium Flashcards

1
Q
  1. LRU Cache

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

Implement the LRUCache class:

LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
int get(int key) Return the value of the key if the key exists, otherwise return -1.
void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.

The functions get and put must each run in O(1) average time complexity.

A

use OrderedDict or Hash Map + Doubly Linked List

OrderedDict:
Any time a key is used (get/put), move it to the end of the ordered dict. Then the first element is the LRU.

Hash Map + Doubly Linked List:
Store nodes in the hash map by key. When you retrieve the node, you can use it to remove itself from the linked list (regardless of its position) and add it back at the end. This allows you to maintain a unique queue of keys.

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

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

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

A

DFS works but is slowish O(4^nm). BFS is O(nm).

class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
self.ROWS = len(grid)
self.COLS = len(grid[0])
visits = set()
count = 0
for r in range(self.ROWS):
for c in range(self.COLS):
count = count + self.dfs(grid, r, c, visits)
return count

def dfs(self, grid, r, c, visits) -> int:
    # base case of out bounds
    if min(r, c) < 0: return 0
    elif r == self.ROWS: return 0
    elif c == self.COLS: return 0
    # base case cur val is zero, return zero
    if grid[r][c] == "0": return 0
    # base case already visited
    if (r,c) in visits: return 0
    # if one, add cur pos to visits
    visits.add((r, c))
    # step
    self.dfs(grid, r, c+1, visits)
    self.dfs(grid, r+1, c, visits)
    self.dfs(grid, r, c-1, visits)
    self.dfs(grid, r-1, c, visits)
    # ignore all return values
    # return one if cur pos is one
    return 1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q
  1. Max Area of Island

You are given an m x n binary matrix grid. An island is a group of 1’s (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.

The area of an island is the number of cells with a value 1 in the island.

Return the maximum area of an island in grid. If there is no island, return 0.

A

DFS works but is slowish

class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
self.ROWS = len(grid)
self.COLS = len(grid[0])
visits = set()
maxArea = 0
for r in range(self.ROWS):
for c in range(self.COLS):
res = self.dfs(grid, r, c, visits)
maxArea = max(res, maxArea)
return maxArea

def dfs(self, grid, r, c, visits) -> int:
    # base case of out bounds
    if min(r, c) < 0: return 0
    elif r >= self.ROWS: return 0
    elif c >= self.COLS: return 0
    # base case cur val is zero, return zero
    if grid[r][c] == 0: return 0
    # base case already visited
    if (r,c) in visits: return 0
    # if one, add cur pos to visits
    visits.add((r, c))
    # step
    count = 1
    count = count + self.dfs(grid, r, c+1, visits)
    count = count + self.dfs(grid, r+1, c, visits)
    count = count + self.dfs(grid, r, c-1, visits)
    count = count + self.dfs(grid, r-1, c, visits)
    # count accumulates the size of the island
    return count
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q
  1. Shortest Path in Binary Matrix

Given an n x n binary matrix grid, return the length of the shortest clear path in the matrix. If there is no clear path, return -1.

A clear path in a binary matrix is a path from the top-left cell (i.e., (0, 0)) to the bottom-right cell (i.e., (n - 1, n - 1)) such that:

All the visited cells of the path are 0.
All the adjacent cells of the path are 8-directionally connected (i.e., they are different and they share an edge or a corner).

The length of a clear path is the number of visited cells of this path.

A

O(n)

BFS - Breadth First Seach of a matrix O(n)

import collections
class Solution:
# BFS. Also could use A, which uses estimates of the remaining dist to prioritize paths.
def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
if grid[0][0] > 0: return -1
n = len(grid)
visits = set()
queue = collections.deque()
queue.append((0, 0))
neigh = [(0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1)]
grid[0][0] = 1 # set num of previous steps
shortest = n
n + 1
while queue: # O(n)
r, c = queue.popleft()
visits.add((r, c))
steps = grid[r][c]
if (r, c) == (n-1, n-1): # reached bottom right corner
if grid[r][c] < shortest:
shortest = grid[r][c]
for dr, dc in neigh: # O(8)
rNeigh = r + dr
cNeigh = c + dc
if min(rNeigh, cNeigh) < 0 or max(rNeigh, cNeigh) >= n or grid[rNeigh][cNeigh] >= 1 or (rNeigh, cNeigh) in visits:
continue
queue.append((rNeigh, cNeigh))
grid[rNeigh][cNeigh] = steps + 1
if shortest > n*n: return -1
return shortest

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

You are given an m x n grid where each cell can have one of three values:

0 representing an empty cell,
1 representing a fresh orange, or
2 representing a rotten orange.

Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten.

Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1.

A

BFS O(nm)
def orangesRotting(self, grid: List[List[int]]) -> int:
ROWS = len(grid)
COLS = len(grid[0])
NEIGH = [[0, 1], [1, 0], [0, -1], [-1, 0]]
steps = 0
rotten = collections.deque()
fresh = set()
for r in range(ROWS):
for c in range(COLS):
if grid[r][c] == 2:
rotten.append((r, c))
elif grid[r][c] == 1:
fresh.add((r, c))

    while fresh:
        if len(rotten) == 0 : break
        rotten.append((-1, -1)) # marker
        while rotten:
            r, c = rotten.popleft()
            if r == -1: # we reached the marker
                break
            # add fresh neighbors to queue
            for dr, dc in NEIGH:
                rN = r + dr
                cN = c + dc
                if (rN, cN) in fresh:
                    rotten.append((rN, cN))
                    fresh.remove((rN, cN))     
                    grid[rN][cN] = 2    
                    if len(fresh) == 0: break
        steps += 1
    if fresh: return -1
    return steps
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q
  1. Search a 2D Matrix

You are given an m x n integer matrix matrix with the following two properties:

Each row is sorted in non-decreasing order.
The first integer of each row is greater than the last integer of the previous row.

Given an integer target, return true if target is in matrix or false otherwise.

You must write a solution in O(log(m * n)) time complexity.

A

Binary search. Treat matrix as as sorted array, calculate index. O(log(mn))

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q
  1. Koko Eating Bananas

Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours.

Koko can decide her bananas-per-hour eating speed of k. Each hour, she chooses some pile of bananas and eats k bananas from that pile. If the pile has less than k bananas, she eats all of them instead and will not eat any more bananas during this hour.

Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.

Return the minimum integer k such that she can eat all the bananas within h hours.

A

Binary search. Search between min/max possible time to eat the bananas to find the optimal rate.

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

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

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

A

Binary decision tree with DP. At every house, skip either 1 or 2 houses. It doesn’t make sense to skip 3, because you could have skipped 1 and gotten a larger sum. Use memoization to speed up.

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

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

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

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

A

2-dimensional DP bottom up approach

def uniquePaths(self, m: int, n: int) -> int:
prevRow = [0] * n
prevRow[n-1] = 1 # puts 1 in the bottom right cell
for row in range(m-1, -1, -1): # iterate through row indices backward
curRow = [0] * n
for col in range(n-1, -1, -1): # iterate through col indices backward
right = curRow[col+1] if col + 1 < n else 0
down = prevRow[col]
curRow[col] = down + right
prevRow = curRow
return prevRow[0]

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

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

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

Note:

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

Step through each cell in the board. Add its value to an array of length 9. We have arrays for each row, col, and 3x3 box. Before writing the value, check if it already exists. If so, return false.

To improve on space complexity, we could use bitmasks instead of arrays.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q
  1. Design Bounded Blocking Queue

Implement a thread-safe bounded blocking queue that has the following methods:

BoundedBlockingQueue(int capacity) The constructor initializes the queue with a maximum capacity.
void enqueue(int element) Adds an element to the front of the queue. If the queue is full, the calling thread is blocked until the queue is no longer full.
int dequeue() Returns the element at the rear of the queue and removes it. If the queue is empty, the calling thread is blocked until the queue is no longer empty.
A

Use two Lock objects, one for enqueue and one for dequeue. Lock the dequeue in init. Use a deque for storage.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q
  1. Fizz Buzz Multithreaded

You have the four functions:

printFizz that prints the word "fizz" to the console,
printBuzz that prints the word "buzz" to the console,
printFizzBuzz that prints the word "fizzbuzz" to the console, and
printNumber that prints a given integer to the console.

You are given an instance of the class FizzBuzz that has four functions: fizz, buzz, fizzbuzz and number. The same instance of FizzBuzz will be passed to four different threads:

Thread A: calls fizz() that should output the word "fizz".
Thread B: calls buzz() that should output the word "buzz".
Thread C: calls fizzbuzz() that should output the word "fizzbuzz".
Thread D: calls number() that should only output the integers.

Modify the given class to output the series [1, 2, “fizz”, 4, “buzz”, …] where the ith token (1-indexed) of the series is:

"fizzbuzz" if i is divisible by 3 and 5,
"fizz" if i is divisible by 3 and not 5,
"buzz" if i is divisible by 5 and not 3, or
i if i is not divisible by 3 or 5.

Implement the FizzBuzz class:

FizzBuzz(int n) Initializes the object with the number n that represents the length of the sequence that should be printed.
void fizz(printFizz) Calls printFizz to output "fizz".
void buzz(printBuzz) Calls printBuzz to output "buzz".
void fizzbuzz(printFizzBuzz) Calls printFizzBuzz to output "fizzbuzz".
void number(printNumber) Calls printnumber to output the numbers.
A

Each thread only calls its function once. Use the printNumber thread as the master thread, run a for loop, and have it release the others as needed. The others have while True loops where they acquire a lock and check the done flag. Then they release the number thread. When done, the number thread acquires its lock again to make sure no other threads are running, then sets the done flag and releases the other threads.

from threading import Semaphore
class FizzBuzz:
def __init__(self, n: int):
self.n = n
self.done = False
self.fLock = Semaphore(0)
self.bLock = Semaphore(0)
self.fbLock = Semaphore(0)
self.nLock = Semaphore(1)

# printFizz() outputs "fizz"
def fizz(self, printFizz: 'Callable[[], None]') -> None:
    print("fizz")
    while True:
        self.fLock.acquire()
        if self.done: break
        printFizz()
        self.nLock.release()

# printBuzz() outputs "buzz"
def buzz(self, printBuzz: 'Callable[[], None]') -> None:
    print("buzz")
    while True:
        self.bLock.acquire()
        if self.done: break
        printBuzz()
        self.nLock.release()

# printFizzBuzz() outputs "fizzbuzz"
def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
    print("fizzbuzz")
    while True:
        self.fbLock.acquire()
        if self.done: break
        printFizzBuzz()
        self.nLock.release()

# printNumber(x) outputs "x", where x is an integer.
def number(self, printNumber: 'Callable[[int], None]') -> None:
    print("number")
    for i in range(1, self.n+1):
        self.nLock.acquire()
        if i % 3 == 0:
            if i % 5 == 0:
                self.fbLock.release()
            else:
                self.fLock.release()
        else:
            if i % 5 == 0: # and not 3
                self.bLock.release()
            else: # not divisible by 3 or 5
                printNumber(i)
                self.nLock.release()
    self.nLock.acquire() # ensures no other threads are running
    self.done = True
    self.fLock.release()
    self.bLock.release()
    self.fbLock.release()
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q
  1. Two Sum II - Input Array Is Sorted

Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length.

Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2.

The tests are generated such that there is exactly one solution. You may not use the same element twice.

Your solution must use only constant extra space.

A

Use two pointers. Move the r pointer up until it get to target. Then move left and right pointers in until you find a match.

def twoSum(self, numbers: List[int], target: int) -> List[int]:
    l = 0
    r = 1
    while r < len(numbers) - 1 and numbers[r] < target:
        if numbers[r] + numbers[l] == target: return [l+1, r+1]
        r += 1
    while l < r:
        sm = numbers[r] + numbers[l]
        if sm == target: 
            return [l+1, r+1]
        elif sm < target:
            l += 1
        else:
            r -= 1
    assert("Solution not found")
    return [0, 0]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q
  1. Rotate Array

Given an integer array nums, rotate the array to the right by k steps, where k is non-negative.

Example 1:

Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]

A

Reverse the entire array, then reverse the first k elements, then reverse the remaining elements.

Another approach is to move each number to its final position (calculated), storing the existing number in a temp variable and moving it to its final position on the next iteration.

k = 3
Original List : 1 2 3 4 5 6 7
After reversing all numbers : 7 6 5 4 3 2 1
After reversing first k numbers : 5 6 7 4 3 2 1
After revering last n-k numbers : 5 6 7 1 2 3 4

class Solution:
def reverse(self, nums: list, start: int, end: int) -> None:
while start < end:
nums[start], nums[end] = nums[end], nums[start]
start, end = start + 1, end - 1

def rotate(self, nums: List[int], k: int) -> None:
    n = len(nums)
    k %= n

    self.reverse(nums, 0, n - 1)
    self.reverse(nums, 0, k - 1)
    self.reverse(nums, k, n - 1)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q
  1. Remove Nth Node From End of List

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

Example 1:

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

A

nth from the END. Use two pointers. Make a dummy head. Start both pointers at the dummy. Advance the leading pointer to n, then advance both by one until reaching the end of the list. Use the trailing pointer to cut out the nth node from the end:
trailing.next = trailing.next.next

def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
trailing = dummy
leading = dummy
for _ in range(n+1):
leading = leading.next
while leading:
trailing = trailing.next
leading = leading.next
trailing.next = trailing.next.next
return dummy.next

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

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

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

A

You can do it with strings, or do math.

We can build up the reverse integer one digit at a time. While doing so, we can check beforehand whether or not appending another digit would cause overflow.

Reversing an integer can be done similarly to reversing a string.

We want to repeatedly “pop” the last digit off of xxx and “push” it to the back of the rev\text{rev}rev. In the end, rev\text{rev}rev will be the reverse of the xxx.

To “pop” and “push” digits without the help of some auxiliary stack/array, we can use math.

//pop operation:
pop = x % 10;
x /= 10;

//push operation:
temp = rev * 10 + pop;
rev = temp;

However, this approach is dangerous, because the statement temp=rev⋅10+pop\text{temp} = \text{rev} \cdot 10 + \text{pop}temp=rev⋅10+pop can cause overflow.

Luckily, it is easy to check beforehand whether or this statement would cause an overflow.

public int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 10;
if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
rev = rev * 10 + pop;
}
return rev;
}

17
Q
  1. String to Integer (atoi)

Implement the myAtoi(string s) function, which converts a string to a 32-bit signed integer (similar to C/C++’s atoi function).

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

Read in and ignore any leading whitespace.
Check if the next character (if not already at the end of the string) is '-' or '+'. Read this character in if it is either. This determines if the final result is negative or positive respectively. Assume the result is positive if neither is present.
Read in next the characters until the next non-digit character or the end of the input is reached. The rest of the string is ignored.
Convert these digits into an integer (i.e. "123" -> 123, "0032" -> 32). If no digits were read, then the integer is 0. Change the sign as necessary (from step 2).
If the integer is out of the 32-bit signed integer range [-231, 231 - 1], then clamp the integer so that it remains in the range. Specifically, integers less than -231 should be clamped to -231, and integers greater than 231 - 1 should be clamped to 231 - 1.
Return the integer as the final result.
A

Pretty straightforward. In Python, ints can’t overflow, so no worries. Just test that the parsed int doesn’t exceed 2^31-1 or -2^31.

def myAtoi(self, s: str) -> int:
stripped = s.strip()
if len(stripped) == 0: return 0
isPos = 1
if stripped[0] == “-“:
isPos = -1
stripped = stripped[1:]
elif stripped[0] == “+”:
stripped = stripped[1:]
digitStr = “”
for i in range(len(stripped)):
if stripped[i].isdecimal():
digitStr += stripped[i]
else:
break
if len(digitStr) == 0: return 0
tempInt = int(digitStr)
if isPos == 1 and tempInt > 231-1: return 231-1
elif tempInt > 231: return -231
return tempInt * isPos

18
Q
  1. Container With Most Water

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

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

Return the maximum amount of water a container can store.

A

Use two pointers. Start at each end and calc the area between them. Move the pointer of the smaller one in, repeat. Return max area.

    l = 0
    r = len(height) - 1
    maxArea = 0
    while l < r:
        if height[l] < height[r]:
            h, w = height[l], r - l
            l += 1
        else:
            h, w = height[r], r - l
            r -= 1
        area = h * w            
        if area > maxArea: maxArea = area
    return maxArea
19
Q
  1. Letter Combinations of a Phone Number

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

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

A

Create a dictionary with numbers mapped to an array of letters. Use recursion to find the combos for smaller and smaller sets of numbers. It’s a DFS.

def findCombos(self, strs: List[List[str]]) -> List[str]:
out = []
if len(strs) == 1:
return strs[0]
else:
res = self.findCombos(strs[1:])
for char in strs[0]:
for s in res:
out.append(char + s)
return out

20
Q
  1. Generate Parentheses

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

Example 1:

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

A

Backtracking. Use a stack to build up each sequence. Pop to backtrack. Time/space complexity n-th Catalan number.

    ans = []
    def backtrack(S = [], left = 0, right = 0):
        if len(S) == 2 * n:
            ans.append("".join(S))
            return
        if left < n:
            S.append("(")
            backtrack(S, left+1, right)
            S.pop()
        if right < left:
            S.append(")")
            backtrack(S, left, right+1)
            S.pop()
    backtrack()
    return ans
21
Q
  1. Swap Nodes in Pairs

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

A

Create a dummy head. Set cur to dummy. Iterate and swap the next two nodes after cur. Advance cur by two.

    if head is None: return None
    dummy = ListNode(0)
    dummy.next = head
    cur = dummy
    while cur and cur.next and cur.next.next:
        left = cur.next
        right = cur.next.next
        left.next = right.next
        right.next = left
        cur.next = right
        cur = cur.next.next
    return dummy.next
22
Q
  1. Divide Two Integers

Given two integers dividend and divisor, divide two integers without using multiplication, division, and mod operator.

The integer division should truncate toward zero, which means losing its fractional part. For example, 8.345 would be truncated to 8, and -2.7335 would be truncated to -2.

Return the quotient after dividing dividend by divisor.

Note: Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For this problem, if the quotient is strictly greater than 2^31 - 1, then return 2^31 - 1, and if the quotient is strictly less than -2^31, then return -2^31.

A

The brute force approach is to count how many times you can subtract the divisor from the dividend. The better approach uses exponential search. Double the divisor until it exceeds the dividend, then back up one step and start again with the remainder. This has you computing the doubles of the divisor multiple times, so you can eliminate that duplicated work by storing the computed doubles.

23
Q
  1. Next Permutation

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

For example, for arr = [1,2,3], the following are all the permutations of arr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].

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

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

Given an array of integers nums, find the next permutation of nums.

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

A

Start from the right side of the array and move left until you find a decrease in value. Then scan again for the smallest number that is higher than the current, and swap them. At this point, the numbers to the right will be in decreasing order, so we reverse them to sort them in increasing order.

def nextPermutation(self, nums: List[int]) -> None:
def reverse(start: int):
i = start
j = len(nums) - 1
while i < j:
nums[i], nums[j] = nums[j], nums[i]
i += 1
j -= 1

    r = len(nums) - 1
    l = r - 1
    while l >= 0:
        if nums[l] < nums[l+1]:
            while nums[r] <= nums[l]:
                r -= 1
            nums[r], nums[l] = nums[l], nums[r]
            reverse(l+1)
            return           
        l -= 1
            
    # if we get here, no higher permutation could be found
    nums.reverse()
24
Q
  1. Search in Rotated Sorted Array

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

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

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

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

A

Use a one-pass binary search. Add some extra checks to determine which half to search next. Recursive is easy. Iterative would use less memory. O(logn).

def search(self, nums: List[int], target: int) -> int:
def binSearch(l, r) -> int:
if r - l == 0 or l >= len(nums): return -1
p = l + ((r - l) // 2)
if nums[p] == target: return p
if nums[p] > target:
if l == p or (nums[l] > target and nums[l] < nums[p]):
return binSearch(p+1, r)
else:
return binSearch(l, p)
else:
if r - 1 == p or (nums[r-1] < target and nums[r-1] > nums[p]):
return binSearch(l, p)
else:
return binSearch(p+1, r)
return binSearch(0, len(nums))

25
Q
  1. Number of Pairs of Strings With Concatenation Equal to Target

Given an array of digit strings nums and a digit string target, return the number of pairs of indices (i, j) (where i != j) such that the concatenation of nums[i] + nums[j] equals target.

A

Notice that pairs can be 0, 1 and 1, 0. Count the number of occurrences of each string. Step through them and look for their compliment. Use the count to determine how many permutations there could be.

def numOfPairs(self, nums: List[str], target: str) -> int:
freq = Counter(nums)
ans = 0
for k, v in freq.items():
if target.startswith(k):
suffix = target[len(k):]
ans += v * freq[suffix]
if k == suffix: ans -= freq[suffix]
return ans

26
Q
  1. 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 the celebrity, but the celebrity does not know any of them.

Now you want to find out who the celebrity is or verify that there is not one. You are only allowed to ask questions like: “Hi, A. Do you know B?” to get information about 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) that tells you whether a knows b. Implement a function int findCelebrity(n). There will be exactly one celebrity if they are at the party.

Return the celebrity’s label if there is a celebrity at the party. If there is no celebrity, return -1.

A

with each call to knows(…), we can conclusively determine that exactly 1 of the people is not a celebrity

The knows API is already defined for you.
# return a bool, whether a knows b
# def knows(a: int, b: int) -> bool:
from functools import lru_cache
class Solution:
@lru_cache(maxsize=None)
def cachedKnows(self, a, b):
return knows(a, b)

def findCelebrity(self, n: int) -> int:
    celeb = 0
    # rule out everyone except the potential celeb
    for i in range(1, n):
        if self.cachedKnows(celeb, i):
            celeb = i

    # makes sure celeb doesn't know anyone
    for i in range(n):
        if i != celeb and (self.cachedKnows(celeb, i) or not self.cachedKnows(i, celeb)):
            return -1
            
    return celeb
27
Q
  1. Subdomain Visit Count
    A website domain “discuss.leetcode.com” consists of various subdomains. At the top level, we have “com”, at the next level, we have “leetcode.com” and at the lowest level, “discuss.leetcode.com”. When we visit a domain like “discuss.leetcode.com”, we will also visit the parent domains “leetcode.com” and “com” implicitly.

A count-paired domain is a domain that has one of the two formats “rep d1.d2.d3” or “rep d1.d2” where rep is the number of visits to the domain and d1.d2.d3 is the domain itself.

For example, "9001 discuss.leetcode.com" is a count-paired domain that indicates that discuss.leetcode.com was visited 9001 times.

Given an array of count-paired domains cpdomains, return an array of the count-paired domains of each subdomain in the input. You may return the answer in any order.

A

Don’t split the string, which is slow. Use find() instead.

def subdomainVisits(self, cpdomains: List[str]) -> List[str]:
counts = dict()
output = list()
for s in cpdomains:
i = s.find(“ “)
cnt = int(s[0:i])
while i >= 0:
subDom = s[i+1:]
if subDom in counts:
counts[subDom] += cnt
else:
counts[subDom] = cnt
i = s.find(“.”, i+1)
for subDom in counts:
output.append(str(counts[subDom]) + “ “ + subDom)
return output

28
Q
  1. Find First and Last Position of Element in Sorted Array

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

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

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

A

def searchRange(self, nums: List[int], target: int) -> List[int]:
lower_bound = self.findBound(nums, target, True)
if (lower_bound == -1):
return [-1, -1]
upper_bound = self.findBound(nums, target, False)
return [lower_bound, upper_bound]

def findBound(self, nums: List[int], target: int, isFirst: bool) -> int:        
    N = len(nums)
    begin, end = 0, N - 1
    while begin <= end:
        mid = int((begin + end) / 2)                
        if nums[mid] == target:                
            if isFirst:
                # This means we found our lower bound.
                if mid == begin or nums[mid - 1] < target:
                    return mid
                # Search on the left side for the bound.
                end = mid - 1
            else:                    
                # This means we found our upper bound.
                if mid == end or nums[mid + 1] > target:
                    return mid                    
                # Search on the right side for the bound.
                begin = mid + 1            
        elif nums[mid] > target:
            end = mid - 1
        else:
            begin = mid + 1        
    return -1