├── 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 | --------------------------------------------------------------------------------