Skip to content

Commit 9f9f1be

Browse files
committed
Initial commit
0 parents  commit 9f9f1be

14 files changed

+522
-0
lines changed

.DS_Store

10 KB
Binary file not shown.

001_find_pairs.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Problem:
3+
This problem was recently asked by Google.
4+
5+
Given a list of numbers and a number k, return whether any two numbers from the list add up to k.
6+
For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17.
7+
Bonus: Can you do this in one pass?
8+
9+
"""
10+
11+
# Solution 1
12+
"""
13+
def findPairs(arr, sum):
14+
# Traverses through list twice to compare one element with the rest and find the sum
15+
for i in range(0, len(arr)):
16+
for j in range(0, len(arr)):
17+
if sum == arr[i] + arr[j]:
18+
return True
19+
return False
20+
"""
21+
22+
# Solution 2
23+
24+
def findPairs(arr, sum):
25+
26+
#Traverse through the list
27+
for i in range(0, len(arr)):
28+
if sum-i in arr:
29+
return True
30+
return False
31+
32+
33+
# Test
34+
A = [10, 15, 3, 7]
35+
print (findPairs(A, 17))
36+
37+

002_array_product_except_index.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
This problem was asked by Uber.
3+
4+
Given an array of integers, return a new array such that each element at index i of the new array is the product of
5+
all the numbers in the original array except the one at i.
6+
For example, if our input was [1, 2, 3, 4, 5], the expected output would be [120, 60, 40, 30, 24].
7+
If our input was [3, 2, 1], the expected output would be [2, 3, 6].
8+
Follow-up: what if you can't use division?
9+
"""
10+
11+
# Solution
12+
# Reference: https://www.interviewcake.com/question/python3/product-of-other-numbers
13+
"""
14+
The product of all the integers except the integer at each index can be broken down into two pieces:
15+
16+
the product of all the integers before each index and
17+
the product of all the integers after each index.
18+
"""
19+
20+
def get_array_product_except_index(arr):
21+
if len(arr) < 2:
22+
raise IndexError('To get the product, we need atlest 2 elements in the list')
23+
24+
# We make a list with length of input to hold the products
25+
products_expect_index = [None] * len(arr)
26+
27+
# For each integer, we find the product of all the integers
28+
# before it (left half) and store the total product so far
29+
# setting it 1 as there are no elements before first element to multiply
30+
31+
product_so_far = 1
32+
for i in range(len(arr)):
33+
products_expect_index [i] = product_so_far
34+
product_so_far *= arr[i]
35+
36+
37+
# For each integer, we find the product of all the integers
38+
# after it. Since each index in product already has the
39+
# product of all the integers before it, now we'are storing the total product of all other integers
40+
41+
# We traverse through the list backwards and calcuate the product using the already calucated product above.
42+
product_so_far = 1
43+
for i in range(len(arr) -1, -1, -1):
44+
products_expect_index[i] *= product_so_far
45+
product_so_far *= arr[i]
46+
47+
return products_expect_index
48+
49+
50+
51+
arr = [1, 2, 3, 4, 5]
52+
print ("Input : ", arr)
53+
print ("Output: ", get_array_product_except_index(arr))
54+
55+
"""
56+
Complexity:
57+
58+
O(n) time and
59+
O(n) space.
60+
61+
We make two passes through our input a list, and the list we build always has the same length as the input list.
62+
63+
"""

003_missing_positive_integer.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""This problem was asked by amazon.
2+
3+
Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.
4+
5+
For example, the input [3, 4, -1, 1] should give 2. The input [1, 2, 0] should give 3.
6+
7+
You can modify the input array in-place."""
8+
9+
# Solution:
10+
11+
# Approach 1:
12+
"""we would just sort the array, while filtering out negative numbers, and iterate over the sorted array and return the first number that doesn't match the index. However, sorting takes O(n log n), so we can't use that here."""
13+
14+
# Approach 2:
15+
"""Clearly we have to use some sort of trick here to get it running in linear time. Since the first missing positive number must be between 1 and len(array) + 1 (why?), we can ignore any negative numbers and numbers bigger than len(array). The basic idea is to use the indices of the array itself to reorder the elements to where they should be. We traverse the array and swap elements between 0 and the length of the array to their value's index. We stay at each index until we find that index's value and keep on swapping.
16+
17+
By the end of this process, all the first positive numbers should be grouped in order at the beginning of the array. We don't care about the others. This only takes O(N) time, since we swap each element at most once.
18+
19+
Then we can iterate through the array and return the index of the first number that doesn't match, just like before."""
20+
21+
22+
def first_missing_positive(nums):
23+
if not nums:
24+
return 1
25+
for i, num in enumerate(nums):
26+
while i + 1 != nums[i] and 0 < nums[i] <= len(nums):
27+
v = nums[i]
28+
nums[i], nums[v - 1] = nums[v - 1], nums[i]
29+
if nums[i] == nums[v - 1]:
30+
break
31+
for i, num in enumerate(nums, 1):
32+
if num != i:
33+
return i
34+
return len(nums) + 1
35+
36+
nums = [3, 4, -1, 1]
37+
print (first_missing_positive(nums))
38+
39+
# Approach 3:
40+
"""Another way we can do this is by adding all the numbers to a set, and then use a counter initialized to 1. Then continuously increment the counter and check whether the value is in the set."""
41+
42+
"""def first_missing_positive(nums):
43+
s = set(nums)
44+
i = 1
45+
while i in s:
46+
i += 1
47+
return i
48+
49+
This is much simpler, but runs in O(N) time and space, whereas the previous algorithm uses no extra space."""

004_Last_Stone_Weight.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Problem: https://leetcode.com/problems/last-stone-weight/
2+
"""
3+
We have a collection of rocks, each rock has a positive integer weight.
4+
5+
Each turn, we choose the two heaviest rocks and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is:
6+
7+
If x == y, both stones are totally destroyed;
8+
If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x.
9+
At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.)
10+
11+
12+
13+
Example 1:
14+
15+
Input: [2,7,4,1,8,1]
16+
Output: 1
17+
Explanation:
18+
We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1] then,
19+
we combine 2 and 4 to get 2 so the array converts to [2,1,1,1] then,
20+
we combine 2 and 1 to get 1 so the array converts to [1,1,1] then,
21+
we combine 1 and 1 to get 0 so the array converts to [1] then that's the value of last stone."""
22+
23+
import heapq
24+
class Solution:
25+
def lastStoneWeight(self, stones):
26+
# we will use heappop which pops smallest elmenent
27+
# Since we need largest, we are adding minus(-) and pick it using heappop
28+
pq = [-x for x in stones]
29+
heapq.heapify(pq)
30+
for i in range(len(stones)-1):
31+
x, y = -heapq.heappop(pq), -heapq.heappop(pq)
32+
heapq.heappush(pq, -abs(x-y))
33+
return -pq[0]

005_max_sum_nonadjacent.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# https://www.geeksforgeeks.org/maximum-sum-such-that-no-two-elements-are-adjacent/
2+
# Function to return max sum such that
3+
# no two elements are adjacent
4+
5+
"""
6+
Given an array of positive numbers, find the maximum sum of a subsequence with the constraint that no 2 numbers in the sequence should be adjacent in the array. So 3 2 7 10 should return 13 (sum of 3 and 10) or 3 2 5 10 7 should return 15 (sum of 3, 5 and 7).Answer the question in most efficient way."""
7+
8+
def find_max_sum(arr):
9+
incl = 0
10+
excl = 0
11+
12+
for i in arr:
13+
14+
# Current max excluding i (No ternary in
15+
# Python)
16+
new_excl = excl if excl>incl else incl
17+
18+
# Current max including i
19+
incl = excl + i
20+
excl = new_excl
21+
22+
# return max of incl and excl
23+
return (excl if excl>incl else incl)
24+
25+
# Driver program to test above function
26+
arr = [5, 5, 10, 100, 10, 5]
27+
print (find_max_sum(arr))
28+
29+
# Time Complexity: O(n)

006_climbing_stairs.py

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""
2+
This problem was asked by Amazon. [Hard]
3+
4+
There exists a staircase with N steps, and you can climb up either 1 or 2 steps at a time. Given N, write a function that returns the number of unique ways you can climb the staircase. The order of the steps matters.
5+
6+
For example, if N is 4, then there are 5 unique ways:
7+
8+
1, 1, 1, 1
9+
2, 1, 1
10+
1, 2, 1
11+
1, 1, 2
12+
2, 2
13+
14+
What if, instead of being able to climb 1 or 2 steps at a time, you could climb any number from a set of positive integers X? For example, if X = {1, 3, 5}, you could climb 1, 3, or 5 steps at a time."""
15+
16+
# Solution:
17+
""" Let's start with small test cases and see if we can find some sort of patterns
18+
19+
Number of stairs -> N
20+
N = 1 -> [1]
21+
N = 2 -> [1, 1], [2]
22+
N = 3 -> [1, 1, ,1] , [1,2] [2,1]
23+
N = 4 -> [1, 1, 1, 1], [1,2,1], [1,1,2], [2,2], [2,1,1]
24+
25+
The only ways to get to N = 3, is to first get to N=1 and then go up by 2 steps, or get to N=2 and go by up by 1 step. So f(3) = f(2) + f(1)
26+
27+
Does this hold for N = 4? Yes, it does. Since we can only get to the 4th step by getting to the 3rd step and going up by one, or by getting to the 2nd step and going up by two. So f(4) = f(3) + f(2).
28+
29+
30+
To generalize, f(n) = f(n - 1) + f(n - 2). That's just the Fibonacci sequence!
31+
------------------------------------------
32+
def staircase(n):
33+
if n < =1:
34+
return 1
35+
return staircase(n-1) + staircase(n-2)
36+
------------------------------------------
37+
38+
39+
Of course, this is really slow (O(2^N)) — we are doing a lot of repeated computations! We can do it a lot faster by just computing iteratively.
40+
-------------------------------
41+
def staircase(n):
42+
a = 1
43+
b = 2
44+
for _ in range(n-1):
45+
a, b = b, a+b
46+
return a
47+
48+
print (staircase(3))
49+
-------------------------------
50+
51+
Now, let's try to generalize what we've learned so that it works if you can take a number of steps from the set X. Similar reasoning tells us that if X = {1, 3, 5}, then our algorithm should be f(n) = f(n - 1) + f(n - 3) + f(n - 5). If n < 0, then we should return 0 since we can't start from a negative number of steps.
52+
53+
Let X = {1, 3, 5}
54+
# Recursive approach O(X^N)
55+
------------------------------
56+
def staircase(n, X):
57+
if n <0:
58+
return 0
59+
elif n == 1:
60+
return 1
61+
else:
62+
return sum(staircase(n - e) for e in X)
63+
64+
This is again, very slow (O(|X|^N)) since we are repeating computations again. We can use dynamic programming to speed it up.
65+
66+
Each entry cache[i] will contain the number of ways we can get to step i with the X."""
67+
68+
def staircase(n, X):
69+
cache = [0 for _ in range(n+1)]
70+
cache[0] = 1
71+
for i in range(1, n+1):
72+
cache[i] += sum(cache[i-x] for x in X if i-x >=0)
73+
return cache[n]
74+
75+
X = {1, 3, 5}
76+
print (staircase(4, X))
77+
78+
#This now takes O(N * |X|) time and O(N) space.
79+
80+
81+
82+
83+
84+
85+
86+

007_longest_substring_count.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""This problem was asked by Amazon. [Hard]
2+
3+
Given an integer k and a string s, find the length of the longest substring that contains at most k distinct characters.
4+
5+
For example, given s = "abcba" and k = 2, the longest substring with k distinct characters is "bcb".
6+
"""
7+
# =====================================================================================================
8+
# Solution 1:
9+
"""The most obvious brute force solution here is to simply try every possible substring of the string to check whether it containts at most k distinct characters. If it does and it is greater than the current longest valid substring, then update the current one. """
10+
11+
"""def longest_substring_with_k_distinct_chars(s, k):
12+
current_longest_substring = ''
13+
for i in range(len(s)):
14+
for j in range(i+1, len(s)+1):
15+
substring = s[i:j]
16+
if len(set(substring)) <= k and len(substring) > len(current_longest_substring):
17+
current_longest_substring = substring
18+
return len(current_longest_substring)
19+
20+
print (longest_substring_with_k_distinct_chars("abcba",2))"""
21+
22+
"""This takes O(n^2 * k) time, since we use n2 to generate each possible substring, and then take k to check each character."""
23+
# =====================================================================================================
24+
25+
# Solution 2:
26+
27+
"""
28+
We can improve this by instead of keeping a running window of our longest substring. We keep a dictionary that maps characters to the index of their last occurence. Then, as we iterate over the string, we will check the size of the dictionary. If it's larger than k, then it means our window is too big, so we have to pop the smallest item in the dictionary and recompute the outbounds. If, when we add a character to the dictionary and it doesn't go over k, then we are safe - the dictionary hasn't been filled up yet or it's a character we have seen before.
29+
"""
30+
def longest_substring_with_k_distinct_chars(s,k):
31+
if k ==0:
32+
return 0
33+
34+
# keep a running window
35+
bounds = (0,0)
36+
h = {}
37+
max_length = 0
38+
for i, char in enumerate(s):
39+
h[char] = i
40+
if len(h) <=k:
41+
new_lower_bound = bounds[0] # lower bound remain same
42+
else:
43+
#otherwise, pop last occuring char
44+
key_to_pop = min(h, key=h.get)
45+
new_lower_bound = h.pop(key_to_pop) + 1
46+
47+
bounds = (new_lower_bound, bounds[1]+1)
48+
max_length = max(max_length, bounds[1] - bounds[0])
49+
return max_length
50+
51+
print (longest_substring_with_k_distinct_chars("abcba",2))
52+
53+
# This takes O(n * k) time and O(k) space.

008_Reversing_array.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
The problem is that we want to reverse a T[] array in O(N) linear time complexity and we want the algorithm to be in-place as well!
3+
4+
For example: input is [1,2,3,4,5] then the output is [5,4,3,2,1]"""
5+
6+
# Solution:
7+
# In place algorithms that reverses array in O(N) with no extra space
8+
9+
def array_reversal(arr):
10+
11+
# pointer to the first item
12+
start_index = 0
13+
# pointer to the last time
14+
end_index = len(arr) - 1
15+
16+
# while the end index is greater than the start index
17+
while end_index > start_index:
18+
#swap two items
19+
arr[start_index], arr[end_index] = arr[end_index], arr[start_index]
20+
21+
#increment the start index
22+
start_index += 1
23+
24+
# decrement the end index
25+
end_index -= 1
26+
27+
return arr
28+
29+
if __name__ == "__main__":
30+
arr = [1, 2, 3, 4, 5]
31+
print (array_reversal(arr))

0 commit comments

Comments
 (0)