Best time to buy a stock
You are given an array prices where prices[i] is the price of a given stock on the ith day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
time: O(n)
space: constant
class BestStockPrice(object):
Contains Duplicate
Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct.
time: linear
space: linear
class ContainsDuplicates(object):
Murder witnesses
Hi, here’s your problem today. This problem was recently asked by Google:
There are n people lined up, and each have a height represented as an integer. A murder has happened right in front of them, and only people who are taller than everyone in front of them are able to see what has happened. How many witnesses are there?
Example: Input: [3, 6, 3, 4, 1] Output: 3 Explanation: Only [6, 4, 1] were able to see in front of them. -# -# -#-# #### #### ##### 36341----------------------------x (murder scene)
time: O(n)
space: constant
import sys class Solution: ----def answer(self, arr): --------_max=-sys.maxsize-1 --------count=0 --------for i in range(len(arr)-1, -1, -1): ------------if arr[i]>_max: ----------------count+=1 ----------------#_max=max(arr[i], _max) ----------------_max=arr[i] --------return count
Sort list of 3 unique numbers
Hi, here’s your problem today. This problem was recently asked by Google:
Given a list of numbers with only 3 unique numbers (1, 2, 3), sort the list in O(n) time.
Example 1: Input: [3, 3, 2, 1, 3, 2, 1] Output: [1, 1, 2, 2, 3, 3, 3] def sortNums(nums): # Fill this in.
print sortNums([3, 3, 2, 1, 3, 2, 1]) # [1, 1, 2, 2, 3, 3, 3]
time: O(n), we do 1 loop
space: constant, we do not create any additional structures
class Solution:
Pythagorean triplets
Hi, here’s your problem today. This problem was recently asked by Uber:
Given a list of numbers, find if there exists a pythagorean triplet in that list. A pythagorean triplet is 3 variables a, b, c where a^2 + b^2 = c^2
Example:
Input: [3, 5, 12, 5, 13]
Output: True
Here, 5^2 + 12^2 = 13^2.
brute for is n^3 without making a preprocessed set, probably need to do some square root stuff too
time: O(n^2), we need to loop twice to see all the values
space: O(n) to store the c^2
class Solution:
First and last index of string/number
Hi, here’s your problem today. This problem was recently asked by AirBNB:
Given a sorted array, A, with possibly duplicated elements, find the indices of the first and last occurrences of a target element, x. Return -1 if the target is not found.
# Example: # Input: A = [1,3,3,5,7,8,9,9,9,15], target = 9 # Output: [6,8]
# Input: A = [100, 150, 150, 153], target = 150 # Output: [1,2]
# Input: A = [1,2,3,4,5,6,10], target = 9 # Output: [-1, -1]
brute force is O n, loop until you find, continue until the number isn’t the target
time: O log(n), binary search
space: O 1, constant space, all work is done in place, no new values stored
class Solution:
strategies for arrays
SORTED use pointers
binary search if you need to look through a sorted array, binary search can return left which is the first index that is larger than it (or it can return len(N), so check for that)
if asked to list combinations of an item, backtracking
There are more array-related data structures or techniques you might want to know. We will not go deeper into most of the concepts in this card but provide the links to the corresponding card in this article.
String (has been introduced in this card)
Hash Table
Linked List
Queue
Stack
2. As we mentioned, we can call the built-in function to sort an array. But it is useful to understand the principle of some widely-used sorting algorithms and their complexity.
Slow-pointer and fast-pointer problem in Linked List
Sliding Window Problem
5. The two-pointer technique sometimes will relate to Greedy Algorithm which helps us design our pointers’ movement strategy.
We will come up with more cards to introduce these techniques mentioned above and update the link in the near future.
Product of Array Except Self
Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].
The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
You must write an algorithm that runs in O(n) time and without using the division operation.
brute force involves a double for loop or using 2 other arrays and doing matrix-type-evaluations on the values before/after the given index.
[1 2 3 4]
forward=[1 1 2 6 ]
backward=[24 12 4 1]
time: O(2n), we loop twice,
space: contant, the response array does not count
class ProductArrayExceptSelf(object):
Maximum addition subarray
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
brute is a double for loop that compares max each iteration
time: linear, O(n)
space: constant
class Solution:
BONUS: good to know how to solve a problem this way
time: O( N*log(N)), we loop through once then split into smaller arrays and loop through those. classic NlogN
space: log (n), this is based off the recursive calls, since lh and rh are being calculate at different times, we only ever see log(n) calls on the stack
————bc = nums[mid]+bl+br
max product subarray
Given an integer array nums, find a contiguous non-empty subarray within the array that has the largest product, and return the product.
It is guaranteed that the answer will fit in a 32-bit integer.
A subarray is a contiguous subsequence of the array.
brute is double for loop with some logic, calculating the max at each iteration. a linear 2 pass solution is to calculate the max going forward/backward.
time: O(n), linear, we do 1 pass
space: constant, we only make new variables
class Solution:
pascal’s triangle 2
Given an integer rowIndex, return the rowIndexth (0-indexed) row of the Pascal’s triangle.
In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:
pascals triangle is a triangle where the edges are always 1 and the inner sections are sums of the parts above it
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
time: O(n^2), we loop through all the row indexes and the lengths of the arrays space O(n^2 + n), since we make an array at each iteration, the space taken up by all the arrays is n^2, the n includes the answer array. I confirmed recursive calls that create arrays are n * height of tree in space, in this case it is n^2
class Solution:
time: O(n^2), we loop through all the row indexes and the lengths of the arrays
space: O(n), linear since we only keep track of the previous array
- —def custom_optimal(self, rowIndex):
- ——-prev, current = deque([1] * (rowIndex + 1)), deque([1] * (rowIndex + 1))
- ——-for i in range(rowIndex + 1):
- ———–for j in range(i):
- —————if j == 0:
- ——————-continue
- —————else:
- ——————-current[j] = prev[j - 1] + prev[j]
- ———–prev, current = current, prev
- ——-return prev
BONUS if you realize you can calculate the next array from the current array, we can even remove the previous array space, making it constant!
Given an integer numRows, return the first numRows of Pascal’s triangle.
In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:
Input: numRows = 5
Output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
Input: numRows = 1
Output: [[1]]
time: O(n^2), we have 5, 4, 3, 2, 1, operations, reduces to n^2
space: the response array is a pascal triangle that takes up n^2 space
class Solution:
Kth Largest Element in an Array
Given an integer array nums and an integer k, return the kth largest element in the array.
Note that it is the kth largest element in the sorted order, not the kth distinct element.
brute force is to do quick sort/heap sort/any sort, then do len(nums)-k and return that index (7-1 gives 6, which would be the largest in an ascending sorted array)
time: O(n) average, worst case same as quick sort which is N^2
space: O(log(n)) average, worst case would be O(n). This comes from the recursive calls resulting from a bad pivot
class Solution:
Combinations
Given two integers n and k, return all possible combinations of k numbers out of the range [1, n].
You may return the answer in any order.
easiest way is to use itertools.combinations(iterable, length). get the iterable from range(1, n+1), then loop over the result and append them to the list. (make sure to convert the tuples to lists first)
time: O(k*combination count) N!/(k!(n-k)!) is the formula for the number of combinations given options N and length K. appending a list takes K time where k is the length of the list, which is why is has the k
space: O(combination count) which is the space of the final return list. if not counting that, it would be N which is the heigh of the recursion tree
class Solution:
permutations
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
brute is to use itertools.permutations(iterable, length), returns a list of tuples. conver the tuples to lists and append to output
time: N!, since it takes N! / (N-K)! to calculate the permutations. N is the values to choose from, K is the size (9 digit keypad, 4 digit code)
space: N!, since that is the output array, recursion depth is N
class Solution:
Find The Duplicates
Given two sorted arrays arr1 and arr2 of passport numbers, implement a function findDuplicates that returns an array of all passport numbers that are both in arr1 and arr2. Note that the output array should be sorted in an ascending order.
time: O(n+m) since worst case we traverse through both of the arrays fully,
space: is output (constant)
class Solution:
time: N log(m) where n is smaller and M is larger
space: output array (constant)
Largest rectangle in histograms
Given an array of integers heights representing the histogram’s bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.
brute force would be to do a double for loop, calculating the area based on the minimum value seen since that is the limiting factor of the rectangle area
class Solution:
time: N log N
space: constant
- —def divide_conquer(self, heights):
- ——-output = 0
- ——-for i in range(len(heights)):
- ———–minimum=heights[i]
- ———–for j in range(i, len(heights)):
- —————current = heights[j]
- —————minimum = min(minimum, current)
- —————response = minimum*(j-i+1)
- —————output = max(output, response, current)
- ——-return output
Min Stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Implement the MinStack class:
MinStack() initializes the stack object. void push(int val) pushes the element val onto the stack. void pop() removes the element on the top of the stack. int top() gets the top element of the stack. int getMin() retrieves the minimum element in the stack.
time: everything is linear
space: the stack itself is N, the min_stack could be N space too worst case
class MinStack:
find pivot index
Given an array of integers nums, calculate the pivot index of this array.
The pivot index is the index where the sum of all the numbers strictly to the left of the index is equal to the sum of all the numbers strictly to the index’s right.
If the index is on the left edge of the array, then the left sum is 0 because there are no elements to the left. This also applies to the right edge of the array.
Return the leftmost pivot index. If no such index exists, return -1.
Example 1:
Input: nums = [1,7,3,6,5,6]
Output: 3
Explanation:
The pivot index is 3.
Left sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11
Right sum = nums[4] + nums[5] = 5 + 6 = 11
brute force could be a 2 pointer, calculate sum on each side of inner-loop, return if true
I tried a 2-pointer solution, but there are too many edge cases with negative numbers that make a left/right sum with pointers extremely difficult
time: O(N)
space: constant
class Solution:
largest number at least twice of others
You are given an integer array nums where the largest integer is unique.
Determine whether the largest element in the array is at least twice as much as every other number in the array. If it is, return the index of the largest element, or return -1 otherwise.
keep track of the largest and second-largest index, at the end check if the largest index is greater than or equal twice that of the second-largest
time: O(N):
space: constant
class Solution:
plus one
You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0’s.
Increment the large integer by one and return the resulting array of digits.
time: O(N)
space: O(N) in worst case bc if we have they’re all 9, we need to add a 1 to the beginning which will require N space
class Solution:
top k frequent words
Given an array of strings words and an integer k, return the k most frequent strings.
Return the answer sorted by the frequency from highest to lowest. Sort the words with the same frequency by their lexicographical order.
time: O(n * log(k)), standard heapq.nlargest time complexity. linear time to make the counter, linear time to make the initial heap
space: linear spae for the counter/heap, k space for the heap
TIME2: O(Klogn)), this is achieved by max-heapifying the array (O(n) time to heapify), then performing max_heappop operations for the range of k. heappop is log(N) and we do it K times, so K*log(n)
SPACE2: linear,
import heapq
from collections import defaultdict, Counter
class Solution:
—-def kLogN(self, words, k):
——–frequency = Counter(words)
——–heap = []
——–for word, freq in frequency.items():
————heap.append(Comparator(freq, word))
——–
——–heapq._heapify_max(heap)
——–return [str(heapq._heappop_max(heap)) for _ in range(k)]
—-def NlogK(self, words, k):
——–frequency = Counter(words)
——–# frequency = defaultdict(int)
——–# for word in words:
————# frequency[word] += 1
——–heap = []
——–for word, freq in frequency.items():
————heap.append(Comparator(freq, word))
——–
——–response = heapq.nlargest(k, heap)
——–return [str(x) for x in response]
————
————
class Comparator:
—-def __init__(self, count, letter):
——–self.count = count
——–self.letter = letter
——–
—-def __lt__(self, other):
——–if self.count == other.count:
————return self.letter > other.letter
——–return self.count < other.count
—-
—-def __str__(self):
——–return str(self.letter)
print(Solution().kLogN([“i”,”love”,”leetcode”,”i”,”love”,”coding”], 2))
pascals triangle
Given an integer numRows, return the first numRows of Pascal’s triangle.
In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:
Example 1:
Input: numRows = 5
Output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
time: O(n^2), we do a double loop from 0 to N, which is by definition quadradic
space: O(n^2) if we count the output array, else it is constant
class Solution:
Remove element from array
Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The relative order of the elements may be changed.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.
Return k after placing the final result in the first k slots of nums.
Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory.
time: O(N), we do 1 loop from both ends
space: constant
class Solution:
time: O(n), we have to iterate through the array
space: constant