├── .gitattributes ├── .gitignore ├── C++ └── Intersection_of_Linked_Lists.cpp ├── C ├── Hamming_Weight.c ├── Intersection_of_Linked_Lists.c ├── Number_Of_Islands.c ├── Product_of_Array_Except_Self.c ├── Product_of_Array_Except_Self.exe └── Symmetric_Tree.c ├── Dart ├── Add_Two_Numbers.dart ├── BST_InOrder_Successor.dart ├── BST_Max_Depth.dart ├── BT_Inorder_Traversal.dart ├── First_Unique_Char.dart ├── Has_Path_Sum.dart ├── Maximum_Sum_Subarray.dart ├── MergeSort ├── Move_Zeroes.dart ├── Plus_One.dart ├── Reverse_Words_in_a_String.dart ├── Symmetric_Tree.dart ├── Two_Sum_All_Pairs.dart ├── Valid_Anagram.dart ├── Validate_Binary_Tree.dart ├── _DATATYPES.dart └── main.dart ├── Go ├── Best_Time_to_Buy_and_Sell_Stock.go ├── Find_Pivot_Index.go ├── First_Missing_Positive.go ├── First_Unique_Char.go ├── Maximum_Subarray.go ├── Move_Zeroes.go ├── Plus_One.go ├── Two_Sum.go └── Valid_Parentheses.go ├── Haskell ├── Test.hs └── g.hs ├── Java ├── Bubble_Sort.java ├── Insertion_Sort.java └── Intersection_of_Linked_Lists.cpp ├── Javascript ├── Add_Two_Numbers.js ├── Bubble_Sort.js ├── Coin_Change.js ├── First_Unique_Char.js ├── Intersection_of_Linked_Lists.js ├── Move_Zeroes.js ├── Pivot_Index.js ├── Plus_One.js ├── Symmetric_Tree.js └── Two_Sum.js ├── Kotlin ├── Find_Pivot_Index.kt ├── First_Missing_Positive.kt ├── Move_Zeroes.kt ├── Two_Sum.kt └── main.kt ├── Python ├── Add_Binary.py ├── Add_Two_Numbers.py ├── BST_InOrder_Predecessor.py ├── BST_InOrder_Successor.py ├── BST_Kth_Smallest_Element.py ├── BST_Min_Depth.py ├── BST_Min_Difference.py ├── BST_Postorder_Traversal.py ├── BST_Preorder_Traversal.py ├── BST_Search.py ├── BST_To_Greater_Tree.py ├── BST_Univalue.py ├── BT_Flatten_To.py ├── BT_Inorder_Traversal.py ├── BT_Lowest_Common_Ancestor.py ├── Best_Time_to_Buy_and_Sell_Stock.py ├── Binary_Search_Tree_to_Greater_Sum_Tree.py ├── Binary_Tree_Inorder_Traversal.py ├── Binary_Tree_Level_Order_Traversal.py ├── Binary_Tree_Maximum_Path_Sum.py ├── Binary_Tree_Zig_Zag_Traversal.py ├── Bubble_Sort.py ├── Climbing_Stairs.py ├── Closest_Binary_Search_Tree_Value.py ├── Coin_Change.py ├── Combination_Sum.py ├── Compare_Version_Numbers.py ├── Connect_Next_Pointer_Tree.py ├── Connected_Components_In_Undirected_Graph.py ├── Count_Inversions.py ├── Course_Schedule.py ├── Course_Schedule_II.py ├── Cycle_In_DAG.py ├── Decode_String.py ├── Decode_Ways.py ├── Delete_Node_From_Linked_List.py ├── Delete_Nodes_And_Return_Forest.py ├── Delete_Operation_for_Two_Strings.py ├── Diagonal_Traverse.py ├── Distance_To_Node.py ├── Edit_Distance.py ├── Find_First_and_Last_Position_of_Element_in_Sorted_Array.py ├── Find_Pivot_Index.py ├── First_Missing_Positive.py ├── First_Unique_Char.py ├── Flip_And_Invert_Image.py ├── Flood_Fill.py ├── Generate_Paranthesis.py ├── Graph_Is_Tree.py ├── Hamming_Distance.py ├── Hamming_Weight.py ├── Happy_Number.py ├── Has_Path_Sum.py ├── Increasing_Triplet_Subsequence.py ├── Insert_into_a_Binary_Search_Tree.py ├── Insertion_Sort.py ├── Intersection_of_Linked_Lists.py ├── Invert_Binary_Tree.py ├── K_Closest_Elements.py ├── K_Diff_Unique_Pairs.py ├── K_difference_pairs.py ├── Kth_Largest_Element.py ├── Kth_Smallest_Element_BST.py ├── Kth_Smallest_Element_in_a_BST.py ├── LRU_Cache.py ├── Least_Num_Squares.py ├── Letter_Combinations_of_a_Phone_Number.py ├── Longest_Common_Prefix.py ├── Longest_Common_Subsequence.py ├── Longest_Consecutive_Sequence.py ├── Longest_Palindrome.py ├── Longest_Palindrome_Substring.py ├── Longest_Substring_Without_Repeating_Characters.py ├── Longest_Substring_with_At_Most_Two_Distinct_Characters.py ├── Longest_unique_substring.py ├── Majority_Element.py ├── Maximum_Length_of_Repeated_Subarray.py ├── Maximum_Product_Subarray.py ├── Maximum_Size_Subarray_Sum_Equals_k.py ├── Maximum_Subarray.py ├── Maximum_Sum_Subarray.py ├── Meeting_Rooms_II.py ├── Merge_Intervals.py ├── Merge_Linked_List.py ├── Merge_Sort.py ├── Merge_k_Sorted_Lists.py ├── Min_Tree_Path.py ├── Minimum_Window_Substring.py ├── Move_Zeroes.py ├── Multiply_By_Others.py ├── Number_Of_Islands.py ├── One_Edit_Distance.py ├── Palindrome_Number.py ├── Parallel_Courses_III.py ├── Path_To_Leaves.py ├── Permutations.py ├── Plus_One.py ├── Pow(x, n).py ├── Product_of_Array_Except_Self.py ├── Redundant_Connection.py ├── Remove_Sorted_Duplicates.py ├── Reverse_Linked_List.py ├── Reverse_Only_Letters.py ├── Reverse_String.py ├── Reverse_Words_In_String_III.py ├── Reverse_Words_in_a_String.py ├── Rotate_Array.py ├── Same_Tree.py ├── Search_Unsorted_Array.py ├── Search_in_Rotated_Sorted_Array.py ├── Selection_Sort.py ├── Shell_Sort.py ├── Shortest_Distance.py ├── Single_Number.py ├── Smallest_Unsorted_Subarray.py ├── Sort_Array_By_Parity.py ├── Spiral_Matrix.py ├── Spiral_Matrix_Traversal.py ├── String_To_Int.py ├── String_to_Integer.py ├── Strobogrammatic_Number.py ├── Subarray_Sum_Equals_K.py ├── Subset_Sum.py ├── Subsets.py ├── Sum_Of_Left_Leaves.py ├── Sum_Root_to_Leaf_Numbers.py ├── Symmetric_Tree.py ├── Text_Justification.py ├── Three_Sum.py ├── Top_K_Frequent_Elements.py ├── Top_Sort_BFS.py ├── Topological_DFS.py ├── Trapping_Rain_Water.py ├── Two_Sum.py ├── Two_Sum_All_Pairs.py ├── Two_Sum_Sorted.py ├── Unique_Paths.py ├── Valid_Anagram.py ├── Valid_Parentheses.py ├── Valid_Sudoku.py ├── Validate_Binary_Tree.py ├── Validate_DAG.py ├── Word_Break.py ├── ZigZag_Conversion.py ├── _DATATYPES.py └── __pycache__ │ └── _DATATYPES.cpython-37.pyc ├── README.md └── Rust ├── Plus_One.rs ├── Two_Sum.rs └── main.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Python/__pycache__ 2 | \.vscode 3 | secrets/ 4 | Rust/*.exe 5 | Rust/*.pdb 6 | Kotlin/*.exe 7 | Kotlin/*.jar 8 | Typescript/*.js -------------------------------------------------------------------------------- /C++/Intersection_of_Linked_Lists.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 | ListNode *a = headA; 5 | ListNode *b = headB; 6 | while (a != b){ 7 | if(!a) a = headB; 8 | else a = a->next; 9 | if(!b) b = headA; 10 | else b = b->next; 11 | } 12 | return a; 13 | } 14 | }; -------------------------------------------------------------------------------- /C/Hamming_Weight.c: -------------------------------------------------------------------------------- 1 | int hammingWeight(uint32_t n) { 2 | int count = 0; 3 | while (n) { 4 | if (n & 1) count++; 5 | n >>= 1; 6 | } 7 | return count; 8 | } -------------------------------------------------------------------------------- /C/Intersection_of_Linked_Lists.c: -------------------------------------------------------------------------------- 1 | struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { 2 | struct ListNode *a = headA; 3 | struct ListNode *b = headB; 4 | 5 | while (a != b){ 6 | if(!a) a = headB; 7 | else a = a->next; 8 | if(!b) b = headA; 9 | else b = b->next; 10 | } 11 | return a; 12 | 13 | } -------------------------------------------------------------------------------- /C/Number_Of_Islands.c: -------------------------------------------------------------------------------- 1 | // Question: Given a grid of 1s and 0s, determine the number of disjoint islands present if islands are connected by 1s 2 | // Solution: Run a DFS on each island, making what you have covered 3 | // Difficulty: Easy 4 | 5 | int numIslands(char** grid, int gridRowSize, int gridColSize) { 6 | int count = 0; 7 | void dfs(int i, int j, char** grid) { 8 | if (i < 0 || j < 0 || i >= gridRowSize || j >= gridColSize || grid[i][j] == '0') return; 9 | grid[i][j] = '0'; 10 | dfs(i - 1, j, grid); 11 | dfs(i + 1, j, grid); 12 | dfs(i, j + 1, grid); 13 | dfs(i, j - 1, grid); 14 | } 15 | 16 | for(int i = 0; i < gridRowSize; i++) { 17 | for (int j = 0; j < gridColSize; j++) { 18 | if (grid[i][j] == '1') { 19 | count++; 20 | dfs(i, j, grid); 21 | } 22 | } 23 | } 24 | 25 | return count; 26 | } -------------------------------------------------------------------------------- /C/Product_of_Array_Except_Self.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | main(){ 4 | int age = 3; 5 | printf("I am %d years old!", &productExceptSelf([1, 2, 8], 3, 3)[0]); 6 | } 7 | 8 | int* productExceptSelf(int* nums, int numsSize, int* returnSize) { 9 | int result[numsSize]; 10 | int i = 0; 11 | for(i; i < numsSize; i++){ 12 | result[i] = 2; 13 | } 14 | result[0] = 5; 15 | int* iii = result[0]; 16 | return iii; 17 | } 18 | -------------------------------------------------------------------------------- /C/Product_of_Array_Except_Self.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kumailn/Algorithms/e6be0a0cbf0caf13a723a9edfd2df33c2234235f/C/Product_of_Array_Except_Self.exe -------------------------------------------------------------------------------- /C/Symmetric_Tree.c: -------------------------------------------------------------------------------- 1 | bool isSymmetric(struct TreeNode* root) { 2 | if(!root) return true; 3 | bool help(struct TreeNode* l, struct TreeNode* r){ 4 | if(!l && !r) return true; 5 | if(l && r && l->val != r->val) return false; 6 | if(!l || !r) return false; 7 | return help(l->left, r->right) && help(l->right, r->left); 8 | }; 9 | return help(root->left, root->right); 10 | } -------------------------------------------------------------------------------- /Dart/Add_Two_Numbers.dart: -------------------------------------------------------------------------------- 1 | import './_DATATYPES.dart'; 2 | 3 | ListNode addNums(ListNode l1, ListNode l2) { 4 | dynamic val1, val2, carry; 5 | ListNode number = ListNode(null); 6 | ListNode origin = number; 7 | val1 = l1.val; 8 | val2 = l2.val; 9 | carry = 0; 10 | while(l1 != null || l2 != null ||carry != 0){ 11 | if(l1 != null) val1 = l1.val; 12 | else val1 = 0; 13 | 14 | if(l2 != null) val2 = l2.val; 15 | else val2 = 0; 16 | 17 | number.next = ListNode((val1 + val2 + carry) % 10); 18 | carry = (val1 + val2 + carry) ~/ 10; 19 | number = number.next; 20 | } 21 | return origin.next; 22 | } 23 | 24 | void main() { 25 | var a = ListNode(1); 26 | 27 | var b = ListNode(4); 28 | 29 | print(addNums(a, b)); 30 | } -------------------------------------------------------------------------------- /Dart/BST_InOrder_Successor.dart: -------------------------------------------------------------------------------- 1 | import './_DATATYPES.dart'; 2 | //Question: Given the root node of a tree, find the in order successor of that node 3 | //Solution: Find the first node that is not smaller than the given one 4 | //Difficulty: Easy 5 | 6 | TreeNode inorderSuccessor(TreeNode root, TreeNode p){ 7 | if (root == null) return null; 8 | dynamic successor = null; 9 | while (root != null){ 10 | if (root.val > p.val) { 11 | successor = root; 12 | root = root.left; 13 | } 14 | else root = root.right; 15 | } 16 | return successor; 17 | } 18 | 19 | main(List args) { 20 | var a = TreeNode(6); 21 | a.left = TreeNode(4); 22 | a.left.right = TreeNode(5); 23 | a.left.left = TreeNode(3); 24 | print(inorderSuccessor(a, TreeNode(4))); 25 | } -------------------------------------------------------------------------------- /Dart/BST_Max_Depth.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import './_DATATYPES.dart'; 3 | 4 | num bstDepth(TreeNode root) { 5 | if (root == null) return 0; 6 | return 1 + max(bstDepth(root.left), bstDepth(root.right)); 7 | } 8 | 9 | void main() { 10 | var a = TreeNode(1); 11 | a.left = TreeNode(2); 12 | a.right = TreeNode(3); 13 | a.left.left = TreeNode(4); 14 | 15 | print(bstDepth(a)); 16 | } -------------------------------------------------------------------------------- /Dart/BT_Inorder_Traversal.dart: -------------------------------------------------------------------------------- 1 | import '_DATATYPES.dart'; 2 | 3 | List inorder(TreeNode root) { 4 | List depthFirst(TreeNode root, List order) { 5 | if (root.left != null) depthFirst(root.left, order); 6 | order.add(root.val); 7 | if (root.right != null) depthFirst(root.right, order); 8 | return order; 9 | } 10 | return depthFirst(root, []); 11 | } 12 | 13 | List inorder2(TreeNode root){ 14 | List stack = []; 15 | List result = []; 16 | while(stack.isNotEmpty || root != null) { 17 | if (root != null) { 18 | stack.add(root); 19 | root = root.left; 20 | } 21 | else{ 22 | TreeNode top = stack.removeLast(); 23 | result.add(top.val); 24 | root = top.right; 25 | } 26 | } 27 | return result; 28 | } 29 | 30 | main(List args) { 31 | var node = new TreeNode(5); 32 | node.left = TreeNode(3); 33 | node.left.right = TreeNode(4); 34 | node.right = TreeNode(7); 35 | 36 | print(inorder(node)); 37 | print(inorder2(node)); 38 | } -------------------------------------------------------------------------------- /Dart/First_Unique_Char.dart: -------------------------------------------------------------------------------- 1 | String firstUniqChar(String str) { 2 | Map letterCounts = Map(); 3 | for(int i=0; i allSums = []; 5 | void sumHelper(TreeNode root, num currentSum) { 6 | if (root.left == null && root.right == null) allSums.add(root.val + currentSum); 7 | if (root.left != null) sumHelper(root.left, currentSum + root.val); 8 | if (root.right != null) sumHelper(root.right, currentSum + root.val); 9 | } 10 | sumHelper(root, 0); 11 | return allSums.contains(sum); 12 | } 13 | 14 | main(List args) { 15 | TreeNode a = TreeNode(5); 16 | a.left = TreeNode(3); 17 | a.right = TreeNode(3); 18 | 19 | print(hasPathSum(a, 8)); 20 | } -------------------------------------------------------------------------------- /Dart/Maximum_Sum_Subarray.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | num maxSubArray(List nums) { 4 | num globalMax = 0, localMax = 0; 5 | for (int i = 0; i < nums.length; ++i) { 6 | localMax = max(nums[i], localMax + nums[i]); 7 | if(localMax > globalMax) globalMax = localMax; 8 | } 9 | return globalMax; 10 | } 11 | 12 | void main () { 13 | print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4])); 14 | } -------------------------------------------------------------------------------- /Dart/MergeSort: -------------------------------------------------------------------------------- 1 | void mergeSort(List list, 2 | {int start: 0, int end, int compare(T a, T b)}) { 3 | end ??= list.length; 4 | compare ??= defaultCompare(); 5 | 6 | int length = end - start; 7 | if (length < 2) return; 8 | if (length < _MERGE_SORT_LIMIT) { 9 | insertionSort(list, compare: compare, start: start, end: end); 10 | return; 11 | } 12 | int middle = start + ((end - start) >> 1); 13 | int firstLength = middle - start; 14 | int secondLength = end - middle; 15 | // secondLength is always the same as firstLength, or one greater. 16 | var scratchSpace = new List(secondLength); 17 | _mergeSort(list, compare, middle, end, scratchSpace, 0); 18 | int firstTarget = end - firstLength; 19 | _mergeSort(list, compare, start, middle, list, firstTarget); 20 | _merge(compare, list, firstTarget, end, scratchSpace, 0, secondLength, list, 21 | start); 22 | } 23 | -------------------------------------------------------------------------------- /Dart/Move_Zeroes.dart: -------------------------------------------------------------------------------- 1 | /* Question: Move 0s to the end of a list 2 | Difficulty: Easy 3 | Solution: Keep an index to place non zeros at and keep incrementing it each time you encounter a non zero 4 | Space Complexity: O(1) 5 | Time Complexity: O(n) */ 6 | 7 | List moveZeroes(List nums) { 8 | int nonZeroIndex = 0; 9 | for (int i = 0; i < nums.length; i++) { 10 | if (nums[i] != 0) { 11 | int swap = nums[i]; 12 | nums[i] = nums[nonZeroIndex]; 13 | nums[nonZeroIndex++] = swap; 14 | } 15 | } 16 | 17 | return nums; 18 | } 19 | 20 | main(List args) { 21 | List nums = [1, 0, 0, 4, 5, 0]; 22 | print(moveZeroes(nums)); 23 | } -------------------------------------------------------------------------------- /Dart/Plus_One.dart: -------------------------------------------------------------------------------- 1 | plusOne(List digits) { 2 | for(int i = digits.length - 1; i >= 0; i--) { 3 | if (digits[i] < 9) { 4 | ++digits[i]; 5 | return digits; 6 | } 7 | digits[i] = 0; 8 | } 9 | return [1] + digits; 10 | } 11 | 12 | void main() { 13 | print(plusOne([1, 2, 3])); 14 | print(plusOne([9, 9, 9])); 15 | print(plusOne([0])); 16 | } -------------------------------------------------------------------------------- /Dart/Reverse_Words_in_a_String.dart: -------------------------------------------------------------------------------- 1 | //Question: Given a string, reverse the positions of the words, for example 'hi my name is' becomes 'is name my hi' 2 | //Solution: Reverse string, then reverse each word 3 | //Time Complexity: O(n) 4 | 5 | String reverseWords(String strin) { 6 | List reverse(int start, int end, List str){ 7 | while (start < end) { 8 | String temp = str[start]; 9 | str[start] = str[end]; 10 | str[end] = temp; 11 | 12 | start++; 13 | end--; 14 | } 15 | return str; 16 | } 17 | 18 | List new_strin = strin.split("").reversed.toList(); 19 | 20 | int i = 0; 21 | while (i < new_strin.length) { 22 | int end = i; 23 | if (new_strin[i] != " ") { 24 | while (end + 1 < new_strin.length && new_strin[end] != " "){ 25 | if (new_strin[end + 1] == " ") break; 26 | end++; 27 | } 28 | } 29 | new_strin = reverse(i, end, new_strin); 30 | i = end + 1; 31 | } 32 | 33 | return new_strin.join(""); 34 | } 35 | 36 | main(List args) { 37 | print(reverseWords("my name is")); 38 | } -------------------------------------------------------------------------------- /Dart/Symmetric_Tree.dart: -------------------------------------------------------------------------------- 1 | import './_DATATYPES.dart'; 2 | 3 | bool isSymmetric(TreeNode root) { 4 | bool symmetricHelper(TreeNode left, TreeNode right) { 5 | if (left == null && right == null) return true; 6 | if (left == null || right == null) return false; 7 | return left.val == right.val ? true : false; 8 | } 9 | return symmetricHelper(root.left, root.right); 10 | } 11 | 12 | main(List args) { 13 | TreeNode a = TreeNode(5); 14 | a.left = TreeNode(3); 15 | a.right = TreeNode(3); 16 | 17 | print(isSymmetric(a)); 18 | } -------------------------------------------------------------------------------- /Dart/Two_Sum_All_Pairs.dart: -------------------------------------------------------------------------------- 1 | num twoAll(List nums, num target) { 2 | Map targetCounts = Map(); 3 | num pairCount = 0; 4 | for(int i=0; i args) { 13 | var nums = [2, 3, 1, 3, 2, 1]; 14 | var nums2 = [1, 1, 1, 1, 1, 2, 0, 3, 0]; 15 | print(twoAll(nums, 5)); 16 | print(twoAll(nums2, 3)); 17 | } -------------------------------------------------------------------------------- /Dart/Valid_Anagram.dart: -------------------------------------------------------------------------------- 1 | 2 | bool isAnagram(String a, String b) { 3 | Map counts = new Map(); 4 | 5 | for(int i = 0; i < a.length; i++) { 6 | if (counts.containsKey(a[i])) counts[a[i]] += 1; 7 | else counts[a[i]] = 1; 8 | 9 | if (counts.containsKey(b[i])) counts[b[i]] -= 1; 10 | } 11 | 12 | return counts.isEmpty; 13 | } 14 | 15 | main(List args) { 16 | print(isAnagram('abcd', 'abdc')); 17 | } -------------------------------------------------------------------------------- /Dart/Validate_Binary_Tree.dart: -------------------------------------------------------------------------------- 1 | import './_DATATYPES.dart'; 2 | 3 | bool isValidBST(TreeNode root, {double maxVal = double.infinity, double minVal = double.negativeInfinity}) { 4 | if (root == null) return true; 5 | if (root.val >= maxVal || root.val <= minVal) return false; 6 | return isValidBST(root.left, maxVal: root.val, minVal: minVal) && isValidBST(root.right, minVal: root.val, maxVal: maxVal); 7 | } 8 | 9 | main(List args) { 10 | TreeNode a = TreeNode(5.0); 11 | a.left = TreeNode(3.0); 12 | a.left.right = TreeNode(4.0); 13 | a.right = TreeNode(11.0); 14 | a.right.left = TreeNode(7.0); 15 | 16 | TreeNode b = TreeNode(5.0); 17 | b.left = TreeNode(4.0); 18 | 19 | print(isValidBST(a)); 20 | } -------------------------------------------------------------------------------- /Dart/_DATATYPES.dart: -------------------------------------------------------------------------------- 1 | 2 | class TreeNode { 3 | dynamic val; 4 | TreeNode left, right; 5 | TreeNode(this.val); 6 | 7 | @override 8 | String toString() { 9 | return val.toString(); 10 | } 11 | } 12 | 13 | class ListNode { 14 | dynamic val; 15 | ListNode next; 16 | ListNode(this.val); 17 | 18 | @override 19 | String toString() { 20 | return val.toString(); 21 | } 22 | } -------------------------------------------------------------------------------- /Dart/main.dart: -------------------------------------------------------------------------------- 1 | void main() => print('Suh'); -------------------------------------------------------------------------------- /Go/Best_Time_to_Buy_and_Sell_Stock.go: -------------------------------------------------------------------------------- 1 | // Question: Given a list of stock prices each day, determine the most profit you could make buying and selling the stock once 2 | // Solution: Loop through finding the minimum price each time, and then the max profit. This works because the profit will be negative on days where the stock goes down 3 | // Difficulty: Easy 4 | // Time Complexity: O(n) 5 | // Space Complexity: O(n) 6 | 7 | import "math" 8 | 9 | func maxProfit(prices []int) int { 10 | lowestPrice := math.Inf(1) 11 | maxProfit := float64(0) 12 | 13 | for _, v := range prices { 14 | // Update lowestPrice to be the min found so far, and maxProfit to the max profit if we solf the lowestPrice today 15 | // this works because lowestPrice is always in the past and maxProfit is calculated for today 16 | lowestPrice = math.Min(lowestPrice, float64(v)) 17 | maxProfit = math.Max(maxProfit, float64(v) - lowestPrice) 18 | } 19 | 20 | return int(maxProfit) 21 | } -------------------------------------------------------------------------------- /Go/Find_Pivot_Index.go: -------------------------------------------------------------------------------- 1 | func pivotIndex(nums []int) int { 2 | if len(nums) == 0 { 3 | return -1 4 | } 5 | 6 | left := 0 7 | right := 0 8 | for _, v := range nums { 9 | right += v 10 | } 11 | 12 | for i, v := range nums { 13 | right -= v 14 | if left == right { 15 | return i 16 | } 17 | left += v 18 | } 19 | 20 | return -1 21 | } -------------------------------------------------------------------------------- /Go/First_Missing_Positive.go: -------------------------------------------------------------------------------- 1 | // Question: Given a list of ints, find the smallest missing positive number 2 | // Solution: Sort the list as you go through by placing every term on its index + 1th place. 3 | // Difficulty: Hard 4 | // Time Complexity: O(n) 5 | // Space Complexity: O(1) 6 | 7 | func firstMissingPositive(nums []int) int { 8 | i := 0 9 | j := len(nums) 10 | 11 | for i < j { 12 | predecessor := nums[i]-1 13 | 14 | // Shift up if the current number is in the correct order (eg. if 5 is in index 4) 15 | if nums[i] == i+1 { 16 | i++ 17 | } 18 | 19 | // If num is within range but its in the wrong spot swap it 20 | // eg. If current num is 5 but nums[5-1] or nums[4] isn't 5 21 | else if (nums[i] > 0 && nums[i]) <= j && nums[predecessor] != nums[i] { 22 | tmp := nums[i] 23 | nums[i] = nums[predecessor] 24 | nums[predecessor] = tmp 25 | } 26 | 27 | // If the above checks fail we have a duplicate or num out of range 28 | // place at end and shrink the bounds 29 | else { 30 | j -= 1 31 | tmp := nums[i] 32 | nums[i] = nums[j] 33 | nums[j] = tmp 34 | } 35 | } 36 | 37 | return j + 1 38 | } -------------------------------------------------------------------------------- /Go/First_Unique_Char.go: -------------------------------------------------------------------------------- 1 | import "math" 2 | 3 | func firstUniqChar(s string) int { 4 | // Create a struct which we can populate our hashmap with 5 | type Pair struct { 6 | count int 7 | index int 8 | } 9 | 10 | seen := map[rune]*Pair{} 11 | 12 | // Loop over the string, incrementing count if the char exists and adding it othwerwise 13 | for i, v := range s { 14 | if _, ok := seen[v]; ok { 15 | seen[v].count++ 16 | } else { 17 | seen[v] = &Pair{1, i} 18 | } 19 | } 20 | 21 | lowest := math.Inf(1) 22 | 23 | // Loop over the hashmap, and find the minimum index with a count of 1 24 | for _, v := range seen { 25 | if v.count == 1 { 26 | lowest = math.Min(lowest, float64(v.index)) 27 | } 28 | } 29 | 30 | if lowest == math.Inf(1) { 31 | return -1 32 | } else { 33 | return int(lowest) 34 | } 35 | } -------------------------------------------------------------------------------- /Go/Maximum_Subarray.go: -------------------------------------------------------------------------------- 1 | import "math" 2 | 3 | func maxSubArray(nums []int) int { 4 | localMax, globalMax := math.Inf(-1), math.Inf(-1) 5 | 6 | for _, v := range nums { 7 | localMax = math.Max(localMax+float64(v), float64(v)) 8 | globalMax = math.Max(globalMax, localMax) 9 | } 10 | 11 | return int(globalMax) 12 | } -------------------------------------------------------------------------------- /Go/Move_Zeroes.go: -------------------------------------------------------------------------------- 1 | func moveZeroes(nums []int) { 2 | notZeroIndex := 0 3 | 4 | for i, v := range nums { 5 | if v != 0 { 6 | nums[i], nums[notZeroIndex] = nums[notZeroIndex], nums[i] 7 | notZeroIndex++ 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Go/Plus_One.go: -------------------------------------------------------------------------------- 1 | // Question: Given a list representing a number add one to it and return as list 2 | // Solution: Loop through list, add 1 if not 9, otherwise change to 0, if head is 0 append 1 to head 3 | // Difficulty: Easy 4 | // Time Complexity: O(n) 5 | // Space Complexity: O(1) 6 | 7 | func plusOne(digits []int) []int { 8 | for i := len(digits) - 1; i >= 0; i-- { 9 | if digits[i] < 9 { 10 | digits[i]++ 11 | return digits 12 | } 13 | digits[i] = 0 14 | } 15 | 16 | return append([]int{1}, digits...) 17 | } -------------------------------------------------------------------------------- /Go/Two_Sum.go: -------------------------------------------------------------------------------- 1 | func twoSum(nums []int, target int) []int { 2 | lookingFor := map[int]int{} 3 | for i, v := range nums { 4 | if val, ok := lookingFor[v]; ok { 5 | return []int{val, i} 6 | } 7 | lookingFor[target-v] = i 8 | } 9 | return []int{-1, -1} 10 | } -------------------------------------------------------------------------------- /Go/Valid_Parentheses.go: -------------------------------------------------------------------------------- 1 | func isValid(s string) bool { 2 | stack := []rune{} 3 | complement := map[rune]rune{ 4 | '}': '{', 5 | ')': '(', 6 | ']': '[', 7 | } 8 | 9 | for _, v := range s { 10 | if v == '(' || v == '[' || v == '{' { 11 | stack = append(stack, v) 12 | } else if len(stack) != 0 && stack[len(stack)-1] == complement[v] { 13 | stack = stack[:len(stack)-1] 14 | } else { 15 | return false 16 | } 17 | } 18 | 19 | return len(stack) == 0 20 | } -------------------------------------------------------------------------------- /Haskell/Test.hs: -------------------------------------------------------------------------------- 1 | import Data.List 2 | import System.IO 3 | 4 | maxInt = maxBound :: Int 5 | sumOfNums = sum[1..1000] -------------------------------------------------------------------------------- /Haskell/g.hs: -------------------------------------------------------------------------------- 1 | inc :: Int -> Int 2 | inc x = x + 1 3 | 4 | main = putStrLn inc(5) 5 | -------------------------------------------------------------------------------- /Java/Bubble_Sort.java: -------------------------------------------------------------------------------- 1 | //Simple bubble sort implemntation 2 | import java.util.Arrays; 3 | 4 | public class Bubble { 5 | public static void main(String[] args) { 6 | int[] myarr = {34, 23, 34, 2, 3, 8, 4, 5}; 7 | BubbleSort(myarr); 8 | System.out.println(Arrays.toString(myarr)); 9 | } 10 | 11 | public static void BubbleSort(int[] arr){ 12 | for(int i = arr.length - 1; i > 1; i--){ 13 | for(int j = 0; j < i; j++){ 14 | if(arr[j] > arr[j+1]){ 15 | int temp = arr[j]; 16 | arr[j] = arr[j+1]; 17 | arr[j+1]= temp; 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Java/Insertion_Sort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Insert { 4 | public static void sortInsert(Integer[] arr){ 5 | for(int i = 0; i < arr.length; i++){ 6 | int j = i; 7 | while(j > 0 && arr[j] < arr[j - 1]){ 8 | int temp = arr[j]; 9 | arr[j] = arr[j-1]; 10 | arr[j-1] = temp; 11 | j--; 12 | } 13 | } 14 | } 15 | 16 | public static void main(String[] args) { 17 | Integer[] a = new Integer[]{5, 6, 4, 3}; 18 | System.out.println(Arrays.toString(a)); 19 | sortInsert(a); 20 | System.out.println(Arrays.toString(a)); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Java/Intersection_of_Linked_Lists.cpp: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 3 | ListNode a = headA; 4 | ListNode b = headB; 5 | while (a != b){ 6 | if(a == null) a = headB; 7 | else a = a.next; 8 | if(b == null) b = headA; 9 | else b = b.next; 10 | }; 11 | return a; 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /Javascript/Add_Two_Numbers.js: -------------------------------------------------------------------------------- 1 | function addTwoNumbers(l1, l2) { 2 | if (!l1 || !l2) return l1 ? l1 : l2 3 | let origin = new ListNode(null), num = origin, carry = 0, n1 = 0, n2 = 0; 4 | while(l1 || l2 || carry){ 5 | n1 = l1 ? l1.val : 0; 6 | n2 = l2 ? l2.val : 0; 7 | num.next = new ListNode((n1 + n2 + carry) % 10); 8 | carry = Math.floor((n1 + n2 + carry)/10); 9 | if(l1) l1 = l1.next; 10 | if(l2) l2 = l2.next 11 | num = num.next 12 | }; 13 | return origin.next; 14 | }; -------------------------------------------------------------------------------- /Javascript/Bubble_Sort.js: -------------------------------------------------------------------------------- 1 | function bubbleSort(arr){ 2 | for(var i = arr.length; i > 0; i--){ 3 | for(var j = 0; j < i; j++){ 4 | if(arr[j] > arr[j+1]){ 5 | var temp = arr[j] 6 | arr[j] = arr[j+1] 7 | arr[j+1] = temp 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Javascript/Coin_Change.js: -------------------------------------------------------------------------------- 1 | // amount = total amount, coins = array of coin 2 | function coinChange(amount, coins){ 3 | let storedAmounts = Array(amount + 1).fill(0); 4 | storedAmounts[0] = 1; 5 | for(let coin of coins){ 6 | for(let currentAmount of storedAmounts.keys()){ 7 | if(currentAmount >= coin){ 8 | let remainder = currentAmount - coin; 9 | storedAmounts[currentAmount] += storedAmounts[remainder]; 10 | } 11 | } 12 | } 13 | return storedAmounts.pop(); 14 | } 15 | 16 | console.log(coinChange(12, [1, 2, 5])); -------------------------------------------------------------------------------- /Javascript/First_Unique_Char.js: -------------------------------------------------------------------------------- 1 | // Question: Given a string, find the first character that is unique 2 | // Solution: Count the occurance of each letter, find the first letter with 1 occurance from your hashmap 3 | // because we don't want to loop over our input string twice if it's very long 4 | // Difficulty: Easy 5 | 6 | /** 7 | * @param {string} s 8 | * @return {number} 9 | */ 10 | 11 | let firstUniqChar = function(s) { 12 | // Create a hashmap to store the counts of each letter as well as the index 13 | let letterCounts = {} 14 | 15 | // Store the lowest index we see with a letter count of 1 when we traverse our hashmap 16 | smallestIndex = s.length 17 | 18 | // Store each items count as well as the first index it occured at 19 | for (let i = 0; i < s.length; i++) { 20 | if (!letterCounts[s[i]]) letterCounts[s[i]] = [1, i]; 21 | else letterCounts[s[i]][0]++; 22 | } 23 | 24 | // Loop through the hashmap updating the smallestIndex each time we see a letter 25 | // with a count of 1 and a smaller index than the previous 26 | let keys = Object.keys(letterCounts); 27 | for(let letter of keys){ 28 | if (letterCounts[letter][0] == 1) { 29 | if (letterCounts[letter][1] < smallestIndex) smallestIndex = letterCounts[letter][1]; 30 | } 31 | } 32 | 33 | // Return either the index of the first char or -1 if there is no unique char 34 | return smallestIndex == s.length ? -1 : smallestIndex 35 | }; -------------------------------------------------------------------------------- /Javascript/Intersection_of_Linked_Lists.js: -------------------------------------------------------------------------------- 1 | function getIntersectionNode(headA, headB) { 2 | let a = headA, b = headB; 3 | while (a !== b){ 4 | a = a ? a.next : headB; 5 | b = b ? b.next : headA; 6 | } 7 | return a; 8 | }; -------------------------------------------------------------------------------- /Javascript/Move_Zeroes.js: -------------------------------------------------------------------------------- 1 | //Question: Move 0s to the end of a list 2 | //Difficulty: Easy 3 | //Solution: Keep an index to place non zeros at and keep incrementing it each time you encounter a non zero 4 | //Space Complexity: O(1) 5 | //Time Complexity: O(n) 6 | 7 | var moveZeroes = function(nums) { 8 | let notZeroIndex = 0; 9 | nums.forEach((val, i) => { 10 | //If the element is not 0, swap it with the item at 'nonZeroIndex' and increment 'NnonZeroIndex' 11 | if (val != 0) { 12 | nums[i] = nums[notZeroIndex]; 13 | nums[notZeroIndex] = val; 14 | notZeroIndex++; 15 | } 16 | }) 17 | }; 18 | 19 | 20 | let main = () => { 21 | let test = [1, 4, 0, 4, 3, 0, 6, 0, 9]; 22 | moveZeroes(test); 23 | console.log(test); 24 | }; 25 | 26 | main(); -------------------------------------------------------------------------------- /Javascript/Pivot_Index.js: -------------------------------------------------------------------------------- 1 | function pivot(nums) { 2 | let total = nums.reduce((a, b) => a + b, 0); 3 | for(let i = 0; i < nums.length; i++){ 4 | let left_sum = nums.slice(0, i).reduce((a, b) => a + b, 0); 5 | console.log(left_sum) 6 | if(left_sum === total - left_sum - nums[i]){ 7 | return i; 8 | } 9 | } 10 | } 11 | 12 | console.log(pivot([1, 7, 3, 6, 5, 6])); -------------------------------------------------------------------------------- /Javascript/Plus_One.js: -------------------------------------------------------------------------------- 1 | function plusOne(nums) { 2 | for(let i = nums.length; i >= 0; i--){ 3 | if (nums[i] < 9) { 4 | nums[i]++; 5 | return nums; 6 | } 7 | nums[i] = 0; 8 | } 9 | return [1].concat(nums); 10 | } 11 | 12 | function main() { 13 | console.log(plusOne([1, 2, 3])); 14 | console.log(plusOne([9, 9, 9])); 15 | console.log(plusOne([0])); 16 | } 17 | 18 | main(); -------------------------------------------------------------------------------- /Javascript/Symmetric_Tree.js: -------------------------------------------------------------------------------- 1 | var isSymmetric = function(root) { 2 | if(!root) return true; 3 | let help = (l, r) => { 4 | if (!l && !r) return true; 5 | if (l && r && l.val != r.val) return false; 6 | if (!l || !r) return false; 7 | return help(l.right, r.left) && help(l.left, r.right); 8 | } 9 | return help(root.left, root.right); 10 | }; -------------------------------------------------------------------------------- /Javascript/Two_Sum.js: -------------------------------------------------------------------------------- 1 | function twoSum(nums, target){ 2 | let countMap = {}, count = 0; 3 | for(let i = 0; i < nums.length; i++){ 4 | if (countMap[target - nums[i]]) count++; 5 | countMap[i] = countMap[i] ? countMap[i] + 1: 1 6 | } 7 | return count 8 | } 9 | 10 | console.log(twoSum([1, 2, 3, 0, 2], 4)) -------------------------------------------------------------------------------- /Kotlin/Find_Pivot_Index.kt: -------------------------------------------------------------------------------- 1 | // Question: Find the index of the element in the list such that 2 | // the sum of elements to its left equals the sum of elements to its right 3 | // Difficulty: Easy 4 | // Solution: Store the sum of the left side and right side and adjust each loop and check 5 | // Space Complexity: O(1) 6 | // Time Complexity: O(n) 7 | 8 | fun pivotIndex(nums: IntArray): Int { 9 | var leftSum = 0; 10 | var rightSum = nums.sum(); 11 | 12 | for(i in 0 until nums.size) { 13 | rightSum -= nums[i]; 14 | if (leftSum == rightSum) return i; 15 | leftSum += nums[i]; 16 | } 17 | return -1; 18 | } 19 | 20 | fun main(args: Array) { 21 | var nums: IntArray = intArrayOf(1, 7, 3, 6, 5, 6); 22 | print(pivotIndex(nums)); 23 | } -------------------------------------------------------------------------------- /Kotlin/First_Missing_Positive.kt: -------------------------------------------------------------------------------- 1 | // Question: Given a list of ints, find the smallest missing positive number 2 | // Solution: Sort the list as you go through by placing every term on its index + 1th place. 3 | // Difficulty: Hard 4 | // Time Complexity: O(n) 5 | // Space Complexity: O(1) 6 | 7 | fun firstMissingPositive(nums: IntArray): Int { 8 | var left = 0; 9 | var right = nums.size; 10 | 11 | while (left < right) { 12 | // If the current number is equal to its index + 1, skip over as its already sorted 13 | // for example if the number 5 is in the 4th index/ 5th place 14 | if (nums[left] == left + 1) left++; 15 | 16 | // Otherwise, if number not in the correct place 17 | // In othe words, if a number n is within our range and the number in the nth position isnt equal to this number, swap the two 18 | else if (nums[left] > 0 && nums[left] <= nums.size && nums[left] != nums[nums[left]-1]) { 19 | nums[nums[left]-1] = nums[left].also{ nums[left] = nums[nums[left]-1] }; 20 | } 21 | 22 | // Case if the number is a duplicate, or out of our range (1 to right). So place it at the end 23 | else nums[left] = nums[--right].also{ nums[right] = nums[left] }; 24 | } 25 | return right + 1; 26 | } 27 | 28 | fun main(args: Array) { 29 | var arr: IntArray = intArrayOf(7,8,9,11,12); 30 | print(firstMissingPositive(arr)); 31 | } -------------------------------------------------------------------------------- /Kotlin/Move_Zeroes.kt: -------------------------------------------------------------------------------- 1 | // Question: Move 0s to the end of a list 2 | // Difficulty: Easy 3 | // Solution: Keep an index to place non zeros at and keep incrementing it each time you encounter a non zero 4 | // Space Complexity: O(1) 5 | // Time Complexity: O(n) 6 | 7 | fun moveZeroes(nums: IntArray): Unit { 8 | //Initialize index to store numbers that aren't 0s 9 | var nonZeroIndex = 0; 10 | for(i in 0 until nums.size) { 11 | 12 | //Everytime a non zero is encountered, swap it with the item at the place of index 'nonZeroIndex' and increment 13 | if (nums[i] != 0) nums[nonZeroIndex] = nums[i].also{nums[i] = nums[nonZeroIndex++]}; 14 | } 15 | } 16 | 17 | fun main(args: Array) { 18 | val numbers: IntArray = intArrayOf(3, 2, 0, 6, 0, 8) 19 | moveZeroes(numbers); 20 | print(numbers.joinToString()); 21 | } -------------------------------------------------------------------------------- /Kotlin/Two_Sum.kt: -------------------------------------------------------------------------------- 1 | import java.util.Arrays 2 | 3 | fun twoSum(nums: IntArray, target: Int): IntArray { 4 | val lookingFor = HashMap(); 5 | for (i in nums.indices) { 6 | if (lookingFor.containsKey(nums[i])) return intArrayOf(lookingFor.get(nums[i])!!, i); 7 | lookingFor.put(target - nums[i], i); 8 | } 9 | 10 | return intArrayOf(0, 0); 11 | } 12 | 13 | fun main(args: Array) { 14 | println(Arrays.toString(twoSum(intArrayOf(2, 11, 15, 7), 9))); 15 | } -------------------------------------------------------------------------------- /Kotlin/main.kt: -------------------------------------------------------------------------------- 1 | fun main(args: Array) { 2 | println("Hello, World!") 3 | } -------------------------------------------------------------------------------- /Python/Add_Binary.py: -------------------------------------------------------------------------------- 1 | #Question: Add two binary numbers 2 | #Solution: Recursively add the numbers based on the last digit 3 | #Difficulty: Easy 4 | 5 | def addBinary(a, b): 6 | """ 7 | :type a: str 8 | :type b: str 9 | :rtype: str 10 | """ 11 | #If one of the strings is null, return the non null one 12 | if not a or not b: return a or b 13 | #If both strings end with a 1, add a 0 at the end, let the 1 overflow into the addition of the two strings again 14 | if a[-1] == '1' and b[-1] == '1': return addBinary(addBinary(a[:-1], b[:-1]), '1') + '0' 15 | #If both end in 0 simply add 0 at the end and continue the addition 16 | if a[-1] == '0' and b[-1] == '0': return addBinary(a[:-1], b[:-1]) + "0" 17 | #If one of them ends in 0 and the other doesn't, just add 1 to the end and add the rest of both strings 18 | return addBinary(a[:-1], b[:-1]) + '1' 19 | 20 | def main(): 21 | a = '1110' 22 | b = '1010' 23 | 24 | #Answer should be 11000 25 | print(addBinary(a, b)) 26 | 27 | main() -------------------------------------------------------------------------------- /Python/Add_Two_Numbers.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import ListNode 2 | # Question: Given two numbers in the form of linked lists, add them 3 | # Solution: Loop until the first list, second list or a carry exists, add accordingly 4 | # Difficulty: Easy 5 | 6 | def addTwoNumbers(l1, l2): 7 | #Initialize variable to hold the carryover from an addition 8 | carry = 0 9 | #Let origin = n = an empty LinkedList node 10 | orig = n = ListNode(None) 11 | #If one of the input nodes is null, return the one that's not 12 | if not l2 or not l1: return l2 if l2 else l1 13 | #While one of the nodes is not null or the carry value exists 14 | while l1 or l2 or carry: 15 | #Let value of node1 be the value of node1 if node1 is not null, otherwise 0, same for node2 16 | lv, lv2 = l1.val if l1 else 0, l2.val if l2 else 0 17 | #Let next node from our temp node be the sum of the values of the nodes and the carry, mod 10, (to find leftmost number) 18 | n.next = ListNode((lv + lv2 + carry) % 10) 19 | #Let the carry be the same sum but int divided by 10 (to find number after leftmost) 20 | carry = (lv + lv2 + carry) // 10 21 | #If node1 exists move to next, if node2 exists move to next, shift temp to next 22 | if l1: l1 = l1.next 23 | if l2: l2 = l2.next 24 | n = n.next 25 | #Return the origin nodes next node 26 | return orig.next 27 | 28 | def main(): 29 | a = ListNode(5) 30 | a.next = ListNode(6) 31 | a.next.next = ListNode(1) 32 | 33 | b = ListNode(9) 34 | b.next = ListNode(3) 35 | 36 | #165 + 39 = 204 37 | print(addTwoNumbers(a, b).printList()) 38 | 39 | main() -------------------------------------------------------------------------------- /Python/BST_InOrder_Predecessor.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given the root node of a tree, find the in order successor of that node 3 | #Solution: Find the first node that is not smaller than the given one 4 | #Difficulty: Easy 5 | 6 | def inorderPredecessor(root, p): 7 | if not root: return None 8 | predecessor = None 9 | 10 | while root: 11 | #Keep moving right if the current roots val is less than our target, while setting 'predecessor' to be the current root 12 | if root.val < p.val: predecessor, root = root, root.right 13 | #If the current roots value is less more our taget, move left 14 | else: root = root.left 15 | return predecessor 16 | 17 | def main(): 18 | a = TreeNode(6) 19 | a.left = TreeNode(4) 20 | a.left.right = TreeNode(5) 21 | a.left.left = TreeNode(3) 22 | 23 | print(inorderPredecessor(a, TreeNode(5))) 24 | 25 | main() -------------------------------------------------------------------------------- /Python/BST_InOrder_Successor.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given the root node of a tree, find the in order successor of that node 3 | #Solution: Find the first node that is not smaller than the given one 4 | #Difficulty: Easy 5 | 6 | def inorderSuccessor(root, p): 7 | if not root: return None 8 | successor = None 9 | while root: 10 | if root.val > p.val: successor, root = root, root.left 11 | else: root = root.right 12 | return successor 13 | 14 | def main(): 15 | a = TreeNode(6) 16 | a.left = TreeNode(4) 17 | a.left.right = TreeNode(5) 18 | a.left.left = TreeNode(3) 19 | 20 | print(inorderSuccessor(a, TreeNode(4))) 21 | 22 | main() -------------------------------------------------------------------------------- /Python/BST_Kth_Smallest_Element.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | 3 | def kthSmallest(root, k): 4 | """ 5 | :type root: TreeNode 6 | :type k: int 7 | :rtype: int 8 | """ 9 | stack = [] 10 | while stack or root: 11 | while root: 12 | stack += [root] 13 | root = root.left 14 | root = stack.pop() 15 | k -= 1 16 | if not k: return root.val 17 | root = root.right 18 | 19 | def main(): 20 | a = TreeNode(6) 21 | a.left = TreeNode(3) 22 | a.right = TreeNode(11) 23 | a.left.right = TreeNode(4) 24 | a.left.right.right = TreeNode(5) 25 | 26 | print(kthSmallest(a, 2)) 27 | 28 | main() -------------------------------------------------------------------------------- /Python/BST_Min_Depth.py: -------------------------------------------------------------------------------- 1 | #Question: Given the root of a tree, find the minimum dept the tree goes 2 | #Solution: Use a BFS traversal to find the first leaf node of the tree 3 | #Difficulty: Easy 4 | 5 | def minDepth(root): 6 | #Define queue, current queue and a mindepth variable 7 | queue = [root]; current = []; mindepth = 0 8 | #If our current node is null, the depth is 0, so return 0 9 | if not root: return mindepth 10 | #As long as our queue exists 11 | while queue: 12 | #For every element in our queue 13 | for i in queue: 14 | #If we have reached a leaf node, we can return 1+mindepth 15 | if not i.left and not i.right: return mindepth + 1 16 | #Else we append the left and right children to our queue (See BFS traversal) 17 | if i.left: current.append(i.left) 18 | if i.right: current.append(i.right) 19 | #Set queue to current queue, current to empty list and add one to our mindepth because we're now on a new level 20 | queue = current 21 | current = [] 22 | mindepth += 1 23 | return mindepth -------------------------------------------------------------------------------- /Python/BST_Min_Difference.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given a BST, find the minimum difference between any two nodes 3 | #Solution: Traverse in order, keep track of the previous node, and find the difference between current one. The minimun difference must be between two consecutive nodes because we are travelling in order! 4 | #Difficulty: Easy 5 | 6 | class Solution(object): 7 | #Value of previous node, set to -infinity intitially 8 | previousVal = float('-inf') 9 | #The minimum difference between the nodes, set to infinity initially 10 | minDifference = float('inf') 11 | def minDiffInBST(self, root): 12 | """ 13 | :type root: TreeNode 14 | :rtype: int 15 | """ 16 | #Define the recursive helper that travels in order 17 | def rec(r): 18 | #If left node exists go left 19 | if r.left: rec(r.left) 20 | #Set the min difference to be the min of itself or the difference between current and previous nodes 21 | self.minDifference = min(self.minDifference, (r.val - self.previousVal)) 22 | #Set the previous node to be the current node 23 | self.previousVal = r.val 24 | #IF right node exists go right 25 | if r.right: rec(r.right) 26 | #Run recursive helper 27 | rec(root) 28 | #Return original tree root 29 | return self.minDifference -------------------------------------------------------------------------------- /Python/BST_Postorder_Traversal.py: -------------------------------------------------------------------------------- 1 | def postorderTraversal(self, root): 2 | """ 3 | :type root: TreeNode 4 | :rtype: List[int] 5 | """ 6 | if not root: return [] 7 | def helper(root, order): 8 | if root.left: helper(root.left, order) 9 | if root.right: helper(root.right, order) 10 | if root: order.append(root.val) 11 | return order 12 | return helper(root, []) -------------------------------------------------------------------------------- /Python/BST_Preorder_Traversal.py: -------------------------------------------------------------------------------- 1 | def preorderTraversal(self, root): 2 | """ 3 | :type root: TreeNode 4 | :rtype: List[int] 5 | """ 6 | if not root: return [] 7 | def preorder(root, order): 8 | if root: order.append(root.val) 9 | if root.left: preorder(root.left, order) 10 | if root.right: preorder(root.right, order) 11 | return order 12 | return preorder(root, []) 13 | -------------------------------------------------------------------------------- /Python/BST_Search.py: -------------------------------------------------------------------------------- 1 | #Question: Given a BST and a value to find, find the node with that value 2 | #Solution: Simple BST tree traversal 3 | #Difficulty: Easy 4 | 5 | def searchBST(root, val): 6 | #As long as the current node is not null, and its value is not the value we're looking for 7 | while root and val != root.val: 8 | #Move to left child node if the value we're looking for is less than current nodes value, else to right child node 9 | root = root.left if val < root.val else root.right 10 | #Return the node we stop at 11 | return root -------------------------------------------------------------------------------- /Python/BST_To_Greater_Tree.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST. 3 | #Solution: Traverse reverse in order, keep count of sums and adjust each node as needed 4 | #Difficulty: Easy 5 | #Note: Due to Python scoping restrictions, var s needs to be in a class to be accessed by a recusive function 6 | 7 | class Solution(object): 8 | sumCount = 0 9 | def convertBST(self, root): 10 | #Recursive helper to traverse reverse in order 11 | def reverseInOrder(r): 12 | #Go to right-most element 13 | if r.right: reverseInOrder(r.right) 14 | #Set its value to be the current sum, and update current sum to be its (old) value 15 | r.val, self.sumCount = r.val + self.sumCount, self.sumCount + r.val 16 | #Go to left node if exists 17 | if r.left: reverseInOrder(r.left) 18 | #Run recursive helper 19 | reverseInOrder(root) 20 | #Return root because alorithm is in-place 21 | return root 22 | 23 | def main(): 24 | t = TreeNode(5) 25 | t.left = TreeNode(2) 26 | t.right = TreeNode(13) 27 | x = Solution() 28 | print(t.printInOrder(t)) 29 | main() 30 | -------------------------------------------------------------------------------- /Python/BST_Univalue.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given the root node of a tree, determine if the tree is univalued (ie all nodes have the same value) 3 | #Solution: Use recursion to compare every node in the tree with the value of the root node 4 | #Difficulty: Easy 5 | #Time Complexity: O(n) 6 | #Space Complexity: O(n) 7 | 8 | def isUnivalTree(self, root): 9 | #If out root node is null, return True becuse it is univalue 10 | if not root: return True 11 | #Define our recursive helper function 12 | def univalue(root, val): 13 | #If the root is null, return true 14 | if not root: return True 15 | #If the roots value is not equal to the value that was passed in, return False 16 | if root.val != val: return False 17 | #Return a recursive call on the left and right node, this ensures every single node will be visited 18 | return univalue(root.left, val) and univalue(root.right, val) 19 | return univalue(root, root.val) -------------------------------------------------------------------------------- /Python/BT_Flatten_To.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | self.prev = None 3 | def flatten(self, root): 4 | """ 5 | :type root: TreeNode 6 | :rtype: void Do not return anything, modify root in-place instead. 7 | """ 8 | if not root: return None 9 | self.flatten(root.right) 10 | self.flatten(root.left) 11 | root.right = self.prev 12 | root.left = None 13 | self.prev = root -------------------------------------------------------------------------------- /Python/BT_Inorder_Traversal.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given the root node of a tree, traverse it in order and return it as a list 3 | #Solution: Run a DFS, keep going left if it exists, add node to list, keep going right if it exists 4 | #Difficulty: Easy 5 | 6 | #First method, go left and right if children exist 7 | def inOrder(root, order=[]): 8 | #If the left child of the current node exists, run the function on the left child 9 | if root.left: inOrder(root.left, order) 10 | #Add the current node to our list, note this would first happen when we have gone to the leftmost child (ie the smallest) 11 | order.append(root.val) 12 | #Run the function on the right child if it exists 13 | if root.right: inOrder(root.right, order) 14 | #Return our list 15 | return order 16 | 17 | #Second method, go left and right always, keep a check at the top if root exists 18 | def inOrder2(root, order=[]): 19 | if not root: return 20 | inOrder2(root.left, order) 21 | order.append(root.val) 22 | inOrder2(root.right, order) 23 | return order 24 | 25 | #Third method, iteratively traverse using a stack and a pointer 26 | def inorder3(root): 27 | order, stack = [], [] 28 | #As long as the stack is not empty OR the pointer to the current node is not null 29 | while stack or root: 30 | #If the pointer to the current node is non-null 31 | if root: 32 | #Append the current (non-null) node to the stack and move left 33 | stack += [root] 34 | root = root.left 35 | #If the pointer to the current node is null, we must have reached the leftmost item in the current stack, so start popping 36 | else: 37 | #Save the popped node into a temporary one and add it's value to our order result 38 | temp = stack.pop() 39 | order += [temp.val] 40 | #Move our current pointer to its right child 41 | root = temp.right 42 | return order 43 | 44 | 45 | 46 | 47 | 48 | def main(): 49 | a = TreeNode(5) 50 | a.left = TreeNode(3) 51 | a.left.right = TreeNode(4) 52 | a.right = TreeNode(7) 53 | a.right.right = TreeNode(12) 54 | 55 | print(inOrder(a)) 56 | print(inOrder2(a)) 57 | print(inorder3(a)) 58 | main() -------------------------------------------------------------------------------- /Python/BT_Lowest_Common_Ancestor.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Find the lowest common ancestor of two nodes 3 | #Solution: Use a recursive approach to look for both nodes, return null, left or right at each recrusive level 4 | #Difficulty: Easy 5 | #Time Complexity: O(n) 6 | 7 | def LCA(root, p, q): 8 | #If we have found p or q to be the root, or the root is null, return the root 9 | if not root or root == p or root == q: return root 10 | #Recursively travel left and then right until we find p or q or null 11 | left = LCA(root.left, p, q) 12 | right = LCA(root.right, p, q) 13 | #Return the root if we both left and right aren't null, else return the one thats not null 14 | return root if left and right else left or right 15 | 16 | def main(): 17 | a = TreeNode(6) 18 | a.left = TreeNode(4) 19 | a.left.left = TreeNode(3) 20 | a.left.right = TreeNode(5) 21 | a.right = TreeNode(7) 22 | 23 | p = a.left.left 24 | q = a.left.right 25 | 26 | print(LCA(a, p, q).val) 27 | 28 | main() -------------------------------------------------------------------------------- /Python/Best_Time_to_Buy_and_Sell_Stock.py: -------------------------------------------------------------------------------- 1 | # Question: Given a list of stock prices each day, determine the most profit you could make buying and selling the stock once 2 | # Solution: Loop through finding the minimum price each time, and then the max profit. This works because the profit will be negative on days where the stock goes down 3 | # Difficulty: Easy 4 | # Time Complexity: O(n) 5 | # Space Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def maxProfit(prices: List[int]) -> int: 10 | # Initialize lowestPrice to MAX_INT and mostProfit to be 0 11 | lowestPrice, mostProfit = float('inf'), 0 12 | 13 | for i, price in enumerate(prices): 14 | # In each loop determing the lowest price, and the max profit by subtracting the current price by the lowest known one 15 | lowestPrice = min(lowestPrice, price) 16 | mostProfit = max(price - lowestPrice, mostProfit) 17 | 18 | return mostProfit 19 | 20 | -------------------------------------------------------------------------------- /Python/Binary_Search_Tree_to_Greater_Sum_Tree.py: -------------------------------------------------------------------------------- 1 | # Question: Given the root of a binary search tree with distinct values, modify it so that every node has a new value equal to the sum of the values of the original tree that are greater than or equal to node.val. 2 | # Solution: Do a reverse in order traversal and keep track of the sum 3 | 4 | def bstToGst(self, root: TreeNode) -> TreeNode: 5 | x = 0 6 | 7 | def revInOrder(root): 8 | nonlocal x 9 | if not root: return 10 | 11 | revInOrder(root.right) 12 | root.val += x 13 | x = root.val 14 | revInOrder(root.left) 15 | 16 | revInOrder(root) 17 | return root -------------------------------------------------------------------------------- /Python/Binary_Tree_Inorder_Traversal.py: -------------------------------------------------------------------------------- 1 | # Question: Given the root node of a tree, traverse it in order and return it as a list 2 | # Solution: Keep track of nodes through a stack and a pointer to the root 3 | # Difficulty: Easy 4 | 5 | def inorderTraversal(root: TreeNode) -> List[int]: 6 | stack = [] 7 | order = [] 8 | 9 | # As long as we have either something in the stack or a non null node 10 | while root or stack: 11 | 12 | # As long as the roots not null, keep going to the left child 13 | while root: 14 | stack += [root] 15 | root = root.left 16 | 17 | # Get the top node in the stack and pop it, this node is in order 18 | # so append its value to our results 19 | root = stack.pop() 20 | order += [root.val] 21 | 22 | # Now move the current root to the right 23 | root = root.right -------------------------------------------------------------------------------- /Python/Binary_Tree_Level_Order_Traversal.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Traverse a tree level by level 3 | #Solution: Typical Breadth First Search (BFS) 4 | #Difficulty: Easy 5 | 6 | def levelOrder(root): 7 | #Return empty list if the root node is null 8 | if not root: return [] 9 | #vaiable to hold final result, queue of nodes and current level of tree 10 | order, queue, nextQueue = [], [root], [] 11 | #While the queue is not empty 12 | while queue: 13 | #For every node in the queue 14 | for node in range(len(queue)): 15 | #If that node has a left child, append to current list, then same for right child 16 | if queue[node].left: nextQueue += [queue[node].left] 17 | if queue[node].right: nextQueue += [queue[node].right] 18 | #Now we append the current queue to the order (the lambda is just there to turn the TreeNode objects to their values) 19 | order += [list(map(lambda x: x.val, queue))] 20 | queue, nextQueue = nextQueue, [] 21 | return order 22 | 23 | def main(): 24 | tree = TreeNode(6) 25 | tree.left = TreeNode(3) 26 | tree.right = TreeNode(12) 27 | tree.left.right = TreeNode(4) 28 | tree.right.right = TreeNode(14) 29 | 30 | print(levelOrder(tree)) 31 | 32 | main() 33 | -------------------------------------------------------------------------------- /Python/Binary_Tree_Maximum_Path_Sum.py: -------------------------------------------------------------------------------- 1 | def maxPathSum(root: TreeNode) -> int: 2 | maxSum = float('-inf') 3 | 4 | def maxChildrenSum(root): 5 | nonlocal maxSum 6 | 7 | # If we land on a null node we can return 0 safely because 8 | # we know that it will not contribute to the sum of the root 9 | if not root: return 0 10 | 11 | # Now we need to compute the sums of the left and right children 12 | # if the sums of either children is less than 0 we know it'll drag down the total 13 | # sum of our path, so we can just omit that child and take 0 instead of it's sum 14 | left = max(maxChildrenSum(root.left), 0) 15 | right = max(maxChildrenSum(root.right), 0) 16 | 17 | # If the path we just computed (ie the path with the current node as root) happens to 18 | # have a bigger sum than the biggest one we've seen, it becomes our new biggest 19 | maxSum = max(maxSum, left + root.val + right) 20 | 21 | # We return the sum of our current node plus the biggest gain on left or the right 22 | # we don't take both the left and right sums because we are looking for an end to 23 | # end path and so cannot traverse down both subtrees 24 | return root.val + max(left, right) 25 | 26 | maxChildrenSum(root) 27 | return maxSum -------------------------------------------------------------------------------- /Python/Binary_Tree_Zig_Zag_Traversal.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Traverse a tree level by level in a zig zag order 3 | #Solution: Typical Breadth First Search (BFS) but keep track of zigzag 4 | #Difficulty: Medium 5 | 6 | def zigzagLevelOrder(root): 7 | #If the root is null, return an empty list 8 | if not root: return [] 9 | #Create variables r (result), q (queue), and c (current queue) 10 | r, q, c = [[]], [root], [] 11 | #Keep track of if we're going left or right in our zigzag traversal 12 | zig = False 13 | #As long as the queue is not empty 14 | while q: 15 | #For each item in the queue 16 | for i in q: 17 | #Append item to the end of the result list 18 | r[-1] += [i.val] 19 | #If left and right children exist, add them to current queue in order of left to right 20 | if i.left: c += [i.left] 21 | if i.right: c += [i.right] 22 | #Reset queue to current queue and current queue to an empty list 23 | q, c = c, [] 24 | #If we're going right to left, reverse the last item in our results list 25 | if zig: 26 | r[-1] = r[-1][::-1] 27 | #Negate out boolen so we go the opposite direction next time 28 | zig = not zig 29 | #If our queue still is non null, add an empty list to our result because we sill have entries to fill 30 | if q: r += [[]] 31 | return r -------------------------------------------------------------------------------- /Python/Bubble_Sort.py: -------------------------------------------------------------------------------- 1 | def checkSort(l): 2 | for i in range(len(l) - 1): 3 | if(l[i] > l[i + 1]): 4 | return False 5 | return True 6 | 7 | def sortBubble(inputList): 8 | while(not checkSort(inputList)): 9 | for i in range(len(inputList) - 1): 10 | if(inputList[i] > inputList[i + 1]): 11 | temp = inputList[i] 12 | inputList[i] = inputList[i + 1] 13 | inputList[i + 1] = temp 14 | return(inputList) 15 | 16 | a = [7, 8, 3, 4, 2, 1, 0] 17 | sortBubble(a) 18 | print(a) 19 | -------------------------------------------------------------------------------- /Python/Climbing_Stairs.py: -------------------------------------------------------------------------------- 1 | #Question: Given a number of stairs to climb, you can climb it by taking 2 steps or 1 at a time, return the number of possible combinations you could climb them. 2 | #Solution: Each stair depends on the number of ways you can climb the previous + number of ways you can count the 2nd previous step 3 | #Difficulty: Easy 4 | 5 | def climbStairs(n): 6 | #Initialize a array to hold the number of combinations at each step, initialize step 0 and step 1 to 1 because they only have 1 combination (no steps and 1 step) 7 | prevSteps = [0] * (n + 1); prevSteps[0] = 1; prevSteps[1] = 1 8 | #For each step starting from step 2 up to the last one 9 | for i in range(2, n + 1): 10 | #The steps combination is equivalent to the combinations possible at step - 1 + step - 2 11 | prevSteps[i] = prevSteps[i - 2] + prevSteps[i - 1] 12 | #Return the combinations at the last step 13 | return prevSteps[-1] -------------------------------------------------------------------------------- /Python/Closest_Binary_Search_Tree_Value.py: -------------------------------------------------------------------------------- 1 | # Question: Find the closest element to a given target in a tree 2 | # Solution: Conduct a simple BST search but update the closest whenever the absloute difference is smaller 3 | # Difficulty: Easy 4 | 5 | def closestValue(root: TreeNode, target: float) -> int: 6 | 7 | # Initialize closest to infinity so its greater than any node 8 | closest = float('inf') 9 | 10 | while root: 11 | 12 | # Every time we come across a node that has a smaller absloute difference than our 13 | # target, we update closest with that nodes value 14 | if abs(closest - target) > abs(root.val - target): 15 | closest = root.val 16 | 17 | # Go to the left child if the current node is greater than the target, otherwise the right child 18 | root = root.left if root.val > target else root.right 19 | 20 | return closest -------------------------------------------------------------------------------- /Python/Coin_Change.py: -------------------------------------------------------------------------------- 1 | #Question: Given a set of coins to chose from, and a target amount, find the number of different combinations you can have to make that amount 2 | #Solution: Dynamic Programming solution (DP) 3 | #Difficulty: Medium 4 | 5 | def coinChange(amount, coins): 6 | #Create a memoized store of the counts of combinations of the previous amount 7 | store = [0] * (amount + 1) 8 | #Let the count of combinations that sum to 0 be 1 (Since only no coins can sum to 0) 9 | store[0] = 1 10 | #For each coin in coins 11 | for coin in coins: 12 | #For each amount in the store 13 | for j in range(len(store)): 14 | #If the amount is greater than the coin in hand then increment the amount by the combinations that're at the amount which is this current amount - the coins value 15 | if(j >= coin): store[j] += store[j-coin] 16 | print(store) 17 | return store[-1] 18 | 19 | 20 | print(coinChange(3, [1, 2])) -------------------------------------------------------------------------------- /Python/Combination_Sum.py: -------------------------------------------------------------------------------- 1 | def combinationSum(candidates, target): 2 | """ 3 | :type candidates: List[int] 4 | :type target: int 5 | :rtype: List[List[int]] 6 | """ 7 | #Firstly we sort the candidates so we can keep track of our progression 8 | candidates = sorted(candidates) 9 | 10 | def backTrack(left, current, results): 11 | #Our base case is when nothing is left, in which case we add the current solution to the results 12 | if not left: 13 | results += [current] 14 | return 15 | 16 | #Now we address all candidates 17 | for number in candidates: 18 | 19 | #If the number is greater than whats left over, we can break this loop, and in turn the recursio 20 | if number > left: break 21 | 22 | #This (along with the sorted candidates) ensures uniqueness because if the number we're at is less than the last number in the curent solution, we can skip it over 23 | if current and number < current[-1]: continue 24 | 25 | #In the case that this number is smaller than whats left over, we continue backtracking 26 | backTrack(left - number, current + [number], results) 27 | 28 | #We can return results in the higest function call 29 | return results 30 | 31 | return backTrack(target, [], []) -------------------------------------------------------------------------------- /Python/Compare_Version_Numbers.py: -------------------------------------------------------------------------------- 1 | #Question: Given two version numbers determine which one is greater 2 | #Solution: Split by the "."s and loop through both and compare 3 | #Difficulty: Easy 4 | 5 | def compareVersion(version1, version2): 6 | #Split each version number by the . (For example: 3.14 -> [3, 14]) 7 | v1 = version1.split(".") 8 | v2 = version2.split(".") 9 | 10 | #Keep a difference index, we'll use it to compare indexes in out version lists 11 | i = 0 12 | #As long as i is less than the length of both versions 13 | while i < len(v1) and i < len(v2): 14 | #If version1[i] is greater than or less than version2[i] return 1 or -1 respectively 15 | if int(v1[i]) > int(v2[i]): return 1 16 | elif int(v1[i]) < int(v2[i]): return -1 17 | i += 1 18 | #If i is less than the len of version1 or version 2 return 1 (or -1) if the last item in version1/2 is 0, otherwise return 0 19 | if i < len(v1): return 1 if int(v1[-1]) != 0 else 0 20 | if i < len(v2): return -1 if int(v2[-1]) != 0 else 0 21 | return 0 22 | -------------------------------------------------------------------------------- /Python/Connect_Next_Pointer_Tree.py: -------------------------------------------------------------------------------- 1 | #Question: 2 | def connect(self, root): 3 | if not root: return None 4 | q, c, head = [root], [], root 5 | while q: 6 | for i, v in enumerate(q): 7 | v.next = q[i + 1] if i + 1 < len(q) else None 8 | if v.left: c += [v.left] 9 | if v.right: c += [v.right] 10 | q, c = c, [] 11 | print([v.val for v in q]) 12 | 13 | -------------------------------------------------------------------------------- /Python/Connected_Components_In_Undirected_Graph.py: -------------------------------------------------------------------------------- 1 | def countComponents(n, edges): 2 | """ 3 | :type n: int 4 | :type edges: List[List[int]] 5 | :rtype: int 6 | """ 7 | parents = list(range(n)) 8 | def find(x, parents): 9 | return x if parents[x] == x else find(parents[x], parents) 10 | for x, y in edges: 11 | x, y = find(x, parents), find(y, parents) 12 | parents[x] = y 13 | count = 0 14 | for i in range(len(parents)): count += 1 if parents[i] == i else 0 15 | return count -------------------------------------------------------------------------------- /Python/Count_Inversions.py: -------------------------------------------------------------------------------- 1 | def countInversions(nums): 2 | #Our recursive base case, if our list is of size 1 we know there's no inversion and that it's already sorted 3 | if len(nums) == 1: return nums, 0 4 | 5 | #We run our function recursively on it's left and right halves 6 | left, leftInversions = countInversions(nums[:len(nums) // 2]) 7 | right, rightInversions = countInversions(nums[len(nums) // 2:]) 8 | 9 | #Initialize our inversions variable to be the number of inversions in each half 10 | inversions = leftInversions + rightInversions 11 | 12 | #Initialize a list to hold our sorted result list 13 | sortedNums = [] 14 | 15 | i = j = 0 16 | #Here we count the inversions that exist between the two halves -- while sorting them at the same time 17 | while i < len(left) and j < len(right): 18 | if left[i] < right[j]: 19 | sortedNums += [left[i]]; i += 1 20 | else: 21 | sortedNums += [right[j]]; j += 1 22 | 23 | #Since we know that 'left' is sorted, once we reach an item in 'left' thats bigger than something in right that item and everything to it's right-hand side must be an inversion! 24 | #This line right here is exactly what shrinks the time of this algorithm from n^2 to nlogn as it means we don't need to compare every single pair 25 | inversions += len(left) - i 26 | 27 | #Once we've exhausted either left or right, we can just add the other one onto our sortedNums list 28 | sortedNums += left[i:] + right[j:] 29 | 30 | return sortedNums, inversions 31 | 32 | 33 | def main(): 34 | nums = [1, 5, 4, 8, 10, 2, 6, 9] 35 | print(countInversions(nums)) 36 | 37 | main() -------------------------------------------------------------------------------- /Python/Course_Schedule.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of course prerequisites, determine if it is possible to complete all the courses 2 | #Solution: Determine if the graph has a Cycle 3 | 4 | def canFinish(numCourses, prerequisites): 5 | """ 6 | :type numCourses: int 7 | :type prerequisites: List[List[int]] 8 | :rtype: bool 9 | """ 10 | if not prerequisites: return True 11 | graph = {i:[] for i in list(range(numCourses))} 12 | for x, y in prerequisites: graph[y] += [x] 13 | def depthFirst(current, unvisited, visiting, completelyVisited, graph): 14 | visiting.add(current); unvisited.remove(current) 15 | for neighbor in graph[current]: 16 | if neighbor in completelyVisited: continue 17 | if neighbor in visiting: return True 18 | if depthFirst(neighbor, unvisited, visiting, completelyVisited, graph): return True 19 | completelyVisited.add(current); visiting.remove(current) 20 | return False 21 | 22 | unvisited = list(range(numCourses)) 23 | visiting = set() 24 | completelyVisited = set() 25 | while unvisited: 26 | currentNode = unvisited[0] 27 | if depthFirst(currentNode, unvisited, visiting, completelyVisited, graph): return False 28 | return True -------------------------------------------------------------------------------- /Python/Course_Schedule_II.py: -------------------------------------------------------------------------------- 1 | # Question(#210): Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses. 2 | # Difficulty: Medium 3 | # What do I learn from this question? How to implement a general topological sort with cycle checking 4 | 5 | def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: 6 | 7 | # Construct the graph by creating a map where each course maps to a list of its prereqs 8 | graph = {course: [] for course in range(numCourses)} 9 | for a, b in prerequisites: graph[a] += [b] 10 | 11 | def depthFirst(course, visiting): 12 | nonlocal order, graph, visited 13 | 14 | # If we've fully visited the course before we can skip it, if we were visiting it 15 | # and have come across it again then we know there was a cycle, so return False 16 | if course in visited: return True 17 | if course in visiting: return False 18 | 19 | # This is where the DFS starts, so we indicate we are now visiting the current node 20 | visiting.add(course) 21 | 22 | # For every course in the prereq of the current course, we conduct a DFS again, returning 23 | # false if our DFS detects a cycle 24 | for prereq in graph[course]: 25 | if not depthFirst(prereq, visiting): return False 26 | 27 | # We now add the current course to visited, indicating we've traversed all it's prereqs 28 | # We also add the current course to order, because the first time we reach here in our 29 | # recursion stack will be when we reach a course with no prerequisutes 30 | visited.add(course) 31 | order += [course] 32 | return True 33 | 34 | visited, order = set(), [] 35 | 36 | # Run our DFS on every node in the graph, since our DFS actually returns a boolean 37 | # we can embed cycle checking in the DFS itself and based on that return an empty list 38 | # if a cycle exists in the graph 39 | for course in graph: 40 | if not (depthFirst(course, set())): return [] 41 | 42 | return order 43 | -------------------------------------------------------------------------------- /Python/Cycle_In_DAG.py: -------------------------------------------------------------------------------- 1 | def hasCycle(edges, numEdges): 2 | #Initialize a graph that stores the neighbor of each node 3 | graph = {i:[] for i in list(range(numEdges))} 4 | #Populate the graph so that the 'children' of each node are stored with the parent as the key 5 | for x, y in edges: graph[x] += [y] 6 | #Create three sets, one to store all unvisited nodes, one to store nodes curently visiting, one to store completely visited ones 7 | unvisited = list(range(numEdges)) 8 | visiting = set() 9 | completelyVisited = set() 10 | 11 | #While we still have nodes that are unvisited 12 | while unvisited: 13 | #We graph a random node from the unvisited collection to run a DFS on 14 | currentNode = unvisited[0] 15 | #If a call to the depth first seach returns true then we know this graph has a cycle and can return true 16 | if depthFirstSearch(currentNode, unvisited, visiting, completelyVisited, graph): return True 17 | #If no call to the depth first search returns true then we can return False that there is no cycle in this graph 18 | return False 19 | 20 | #Define our helper depth first search for a cycle 21 | def depthFirstSearch(currentNode, unvisited, visiting, completelyVisited, graph): 22 | #Firstly, we need to move the current node we're at from unvisited and to visiting 23 | unvisited.remove(currentNode) 24 | visiting.add(currentNode) 25 | #Now for each of this nodes adjacent neighbors we need to run this DFS again 26 | for neighbor in graph[currentNode]: 27 | #If that neighbor has already been completely visited, we can skip tis particular neighbor 28 | if neighbor in completelyVisited: continue 29 | #If this neighbor is already a node we're visiting then return true that this has a cycle! Because we've circled back to a parent node 30 | if neighbor in visiting: return True 31 | #If any its neighbors have a cycle return true as well 32 | if depthFirstSearch(neighbor, unvisited, visiting, completelyVisited, graph): return True 33 | #Finally remove this current node from visiting and add it to completely visited 34 | visiting.remove(currentNode) 35 | completelyVisited.add(currentNode) 36 | 37 | def main(): 38 | print(hasCycle([[1, 0], [0, 2]], 3)) 39 | 40 | main() -------------------------------------------------------------------------------- /Python/Decode_String.py: -------------------------------------------------------------------------------- 1 | # Question (#394): Given an encoded string, return its decoded string. 2 | # Solution: Use a stack and keep track of the last string you've built so far 3 | 4 | def decodeString(s: str) -> str: 5 | # Contains the string we're adding to and the number we want to multiply the current string by 6 | stack = [] 7 | num, string = 0, '' 8 | 9 | for char in s: 10 | # Every time we see an opening bracket, we know we need to start a new computation, so we push our current string and 11 | # the number we've seen so far to the stack and reset it 12 | if char == '[': 13 | stack += [num, string] 14 | num, string = 0, '' 15 | # When we see a closing bracket we know something can be decoded, so we take the last string we had 16 | # and add it to the current string * the number of times we want to expand it 17 | elif char == ']': 18 | string = stack.pop() + stack.pop() * string 19 | elif char.isdigit(): 20 | num = num * 10 + int(char) 21 | else: 22 | string += char 23 | return string -------------------------------------------------------------------------------- /Python/Decode_Ways.py: -------------------------------------------------------------------------------- 1 | #Question: Given a decoding for each letter in the alphabet (A-> 1, ... Z-> 26) determine the number of ways a given string of digits could be interpereted 2 | #Solution: Recursively compute all possibilities using dynamic programming 3 | #Difficulty: Medium 4 | 5 | def numDecodings(s, l, store): 6 | 7 | #Set the index we're starting from to be the length of the string - the length we're at 8 | startIndex = len(s) - l 9 | 10 | #Recursive base cases -- If the length we're at is 0 return 1 (for 1 possibility) 11 | if(l == 0): return 1 12 | #If s starts with a 0 then it's invalid 13 | if(s[startIndex] == '0'): return 0 14 | #If we're already computed the possibilites at index l, return it 15 | if(store[l]): return store[l] 16 | 17 | #Recursively compute the number of decodings by subtracting 1 from the length 18 | res = numDecodings(s, l - 1, store) 19 | 20 | #Recursively compute the number of decodings by subtracting 2 from the length and also cecking if those 2 numbers are <= 26 21 | if(l >= 2 and int(s[startIndex] + s[startIndex + 1]) <= 26): res += numDecodings(s, l - 2, store) 22 | 23 | #Store the result in our dynamic programs array 24 | store[l] = res 25 | 26 | #Return the result 27 | return res 28 | 29 | def main(): 30 | data = '12' 31 | print(numDecodings(data, len(data), [None] * (len(data) + 1))) 32 | main() 33 | -------------------------------------------------------------------------------- /Python/Delete_Node_From_Linked_List.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import ListNode 2 | #Question: Given ta node in a linked list, delete it 3 | #Solution: Copy next value into current node and let next be nexts next 4 | #Difficulty: Easy 5 | 6 | def deleteNode(node): 7 | #Set the current nodes value to the value of the next node 8 | node.val = node.next.val 9 | #Set the current nodes next property to the next nodes next, esspentially 'deleting' the original next node 10 | node.next = node.next.next -------------------------------------------------------------------------------- /Python/Delete_Nodes_And_Return_Forest.py: -------------------------------------------------------------------------------- 1 | # Question (#1110): Given the root of a binary tree, After deleting all nodes with a value in to_delete, we are left with a forest (a disjoint union of trees). 2 | # Return the roots of the trees in the remaining forest. You may return the result in any order. 3 | # Solution: Recursively traverse through the tree and keep track of parents, after deleting a node, a given node is the head of the forest 4 | # if it has no parent node. 5 | 6 | def delNodes(root: TreeNode, to_delete: List[int]) -> List[TreeNode]: 7 | 8 | # Our recursive helper function 9 | def delNode(root, parent, to_delete, forest): 10 | # If we get to a None node, return None 11 | if not root: return root 12 | 13 | # If the current node is one we want to delete, we need to traverse down it's subtrees 14 | # and delete other nodes before we delete this one. Once we have finished our recursion, 15 | # delete the current node by returning None to its parent. 16 | if root.val in to_delete: 17 | # Set it's left and right nodes to be recursive calls to our helper, we need to set the parent in our 18 | # recursive call to None as the current Node will be deleted and will no longer be a parent. 19 | root.left = delNode(root.left, None, to_delete, forest) 20 | root.right = delNode(root.right, None, to_delete, forest) 21 | return None 22 | 23 | # Otherwise, if we don't want to delete this node, recursively call our helper in it's subtrees 24 | root.left = delNode(root.left, root, to_delete, forest) 25 | root.right = delNode(root.right, root, to_delete, forest) 26 | 27 | #Finally, if the node we're currently at has no parent, then add it to our forest 28 | if not parent: forest += [root] 29 | return root 30 | 31 | forest = [] 32 | delNode(root, None, to_delete, forest) 33 | return forest -------------------------------------------------------------------------------- /Python/Delete_Operation_for_Two_Strings.py: -------------------------------------------------------------------------------- 1 | # Question: Given two strings find the minimum number of letters you need to delete from each to get the same strings 2 | # Solution: Implement a top down or bottom up DP 3 | # Difficulty: Medium 4 | 5 | def minDistance(w1: str, w2: str, store={}) -> int: 6 | # Our base cases are, if both strings are the same (this includes when they're both null) return 0 because nothing needs to be 7 | # deleted, if only one of them is non-null, then return the length of it since everything needs to be deleted 8 | if w1 == w2: return 0 9 | if not w1 or not w2: return len(w1 or w2) 10 | 11 | # If we have this pair of words in our store then just return the deletion distance from that 12 | if (w1,w2) in store: return store[(w1,w2)] 13 | 14 | # If both words start with the same letter, nothing needs to be deleted, so just rerun the function 15 | # on the substrings with the first character removed, otherwise try deleting the first letter from each word 16 | # and seeing which one results in the shorter deletion distance 17 | if w1[0] == w2[0]: 18 | edit = self.minDistance(w1[1:], w2[1:], store) 19 | else: 20 | edit = 1 + min(self.minDistance(w1[1:], w2, store), self.minDistance(w1, w2[1:], store)) 21 | 22 | # Once the computation is completed, store 23 | store[(w1,w2)] = edit 24 | return edit -------------------------------------------------------------------------------- /Python/Diagonal_Traverse.py: -------------------------------------------------------------------------------- 1 | inp = [ 2 | [ 1, 2, 3 ], 3 | [ 4, 5, 6 ], 4 | [ 7, 8, 9 ] 5 | ] 6 | 7 | def diagonal(matrix): 8 | direction = "R" 9 | traversal = [] 10 | x = y = 0 11 | for i in range(len(matrix[0]) * len(matrix)): 12 | if(direction == "R"): 13 | traversal += [matrix[x][y]] 14 | y += 1 15 | 16 | -------------------------------------------------------------------------------- /Python/Distance_To_Node.py: -------------------------------------------------------------------------------- 1 | 2 | def distance(nodes, pointFrom, pointTo): 3 | graph = {i:[] for i in list(set([n for m in nodes for n in m]))} 4 | for x, y in nodes: graph[x] += [y]; graph[y] += [x] 5 | 6 | queue, currentQueue, visited = [pointFrom], [], [] 7 | 8 | count = 1 9 | 10 | while queue: 11 | for node in queue: 12 | visited += [node] 13 | currentQueue += [adjacentNode for adjacentNode in graph[node] if adjacentNode not in visited] 14 | if pointTo in currentQueue: return count 15 | count += 1 16 | queue, currentQueue = currentQueue, [] 17 | 18 | return count 19 | 20 | print(distance([['A', 'B'], ['C', 'F'], ['B', 'F']], 'A', 'C')) -------------------------------------------------------------------------------- /Python/Edit_Distance.py: -------------------------------------------------------------------------------- 1 | # Question: Give 2 | # Solution: Track the offset of the inner level of the spiral we're at, keep track of the directions 3 | # Difficulty: Medium 4 | 5 | def minDistance(self, word1: str, word2: str, store={}) -> int: 6 | # We have 3 base cases, if both words are the same (including null) return 0 as nothing needs to be changed, 7 | # if of the words is null, return the length of the other one. Lastly, if we've seen this combination of words before, 8 | # return the distance we already computed 9 | if word1 == word2: return 0 10 | if not word1 or not word2: return len(word1 or word2) 11 | if (word1, word2) in store: return store[(word1, word2)] 12 | 13 | # If both words start with the same letter, we dont need to edit, so recursively call the function on the substrings without the first character 14 | if word1[0] == word2[0]: return self.minDistance(word1[1:], word2[1:]) 15 | 16 | # The trick here is to realize that even though we can insert any letter, it only makes sense to insert a characher present in the other 17 | # word, we could go ahead and try inserting all characters from the other word but we can also realize that insertion is actually the same as deletion. 18 | # If we have two words fog and frog, we clearly need to insert an r (eventually), firstly we delete both f's, we then get the strings og and rog, now we could insert 19 | # r infront of og, or we could simply remove the r in rog and pretend like we actually inserted the r in og and deleted both letters since they became the same! 20 | 21 | # We also need to realize that replacing letters is actually the same as deleting them both, or both of them being the same, so we do the same thing as 22 | # we did in the case where the words started with the same letters, for example to change cat to bat, we would need to replace the c to a b, but this is the same thing 23 | # as removing the c and the b (adding 1) and then comparing the strings at and at. 24 | insert = 1 + self.minDistance(word1, word2[1:]) 25 | delete = 1 + self.minDistance(word1[1:], word2) 26 | replace = 1 + self.minDistance(word1[1:], word2[1:]) 27 | 28 | store[(word1, word2)] = min(insert, delete, replace) 29 | 30 | return min(insert, delete, replace) -------------------------------------------------------------------------------- /Python/Find_First_and_Last_Position_of_Element_in_Sorted_Array.py: -------------------------------------------------------------------------------- 1 | # Question: Given a sorted array, find the first and last indices of a target number 2 | # Solution: Run two (lower bounded) binary searches, one for the target number and one 3 | # for the successor of the target (the next natural number after the targer number) 4 | # Difficulty: Medium 5 | 6 | def searchRange(nums: List[int], target: int) -> List[int]: 7 | 8 | def lowerBin(nums, target): 9 | l, r = 0, len(nums) - 1 10 | 11 | # Note: setting this while statement to be <= and not just != means it can also 12 | # catch cases when the input is an empty array, as l = 0 and r = -1 in that case 13 | while l <= r: 14 | 15 | # In each iteration set the midpoint to half the difference of the left 16 | # and right pointers offset by the left pointer 17 | mid = (r - l) // 2 + l 18 | 19 | # This binary search always returns the lower bound on a number because 20 | # if the current number is less than target it shifts left to the next number to the right of mid, 21 | # and if the number is greater than or equal to the target it shifts right to the number to the left of mid 22 | # this ensures that if numbers are duplicated the search will always narrow into the leftmost number 23 | if nums[mid] < target: l = mid + 1 24 | else: r = mid - 1 25 | return l 26 | 27 | # This simply finds the index of the lowest target 28 | lowerIndex = lower(nums, target) 29 | 30 | # This finds the index of the first number larger than the target, and then subtracts 31 | # one from the index it finds which is going to be the rightmost target 32 | upperIndex = lower(nums, target + 1) - 1 33 | 34 | # If we didn't go out of bounds in our search and if the number at the lowerIndex actually equals our 35 | # target (because our binary search will return the next largest number if it didn't exist) we can return the indices 36 | if lowerIndex < len(nums) and nums[lowerIndex] == target: 37 | return [lowerIndex, upperIndex] 38 | else: return [-1, -1] -------------------------------------------------------------------------------- /Python/Find_Pivot_Index.py: -------------------------------------------------------------------------------- 1 | # Question: Find the index of the element in the list such that 2 | # the sum of elements to its left equals the sum of elements to its right 3 | # Difficulty: Easy 4 | # Solution: Store the sum of the left side and right side and adjust each loop and check 5 | # Space Complexity: O(1) 6 | # Time Complexity: O(n) 7 | 8 | from typing import List 9 | 10 | def pivotIndex(self, nums: List[int]) -> int: 11 | leftSum = 0 12 | rightSum = sum(nums) 13 | 14 | for i, v in enumerate(nums): 15 | rightSum -= v 16 | if leftSum == rightSum: return i 17 | leftSum += v 18 | 19 | return -1 20 | 21 | -------------------------------------------------------------------------------- /Python/First_Missing_Positive.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of ints, find the smallest missing positive number 2 | #Solution: Sort the list as you go through by placing every term on its index + 1th place. 3 | #Difficulty: Hard 4 | #Time Complexity: O(n) 5 | #Space Complexity: O(1) 6 | 7 | from typing import List 8 | 9 | def firstMissingPositive(nums: List[int]) -> int: 10 | i, j = 0, len(nums) 11 | while i < j: 12 | 13 | #If the current number is equal to its index + 1, skip over as its already sorted 14 | #for example if the number 5 is in the 4th index/ 5th place 15 | if nums[i] == i+1: i += 1 16 | 17 | #Regular case, ie a number not in the correct place 18 | #In othe words, if a number n is within our range and the number in the nth position isnt equal to this number, swap the two 19 | elif nums[i] > 0 and nums[i] <= j and nums[nums[i]-1] != nums[i]: 20 | nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1] 21 | 22 | #Case if the number is a duplicate, or out of our range (1 to j). So place it at the end 23 | else: 24 | j -= 1 25 | nums[j], nums[i] = nums[i], nums[j] 26 | 27 | return j + 1 28 | 29 | def main(): 30 | print(firstMissingPositive([1, 5, 4, 3, 2, 7, 0])) 31 | 32 | main() -------------------------------------------------------------------------------- /Python/First_Unique_Char.py: -------------------------------------------------------------------------------- 1 | # Question: Given a string, find the first character that is unique 2 | # Solution: Count the occurance of each letter, find the first letter with 1 occurance from your hashmap 3 | # because we don't want to loop over our input string twice if it's very long 4 | # Difficulty: Easy 5 | 6 | def firstUniqChar(s: str) -> int: 7 | # Create a hashmap to store the counts of each letter as well as the index 8 | letterCounts = {} 9 | 10 | # Store the lowest index we see with a letter count of 1 when we traverse our hashmap 11 | smallestIndex = len(s) 12 | 13 | # Store each items count as well as the first index it occured at 14 | for i, v in enumerate(s): 15 | getChar = letterCounts.get(v, [0, i]) 16 | letterCounts[v] = (getChar[0] + 1, getChar[1]) 17 | 18 | # Loop through the hashmap updating the smallestIndex each time we see a letter 19 | # with a count of 1 and a smaller index than the previous 20 | for i, v in enumerate(letterCounts): 21 | if letterCounts[v][0] == 1: 22 | smallestIndex = min(smallestIndex, letterCounts[v][1]) 23 | 24 | # Return either the index of the first char or -1 if there is no unique char 25 | return smallestIndex if smallestIndex != len(s) else -1 26 | -------------------------------------------------------------------------------- /Python/Flip_And_Invert_Image.py: -------------------------------------------------------------------------------- 1 | def flipAndInvertImage(self, A): 2 | return list(map(lambda x: [0 if i == 1 else 1 for i in x], list(map(lambda x: x[::-1], A)))) -------------------------------------------------------------------------------- /Python/Flood_Fill.py: -------------------------------------------------------------------------------- 1 | #Question: Given a image (2D list), a x and y coordinate of a pixel, and a new color, flood fill all neigbboring pixels with the same color to the new color 2 | #Solution: Run a DFS on the input pixel 3 | #Difficulty: Easy 4 | 5 | from typing import List 6 | def floodFill(image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: 7 | 8 | #If the pixel at the given coordinates is already the new color, return the image 9 | if image[sr][sc] == newColor: return image 10 | 11 | #Define a recursive DFS to help us flood fill 12 | def dfs(i, j, newColor, oldColor, image): 13 | 14 | #If the coordinates passed are not out of bounds and the color is the same as the previous one 15 | if i >= 0 and j >= 0 and i < len(image) and j < len(image[0]) and image[i][j] == oldColor: 16 | 17 | #Set the pixel at the given coordinates to the new color 18 | image[i][j] = newColor 19 | 20 | #Recursively repeat on the pixel left, right, above and below 21 | dfs(i + 1, j, newColor, oldColor, image) 22 | dfs(i - 1, j, newColor, oldColor, image) 23 | dfs(i, j + 1, newColor, oldColor, image) 24 | dfs(i, j - 1, newColor, oldColor, image) 25 | 26 | #Call our DFS function on the original inputs 27 | dfs(sr, sc, newColor, image[sr][sc], image) 28 | return image 29 | 30 | def main(): 31 | print(floodFill([[0,0,0],[0,1,1]], 0, 0, 6)) 32 | 33 | main() -------------------------------------------------------------------------------- /Python/Generate_Paranthesis.py: -------------------------------------------------------------------------------- 1 | #Question: Generate all possible pairs of parenthesis for a given number n 2 | #Solution: Recursive backtracking, keep count of left brackets and right brackets 3 | #Difficulty: Medium 4 | 5 | def generateParenthesis(n): 6 | """ 7 | :type n: int 8 | :rtype: List[str] 9 | """ 10 | results = [] 11 | def helper(results, string, leftCount, rightCount): 12 | #If we've reached the base case where no more brackets can be added, append the current string to our array 13 | if not leftCount and not rightCount: results += [string] 14 | #If there are still left brackers to be added, add left bracket and recall function with 1 less left bracket but 1 more right bracket (Since we've opened a new bracket that needs to be closed) 15 | if leftCount: helper(results, string + "(", leftCount-1, rightCount+1) 16 | #If there are right brackets that need to be added, add 1 then recall function with 1 less right bracket 17 | if rightCount: helper(results, string + ")", leftCount, rightCount-1) 18 | #Call initially with empty array, empty string, n left brackets and no right brackets 19 | helper(results, "", n, 0) 20 | return results -------------------------------------------------------------------------------- /Python/Graph_Is_Tree.py: -------------------------------------------------------------------------------- 1 | #Question: Given the number of nodes in a graph and the edges, determing if the graph is also a tree 2 | #Solution: Determine if the graph has any clycles in it (using union-find), if it does, it can't be a tree 3 | #Difficulty: Medium 4 | 5 | def validTree(n, edges): 6 | #Create a list where each item is the parent of itself 7 | parent = list(range(n)) 8 | #Helper function to find the greatest parent of a node 9 | def findParent(x): 10 | #If the node is it's own parent return itself, otherwise find parent of parent[node] 11 | return x if parent[x] is x else findParent(parent[x]) 12 | for edge in edges: 13 | #x is parent of edge_from y is parent of edge_to 14 | x, y = findParent(edge[0]), findParent(edge[1]) 15 | #If both the edge_from and edge_to have the same parent they create a cycle that goes from edge_from to parent to edge_to, so the graph can't be a tree 16 | if x is y: return False 17 | #Otherwise set the parent of the edge_from to be edge_to, note you could also do this the other way around 18 | parent[x] = y 19 | #Make sure that number of edges is 1 less than number of nodes to ensure nothing is in a cycle, and no less, otherwise there will be multiple trees 20 | #(Because if we had 2 nodes and 2 edges, there would be a cycle, so ensure there is no cycle the number of edges is 1 less than the number of nodes) 21 | return len(edges) == n - 1 22 | 23 | def main(): 24 | a = [[0,1], [0,2], [0,3], [1,4]] 25 | an = 5 26 | 27 | b = [[0,1], [1,2], [2,3], [1,3], [1,4]] 28 | bn = 5 29 | 30 | print(validTree(an, a)) 31 | print(validTree(bn, b)) 32 | main() -------------------------------------------------------------------------------- /Python/Hamming_Distance.py: -------------------------------------------------------------------------------- 1 | #Question: Find the difference between the bits of two numbers 2 | #Solution: XOR the two numbers (Creates a new number with 1s in place of the differences), then find hamming weight (See Hamming_Weight.py) 3 | #Difficulty: Easy 4 | 5 | def hammingDistance(x, y): 6 | #Simply XOR the two numbers and count the hamming weight 7 | n, c = x ^ y, 0 8 | while n: 9 | c += 1 if n & 1 else 0 10 | n >>= 1 11 | return c -------------------------------------------------------------------------------- /Python/Hamming_Weight.py: -------------------------------------------------------------------------------- 1 | #Question: Find the number of 1s in the binary representation of a number 2 | #Solution: Keep counting last bit and bitshifting by 1 3 | #Difficulty: Easy 4 | 5 | def hammingWeight(self, n): 6 | #Variable to count the weight 7 | c = 0 8 | #While number is not null (ie 0) 9 | while n: 10 | #Increment c by 1 if last bit of number is 1 (Check last bit by doing bitwise AND with 1) 11 | c += 1 if n & 1 else 0 12 | #Right shift number by 1 bit (essentially, delete rightmost bit) 13 | n >>= 1 14 | return c -------------------------------------------------------------------------------- /Python/Happy_Number.py: -------------------------------------------------------------------------------- 1 | # Question: See https://leetcode.com/problems/happy-number/ 2 | # Difficulty: Easy 3 | # Solution: Maintain a set of already seen numbers and loop 4 | # Space Complexity: O(n) 5 | # Time Complexity: O(n) 6 | 7 | 8 | def isHappy(n: int) -> bool: 9 | seen = set() 10 | while n != 1: 11 | seen.add(n) 12 | n = sum(map(lambda x: int(x) ** 2, list(str(n)))) 13 | if n in seen: 14 | return False 15 | return True 16 | 17 | 18 | def main(): 19 | print(isHappy(19)) 20 | 21 | 22 | main() 23 | -------------------------------------------------------------------------------- /Python/Has_Path_Sum.py: -------------------------------------------------------------------------------- 1 | #Question: Given a trees root, and a number, determine if any path in that tree sums to the given number 2 | #Solution: 3 | 4 | def hasPathSum(root, sum): 5 | #Keep track of all the sums 6 | sums = [] 7 | #Define a helper that takes into account the sum of the current path 8 | def helper(root, pathSum, sums): 9 | #If our node is null return nothing 10 | if not root: return 11 | #If the node is a leaf child, we have reached a sum path, append the current sum to the sums list 12 | if not root.left and not root.right: sums.append(pathSum + root.val) 13 | #If the left or right children exist, then recursively go into them and update the current paths sum with their values 14 | if root.left: helper(root.left, pathSum + root.val, sums) 15 | if root.right: helper(root.right, pathSum + root.val, sums) 16 | #Run the helper function on th given root with the given sum 17 | helper(root, 0, sums) 18 | #Return true if the given sum exists in our sums list, else return false 19 | return sum in sums 20 | -------------------------------------------------------------------------------- /Python/Increasing_Triplet_Subsequence.py: -------------------------------------------------------------------------------- 1 | #Question: Given an array of numbers, determine if a triplet that is increasing exists (doesn't need to be continious) 2 | #Solution: Keep track of first, second and third largest numbers 3 | #Difficulty: Medium 4 | #Complexity: O(N) 5 | 6 | def increasingTriplet(nums): 7 | #Keep track of the first largest, and second largest numbers, where second <= first 8 | first = second = float('inf') 9 | for i, v in enumerate(nums): 10 | #If the current number is less than or equal to the first largest number, set first to it 11 | if v <= first: first = v 12 | #Otherwise if its not less than the first largest number, but less than the second largest, set second to that 13 | elif v <= second: second = v 14 | else: return True 15 | return False 16 | -------------------------------------------------------------------------------- /Python/Insert_into_a_Binary_Search_Tree.py: -------------------------------------------------------------------------------- 1 | def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: 2 | original = root 3 | 4 | last = None 5 | while root: 6 | last = root 7 | if root.val > val: root = root.left 8 | else: root = root.right 9 | 10 | if last.val > val: last.left = TreeNode(val) 11 | else: last.right = TreeNode(val) 12 | 13 | return original -------------------------------------------------------------------------------- /Python/Insertion_Sort.py: -------------------------------------------------------------------------------- 1 | #Insertion sort implementation in Python 2 | def sortInsert(inputList): 3 | print(inputList) 4 | #Start from second item (because first item is already inserted correctly) 5 | for i in range(1, len(inputList)): 6 | j = i 7 | #As long as the item before is larger than the current item 8 | while(j > 0 and inputList[j] < inputList[j - 1]): 9 | #print("Iteration: ", inputList) 10 | #Save current item as temp 11 | temp = inputList[j] 12 | #Change current item to previous item 13 | inputList[j] = inputList[j - 1] 14 | #Change previous item to saved temp item 15 | inputList[j-1] = temp 16 | #Decrement i 17 | j = j - 1 18 | return inputList 19 | 20 | 21 | a = [7, 8, 3, 4, 2, 1, 0] 22 | sortInsert(a) 23 | print(a) 24 | -------------------------------------------------------------------------------- /Python/Intersection_of_Linked_Lists.py: -------------------------------------------------------------------------------- 1 | def getIntersectionNode(headA, headB): 2 | #Save heads of a and b 3 | a, b = headA, headB 4 | #As long as both aren't equal (they'll be equal if the have an intersection 5 | # of if they both reach the end of the linked list) 6 | while a != b: 7 | #Swap the values if they've become null, else move onto next value 8 | a = headB if not a else a.next 9 | b = headA if not b else b.next 10 | return a -------------------------------------------------------------------------------- /Python/Invert_Binary_Tree.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given a Binary Search Tree, swap all mirrored nodes 3 | #Solution: Recursively swap all pairs of mirroring nodes 4 | #Difficulty: Easy 5 | 6 | def invertTree(root): 7 | #If root is null return null 8 | if not root: return None 9 | #Let the left and right children be recursive calls to right and left children respectively 10 | root.right, root.left = invertTree(root.left), invertTree(root.right) 11 | #return current root 12 | return root 13 | 14 | def main(): 15 | a = TreeNode(4) 16 | a.left = TreeNode(3) 17 | a.right = TreeNode(5) 18 | print(invertTree(TreeNode(None))) 19 | print(invertTree(a).right) 20 | main() -------------------------------------------------------------------------------- /Python/K_Closest_Elements.py: -------------------------------------------------------------------------------- 1 | def findClosestElements(arr, k, x): 2 | """ 3 | :type arr: List[int] 4 | :type k: int 5 | :type x: int 6 | :rtype: List[int] 7 | """ 8 | #Set left and right pointers, right is k less than len 9 | left, right = 0, len(arr) - k 10 | #As long as left is less than right 11 | while left < right: 12 | #Find the mid point of left and right 13 | mid = (left + right) // 2 14 | #If the mid point less targer is greater than 15 | if (x - arr[mid]) > (arr[mid + k] - x): 16 | left = mid + 1 17 | else: 18 | right = mid 19 | return arr[left:left + k] 20 | 21 | def insertSorted(arr, x): 22 | i = 0 23 | while i < len(arr): 24 | if arr[i] >= x: 25 | arr.insert(i, x) 26 | return arr 27 | i += 1 28 | return arr + [x] 29 | 30 | print(findClosestElements([1, 2, 3, 4, 5, 6], 2, 3)) 31 | print(insertSorted([1, 2, 3, 4, 5], 0.4)) -------------------------------------------------------------------------------- /Python/K_Diff_Unique_Pairs.py: -------------------------------------------------------------------------------- 1 | def findPairs(self, nums, k): 2 | if k < 0 or not nums: return 0 3 | lookingFor = {}; pairs = 0 4 | for i in range(len(nums)): 5 | lookingFor[nums[i]] = lookingFor.get(nums[i], 0) + 1 6 | for i in lookingFor: 7 | if k == 0: 8 | if lookingFor[i] > 1: 9 | pairs += 1 10 | else: 11 | if k + i in lookingFor: 12 | pairs += 1 13 | return pairs -------------------------------------------------------------------------------- /Python/K_difference_pairs.py: -------------------------------------------------------------------------------- 1 | def kpairs(nums, k): 2 | lookingFor = {} 3 | pairs = 0 4 | for i, v in enumerate(nums): 5 | if v + k in lookingFor: 6 | pairs += lookingFor[v + k] 7 | if v - k in lookingFor: 8 | pairs += lookingFor[v - k] 9 | if v in lookingFor: 10 | lookingFor[v] += 1 11 | else: 12 | lookingFor[v] = 1 13 | return pairs 14 | 15 | def kk(nums, k): 16 | lookingFor = {}; pairs = 0 17 | for i, v in enumerate(nums): 18 | lookingFor[v] = lookingFor.get(v, 0) + 1 19 | for i in lookingFor: 20 | if (i + k) in lookingFor: pairs += 1; print("pair ", i+k, i) 21 | print(lookingFor, 'look') 22 | return pairs 23 | 24 | def main(): 25 | nums = [1, 3, 6, 8, 5] 26 | #print(kk(nums, 2)) 27 | 28 | print(kk([8, 12, 16, 4, 0, 0, 20], 4)) 29 | 30 | main() -------------------------------------------------------------------------------- /Python/Kth_Largest_Element.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kumailn/Algorithms/e6be0a0cbf0caf13a723a9edfd2df33c2234235f/Python/Kth_Largest_Element.py -------------------------------------------------------------------------------- /Python/Kth_Smallest_Element_BST.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | a = 0; result = None 3 | def kthSmallest(self, root, k): 4 | self.a = k 5 | def rec(r): 6 | if r.left: rec(r.left) 7 | self.a -= 1 8 | if not self.a: self.result = r.val; return 9 | if r.right: rec(r.right) 10 | rec(root) 11 | return self.result 12 | 13 | 14 | -------------------------------------------------------------------------------- /Python/Kth_Smallest_Element_in_a_BST.py: -------------------------------------------------------------------------------- 1 | 2 | # Question: Given the root node of a tree, find the nth smallest element in the tree 3 | # Solution: Traverse in order iteratively and keep track of the nth smallest element 4 | # Difficulty: Easy 5 | 6 | 7 | def kthSmallest(self, root: TreeNode, k: int) -> int: 8 | stack = [] 9 | val = None 10 | 11 | # Iterative in order travesal, keep track of K 12 | while (stack or root) and k != 0: 13 | while root: 14 | stack += [root] 15 | root = root.left 16 | 17 | # Every time we pop something from the stack we know that it's ordered 18 | # so subtract 1 from k and set out value to be that nodes value 19 | root = stack.pop() 20 | k -= 1 21 | val = root.val 22 | 23 | # Shift node to its right child normally 24 | root = root.right 25 | 26 | return val -------------------------------------------------------------------------------- /Python/LRU_Cache.py: -------------------------------------------------------------------------------- 1 | # Question: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. 2 | # Difficulty: Hard 3 | 4 | 5 | class LRUCache: 6 | def __init__(self, capacity: int): 7 | self.hash = {} 8 | self.cap = capacity 9 | self.head = Node(0, 0) 10 | self.tail = Node(0, 0) 11 | self.head.next = self.tail 12 | self.tail.prev = self.head 13 | 14 | def get(self, key: int) -> int: 15 | if key in self.hash: 16 | node = self.hash[key] 17 | self.remove(node) 18 | self.add(node) 19 | return node.val 20 | return -1 21 | 22 | def put(self, key: int, value: int) -> None: 23 | if key in self.hash: 24 | self.remove(self.hash[key]) 25 | node = Node(key, value) 26 | self.add(node) 27 | self.hash[key] = node 28 | if len(self.hash) > self.cap: 29 | oldest = self.head.next 30 | self.remove(oldest) 31 | del self.hash[oldest.key] 32 | 33 | def remove(self, node): 34 | prev = node.prev 35 | nxt = node.next 36 | prev.next = nxt 37 | nxt.prev = prev 38 | 39 | def add(self, node): 40 | beforeTail = self.tail.prev 41 | beforeTail.next = node 42 | self.tail.prev = node 43 | node.prev = beforeTail 44 | node.next = self.tail 45 | 46 | 47 | class Node: 48 | def __init__(self, k, x, n=None, m=None): 49 | self.key = k 50 | self.val = x 51 | self.next = n 52 | self.prev = m 53 | -------------------------------------------------------------------------------- /Python/Least_Num_Squares.py: -------------------------------------------------------------------------------- 1 | # def leastNumSquares(num): 2 | # #Because of Lagrange's four square theorem, the max number can be 4 3 | # if(isSquare(num)): 4 | # return 1 5 | # # If num is not in the form of 4^k*(8*m + 7), due to Legendres theorem 6 | # while(n % 4 = 0): 7 | 8 | 9 | 10 | def leastNumSquares(num): 11 | if(num <= 0): 12 | return 0 13 | elif(isSquare(num)): 14 | return 1 15 | l = [i for i in range(num + 1)] 16 | sqrs = [i**2 for i in range(1, int(num ** 0.5) + 1)] 17 | for i in l: 18 | for j in sqrs: 19 | if(i - j < 0): 20 | break 21 | l[i] = min(l[i], l[i - j] + 1) 22 | return l[-1] 23 | 24 | 25 | def leastNumSquaresv2(num): 26 | if (num <= 0): 27 | return 0 28 | perfectSqCounts = [1] 29 | while len(perfectSqCounts) <= num: 30 | currentNum = len(perfectSqCounts) 31 | currentSquareCount = 4 32 | for i in range(1, currentNum + 1): 33 | print(i, currentNum) 34 | currentSquareCount = min(currentSquareCount, perfectSqCounts[currentNum - (i ** 2)] + 1) 35 | perfectSqCounts += [currentSquareCount] 36 | return perfectSqCounts[-1] 37 | 38 | def isSquare(num): 39 | return (num ** 0.5) * (num ** 0.5) == num 40 | 41 | print(leastNumSquaresv2(12)) -------------------------------------------------------------------------------- /Python/Letter_Combinations_of_a_Phone_Number.py: -------------------------------------------------------------------------------- 1 | #Question: Given a number, find all the possible combinations you could make with it using a traditional cellphone keyboard 2 | #Solution: Use backtracking 3 | 4 | def letterCombinations(digits): 5 | digits = str(digits) 6 | #Keep track of all the possible comibnations we can make 7 | possibleCombinations = [] 8 | #If we have no number, return our list 9 | if not digits: return possibleCombinations 10 | #Define a dictionary that maps a number to the letters on the keypad 11 | keypad = {1: " ", 2: "abc", 3: "def", 4: "ghi", 5: "jkl", 6: "mno", 7: "pqrs", 8: "tuv", 9: "wxyz"} 12 | #Define a recursive helper that backtracks to find possible combinations 13 | def r(digitsString, currentResultString): 14 | #If we've reached a digit string of null, we can append our constructed result to our result list 15 | if not digitsString: possibleCombinations.append(currentResultString) 16 | else: 17 | #For every letter in the possible letters of the first letter of the digitstring 18 | for i in keypad[int(digitsString[0])]: 19 | #Recall the recursive helper on the digitstring but without the first number, and the result string but with the mapped letter 20 | r(digitsString[1:], currentResultString + (i if i != " " else "")) 21 | #Run our helper initially on the original number, and an empry result string 22 | r(digits, "") 23 | return possibleCombinations 24 | 25 | def main(): 26 | print(letterCombinations(321)) 27 | 28 | main() -------------------------------------------------------------------------------- /Python/Longest_Common_Prefix.py: -------------------------------------------------------------------------------- 1 | def longestCommonPrefix(strs): 2 | """ 3 | :type strs: List[str] 4 | :rtype: str 5 | """ 6 | for (string in strs): 7 | for i in range(len(string)[::-1]: 8 | 9 | if(string[:i] in ) 10 | 11 | 12 | 13 | print(longestCommonPrefix(["flower","flow","flight"])) -------------------------------------------------------------------------------- /Python/Longest_Common_Subsequence.py: -------------------------------------------------------------------------------- 1 | # Question(#1143): Given two strings text1 and text2, return the length of their longest common subsequence. 2 | # Solution: Use the longest common susequence dynamic programming algorithm 3 | 4 | def longestCommonSubsequence(text1: str, text2: str) -> int: 5 | grid = [[0 for _ in range(len(text2)+1)] for _ in range(len(text1)+1)] 6 | 7 | for i in range(1, len(text1)+1): 8 | for j in range(1, len(text2)+1): 9 | if text1[i-1] == text2[j-1]: 10 | grid[i][j] = 1 + grid[i-1][j-1] 11 | else: 12 | grid[i][j] = max(grid[i][j-1], grid[i-1][j]) 13 | 14 | return grid[-1][-1] -------------------------------------------------------------------------------- /Python/Longest_Consecutive_Sequence.py: -------------------------------------------------------------------------------- 1 | # Question(#128): Given an unsorted array of integers, find the length of the longest consecutive elements sequence. 2 | # Difficulty: Hard 3 | 4 | 5 | def longestConsecutive(self, nums: List[int]) -> int: 6 | # Turn nums into a set so lookups happen in constant time 7 | nums = set(nums) 8 | longest = 0 9 | 10 | for a in nums: 11 | # If a smaller number does not exist, we know this is the smallest in 12 | # the potential sequence of consecutive elements and we can just check for larger nums 13 | if a - 1 not in nums: 14 | b = a + 1 15 | # As long as a number 1 greater exists, we can keep checking for the next 16 | # consecutive element in the set, longest will then just be the max of the distances 17 | while b in nums: 18 | b += 1 19 | longest = max(longest, b - a) 20 | 21 | return longest 22 | -------------------------------------------------------------------------------- /Python/Longest_Palindrome.py: -------------------------------------------------------------------------------- 1 | #Question: Given a string, find the longest palindrome you can construct using its letters 2 | #Solution: Add together all counts of letters, if an odd count exists then add count - 1 otherwise count, return 1 + total if an odd existed because it can be used in the middle. 3 | #Difficulty: Easy 4 | 5 | def longestPalindrome(s): 6 | #Dictionary to keep count of each character 7 | counts = {} 8 | #Total count to return 9 | count = 0 10 | #Bool to remember if an odd count of numbers is found 11 | oddFound = False 12 | #Count each character, store in dictionary 13 | for i, v in enumerate(s): 14 | counts[v] = counts.get(v, 0) + 1 15 | #For every character we counted 16 | for char in counts: 17 | #If it occurs an odd number of times set oddFound flag to true 18 | if counts[char] % 2 == 1: oddFound = True 19 | #Increase total by occurence of current letter if its count is even, otherwise subtract 1 from its occurance 20 | count += counts[char] if counts[char] % 2 == 0 else counts[char] - 1 21 | return count + 1 if oddFound else count 22 | -------------------------------------------------------------------------------- /Python/Longest_Palindrome_Substring.py: -------------------------------------------------------------------------------- 1 | #Question: Given a string, find the longest palindrome in it 2 | #Difficulty: Iterate through each element and determine if its a palindrome 3 | #Difficulty: Easy 4 | 5 | def longestPalindrome(s): 6 | #Keep track of largest palindrome found so far 7 | gmax = "" 8 | #Helper function to find the longest palindrome given a left starting index and a right starting index 9 | def checkPal(s, l, r): 10 | #As long as l >= 0 and r is less than length of the string and the items at s and l are equal 11 | while l >= 0 and r < len(s) and s[l] == s[r]: 12 | l -= 1; r += 1 13 | #Return s[l+1:r] because the while loop will exit after it is done one extra decrement of l, (ie s[l] != s[r] anymore), and up to r because python list slicing goes up to but not including 14 | return s[l + 1: r] 15 | #For each index in s 16 | for i in range(len(s)): 17 | #Check the palindrome as an odd palindrome, so where both l and r are equal, and as an even length palindrome 18 | o, e = checkPal(s, i, i), checkPal(s, i, i + 1) 19 | #Set gmax to the longest palindrome found 20 | if len(o) > len(gmax): gmax = o 21 | if len(e) > len(gmax): gmax = e 22 | return gmax -------------------------------------------------------------------------------- /Python/Longest_Substring_Without_Repeating_Characters.py: -------------------------------------------------------------------------------- 1 | # Question: Given a string find the largest substring that consists of only unique characters 2 | # Solution: Store the last seen position of letters in a hashmap 3 | # Difficulty: Medium 4 | 5 | def lengthOfLongestSubstring(s: str) -> int: 6 | # We initialize each letter to -1 indicating we haven't seen it yet 7 | lastSeen = {v: -1 for v in s} 8 | 9 | # We start from -1 to handle the edge case where the string has length 1 10 | # because if length was one we woule compute longest as i - start (0 - 0) and return 0 11 | # instead of returning 1 12 | start, longest = -1, 0 13 | 14 | for i, v in enumerate(s): 15 | 16 | # If the letter was seen after the starting index of our current 17 | # index, then set the new start to be the letter 18 | start = max(start, lastSeen[v]) 19 | lastSeen[v] = i 20 | longest = max(longest, i - start) 21 | return longest 22 | -------------------------------------------------------------------------------- /Python/Longest_Substring_with_At_Most_Two_Distinct_Characters.py: -------------------------------------------------------------------------------- 1 | def longest(substr): 2 | i, j = 0, -1 3 | maxlen = 0 4 | for k in range(1, len(substr)): 5 | if substr[k] == substr[k-1]: continue 6 | if j > -1 and substr[k] != substr[j]: 7 | maxlen = max(maxlen, k - i) 8 | i = j -------------------------------------------------------------------------------- /Python/Longest_unique_substring.py: -------------------------------------------------------------------------------- 1 | #Question: Given a string find the largest substring that consists of only unique characters 2 | #Solution: Modified Kadanes algorithm 3 | #Difficulty: Medium 4 | 5 | def lengthOfLongestSubstring(s): 6 | #Trivial case 7 | if not s: return 0 8 | #Let global max and global min the first item 9 | cmax, gmax = [s[0]], [s[0]] 10 | #For i in range from the second element to last, since 0th item is already in cmax and gmax 11 | for i in range(1, len(s)): 12 | #If element is not in the current max, then append 13 | if s[i] not in cmax: cmax += [s[i]] 14 | #Otherwise, delete everything in current max up to (but not including) the current element, and append the current element 15 | else: cmax = cmax[cmax.index(s[i]) + 1:] + [s[i]] 16 | #If current max is greater than global max, set global to current 17 | if len(cmax) > len(gmax): gmax = cmax 18 | return len(gmax) 19 | 20 | 21 | #More compact 22 | def lengthOfLongestSubstring2(s): 23 | """ 24 | :type s: str 25 | :rtype: int 26 | """ 27 | cmax = gmax = [s[0]] if s else [] 28 | for i in range(1, len(s)): 29 | cmax = cmax + [s[i]] if s[i] not in cmax else cmax[cmax.index(s[i]) + 1:] + [s[i]] 30 | if len(cmax) > len(gmax): gmax = cmax 31 | return len(gmax) -------------------------------------------------------------------------------- /Python/Majority_Element.py: -------------------------------------------------------------------------------- 1 | #Question: Given a set of elements, determine what the majority element (occuring more than 50% of the time) if it exists is. You cannot count elements, the only operation available is inputting two items into a tester to check if they're the same or not. 2 | #Solution: Divide like mergesort and pass back majority elements up the recussion tree 3 | #Difficulty: Medium 4 | 5 | import random 6 | from _DATATYPES import equivalenceTester 7 | 8 | def majorityElement(items): 9 | tester = equivalenceTester() 10 | 11 | #Base cases, if there's 1 item left then it is the majority element! If there's two we can see if they're the same using the tester and return that 12 | if len(items) == 1: return items[0] 13 | if len(items) == 2: return tester.test(items[0], items[1]) 14 | 15 | #Divide the list of items into a left and a right half 16 | set2 = items[len(items)//2:] 17 | set1 = items[:len(items)//2] 18 | 19 | #Recurse on the left and right halves 20 | item1 = majorityElement(set1) 21 | item2 = majorityElement(set2) 22 | 23 | #Once item1 and item2 have been returned up the recursion tree we count the number of occurances of each 24 | countLeft = countRight = 0 25 | for i in items: 26 | if tester.test(item1, i): countLeft += 1 27 | if tester.test(item2, i): countRight += 1 28 | 29 | #Result1 is set to item1 if item1's count is >= half the items, likewise for result2. Otherwise it's not a majority element and we set it to None 30 | result1 = item1 if countLeft >= len(items) // 2 else None 31 | result2 = item2 if countRight >= len(items) // 2 else None 32 | 33 | #Return either of the two, whichever is non-null 34 | return result1 or result2 35 | 36 | 37 | def main(): 38 | items = ['A', 'B', 'B', 'B', 'C'] 39 | random.shuffle(items) 40 | 41 | #Should return 'B' as that occurs more than half the time 42 | print(majorityElement(items)) 43 | 44 | main() 45 | -------------------------------------------------------------------------------- /Python/Maximum_Length_of_Repeated_Subarray.py: -------------------------------------------------------------------------------- 1 | # Question(#718): Given two integer arrays A and B, return the maximum length of an subarray that appears in both arrays. 2 | # Solution: Use the longest common substring algorithm and optimize it to use only O(N) space 3 | # Difficulty: Medium 4 | 5 | def findLength(A: List[int], B: List[int]) -> int: 6 | # Keep track of the last row of each letter 7 | last = [0 for _ in range(len(B)+1)] 8 | maxlen = 0 9 | 10 | for i in range(1, len(A)+1): 11 | # Current represents the current row, we only really need two rows at any given time to compute our solution 12 | current = [0 for _ in range(len(A)+1)] 13 | for j in range(1, len(B)+1): 14 | # If the elements are equal then the longest subarray must be the longest subarray we see if we remove both elements 15 | # for example [1, 2, 3] and [0, 2, 3], if we're at index 2 in each array then the longest subarray if both elements at index 2 16 | # are the same is the longest subarray at index 1. 17 | if A[i-1] == B[j-1]: 18 | current[j] = 1 + last[j-1] 19 | # Keep track of the max since we might lose it as we're clearing our current row each time 20 | maxlen = max(maxlen, current[j]) 21 | last = current 22 | return maxlen -------------------------------------------------------------------------------- /Python/Maximum_Product_Subarray.py: -------------------------------------------------------------------------------- 1 | def maxprod(arr): 2 | currentMax = globalMax = arr[0] 3 | for i in range(1, len(arr)): 4 | currentMax = max(arr[i], arr[i] * currentMax) 5 | if(currentMax > globalMax): 6 | print(arr[i], currentMax, globalMax) 7 | globalMax = currentMax 8 | return globalMax 9 | 10 | print(maxprod([2,3,-2,4])) -------------------------------------------------------------------------------- /Python/Maximum_Size_Subarray_Sum_Equals_k.py: -------------------------------------------------------------------------------- 1 | #Question: Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isn't one, return 0 instead. 2 | #Solution: Keep a hashmap of sums up to that point 3 | #Difficulty: Medium 4 | #Space Complexity: O(n) 5 | #Time Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def maxSubArrayLen(nums: List[int], k: int): 10 | #Initialize values for the max sub-array itself and it's value 11 | answer, accumulator = [], 0 12 | 13 | #Create a hashmap with keys being sums and values indexes, sum at index -1 is 0 14 | #This is important because if the accumulator sums to 0 at any point we can use this 0 and include all numbers from the beginning 15 | sumMap = {0: -1} 16 | 17 | for i, v in enumerate(nums): 18 | #Increment the accumulator by the number in the array 19 | accumulator += v 20 | 21 | #If we haven't previously encountered this number, add it to hashmap with index i 22 | if accumulator not in sumMap: sumMap[accumulator] = i 23 | 24 | #If the accumulator - the k we're looking for happens to be in our map 25 | #This is because accumulator - (accumulator - k) = k. In other words the accumulator up to this point, subtracted by the (accumulator-k) must be k 26 | if accumulator - k in sumMap: 27 | 28 | #If the length of k is greater than the length of our answer, because k spans from index at sum accumulator - k to index at i (from the above comment) 29 | if (i - sumMap[accumulator - k]) > len(answer): 30 | 31 | #Set answer to be the subarray starting from the inde of the sum (accumulator-k) to i inclusively 32 | #We want the starting point to be non-inclusive of the last item in the sum (accumulator-k) because we need to subtract this sum completely... 33 | #..from the current accumulator in order to obtain k. (Since accumulator - (accumulator - k) = k) 34 | answer = nums[sumMap[accumulator-k]+1:i+1] 35 | return answer 36 | 37 | 38 | def main(): 39 | print(maxSubArrayLen([1, 1, 2, 3, -1, 0, -1, 1, 2, 3], 5)) 40 | print(maxSubArrayLen([-2, -1, 2, 1, 9], 9)) 41 | main() -------------------------------------------------------------------------------- /Python/Maximum_Subarray.py: -------------------------------------------------------------------------------- 1 | # Question: Find the sum of a continuous subarray in an array with the largest sum 2 | # Solution: Kadane's algorithm (explained below) 3 | # Difficulty: Easy 4 | # Time Complexity: O(n) 5 | # Space Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def maxSubArray(nums: List[int]) -> int: 10 | # Initialize a store for the local and global maximum sumarrays 11 | localMax = globalMax = float('-inf') 12 | 13 | for i, v in enumerate(nums): 14 | # LocalMax becomes the larger of the current number or the current number + localMax itself 15 | localMax = max(v, v + localMax) 16 | 17 | # If localMax happens to become larger than globalMax, set globalMax to localMax 18 | if localMax > globalMax: globalMax = localMax 19 | return globalMax -------------------------------------------------------------------------------- /Python/Maximum_Sum_Subarray.py: -------------------------------------------------------------------------------- 1 | #Question: Find the sum of a continious subarray in an array with the largest sum 2 | #Solution: Kadanes algorithm (explained below) 3 | #Difficulty: Easy 4 | #Time Complexity: O(n) 5 | 6 | def maxSubArray(nums): 7 | """ 8 | :type nums: List[int] 9 | :rtype: int 10 | """ 11 | 12 | #Trivial case 13 | if not nums: return 0 14 | 15 | #Initialize a store for the local and global maximum sumarrays 16 | localMax = globalMax = nums[0] 17 | 18 | #Start looping through the numbers from index 1 because local and gloval are nums[0] 19 | for i in range(1, len(nums)): 20 | #LocalMax becomes the larger of the current number or the current number + localMax itself 21 | localMax = max(localMax + nums[i], nums[i]) 22 | 23 | #If localMax happens to become larger than globalMax, set globalMax to localMax 24 | if localMax > globalMax: 25 | globalMax = localMax 26 | 27 | return globalMax 28 | 29 | def main(): 30 | #Result should be 6 31 | print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4])) 32 | 33 | main() -------------------------------------------------------------------------------- /Python/Meeting_Rooms_II.py: -------------------------------------------------------------------------------- 1 | def minMeetingRooms(intervals: List[List[int]]) -> int: 2 | intervals = sorted(intervals, key=lambda x: x[0]) 3 | heap = [] 4 | for i in intervals: 5 | # We need a new room, when the heap is empty or when an interval overlaps 6 | # An interval overlaps (and thus requires a new room) if its start time is less 7 | # than the end time of the first item in the min-heap. We push the end time of the item to the heap. 8 | # In other words, if this meeting starts before our earliest meeting ends, we need another room. 9 | if not heap or i[0] < heap[0]: 10 | heapq.heappush(heap, i[1]) 11 | # If the item does not overlap, then we pop the first item in the heap (as it didn't overlap) 12 | # and push the current one 13 | else: 14 | heapq.heappop(heap) 15 | heapq.heappush(heap, i[1]) 16 | return len(heap) 17 | -------------------------------------------------------------------------------- /Python/Merge_Intervals.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of time intervals merge overpapping ones together, (ex. [1,3],[2,6] become [1, 6]) 2 | #Solution: Sort by start time then traverse intervals, setting each interval to be the [start first, max(end first, end second)] and deleteing the ocurrent one in-place 3 | #Difficulty: Medium 4 | 5 | def merge(intervals): 6 | """ 7 | :type intervals: List[List] 8 | :rtype: List[List] 9 | """ 10 | i = 0 11 | intervals = sorted(intervals, key=lambda x: x[0]) 12 | while i < len(intervals) - 1: 13 | if intervals[i][1] >= intervals[i + 1][0]: 14 | intervals[i] = [intervals[i][0], max(intervals[i+1][1], intervals[i][1])] 15 | del intervals[i + 1] 16 | else: i += 1 17 | return intervals -------------------------------------------------------------------------------- /Python/Merge_Linked_List.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import ListNode 2 | #Question: Given two sorted linked lists, join them 3 | #Solution: Traverse through both lists, swapping values to find smallest, then working backwards 4 | #Difficulty: Easy 5 | 6 | def mergeList(a, b): 7 | #If the first node is null, or the second node exists and is smaller than the first node, swap the two nodes 8 | #This ensures that a is always the smallest non null node 9 | if not a or b and a.val > b.val: a, b = b, a 10 | #If a is not null, then let its next value be a recursive call to its next value, and b (the smaller nodes next value will become the smaller of its current next value, or the other lists current value) 11 | if a: a.next = mergeList(a.next, b) 12 | #Return a's head as we never shifted a in this scope, only in subsequent recursive calls 13 | return a 14 | 15 | def main(): 16 | a = ListNode(4) 17 | a.next = ListNode(23) 18 | a.next.next = ListNode(44) 19 | 20 | b = ListNode(5) 21 | b.next = ListNode(11) 22 | b.next.next = ListNode(14) 23 | mergeList(b, a) 24 | 25 | print(a.printList()) 26 | main() -------------------------------------------------------------------------------- /Python/Merge_Sort.py: -------------------------------------------------------------------------------- 1 | def sortMerge(nums): 2 | #Our base case, if the list is 1 item long we can return itself because it's already sorted 3 | if len(nums) == 1: return nums 4 | 5 | #Recursively merge sort left and right lists 6 | left = sortMerge(nums[:len(nums) // 2]) 7 | right = sortMerge(nums[len(nums) // 2:]) 8 | 9 | sortedNums, i, j = [], 0, 0 10 | 11 | #While i and j are less than he lengths of each of their lists 12 | while i < len(left) and j < len(right): 13 | #Add the smaller item in the left list or right list and increment our counter 14 | if left[i] < right[j]: 15 | sortedNums += [left[i]]; i += 1 16 | else: 17 | sortedNums += [right[j]]; j += 1 18 | 19 | #Add the rest of the numbers as we've exhausted one of the lists 20 | sortedNums += left[i:] + right[j:] 21 | 22 | return sortedNums 23 | 24 | def main(): 25 | nums = [6, 7, 3, 2, 9, 3, 1, 0] 26 | print(sortMerge(nums)) 27 | 28 | main() -------------------------------------------------------------------------------- /Python/Merge_k_Sorted_Lists.py: -------------------------------------------------------------------------------- 1 | # Question (#23): 2 | # Solution: Use a heap! It'll track all heads of the various linked lists, and at any given 3 | # point you can poll for the smallest head and add that to your output linked list 4 | 5 | def mergeKLists(lists: List[ListNode]) -> ListNode: 6 | # Create a heap with all heads of our linkedlists, note the item we're storing in the heap 7 | # is a tuple of 3 items, the value of the head (this will help the heap store the smallest value), the index 8 | # of the head (this will help the heap distinuish heads if their values are the same in the heap), and the actual 9 | # node, this let's us access the rest of the linked list. 10 | heap = [(head.val, i, head) for i, head in enumerate(lists) if head] 11 | heapq.heapify(heap) 12 | 13 | origin = head = ListNode(None) 14 | 15 | while heap: 16 | # Pop off the smallest item in the heap (the node with the lowest value) 17 | v, i, node = heapq.heappop(heap) 18 | 19 | # If the node we just popped off has a next, then we need to put that back into 20 | # our heap, since it's a value we'll need later on 21 | if node.next: 22 | heapq.heappush(heap, (node.next.val, i, node.next)) 23 | 24 | # Append the node we popped off to our head and move on to the next 25 | head.next = node 26 | head = head.next 27 | 28 | return origin.next 29 | -------------------------------------------------------------------------------- /Python/Min_Tree_Path.py: -------------------------------------------------------------------------------- 1 | #Question: Given a tree (Not necessairly a BST), determing the shortest path of any complete branch, where the values of the node determine the path lengths 2 | # 3 | 4 | def get_cheapest_cost(rootNode): 5 | minval = float('inf') 6 | def helper(root, minval): 7 | if not root.children: return 0 8 | for i in root.children: 9 | val = i.cost + helper(i, minval) 10 | if val < minval: minval = val 11 | return minval 12 | return helper(rootNode, minval) -------------------------------------------------------------------------------- /Python/Minimum_Window_Substring.py: -------------------------------------------------------------------------------- 1 | # Question: Given a string and a list of target letters, find the shortest continious string that has all those letters 2 | # Solution/Pattern: The intuition here is to try and find the first substring that contains all letters and then try shrinking 3 | # it's left boundary until we lose a character that was required. We contntinue to do this for all characters in 4 | # the string, hence creating a 'sliding window' 5 | # Difficulty: Hard 6 | 7 | 8 | def minWindow(self, s: str, t: str) -> str: 9 | 10 | # Initialize the starting point of our starting window 11 | start = 0 12 | shortest = len(s) + 1 13 | # We store the count of each letter needed in a hashmap 14 | lookingFor = collections.Counter(t) 15 | # We also store the total number of chars we have left to find 16 | charsNeeded = len(t) 17 | shortestString = "" 18 | 19 | for end, v in enumerate(s): 20 | # If this char is one we were looking for (one that's present in our target) thenwe need 21 | # to decrement it's count by one indicating we've seen it. 22 | # After we've decremented the count we need to check if we've seen it enough times, if the the 23 | # count of the character is less than 0 that means that it's a extra char occuring more times than in t 24 | # However, if after decrementing we have a number greater than or equal to 0 then we can say this was one 25 | # of the targets we were lookingFor and decrement our chars needed count 26 | if v in lookingFor: 27 | lookingFor[v] -= 1 28 | if lookingFor[v] >= 0: charsNeeded -= 1 29 | 30 | # Now, if charsNeeded == 0, we can start shrinking our window from the left 31 | # since we don't need any more chars, we know the current string we have from start to end contains 32 | # all the characters present in our target, so we can check if it's length is less than the the one we currently have 33 | # if it's length is less, we update the min length we've found so far and then update the shortest string we've found 34 | # Every time we shrink the window we have to check if we're removing a character we actually needed and then update charsNeeded 35 | # if we removed a character that was required. Finally we shrink the window from the left by incrementing start 36 | while not charsNeeded: 37 | if shortest > end - start + 1: 38 | shortest = end - start + 1 39 | shortestString = s[start:end + 1] 40 | 41 | if s[start] in lookingFor: 42 | lookingFor[s[start]] += 1 43 | if lookingFor[s[start]] > 0: 44 | charsNeeded += 1 45 | start += 1 46 | return shortestString -------------------------------------------------------------------------------- /Python/Move_Zeroes.py: -------------------------------------------------------------------------------- 1 | # Question: Move 0s to the end of a list 2 | # Difficulty: Easy 3 | # Solution: Keep an index to place non zeros at and keep incrementing it each time you encounter a non zero 4 | # Space Complexity: O(1) 5 | # Time Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def moveZeroes(nums: List[int]) -> None: 10 | nonZeroIndex = 0 11 | 12 | for i, v in enumerate(nums): 13 | # If the element is not 0, swap it with the item at 'nonZeroIndex' and increment 'NnonZeroIndex' 14 | if v != 0: 15 | nums[i], nums[nonZeroIndex] = nums[nonZeroIndex], nums[i] 16 | nonZeroIndex += 1 17 | -------------------------------------------------------------------------------- /Python/Multiply_By_Others.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of numbers, multiply each number by all other numbers except itself 2 | #Solution: Traverse right then left while multiplying 3 | #Difficulty: Hard 4 | 5 | def multiplyRest(nums): 6 | #Create new list with 1s 7 | nums2 = [1 for i in nums] 8 | #Initialize the multiplier to 1 9 | multiplier = 1 10 | #Loop through to the right side 11 | for i in range(1, len(nums2)): 12 | #Let the multiplier be the product of itself the previous number 13 | multiplier *= nums[i - 1] 14 | #Set temp list[i] to the mutiplier 15 | nums2[i] = multiplier 16 | #Reset multiplier 17 | multiplier = 1 18 | #Repeat process but go from right to left 19 | for i in range(len(nums2) - 1)[::-1]: 20 | multiplier *= nums[i + 1] 21 | nums2[i] *= multiplier 22 | return nums2 23 | 24 | def main(): 25 | print(multiplyRest([1, 2, 3, 4])) 26 | print(multiplyRest([4,3,2,1,2])) 27 | main() 28 | -------------------------------------------------------------------------------- /Python/Number_Of_Islands.py: -------------------------------------------------------------------------------- 1 | #Question: Given a grid of 1s and 0s, determine the number of disjoint islands present if islands are connected by 1s 2 | #Solution: Run a DFS on each island, making what you have covered 3 | #Difficulty: Easy 4 | 5 | def numIslands(self, grid): 6 | c = 0 7 | def dfs(i, j, grid): 8 | if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] == "0": return 9 | grid[i][j] = "0" 10 | dfs(i - 1, j, grid) 11 | dfs(i + 1, j, grid) 12 | dfs(i, j + 1, grid) 13 | dfs(i, j - 1, grid) 14 | for i, v in enumerate(grid): 15 | for j, u in enumerate(v): 16 | if u == "1": c += 1; dfs(i, j, grid) 17 | return c -------------------------------------------------------------------------------- /Python/One_Edit_Distance.py: -------------------------------------------------------------------------------- 1 | # Question: (#161) Given two strings s and t, determine if they are both one edit distance apart. 2 | # Solution: Use two pointers and a variable to keep track of the edits. Shift the pointer of the longer string 3 | # when we see characters which aren't the same and count that edit. 4 | # Difficulty: Medium 5 | 6 | def isOneEditDistance(self, s: str, t: str) -> bool: 7 | # Since the strings need to be exactly 1 edit apart, if they're the same 8 | # of if they differ in length by more than one, we know they arent one edit apart 9 | if s == t or abs(len(s) - len(t)) > 1: return False 10 | if len(t) > len(s): s, t = t, s 11 | i = j = edits = 0 12 | 13 | while i < len(s) and j < len(t): 14 | 15 | # When we run into a character that's not the same in 16 | # both strings, increment the pointer of the longer string or 17 | # if both strings have the same length, increment both pointers. 18 | if s[i] != t[j]: 19 | edits += 1 20 | i += 1 21 | if len(s) == len(t): j += 1 22 | 23 | # If they character was the same just increment both pointers 24 | else: i += 1; j += 1 25 | 26 | # If ever edits becomes more than one we can return false 27 | if edits > 1: return False 28 | return True -------------------------------------------------------------------------------- /Python/Palindrome_Number.py: -------------------------------------------------------------------------------- 1 | def isPalindrome(self, x): 2 | """ 3 | :type x: int 4 | :rtype: bool 5 | """ 6 | if x < 0: return False 7 | return str(x) == str(x)[::-1] -------------------------------------------------------------------------------- /Python/Parallel_Courses_III.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of courses and their prerequisites, and time needed to complete each course, find the min time to complete all courses 2 | #Solution: Use Khans algorithm to perform a top sort, updating a store of time needed for each course, 3 | # the time for each course is the max of itself or the time needed to complete the previous course + time for this course 4 | #Difficulty: Hard 5 | 6 | from typing import List 7 | from collections import defaultdict 8 | 9 | def minimumTime(n: int, relations: List[List[int]], time: List[int]) -> int: 10 | indegrees = {} 11 | graph = defaultdict(list) 12 | timeToCourse = [0] + time 13 | 14 | for prev, nxt in relations: 15 | indegrees[prev] = 0 16 | indegrees[nxt] = 0 17 | 18 | for prev, nxt in relations: 19 | indegrees[nxt] += 1 20 | graph[prev].append(nxt) 21 | 22 | # get all courses without any prerequisites 23 | q = [course for course, ins in indegrees.items() if ins == 0] 24 | 25 | while q: 26 | course = q.pop() 27 | for nxt in graph[course]: 28 | # time to the next course is either the max of itself (ie we got to the nxt course through another path in the graph), or this path, which is 29 | # currentCourseTime + timeToPrevious course takes more time, the max of either is the bottleneck 30 | timeToCourse[nxt] = max(timeToCourse[nxt], timeToCourse[course] + time[nxt-1]) 31 | indegrees[nxt] -= 1 32 | if indegrees[nxt] == 0: q.append(nxt) 33 | 34 | return max(timeToCourse) -------------------------------------------------------------------------------- /Python/Path_To_Leaves.py: -------------------------------------------------------------------------------- 1 | def sol(t): 2 | def helper(r, l): 3 | if not r.left and not r.right: 4 | print(l + [r.val]) 5 | if r.left: 6 | l.append(r.val) 7 | helper(r.left, l) 8 | if l: del l[-1] 9 | if r.right: 10 | l.append(r.val) 11 | helper(r.right, l) 12 | if l: del l[-1] 13 | l = [] 14 | helper(t, l) 15 | return 16 | 17 | def main(): 18 | a = TreeNode("A") 19 | a.left = TreeNode("B") 20 | a.right = TreeNode("C") 21 | a.left.left = TreeNode("E") 22 | a.left.right = TreeNode("F") 23 | a.right.left = TreeNode("D") 24 | a.right.right = TreeNode("G") 25 | sol(a) 26 | 27 | main() 28 | 29 | 30 | 31 | 32 | A 33 | B C 34 | 35 | D E F G 36 | 37 | A->B->D PRINT ABD 38 | -------------------------------------------------------------------------------- /Python/Permutations.py: -------------------------------------------------------------------------------- 1 | def permute(self, nums): 2 | """ 3 | :type nums: List[int] 4 | :rtype: List[List[int]] 5 | """ 6 | r = [] 7 | def rec(nums, r, current): 8 | if not nums: r += [current] 9 | for i in range(len(nums)): 10 | rec(nums[:i] + nums[i+1:], r, current + [nums[i]]) 11 | return r 12 | return(rec(nums, r, [])) -------------------------------------------------------------------------------- /Python/Plus_One.py: -------------------------------------------------------------------------------- 1 | # Question: Given a list representing a number add one to it and return as list 2 | # Solution: Loop through list, add 1 if not 9, otherwise change to 0, if head is 0 append 1 to head 3 | # Difficulty: Easy 4 | # Time Complexity: O(n) 5 | # Space Complexity: O(1) 6 | 7 | from typing import List 8 | 9 | def plusOne(self, digits: List[int]) -> List[int]: 10 | i = len(digits) - 1 11 | 12 | # Loop through the list backwards, as soon as we see something that's 13 | # not a 9 we can increment and return the list. If it's 9 set it to 0 14 | while i >= 0: 15 | if digits[i] != 9: 16 | digits[i] += 1 17 | return digits 18 | digits[i] = 0 19 | i -= 1 20 | 21 | # If we exit the loop without returning that means digits is now 22 | # an array of all 0s, so just append a 1 at the front and return 23 | return [1] + digits -------------------------------------------------------------------------------- /Python/Pow(x, n).py: -------------------------------------------------------------------------------- 1 | # Question[#50]: Given a number, compute its power 2 | # Difficulty: Medium 3 | # Solution: Use recursion to break the computation into halves each time to achieve O(log n) 4 | 5 | 6 | def myPow(x: float, n: int) -> float: 7 | # Our base case, anything ^ 0 = 1 8 | if n == 0: 9 | return 1 10 | 11 | # If our power is negative, simply invert the number and make the power positive 12 | if n < 0: 13 | x = 1/x 14 | n *= -1 15 | 16 | # If the power is even we want to compute the number times itelf with half the power 17 | # ie (3^8 == (3^2^4) == (3*3)^4)) and if its odd we multiply it with itself but with a power of one less 18 | return self.myPow(x*x, n // 2) if n % 2 == 0 else self.myPow(x, n - 1) * x 19 | -------------------------------------------------------------------------------- /Python/Product_of_Array_Except_Self.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of numbers, multiply each number by all other numbers except itself 2 | #Solution: Traverse right then left while multiplying 3 | #Difficulty: Medium 4 | #Time Complexity: O(n) 5 | #Space Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def productExceptSelf(nums: List[int]) -> List[int]: 10 | #Initialize a variable to store the current multiplication, and one to store the result 11 | multiplier, result = 1, [1] * len(nums) 12 | 13 | #Loop through forwards 14 | for i, v in enumerate(nums): 15 | 16 | #Set the ith index to be the multiplier, and multiply the multiplier by the current number 17 | result[i] *= multiplier 18 | multiplier *= v 19 | 20 | #Reset the multiplier 21 | multiplier = 1 22 | 23 | #Loop through backwards doing the same thing 24 | for i, v in reversed(list(enumerate(nums))): 25 | result[i] *= multiplier 26 | multiplier *= v 27 | 28 | return result 29 | 30 | 31 | def main(): 32 | print(productExceptSelf([1, 2, 3, 4])) 33 | print(productExceptSelf([4,3,2,1,2])) 34 | main() 35 | -------------------------------------------------------------------------------- /Python/Redundant_Connection.py: -------------------------------------------------------------------------------- 1 | def findRedundantConnection(edges): 2 | """ 3 | :type edges: List[List[int]] 4 | :rtype: List[int] 5 | """ 6 | parents = list(range(len(edges) + 1)) 7 | def find(x, parents): 8 | return x if parents[x] == x else find(parents[x], parents) 9 | found = [] 10 | for x, y in edges: 11 | x1, y1 = find(x, parents), find(y, parents) 12 | if x1 == y1: found = [x, y] 13 | parents[x1] = y1 14 | return found -------------------------------------------------------------------------------- /Python/Remove_Sorted_Duplicates.py: -------------------------------------------------------------------------------- 1 | def removeDuplicates(self, nums): 2 | i = 0 3 | while i < (len(nums) - 1): 4 | if(nums[i] == nums[i + 1]): del nums[i] 5 | else: i += 1 6 | return len(nums) -------------------------------------------------------------------------------- /Python/Reverse_Linked_List.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import ListNode 2 | #Question: Given a linked list, reverse it, in place 3 | #Solution: Iterate through, swapping pointers 4 | #Difficulty: Easy 5 | 6 | def reverseList(head): 7 | """ 8 | :type head: ListNode 9 | :rtype: ListNode 10 | """ 11 | #Let previous node be null and current be head 12 | previous = None 13 | current = head 14 | #As long as head isnt null 15 | while head: 16 | #Set current to head, head to the next (Important otherwise heads next node will also become previous) 17 | current, head = head, head.next 18 | #Let current's next node be previous 19 | current.next = previous 20 | #Let previous be current 21 | previous = current 22 | return current 23 | -------------------------------------------------------------------------------- /Python/Reverse_Only_Letters.py: -------------------------------------------------------------------------------- 1 | #Question: Given a string S, return the "reversed" string where all characters that are not a letter stay in the same place, and all letters reverse their positions. 2 | #Solution: Remove all non letter chars and then reverse string, then traverse original string inserting non letter chars back into original indexes 3 | #Time Complexity: O(n) 4 | 5 | def reverseOnlyLetters(S): 6 | """ 7 | :type S: str 8 | :rtype: str 9 | """ 10 | alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 11 | 12 | #Construct a new list consisting of ONLY the letters in S and reverse it 13 | s2 = [letter for letter in S if letter in alphabet][::-1] 14 | 15 | #Loop through S and insert non letters into s2 16 | for i, letter in enumerate(S): 17 | if letter not in alphabet: s2.insert(i, letter) 18 | 19 | return ''.join(s2) 20 | 21 | 22 | def main(): 23 | 24 | #Should be "Qedo1ct-eeLg=ntse-T!" 25 | print(reverseOnlyLetters("Test1ng-Leet=code-Q!")) 26 | 27 | main() -------------------------------------------------------------------------------- /Python/Reverse_String.py: -------------------------------------------------------------------------------- 1 | #Question: Reverse a string 2 | #Solution: Swap left and right pointers 3 | #Difficulty: Easy 4 | 5 | def reverseString(self, s): 6 | """ 7 | :type s: str 8 | :rtype: str 9 | """ 10 | s = list(s) 11 | for i in range(len(s) // 2): s[i], s[-i - 1] = s[-i - 1], s[i] 12 | return "".join(s) -------------------------------------------------------------------------------- /Python/Reverse_Words_In_String_III.py: -------------------------------------------------------------------------------- 1 | #Question: Given a string, reverse each word in the string 2 | #Solution: Reverse each word in the string using a helper function 3 | #Difficulty: Easy 4 | 5 | def reverseWords(self, s): 6 | """ 7 | :type s: str 8 | :rtype: str 9 | """ 10 | s = list(s) 11 | def rev(s, l, r): 12 | while l < r: 13 | s[l], s[r] = s[r], s[l] 14 | r -= 1 15 | l += 1 16 | l, r = 0, 0 17 | while r < len(s): 18 | r += 1 19 | if r == len(s) or s[r] == " ": 20 | rev(s, l, r - 1) 21 | l = r + 1 22 | r += 1 23 | return "".join(s) -------------------------------------------------------------------------------- /Python/Reverse_Words_in_a_String.py: -------------------------------------------------------------------------------- 1 | #Question: Given a string, reverse the positions of the words, for example 'hi my name is' becomes 'is name my hi' 2 | #Solution: Reverse string, then reverse each word 3 | #Time Complexity: O(n) 4 | 5 | def reverseWords(strin): 6 | """ 7 | :type str: List[str] 8 | :rtype: void Do not return anything, modify str in-place instead. 9 | """ 10 | 11 | #Helper function to reverse items in a list from a start index to an end index 12 | def rev(start, end, stringList): 13 | #As long as the start index is less than the end index, swap the items at those indices and increment and decrement the indexs respectively 14 | while start < end: 15 | stringList[start], stringList[end] = stringList[end], stringList[start] 16 | start += 1; end -= 1 17 | return stringList 18 | 19 | #Reverse the input string 20 | strin[:] = strin[::-1] 21 | i = 0 22 | 23 | while i < len(strin): 24 | end = i 25 | #If the letter we're at is not a space, move up end to the next space 26 | if strin[i] != " ": 27 | while end + 1 < len(strin) and strin[end] != " ": 28 | if strin[end + 1] == " ": break 29 | end += 1 30 | #Reverse the string starting at index i to index end 31 | strin[:] = rev(i, end, strin) 32 | #Move i up to the next letter after the space 33 | i = end + 1 34 | 35 | return strin 36 | 37 | def main(): 38 | s = list("hi my name is") 39 | reverseWords(s) 40 | 41 | print(s) 42 | 43 | main() -------------------------------------------------------------------------------- /Python/Rotate_Array.py: -------------------------------------------------------------------------------- 1 | def rotate(nums, k): 2 | """ 3 | :type nums: List[int] 4 | :type k: int 5 | :rtype: void Do not return anything, modify nums in-place instead. 6 | """ 7 | nn = nums[:] 8 | for i in range(k): 9 | temp = nn[-1] 10 | nn = [temp] + nn 11 | del nn[-1] 12 | print(i, temp, nn) 13 | nums[:] = nn[:] 14 | print(nn) 15 | return None 16 | 17 | n = [1,2,3,4,5,6,7] 18 | rotate(n, 3) 19 | print(n) -------------------------------------------------------------------------------- /Python/Same_Tree.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given two trees, check if they are the exact same 3 | #Solution: Traverse both trees recursively 4 | #Difficulty: Easy 5 | 6 | def isSameTree(p, q): 7 | """ 8 | :type p: TreeNode 9 | :type q: TreeNode 10 | :rtype: bool 11 | """ 12 | #If both p and q are non null, their values should be the same, and so should their left and right children 13 | if p and q: return p.val == q.val and isSameTree(p.left, q.left) and isSameTree(p.right, q.right) 14 | #Otherwise return p == q (True only if both p and q have become null) 15 | return p == q -------------------------------------------------------------------------------- /Python/Search_Unsorted_Array.py: -------------------------------------------------------------------------------- 1 | def search(arr, n, x): 2 | 3 | #This is the first comparision 4 | if arr[n - 1] == x: return True 5 | 6 | #Save last element in back and set last element to target 7 | back = arr[n - 1] 8 | arr[n - 1] = x 9 | 10 | i = 0 11 | while i < n: 12 | if arr[i] == x: 13 | arr[n - 1] = back 14 | if i < n - 1: return True 15 | return False 16 | i += 1 17 | 18 | print(search([1,4, 5, 2], 4, 2)) -------------------------------------------------------------------------------- /Python/Search_in_Rotated_Sorted_Array.py: -------------------------------------------------------------------------------- 1 | # Question (#33): Given an array that's sorted but is shifted at a given pivot, find the index of a given number 2 | # Solution: Use a regular binary search, but each time you land on the 'wrong side' of the array from the target, set that 3 | # value to be + or - infinity and do a regular binary search. 4 | # The idea is if our array is [5, 6, 7, 8, 1, 2, 3, 4], we can't do a binary search on it because of the rotation, 5 | # but if we know what side our target is we can make the array [-inf, -inf, -inf, -inf, 1, 2, 3, 4] or [5, 6, 7, 8, inf, inf, inf, inf] 6 | # this way we can continue to do a regular binary search. 7 | 8 | def search(self, nums: List[int], target: int) -> int: 9 | l, r = 0, len(nums) - 1 10 | 11 | while l <= r: 12 | mid = (l+r)//2 13 | 14 | # If our midpoint is greater than or equal to the starting point, and our target is greater than or equal to the 15 | # starting point, we know that we've landed in the correct side of the array relative to the target (the left in this case), so don't do 16 | # anything! 17 | if (nums[mid] >= nums[0]) and (target >= nums[0]): 18 | pass 19 | 20 | # Conversely, if the mid is less than the start and the target is also less than the start, then we've landed on the correct side (the right side) 21 | # this is a strict less than comparision and not a less than or equal, because we can only be sure we're on the correct side 22 | # if the mid is strictly less than the start and so is the target. If we land on the left side and our target is on the right side, this could evaluate to true if it were <=. 23 | elif (nums[mid] < nums[0]) and (target < nums[0]): 24 | pass 25 | 26 | # If we're on the wrong side, check which wrong side it is. If the start is greater than the target, we know we landed 27 | # landed on the left side and our target is on the right, so set the current value to be -INF. And vice versa for if the start is 28 | # less than the target. 29 | elif nums[0] > target: 30 | nums[mid] = float('-inf') 31 | else: 32 | nums[mid] = float('inf') 33 | 34 | # Do a regular binary search now, since we've updated mid! 35 | if nums[mid] == target: return mid 36 | elif nums[mid] > target: 37 | r = mid - 1 38 | else: 39 | l = mid + 1 40 | return -1 -------------------------------------------------------------------------------- /Python/Selection_Sort.py: -------------------------------------------------------------------------------- 1 | def sortSelection(inputList): 2 | for i in range(len(inputList)): 3 | min = i+1 4 | for j in range(i, len(inputList)): 5 | if(inputList[j] < min): 6 | min = j 7 | temp = inputList[i] 8 | inputList[i] = inputList[j] 9 | inputList[j] = temp 10 | return(inputList) 11 | 12 | a = [4, 3, 2, 5] 13 | print(sortSelection(a)) -------------------------------------------------------------------------------- /Python/Shell_Sort.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kumailn/Algorithms/e6be0a0cbf0caf13a723a9edfd2df33c2234235f/Python/Shell_Sort.py -------------------------------------------------------------------------------- /Python/Shortest_Distance.py: -------------------------------------------------------------------------------- 1 | #Question: Given a sentence of words, find the shortest distance between two given words 2 | #Difficulty: Easy 3 | #Solution: Keep two pointers and the distance, update distance when the pointers are closer together 4 | #Space Complexity: O(1) 5 | #Time Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def shortestDistance(words: List[str], word1: str, word2: str) -> int: 10 | #Initialize two pointers, initialize distance to MAX_INTs 11 | p1 = p2 = -1 12 | distance = float('inf') 13 | 14 | #Loop through the words 15 | for i, v in enumerate(words): 16 | 17 | #Every time the current word is word1 update p1 and vice versa for p2 18 | if v == word1: p1 = i 19 | if v == word2: p2 = i 20 | 21 | #If we've found both word1 and word2 (ie when both pointers are not -1) 22 | #Update distance to be the min or itself or the updated pointers 23 | if p1 != -1 and p2 != -1: distance = min(distance, abs(p1 - p2)) 24 | return distance 25 | 26 | def main(): 27 | print(shortestDistance(["a","c","a","b"], "b", "a")) 28 | 29 | main() -------------------------------------------------------------------------------- /Python/Single_Number.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of numbers where every number is repeted twice except one, find that number 2 | #Solution: XOR every number together, words because XOR is commutative and a number XOR itself is 0 3 | #Difficulty: Easy 4 | 5 | def singleNumber(nums): 6 | """ 7 | :type nums: List[int] 8 | :rtype: int 9 | """ 10 | r = 0 11 | for i in nums: r ^= i 12 | return r -------------------------------------------------------------------------------- /Python/Smallest_Unsorted_Subarray.py: -------------------------------------------------------------------------------- 1 | #Question: Given an array, find the length of the smallest subarray such that if you sort the subarray the entire array becomes sorted 2 | #Solution: Sort array and see differences, (Naive approach) 3 | 4 | 5 | #Naive approach 6 | def findUnsortedSubarrayN(arr): 7 | """ 8 | :type nums: List[int] 9 | :rtype: int 10 | """ 11 | cmin, cmax, end, beg = arr[-1], arr[0], -2, -1 12 | for i in range(1, len(arr)): 13 | cmax = max(cmax, arr[i]) 14 | cmin = min(cmin, arr[len(arr) - 1 - i]) 15 | if arr[i] < cmax: end = i 16 | if arr[len(arr) - 1 - i] > min: beg = len(arr) - 1 - i 17 | return end - beg + 1 18 | 19 | #Optimal approach 20 | def findUnsortedSubarray(self, nums): 21 | """ 22 | :type nums: List[int] 23 | :rtype: int 24 | """ 25 | l, r = -1, 0 26 | mmin, mmax = float('inf'), float('-inf') 27 | for i in range(len(nums)): 28 | mmax = max(mmax, nums[i]) 29 | if nums[i] != mmax: l = i 30 | 31 | mmin = min(mmin, nums[len(nums) - i - 1]) 32 | if nums[len(nums) - i - 1] != mmin: r = len(nums) - i - 1 33 | print(l, r) 34 | return l - r + 1 35 | 36 | 37 | 38 | def main(): 39 | a = [1, 4, 6, 8, 3, 2, 9] 40 | arr = [2,6,4,8,10,9,15] 41 | 42 | print(smallesUnsortedSubarray(a)) 43 | print(smallesUnsortedSubarray(arr)) 44 | 45 | main() -------------------------------------------------------------------------------- /Python/Sort_Array_By_Parity.py: -------------------------------------------------------------------------------- 1 | #Question: Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A. 2 | #Difficulty: Easy 3 | def sortArrayByParity(A): 4 | """ 5 | :type A: List[int] 6 | :rtype: List[int] 7 | """ 8 | even = 0 9 | for i in range(len(A)): 10 | if A[i] % 2 == 0: 11 | A[even], A[i] = A[i], A[even] 12 | even += 1 13 | return A -------------------------------------------------------------------------------- /Python/Spiral_Matrix.py: -------------------------------------------------------------------------------- 1 | # Question: Given a matrix (2x2 array), traverse it in a spiral 2 | # # Solution: Track the offset of the inner level of the spiral we're at, keep track of the directions 3 | # Difficulty: Medium 4 | 5 | def spiralOrder(matrix): 6 | 7 | # Initially our direction needs to be right and our offset 0 8 | direction = "R" 9 | i = j = offset = 0 10 | result = [] 11 | if not matrix: return matrix 12 | m, n = len(matrix) - 1, len(matrix[0]) - 1 13 | 14 | # Loop through the number of values in the matrix 15 | for _ in range(len(matrix) * len(matrix[0])): 16 | result += [matrix[i][j]] 17 | 18 | # If the direction is right keep incrementing j (the horizantal index) 19 | # once j reaches the end (the length of the horizantal - the offset), switch directions 20 | # accordingly; similar approaches for when traversing down and left 21 | if direction == "R": 22 | if j == n - offset: direction = "D" 23 | else: j += 1 24 | if direction == "D": 25 | if i == m - offset: direction = "L" 26 | else: i += 1 27 | if direction == "L": 28 | if j == offset: direction = "U" 29 | else: j -= 1 30 | 31 | # If we're traversing upwards we need to increment the offset once i is 1 more than the offset, 32 | # this is because if i == offset + 1 then i is right below the offset and we want to start traversing 33 | # an inner spiral of the matrix. We also increment j in this case and indicate the next move is to the right 34 | if direction == 'U': 35 | if i == offset + 1: 36 | direction = "R" 37 | offset += 1 38 | j += 1 39 | else: i -= 1 40 | 41 | return result 42 | 43 | -------------------------------------------------------------------------------- /Python/Spiral_Matrix_Traversal.py: -------------------------------------------------------------------------------- 1 | tesft = [ 2 | [1, 2, 3, 4], 3 | [5, 6, 7, 8], 4 | [9, 10, 11, 12], 5 | [13, 14, 15, 16] 6 | ] 7 | 8 | test1 = [ 9 | [1, 2, 3, 4, 5], 10 | [6, 7, 8, 9, 10], 11 | [11, 12, 13, 14, 15], 12 | [16, 17, 18, 19, 20], 13 | [21, 22, 23, 24, 25] 14 | ] 15 | 16 | test3 = [[2,5],[8,4],[0,-1]] 17 | 18 | def spiral(matrix): 19 | directions = ["R", "D", "L", "U"] 20 | direction_index = 0 21 | direction = "R" 22 | traversal = [] 23 | offset = 0 24 | total = 0 25 | x = 0 26 | y = 0 27 | # if(len(matrix) == 0): 28 | # return matrix 29 | # if(len(matrix) == 1): 30 | # for i in matrix: 31 | # traversal += [i] 32 | # return traversal 33 | # if(len(matrix[0]) == 1): 34 | # for i in matrix: 35 | # traversal += [i[0]] 36 | # return traversal 37 | if(len(matrix) == 0): 38 | return traversal 39 | for i in range(len(matrix) * len(matrix[0])): 40 | total += 1 41 | print(traversal, offset) 42 | if(direction == 'R'): 43 | traversal += [matrix[x][y]] 44 | if(y == (len(matrix[0]) - 1 - offset)): 45 | #traversal += ['X'] 46 | direction = 'D' 47 | x += 1 48 | else: 49 | y += 1 50 | elif(direction == 'D'): 51 | traversal += [matrix[x][y]] 52 | if(x == (len(matrix) - 1 - offset)): 53 | #traversal += ['X'] 54 | direction = 'L' 55 | y -= 1 56 | else: 57 | x += 1 58 | elif(direction == 'L'): 59 | traversal += [matrix[x][y]] 60 | if(y == offset): 61 | #traversal += ['X'] 62 | direction = 'U' 63 | offset += 1 64 | x -= 1 65 | else: 66 | y -= 1 67 | elif(direction == 'U'): 68 | traversal += [matrix[x][y]] 69 | if(x == offset): 70 | #traversal += ['X'] 71 | direction = 'R' 72 | y += 1 73 | else: 74 | x -= 1 75 | print(total) 76 | return traversal 77 | 78 | print(spiral(test3)) 79 | 80 | -------------------------------------------------------------------------------- /Python/String_To_Int.py: -------------------------------------------------------------------------------- 1 | def toInt(s): 2 | """ 3 | :type str: str 4 | :rtype: int 5 | """ 6 | num = i = 0 7 | nums = "0987654321" 8 | s = s.strip(" ") 9 | if not s: return 0 10 | neg = s[0] == "-" 11 | if s[0] == "+" or neg: s = s[1:] 12 | if not s: return 0 13 | if s[0] != "-" and s[0] != "+" and s[0] not in nums: return 0 14 | while i < len(s) and s[i] in nums: i += 1 15 | if not i and s[i] not in nums: return 0 16 | num = int(s[:i]) if not neg else - 1 * int(s[:i]) 17 | if num > (2**31) - 1: return (2 ** 31) - 1 18 | if num < -(2**31): return -1 * (2 ** 31) 19 | return num 20 | -------------------------------------------------------------------------------- /Python/String_to_Integer.py: -------------------------------------------------------------------------------- 1 | # Question(#8): Given a string representing an integer, return that integer 2 | # Solution: Parse the string and bulild up the number 3 | 4 | def myAtoi(self, str: str) -> int: 5 | # Firstly, strip the string of whitespaces, initialize variables to hold our number and the sign (positive or negative) 6 | str = str.lstrip() 7 | sign = 1 8 | base = i = 0 9 | 10 | if not str: return 0 11 | 12 | # If the string starts with a sign, set out sign variable appropriately 13 | if str[0] in '-+': 14 | sign = -1 if str[0] == '-' else 1 15 | str = str[1:] 16 | 17 | while i < len(str): 18 | # If we encounter something thats not a digit, we can break out of our loop 19 | if not str[i].isdigit(): break 20 | 21 | # Multiply the number by 10 and add out current digit (this is a very common technique for building numbers from strings) 22 | base *= 10 23 | base += int(str[i]) 24 | i += 1 25 | 26 | if base*sign >= 2**31-1: return 2**31-1 27 | if base*sign <= -2**31: return -2**31 28 | return base * sign -------------------------------------------------------------------------------- /Python/Strobogrammatic_Number.py: -------------------------------------------------------------------------------- 1 | def isStrobogrammatic(self, num): 2 | """ 3 | :type num: str 4 | :rtype: bool 5 | """ 6 | n2 = "" 7 | updowns = {"6": "9", "8": "8", "9": "6", "0":"0", "1":"1"} 8 | if "7" in num or "5" in num or "3" in num or "4" in num or "2" in num: return False 9 | for i, v in enumerate(num[::-1]): 10 | n2 += updowns[v] 11 | print(n2) 12 | return num == n2 -------------------------------------------------------------------------------- /Python/Subarray_Sum_Equals_K.py: -------------------------------------------------------------------------------- 1 | def subarraySum(self, nums, k): 2 | """ 3 | :type nums: List[int] 4 | :type k: int 5 | :rtype: int 6 | """ 7 | countMap = {0: 1} 8 | current = 0 9 | result = 0 10 | for i in nums: 11 | current += i 12 | result += countMap[current - k] if (current - k) in countMap else 0 13 | countMap[current] = countMap.get(current, 0) + 1 14 | print(countMap) 15 | return result -------------------------------------------------------------------------------- /Python/Subset_Sum.py: -------------------------------------------------------------------------------- 1 | def subsetSum(nums, sumTo): 2 | sumleft = sumTo 3 | store = [[0 for i in range(sumTo + 1)] for j in range(len(nums) + 1)] 4 | print(store) 5 | 6 | for i in range(1, len(nums) + 1): 7 | for w in range(1, sumTo + 1): 8 | if w > sumleft: 9 | store[i][sumleft] = store[i - 1][w] 10 | else: 11 | store[i][sumleft] = max(store[i - 1][sumleft], w + store[i - 1][sumleft - w]) 12 | print(store) 13 | return store[len(nums)][sumTo] 14 | 15 | def main(): 16 | print(subsetSum([3, 34, 4, 12, 5, 2], 9)) 17 | 18 | main() -------------------------------------------------------------------------------- /Python/Subsets.py: -------------------------------------------------------------------------------- 1 | #Question: Given a list of ints, generate the powerset 2 | #Difficulty: Backtrack to determine all possible sets 3 | #Difficulty: Medium 4 | #Type: Backtracking 5 | 6 | -------------------------------------------------------------------------------- /Python/Sum_Of_Left_Leaves.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | lsum = 0 3 | def sumOfLeftLeaves(self, root): 4 | """ 5 | :type root: TreeNode 6 | :rtype: int 7 | """ 8 | if not root: return 0 9 | def helper(root): 10 | if root.right: helper(root.right) 11 | if root.left: helper(root.left) 12 | if root.left and not root.left.left and not root.left.right: 13 | self.lsum += root.left.val 14 | helper(root) 15 | return self.lsum -------------------------------------------------------------------------------- /Python/Sum_Root_to_Leaf_Numbers.py: -------------------------------------------------------------------------------- 1 | def sumNumbers(self, root): 2 | """ 3 | :type root: TreeNode 4 | :rtype: int 5 | """ 6 | if not root: return 0 7 | def helper(root, currentPath, allPaths): 8 | if not root.left and not root.right: allPaths.append(currentPath + [root.val]) 9 | if root.left: helper(root.left, currentPath + [root.val], allPaths) 10 | if root.right: helper(root.right, currentPath + [root.val], allPaths) 11 | return allPaths 12 | return sum(map(lambda x: int("".join(list(map(str, x)))), helper(root, [], []))) 13 | -------------------------------------------------------------------------------- /Python/Symmetric_Tree.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import * 2 | #Question: Determine if a tree is symmetric 3 | #Solution: Recursively call mirroring nodes 4 | #Difficulty: Easy 5 | 6 | 7 | def isSymmetric(root): 8 | #If node is null then tree is symmetric 9 | if not root: return True 10 | #Define resursive helper function that takes in two nodes and compares their values 11 | def help(l, r): 12 | #If both nodes are null return True (this is a base case) 13 | if not l and not r: return True 14 | #If only one of the nodes is null return false as tree is imbalanced, or values of aren't the same (another base case) 15 | if not l or not r or l.val != r.val: return False 16 | #Otherwise call same function on the inner two nodes (lefts right and rights left) and outer two nodes (rights right and lefts left) 17 | return help(l.left, r.right) and help(l.right, r.left) 18 | #Call helper on the first pair of children 19 | return help(root.left, root.right) 20 | 21 | -------------------------------------------------------------------------------- /Python/Text_Justification.py: -------------------------------------------------------------------------------- 1 | #Question: A list of words and the maxWidth of a line, return a list of the justified text 2 | #Solution: Loop through the words, for each line add in a space between the words round-robin until the maxWidth is reached 3 | #Difficulty: Hard 4 | #Time Complexity: O(n) 5 | #Space Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def fullJustify(words: List[str], maxWidth: int) -> List[str]: 10 | #Variables to store the final outpur, the current sentence, and the number of letters 11 | justified, current, letterCount = [], [], 0 12 | 13 | #Loop through all words 14 | for i, word in enumerate(words): 15 | 16 | #If the length of word + current + number of letters is greater than maxWidth 17 | #The letterCount tells us the length of the letters and len(current) tells the length of the min spaces needed 18 | #If the length of the sentence (with minimal spacing) + the length of the current word is more than the maxWidth, the current word cannot fit in the sentence 19 | if (letterCount + len(current)) + len(word) > maxWidth: 20 | 21 | #For each space left over from the maxWidth 22 | for i in range(maxWidth - letterCount): 23 | #Add spaces round-robin to each word, except for the last word 24 | #This is why we subtract 1 from the length, also, if the length - 1 is 0 mod by 1 instead 25 | current[i % (len(current) - 1 if len(current) - 1 else 1)] += " " 26 | 27 | #Once we're finished justifying add the sentence to the result and reset the current line and letter count 28 | justified += ["".join(current)] 29 | current, letterCount = [], 0 30 | 31 | #Once we've looped through a word, append it to the current line and increment the letter count by its length 32 | current += [word] 33 | letterCount += len(word) 34 | 35 | #Return the result + the last line, which is simply left aligned with padding on the right 36 | return justified + [" ".join(current).ljust(maxWidth)] 37 | 38 | print(fullJustify(["Listen","to","many,","speak","to","a","few."], 20)) 39 | -------------------------------------------------------------------------------- /Python/Three_Sum.py: -------------------------------------------------------------------------------- 1 | #Question: Find 3 unique numbers that add to a given newTarget number 2 | #Solution: Sort list first then move pointers accordingly to find a number that sums to newTarget 3 | #Difficulty: Medium 4 | #Complexity: O(N) = O(N + NLog(N)) 5 | 6 | 7 | def threeSum(nums, target): 8 | """ 9 | :type nums: List[int] 10 | :rtype: List[List[int]] 11 | """ 12 | #The set of possible solutions 13 | solutions = [] 14 | #Sort the numbers array, this uses NlogN complexity 15 | nums = sorted(nums) 16 | #Loop up till the 3rd last element! This is beacuse the last possible solution set starts at the third last element 17 | for i in range(len(nums) - 2): 18 | #If i is not 0, and i is the same as the previous i, skip this loop iteration 19 | if i and nums[i] is nums[i - 1]: continue 20 | #Initialize the left pointer, right pointer to be i + 1 (next value) and len(n) - 1 (last value). Initialize a newtarget we're looking for, which is the original target minus the current number we're at in the loop 21 | l, r, newTarget = i + 1, len(nums) - 1, target - nums[i] 22 | #While left pointer is less than right pointer 23 | while l < r: 24 | #If the numbers at the left and right pointer sum to the new target, add that solution to our result! 25 | if nums[l] + nums[r] == newTarget: 26 | solutions += [[nums[r], nums[l], nums[i]]] 27 | #Increace l as long as its equal to its previous value, and vice versa for r 28 | while l < r and nums[l] == nums[l+1]: l += 1 29 | while l < r and nums[r] == nums[r-1]: r -= 1 30 | #Increase and decrease l and r 31 | l += 1; r -= 1 32 | #If the left and right poniters add to less than our sum, we know we can shift the left pointer up because the list is sorted! 33 | elif nums[l] + nums[r] < newTarget: l += 1 34 | #If they they add to a smaller number move right pointer down 35 | else: r -= 1 36 | return solutions -------------------------------------------------------------------------------- /Python/Top_K_Frequent_Elements.py: -------------------------------------------------------------------------------- 1 | # Question(#347): Given a non-empty array of integers, return the k most frequent elements. 2 | # Solution: Use a counting sort to place the most frequent items into buckets, loop through the buckets backwards, 3 | # (since the last bucket cooresponds to the most common item), add the items in the bucket to our result and decrement 4 | # value of k by the amount of items in the bucket. An alternate solution is to use a Heap. 5 | 6 | # Using a counting sort 7 | def topKFrequent(nums: List[int], k: int) -> List[int]: 8 | # Make an array with len(nums) + 1 positions, because the max frequency of any element 9 | # can coorespond to the len(nums) + 1 index. 10 | buckets = [[] for _ in range(len(nums) + 1)] 11 | result = [] 12 | 13 | # Save a number to the bucket which cooresponds to its frequency 14 | for a, b in collections.Counter(nums).items(): buckets[b] += [a] 15 | 16 | # Loop through the buckets backwards, since the ones at the end are the most frequent elements 17 | for i in buckets[::-1]: 18 | # If k becomes 0 or negative, we've found enough items 19 | if k <= 0: return result 20 | 21 | # If there's stuff in the current bucket, add that stuff to our result, and 22 | # decrement k by the amount of things we just added 23 | if i: 24 | result += i 25 | k -= len(i) 26 | 27 | return result 28 | 29 | # Using a max heap 30 | def topKFrequent(nums: List[int], k: int) -> List[int]: 31 | result, heap = [], [] 32 | 33 | # Add every item to the max-heap, (Note we add -b instead of b since python supports min-heaps), 34 | # each item consists of its count and its value. 35 | for a, b in collections.Counter(nums).items(): 36 | heapq.heappush(heap, (-b, a)) 37 | 38 | # As long as we either have items in the heap and we have k left, we want to take things 39 | # off of the max heap. Pop the top, add the value associated with it to the result and decrement k. 40 | while k and heap: 41 | result += [heapq.heappop(heap)[1]] 42 | k -= 1 43 | 44 | return result -------------------------------------------------------------------------------- /Python/Top_Sort_BFS.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from collections import defaultdict 3 | 4 | 5 | def topSort(numNodes: int, edges: List[int]) -> List[int]: 6 | graph = defaultdict(list) 7 | # indegrees is simply the number of incoming arrows at each node 8 | indegrees = {} 9 | result = [] 10 | 11 | for pre, nxt in edges: 12 | graph[pre].append(nxt) 13 | if pre not in indegrees: indegrees[pre] = 0 14 | if nxt not in indegrees: indegrees[nxt] = 0 15 | indegrees[nxt] += 1 16 | 17 | # get all nodes with 0 incoming edges, we know these have no prerequisites and so we can start with them 18 | queue = [node for node in indegrees if indegrees[node] == 0] 19 | 20 | while queue: 21 | node = queue.pop() 22 | result.append(node) 23 | 24 | # go through all nodes that depend on the current node and decrement their indegrees by 1 25 | # because the current node is being removed from the graph 26 | for nxt in graph[node]: 27 | indegrees[nxt] -= 1 28 | # if a nodes indegrees ever becomes 0 we know it has no more dependencies left in the graph, enqueue it 29 | if indegrees[nxt] == 0: queue.append(nxt) 30 | 31 | # if we don't have exactly the all the nodes in the output, there was a cycle somewhere 32 | return result if len(result) == numNodes else None 33 | 34 | def main(): 35 | graph = [["A", "B"], ["B", "C"], ["C", "D"], ["B", "G"]] 36 | print(topSort(5, graph)) 37 | 38 | main() 39 | -------------------------------------------------------------------------------- /Python/Topological_DFS.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | def topSort(numEdges: int, edges: List[int]) -> List[int]: 4 | graph = {} 5 | def depthFirst(current, visited, visitedNodes, graph): 6 | visited.add(current) 7 | for edge in graph[current]: 8 | if not (edge in visited): 9 | depthFirst(edge, visited, visitedNodes, graph) 10 | visitedNodes.append(current) 11 | 12 | # Populate the graph 13 | for i in range(numEdges): graph[i] = [] 14 | for x, y in edges: graph[y] = [x] 15 | 16 | visited = set(); result = [] 17 | for node in graph: 18 | if not (node in visited): 19 | visitedNodes = [] 20 | depthFirst(node, visited, visitedNodes, graph) 21 | for node2 in visitedNodes: result.insert(0, node2) 22 | return result 23 | 24 | def main(): 25 | graph = [[0, 5], [5, 0], [0, 4], [1, 4], [2, 5], [3, 2], [1, 3]] 26 | print(topSort(6, graph)) 27 | 28 | main() -------------------------------------------------------------------------------- /Python/Trapping_Rain_Water.py: -------------------------------------------------------------------------------- 1 | # Question: Determing how much rain water is trapped in a stage of blocks 2 | # Solution: Use two pointers to determine the lower bound and shift accordingly 3 | # Difficulty: Hard 4 | 5 | 6 | def trap(height: List[int]) -> int: 7 | water = smaller = depth = 0 8 | l, r = 0, len(height) - 1 9 | 10 | while l < r: 11 | # Set 'smaller' to be the smaller height of the two pointers, and shift pointers accordingly 12 | if height[l] < height[r]: 13 | smaller = height[l] 14 | l += 1 15 | else: 16 | smaller = height[r] 17 | r -= 1 18 | 19 | # Set depth to be the largest lower bound we've encountered so far 20 | # this will be the upper bound of the level of the water 21 | depth = max(depth, smaller) 22 | 23 | # The water level per block will simply be the depth we've computed minus the smaller bound we're currently at 24 | water += depth - smaller 25 | return water 26 | -------------------------------------------------------------------------------- /Python/Two_Sum.py: -------------------------------------------------------------------------------- 1 | # Question: Given an array of integers, return indices of the two numbers such that they add up to a specific target. 2 | # Solution: Keep a hashmap with keys of target - num 3 | # Difficulty: Easy 4 | # Time Complexity: O(n) 5 | # Space Complexity: O(n) 6 | 7 | from typing import List 8 | 9 | def twoSum(nums: List[int], target: int) -> List[int]: 10 | # Create a hashmap to store numbers we want to look for 11 | lookingFor = {} 12 | 13 | for i, v in enumerate(nums): 14 | # If the number we're at is one we're looking for 15 | # return it's index along with the one in the hashmap 16 | if v in lookingFor: 17 | return [lookingFor[v], i] 18 | 19 | # Otherwise we want to remember to look for the (target - current) later 20 | lookingFor[target - v] = i 21 | -------------------------------------------------------------------------------- /Python/Two_Sum_All_Pairs.py: -------------------------------------------------------------------------------- 1 | #Question: Count the number of pairs that add to a given value 2 | #Solution: Modifiy a traditional two sum 3 | #Difficulty: Easy 4 | #Time Complexity: O(n) 5 | #Space Complexity: O(n) 6 | 7 | def twoAll(nums, target): 8 | #Keep a hashmap of the counts of our new targets 9 | counts = {} 10 | #Keep a variable to store all pair counts 11 | count = 0 12 | for i, v in enumerate(nums): 13 | #If the current number in our nums array is present in our counts hashmap, then increment our count variable by the number of times it's been seen so far 14 | if v in counts: count += counts[v] 15 | #Update our counts hashmap and increment the count of our new target (target - v) by 1 16 | counts[target - v] = counts.get(target - v, 0) + 1 17 | return count 18 | 19 | 20 | 21 | 22 | def main(): 23 | nums = [2, 3, 1, 3, 2, 1] 24 | nums2 = [1, 1, 1, 1, 1, 2, 0, 3, 0] 25 | print(twoAll(nums, 5)) 26 | print(twoAll(nums2, 3)) 27 | main() -------------------------------------------------------------------------------- /Python/Two_Sum_Sorted.py: -------------------------------------------------------------------------------- 1 | #Question: Given a sorted list of numbers, find two numbers that add to a given target 2 | #Solution: Keep left and right pointers and adjust accordingly 3 | #Difficulty: Easy 4 | 5 | def twoSum(numbers, target): 6 | """ 7 | :type numbers: List[int] 8 | :type target: int 9 | :rtype: List[int] 10 | """ 11 | #left and right pointers 12 | l, r = 0, len(numbers) - 1 13 | #while left is less than right 14 | while l < r: 15 | #If left + right is the target return them 16 | if numbers[l] + numbers[r] == target: return [l, r] 17 | #If its more then the target we need to find smaller numbers to add so move right pointer down 18 | elif numbers[l] + numbers[r] > target: r -= 1 19 | #If its more move left pointer up 20 | else: l += 1 21 | return [] -------------------------------------------------------------------------------- /Python/Unique_Paths.py: -------------------------------------------------------------------------------- 1 | # Question (#62): Given a grid, find the number paths there are that you can take to get to the last position 2 | # Solution: Use dynamic programming to build up the number of paths possible, the number of paths at each position 3 | # in the grid is the sum of the number of paths possible to the grid above and the grid to the left 4 | # Difficulty: Medium 5 | 6 | def uniquePaths(m: int, n: int) -> int: 7 | # Set up an m by n grid, set all positions to 1 initially, since there's at least 1 way to get anywhere 8 | grid = [[1] * n] * m 9 | 10 | # Start looping through rows and colums, start at 1 since we need to look 11 | # to the left and top positions in the grid to find the number of paths 12 | for i in range(1, m): 13 | for j in range(1, n): 14 | # Set each position in the grid to be the sum of the paths possible above it and to it's left 15 | grid[i][j] = grid[i-1][j] + grid[i][j-1] 16 | 17 | # Return the last position in the grid, as thats the total number of paths possible to get to the end of the grid 18 | return grid[-1][-1] -------------------------------------------------------------------------------- /Python/Valid_Anagram.py: -------------------------------------------------------------------------------- 1 | #Question: Given two words, determine if theyre anagrams 2 | #Solution: Sort and compare 3 | #Difficulty: Easy 4 | #Time Complexity: O(log n) / O(n) 5 | #Space Complexity: O(1) / O(n) 6 | 7 | #Trivial solution, sort both strings and compare, complexity is O(log n) 8 | def isAnagram(self, s, t): 9 | """ 10 | :type s: str 11 | :type t: str 12 | :rtype: bool 13 | """ 14 | return sorted(s) == sorted(t) 15 | -------------------------------------------------------------------------------- /Python/Valid_Parentheses.py: -------------------------------------------------------------------------------- 1 | # Question: Given a string of parentheses determine if it's valid or not 2 | # Solution: Keep a stack of seen opening parentheses 3 | # Difficulty: Easy 4 | 5 | def isValid(s: str) -> bool: 6 | pairs = {'(':')', '{':'}', '[':']'} 7 | stack = [] 8 | 9 | for i, v in enumerate(s): 10 | 11 | # Add to the top of the stack if it's a opening bracket 12 | if v in '({[': stack += [v] 13 | 14 | # If the stack is not empty and the top is the pair of the current closing bracket, pop it 15 | elif stack and pairs[stack[-1]] == v: del stack[-1] 16 | 17 | # If the stack became empty at any point ot the brackets didnt match, return False 18 | else: return False 19 | 20 | # Return true if the stack is empty 21 | return not stack 22 | -------------------------------------------------------------------------------- /Python/Valid_Sudoku.py: -------------------------------------------------------------------------------- 1 | # Question: Given a sudoku board, check if it is invalid 2 | # Solution: Store each item in its correct row, col and block in a set or map, and check if it has been repeated 3 | # Difficulty: Easy 4 | 5 | def isValidSudoku(self, board: List[List[str]]) -> bool: 6 | alreadySeen = set() 7 | for i, row in enumerate(board): 8 | for j, number in enumerate(row): 9 | 10 | # We don't care if the number is empty 11 | if number == ".": continue 12 | 13 | # Store each of 3 categories in our set, for example if we come across a '5' 14 | # in the third row, first column and first block our set will contain {'5row3', '5col1', '5block1'} 15 | # this way if we ever run into a number that is in the same block/col/row it will already exist in our set 16 | # and we can look it up in O(1) time and return false if it does exist since it invalidates the sudoku board 17 | numberInRow = number + 'row' + str(i) 18 | numberInCol = number + 'col' + str(j) 19 | numberInBlock = number + 'block' + str(i//3) + str(j//3) 20 | 21 | if alreadySeen.intersection({numberInCol, numberInRow, numberInBlock}): 22 | return False 23 | 24 | alreadySeen.add(numberInCol) 25 | alreadySeen.add(numberInRow) 26 | alreadySeen.add(numberInBlock) 27 | 28 | return True -------------------------------------------------------------------------------- /Python/Validate_Binary_Tree.py: -------------------------------------------------------------------------------- 1 | from _DATATYPES import TreeNode 2 | #Question: Given a Binary Search Tree, determing if it's valid 3 | #Solution: Recursively check all nodes in tree are within their valid ranges 4 | #Difficulty: Easy 5 | 6 | def isValidBST(root): 7 | """ 8 | :type root: TreeNode 9 | :rtype: bool 10 | """ 11 | #If node is null then return True 12 | if not root: return True 13 | #Define recursive helper, takes in current node and its valid range 14 | def helper(r, minVal, maxVal): 15 | #If node is null return true 16 | if not r: return True 17 | #If nodes val is not within given range, return False 18 | if r.val <= minVal or r.val >= maxVal: return False 19 | #Call helper on left and right children, for left child let the maxVal be the current nodes value (Max decreases as you go left) 20 | #For right child let minVal be current nodes val (Min increases as you go right) 21 | return helper(r.left, minVal, r.val) and helper(r.right, r.val, maxVal) 22 | #Initially call on root node with a min of -infinity and max of +infinity 23 | return helper(root, float('-inf'), float('inf')) 24 | 25 | -------------------------------------------------------------------------------- /Python/Validate_DAG.py: -------------------------------------------------------------------------------- 1 | def hasCycle(edges, numEdges): 2 | #Initialize a graph that stores the neighbor of each node 3 | graph = {i:[] for i in list(range(numEdges))} 4 | #Populate the graph so that the 'children' of each node are stored with the parent as the key 5 | for x, y in edges: graph[x] += [y] 6 | #Create three sets, one to store all unvisited nodes, one to store nodes curently visiting, one to store completely visited ones 7 | unvisited = list(range(numEdges)) 8 | visiting = set() 9 | completelyVisited = set() 10 | 11 | #While we still have nodes that are unvisited 12 | while unvisited: 13 | #We graph a random node from the unvisited collection to run a DFS on 14 | currentNode = unvisited[0] 15 | #If a call to the depth first seach returns true then we know this graph has a cycle and can return true 16 | if depthFirstSearch(currentNode, unvisited, visiting, completelyVisited, graph): return True 17 | #If no call to the depth first search returns true then we can return False that there is no cycle in this graph 18 | return False 19 | 20 | #Define our helper depth first search for a cycle 21 | def depthFirstSearch(currentNode, unvisited, visiting, completelyVisited, graph): 22 | #Firstly, we need to move the current node we're at from unvisited and to visiting 23 | unvisited.remove(currentNode) 24 | visiting.add(currentNode) 25 | #Now for each of this nodes adjacent neighbors we need to run this DFS again 26 | for neighbor in graph[currentNode]: 27 | #If that neighbor has already been completely visited, we can skip tis particular neighbor 28 | if neighbor in completelyVisited: continue 29 | #If this neighbor is already a node we're visiting then return true that this has a cycle! Because we've circled back to a parent node 30 | if neighbor in visiting: return True 31 | #If any its neighbors have a cycle return true as well 32 | if depthFirstSearch(neighbor, unvisited, visiting, completelyVisited, graph): return True 33 | #Finally remove this current node from visiting and add it to completely visited 34 | visiting.remove(currentNode) 35 | completelyVisited.add(currentNode) 36 | 37 | def main(): 38 | print(hasCycle([[1, 0], [0, 2]], 3)) 39 | 40 | main() -------------------------------------------------------------------------------- /Python/Word_Break.py: -------------------------------------------------------------------------------- 1 | def wordBreak(s, dict): 2 | checklist = [False] * (len(s) + 1) 3 | checklist[len(s)] = True 4 | for i in range(len(s))[::-1]: 5 | for j in range(i,len(s)): 6 | if s[i:j+1] in dict and checklist[j+1]==True: 7 | checklist[i]=True 8 | return checklist[0] 9 | 10 | print(wordBreak("cars", ["car","ca","rs"])) -------------------------------------------------------------------------------- /Python/ZigZag_Conversion.py: -------------------------------------------------------------------------------- 1 | # Question: Given a string like "PAYPALISHIRING" produce a zigzag pattern like so 2 | # P I N 3 | # A L S I G 4 | # Y A H R 5 | # P I 6 | # Solution: Create an array with elements equal to number of rows, keep a stepper to keep tack of 7 | # wether to go up or down the zig-zag, flip the stepper everytime 8 | # Difficulty: Medium 9 | 10 | 11 | 12 | def convert(s: str, numRows: int) -> str: 13 | if numRows == 1: return s 14 | 15 | i, step = 0, 1 16 | rows = [""] * numRows 17 | 18 | for letter in s: 19 | 20 | # For every letter we add it to some place in our array 21 | rows[i] += letter 22 | 23 | # We increment our pointer by the step, initially we simply increment it by 1 24 | # when we reach the bottom we reverse the step, and reverse again when get back to the top 25 | i += step 26 | 27 | # Reverse the step when we reach a upper or lower boundary 28 | if i == 0 or i == numRows - 1: step *= -1 29 | 30 | return "".join(rows) -------------------------------------------------------------------------------- /Python/_DATATYPES.py: -------------------------------------------------------------------------------- 1 | #This file defines the different types of data structures used 2 | 3 | #Definition for a binary tree node. 4 | class TreeNode: 5 | inOrder = [] 6 | def __init__(self, x): 7 | self.val = x 8 | self.left = None 9 | self.right = None 10 | def __str__(self): 11 | return str(self.val) 12 | def printInOrder(self, r): 13 | if r.left: r.printInOrder(r.left) 14 | self.inOrder += [r.val] 15 | if r.right: r.printInOrder(r.right) 16 | return self.inOrder 17 | 18 | 19 | # Definition for singly-linked list. 20 | class ListNode: 21 | def __init__(self, x): 22 | self.val = x 23 | self.next = None 24 | def __str__(self): 25 | return str(self.val) 26 | def printList(self): 27 | r, t = [], self 28 | while t: 29 | r += [t.val] 30 | t = t.next 31 | return r 32 | 33 | class equivalenceTester: 34 | def __init__(self): 35 | self.x = "" 36 | def test(self, a, b): 37 | if len(set([a, b])) == 1: 38 | return a 39 | else: 40 | return None -------------------------------------------------------------------------------- /Python/__pycache__/_DATATYPES.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kumailn/Algorithms/e6be0a0cbf0caf13a723a9edfd2df33c2234235f/Python/__pycache__/_DATATYPES.cpython-37.pyc -------------------------------------------------------------------------------- /Rust/Plus_One.rs: -------------------------------------------------------------------------------- 1 | fn plus_one(mut nums: Vec) -> std::vec::Vec { 2 | for i in (0..nums.len()).rev() { 3 | if nums[i] < 9 { 4 | nums[i] += 1; 5 | return nums; 6 | } 7 | nums[i] = 0; 8 | } 9 | let mut newnum = vec![1]; 10 | newnum.extend(nums); 11 | return newnum; 12 | } 13 | 14 | fn main(){ 15 | println!("{:?}",(plus_one([1, 3, 9].to_vec()))); 16 | } -------------------------------------------------------------------------------- /Rust/Two_Sum.rs: -------------------------------------------------------------------------------- 1 | fn two_sum(nums: Vec, target: i32) -> i32 { 2 | use std::collections::HashMap; 3 | let mut counts: HashMap = HashMap::new(); 4 | for i in 0..nums.len() { 5 | counts.insert(nums[i], i as i32); 6 | } 7 | let mut count = 0; 8 | for i in 0..nums.len() { 9 | match counts.get(&(target - nums[i])) { 10 | Some(index) if i as i32 != *index => count += 1, 11 | None => (), 12 | _ => () 13 | } 14 | } 15 | return count; 16 | } 17 | 18 | fn main(){ 19 | println!("{:?}",(two_sum([1, 3, 9, 2, 5, -2].to_vec(), 4))); 20 | } -------------------------------------------------------------------------------- /Rust/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } --------------------------------------------------------------------------------