├── README.md
├── array
├── easy
│ ├── add_digits.py
│ ├── best_time_to_buy_and_sell_stock.py
│ ├── build_array_from_permutation.py
│ ├── counting_bits.py
│ ├── fizz_buzz.py
│ ├── happy_number.py
│ ├── majority_element.py
│ ├── maximum_subarray.py
│ ├── merge_two_sorted_lists.py
│ ├── move_zeroes.py
│ ├── palindrome_number.py
│ ├── plus_one.py
│ ├── remove_element.py
│ ├── reverse_bits.py
│ ├── roman_to_integer.py
│ └── two_sum.py
└── medium
│ ├── 3sum.py
│ ├── next_permutation.py
│ └── strictly_palindromic_number.py
├── binary
├── easy
│ ├── counting_bits.py
│ └── number_of_1_bits.py
└── medium
│ └── sum_of_two_integers.py
├── dynamic_programming
└── easy
│ └── climbing_stairs.py
├── recursion
└── easy
│ └── number-of-1-bits.py
├── sorting
├── bubble_sort.py
├── insertion_sort.py
└── selection_sort.py
├── string
├── easy
│ ├── is_subsequence.py
│ ├── length_of_last_word.py
│ ├── longest_common_prefix.py
│ ├── unique_email_addresses.py
│ ├── valid_anagram.py
│ ├── valid_palindrome.py
│ └── valid_parentheses.py
└── medium
│ ├── find_all_anagrams_in_a_string.py
│ ├── group_anagrams.py
│ ├── longest_substring_without_repeating_characters.py
│ └── palindromic_substrings.py
└── tree
└── easy
├── balanced_binary_tree.py
├── binary_tree_preorder_traversal.py
├── maximum_depth_binary_tree.py
├── same_tree.py
└── symmetric_tree.py
/README.md:
--------------------------------------------------------------------------------
1 |
Master DSA With Python
2 |
3 | This repository covers various problems of Arrays, Stacks, Queues, Trees, Graphs and different other Algorithms across all the levels.
4 |
5 | Topic | Number of problems solved | Sources
6 | ----- | ------------------------- | ------------------------
7 | Arrays| 3 | Leet Code
8 |
--------------------------------------------------------------------------------
/array/easy/add_digits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def addDigits(self, num: int) -> int:
3 | nums = list(map(int, str(num)))
4 | if len(nums)>1:
5 | nums = sum(nums)
6 | nums = self.addDigits(nums)
7 | else:
8 | nums = nums[0]
9 | return nums
10 |
--------------------------------------------------------------------------------
/array/easy/best_time_to_buy_and_sell_stock.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def maxProfit(self, prices: List[int]) -> int:
3 | if len(prices) <= 1:
4 | return 0
5 |
6 | max_profit = prices[1] - prices[0]
7 | min_price = prices[0]
8 |
9 | for idx in range(1, len(prices)):
10 | if prices[idx] - min_price > max_profit:
11 | max_profit = prices[idx] - min_price
12 | if prices[idx] < min_price:
13 | min_price = prices[idx]
14 | if max_profit < 0:
15 | max_profit = 0
16 | return max_profit
17 |
--------------------------------------------------------------------------------
/array/easy/build_array_from_permutation.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def buildArray(self, nums: List[int]) -> List[int]:
3 | out = []
4 | for i in nums:
5 | out.append(nums[i])
6 | return out
7 |
--------------------------------------------------------------------------------
/array/easy/counting_bits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def countBits(self, n: int) -> List[int]:
3 | final_list = []
4 | for i in range(n+1):
5 | if i == 0:
6 | final_list.append(0)
7 | elif i%2 == 0:
8 | final_list.append(final_list[i//2])
9 | else:
10 | final_list.append(final_list[i//2] + 1)
11 | return final_list
12 |
13 |
--------------------------------------------------------------------------------
/array/easy/fizz_buzz.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def fizzBuzz(self, n: int) -> List[str]:
3 | final_output = []
4 | for i in range(1, n+1):
5 | if i%3 == 0 and i%5 == 0:
6 | final_output.append("FizzBuzz")
7 | elif i%3 == 0:
8 | final_output.append("Fizz")
9 | elif i%5 == 0:
10 | final_output.append("Buzz")
11 | else:
12 | final_output.append(str(i))
13 | return final_output
14 |
15 |
--------------------------------------------------------------------------------
/array/easy/happy_number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isHappy(self, n: int) -> bool:
3 | visited_n = []
4 | while n not in visited_n:
5 | visited_n.append(n)
6 | sum_number = 0
7 | while n:
8 | sum_number += (n % 10) ** 2
9 | n //= 10
10 | n = sum_number
11 | if n == 1:
12 | return True
13 | return False
14 |
15 |
--------------------------------------------------------------------------------
/array/easy/majority_element.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def majorityElement(self, nums: List[int]) -> int:
3 | hash_map = {i: nums.count(i) for i in set(nums)}
4 | final_output = sorted(hash_map.items(), key=lambda x: x[1], reverse=True)[0][0]
5 | return final_output
6 |
--------------------------------------------------------------------------------
/array/easy/maximum_subarray.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def maxSubArray(self, nums: List[int]) -> int:
3 | sum_subarray = 0
4 | max_subarray = nums[0]
5 |
6 | for i in nums:
7 | sum_subarray += i
8 | if sum_subarray > max_subarray:
9 | max_subarray = sum_subarray
10 | if sum_subarray < 0:
11 | sum_subarray = 0
12 | return max_subarray
13 |
--------------------------------------------------------------------------------
/array/easy/merge_two_sorted_lists.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/array/easy/move_zeroes.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def moveZeroes(self, nums: List[int]) -> None:
3 | non_zero = 0
4 |
5 | for i in nums:
6 | if i != 0:
7 | nums[non_zero] = i
8 | non_zero += 1
9 | for i in range(non_zero, len(nums)):
10 | nums[i] = 0
11 |
12 |
--------------------------------------------------------------------------------
/array/easy/palindrome_number.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 | class Solution:
4 | def isPalindrome(self, x: int) -> bool:
5 | x = str(x)
6 | end = len(x)
7 | for i in range (0, math.ceil(end/2)):
8 | if x[i] != x[(end - i) - 1]:
9 | return False
10 | return True
11 |
12 |
--------------------------------------------------------------------------------
/array/easy/plus_one.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def plusOne(self, digits: List[int]) -> List[int]:
3 | int_digits = int(''.join(map(str, digits)))
4 | int_digits = int_digits+1
5 | int_digits = list(map(int, str(int_digits)))
6 | return int_digits
7 |
--------------------------------------------------------------------------------
/array/easy/remove_element.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def removeElement(self, nums: List[int], val: int) -> int:
3 | if len(nums) == 0:
4 | return 0
5 |
6 | final_length = 0
7 | for i in nums:
8 | if i != val:
9 | nums[final_length] = i
10 | final_length += 1
11 | return final_length
12 |
--------------------------------------------------------------------------------
/array/easy/reverse_bits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def reverseBits(self, n: int) -> int:
3 | final_output = 0
4 | for _ in range(0,32):
5 | final_output <<= 1
6 | final_output = final_output | (n & 1)
7 | n >>= 1
8 | return final_output
9 |
--------------------------------------------------------------------------------
/array/easy/roman_to_integer.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def romanToInt(self, s: str) -> int:
3 | roman_dict = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
4 | output = 0
5 | for idx in range(0, len(s) - 1):
6 | if roman_dict[s[idx]] < roman_dict[s[(idx + 1)]]:
7 | output -= roman_dict[s[idx]]
8 | else:
9 | output += roman_dict[s[idx]]
10 | output += roman_dict[s[len(s) - 1]]
11 | return output
12 |
--------------------------------------------------------------------------------
/array/easy/two_sum.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def twoSum(self, nums: List[int], target: int) -> List[int]:
3 | nums_dict = {}
4 | for idx, num in enumerate(nums):
5 | if target - num in nums_dict:
6 | return [nums_dict[(target - num)] ,idx]
7 | else:
8 | nums_dict[num] = idx
9 |
10 |
--------------------------------------------------------------------------------
/array/medium/3sum.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def threeSum(self, nums: List[int]) -> List[List[int]]:
3 |
4 |
--------------------------------------------------------------------------------
/array/medium/next_permutation.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def nextPermutation(self, nums: List[int]) -> None:
3 | if len(nums) <= 1:
4 | return
5 | for idx, i in enumerate(nums[:-2]):
6 | if nums[idx] <= nums[idx + 1]:
7 | idx1 = idx + 1
8 | for idx_reverse in reversed(range(len(nums))):
9 | if nums[idx_reverse] >= nums[idx1]:
10 | nums[idx1], nums[idx_reverse] = nums[idx_reverse], nums[idx1]
11 | nums[idx1:-1].reverse()
12 |
--------------------------------------------------------------------------------
/array/medium/strictly_palindromic_number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isStrictlyPalindromic(self, n: int) -> bool:
3 | for i in range(2, n - 1):
4 | new_n = i ** n
5 | reverse = 0
6 | while new_n > 0:
7 | digit = new_n % 10
8 | reverse = reverse * 10 + digit
9 | new_n = new_n // 10
10 | if i ** n != reverse:
11 | return False
12 | return True
13 |
14 |
--------------------------------------------------------------------------------
/binary/easy/counting_bits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def countBits(self, n: int) -> List[int]:
3 | output = [0]
4 | for i in range(1, n+1):
5 | output.append(output[i>>1] + i%2)
6 | return output
7 |
--------------------------------------------------------------------------------
/binary/easy/number_of_1_bits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def hammingWeight(self, n: int) -> int:
3 | count = 0
4 | while n:
5 | if n & 1: count += 1
6 | n>>=1
7 | return count
8 |
--------------------------------------------------------------------------------
/binary/medium/sum_of_two_integers.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def getSum(self, a: int, b: int) -> int:
3 | carry = b
4 | while carry!=0:
5 | xor = a ^ b
6 | carry = (a & b) << 1
7 | b = carry
8 | a = xor
9 | return xor
10 |
--------------------------------------------------------------------------------
/dynamic_programming/easy/climbing_stairs.py:
--------------------------------------------------------------------------------
1 | class Solution(object):
2 | def climbStairs(self, n):
3 | dp = [0, 1, 2]
4 | for i in range(3, n + 1):
5 | dp.append(dp[i - 1] + dp[i - 2])
6 | return dp[n]
7 |
--------------------------------------------------------------------------------
/recursion/easy/number-of-1-bits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def hammingWeight(self, n: int) -> int:
3 | if n == 0:
4 | return 0
5 | else:
6 | return (n & 1) + self.hammingWeight(n >> 1)
7 |
--------------------------------------------------------------------------------
/sorting/bubble_sort.py:
--------------------------------------------------------------------------------
1 | def bubblesort(array, size):
2 | for i in range(size):
3 | for j in range(size-i-1):
4 |
5 | if array[j] > array[j+1]:
6 | (array[j], array[j+1]) = (array[j+1], array[j])
7 |
8 | return array
9 |
--------------------------------------------------------------------------------
/sorting/insertion_sort.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sorting/selection_sort.py:
--------------------------------------------------------------------------------
1 | def selectionSort(array, size):
2 |
3 | for j in range(size):
4 | min_idx = j
5 |
6 | for i in range(j + 1, size):
7 |
8 | if array[i] < array[min_idx]:
9 | min_idx = i
10 |
11 | (array[j], array[min_idx]) = (array[min_idx], array[j])
12 |
--------------------------------------------------------------------------------
/string/easy/is_subsequence.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isSubsequence(self, s: str, t: str) -> bool:
3 | i, j = 0, 0
4 | while i int:
3 | length = len(s.rstrip().split(' ')[-1])
4 | return length
5 |
--------------------------------------------------------------------------------
/string/easy/longest_common_prefix.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def longestCommonPrefix(self, strs: List[str]) -> str:
3 | for i in range(len(strs[0])):
4 | for j in range(1, len(strs)):
5 | if i == len(strs[j]) or strs[0][i]!=strs[j][i]:
6 | return strs[0][0:i]
7 |
8 | return strs[0]
9 |
--------------------------------------------------------------------------------
/string/easy/unique_email_addresses.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numUniqueEmails(self, emails: List[str]) -> int:
3 | final_output = {}
4 | for i in emails:
5 | domain = i.split("@")[-1]
6 | if "+" in i:
7 | i = i.split("+")[0] + "@" + domain
8 | if "." in i:
9 | i = i.replace(".", "") + "@" + domain
10 | final_output[i] = 1
11 | return len(final_output)
12 |
--------------------------------------------------------------------------------
/string/easy/valid_anagram.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isAnagram(self, s: str, t: str) -> bool:
3 | if len(s) == len(t):
4 | hash_map = dict.fromkeys(set("".join([s, t])), 0)
5 | for i, j in zip(s, t):
6 | hash_map[i] += 1
7 | hash_map[j] -= 1
8 | if any(hash_map.values()):
9 | return False
10 | else:
11 | return True
12 | else:
13 | return False
14 |
--------------------------------------------------------------------------------
/string/easy/valid_palindrome.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | class Solution:
5 | def isPalindrome(self, s: str) -> bool:
6 | sentence = ("".join(re.findall("[a-zA-Z0-9]+", s))).lower()
7 | length_sentence = len(sentence)
8 | if length_sentence == 0 or length_sentence == 1:
9 | return True
10 | for i in range(length_sentence // 2):
11 | if sentence[i] == sentence[length_sentence - i - 1]:
12 | pass
13 | else:
14 | return False
15 | return True
16 |
--------------------------------------------------------------------------------
/string/easy/valid_parentheses.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isValid(self, s: str) -> bool:
3 | if len(s) == 0: return false
4 | open_bracket = {")":"(", "}":"{", "]":"["}
5 | stack = []
6 | for i in s:
7 | if i in open_bracket.values():
8 | stack.append(i)
9 | elif len(stack) == 0 and i in open_bracket.keys():
10 | return False
11 | elif open_bracket[i] == stack[len(stack)-1] and len(stack)>0:
12 | stack.pop()
13 | elif open_bracket[i] != stack[len(stack) - 1] and len(stack)>0:
14 | return False
15 |
16 | if len(stack)==0:
17 | return True
18 |
--------------------------------------------------------------------------------
/string/medium/find_all_anagrams_in_a_string.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findAnagrams(self, s: str, p: str) -> List[int]:
3 |
4 | phash = (dict.fromkeys(p+s, 0))
5 | shash = (dict.fromkeys(p+s, 0))
6 | final_result = []
7 |
8 | for i in p:
9 | phash[i] += 1
10 |
11 | for i in s[:len(p)]:
12 | shash[i] += 1
13 | if phash == shash:
14 | final_result.append(0)
15 |
16 | for idx, j in enumerate(s[1:-(len(p)-1) if len(p)!=1 else len(s)]):
17 | shash[s[idx]]-=1
18 | shash[s[idx+len(p)]]+=1
19 | if phash == shash:
20 | final_result.append(idx+1)
21 | return final_result
22 |
--------------------------------------------------------------------------------
/string/medium/group_anagrams.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 |
3 | class Solution:
4 | def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
5 | final_output = defaultdict(list)
6 | for w in strs:
7 | final_output["".join(sorted(w))].append(w)
8 | return final_output.values()
9 |
--------------------------------------------------------------------------------
/string/medium/longest_substring_without_repeating_characters.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/string/medium/palindromic_substrings.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tree/easy/balanced_binary_tree.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tree/easy/binary_tree_preorder_traversal.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 |
8 | class Solution:
9 | def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
10 | if root is None:
11 | return []
12 |
13 | return (
14 | [root.val]
15 | + self.preorderTraversal(root.left)
16 | + self.preorderTraversal(root.right)
17 | )
18 |
--------------------------------------------------------------------------------
/tree/easy/maximum_depth_binary_tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 |
8 |
9 | class Solution:
10 | def maxDepth(self, root: Optional[TreeNode]) -> int:
11 | if root is None:
12 | return 0
13 | return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
14 |
--------------------------------------------------------------------------------
/tree/easy/same_tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right'
7 | class Solution:
8 | def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
9 | if (p is None) and (q is None):
10 | return True
11 | elif (p is None) or (q is None) or (p.val != q.val):
12 | return False
13 | return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
14 | qu
15 |
--------------------------------------------------------------------------------
/tree/easy/symmetric_tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 |
8 | class Solution:
9 | def isSymmetric(self, root: Optional[TreeNode]) -> bool:
10 | if root is None:
11 | return True
12 | return self.check_mirror(root.left, root.right)
13 |
14 | def check_mirror(
15 | self, left_node: Optional[TreeNode], right_node: Optional[TreeNode]
16 | ) -> bool:
17 | if left_node and right_node:
18 | return (
19 | left_node.val == right_node.val
20 | and self.check_mirror(left_node.left, right_node.right)
21 | and self.check_mirror(left_node.right, right_node.left)
22 | )
23 | return left_node == right_node
24 |
--------------------------------------------------------------------------------