Design Flashcards

1
Q

LRU Cache (Medium)

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

The cache is initialized with a positive capacity.

A

Initialize with capacity, cache (map) and doubly linked list
map maps key to list nodes
list tracks nodes with head being most recent, tail being least recent, length of capacity

get:
if key not in cache, return -1
update cache for key
return cache.get(key).value

put:
create new node for key/value
if cache has key, remove node from list
if cache over capacity, remove tail and delete from cache
insert node to head of list
set node in cache with key

update:
remove node from list
set node to head of list
update node in cache

doubly linked list:
sentinel head/tail
insertHead(node)
remove(node)
removeTail(), return key (so you can remove from cache)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Read N Characters Given Read 4 (Hard)

Given a file and assume that you can only read the file using a given method read4, implement a method read to read n characters. Your method read may be called multiple times.

Method read4:
The API read4 reads 4 consecutive characters from the file, then writes those characters into the buffer array buf.
The return value is the number of actual characters read.

A
create internalBuf outside fn
let readChars = 0

while (n > 0) (still have chars to read)
if internalBuf empty, then call read4 w/ internalBuf
if read4 returns 0, return readChars
push to output buffer one character at a time from internalBuf
increment readChars
decrement n

return readChars

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

Implement Trie Prefix Tree (Medium)

Implement a trie with insert, search, and startsWith methods.

A
TrieNode class
children = new Map()
word = false

this.trie = new TrieNode()

insert:
set current node to trie, iterate through word, if node.children doesn’t have char, add to map (char to TrieNode), set node to matching child
at end set node.word to true

search:
iterate through word, set node to matching child, if reach end and word = true, return true
for wildcard search, if char not found and char equal wildcard, check all nodes at this level recursively, return true if any find word

startsWith:
iterate through word, set node to matching child, return if matching node regardless if word = true

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

Implement Stack With Queues (Easy)

Implement Queue With Stacks (Easy)

A

Use two stacks/queues

When adding, push to first if empty, otherwise pop/shift everything off first and push to second, then add new value to first, then pop/shift everything off second and push back to first

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

First Bad Version (Easy)

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.

Suppose you have n versions [1, 2, …, n] and you want to find out the first bad one, which causes all the following ones to be bad.

You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

A
Start = 1, End = n
Binary Search
if isBadVersio() end = mid - 1
else start = mid + 1

return start

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

Insert Delete GetRandom O(1) (Medium)

Design a data structure that supports all following operations in average O(1) time.

insert(val): Inserts an item val to the set if not already present.
remove(val): Removes an item val from the set if present.
getRandom: Returns a random element from current set of elements (it’s guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.

A

initialize with map and list (array)

insert:
if map has value return false
map.set(val, list.length)
list.push(val)

remove:
if map does not have value return false
get index of val from map
map.delete(val)
pop last item off list
if list.length equals index, that means it was already last item, return true
otherwise map.set(last, idx) and list[idx] = last

getRandom:
calc random index
Math.floor(Math.random() * list.length)

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

Random Pick Index (Medium)

Given an array of integers 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.

A

Initialize with nums

pick:
If length of array is 1, return 0
let count = 0, let result = 0
iterate through array
reservoir sampling
if nums[i] = target & floor(random() * ++count) === 0
result = i

return result

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

All O(1) Data Structure (Hard)

Implement a data structure supporting the following operations:

Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty string.
Dec(Key) - If Key’s value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string.
GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string “”.
GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string “”.

Challenge: Perform all these in O(1) time complexity.

A
class Node, set of keys, count, prev/next pointers
addKey, removeKey methods
Initialize:
head = node(min_safe_integer)
tail = node(max_safe_integer)
keyCount (map of keys to count)
countKeys (map of count to keys/nodes)
inc:
get oldCount from keyCount || 0
count = oldCount + 1
keyCount.set(key, count)
countKeys.set(count, new Node(count))
addKey
find oldNode and remove key
add new node to list (insert after oldNode)
if oldNode now empty (no keys), remove
dec:
if keyCount does not have key, return
get oldCount from keyCount
if oldCount is 1, delete from keyCount
count = oldCount - 1
keyCount.set(key, count)
add key to new count
find oldNode and remove key
add new node to list (insert before oldNode)
if oldNode now empty (no keys), remove

getMaxKey:
return one of keys from tail.prev

getMinKey:
return one of keys from head.next

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

Random Pick With Weight (Medium)

Given an array of positive integers w. where w[i] describes the weight of ith index (0-indexed).

We need to call the function pickIndex() which randomly returns an integer in the range [0, w.length - 1]. pickIndex() should return the integer proportional to its weight in the w array. For example, for w = [1, 3], the probability of picking index 0 is 1 / (1 + 3) = 0.25 (i.e 25%) while the probability of picking index 1 is 3 / (1 + 3) = 0.75 (i.e 75%).

More formally, the probability of picking index i is w[i] / sum(w).

A

Initialize:
Track totalSum and array of prefix sums

pickIndex:
target = Math.random() * totalSum
Binary search
start = 0
end = prefixSums.length - 1

while (low < high)
if target > prefixSums[mid] low = mid + 1
else high = mid - 1
return low

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