My walkthroughs, designed to help build solid fundamentals and understanding for concepts in data structures and algorithms, and how to identify patterns and efficiently solve various DSA problems.
This project contains comprehensive walkthroughs for how to solve data structures and algorithm related problems. I detail how I derived my solution, algorithms, and how to build intuition and discover patterns to solve these problems efficiently.
def findOrder(self, numCourses, prerequisites):
prereq = {i:[] for i in range(numCourses)}
for course, prereqs in prerequisites:
prereq[course].append(prereqs)
output = []
visit, cycle = set(), set()
def dfs(courses):
if courses in cycle:
return False
if courses in visit:
return True
cycle.add(courses)
for i in prereq[courses]:
if dfs(i) == False: return False
cycle.remove(courses)
visit.add(courses)
output.append(courses)
return True
for i in range(numCourses):
if dfs(i) == False:
return []
return output
Use the sliding window pattern whenever you need to work with arrays, linked lists or any data structure where the elements need to be iterated through in a contiguous order. Sliding window works well as we visit the elements only once hence avoid duplicates or constantly revisiting elements as seen with brute force approaches. The main takeaway here should be that the sliding window pattern should be the first thing which comes to mind when doing anything which involves subsets of any given set ie subarrays of an array.
Fixed length sliding window means that the windows size does not change, hence, the subarray size we are looking at will never change, we are always looking at the same number of elements. For this problem all we need to do is once our sliding window hits the fixed size given in the question we simply increment both window_start and window_end and take the max of each contiguous fixed window until we reach the end of the array.
def minSubArrayLen(target, nums):
min_window_size = 2 ** 31 - 1
current_window_sum = 0
window_start = 0
flag = False
for window_end in range(len(nums)):
current_window_sum += nums[window_end]
while current_window_sum >= target:
min_window_size = min(min_window_size, window_end - window_start + 1)
current_window_sum -= nums[window_start]
window_start += 1
flag = True
return min_window_size if flag == True else 0
Dynamic sized sliding windows have no fixed length they are altered in respect to the given conditions of the problem. A dynamic sized sliding window works well for this problem as, what we need to do is have two pointers, I like to refer to them as windowStart and windowEnd. Starting from the beginning and end of the array we adjust our two pointers hence our dynamic window in order to find the largest area of the container. The formula is simply area = width x height, where height is the minimum value between the elements which are at the windowStart and windowEnd indexes in the array. The width is the distance between these elements, given as windowEnd - windowStart.
def maxArea(height):
maxSum = 0
windowStart = 0
windowEnd = len(height) - 1
while windowStart < len(height):
runningSum = min(height[windowStart], height[windowEnd]) * (windowEnd - windowStart)
maxSum = max(maxSum, runningSum)
if height[windowEnd] < height[windowStart]:
windowEnd -= 1
else:
windowStart += 1
return maxSum
The idea for this algorithm is if we add every element in our window into our set, if we come across the same element we have a duplicate somewhere we keep removing elements from the set until the duplicate issue is rectified, finally as we are adding elements to our set, we are recording the MAX length of the set, we return the max length the set was hence the longest non-repeating substring.
def lengthOfLongestSubstring(s):
# Starting window index
windowStart = 0
# Ending window index
windowEnd = 0
# Our running sum which holds the max subarray(window size) which is a set of substring of our string without repetitions
running_sum = 0
# Our hash set which will hold the characters without holding any repeats
hash_set = set()
while windowEnd < len(s):
# We need to stop when the end window index reaches the end of the array
if s[windowEnd] not in hash_set:
# If the current element we are looking at is not in the set, add it to the set.
hash_set.add(s[windowEnd])
# Increase the size of our window
windowEnd += 1
# Update the running_sum to hold the new max window size, if the new size is less of course we will stick with the previous max window size of running sum
running_sum = max(running_sum, len(hash_set))
else:
# Else, if we have come across a repetition, this means that the current element we are looking at with s[windowEnd] is already in our hash_set, so we are going to remove the first element
# in our hash set, thus incrementing our window as we don't want the repeats, we keep doing this until that repeat is gone
hash_set.remove(s[windowStart])
# This will make the size of our window smaller
windowStart += 1
return running_sum
def lengthOfLongestSubstringTwoDistinct(s):
hash_map = {}
windowStart = 0
windowEnd = 0
maxLen = 0
while windowEnd < len(s):
hash_map[s[windowEnd]] = windowEnd
if len(hash_map) >= 3:
find_min = min(hash_map.values())
del hash_map[s[find_min]]
windowStart = find_min + 1
maxLen = max(maxLen, windowEnd - windowStart + 1)
windowEnd += 1
return maxLen
Dynamic sliding window, two pointer approach, apply x + y + z = 0 formula nice and easy!
IMPORTANT NOTES!
If we need to check 3 elements in an array we must use len(array) -2, if we need to check only two elements we use len(array) -1 and follow this pattern
USING CONTINUE MEANS YOU SKIP THE ITERATION OF THE FOR LOOP!
Use if i > 0 and nums[i] == nums[i-1]: continue to check for duplicates!
def threeSum(nums):
triples = []
# We need to sort before doing any 2sum, 3sum approach using dynamic window
nums.sort()
# We use len - 2 because we need at least 3 numbers to continue
for i in range(len(nums) - 2):
# This is how we can check for duplicates and avoid them! THIS IS MUCH MORE EFFICIENT THAN USING A SET!
if i > 0 and nums[i] == nums[i - 1]:
continue
windowStart = i + 1
windowEnd = len(nums) - 1
while windowStart < windowEnd:
target = nums[i] + nums[windowStart] + nums[windowEnd]
if target < 0:
windowStart += 1
elif target > 0:
windowEnd -= 1
else:
triples.append((nums[i], nums[windowStart], nums[windowEnd]))
# These two while loops will avoid the duplicates for both windows!
while windowStart < windowEnd and nums[windowStart] == nums[windowStart + 1]:
windowStart += 1
while windowStart < windowEnd and nums[windowEnd] == nums[windowEnd - 1]:
windowEnd -= 1
windowStart += 1
windowEnd -= 1
return triples
The pattern here is that we always use the inorder traversal list to build the tree. In particular, we can dervie the root indexes easily from both preorder and postorder as preorder root = 0th element and postorder root = -1 element in respective lists. Now we know that once we have the main root we can identify the left and right subtrees from the inorder list. We then recursively keep popping off the indexes and assigning them as roots from the pre/postorder traversal lists, building left subtree to right subtree recursivley for preorder and right subtree to left subtree recursivley for postorder.
def buildTree(inorder, postorder):
def recurse(inorder, postorder):
if not inorder or not postorder: return
root = TreeNode(postorder.pop())
root.right = recurse(inorder[inorder.index(root.val) + 1:], postorder)
root.left = recurse(inorder[:inorder.index(root.val)], postorder)
return root
return recurse(inorder, postorder)
def buildTree(preorder, inorder):
def recurse(preorder, inorder):
if not inorder: return
root = TreeNode(preorder.pop(0))
mid = inorder.index(root.val)
root.left = recurse(preorder, inorder[:mid])
root.right = recurse(preorder, inorder[mid + 1:])
return root
return recurse(preorder, inorder)
However, we can optimize this by using a hash table and “binary search” pattern. All we do is assign the inorder indexes and corresponding values to the hash table, hence we get O(1) searching/indexing time for finding the mid, and instead of the lists, we pass to min and max indexes which we increment in respect to mid, so similar to a binary search.
*OPTIMAL
def buildTree(preorder, inorder):
hashMap = {value: index for index, value in enumerate(inorder)}
def recurse(minVal, maxVal):
if minVal > maxVal: return
root = TreeNode(preorder.pop(0))
mid = hashMap[root.val]
root.left = recurse(minVal, mid - 1)
root.right = recurse(mid + 1, maxVal)
return root
return recurse(0, len(inorder) - 1) # (36 ms, faster than 99.21%, 18.1 MB, less than 90.83%)
hashMap = {inorder[i]: i for i in range(len(inorder))}
def recurse(minVal, maxVal):
if minVal > maxVal: return
root = TreeNode(postorder.pop())
midVal = hashMap[root.val]
root.right = recurse(midVal + 1, maxVal)
root.left = recurse(minVal, midVal - 1)
return root
return recurse(0, len(inorder) - 1)
def letterCombinations(self, digits):
if digits == "":
return []
hash_map = {1: [], 2: ["a", "b", "c"], 3: ['d', 'e', 'f'], 4: ['g', 'h', 'i'], 5: ['j', 'k', 'l'],
6: ['m', 'n', 'o'], 7: ['p', 'q', 'r', 's'], 8: ['t', 'u', 'v'], 9: ['w', 'x', 'y', 'z']}
def backTrack(path, index):
if index == len(digits):
combinations.append("".join(path))
return
else:
curr_key_letters = hash_map[int(digits[index])]
for letter in curr_key_letters:
path.append(letter)
backTrack(path, index + 1)
path.pop()
combinations, path = [], []
backTrack(path, 0)
return combinations
def letterCombinations(self, digits):
if digits == "":
return []
# Mapping where each key is the digit number and values are the letters assigned to it.
hash_map = {1: [], 2: ["a", "b", "c"], 3: ['d', 'e', 'f'], 4: ['g', 'h', 'i'], 5: ['j', 'k', 'l'],
6: ['m', 'n', 'o'], 7: ['p', 'q', 'r', 's'], 8: ['t', 'u', 'v'], 9: ['w', 'x', 'y', 'z']}
# Recursive function to generate the combination strings.
def backTrack(path, index):
if index == len(digits):
combinations.append("".join(path))
return
else:
curr_key_letters = hash_map[int(digits[index])]
for letter in curr_key_letters:
path.append(letter)
backTrack(path, index + 1)
path.pop()
combinations, path = [], []
backTrack(path, 0)
return combinations
def generateParenthesis(self, n):
result, stack = [], []
def backTrack(open_count, close_count):
if len(stack) == (2 * n):
result.append("".join(stack))
return
if open_count < n:
stack.append("(")
backTrack(open_count + 1, close_count)
stack.pop()
if close_count < open_count:
stack.append(")")
backTrack(open_count, close_count + 1)
stack.pop()
backTrack(0, 0)
return result
def fib(n):
if n <= 1:
return n
else:
return fib(n-1) + fib(n-2)
print(fib(6))
def fibM(n, memo={}):
if n in memo:
return memo[n]
elif n < 2:
return n
else:
memo[n] = fibM(n-1) + fibM(n-2)
return fibM(n-1) + fibM(n-2)
def missingNumber(self, nums):
# Remember the Gaussian summation formula! The sum of a sequence is n(n+1)/2
# This is a beautiful solution. The sum as the gauss formula gives us the sum of n natural numbers and we use that sum to figure out which value is missing as the sum of the nums array is going to give us the sum of n natural numbers also, minus one number from that set of n naturals, and we can easily find that number by taking the difference between the guassian and array sum.
gauss = len(nums) * (len(nums) + 1) // 2
num_sum = sum(nums)
return gauss - num_sum
def getGCD(num1, num2):
while num1 % num2 != 0:
prev_num1 = num1
prev_num2 = num2
num1 = prev_num2
num2 = prev_num1
return num2
def recurisveGCD(num1, num2):
if num2 > num1:
return recurisveGCD(num2, num1)
elif num1 % num2 == 0:
return num2
else:
return recurisveGCD(num2, num1 % num2)
def getFactors(n):
return [i for i in range(1, n+1) if n % i == 0]
def checkPrime(n):
return "{} is not prime number".format(n) if len([i for i in range(2, n) if n % i == 0]) >= 1 else "{} is a prime number".format(n)
def getPrimeFactors(n):
i = 2
prime_factors = []
while i <= n:
if n % i == 0:
prime_factors.append(i)
n /= i
else:
i += 1
return prime_factors
All we need to do with this question is firstly clean up the given string S by making it uppercase and replacing all instances of - with empty strings.
Now, the main trick to solving this problem is the fact that the first grouping can have any number of elements, hence this is why we need to work FROM THE END of the string. As all we really need to do is split the string into groups of size K, however the first group can be any size aslong as the rest are size K, meaning the first group is like the leftovers which we get from splitting the string into K units! Therefore, all we need to do to solve this problem is run a simple string splitting for loop, BUT FIRST REVERSE THE LIST, because we want to our leftovers which are not a full K units to be the first alphanumeric characters in the string. Finally, after completing the splitting process return the string reversed again, hence in the original order.
def licenseKeyFormatting(self, S, K):
S = S.replace('-','').upper()[::-1]
#Replace the dashes, go uppercase, reverse the string
new_S = []
#Break the string into K units append each unit to new list
for i in range(0, len(S), K):
new_S.append(S[i:i+K])
#Join the new list and return in after reversing!
return "-".join(new_S)[::-1]
Remember the time conversions!
def nextClosestTime(time):
hoursInMins = int(time[:2]) * 60
totalMins = hoursInMins + int(time[3:])
hashSet = set()
for i in time:
if i.isdigit():
hashSet.add(int(i))
while True:
totalMins = (totalMins + 1) % (1440)
totalNewTime = str(totalMins / 60 / 10) + str(totalMins / 60 % 10) + ":" + str(totalMins % 60 / 10) + str(
totalMins % 60 % 10)
flag = True
for i in totalNewTime:
if i.isdigit():
if int(i) not in hashSet:
flag = False
if flag == True:
return totalNewTime
def inflectionPointPattern(nums):
# If the element at the 0th index is <= the element at the end of the array, then the array has NOT been rotated so return the first value
# As the first value IS the minimum value
# [1,2,3,4,5] implies n[0] <= n[-1] implies 1 <= 5 implies array HAS NOT been rotated
# [5,1,2,3,4] implies n[0] <= n[-1] implies 5 > 4 implies array HAS been rotated
# [2,3,4,5,1] implies n[0] <= n[-1] implies 2 > 1 implies array HAS been rotated
if nums[0] <= nums[-1]:
return nums[0]
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
# If value behind/prior to the current value is GREATER THAN the current value, this implies that the current value is the inflection point
# This is because that remember the array is in sorted order, so even if it has been rotated, if you ever arrive at an instance where
# nums[i-1] > nums[i] then nums[i] is the inflection point
# [2,3,4,5,1], nums[i] = 1, then nums[i-1] = 5, then nums[i-1] > nums[i] then nums[i] MUST be the inflection point as there can only ever
# be one such occurence in the rotated sorted array!
if nums[(mid-1)%len(nums)] > nums[mid]:
return nums[mid]
# If value at the current index is greater than the value at the i+1th index, then clearly, given this is a sorted array the value at the
# i+1th index is the inflection point!
# [3,4,5,1,2], given nums[i] = 5, then nums[i+1] = 1, then nums[i] > nums[i+1] but because the array is sorted this should be impossible!
# However the array is rotated and all this implies is that the i+1th index element is the inflection point!
elif nums[mid] > nums[(mid+1)%len(nums)]:
return nums[(mid+1)%len(nums)]
# If the element at the current mid index is greater than the element at the start of the array, then we can say that up till this point
# in the array it is in proper sorted order so we just go right.
# [2,3,4,5,1], mid = 4, nums[0] = 2, therefore 4 > 2, hence nums[0:mid] is in proper sorted order so we go right!
elif nums[mid] > nums[0]:
left = mid + 1
# If the element at the current mid index is LESS THAN the element at the 0th index, the start of the array, this implies that the rotated
# portion of the array falls within nums[0:mid], this implies that the smallest element falls within this subarray too, so we need to go
# left
# [5,1,2,3,4]
else:
right = mid - 1
# MAIN KEY FOR GOING LEFT AND RIGHT IN THE ROT
# TO GO LEFT IN ARRAY FOR BINARY SEARCH WE DO RIGHT = MID -1
# TO GO RIGHT IN ARRAY FOR BINARY SEARCH WE DO LEFT = MID + 1
print(inflectionPointPattern([1,2,3,4,5]))
print(inflectionPointPattern([5,1,2,3,4]))
print(inflectionPointPattern([2,3,4,5,1]))
print(inflectionPointPattern([2,1]))
public static int findInflectionPoint(int[] nums) {
if (nums[0] <= nums[nums.length-1]) {
return nums[0];
}
int left,right,mid;
left = 0;
right = nums.length-1;
while (left<=right) {
mid = (left+right) / 2;
if (mid != 0 && nums[mid] < nums[(mid-1)%nums.length]) {
return nums[mid];
}
else if (nums[mid] > nums[(mid+1)%nums.length]) {
return nums[(mid+1)%nums.length];
}
else if (nums[mid] > nums[0]) {
left = mid + 1;
}
else if (nums[mid] < nums[0]) {
right = mid - 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] nums = {5,1,2,3,4};
System.out.println(findInflectionPoint(nums));
}
public static int findInflectionPoint(int[] nums) {
if (nums[0] <= nums[nums.Length-1]) {
return nums[0];
}
int left, right, mid;
left = 0;
right = nums.Length-1;
while (left<=right) {
mid = (left+right) / 2;
if (mid != 0 && nums[mid] < nums[(mid-1)%nums.Length]) {
return nums[mid];
}
else if (nums[mid] > nums[(mid+1)%nums.Length]) {
return nums[(mid+1)%nums.Length];
}
else if (nums[mid] > nums[0]) {
left = mid + 1;
}
else if (nums[mid] <= nums[0]) {
right = mid - 1;
}
}
return -1;
}
public static void Main(string[] args) {
int[] nums = {5,1,2,3,4};
Console.WriteLine(findInflectionPoint(nums));
}
def countSeq(nums):
nums_set = set(nums)
max_sequence = 1
for i in nums_set:
if i-1 not in nums_set:
count = 1
sequence = i+1
while sequence in nums_set:
count += 1
sequence += 1
max_sequence = max(max_sequence, count)
return max_sequence
print(countSeq([0,3,7,2,5,8,4,6,0,1]))
class LongestConsecutiveSequence {
public static int maxSeq(int[] nums) {
Set<Integer> hashSet = new HashSet<>();
for (int i=0; i<nums.length;i++) {
hashSet.add(nums[i]);
}
int sequence, maxSeq, count;
maxSeq = 1;
count = 1;
for (int i=0;i<nums.length;i++) {
if (!hashSet.contains(nums[i]-1)) {
sequence = nums[i] + 1;
count = 1;
while (hashSet.contains(sequence)) {
count++;
sequence++;
}
}
maxSeq = Math.max(maxSeq, count);
}
return maxSeq;
}
public static void main(String[] args) {
int[] nums = {0,3,7,2,5,8,4,6,0,1};
System.out.println(maxSeq(nums));
}
}
class LongestConsecutiveSequence {
public static int maxSeq(int[] nums) {
int count, maxSeq, sequence;
count = maxSeq = 1;
HashSet<int> hashSet = new HashSet<int>(nums);
for (int i=0;i<nums.Length;i++) {
if (!hashSet.Contains(nums[i]-1)) {
sequence = nums[i] + 1;
count = 1;
while (hashSet.Contains(sequence)) {
count++;
sequence++;
}
}
maxSeq = Math.Max(maxSeq, count);
}
return maxSeq;
}
public static void Main(string[] args) {
int[] nums = {0,3,7,2,5,8,4,6,0,1};
Console.Write(maxSeq(nums));
}
}
def trapWater(heights):
left_subarray = [0] * len(heights)
right_subarray = [0] * len(heights)
max_left = heights[0]
max_right = heights[-1]
water = 0
for i in range(1, len(heights)):
left_subarray[i] = max_left
max_left = max(max_left, heights[i])
for i in range(len(heights)-2, -1, -1):
right_subarray[i] = max_right
max_right = max(max_right, heights[i])
for i in range(1, len(heights)-1):
min_max_value = min(left_subarray[i], right_subarray[i])
water += max(0, min_max_value - heights[i])
return water
heights = [0,1,0,2,1,0,1,3,2,1,2,1]
print(trapWater(heights))
public class TrappingRainWater {
public static int trapWater(int[] height) {
int[] leftSubarray = new int[height.length];
int[] rightSubarray = new int[height.length];
int maxLeft, maxRight, water;
maxLeft = height[0];
maxRight = height[height.length-1];
water = 0;
for (int i=0;i<height.length;i++) {
leftSubarray[i] = maxLeft;
maxLeft = Math.max(maxLeft, height[i]);
}
for (int i=height.length-2;i>-1;i--) {
rightSubarray[i] = maxRight;
maxRight = Math.max(maxRight, height[i]);
}
for (int i=1;i<height.length-1;i++) {
water += Math.max(0, Math.min(leftSubarray[i], rightSubarray[i]) - height[i]);
}
return water;
}
public static void main(String[] args) {
int[] height = {0,1,0,2,1,0,1,3,2,1,2,1};
System.out.println(trapWater(height));
}
}
class TrappingRainWater {
public static int trapWater(int[] height) {
int[] leftSubarray = new int[height.Length];
int[] rightSubarray = new int[height.Length];
int maxLeft, maxRight, water;
maxLeft = height[0];
maxRight = height[height.Length-1];
water = 0;
for (int i=0;i<height.Length;i++) {
leftSubarray[i] = maxLeft;
maxLeft = Math.Max(maxLeft, height[i]);
}
for (int i=height.Length-2;i>-1;i--) {
rightSubarray[i] = maxRight;
maxRight = Math.Max(maxRight, height[i]);
}
for (int i=1;i<height.Length-1;i++) {
water += Math.Max(0, Math.Min(leftSubarray[i], rightSubarray[i]) - height[i]);
}
return water;
}
public static void Main(String[] args) {
int[] height = {0,1,0,2,1,0,1,3,2,1,2,1};
Console.Write(trapWater(height));
}
}
def maxArea(height):
ws = 0
we = len(height) - 1
max_area = 0
while ws < we:
width = we - ws
min_height = min(height[ws], height[we])
area = width * min_height
max_area = max(max_area, area)
if height[ws] < height[we]:
ws += 1
else:
we -= 1
return max_area
class Solution {
static int maxArea(int[] height) {
int ws, we, width, minHeight, area, maxArea;
ws = 0;
we = height.length - 1;
maxArea = 0;
while (ws < we) {
width = we - ws;
minHeight = Math.min(height[ws], height[we]);
area = width * minHeight;
maxArea = Math.max(maxArea, area);
if (height[ws] < height[we]) {
ws++;
} else {
we--;
}
}
return maxArea;
}
}
class ContainerWithMostWater {
static int maxArea(int[] height) {
int ws, we, width, minHeight, area, maxArea;
ws = 0;
we = height.Length - 1;
maxArea = 0;
while (ws < we) {
width = we - ws;
minHeight = Math.Min(height[ws], height[we]);
area = width * minHeight;
maxArea = Math.Max(maxArea, area);
if (height[ws] < height[we]) {
ws++;
} else {
we--;
}
}
return maxArea;
}
}
def maxSubarray(nums):
local_max = nums[0]
global_max = nums[0]
for i in nums[1:]:
local_max = max(i, local_max + i)
global_max = max(global_max, local_max)
return global_max
print(maxSubarray([-2,1,-3,4,-1,2,1,-5,4]))
class MaximumSubarray {
static int maximumSubarray(int[] nums) {
int localMax, globalMax;
localMax = globalMax = nums[0];
for (int i=1; i<nums.length; i++) {
localMax = Math.max(nums[i], (localMax + nums[i]));
globalMax = Math.max(globalMax, localMax);
}
return globalMax;
}
public static void main(String[] args) {
int[] nums = {-2,1,-3,4,-1,2,1,-5,4};
System.out.println(maximumSubarray(nums));
}
}
class MaximumSubarray {
static int maximumSubarray(int[] nums) {
int localMax, globalMax;
localMax = globalMax = nums[0];
for (int i=1; i<nums.Length; i++) {
localMax = Math.Max(nums[i], localMax + nums[i]);
globalMax = Math.Max(globalMax, localMax);
}
return globalMax;
}
public static void Main(string[] args) {
int[] nums = {-2,1,-3,4,-1,2,1,-5,4};
Console.WriteLine(maximumSubarray(nums));
}
}
For example: Given nums = [1,2,3,4] then the corresponding prefix array of nums would be [1, 1, 2, 6].
As 1 is the product prefix of the 0th index element in the nums array as there exists no prefix to the 0th index element in the.
1 is also the product prefix of the 1th index element in the nums array as it has only one prefix value which is the 0th index element which implies we derive 1*1 which is 1
2 is the product prefix of the 2nd index element in the nums array as the 2nd index elements prefix elements are 1 and 2 so 1 * 2 = 2
so on and so forth for the prefix product portion
Now for the suffix we simply repeat the same process however we just go from the end of the array so a reverse for loop and we also need to multiply the suffix product with the previously derived prefix product as this derives the product of the entire array except the current element.
Steps:
def productExceptSelf(nums):
ans = [1] * len(nums)
product = 1
for i in range(len(nums)):
ans[i] = product
product *= nums[i]
product = 1
for i in range(len(nums)-1, -1, -1):
ans[i] *= product
product *= nums[i]
return ans
class ProductOfArrayExceptSelf {
static int[] productOfArrayExceptSelf(int[] nums) {
int[] ans = new int[nums.length];
int prefixProducts = 1;
for (int i=0; i<nums.length; i++) {
ans[i] = prefixProducts;
prefixProducts *= nums[i];
}
int suffixProducts = 1;
for (int i=nums.length-1; i>-1; i--) {
ans[i] *= suffixProducts;
suffixProducts *= nums[i];
}
return ans;
}
public static void main(String[] args) {
int[] nums = {1,2,3,4};
System.out.println(Arrays.toString(productOfArrayExceptSelf(nums)));
}
}
class ProductOfArrayExceptSelf {
static int[] productOfArrayExceptSelf(int[] nums) {
int[] ans = new int[nums.Length];
int prefix, suffix;
prefix = 1;
for (int i=0; i<nums.Length; i++) {
ans[i] = prefix;
prefix *= nums[i];
}
suffix = 1;
for (int i=nums.Length-1; i>-1; i--) {
ans[i] *= suffix;
suffix *= nums[i];
}
return ans;
}
static void Main(string[] args) {
int[] nums = {1,2,3,4};
Console.WriteLine(string.Join(", ", productOfArrayExceptSelf(nums)));
}
}
def containsDuplicate(nums):
dict = {}
for i in nums:
if i not in dict:
dict[i] = 0
else:
dict[i] += 1
if sum(dict.values()) == 0:
return False
else:
return True
print(containsDuplicate([1,2,3,1]))
def containsDuplicateOneLiner(nums):
return len(set(nums)) != len(nums)
print(containsDuplicateOneLiner([1,2,3,1]))
class ContainsDuplicate {
static Boolean containsDuplicate(int[] nums) {
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
for (int i: nums) {
if (!hashMap.containsKey(i)) {
hashMap.put(i, 0);
}
else {
int count = hashMap.get(i);
hashMap.put(i, count + 1);
}
}
int sum = 0;
for (int i: hashMap.values()) {
sum += i;
}
return sum == 0 ? false : true;
}
public static void main(String[] args) {
int[] nums = {1,2,3,1};
System.out.println(containsDuplicate(nums));
}
}
class ContainsDuplicate {
static Boolean containsDuplicate(int[] nums) {
Dictionary<int, int> dict = new Dictionary<int, int>();
for (int i=0; i<nums.Length; i++) {
if (!dict.ContainsKey(nums[i])) {
dict.Add(nums[i], 0);
}
else {
dict[nums[i]] += 1;
}
}
int[] dictValues = dict.Values.ToArray();
int sum = dictValues.Sum(x => x);
return sum == 0 ? false:true;
}
static void Main(string[] args) {
int[] nums = {1,2,3};
Console.WriteLine(containsDuplicate(nums));
}
}
def maxProfit(nums):
min_value = max_value = nums[0]
max_profit = 0
for i in nums[1:]:
if i < min_value:
min_value = i
max_value = i
else:
max_value = max(i, max_value)
max_profit = max(max_profit, max_value - min_value)
return max_profit
class BestTimeBuySellStock {
public static int maxProfit(int[] nums) {
int minVal, maxVal, maxProfit;
minVal = maxVal = nums[0];
maxProfit = 0;
for (int i=1; i<nums.length; i++) {
if (nums[i] < minVal) {
minVal = nums[i];
maxVal = nums[i];
}
else {
maxVal = Math.max(maxVal, nums[i]);
}
maxProfit = Math.max(maxProfit, maxVal - minVal);
}
return maxProfit;
}
public static void main(String[] args) {
int[] prices = {7,1,5,3,6,4};
System.out.println(maxProfit(prices));
}
}
class Solution {
static int maxProfit(int[] nums) {
int minVal, maxVal, maxProfit;
minVal = maxVal = nums[0];
maxProfit = 0;
for (int i=1; i<nums.Length; i++) {
if (nums[i] < minVal) {
minVal = nums[i];
maxVal = nums[i];
}
else {
maxVal = Math.Max(maxVal, nums[i]);
}
maxProfit = Math.Max(maxProfit, maxVal - minVal);
}
return maxProfit;
}
static void Main(string[] args) {
int[] prices = {7,1,5,3,6,4};
int ans = maxProfit(prices);
Console.WriteLine(ans);
}
}
def twoSum(nums, target):
dict = {}
for i in nums:
if (target - i) in dict:
return [nums.index(i), dict[target-i]]
return -1
class Solution {
public static int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
for (int i=0; i<nums.length; i++) {
hashMap.put(nums[i], i);
}
for (int i=0; i<nums.length; i++) {
if (hashMap.containsKey(target-nums[i])) {
int[] ans = {i, hashMap.get(target-nums[i])};
return ans;
}
}
return null;
}
public static void main(String[] args) {
int[] nums = {2,7,11,15};
int target = 9;
System.out.println(Arrays.toString(twoSum(nums, target)));
}
}
using System;
namespace twoSumProgram {
class Solution {
public static int[] twoSum(int[] nums, int target) {
Dictionary<int, int> hashMap = new Dictionary<int, int>();
for (int i=0; i<nums.Length; i++) {
hashMap.Add(nums[i], i);
}
for (int i=0; i<nums.Length; i++) {
int valueRequired = target - nums[i];
if (hashMap.ContainsKey(valueRequired)) {
int[] ans = {i, hashMap[valueRequired]};
return ans;
}
}
return null;
}
public static void Main(string[] args) {
int[] nums = {2,7,11,15};
int target = 9;
int[] res = twoSum(nums, target);
Array.ForEach(res, i => Console.Write($"{i}, "));
}
}
}
def findMissingRanges(nums, lower, upper):
ranges = []
windowEnd = lower - 1
for i in range(len(nums) + 1):
windowStart = nums[i] if i < len(nums) else upper + 1
if windowEnd + 1 <= windowStart - 1:
ranges.append(formatStr(windowEnd + 1, windowStart - 1))
windowEnd = windowStart
return ranges
def formatStr(windowEnd, windowStart):
return str(windowEnd) if windowEnd == windowStart else str(windowEnd) + "->" + str(windowStart)
public class BestTimeToBuySellStock {
public int maxProfit(int[] prices) {
int min_val = prices[0];
int max_profit = 0;
for (int i = 1; i < prices.length; i++) {
max_profit = Math.max(max_profit, prices[i] - min_val);
min_val = Math.min(min_val, prices[i]);
}
return max_profit;
}
}
public class BestTimeToBuySellMultiple {
public int maxProfit(int[] prices) {
int max_profit = 0;
for (int i = 0; i < prices.length - 1; i++) {
max_profit += Math.max(prices[i + 1] - prices[i], 0);
}
return max_profit;
}
}
public class MaximumSubArray {
public int maxSubArray(int[] nums) {
int currMax = nums[0]; int globalMax = nums[0];
for (int i = 1; i < nums.length; i++) {
currMax = Math.max(nums[i], nums[i] + currMax);
globalMax = Math.max(globalMax, currMax);
}
return globalMax;
}
}
def mergeKLists(lists):
head = list2 = ListNode(0)
for i in lists:
current = i
while current:
list2.next = current
current = current.next
list2 = list2.next
curr = head.next
sortedArray = []
while curr:
sortedArray.append(curr.val)
curr = curr.next
sortedArray.sort()
dummy = sortedLL = ListNode(0)
for i in sortedArray:
sortedLL.next = ListNode(i)
sortedLL = sortedLL.next
return dummy.next
def removeNthFromEnd(head, n):
dummy = current = ListNode(0, head)
runner = head
for i in range(n):
runner = runner.next
while runner:
current = current.next
runner = runner.next
current.next = current.next.next
return dummy.next
def remove_dupes(linked_list):
current = linked_list.get_head() # Current will point to head node of linked list
runner = linked_list.get_head() # Runner also points at head node of linked list
while current != None: # Iterate while current != None
while runner.get_next() != None: # While the element after the head element also does not equal None
if current.get_data() == runner.get_next().get_data(): # If the current data in the linked list is present in the next node of the linked list
runner.remove_after() # Remove that node
else:
runner = runner.get_next() # Else increment runner
runner = current.get_next() # Reset runner to the next element of the linked list
current = current.get_next() # Reset current to the next element of the linked list
def copyRandomList(head):
if not head: return None
current = head
hashMap = {}
while current:
hashMap[current] = Node(current.val, None, None)
current = current.next
current = head
while current:
if current.next:
hashMap[current].next = hashMap[current.next]
if current.random:
hashMap[current].random = hashMap[current.random]
current = current.next
return hashMap[head]
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
}
def binarySearch(sorted_array, element_to_find):
min_index = 0
max_index = len(sorted_array) - 1
while min_index <= max_index:
mid = (min_index + max_index) // 2
if sorted_array[mid] == element_to_find:
return mid
elif sorted_array[mid] < element_to_find:
min_index = mid + 1
elif sorted_array[mid] > element_to_find:
max_index = mid - 1
return -1
def recursiveBS(min_index, max_index, element_to_find, array):
index = 0
if min_index > max_index:
return -1
else:
mid = (min_index + max_index) // 2
if array[mid] == element_to_find:
index = mid
return index
elif array[mid] < element_to_find:
index = recursiveBS(mid + 1, max_index, element_to_find, array)
elif array[mid] > element_to_find:
index = recursiveBS(min_index, mid - 1, element_to_find, array)
return index
def findIndex(array, element_to_find):
return recursiveBS(0, len(array)-1, element_to_find, array)
def trinary_search(my_list, x):
min = 0
max = len(my_list) - 1
mid_points_computed = []
while min <= max:
mid1 = min + (max - min) // 3
mid2 = max - (max - min) // 3
mid_points_computed.append(mid1)
if x > my_list[mid1]:
mid_points_computed.append(mid2)
if my_list[mid1] == x:
return (mid1,mid_points_computed)
elif my_list[mid1] < x:
if my_list[mid2] == x:
return (mid2,mid_points_computed)
elif my_list[mid2] > x:
min = mid1 + 1
max = mid2 - 1
elif my_list[mid2] < x:
min = mid2 + 1
else:
max = mid1 - 1
return (-1,mid_points_computed)
def bubbleSort(array):
for i in range(1, len(array)):
swap = False
for n in range(len(array) - 1):
if array[n] > array[n + 1]:
array[n], array[n + 1] = array[n + 1], array[n]
swap = True
if swap == False:
break
return array
print(bubbleSort([7, 6, 5, 4, 3, 2, 1]))
def insertionSort(array):
for index in range(1, len(array)):
value = array[index]
i = index - 1
while i >= 0 and array[i] > value: # Change the condition here in order to sort in respect to a different parameter.
array[i + 1] = array[i]
array[i] = value
i -= 1
return array
print(insertionSort([7,6,5,4,3,2,1]))
def ReverseinsertionSort(array):
for index in range(1, len(array)):
value = array[index]
i = index - 1
while i >= 0 and array[i] < value: # Reverse sort
array[i + 1] = array[i]
array[i] = value
i -= 1
return array
print(ReverseinsertionSort([7,6,5,4,3,2,1]))
def LengthinsertionSort(array):
for index in range(1, len(array)):
value = array[index]
i = index - 1
while i >= 0 and len(array[i]) > len(value): # Length sort string array.
array[i + 1] = array[i]
array[i] = value
i -= 1
return array
print(LengthinsertionSort(["goku", "vegeta", "gohan", "frieza", "Perfect cell"]))
# Top down, main idea is we go from the end of the list and swap the largest elements
def selectionSort(array):
for i in range(len(array)-1, -1, -1):
largest = 0
for n in range(i + 1):
if array[n] > array[largest]:
largest = n
array[i], array[largest] = array[largest], array[i]
return array
print(selectionSort([7,6,5,4,3,2,1]))
# Bottom up, main idea is we go from the front of the list and swap the smallest elements
def selectionSortBU(array):
for i in range(0, len(array)-1):
smallest = i
for n in range(i + 1, len(array)):
if array[n] < array[smallest]:
smallest = n
array[i], array[smallest] = array[smallest], array[i]
return array
print(selectionSortBU([7,6,5,4,3,2,1]))
import random
def bogosort(list_of_elements):
n = len(list_of_elements)
while is_sorted(list_of_elements) == False:
shuffle(list_of_elements)
def is_sorted(list_of_elements):
n = len(list_of_elements)
for i in range(0, n - 1):
if list_of_elements[i] > list_of_elements[i + 1]:
return False
return True
def shuffle(list_of_elements):
n = len(list_of_elements)
for i in range(0, n):
random_index = random.randrange(0, n - 1)
list_of_elements[i], list_of_elements[random_index] = list_of_elements[random_index], list_of_elements[i]
my_list = [1, 3, 4, 2]
bogosort(my_list)
print(my_list)
def mergesort(a_list):
if len(a_list) > 1:
mid = len(a_list) // 2 # Finding the mid of the array
left_sublist = a_list[:mid] # Dividing the array elements
right_sublist = a_list[mid:] # into 2 halves
mergesort(left_sublist) # Sorting the first half
mergesort(right_sublist) # Sorting the second half
small_unsort_left = small_unsort_right = main_list_pos = 0
# Copy data to temp arrays L[] and R[]
while small_unsort_left < len(left_sublist) and small_unsort_right < len(right_sublist):
if left_sublist[small_unsort_left] < right_sublist[small_unsort_right]:
a_list[main_list_pos] = left_sublist[small_unsort_left]
small_unsort_left += 1
else:
a_list[main_list_pos] = right_sublist[small_unsort_right]
small_unsort_right += 1
main_list_pos += 1
# Checking if any element was left
while small_unsort_left < len(left_sublist):
a_list[main_list_pos] = left_sublist[small_unsort_left]
small_unsort_left += 1
main_list_pos += 1
while small_unsort_right < len(right_sublist):
a_list[main_list_pos] = right_sublist[small_unsort_right]
small_unsort_right += 1
main_list_pos += 1
return a_list
print(mergesort([8, 7, 6, 5, 4, 3, 2, 1]))
def quick_sort(a_list):
if len(a_list) < 2:
return a_list
else:
pivot = a_list[0]
less = quick_sort([i for i in a_list if i < pivot])
greater = quick_sort([i for i in a_list if i > pivot])
return less + [pivot] + greater
print(quick_sort([7,6,3,99]))
def findMedianSortedArrays(nums1, nums2):
new_nums = []
# Edge cases
if len(nums1) == 0 and len(nums2) == 0:
return []
elif len(nums1) == 0 and len(nums2) != 0:
new_nums = nums2
elif len(nums2) == 0 and len(nums1) != 0:
new_nums = nums1
else:
new_nums = nums1 + nums2
if len(new_nums) == 1:
return float(new_nums[0])
new_nums.sort()
mid = (0 + len(new_nums) - 1) // 2
if len(new_nums) % 2 != 0:
return new_nums[mid]
else:
return (new_nums[mid + 1] + new_nums[mid]) / 2.0
def get_quartiles(list_of_numbers):
list_of_numbers.sort()
#We must sort the list!
lower_quartile = int(len(list_of_numbers) * 0.25)
#Simply take the lenth of the list and mutliply it by 0.25
#The length of the list in a percentage is 100% and we want 25% from this 100%
#Therefore when we multiply the length of the list by 0.25 we derive the value which
#is equivalent to 25% of the length of the list
upper_quartile = int(len(list_of_numbers) * 0.75)
#We want the 75% index value of the list. Therefore we mutiply by 0.75 which gives us
#the 75% index out of the 100% index of the list
median_quartile = int(len(list_of_numbers) * 0.5)
#This will give us the index right in the middle of the list
return list_of_numbers[lower_quartile], list_of_numbers[upper_quartile]
def isValid(self, s):
stack = []
validBrackets = ["[]", "{}", "()"]
openBracket = ["(", "[", "{"]
for i in s:
if i in openBracket:
stack.append(i)
elif len(stack) > 0:
bracket = stack.pop()
if bracket + i in validBrackets:
pass
else:
return False
else:
return False
return True if len(s) > 1 and len(stack) == 0 else False
def decodeString(self, s):
stack = [["", 1]]
k = 0
for i in s:
if i.isdigit():
k = k * 10 + int(i)
elif i == '[':
stack.append(["", k])
k = 0
elif i == ']':
char_string, repeat_val = stack.pop()
stack[-1][0] += char_string * repeat_val
else:
stack[-1][0] += i
return stack[-1][0]
Definition for a binary tree node.
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def levelOrder(root):
if not root: return []
queue = [root]
level = []
next_queue = []
result = []
while queue:
for root in queue:
level.append(root.val)
if root.left:
next_queue.append(root.left)
if root.right:
next_queue.append(root.right)
result.append(level)
queue = next_queue
next_queue = []
level = []
return result
# Preorder = print, left, right. DFS = moving down the tree.
def preorderTraversal(self, root):
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right) if root != None else []
def preorderTraversal(self, root):
if not root: return []
stack = [root]
result = []
while stack:
root = stack.pop()
result.append(root.val)
if root.right:
stack.append(root.right)
if root.left:
stack.append(root.left)
return result
def inorderTraversal(self, root):
return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right) if root != None else []
def inorderTraversal(self, root):
stack, result = [], []
while root or stack:
while root:
stack.append(root)
root = root.left
root = stack.pop()
result.append(root.val)
root = root.right
return result
def postorderTraversal(root):
return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val] if root else []
public class LongestIncreasingPathMatrix {
private int[][] DIRECTIONS = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
public int longestIncreasingPath(int[][] matrix) {
if (matrix.length == 0 || matrix == null) return 0;
int rows = matrix.length;
int cols = matrix[0].length;
int longestPath = 0;
int[][] memoization = new int[rows][cols];
for (int currRow = 0; currRow < rows; currRow++) {
for (int currCol = 0; currCol < cols; currCol++) {
int longest = dfs(matrix, memoization, rows, cols, currRow, currCol);
longestPath = Math.max(longestPath, longest);
}
}
return longestPath;
}
public int dfs(int[][] matrix, int[][] memoization, int rows, int cols, int currRow, int currCol) {
if (memoization[currRow][currCol] != 0) return memoization[currRow][currCol];
int max = 0;
for (int[] direction : DIRECTIONS) {
int X = direction[0] + currRow;
int Y = direction[1] + currCol;
if (X >= 0 && Y >= 0 && X < rows && Y < cols && matrix[X][Y] > matrix[currRow][currCol]) {
int longest = dfs(matrix, memoization, rows, cols, X, Y);
max = Math.max(max, longest);
}
}
memoization[currRow][currCol] = max + 1;
return memoization[currRow][currCol];
}
}
def calcEquation(self, equations, values, queries):
# Step 1: Build the graph
graph = collections.defaultdict(dict)
# Default dict beacuse if a value DNE it won't throw an expection unlike normal dict
for (num, denom), product in zip(equations, values):
# zip(equations, values) = [([a, b], 2.0), ([b, c], 3.0)]
graph[num][denom] = product
## dict[x][y] implies x is pointing to y. ie {'a': {'b': 2.0}} a is pointing to b.
# Set the key as the num, denom and value as the product of the division in the defaultdict
graph[denom][num] = 1.0/product
def dfs(numerator, denominator, visited):
if numerator not in graph or denominator not in graph:
return -1.0
if denominator in graph[numerator]:
return graph[numerator][denominator]
# Recall that our dict is set up such that the numerator points to the deominator, hence if denominator is in the denominator it
# is a key of the numerator so we can return that value.
# ie {'a': {'b': 2.0}}, a is the numerator and b is the denominator. If the query was a/b we would ask "is b in a?" we can see it is hence we just return the value which is the product of a/b.
for i in graph[numerator]:
if i not in visited:
visited.add(i)
temp = dfs(i, denominator, visited)
if temp == -1:
continue
else:
return graph[numerator][i] * temp
return -1
result_list = []
for numerator, denominator in queries:
result_list.append(dfs(numerator, denominator, set()))
# Pass the numerator and denominator of the query division to dfs where we will find the product.
return result_list
def maxDepth(self, root):
if root is None:
return 0
if root.left is None and root.right is None:
return 1
findLeft = 1 + self.maxDepth(root.left)
findRight = 1 + self.maxDepth(root.right)
return max(findLeft, findRight)
def isSymmetric(self, root):
return checkSubtrees(root, root)
def checkSubtrees(t1, t2):
if t1 is None and t2 is None: return True
if t1 is None or t2 is None: return False
return t1.val == t2.val and checkSubtrees(t1.left, t2.right) and checkSubtrees(t1.right, t2.left)
def hasPathSum(self, root, targetSum):
if root == None:
return False
elif root.left == None and root.right == None and targetSum - root.val == 0:
return True
else:
return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum(root.right, targetSum - root.val)
def buildTree(inorder, postorder):
def recurse(inorder, postorder):
if not inorder or not postorder: return
root = TreeNode(postorder.pop())
root.right = recurse(inorder[inorder.index(root.val) + 1:], postorder)
root.left = recurse(inorder[:inorder.index(root.val)], postorder)
return root
return recurse(inorder, postorder)
def buildTree(inorder, postorder):
hashMap = {inorder[i]: i for i in range(len(inorder))}
def recurse(minVal, maxVal):
if minVal > maxVal: return
root = TreeNode(postorder.pop())
midVal = hashMap[root.val]
root.right = recurse(midVal + 1, maxVal)
root.left = recurse(minVal, midVal - 1)
return root
return recurse(0, len(inorder) - 1)
def buildTree(preorder, inorder):
hashMap = {value: index for index, value in enumerate(inorder)}
def recurse(minVal, maxVal):
if minVal > maxVal: return
root = TreeNode(preorder.pop(0))
mid = hashMap[root.val]
root.left = recurse(minVal, mid - 1)
root.right = recurse(mid + 1, maxVal)
return root
return recurse(0, len(inorder) - 1) # (36 ms, faster than 99.21%, 18.1 MB, less than 90.83%)
def buildTree(preorder, inorder):
def indexConstruct(preorder, index):
if index >= len(preorder): return
root = TreeNode(preorder[index])
root.left = indexConstruct(preorder, 2 * index + 1)
root.right = indexConstruct(preorder, 2 * index + 2)
return root
return indexConstruct(preorder, 0)
def connect(root):
if not root: return
leftmost = root
while leftmost.left:
head = leftmost
while head:
head.left.next = head.right
if head.next:
head.right.next = head.next.left
head = head.next
leftmost = leftmost.left
return root
class NextRightPointerBT {
public Node connect(Node root) {
if (root == null) {
return root;
}
Queue<Node> Q = new LinkedList<Node>();
Q.add(root);
while (Q.size() > 0) {
int size = Q.size();
for (int i = 0; i < size; i++) {
Node node = Q.poll();
if (i < size - 1) {
node.next = Q.peek();
}
if (node.left != null) {
Q.add(node.left);
}
if (node.right != null) {
Q.add(node.right);
}
}
} return root;
}
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// if root is null return null as it is not p or q.
if (root == null) return null;
// Check if root is p or q each call, if it is return root as we have found one of the nodes.
if (root == p || root == q) return root;
// Recurse down the left subtree, look for p or q, if we find it we are returned p or q else if it is NOT in the left subtree we are returned null and move onto the right subtree.
TreeNode leftSubtree = lowestCommonAncestor(root.left, p, q);
// Recurse down the right subtree, look for p and q, if we find it we are returned p or q else if it is NOT in the right subtree we are returned null and move onto our conditionals.
TreeNode rightSubtree = lowestCommonAncestor(root.right, p, q);
// Check if the current node we are at has two NOT NULL left right children, these children can only possibly be p and q therefore, the FIRST node to have TWO children is the LOWEST COMMON ANCESTOR. Return that node.
if (leftSubtree != null && rightSubtree != null) return root;
// If both the left and right nodes are null this parent node is NOT a ancestor hence return null.
if (leftSubtree == null && rightSubtree == null) return null;
// If ONE of the left or right nodes are NOT null, then we have found ONE of our required nodes, hence return the node we found and move back UP the recursive call stack.
return (leftSubtree != null) ? leftSubtree:rightSubtree;
}
}
def countUnivalSubtrees(self, root):
self.count = 0
self.recurse(root)
return self.count
def recurse(self, root):
if not root: return True
left = self.recurse(root.left)
right = self.recurse(root.right)
if left == True and right == True and (root.left == None or root.left.val == root.val) and (
root.right == None or root.right.val == root.val):
self.count += 1
return True
return False
def maxPathSum(self, root: TreeNode) -> int:
max_path = root.val
def findMaxPath(root):
nonlocal max_path
if not root: return 0
left_subtree = max(findMaxPath(root.left), 0)
right_subtree = max(findMaxPath(root.right), 0)
max_path = max(max_path, root.val + left_subtree + right_subtree)
return root.val + max(left_subtree, right_subtree)
findMaxPath(root)
return max_path
def binaryTreePaths(self, root):
path_list = []
def recurse(root, path):
if root:
path += str(root.val)
if not root.left and not root.right:
path_list.append(path)
else:
recurse(root.left, path + "->")
recurse(root.right, path + "->")
recurse(root, "")
return path_list
public class NumberOfIslands {
public int numIslands(char[][] grid) {
int islands = 0;
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == '1') {
dfs(grid, row, col);
islands++;
}
}
} return islands;
}
private void dfs(char[][] grid, int row, int col) {
if (row >= 0 && col >= 0 && row < grid.length && col < grid[row].length && grid[row][col] == '1') {
grid[row][col] = '0';
dfs(grid, row - 1, col); // Top
dfs(grid, row + 1, col); // Bottom
dfs(grid, row, col - 1); // Left
dfs(grid, row, col + 1); // Right
}
}
}
import java.util.*;
public class WordLadder {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Queue<String> queue = new LinkedList<>(); // Queue to do BFS of the graph we are going to build.
Set<String> wordSet = new HashSet<>(wordList); // NOTE THIS IS HOW YOU ADD A LIST OF WORDS TO HASHSET!
wordSet.remove(beginWord); // Remove the beginning word from set
queue.add(beginWord); // Add it to queue to build first level
int level = 0;
while (!queue.isEmpty()) {
level++; // Increment level as we iterate
int size = queue.size();
for (int i = 0; i < size; i++) {
String currentWord = queue.poll(); // Current word node at level
if (currentWord.equals(endWord)) return level; // Found the endWord in the queue so we are done
List<String> allSeqList = findSeqs(currentWord); // Get an array holding all possible sequences
for (String s: allSeqList) { //For every possible sequence in the array in respect to currentword
if (wordSet.contains(s)) { // If the particular sequence is in the hashSet
wordSet.remove(s); // Remove that element from the hashset as we have visited it
queue.add(s); //Add it to the next level of the queue.
}
}
}
} return 0;
}
public static List<String> findSeqs(String currentWord) {
char[] charArray = currentWord.toCharArray(); // Make a list of chars so each individual char from cWord
List<String> allPossSeqs = new ArrayList<>(); // Array to hold all combinations of the word
for (int i = 0; i < charArray.length; i++) { // For every single CHAR in the passed word. This is important because recall we want to change EVERY single char to get ALL possible combinations.
char temp = charArray[i]; // We need a temp char so we can eventually revert back.
for (char c = 'a'; c <= 'z'; c++) { // This sets c to go from a - z hence the entire alphabet
charArray[i] = c; // Make the CURRENT char we are looking at = to each alphabet character
String nextSeq = new String(charArray);// Convert the current charArray WITH the transformed letter to a string and add that string to all possible sequences array.
allPossSeqs.add(nextSeq); // Add this combination to our combinations array
}
charArray[i] = temp; // Revert the character back to original and move onto the next one in the word.
}
return allPossSeqs; // Return array of all possible combinations of passed argument currentWord
}
}
public class IsValidBST {
public boolean isValidBST(TreeNode root) {
return DFS(root, null, null);
}
private boolean DFS(TreeNode root, Integer low, Integer high) {
if (root == null) return true;
if (low != null && low >= root.val)
return false;
if (high != null && high <= root.val)
return false;
return DFS(root.left, low, root.val) && DFS(root.right, root.val, high);
}
}
def diameterOfBinaryTree(self, root):
diameter = 0
def dfs(root):
nonlocal diameter
if not root: return 0
left = dfs(root.left)
right = dfs(root.right)
diameter = max(diameter, left + right)
return max(left, right) + 1
dfs(root)
return diameter
public class FlipEquivBinaryTree {
public boolean flipEquiv(TreeNode root1, TreeNode root2) {
if (root1 == root2) return true;
if (root1 == null || root2 == null || root1.val != root2.val) return false;
return flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right) ||
flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left);
}
}
The way to approach the maximum Subarray problem is by using Kadane’s algorithm. How Kadane’s algorithm works is, we start off with the first index element in the array. We set our current max and global max to this element. We then want to iterate through the remainder of the array, we want to build up the sum in our current max variable. However, what we are going to do is always take the maximum between the current array elemet (list[i]) and the current array element plus whatever we have in our current sub array so (list[i] + current_max). This was we only take the maximum sub array in each iteration, this is how we build up our current maximum sub array. Then each iteration, we ask is the current sum of our current_max subarray LARGER than the sum in the global_max subarray? We the update accordingly. Finally we are left with the largest subarray sum in global_max.
def maxSubArray(nums):
# Initalize two variables, current and global max to point at the first element in the array
current_max = global_max = nums[0]
#Iterate from the 1st index in the array till the end, we skip the 0th index because we are already looking at it with curret_max and global_max
for i in range(1, len(nums)):
# Every iteration, we ask, is the current array value greater than the current array value plus the previous array value, we ask this ofcourse as there may be negative elements
# Which decrease our total maximum sum, which we do not want, we want the maximum.
current_max = max(nums[i], nums[i] + current_max)
# Next we keep updating our global maximum aslong as current_max is growing!
if current_max > global_max:
global_max = current_max
return global_max
def canJump(nums):
lastGoodIndex = len(nums) - 1
for i in range(len(nums) - 1, -1, -1):
if i + nums[i] >= lastGoodIndex:
lastGoodIndex = i
return True if lastGoodIndex == 0 else False
def maxDistToClosest(seats):
lastSeen = [0] * len(seats)
distance = -1
for i in range(len(seats)):
if seats[i] == 0 and distance != -1:
distance += 1
lastSeen[i] = distance
else:
distance = 0
distance = -1
for i in range(len(seats) - 1, -1, -1):
if seats[i] == 0 and distance != -1:
distance += 1
if lastSeen[i] == 0:
lastSeen[i] = distance
else:
lastSeen[i] = min(distance, lastSeen[i])
else:
distance = 0
return max(lastSeen)
def trapping_rainwater(height):
dpLeft = []
dpRight = []
maxRight = 0
maxLeft = 0
for i in range(len(height)):
maxLeft = max(height[i], maxLeft)
dpLeft.append(maxLeft)
for i in range(len(height)-1,-1,-1):
maxRight = max(height[i],maxRight)
dpRight.append(maxRight)
dpRight.reverse()
for i in range(len(dpLeft)):
dpLeft[i] = (min(dpLeft[i], dpRight[i]) - height[i])
return sum(dpLeft)
public class SumTwoIntegers {
public static int SumTwoIntegers(int a, int b) {
while (b != 0) {
int addition = a ^ b;
int carryShift = (a & b) << 1;
a = addition;
b = carryShift;
}
return a;
}
bin() will return the string binary represenation of a given integer value with 0b tacked on the front. Super useful opeartor so keep it in mind.
def countBits(self, nums):
return [len(bin(i)[2:].replace("0", "")) for i in range(nums + 1)]
def missingNumber(self, nums):
xor = len(nums)
for i in range(len(nums)):
xor = xor ^ nums[i] ^ i
return xor