├── LinkedList ├── Lecture 03 │ ├── Delete Node in a Linked List.py │ ├── Delete Node.cpp │ ├── Delete Node.java │ └── README.md ├── Lecture 05 │ ├── Middle of Linked List Approach 2.py │ ├── Middle of Linked List.py │ ├── Middle of a Linked List Approach 1.cpp │ ├── Middle of a Linked List Approach 1.java │ ├── Middle of a Linked List Approach 2.cpp │ ├── Middle of a Linked List Approach 2.java │ └── README.md ├── Lecture 06 │ ├── Convert Binary Number in a Linked List to Integer.py │ ├── Convert Binary Number in a LinkedList to Integer.cpp │ ├── Convert Binary Number in a LinkedList to Integer.java │ └── README.md ├── Lecture 08 │ ├── Design HashSet.cpp │ ├── Design HashSet.java │ ├── Design a Hashset.py │ └── README.md ├── Lecture 09 │ ├── Design Hash Map.py │ ├── Design HashMap.cpp │ ├── Design HashMap.java │ └── README.md ├── Lecture 10 │ ├── README.md │ ├── Reverse Linked List Approach 1.py │ ├── Reverse Linked List Approach 2.py │ ├── Reverse a Linked List Approach 1.cpp │ ├── Reverse a Linked List Approach 1.java │ ├── Reverse a Linked List Approach 2.cpp │ └── Reverse a Linked List Approach 2.java ├── Lecture 11 │ ├── README.md │ ├── Reverse Nodes in K-Group Approach 2.cpp │ ├── Reverse Nodes in K-Group Approach 2.java │ ├── Reverse Nodes in K-Group.java │ ├── Reverse Nodes in k-Group Approach 1.cpp │ ├── Reverse Nodes in k-Group Approach 1.py │ └── Reverse Nodes in k-Group Approach 2.py ├── Lecture 13 │ ├── Merge Two Sorted Lists Approach 1.cpp │ ├── Merge Two Sorted Lists Approach 1.java │ ├── Merge Two Sorted Lists Approach 1.py │ ├── Merge Two Sorted Lists Approach 2.cpp │ ├── Merge Two Sorted Lists Approach 2.java │ ├── Merge Two Sorted Lists Approach 2.py │ └── README.md ├── Lecture 14 │ ├── Merge K Sorted Lists.cpp │ ├── Merge K Sorted Lists.java │ ├── Merge K Sorted Lists.py │ └── README.md ├── Lecture 15 │ ├── README.md │ ├── Remove Duplicates from Sorted List Approach 1.cpp │ ├── Remove Duplicates from Sorted List Approach 1.java │ ├── Remove Duplicates from Sorted List Approach 1.py │ ├── Remove Duplicates from Sorted List Approach 2.cpp │ ├── Remove Duplicates from Sorted List Approach 2.java │ └── Remove Duplicates from Sorted List Approach 2.py ├── Lecture 16 │ ├── Linked List Cycle.cpp │ ├── Linked List Cycle.java │ ├── Linked List Cycle.py │ └── README.md ├── Lecture 17 │ ├── Linked List Cycle II.cpp │ ├── Linked List Cycle II.java │ ├── Linked List Cycle II.py │ └── README.md ├── Lecture 18 │ ├── Intersection of Linked list.cpp │ ├── Intersection of Linked list.java │ ├── Intersection of Linked list.py │ └── README.md ├── Lecture 19 │ ├── Palindrome Linked List.cpp │ ├── Palindrome Linked List.java │ ├── Palindrome Linked List.py │ └── README.md ├── Lecture 20 │ ├── README.md │ ├── Remove Linked List Elements Approach 1.cpp │ ├── Remove Linked List Elements Approach 1.java │ ├── Remove Linked List Elements Approach 1.py │ ├── Remove Linked List Elements Approach 2.cpp │ ├── Remove Linked List Elements Approach 2.java │ ├── Remove Linked List Elements Approach 2.py │ ├── Remove Linked List Elements Approach 3.cpp │ └── Remove Linked List Elements Approach 3.java ├── Lecture 21 │ ├── Design Browser History.cpp │ ├── Design Browser History.java │ ├── Design Browser History.py │ └── README.md ├── Lecture 22 │ ├── LRU Cache.cpp │ ├── LRU Cache.java │ ├── LRU Cache.py │ └── README.md ├── Lecture 23 │ ├── Copy List with Random Pointer.cpp │ ├── Copy List with Random Pointer.java │ ├── Copy List with Random Pointer.py │ └── README.md ├── Lecture 24 │ ├── Copy List with Random Pointer Approach 2.cpp │ ├── Copy List with Random Pointer Approach 2.py │ └── README.md └── READEME.md ├── README.md └── Recursion ├── Lecture 01 └── CodeStudio │ ├── Factorial of a Number.cpp │ ├── Factorial of a Number.java │ ├── Factorial of a Number.js │ ├── Factorial of a Number.py │ └── README.md ├── Lecture 03 ├── CodeStudio │ ├── Nth Fibnacci .py │ ├── Nth Fibnacci Number_Optimised.py │ ├── Nth Fibonacci Number.cpp │ ├── Nth Fibonacci Number.java │ └── README.md └── LeetCode │ ├── Fibonacci Number.cpp │ ├── Fibonacci Number.java │ ├── Fibonacci Number.py │ └── README.md ├── Lecture 04 ├── CodeStudio │ ├── Find power of a number.cpp │ ├── Find power of a number.java │ ├── Find power of a number.py │ └── README.md └── LeetCode │ ├── Pow(x, n).cpp │ ├── Pow(x, n).py │ └── READEME.md ├── Lecture 05 ├── CodeStudio │ ├── Check Palindrome.cpp │ ├── Check Palindrome.java │ ├── Check Palindrome.py │ └── README.md └── LeetCode │ ├── README.md │ ├── Valid Palindrome.cpp │ └── Valid Palindrome.py ├── Lecture 06 └── CodeStudio │ ├── README.md │ ├── Reverse The Array.cpp │ ├── Reverse The Array.java │ └── Reverse The Array.py ├── Lecture 07 ├── CodeStudio │ ├── Power Set.cpp │ ├── Power Set.java │ ├── Power Set.py │ └── README.md └── LeetCode │ ├── README.md │ ├── Subsets.cpp │ ├── Subsets.java │ └── Subsets.py ├── Lecture 08 ├── CodeStudio │ ├── Permutations of a String.cpp │ ├── Permutations of a String.java │ ├── Permutations of a String.py │ └── README.md └── LeetCode │ ├── Permutations II.py │ ├── Permutations.cpp │ ├── Permutations.java │ ├── Permutations.py │ └── README.md ├── Lecture 09 ├── CodeStudio │ ├── All Unique Permutations lecture code.py │ ├── All Unique Permutations.cpp │ ├── All Unique Permutations.java │ ├── All Unique Permutations_Optimised.py │ └── README.md └── LeetCode │ ├── Permutations II.cpp │ ├── Permutations II.java │ ├── Permutations II.py │ └── README.md ├── Lecture 10 ├── CodeStudio │ ├── README.md │ ├── Subsets II.cpp │ └── Subsets II.py └── LeetCode │ ├── README.md │ ├── Subsets II.cpp │ ├── Subsets II.java │ └── Subsets II.py ├── Lecture 11 ├── CodeStudio │ ├── Combinations.cpp │ ├── Combinations.java │ ├── Combinations.py │ └── README.md └── LeetCode │ ├── Combinations.cpp │ ├── Combinations.java │ ├── Combinations.py │ └── README.md ├── Lecture 12 ├── CodeStudio │ ├── Combination Sum.cpp │ ├── Combination Sum.java │ ├── Combination Sum.py │ └── README.md └── LeetCode │ ├── Combination Sum-1.cpp │ ├── Combination Sum.java │ ├── Combination Sum.py │ └── README.md ├── Lecture 13 ├── CodeStudio │ ├── Combination Sum II.cpp │ ├── Combination Sum II.java │ ├── Combination Sum-II.py │ └── README.md └── LeetCode │ ├── Combination Sum II.java │ ├── Combination Sum-2.cpp │ ├── Combination Sum-II.py │ └── README.md ├── Lecture 14 ├── CodeStudio │ ├── Combination Sum III.cpp │ ├── Combination Sum III.java │ ├── Combination Sum-III.py │ └── README.md └── LeetCode │ ├── Combination Sum III.java │ ├── Combination Sum-3.cpp │ ├── Combination Sum-III.py │ └── README.md ├── Lecture 15 ├── CodeStudio │ ├── Letter Combinations of a Phone Number.cpp │ ├── Letter Combinations of a Phone Number.java │ ├── Letter Combinations of a Phone Number.py │ └── README.md └── LeetCode │ ├── Letter Combination of a Phone Number.cpp │ ├── Letter Combinations of a Phone Number.java │ ├── Letter Combinations of a Phone Number.py │ └── README.md ├── Lecture 16 ├── CodeStudio │ ├── Partition to K equal Sum Subsets.java │ ├── Partition to K equal sum subsets.cpp │ ├── Partition to K equal sum subsets.py │ └── README.md └── LeetCode │ ├── Partition to K Equal Sum Subsets.cpp │ ├── Partition to K Equal Sum Subsets.py │ ├── Partition to K equal Sum Subsets.java │ └── README.md ├── Lecture 17 ├── CodeStudio │ ├── Maximum Length of a Concatenated String with Unique Characters.cpp │ ├── Maximum Length of a Concatenated String with Unique Characters.java │ └── README.md └── LeetCode │ ├── Max Length of a Concatenated String with Unique Characters.cpp │ ├── Maximum Length of a Concatenated String with Unique Characters.java │ └── README.md ├── Lecture 18 ├── CodeStudio │ ├── Flood Fill Algorithm.cpp │ ├── Flood Fill Algorithm.java │ └── README.md └── LeetCode │ ├── Flood Fill Algorithm.java │ ├── Flood Fill.cpp │ └── README.md ├── Lecture 19 ├── CodeStudio │ ├── README.md │ └── Word Search.cpp └── LeetCode │ ├── README.md │ └── Word Search.cpp ├── Lecture 20 └── CodeStudio │ ├── README.md │ └── Rat in a Maze.cpp └── Lecture 21 ├── CodeStudio ├── N Queens Approach 1.cpp ├── N Queens Approach 2.cpp └── README.md └── LeetCode ├── N Queens Approach 1.cpp ├── N Queens Approach 2.cpp └── README.md /LinkedList/Lecture 03/Delete Node in a Linked List.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | '''In this problem, we are given the reference to the Node which is to be deleted 8 | Since, we cannot go back to the previous Node in any way and it is guaranteed that the given Node will never be a Tail Node, 9 | Thus, we store Node -> next in temp2 and we swap the data / val of given Node with next Node, and make Node -> next point to Node -> next -> next. 10 | Lastly, we delete temp2 11 | ''' 12 | 13 | class Solution: 14 | def deleteNode(self, node): 15 | """ 16 | :type node: ListNode 17 | :rtype: void Do not return anything, modify node in-place instead. 18 | """ 19 | while node.next: #checking whether next node is None or not 20 | # if it is not None then make its value copy to current Node 21 | # In this Approach We are not using any temporary Node to copy the data 22 | node.val = node.next.val 23 | if node.next.next == None: 24 | node.next = None 25 | break 26 | node = node.next # shift the node pointing to current to current->next in each iteration 27 | 28 | 29 | ''' 30 | Time Complexity: O(1) 31 | Space Complexity: O(1) 32 | 33 | ''' 34 | 35 | -------------------------------------------------------------------------------- /LinkedList/Lecture 03/Delete Node.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | 10 | /* In this problem, we are given the reference to the Node which is to be deleted 11 | Since, we cannot go back to the previous Node in any way and it is guaranteed that the given Node will never be a Tail Node, 12 | Thus, we store Node -> next in temp2 and we swap the data / val of given Node with next Node, and make Node -> next point to Node -> next -> next. 13 | Lastly, we delete temp2 14 | */ 15 | 16 | class Solution { 17 | public: 18 | void deleteNode(ListNode* node) { 19 | 20 | // Since it's given that Last Node will Never be Tail Node, so this condition will never be true 21 | 22 | if(node -> next == NULL) 23 | delete node ; 24 | 25 | // We swap the values of Node and Node's Next Node 26 | 27 | swap(node -> val , node -> next -> val) ; 28 | 29 | // We now need to delete Node's Next Node so we store that Node's address in temp2 30 | 31 | ListNode *temp2 = node -> next ; 32 | 33 | // Lastly, we need to point Node -> next with temp2 -> next(node -> next -> next) 34 | 35 | node -> next = node -> next -> next ; 36 | 37 | delete temp2 ; 38 | 39 | } 40 | }; 41 | 42 | /* 43 | Time Complexity: O(1) 44 | Space Complexity: O(1) 45 | */ 46 | -------------------------------------------------------------------------------- /LinkedList/Lecture 03/Delete Node.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode(int x) { val = x; } 7 | * } 8 | */ 9 | 10 | 11 | // In this problem, we are given the reference to the Node which is to be deleted 12 | // Since, we cannot go back to the previous Node in any way and it is guaranteed that the given Node will never be a Tail Node 13 | 14 | class Solution { 15 | 16 | public void deleteNode(ListNode node) { 17 | 18 | // we copy the value of next node to the current node which is to be deleted. 19 | 20 | node.val=node.next.val; 21 | 22 | // After copying the value , we make the current node next to next of next of current node 23 | // Suppose Linked list is 1 2 3 4 , 2 is to be delete 24 | // First we will copy the 3 to 2 i.e new list will be 1 3 3 4 25 | // now the first 3's next will be 4 , here we can observe that 2 is deleted. 26 | 27 | node.next=node.next.next; 28 | 29 | } 30 | 31 | } 32 | /* 33 | Time Complexity: O(1) 34 | Space Complexity: O(1) 35 | */ -------------------------------------------------------------------------------- /LinkedList/Lecture 03/README.md: -------------------------------------------------------------------------------- 1 | ## 237. Delete Node in a Linked List 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/Middle of Linked List Approach 2.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | ''' 8 | In 2nd Approach, we don't need to count the Number of Nodes present inside the LinkedList 9 | We will use Two Pointers - Slow and Fast 10 | Slow will move with a Single Node every time 11 | Fast will move with a speed double that of Slow, that is, by Moving Two Nodes everytime 12 | When our Fast will be NULL or our Fast will be at the Last Node, then our Slow pointer will 13 | ''' 14 | class Solution: 15 | def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]: 16 | slow = head 17 | fast = head 18 | # We will come out of the While Loop whenever we our Fast pointer becomes NULL or our Fast pointer is pointing to the Last Node 19 | while fast != None and fast.next != None: 20 | slow = slow.next 21 | fast = fast.next.next 22 | 23 | # At the end, our Slow pointer will be pointing to the Middle of the LinkedList 24 | return slow 25 | 26 | ''' 27 | Time Complexity: O(N) { Only a Single iteration is used } 28 | Space Complexity: O(1) 29 | ''' 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/Middle of Linked List.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | ''' In 1st Approach, we will count the Number of Nodes present inside the Linked-List. 7 | Lastly, we will use another While Loop which will run till (N / 2) times. 8 | And the Node where it will stop will be our Middle of LinkedList 9 | 10 | ''' 11 | class Solution: 12 | def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]: 13 | # N will store the number of Nodes present in the Linked List 14 | n = 0 15 | # We always use a temp pointer so that our head pointer doesn't get lost 16 | temp = head 17 | while temp != None: 18 | n+=1 19 | temp = temp.next 20 | # Again we Assign head to temp for thr second iteration 21 | temp = head 22 | half = n//2 23 | # Second While Loop runs till half is greater than 0 24 | while half: 25 | temp = temp.next 26 | half-=1 27 | # At the end our temp Node will be pointing to the middle of the Linked List 28 | return temp 29 | ''' 30 | Time Complexity: O(N) { Two iterations are used } 31 | Space Complexity: O(1) 32 | ''' 33 | 34 | 35 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/Middle of a Linked List Approach 1.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | 12 | /* In 1st Approach, we will count the Number of Nodes present inside the Linked-List. 13 | Lastly, we will use another While Loop which will run till (N / 2) times. 14 | And the Node where it will stop will be our Middle of LinkedList 15 | */ 16 | 17 | class Solution { 18 | public: 19 | ListNode* middleNode(ListNode* head) { 20 | 21 | // N will store the number of Nodes present in the LinkedList 22 | 23 | int n = 0 ; 24 | 25 | // We always use a temp pointer so that our head pointer doesn't get lost 26 | 27 | ListNode *temp = head ; 28 | 29 | // In the first iteration, we count the Number of Nodes present inside the LinkedList 30 | 31 | while(temp != NULL) 32 | { 33 | n++ ; 34 | 35 | temp = temp -> next ; 36 | 37 | } 38 | 39 | // We re-assign temp to head for second iteration 40 | 41 | temp = head ; 42 | 43 | // We calculate half which is N / 2 44 | 45 | int half = n / 2 ; 46 | 47 | // Second While Loop runs till half is greater than 0 48 | 49 | while(half--) 50 | { 51 | temp = temp -> next ; 52 | 53 | } 54 | 55 | // At the end our temp Node will be pointing to the middle of the Linked List 56 | 57 | return temp ; 58 | } 59 | }; 60 | 61 | /* 62 | Time Complexity: O(N) { Two iterations are used } 63 | Space Complexity: O(1) 64 | */ 65 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/Middle of a Linked List Approach 1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | class Solution { 12 | public ListNode middleNode(ListNode head) { 13 | 14 | // N will store the number of Nodes present in the LinkedList 15 | 16 | int n=0; 17 | 18 | // We always use a temp pointer so that our head pointer doesn't get lost 19 | 20 | ListNode temp=head; 21 | 22 | // In the first iteration, we count the Number of Nodes present inside the LinkedList 23 | 24 | while(temp!=null){ 25 | 26 | n++; 27 | 28 | temp=temp.next; 29 | 30 | } 31 | // We re-assign temp to head for second iteration 32 | 33 | temp=head; 34 | 35 | // We calculate half which is N / 2 36 | 37 | int half=n/2; 38 | 39 | // Second While Loop runs till half is greater than 0 40 | 41 | while(half-->0){ 42 | 43 | temp=temp.next; 44 | 45 | } 46 | // At the end our temp Node will be pointing to the middle of the Linked List 47 | 48 | return temp; 49 | 50 | } 51 | } 52 | 53 | 54 | /* 55 | Time Complexity: O(N) { Two iterations are used } 56 | Space Complexity: O(1) 57 | */ 58 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/Middle of a Linked List Approach 2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | 12 | /* In 2nd Approach, we don't need to count the Number of Nodes present inside the LinkedList 13 | We will use Two Pointers - Slow and Fast 14 | Slow will move with a Single Node every time 15 | Fast will move with a speed double that of Slow, that is, by Moving Two Nodes everytime 16 | When our Fast will be NULL or our Fast will be at the Last Node, then our Slow pointer will be pointing to the Middle of the LinkedList 17 | */ 18 | 19 | class Solution { 20 | public: 21 | ListNode* middleNode(ListNode* head) { 22 | 23 | // Slow and Fast pointers both should be initialised with head 24 | 25 | ListNode *slow = head ; 26 | ListNode *fast = head ; 27 | 28 | // We will come out of the While Loop whenever we our Fast pointer becomes NULL or our Fast pointer is pointing to the Last Node 29 | 30 | while(fast != NULL && fast -> next != NULL) 31 | { 32 | slow = slow -> next ; 33 | 34 | fast = fast -> next -> next ; 35 | 36 | } 37 | 38 | // At the end, our Slow pointer will be pointing to the Middle of the LinkedList 39 | 40 | return slow ; 41 | 42 | } 43 | }; 44 | 45 | /* 46 | Time Complexity: O(N) { Only a Single iteration is used } 47 | Space Complexity: O(1) 48 | */ 49 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/Middle of a Linked List Approach 2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | class Solution { 12 | 13 | public ListNode middleNode(ListNode head) { 14 | 15 | // Slow and Fast pointers both should be initialised with head 16 | 17 | ListNode slow = head; 18 | ListNode fast = head; 19 | 20 | // We will come out of the while loop whenever we our Fast pointer becomes null or our fast pointer is pointing to the last node 21 | 22 | while (fast != null && fast.next != null) { 23 | slow = slow.next; 24 | fast = fast.next.next; 25 | } 26 | // At the end, our slow pointer will be pointing to the middle of the LinkedList 27 | 28 | return slow; 29 | } 30 | } 31 | /* 32 | Time Complexity: O(N) { Only a Single iteration is used } 33 | Space Complexity: O(1) 34 | */ 35 | -------------------------------------------------------------------------------- /LinkedList/Lecture 05/README.md: -------------------------------------------------------------------------------- 1 | ## 876. Middle of the Linked List 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 06/Convert Binary Number in a Linked List to Integer.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | ''' 8 | We are standing at the Head of the Linked-List consisting of only 0 and 1. We need to return the corresponding decimal number after converting the Binary Linked-List to Decimal 9 | We can do this in a single traversal only. 10 | Everytime we stand at a Node, we assume that it is the Last Node and we add it's value to our ans varible 11 | Again, when we encounter another Node, we increment all the powers of the previous Nodes by 1, that is, multiplying our ans by 2 12 | 13 | ''' 14 | class Solution: 15 | def getDecimalValue(self, head: ListNode) -> int: 16 | # ans will store our final decimal number after traversing the given LinkedList 17 | 18 | ans = 0 19 | temp = head 20 | while temp != None: 21 | # Everytime we encourage a Node, we multiply ans by 2 to increment the power of all 22 | ans*=2 23 | 24 | # we add the data presentin temp Node to our ans variable 25 | ans+=(temp.val) 26 | temp = temp.next 27 | return ans 28 | ''' 29 | Time Complexity: O(N) 30 | Space Complexity: O(1) 31 | 32 | ''' 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /LinkedList/Lecture 06/Convert Binary Number in a LinkedList to Integer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | 12 | /* We are standing at the Head of the Linked-List consisting of only 0 and 1. We need to return the corresponding decimal number after converting the Binary Linked-List to Decimal 13 | We can do this in a single traversal only. 14 | Everytime we stand at a Node, we assume that it is the Last Node and we add it's value to our ans varible 15 | Again, when we encounter another Node, we increment all the powers of the previous Nodes by 1, that is, multiplying our ans by 2 16 | */ 17 | 18 | class Solution { 19 | 20 | public: 21 | int getDecimalValue(ListNode* head) { 22 | 23 | // ans will store our Final Decimal Number after traversing the given LinkedList 24 | 25 | int ans = 0 ; 26 | 27 | // We move with temp so that it doesn't get lost 28 | 29 | ListNode *temp = head ; 30 | 31 | while(temp != NULL) 32 | { 33 | // Everytime we encounter a Node, we multiply ans by 2 to increment the power of all the previously encountered Nodes by 1 34 | 35 | ans *= 2 ; 36 | 37 | // We add the data present in temp Node to our ans variable 38 | 39 | ans += (temp -> val) ; 40 | 41 | // We move temp to the Next Node 42 | 43 | temp = temp -> next ; 44 | } 45 | 46 | // At the end, we return ans which contains our Decimal Number 47 | 48 | return ans ; 49 | } 50 | }; 51 | 52 | /* 53 | Time Complexity: O(N) 54 | Space Complexity: O(1) 55 | */ 56 | -------------------------------------------------------------------------------- /LinkedList/Lecture 06/Convert Binary Number in a LinkedList to Integer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | 12 | /* We are standing at the Head of the Linked-List consisting of only 0 and 1. We need to return the corresponding decimal number after converting the Binary Linked-List to Decimal 13 | We can do this in a single traversal only. 14 | Everytime we stand at a Node, we assume that it is the Last Node and we add it's value to our ans varible 15 | Again, when we encounter another Node, we increment all the powers of the previous Nodes by 1, that is, multiplying our ans by 2 16 | */ 17 | 18 | class Solution { 19 | 20 | public int getDecimalValue(ListNode head) { 21 | // ans will store our Final Decimal Number after traversing the given LinkedList 22 | 23 | int ans = 0; 24 | 25 | // We move with temp so that it doesn't get lost 26 | 27 | ListNode temp = head; 28 | 29 | while (temp != null) { 30 | // Everytime we encounter a Node, we multiply ans by 2 to increment the power of all the previously encountered Nodes by 1 31 | 32 | ans *= 2; 33 | 34 | // We add the data present in temp Node to our ans variable 35 | 36 | ans += temp.val; 37 | 38 | // We move temp to the Next Node 39 | 40 | temp = temp.next; 41 | } 42 | 43 | // At the end, we return ans which contains our Decimal Number 44 | 45 | return ans; 46 | } 47 | } 48 | // Time Complexity: O(N) 49 | // Space Complexity: O(1) 50 | -------------------------------------------------------------------------------- /LinkedList/Lecture 06/README.md: -------------------------------------------------------------------------------- 1 | ## 1290. Convert Binary Number in a Linked List to Integer 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 08/Design HashSet.java: -------------------------------------------------------------------------------- 1 | class MyHashSet { 2 | // We use a ArrayList of Linked List to store all our elements of HashSet Class 3 | ArrayList> list; 4 | int size = 100; 5 | 6 | public MyHashSet() { 7 | // Inside the constructor we initialise arraylist with empty linked list 8 | list = new ArrayList<>(size); 9 | for (int i = 0; i < size; i++) { 10 | list.add(new LinkedList()); 11 | } 12 | } 13 | 14 | // Our hash function simply returns the index by taking modulo with list.size() 15 | public int hash(int key) { 16 | return key % list.size(); 17 | } 18 | // search operation is being performed here 19 | public int search(int key) { 20 | int i = hash(key); 21 | 22 | LinkedList temp = list.get(i); 23 | int ans = -1; 24 | 25 | for (int j = 0; j < temp.size(); j++) { 26 | if (key == temp.get(j)) { 27 | return j; 28 | } 29 | } 30 | return ans; 31 | } 32 | //Search() function returns us the position where the key is present 33 | 34 | public void add(int key) { 35 | // If the key is already present then there is no need to add again 36 | //Otherwise , we will find the index i where we need to add our key using hash() function 37 | if (search(key) == -1) { 38 | int i = hash(key); 39 | // we add the key at the end in O(1) Time Complexity 40 | list.get(i).add(key); 41 | } 42 | } 43 | // remove method will delete the given key from our ArrayList> 44 | public void remove(int key) { 45 | if (search(key) != -1) { 46 | int i = hash(key); 47 | list.get(i).remove(Integer.valueOf(key)); 48 | } 49 | } 50 | // contains() function return true if the key is present , else it will return false 51 | public boolean contains(int key) { 52 | return search(key) != -1; 53 | } 54 | } 55 | 56 | /* 57 | Time Complexity: O(N) --> In the worst case, we need to search the entire list[i] to check if key is present 58 | Space Complexity: O(N) --> We use a ArrayList> list; to store all the Unique Keys 59 | */ 60 | 61 | 62 | 63 | /** 64 | * Your MyHashSet object will be instantiated and called as such: 65 | * MyHashSet obj = new MyHashSet(); 66 | * obj.add(key); 67 | * obj.remove(key); 68 | * boolean param_3 = obj.contains(key); 69 | */ -------------------------------------------------------------------------------- /LinkedList/Lecture 08/Design a Hashset.py: -------------------------------------------------------------------------------- 1 | ''' 2 | We need to design a HashSet Class which contains only Unique Values like any HashSet Class. 3 | Our HashSet class contains the following operations: 4 | a) void add(int key) --> Adds an element into the HashSet 5 | b) void remove(int key) --> Removes the key element from the HashSet 6 | c) bool contains(int key) --> Returns true if key is present in our HashSet else returns false 7 | 8 | Instead of using unneccessary space, we can use limited space by using the concept of Hashing & Chaining 9 | We require chaining to prevent collisions in our HashSet 10 | 11 | ''' 12 | 13 | 14 | class MyHashSet: 15 | # We Use a list to store all our elements of Hashset Class 16 | 17 | def __init__(self): 18 | self.L = [] 19 | 20 | 21 | def add(self, key: int) -> None: 22 | # add() function adds the given Key into our Hash List at the index specified by our hash() function 23 | # If the key is already present, we don't need to add it again 24 | if key in self.L: 25 | pass 26 | # Otherwise, we will find the index i where we need to add our key using hash() function 27 | else: 28 | # We add the key at the end in O(1) Time Complexity so we appended it to list 29 | self.L.append(key) 30 | 31 | # remove() function deletes the given Key from our List L 32 | def remove(self, key: int) -> None: 33 | # Firstly, we need to check whether our key is present inside our List. If the key is not present, we cannot delete it, thus we directly return 34 | try: 35 | self.L.remove(key) 36 | except: 37 | pass 38 | 39 | 40 | # contains() function returns true if the key is present else returns false 41 | def contains(self, key: int) -> bool: 42 | return key in self.L 43 | 44 | 45 | 46 | # Your MyHashSet object will be instantiated and called as such: 47 | # obj = MyHashSet() 48 | # obj.add(key) 49 | # obj.remove(key) 50 | # param_3 = obj.contains(key) 51 | """" 52 | Time Complexity: O(N) --> In the worst case, we need to search the entire m[i] to check if key is present 53 | Space Complexity: O(N) --> We use a vector> to store all the Unique Keys 54 | 55 | """ 56 | -------------------------------------------------------------------------------- /LinkedList/Lecture 08/README.md: -------------------------------------------------------------------------------- 1 | ## 705. Design HashSet 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 09/README.md: -------------------------------------------------------------------------------- 1 | ## 706. Design HashMap 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/README.md: -------------------------------------------------------------------------------- 1 | ## 206. Reverse Linked List 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/Reverse Linked List Approach 1.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | ''' 8 | To reverse a LinkedList iteratively, we require 3 pointers - Previous(p) , Current(c) and Next(n) 9 | Previous pointer will be initially pointing to NULL 10 | Current pointer will be intially pointing to head 11 | Next pointer will be initally pointing to head -> next 12 | Our While Loop runs till our Current Pointer becomes NULL 13 | Everytime we will make Current Pointer's next point to Previous Pointer 14 | And then move Previous to Current , Current to Next and Next to it's Next Node(if it exists) 15 | 16 | ''' 17 | class Solution: 18 | def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: 19 | # If head is Equal to None, we don't have a LinkedList to reverse, so we directly return None 20 | if head == None: 21 | return None 22 | # Previous variable(p) initially points to None 23 | p = None 24 | # Current variable(c) initially points to head 25 | c = head 26 | 27 | # Next refrence variable(n) initally points to head -> next 28 | 29 | n = head.next 30 | 31 | #Our Loop runs till Current becomes Not Equal to None 32 | while c is not None: 33 | c.next = p 34 | # We move Previous to Current 35 | p = c 36 | # Current moves to Next 37 | c = n 38 | # Next refrence variable to it's next node 39 | if n != None: 40 | n = n.next 41 | 42 | 43 | 44 | return p 45 | 46 | """ 47 | Time Complexity: O(N) 48 | Space Complexity: O(1) 49 | """ 50 | 51 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/Reverse Linked List Approach 2.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | """ 8 | To reverse a LinkedList recursively, we need to design a Recursive function reverse(head) which takes the head of the Head of the intial LinkedList and returns the Head of the Reversed LinkedList 9 | We will just reverse Two Nodes & ask recursion to do rest of the Task 10 | We will just change Reverse Two Nodes: head and the Node next to head 11 | To reverse, we will make head -> next -> next to point to head 12 | After that, we will return the Reversed-Head given to us by LinkedList 13 | We will stop when we are at the Last Node because a Single Node cannot be Reversed 14 | 15 | 16 | """ 17 | class Solution: 18 | def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: 19 | def reverse(head): 20 | # Base Condition 21 | if head.next == None: 22 | return head 23 | 24 | # Ask Recursion to return head 25 | reverseHead = reverse(head.next) 26 | # Reverse the Adjascent Nodes that is, Head & Head's next Node 27 | head.next.next = head 28 | head.next = None 29 | 30 | # Returns the Reversed Head at the end 31 | return reverseHead 32 | # If head is Equal to NULL, we don't have a LinkedList to reverse, so we directly return NULL 33 | if head == None: 34 | return None 35 | # Otherwise we return the Reversed-Head given to us by the Recursive function reverse() 36 | return reverse(head) 37 | 38 | 39 | """ 40 | Time Complexity: O(N) 41 | Space Complexity: O(N) { Auxillary Stack Space of Recursion } 42 | 43 | """ 44 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/Reverse a Linked List Approach 1.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | 12 | /* To reverse a LinkedList iteratively, we require 3 pointers - Previous(p) , Current(c) and Next(n) 13 | Previous pointer will be initially pointing to NULL 14 | Current pointer will be intially pointing to head 15 | Next pointer will be initally pointing to head -> next 16 | Our While Loop runs till our Current Pointer becomes NULL 17 | Everytime we will make Current Pointer's next point to Previous Pointer 18 | And then move Previous to Current , Current to Next and Next to it's Next Node(if it exists) 19 | */ 20 | 21 | class Solution { 22 | public: 23 | ListNode* reverseList(ListNode* head) { 24 | 25 | // If head is Equal to NULL, we don't have a LinkedList to reverse, so we directly return NULL 26 | 27 | if(head == NULL) 28 | return NULL ; 29 | 30 | // Previous pointer(p) initially points to NULL 31 | 32 | ListNode *p = NULL ; 33 | 34 | // Current pointer(c) initially points to head 35 | 36 | ListNode *c = head ; 37 | 38 | // Next pointer(n) initally points to head -> next 39 | 40 | ListNode *n = head -> next ; 41 | 42 | // Our Loop runs till Current Pointer becomes Not Equal to NULL 43 | 44 | while(c != NULL) 45 | { 46 | // We reverse the Nodes by making Current's next point to Previous 47 | 48 | c -> next = p ; 49 | 50 | // We move Previous to Current Pointer 51 | 52 | p = c ; 53 | 54 | // Current moves to Next Pointer 55 | 56 | c = n ; 57 | 58 | // Next Pointer to it's Next Node(if it exists) 59 | 60 | if(n != NULL) 61 | n = n -> next ; 62 | 63 | } 64 | 65 | // At the end, our Previous Pointer will be the Head of the Reversed LinkedList 66 | 67 | return p ; 68 | } 69 | }; 70 | 71 | /* 72 | Time Complexity: O(N) 73 | Space Complexity: O(1) 74 | */ 75 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/Reverse a Linked List Approach 1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | 12 | /* To reverse a LinkedList iteratively, we require 3 pointers - Previous(p) , Current(c) and Next(n) 13 | Previous pointer will be initially pointing to null 14 | Current pointer will be intially pointing to head 15 | Next pointer will be initally pointing to head.next 16 | Our while loop runs till our Current Pointer becomes NULL 17 | Everytime we will make Current Pointer's next point to Previous Pointer 18 | And then move Previous to Current , Current to Next and Next to it's Next Node(if it exists) 19 | */ 20 | 21 | class Solution { 22 | 23 | public ListNode reverseList(ListNode head) { 24 | 25 | // If head is Equal to null, we don't have a LinkedList to reverse, so we directly return null 26 | 27 | if (head == null) { 28 | return null; 29 | } 30 | // Previous pointer(p) initially points to null 31 | 32 | ListNode p = null; 33 | 34 | // Current pointer(c) initially points to head 35 | 36 | ListNode c = head; 37 | 38 | // Next pointer(n) initally points to head.next 39 | 40 | ListNode n = head.next; 41 | 42 | // Our loop runs till Current Pointer becomes not equal to null 43 | 44 | while (c != null) { 45 | 46 | // We reverse the Nodes by making Current's next pointer to Previous 47 | 48 | c.next = p; 49 | // We move Previous to Current Pointer 50 | 51 | p = c; 52 | // Current moves to Next Pointer 53 | 54 | c = n; 55 | // Next Pointer to it's Next Node(if it exists) 56 | 57 | if (n != null) { 58 | n = n.next; 59 | } 60 | } 61 | // At the end, our Previous Pointer will be the Head of the Reversed LinkedList 62 | 63 | return p; 64 | } 65 | } 66 | /* 67 | Time Complexity: O(N) 68 | Space Complexity: O(1) 69 | */ 70 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/Reverse a Linked List Approach 2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | 12 | /* To reverse a LinkedList recursively, we need to design a Recursive function reverse(head) which takes the head of the Head of the intial LinkedList and returns the Head of the Reversed LinkedList 13 | We will just reverse Two Nodes & ask recursion to do rest of the Task 14 | We will just change Reverse Two Nodes: head and the Node next to head 15 | To reverse, we will make head -> next -> next to point to head 16 | After that, we will return the Reversed-Head given to us by LinkedList 17 | We will stop when we are at the Last Node because a Single Node cannot be Reversed 18 | */ 19 | 20 | class Solution { 21 | 22 | private: 23 | 24 | ListNode *reverse(ListNode *head) 25 | { 26 | // Base Condition 27 | 28 | if(head -> next == NULL) 29 | return head ; 30 | 31 | // Ask recursion to return the Reversed Head 32 | 33 | ListNode *reverseHead = reverse(head -> next) ; 34 | 35 | // Reverse the Adjacent Nodes that is, Head & Head's Next Node 36 | 37 | head -> next -> next = head ; 38 | 39 | head -> next = NULL ; 40 | 41 | // Return the Reversed Head at the end 42 | 43 | return reverseHead ; 44 | } 45 | public: 46 | ListNode* reverseList(ListNode* head) { 47 | 48 | // If head is Equal to NULL, we don't have a LinkedList to reverse, so we directly return NULL 49 | 50 | if(head == NULL) 51 | return NULL ; 52 | 53 | // Otherwise we return the Reversed-Head given to us by the Recursive function reverse() 54 | 55 | return reverse(head) ; 56 | } 57 | }; 58 | 59 | /* 60 | Time Complexity: O(N) 61 | Space Complexity: O(N) { Auxillary Stack Space of Recursion } 62 | */ 63 | -------------------------------------------------------------------------------- /LinkedList/Lecture 10/Reverse a Linked List Approach 2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | 12 | /* To reverse a LinkedList recursively, we need to design a Recursive function reverse(head) which takes the head of the Head of the intial LinkedList and returns the Head of the Reversed LinkedList 13 | We will just reverse Two Nodes & ask recursion to do rest of the Task 14 | We will just change Reverse Two Nodes: head and the Node next to head 15 | To reverse, we will make head.next.next to point to head 16 | After that, we will return the Reversed-Head given to us by LinkedList 17 | We will stop when we are at the Last Node because a Single Node cannot be Reversed 18 | */ 19 | 20 | class Solution { 21 | 22 | private ListNode reverse(ListNode head) { 23 | // Base Condition 24 | 25 | if (head.next == null) { 26 | return head; 27 | } 28 | // Ask recursion to return the Reversed Head 29 | // Have Faith 30 | 31 | ListNode reverseHead = reverse(head.next); 32 | 33 | // Reverse the Adjacent Nodes that is, Head & Head's Next Node 34 | 35 | head.next.next = head; 36 | head.next = null; 37 | 38 | // Return the Reversed Head at the end 39 | 40 | return reverseHead; 41 | } 42 | 43 | public ListNode reverseList(ListNode head) { 44 | 45 | // If head is Equal to null, we don't have a LinkedList to reverse, so we directly return NULL 46 | 47 | if (head == null) { 48 | 49 | return null; 50 | 51 | } 52 | 53 | // Otherwise we return the Reversed-Head given to us by the Recursive function reverse() 54 | 55 | return reverse(head); 56 | } 57 | } 58 | /* 59 | Time Complexity: O(N) 60 | Space Complexity: O(N) { Auxillary Stack Space of Recursion } 61 | */ 62 | -------------------------------------------------------------------------------- /LinkedList/Lecture 11/README.md: -------------------------------------------------------------------------------- 1 | ## 25. Reverse Nodes in k-Group 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 13/README.md: -------------------------------------------------------------------------------- 1 | ## 21. Merge Two Sorted Lists 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 14/Merge K Sorted Lists.py: -------------------------------------------------------------------------------- 1 | from queue import PriorityQueue 2 | """ 3 | In Python A library named Queue Provides already standard implemented Priority Queue under in PriorityQueue Module 4 | 5 | The optimised approach of the problem - Merge K Sorted Lists, involves the usage of Min-Heap 6 | 7 | At the begining, we will be storing only K Elements, into our Min-Heap. 8 | We will also have a dummy Node to keep track of the Head of our Merged LinkedList. 9 | Tail pointer will intially point to dummy but keeps on Nodes in order to form the Merged K Sorted LinkedList 10 | After adding first K Elements, we will use a While Loop which runs till our Priority-Queue has not become empty. 11 | Everytime, we will pick the Top Element from the Priority-Queue(which will also be smallest among all K Nodes present). We will make Tail's Next point to that Top Node. Make Tail shift to that Node. And, also add it's Next Node(if it exists) 12 | By repeating the process, we will have our Merged K Sorted LinkedList ready. The Head of that LinkedList will be pointed by Dummy's Next 13 | 14 | 15 | 16 | """ 17 | class Solution: 18 | def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: 19 | pq = PriorityQueue() 20 | 21 | for node in lists: 22 | if node: 23 | pq.put((node.val, id(node), node)) 24 | 25 | """ Two Dummy nodes have been created """ 26 | dummy = ListNode(val=-1) 27 | tail = dummy 28 | 29 | # Loop till Our Prorrity Queue is not Empty 30 | while not pq.empty(): 31 | #Fetch the top most value of the Priority Queue 32 | val, _id, node = pq.get() 33 | tail.next = ListNode(val=val) 34 | # Now move tail tail->next 35 | tail = tail.next 36 | 37 | """ We enter Temp's Next Node into our Priority-Queue if it exists """ 38 | if node.next: 39 | pq.put((node.next.val, id(node.next), node.next)) 40 | 41 | # At the End we return the dummy's next which contains the head address 42 | 43 | return dummy.next 44 | """ 45 | Time Complexity: O(N*LogK) 46 | Space Complexity: O(K) 47 | 48 | 49 | """ 50 | -------------------------------------------------------------------------------- /LinkedList/Lecture 14/README.md: -------------------------------------------------------------------------------- 1 | ## 23. Merge k Sorted Lists 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 15/README.md: -------------------------------------------------------------------------------- 1 | ## 83. Remove Duplicates from Sorted List 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 15/Remove Duplicates from Sorted List Approach 1.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | /* In Approach - 1, we will be discussing the Recursive Solution to remove Duplicates from Sorted LinkedList. 12 | We will check for the values of pointed by Head and Head's Next pointer. 13 | If their values match, then we don't need to include Head in our LinkedList 14 | Otherwise, if the values don't match, then we make Head's Next point to the New-Head pointer given to us by Recursion. 15 | If at any moment our Head has become NULL or our Head's Next is pointing to NULL, that is, we are standing on the Last Node, in that scenario, we will simoly return Head without moving further 16 | */ 17 | 18 | class Solution { 19 | public: 20 | ListNode* deleteDuplicates(ListNode* head) { 21 | 22 | // If our Head is NULL , OR , Head's Next is pointing to NULL, we then directly return Head 23 | 24 | if(head == NULL || head -> next == NULL) 25 | return head ; 26 | 27 | // We ask Recursion to remove all Duplicates starting from Head's Next 28 | 29 | ListNode *newHead = deleteDuplicates(head -> next) ; 30 | 31 | // If the values pointed by Head and newHead(given to us by Recursion) are same, we don't need to add Head into our new Sorted LinkedList without any Duplicates, so we directly return newHead 32 | 33 | if(head -> val == newHead -> val) 34 | return newHead ; 35 | 36 | // Otherwise, their values don't match, so we need to include Head into our Linkedlist. So we make Head's Next point oto newHead and we return head 37 | 38 | else 39 | { 40 | head -> next = newHead ; 41 | 42 | return head ; 43 | } 44 | 45 | } 46 | }; 47 | 48 | /* 49 | Time Complexity: O(N) { N is the Number of Nodes present in Linkedlist } 50 | Space Complexity: O(N) { Auxillary Recursive Stack Space } 51 | */ 52 | -------------------------------------------------------------------------------- /LinkedList/Lecture 15/Remove Duplicates from Sorted List Approach 1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | class Solution { 12 | public ListNode deleteDuplicates(ListNode head) { 13 | 14 | // If our Head is null , OR , Head's Next is pointing to NULL, we then directly return Head 15 | 16 | if(head==null || head.next==null){ 17 | return head; 18 | } 19 | 20 | // We ask Recursion to remove all Duplicates starting from Head's Next 21 | 22 | ListNode newHead=deleteDuplicates(head.next); 23 | 24 | // If the values pointed by Head and newHead(given to us by Recursion) are same, we don't need to add Head into our new Sorted LinkedList without any Duplicates, so we directly return newHead 25 | 26 | if(head.val==newHead.val){ 27 | 28 | return newHead; 29 | } 30 | 31 | // Otherwise, their values don't match, so we need to include Head into our Linkedlist. So we make Head's Next point oto newHead and we return head 32 | 33 | 34 | else{ 35 | 36 | head.next=newHead; 37 | 38 | return head; 39 | } 40 | 41 | } 42 | } 43 | 44 | /* 45 | Time Complexity: O(N) { N is the Number of Nodes present in Linkedlist } 46 | Space Complexity: O(N) { Auxillary Recursive Stack Space } 47 | */ 48 | -------------------------------------------------------------------------------- /LinkedList/Lecture 15/Remove Duplicates from Sorted List Approach 1.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | """ 8 | In Approach - 1, we will be discussing the Recursive Solution to remove Duplicates from Sorted LinkedList. 9 | We will check for the values of pointed by Head and Head's Next pointer. 10 | If their values match, then we don't need to include Head in our LinkedList 11 | Otherwise, if the values don't match, then we make Head's Next point to the New-Head pointer given to us by Recursion. 12 | If at any moment our Head has become NULL or our Head's Next is pointing to NULL, that is, we are standing on the Last Node, in that scenario, we will simoly return Head without moving further 13 | 14 | """ 15 | class Solution: 16 | def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: 17 | 18 | # if our head is None or Head's Next is poinitng to None,we then dierectly return Head 19 | if head == None or head.next == None: 20 | return head 21 | 22 | """ We ask Recursion to remove all duplicates starting from Head's next""" 23 | newHead = self.deleteDuplicates(head.next) 24 | # If the values pointed by Head and newHead(given to us by Recursion) are same, we don't need to add Head into our new Sorted LinkedList without any Duplicates, so we directly return newHead 25 | if head.val == newHead.val: 26 | return newHead 27 | else: # Otherwise, their values don't match, so we need to include Head into our Linkedlist 28 | head.next = newHead 29 | return head 30 | 31 | """ 32 | Time Complexity: O(N) { N is the Number of Nodes present in Linkedlist } 33 | Space Complexity: O(N) { Auxillary Recursive Stack Space } 34 | 35 | 36 | """ 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /LinkedList/Lecture 15/Remove Duplicates from Sorted List Approach 2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | class Solution { 12 | public ListNode deleteDuplicates(ListNode head) { 13 | 14 | // If Head is null , OR , Head's Next is null , that is, we have only One Node, in that case, we directly return Head 15 | 16 | if(head==null || head.next==null){ 17 | return head; 18 | } 19 | 20 | // Otherwise, we store Head into our Temp Node 21 | 22 | ListNode temp=head; 23 | 24 | // Our While Loop runs till Temp's Next doesn't become NULL 25 | 26 | while(temp.next!=null){ 27 | 28 | // If the value of Two Adjacent Nodes are same, we simply Delete Temp's Next Node 29 | 30 | if(temp.val==temp.next.val){ 31 | 32 | // We store Temp's Next Node into a Del reference 33 | ListNode del=temp.next; 34 | 35 | // We make Temp's Next point to Del's Next 36 | 37 | temp.next=del.next; 38 | 39 | // But our Temp Pointer moves only when values pointed by Temp & Temp's Next are different 40 | 41 | }else{ 42 | temp=temp.next; 43 | } 44 | } 45 | 46 | // At the end, we return Head pointing to the Head of the LinkedList 47 | 48 | 49 | return head; 50 | 51 | } 52 | } 53 | 54 | /* 55 | Time Complexity: O(N) { N is the Number of Nodes present in Linkedlist } 56 | Space Complexity: O(1) 57 | */ 58 | -------------------------------------------------------------------------------- /LinkedList/Lecture 15/Remove Duplicates from Sorted List Approach 2.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | """ 8 | In Approach - 2, we will be discussing the Iterative Solution to remove Duplicates from Sorted LinkedList. 9 | In the iterative solution, we will using Temp pointer to iterate over the entire LinkedList. And we will stop whenever our Temp's Next become NULL, that is, we are standing at the Last Node of the LinkedList 10 | 11 | We will check if the values of adjacent nodes , that is , value pointed by Temp & value pointed by Temp's Next are same or not. 12 | If they are same, we will store Temp's Next Node in a Del pointer. And we make Temp's Next point to Del's Next. (If you have any issue understanding this part, please refer to the Lecture's Video or Article) 13 | And we will delete the Del Node. 14 | If the values are not same, in that part, we just need to move Temp to Temp's Next 15 | 16 | """ 17 | class Solution: 18 | def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: 19 | 20 | # if head is None or Head's next is Noneso in that case return head 21 | if head == None or head.next == None: 22 | return head 23 | # Otherwise store Head into our temp Node 24 | temp = head 25 | # Our while Loop runs till Temp's next node does not became None 26 | 27 | while temp.next != None: 28 | # If the value of Two Adjacent Nodes are same, we simply Delete Temp's Next Node 29 | if temp.val == temp.next.val: 30 | # WE store temp's next Node into a del variable 31 | Del = temp.next 32 | # we make temp's next point Del's next 33 | temp.next = Del.next 34 | # we simply delete Del Node 35 | del Del 36 | 37 | # But our Temp Pointer moves only when values pointed by Temp & Temp's Next are different 38 | else: 39 | temp = temp.next 40 | # at the end we return head of the linked list 41 | 42 | return head 43 | 44 | """ 45 | Time Complexity: O(N) { N is the Number of Nodes present in Linkedlist } 46 | Space Complexity: O(1) 47 | 48 | """ 49 | -------------------------------------------------------------------------------- /LinkedList/Lecture 16/Linked List Cycle.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | 10 | /* To detect LinkedList Cycle, we will use the concept of Slow and Fast pointer. 11 | We will make our Fast Pointer move with a Speed twice to that of our Slow Pointer. 12 | If there's a Cycle in the LinkedList, then eventually our Fast Pointer will catch our Slow pointer. 13 | Otherwise, if there's no Cycle in the LinkedList, we come out of the While Loop and return false 14 | */ 15 | 16 | class Solution { 17 | public: 18 | bool hasCycle(ListNode *head) { 19 | 20 | // Initally, both Fast and Slow pointer will point to Head 21 | 22 | ListNode *fast = head ; 23 | ListNode *slow = head ; 24 | 25 | // While Loop runs till our Fast Pointer doesn't become NULL or our Fast pointer doesn't point to the Last Node of the LinkedList 26 | 27 | while(fast != NULL && fast -> next != NULL) 28 | { 29 | // Slow pointer will move by a Single Node everytime 30 | 31 | slow = slow -> next ; 32 | 33 | // Fast Pointer will move with a speed twice to that of Slow Pointer 34 | 35 | fast = fast -> next -> next ; 36 | 37 | // If there's a Cycle in the LinkedList, then Fast and Slow pointer will eventually meet 38 | 39 | if(fast == slow) 40 | return true ; 41 | } 42 | 43 | // If we come out of the While Loop, it implies there's no Cycle present in the LinkedList, so we return false 44 | 45 | return false ; 46 | } 47 | }; 48 | 49 | /* 50 | Time Complexity: O(N) 51 | Space Complexity: O(1) 52 | */ 53 | -------------------------------------------------------------------------------- /LinkedList/Lecture 16/Linked List Cycle.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode(int x) { 7 | * val = x; 8 | * next = null; 9 | * } 10 | * } 11 | */ 12 | 13 | 14 | /* To detect LinkedList Cycle, we will use the concept of Slow and Fast pointer. 15 | We will make our Fast Pointer move with a Speed twice to that of our Slow Pointer. 16 | If there's a Cycle in the LinkedList, then eventually our Fast Pointer will catch our Slow pointer. 17 | Otherwise, if there's no Cycle in the LinkedList, we come out of the While Loop and return false 18 | */ 19 | 20 | public class Solution { 21 | public boolean hasCycle(ListNode head) { 22 | 23 | // Initally, both Fast and Slow pointer will point to Head 24 | 25 | ListNode fast=head; 26 | ListNode slow=head; 27 | 28 | // While Loop runs till our Fast Pointer doesn't become null or our Fast pointer doesn't point to the Last Node of the LinkedList 29 | 30 | // fast!=null for even length linked list 31 | // fast.next for odd length linked list 32 | 33 | while(fast!=null && fast.next!=null){ 34 | 35 | // Slow pointer will move by a Single Node everytime 36 | 37 | slow=slow.next; 38 | 39 | // Fast Pointer will move with a speed twice to that of Slow Pointer 40 | 41 | fast=fast.next.next; 42 | 43 | // If there's a Cycle in the LinkedList, then Fast and Slow pointer will eventually meet 44 | 45 | if(fast==slow){ 46 | return true; 47 | } 48 | } 49 | 50 | // If we come out of the While Loop, it implies there's no Cycle present in the LinkedList, so we return false 51 | 52 | return false; 53 | 54 | } 55 | } 56 | 57 | /* 58 | Time Complexity: O(N) 59 | Space Complexity: O(1) 60 | */ 61 | -------------------------------------------------------------------------------- /LinkedList/Lecture 16/Linked List Cycle.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | 8 | """ 9 | To detect LinkedList Cycle, we will use the concept of Slow and Fast pointer. 10 | We will make our Fast Pointer move with a Speed twice to that of our Slow Pointer. 11 | If there's a Cycle in the LinkedList, then eventually our Fast Pointer will catch our Slow pointer. 12 | Otherwise, if there's no Cycle in the LinkedList, we come out of the While Loop and return false 13 | 14 | """ 15 | 16 | class Solution: 17 | def hasCycle(self, head: Optional[ListNode]) -> bool: 18 | # Initailly , both fast and slow pointer will point to head 19 | fast = head 20 | slow = head 21 | 22 | # While Loop runs till our fst pointer does nnot None or Our Fst pointer Does not point to last node if linked list 23 | 24 | while fast != None and fast.next != None: 25 | # slow pointer will move by a single node everytime 26 | slow = slow.next 27 | 28 | # fast will move speed twicw that of slow pointer 29 | fast = fast.next.next 30 | 31 | # If there's a Cycle in the LinkedList, then Fast and Slow pointer will eventually meet 32 | 33 | if fast == slow: 34 | return True 35 | return False 36 | 37 | """ 38 | Time Complexity: O(N) 39 | Space Complexity: O(1) 40 | 41 | """ 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LinkedList/Lecture 16/README.md: -------------------------------------------------------------------------------- 1 | ## 141. Linked List Cycle 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 17/Linked List Cycle II.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | /* This question is exactly similar to the Linked List Cycle I. Only difference is that in this problem we need to find the Node from where the cycle begins. 10 | But our apporach remains same. We will use 2 pointers - slow & fast where fast moves with a speed double the speed of slow. 11 | If slow and fast meet, then the LinkedList definetly contains a Cycle. 12 | To find the starting point of tat Cycle, we will use 2 pointers again- ptr1 & ptr2 13 | Ptr1 will start from the Head of the LinkedList, while ptr2 will start from the Slow pointer 14 | Both ptr1 & ptr2 will move at the same time. The point where ptr1 & ptr2 meets is the Required Node 15 | */ 16 | 17 | class Solution { 18 | public: 19 | ListNode *detectCycle(ListNode *head) { 20 | 21 | // Intially, Slow & Fast pointer both will start from Head of the LinkedList 22 | 23 | ListNode *slow = head ; 24 | ListNode *fast = head ; 25 | 26 | while(fast != NULL && fast -> next != NULL) 27 | { 28 | slow = slow -> next ; 29 | 30 | // Fast Pointer moves with a speed double that speed of Slow pointer 31 | 32 | fast = fast -> next -> next ; 33 | 34 | // If Slow & Fast pointer meets, then there's a Cycle in the LinkedList 35 | 36 | if(slow == fast) 37 | break ; 38 | } 39 | 40 | // If our Fast becomes NULL or our Fast's Next Node is NULL, it means there's No Loop in the LinkedList 41 | 42 | if(fast == NULL || fast -> next == NULL) 43 | return NULL ; 44 | 45 | // To find the starting point of the Loop, ptr1 starts from head while ptr2 starts from slow 46 | 47 | ListNode *ptr1 = head ; 48 | ListNode *ptr2 = slow ; 49 | 50 | while(ptr1 != ptr2) 51 | { 52 | // Ptr1 & Ptr2 moves with the same speed 53 | 54 | ptr1 = ptr1 -> next ; 55 | ptr2 = ptr2 -> next ; 56 | } 57 | 58 | // At the end, both Ptr1 or Ptr2 will point to the starting Node of the LinkedList Cycle / Loop 59 | 60 | return ptr1 ; 61 | 62 | } 63 | }; 64 | 65 | /* 66 | Time Complexity: O(N) 67 | Space Complexity: O(1) 68 | */ 69 | -------------------------------------------------------------------------------- /LinkedList/Lecture 17/Linked List Cycle II.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode(int x) { 7 | * val = x; 8 | * next = null; 9 | * } 10 | * } 11 | */ 12 | 13 | /* This question is exactly similar to the Linked List Cycle I. Only difference is that in this problem we need to find the Node from where the cycle begins. 14 | But our apporach remains same. We will use 2 pointers - slow & fast where fast moves with a speed double the speed of slow. 15 | If slow and fast meet, then the LinkedList definetly contains a Cycle. 16 | To find the starting point of tat Cycle, we will use 2 pointers again- ptr1 & ptr2 17 | Ptr1 will start from the Head of the LinkedList, while ptr2 will start from the Slow pointer 18 | Both ptr1 & ptr2 will move at the same time. The point where ptr1 & ptr2 meets is the Required Node 19 | */ 20 | 21 | public class Solution { 22 | public ListNode detectCycle(ListNode head) { 23 | 24 | // Intially, Slow & Fast pointer both will start from Head of the LinkedList 25 | 26 | ListNode slow=head; 27 | ListNode fast=head; 28 | 29 | while(fast!=null && fast.next!=null){ 30 | 31 | slow=slow.next; 32 | 33 | // Fast Pointer moves with a speed double that speed of Slow pointer 34 | 35 | fast=fast.next.next; 36 | 37 | // If Slow & Fast pointer meets, then there's a Cycle in the LinkedList 38 | 39 | if(slow==fast){ 40 | break; 41 | } 42 | } 43 | 44 | // If our Fast becomes NULL or our Fast's Next Node is NULL, it means there's No Loop in the LinkedList 45 | 46 | if(fast==null || fast.next==null){ 47 | return null; 48 | } 49 | 50 | // To find the starting point of the Loop, ptr1 starts from head while ptr2 starts from slow 51 | 52 | ListNode ptr1=head; 53 | ListNode ptr2=slow; 54 | 55 | while(ptr1!=ptr2){ 56 | 57 | // Ptr1 & Ptr2 moves with the same speed 58 | 59 | ptr1=ptr1.next; 60 | 61 | ptr2=ptr2.next; 62 | 63 | } 64 | 65 | // At the end, both Ptr1 or Ptr2 will point to the starting Node of the LinkedList Cycle / Loop 66 | 67 | 68 | return ptr1; 69 | } 70 | 71 | } 72 | 73 | /* 74 | Time Complexity: O(N) 75 | Space Complexity: O(1) 76 | */ 77 | -------------------------------------------------------------------------------- /LinkedList/Lecture 17/Linked List Cycle II.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | """ 8 | This question is exactly similar to the Linked List Cycle I. Only difference is that in this problem we need to find the Node from where the cycle begins. 9 | But our apporach remains same. We will use 2 pointers - slow & fast where fast moves with a speed double the speed of slow. 10 | If slow and fast meet, then the LinkedList definetly contains a Cycle. 11 | To find the starting point of tat Cycle, we will use 2 pointers again- ptr1 & ptr2 12 | Ptr1 will start from the Head of the LinkedList, while ptr2 will start from the Slow pointer 13 | Both ptr1 & ptr2 will move at the same time. The point where ptr1 & ptr2 meets is the Required Node 14 | 15 | """ 16 | 17 | 18 | class Solution: 19 | def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: 20 | 21 | # Intially, Slow & Fast pointer both will start from Head of the LinkedList 22 | slow = head 23 | fast = head 24 | 25 | # Loop till Fast or Fast's next not None 26 | while fast != None and fast.next != None: 27 | slow = slow.next 28 | 29 | # Fast pointer moves with speed double that of slow pointer 30 | fast = fast.next.next 31 | 32 | # if slow and Fast pointer meets, then there's a Cycle in the LinkedList 33 | 34 | if slow == fast: 35 | break 36 | 37 | # If our Fast becomes NULL or our Fast's Next Node is NULL, it means there's No Loop in the LinkedList 38 | if fast == None or fast.next == None: 39 | return None 40 | # To find the starting point of the Loop, ptr1 starts from head while ptr2 starts from slow 41 | ptr1 = head 42 | ptr2 = slow 43 | 44 | while ptr1 != ptr2: 45 | 46 | # ptr1 and ptr2 moves with same speed 47 | ptr1 = ptr1.next 48 | ptr2 = ptr2.next 49 | 50 | # At the end, both Ptr1 or Ptr2 will point to the starting Node of the LinkedList Cycle / Loop 51 | return ptr1 52 | 53 | """ 54 | Time Complexity: O(N) 55 | Space Complexity: O(1) 56 | 57 | """ 58 | 59 | -------------------------------------------------------------------------------- /LinkedList/Lecture 17/README.md: -------------------------------------------------------------------------------- 1 | ## 142. Linked List Cycle II 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 18/Intersection of Linked list.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | /* To get the Intersection of Two LinkedLists, we will use Two pointers A & B which will initallly point to HeadA & HeadB respetively 10 | To get the intersection point, we will simply run a While Loop. The While Loop runs A is not equal to B. 11 | And at any moment, if A becomes NULL, we make A point to HeadB 12 | Similarly, at any moment, if B becomes NULL, we make B point to HeadA 13 | In this way, we can get the Intersection point of Two LinkedLists 14 | */ 15 | 16 | class Solution { 17 | public: 18 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 19 | 20 | // Initally, both A & B points to HeadA & HeadB respectively 21 | 22 | ListNode *a = headA ; 23 | ListNode *b = headB ; 24 | 25 | while(a != b) 26 | { 27 | // If A has become NULL, we assign it to HeadB 28 | 29 | if(a == NULL) 30 | a = headB ; 31 | 32 | // Else we move A to it's Next Node 33 | 34 | else 35 | a = a -> next ; 36 | 37 | // Similarly, if B has become NULL , we assign it to HeadA 38 | 39 | if(b == NULL) 40 | b = headA ; 41 | 42 | // Else we move B to it's Next Node 43 | 44 | else 45 | b = b -> next ; 46 | } 47 | 48 | // At the end, A will point to NULL, if the LinkedList's don't have an Intersection Point 49 | // Otherwise, it will point to the Intersecting Node of the LinkedList 50 | 51 | return a ; 52 | 53 | } 54 | }; 55 | 56 | /* 57 | Time Complexity: O(M + N) 58 | Space Complexity: O(1) 59 | */ 60 | -------------------------------------------------------------------------------- /LinkedList/Lecture 18/Intersection of Linked list.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode(int x) { 7 | * val = x; 8 | * next = null; 9 | * } 10 | * } 11 | */ 12 | public class Solution { 13 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 14 | 15 | // Initally, both A & B points to HeadA & HeadB respectively 16 | 17 | ListNode a=headA; 18 | ListNode b=headB; 19 | while(a!=b){ 20 | 21 | // If A has become NULL, we assign it to HeadB 22 | 23 | if(a==null){ 24 | a=headB; 25 | } 26 | 27 | // Else we move A to it's Next Node 28 | 29 | else{ 30 | a=a.next; 31 | } 32 | 33 | // Similarly, if B has become NULL , we assign it to HeadA 34 | 35 | 36 | if(b==null){ 37 | b=headA; 38 | } 39 | 40 | // Else we move B to it's Next Node 41 | 42 | else{ 43 | b=b.next; 44 | } 45 | 46 | } 47 | 48 | // At the end, A will point to NULL, if the LinkedList's don't have an Intersection Point 49 | // Otherwise, it will point to the Intersecting Node of the LinkedList 50 | return a; 51 | 52 | } 53 | } 54 | 55 | 56 | /* 57 | Time Complexity: O(M + N) 58 | Space Complexity: O(1) 59 | */ 60 | -------------------------------------------------------------------------------- /LinkedList/Lecture 18/Intersection of Linked list.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | 8 | """ 9 | To get the Intersection of Two LinkedLists, we will use Two pointers A & B which will initallly point to HeadA & HeadB respetively 10 | To get the intersection point, we will simply run a While Loop. The While Loop runs A is not equal to B. 11 | And at any moment, if A becomes NULL, we make A point to HeadB 12 | Similarly, at any moment, if B becomes NULL, we make B point to HeadA 13 | In this way, we can get the Intersection point of Two LinkedLists 14 | 15 | """ 16 | class Solution: 17 | def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: 18 | 19 | # intially, both A & B points to HeadA & HeadB respectively 20 | 21 | a = headA 22 | b = headB 23 | 24 | while a != b: 25 | 26 | # if A has became None, we assign it to HeadB 27 | 28 | if a == None: 29 | a = headB 30 | 31 | # Else we move to it's Next Node 32 | else: 33 | a = a.next 34 | # Similarly , if B has became None , we assign it to HeadA 35 | 36 | if b == None: 37 | b = headA 38 | # Else we move B to it's Next Node 39 | 40 | else: 41 | b = b.next 42 | 43 | ''' 44 | 45 | At the end, A will point to NULL, if the LinkedList's don't have an Intersection Point 46 | Otherwise, it will point to the Intersecting Node of the LinkedList 47 | 48 | ''' 49 | return a 50 | """ 51 | Time Complexity: O(M + N) 52 | Space Complexity: O(1) 53 | 54 | """ 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /LinkedList/Lecture 18/README.md: -------------------------------------------------------------------------------- 1 | ## 160. Intersection of Two Linked Lists 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 19/README.md: -------------------------------------------------------------------------------- 1 | ## 234. Palindrome Linked List 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/README.md: -------------------------------------------------------------------------------- 1 | ## 203. Remove Linked List Elements 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | 12 | /* In Approach - 1, we will use iteration to remove the occurrences of val(key) from the given LinkedList 13 | We will create a Dummy Node to keep track of our new LinkedList after removing all occurrences from the given Linkedlist. 14 | We require another point Tail to traverse the LinkedList. Tail initally points to Dummy 15 | We move Tail till Tail is not Equal to null OR Tail's Next is Not Equal to null. 16 | If Tail's Value is equal to Tail's Next Node's Value, we perform Deletion 17 | Otherwise, we keep moving Tail to Next Node 18 | */ 19 | 20 | class Solution { 21 | public ListNode removeElements(ListNode head, int val) { 22 | // If head is null, we directly return null 23 | 24 | if(head == null) 25 | return null ; 26 | 27 | // We create Dummy to keep track of the Linkedlist after removing all occurrences of Val 28 | 29 | ListNode dummy = new ListNode(-1) ; 30 | 31 | dummy.next = head ; 32 | 33 | // Tail initally points to Dummy 34 | 35 | ListNode tail = dummy ; 36 | 37 | while(tail != null && tail.next != null) 38 | { 39 | // If Tail's Next is equal to Val(key) 40 | 41 | if(tail.next.val == val) 42 | { 43 | // We make Temp point to Tail's Next Node 44 | 45 | ListNode temp = tail.next ; 46 | 47 | tail.next = temp.next ; 48 | 49 | } 50 | 51 | // Else the values are not equal, so we make Tail move to Tail's Next Node 52 | 53 | else 54 | { 55 | tail = tail.next ; 56 | } 57 | } 58 | 59 | // At the end, we return Dummy's Next which points to LinkedList after removing all occurrences of Val(key) 60 | 61 | return dummy.next ; 62 | 63 | } 64 | } -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 1.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | """ 7 | In Approach - 1, we will use iteration to remove the occurrences of val(key) from the given LinkedList 8 | We will create a Dummy Node to keep track of our new LinkedList after removing all occurrences from the given Linkedlist. 9 | We require another point Tail to traverse the LinkedList. Tail initally points to Dummy 10 | We move Tail till Tail is not Equal to NULL OR Tail's Next is Not Equal to NULL. 11 | If Tail's Value is equal to Tail's Next Node's Value, we perform Deletion 12 | Otherwise, we keep moving Tail to Next Node 13 | 14 | """ 15 | 16 | 17 | class Solution: 18 | def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: 19 | 20 | # if head is None , then we dierectly Return it 21 | if head == None: 22 | return head 23 | # We create Dummy to keep track of the Linkedlist after removing all occurrences of Val 24 | 25 | dummy = ListNode(-1) 26 | dummy.next = head 27 | 28 | # Tail initially points to head 29 | tail = dummy 30 | 31 | while tail != None and tail.next != None: 32 | 33 | # if Tail's Next is Equal to Val(key) 34 | 35 | if tail.next.val == val: 36 | 37 | # We make temp to tail's next node 38 | temp = tail.next 39 | tail.next = temp.next 40 | # And then delete temp 41 | del temp 42 | # Else the values are not equal , so we make tail move to tail's next node 43 | 44 | else: 45 | tail = tail.next 46 | # At the end, we return Dummy's Next which points to LinkedList after removing all occurrences of Val(key) 47 | return dummy.next 48 | 49 | """ 50 | Time Complexity: O(N) 51 | Space Complexity: O(1) 52 | 53 | """ 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | /* In Approach - 2, we will use Recursion to remove the occurrences of val(key) from the given LinkedList 12 | Unlike in iteration, we will ask Recursion to do most of the Task. We will only do a small Task 13 | We will ask recursion to remove all occurrences of Val from LinkedList starting from Head's Next Node and return the newHead 14 | After that we will check if Head's Val is equal to newHead or Not. 15 | If true, we shouldn't add Head into our LinkedList so we return newHead 16 | Else, Value is not equal to Val(Key), so we add Head's Next to newHead and return head 17 | */ 18 | 19 | class Solution { 20 | public: 21 | ListNode* removeElements(ListNode* head, int val) 22 | { 23 | // If head is NULL, wr directly return NULL 24 | 25 | if(head == NULL) 26 | return NULL ; 27 | 28 | // Otherwise, we ask Recursion to do rest of the task and remove all the occurrences of Val(Key) starting from Head's Next Node 29 | 30 | head -> next = removeElements(head -> next , val) ; 31 | 32 | // If Head' Value is equal to Val(Key) 33 | 34 | if(head -> val == val) 35 | { 36 | // We store Head's Next in Ans pointer 37 | 38 | ListNode *ans = head -> next ; 39 | 40 | // We delete Head 41 | 42 | delete head ; 43 | 44 | // We return Ans 45 | 46 | return ans ; 47 | } 48 | 49 | // Else, Head will be a part our LinkedList, so we return Head 50 | 51 | else 52 | { 53 | return head ; 54 | } 55 | } 56 | }; 57 | 58 | /* 59 | Time Complexity: O(N) 60 | Space Complexity: O(N) { Auxillary Stack Space } 61 | */ 62 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | 12 | /* In Approach - 2, we will use Recursion to remove the occurrences of val(key) from the given LinkedList 13 | Unlike in iteration, we will ask Recursion to do most of the Task. We will only do a small Task 14 | We will ask recursion to remove all occurrences of Val from LinkedList starting from Head's Next Node and return the newHead 15 | After that we will check if Head's Val is equal to newHead or Not. 16 | If true, we shouldn't add Head into our LinkedList so we return newHead 17 | Else, Value is not equal to Val(Key), so we add Head's Next to newHead and return head 18 | */ 19 | 20 | class Solution { 21 | public ListNode removeElements(ListNode head, int val) { 22 | // If head is null, wr directly return null 23 | 24 | if(head == null) 25 | return null ; 26 | 27 | // Otherwise, we ask Recursion to do rest of the task and remove all the occurrences of Val(Key) starting from Head's Next Node 28 | 29 | head.next = removeElements(head.next , val) ; 30 | 31 | // If Head' Value is equal to Val(Key) 32 | 33 | if(head.val == val) 34 | { 35 | // We store Head's Next in Ans pointer 36 | 37 | ListNode ans = head.next ; 38 | // We return Ans 39 | 40 | return ans ; 41 | } 42 | 43 | // Else, Head will be a part our LinkedList, so we return Head 44 | 45 | else 46 | { 47 | return head ; 48 | } 49 | 50 | } 51 | } 52 | /* 53 | Time Complexity: O(N) 54 | Space Complexity: O(N) { Auxillary Stack Space } 55 | */ 56 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 2.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | 7 | """ 8 | In Approach - 2, we will use Recursion to remove the occurrences of val(key) from the given LinkedList 9 | Unlike in iteration, we will ask Recursion to do most of the Task. We will only do a small Task 10 | We will ask recursion to remove all occurrences of Val from LinkedList starting from Head's Next Node and return the newHead 11 | After that we will check if Head's Val is equal to newHead or Not. 12 | If true, we shouldn't add Head into our LinkedList so we return newHead 13 | Else, Value is not equal to Val(Key), so we add Head's Next to newHead and return head 14 | 15 | """ 16 | 17 | class Solution: 18 | def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: 19 | # if head is None then dierectly return it 20 | 21 | if head == None: 22 | return head 23 | 24 | # Otherwise , we ask Recursion to do the task and remove all the occurences of Val(Key) starting from Head's Next Node 25 | head.next = self.removeElements(head.next,val) 26 | 27 | # if Head's Value is equal to Val(key) 28 | 29 | if head.val == val: 30 | # we store head's next in ans pointer 31 | ans = head.next 32 | 33 | # we delete head 34 | 35 | del head 36 | 37 | # we return Ans 38 | return ans 39 | else: 40 | return head 41 | 42 | """ 43 | Time Complexity: O(N) 44 | Space Complexity: O(N) { Auxillary Stack Space } 45 | 46 | """ 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 3.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | /* In Approach - 3, we will again use Recursion to remove the occurrences of val(key) from the given LinkedList. 12 | All our logic remains the same, but our code becomes more compact and clean (3 - liner code) 13 | */ 14 | 15 | class Solution { 16 | public: 17 | ListNode* removeElements(ListNode* head, int val) 18 | { 19 | // If head is NULL, wr directly return NULL 20 | 21 | if(head == NULL) 22 | return NULL ; 23 | 24 | // We ask recursion to do rest of the task 25 | 26 | head -> next = removeElements(head -> next , val) ; 27 | 28 | // We make our code more compact using Ternary Operator 29 | // The Logic still remains the same. Only difference is that we are not actually deleteing the Head Node if it's Value is equal to Val(Key) 30 | 31 | return head -> val == val? head -> next : head ; 32 | } 33 | }; 34 | 35 | /* 36 | Time Complexity: O(N) 37 | Space Complexity: O(N) { Auxillary Stack Space } 38 | */ 39 | -------------------------------------------------------------------------------- /LinkedList/Lecture 20/Remove Linked List Elements Approach 3.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | 12 | /* In Approach - 3, we will again use Recursion to remove the occurrences of val(key) from the given LinkedList. 13 | All our logic remains the same, but our code becomes more compact and clean (3 - liner code) 14 | */ 15 | 16 | class Solution { 17 | public ListNode removeElements(ListNode head, int val) { 18 | // If head is null, wr directly return null 19 | 20 | if(head == null) 21 | return null ; 22 | 23 | // We ask recursion to do rest of the task 24 | 25 | head.next = removeElements(head.next , val) ; 26 | 27 | // We make our code more compact using Ternary Operator 28 | // The Logic still remains the same. Only difference is that we are not actually deleteing the Head Node if it's Value is equal to Val(Key) 29 | 30 | return head.val == val? head.next : head ; 31 | 32 | } 33 | } 34 | 35 | /* 36 | Time Complexity: O(N) 37 | Space Complexity: O(N) { Auxillary Stack Space } 38 | */ 39 | -------------------------------------------------------------------------------- /LinkedList/Lecture 21/Design Browser History.java: -------------------------------------------------------------------------------- 1 | class BrowserHistory { 2 | int current; 3 | ArrayList history; 4 | public BrowserHistory(String homepage) { 5 | this.history = new ArrayList<>(); 6 | history.add(homepage); 7 | this.current = 0; 8 | } 9 | 10 | public void visit(String url) { 11 | 12 | //delete forward history 13 | 14 | while (history.size()-1 > current) { 15 | //which means delete everything beyond our current website 16 | history.remove(history.size()-1); 17 | } 18 | history.add(url); 19 | ++current; 20 | } 21 | 22 | public String back(int steps) { 23 | 24 | //if we can't get enough back, we return first thing in our history 25 | 26 | if (steps>current) current = 0; 27 | 28 | //if there will be no arrayindexoutofrange error, go back 29 | 30 | else current -= steps; 31 | 32 | //return current webpage 33 | 34 | return history.get(current); 35 | } 36 | 37 | public String forward(int steps) { 38 | 39 | //if we are going to move more than our arraylist then we will return the last element 40 | 41 | if (steps+current>=history.size()) current = history.size() - 1; 42 | 43 | //if there will be no arrayindexoutofrange error, go forward! 44 | 45 | else current += steps; 46 | 47 | return history.get(current); 48 | 49 | //return the current webpage 50 | } 51 | } 52 | 53 | /** 54 | * Your BrowserHistory object will be instantiated and called as such: 55 | * BrowserHistory obj = new BrowserHistory(homepage); 56 | * obj.visit(url); 57 | * String param_2 = obj.back(steps); 58 | * String param_3 = obj.forward(steps); 59 | */ -------------------------------------------------------------------------------- /LinkedList/Lecture 21/README.md: -------------------------------------------------------------------------------- 1 | ## 1472. Design Browser History 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 22/README.md: -------------------------------------------------------------------------------- 1 | ## 146. LRU Cache 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 23/Copy List with Random Pointer.java: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | int val; 5 | Node next; 6 | Node random; 7 | 8 | public Node(int val) { 9 | this.val = val; 10 | this.next = null; 11 | this.random = null; 12 | } 13 | } 14 | */ 15 | class Solution { 16 | public Node copyRandomList(Node head) { 17 | 18 | Node temp=head; 19 | 20 | // We store the Nodes And their Deep Copies inside m M 21 | HashMap m=new HashMap<>(); 22 | 23 | // In 1st iteration, we create copies and store the Nodes and their Copies as Key-Value pair inside our Map M 24 | 25 | 26 | while(temp!=null) 27 | { 28 | // We create a Copy of the Given Node using Temp's Value 29 | m.put(temp,new Node(temp.val)); 30 | temp=temp.next; 31 | } 32 | 33 | // We again reinitialise Temp to Head to iterate again 34 | 35 | temp=head; 36 | 37 | // In 2nd iteration, we will make connections of the copies stored in Map M 38 | 39 | while(temp!=null) 40 | { 41 | // Writing in the form of array for better understandability 42 | // M[Temp] will give us the Copy Node of Temp 43 | // M[Temp -> Next] will give us th Copy Node of Temp's Next 44 | // Copied Node's Next should point to the Copied Node of Temp's Next 45 | // check out the syntax below 46 | 47 | m.get(temp).next=m.get(temp.next); 48 | 49 | // Similarly, M[Temp -> Random] will give us the Copy Node of Temp's Random 50 | 51 | m.get(temp).random=m.get(temp.random); 52 | 53 | temp=temp.next; 54 | } 55 | 56 | // At the end, we return M[head] which is actually Head of our Copied LinkedList 57 | 58 | return m.get(head); 59 | } 60 | } 61 | 62 | /* 63 | Time Complexity: O(N) 64 | Space Complexity: O(N) 65 | */ 66 | -------------------------------------------------------------------------------- /LinkedList/Lecture 23/README.md: -------------------------------------------------------------------------------- 1 | ## 138. Copy List with Random Pointer 2 | -------------------------------------------------------------------------------- /LinkedList/Lecture 24/README.md: -------------------------------------------------------------------------------- 1 | ## 138. Copy List with Random Pointer 2 | -------------------------------------------------------------------------------- /LinkedList/READEME.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeadCoding Codes 2 | 3 | ## Recursion 4 | 21 Lectures 5 | ## Linked List 6 | 24 Lectures 7 | 8 | # Content 9 | 10 | - The main directories of this repository contains the series 11 | - Each series contains lectures which are taught in the respective series 12 | - Each lecture contains the question, LeetCode solution, and CodeStudio solution 13 | - All the solutions are provided in 4 languages: 14 | - C++ 15 | - Java 16 | - Python 17 | - Java Script 18 | 19 | 20 | Subscribe to LeadCoding channel for all the video lectures 21 | -------------------------------------------------------------------------------- /Recursion/Lecture 01/CodeStudio/Factorial of a Number.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // this function fac() will return us the factorial of the number n 5 | int fac(int n) 6 | { 7 | // base condition 8 | if (n == 0) 9 | return 1; 10 | 11 | // recursion call 12 | return n * fac(n - 1); 13 | } 14 | int main() 15 | { 16 | // Write your code here 17 | int n; 18 | cin >> n; 19 | if (n < 0) 20 | cout << "Error"; 21 | else 22 | { 23 | cout << fac(n); 24 | } 25 | return 0; 26 | } 27 | 28 | /* 29 | time complexity : O(n) 30 | space complexity : O(n) 31 | */ 32 | -------------------------------------------------------------------------------- /Recursion/Lecture 01/CodeStudio/Factorial of a Number.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.*; 3 | 4 | class Solution { 5 | 6 | // this function fac() will return us the factorial of the number n 7 | static int fac(int n){ 8 | if(n==0) return 1; 9 | 10 | // recursion call 11 | return n*fac(n-1); 12 | } 13 | 14 | public static void main(String args[]) { 15 | // Write code here 16 | Scanner sc=new Scanner(System.in); 17 | int n=sc.nextInt(); 18 | if(n<0){ 19 | System.out.println("Error"); 20 | } 21 | else{ 22 | System.out.println(fac(n)); 23 | } 24 | } 25 | } 26 | 27 | /* 28 | time complexity : O(n) 29 | space complexity : O(n) 30 | */ 31 | -------------------------------------------------------------------------------- /Recursion/Lecture 01/CodeStudio/Factorial of a Number.js: -------------------------------------------------------------------------------- 1 | // this function fac() will return us the factorial of the number n 2 | function fact(n) { 3 | /* Write your code here */ 4 | if (n == 0) return 1; 5 | if (n < 0) return "Error"; 6 | 7 | // recursion call 8 | else return n * fact(n - 1); 9 | } 10 | 11 | /* 12 | time complexity : O(n) 13 | space complexity : O(n) 14 | */ 15 | -------------------------------------------------------------------------------- /Recursion/Lecture 01/CodeStudio/Factorial of a Number.py: -------------------------------------------------------------------------------- 1 | # Your code goes here 2 | # this function fac() will return us the factorial of the number n 3 | def fac(n): 4 | if n == 0: 5 | return 1 6 | 7 | # recursion call 8 | return n*fac(n-1) 9 | 10 | 11 | n = int(input()) 12 | if n < 0: 13 | print("Error") 14 | else: 15 | print(fac(n)) 16 | 17 | 18 | """ 19 | time complexity: O(n) 20 | space complexity: O(n) 21 | """ 22 | 23 | -------------------------------------------------------------------------------- /Recursion/Lecture 01/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Factorial of a Number 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/CodeStudio/Nth Fibnacci .py: -------------------------------------------------------------------------------- 1 | def fib(n): 2 | 3 | # Base case 4 | if n == 0: 5 | return 0 6 | if n == 1 or n == 2: 7 | return 1 8 | 9 | 10 | 11 | ans1 = fib(n -1) # recursion call that will give us the (n-1)th fibo number 12 | ans2 = fib(n - 2) # recursion call that will give us the (n-2)th fibo number 13 | return ans1 + ans2 # will return the addition of (n-1)th & (n-2)th fibo number which is the nth fibo number 14 | 15 | n = int(input()) 16 | print(fib(n)) # calling the function 17 | 18 | """ALgorithm 19 | Time complexity : O(2**n) 20 | Space complexity : O(n) 21 | """ 22 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/CodeStudio/Nth Fibnacci Number_Optimised.py: -------------------------------------------------------------------------------- 1 | def fib(n): 2 | 3 | # Base case 4 | if n < 2: 5 | return n 6 | 7 | # memoization | searching for "n" in memo, if available retriving it will save time. 8 | # it'll save redundant calculations 9 | if n in memo: 10 | return memo[n] 11 | 12 | # storing calculated fibonaci numbers in memo, if it's not previously calculated 13 | memo[n-1] = fib(n-1) 14 | memo[n-2] = fib(n-2) 15 | 16 | # Formula for nth fibonachi number is, fib(n) = fib(n-1) + fib(n-2) 17 | return memo[n-1] + memo[n-2] 18 | 19 | n = int(input()) 20 | # memo is a dictionary in python | it's refered as a Hashmap is other lang 21 | memo = {} 22 | # calling the function 23 | print(fib(n)) 24 | 25 | """ 26 | ALgorithm 27 | Time complexity : O(2**n) 28 | Space complexity : O(n) 29 | 30 | MEMOIZING 31 | 1. We have to create A dictionary: with key & value pair as follow | Key == n -> value == fib(n) 32 | 2. store the pair in dictionary for each recursive calls for fib(n) | memo[n] = fin(n) 33 | 3. At the begining of fib function after Base case, To avoid redundant calculation of fib(n) 34 | search for key() -> n if already stored in "memo", If found return that value. 35 | 36 | EXAMPLE | To View redundant calculation in a recursive tree 37 | Link >> https://realpython.com/fibonacci-sequence-python/ 38 | """ 39 | 40 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/CodeStudio/Nth Fibonacci Number.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // this function fibo() will return us the nth fibonacci number 5 | int fibo(int n) 6 | { 7 | // base condition 8 | if (n == 1 || n == 2) 9 | return 1; 10 | 11 | // recursion call that will give us the (n-1)th fibo number 12 | int ans1 = fibo(n - 1); 13 | 14 | // recursion call that will give us the (n-2)th fibo number 15 | int ans2 = fibo(n - 2); 16 | 17 | // will return the addition of (n-1)th & (n-2)th fibo number which is actually our nth fibo number that we need 18 | return ans1 + ans2; 19 | } 20 | int main() 21 | { 22 | // Write your code here. 23 | int n; 24 | cin >> n; 25 | n = fibo(n); 26 | cout << n; 27 | } 28 | 29 | /* 30 | time complexity : O(2^n) 31 | space complexity : O(n) 32 | */ 33 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/CodeStudio/Nth Fibonacci Number.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | public class Solution { 4 | // this function fibo() will return us the nth fibonacci number 5 | public static int fibo(int n){ 6 | 7 | // base condition 8 | if(n==1 || n==2) return 1; 9 | 10 | // recursion call that will return (n-1)th & (n-2)th fibo number which will then be added to give us the nth fibo number 11 | return fibo(n-1)+fibo(n-2); 12 | } 13 | 14 | public static void main(String[] args) { 15 | Scanner sc=new Scanner(System.in); 16 | int n=sc.nextInt(); 17 | System.out.println(fibo(n)); 18 | } 19 | 20 | } 21 | 22 | /* 23 | time complexity : O(2^n) 24 | space complexity : O(n) 25 | */ 26 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Nth Fibonacci Number 2 | 3 | #### NOTE 4 | PYTHON SOLUTIONS ONLY: 5 | 6 | We have two solutions for python: 7 | 1. "Nth Fibonacci Number.py" this solution is taught in the lecture, it is only a recursion-based solution. It may give "TLE" for the upper bound. 8 | 2. "Nth Fibonacci Number_Optimised.py" is an accepted solution, used memoization technique to optimize the solution. Please follow the comments for a better understanding. 9 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/LeetCode/Fibonacci Number.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int fib(int n) { 4 | 5 | // base condition 6 | if (n == 0) 7 | return 0; 8 | 9 | if (n == 1 || n == 2) 10 | return 1; 11 | 12 | // recursion call that will give us the (n-1)th fibo number 13 | int ans1 = fib(n - 1); 14 | 15 | // recursion call that will give us the (n-2)th fibo number 16 | int ans2 = fib(n - 2); 17 | 18 | // will return the addition of (n-1)th & (n-2)th fibo number which is actually our nth fibo number that we need 19 | return ans1 + ans2; 20 | } 21 | }; 22 | 23 | /* 24 | time complexity : O(2^n) 25 | space complexity : O(n) 26 | */ 27 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/LeetCode/Fibonacci Number.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int fib(int n) { 3 | // base condition 4 | if(n==0) 5 | return 0; 6 | if(n==1 || n==2) 7 | return 1; 8 | 9 | // recursion call that will return (n-1)th & (n-2)th fibo number which will then be added to give us the nth fibo number 10 | return fib(n-1)+fib(n-2); 11 | } 12 | } 13 | 14 | /* 15 | time complexity : O(2^n) 16 | space complexity : O(n) 17 | */ 18 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/LeetCode/Fibonacci Number.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def fib(self, n: int) -> int: 3 | 4 | # Base case 5 | if n == 0: 6 | return 0 7 | 8 | if n == 1 or n == 2: 9 | return 1 10 | 11 | # recursion call that will give us the (n-1)th fibo number 12 | ans1 = self.fib(n - 1) 13 | 14 | # recursion call that will give us the (n-2)th fibo number 15 | ans2 = self.fib(n - 2) 16 | 17 | # will return the addition of (n-1)th & (n-2)th fibo number which is the nth fibo number 18 | return ans1 + ans2 19 | 20 | """ 21 | ALgorithm 22 | Time complexity : O(2**n) 23 | Space complexity : O(n) 24 | 25 | """ 26 | 27 | -------------------------------------------------------------------------------- /Recursion/Lecture 03/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## Fibonacci Number 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 04/CodeStudio/Find power of a number.cpp: -------------------------------------------------------------------------------- 1 | long long Pow(int X, int N) 2 | { 3 | // base condition 4 | if(N==0) return 1; 5 | 6 | // return type is long long & as we are returning temp therefore it also has to be a long long datatype 7 | long long temp=Pow(X,N/2); // recursion call 8 | 9 | // if N is odd then we will have to multiply X 10 | if(N%2==1) return temp*temp*X; 11 | return temp*temp; 12 | } 13 | 14 | /* 15 | time complexity : O(log n) 16 | space complexity : O(log n) 17 | */ 18 | -------------------------------------------------------------------------------- /Recursion/Lecture 04/CodeStudio/Find power of a number.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public static long Pow(int X, int N) { 4 | // base condition 5 | if(N==0) return 1; 6 | 7 | long temp=Pow(X,N/2); // recursion call 8 | 9 | // if N is odd then we will have to multiply X 10 | if(N%2==1) return temp*temp*X; 11 | return temp*temp; 12 | } 13 | } 14 | 15 | 16 | /* 17 | time complexity : O(log n) 18 | space complexity : O(log n) 19 | */ 20 | -------------------------------------------------------------------------------- /Recursion/Lecture 04/CodeStudio/Find power of a number.py: -------------------------------------------------------------------------------- 1 | def pow(X, N): 2 | 3 | # base case 4 | if N == 0: 5 | return 1 6 | 7 | # recurssion call 8 | temp = pow(X, N//2) 9 | 10 | # if N is odd then we will have to multiply x 11 | if N%2 == 1: 12 | return temp*temp*X 13 | 14 | return temp*temp 15 | 16 | """ 17 | Algorithm 18 | 19 | time complexity : O(log n) 20 | space complexity : O(log n) 21 | """ 22 | -------------------------------------------------------------------------------- /Recursion/Lecture 04/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Find power of a number 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 04/LeetCode/Pow(x, n).cpp: -------------------------------------------------------------------------------- 1 | class Solution 2 | { 3 | public: 4 | double myPow(double x, int n) 5 | { 6 | // base condition 7 | if (n == 0) 8 | return 1; 9 | 10 | // when n is negative then this if-statement will be execute 11 | if (n < 0) 12 | { 13 | x = 1 / x; 14 | n = abs(n); 15 | } 16 | double temp = myPow(x, n / 2); 17 | 18 | // if N is odd then we will have to multiply X 19 | if (n % 2 == 1) 20 | return temp * temp * x; 21 | 22 | return temp * temp; 23 | } 24 | }; 25 | 26 | /* 27 | time complexity : O(log n) 28 | space complexity : O(log n) 29 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 04/LeetCode/Pow(x, n).py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def myPow(self, x: float, n: int) -> float: 3 | 4 | # base case 5 | if n == 0: 6 | return 1 7 | 8 | # when n is negative then this if-statement will be execute 9 | if n < 0: 10 | x = 1 / x 11 | n = abs(n) 12 | 13 | temp = self.myPow(x, n // 2) # "//" is floor divisinon operator 14 | 15 | # if n is odd then we will have to multiply x 16 | if n % 2 == 1: 17 | return temp * temp * x 18 | 19 | else: 20 | return temp * temp 21 | 22 | """ 23 | Algorithm 24 | 25 | time complexity : O(log n) 26 | space complexity : O(log n) 27 | """ 28 | -------------------------------------------------------------------------------- /Recursion/Lecture 04/LeetCode/READEME.md: -------------------------------------------------------------------------------- 1 | ## 50. Pow(x, n) 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 05/CodeStudio/Check Palindrome.cpp: -------------------------------------------------------------------------------- 1 | bool isPalindromeNumber(int l, int r, string &s) 2 | { 3 | // base condition 4 | // l : left pointer, r : right pointer 5 | if (l >= r) 6 | return true; 7 | 8 | // base condition 9 | // when character at s[left] is not equal to character at s[right] that means it is not a palindrome thus return false 10 | if (s[l] != s[r]) 11 | return false; 12 | 13 | // recursion call 14 | return isPalindromeNumber(l + 1, r - 1, s); 15 | } 16 | 17 | bool isPalindrome(string &s) 18 | { 19 | // Write your code here. 20 | // here we are going to use two pointer approach 21 | // left pointer starting from first index 0 22 | // right pointer starting from last index s.size() - 1 23 | return isPalindromeNumber(0, s.size() - 1, s); 24 | } 25 | 26 | /* 27 | time complexity : O(n) 28 | space complexity : O(n) 29 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 05/CodeStudio/Check Palindrome.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | static Boolean helper(int l, int r, String s){ 3 | // base condition 4 | // l : left pointer, r : right pointer 5 | if(l>=r) return true; 6 | 7 | // base condition 8 | // when character at s[left] is not equal to character at s[right] that means it is not a palindrome thus return false 9 | if(s.charAt(l)!=s.charAt(r)) return false; 10 | 11 | // recursion call 12 | return helper(l+1,r-1,s); 13 | } 14 | 15 | public static Boolean isPalindrome(String s) { 16 | // Write your code here.. 17 | // here we are going to use two pointer approach 18 | // left pointer starting from first index 0 19 | // right pointer starting from last index s.size() - 1 20 | return helper(0,s.length()-1,s); 21 | } 22 | } 23 | 24 | /* 25 | time complexity : O(n) 26 | space complexity : O(n) 27 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 05/CodeStudio/Check Palindrome.py: -------------------------------------------------------------------------------- 1 | def isPalindrome(s: str) -> bool: 2 | 3 | # helper function to check for palindrome 4 | def isPalindromeHelper(l, r, s): 5 | 6 | # Base case, checking if the left pointer crosses the right pointer, or overlaps then it's a palindrome 7 | if l >= r: 8 | return True 9 | 10 | # at any moment if the s[left] != s[right] stop and return Fasle 11 | if s[l] != s[r]: 12 | return False 13 | 14 | return isPalindromeHelper(l+1, r-1, s) 15 | 16 | # Recursive call 17 | return isPalindromeHelper(0, len(s)-1, s) 18 | 19 | """ 20 | Algorithm 21 | Tc : O(n/2) 22 | Sc : O(1) || O(n/2) stack memory 23 | 24 | """ 25 | -------------------------------------------------------------------------------- /Recursion/Lecture 05/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Check Palindrome 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 05/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 125. Valid Palindrome 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 05/LeetCode/Valid Palindrome.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NOTE: 3 | The Question is exactly similar to checking a Palindrome 4 | Only difference is that we need to create a new string which contains only AlphaNumeric characters and all alphabets shoould be in Lower Case only 5 | */ 6 | 7 | class Solution { 8 | private : 9 | bool isPalindromeHelper(int l , int r , string &s) 10 | { 11 | // While checking if our left pointer crosses our right pointer, it indicates the string is Palindrome 12 | 13 | if(l >= r) 14 | return true ; 15 | 16 | // At any moment if s[l] != s[r], we are sure it's not an Palindrome 17 | 18 | if(s[l] != s[r]) 19 | return false ; 20 | 21 | // Asking recursion to do rest of the task 22 | 23 | return isPalindromeHelper(l + 1 , r - 1 , s) ; 24 | } 25 | 26 | public: 27 | bool isPalindrome(string s) { 28 | 29 | // We need to create a seperate string devoid of spaces and Non-Alphanumeirc Values 30 | 31 | string str = "" ; 32 | 33 | for(char ch : s) 34 | { 35 | // isalnum(ch) returns true if the character is a digit or alpbhabet else returns false 36 | 37 | if(isalnum(ch) == false) 38 | continue ; 39 | 40 | // If ch is equal to white space, we don't include it in our new string 41 | 42 | if(ch == ' ') 43 | continue ; 44 | 45 | // If ch is in Upper-Case, we can convert it in Lower Case easily by adding 32 to it's ASCII Value 46 | 47 | if(isupper(ch) ) 48 | ch = ch + 32 ; 49 | 50 | // At the end, we push ch into our new string 51 | 52 | str.push_back(ch) ; 53 | 54 | } 55 | 56 | // If our new string is still empty, we directly return true 57 | 58 | if(str.size() == 0) 59 | return true ; 60 | 61 | bool ans = isPalindromeHelper(0 , str.size() - 1 , str) ; 62 | 63 | return ans ; 64 | 65 | } 66 | }; 67 | 68 | /* Time Complexity: O(N) 69 | Space Complexity: O(N) 70 | */ 71 | -------------------------------------------------------------------------------- /Recursion/Lecture 05/LeetCode/Valid Palindrome.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isPalindrome(self, s: str) -> bool: 3 | 4 | def isPalindromeHelper(l, r, s): 5 | 6 | # Base case, checking if the left pointer crosses the right pointer, or overlaps then it's a palindrome 7 | if l >= r: 8 | return True 9 | 10 | # at any moment if the s[left] != s[right] stop and return Fasle 11 | if s[l] != s[r]: 12 | return False 13 | 14 | return isPalindromeHelper(l+1, r-1, s) 15 | 16 | charString = "" 17 | 18 | for char in s: 19 | 20 | # remoes value of indices other then character or digit 21 | if char.isalnum() == False: 22 | continue 23 | 24 | # skipping spaces 25 | if char == " ": 26 | continue 27 | 28 | # converting upperCase to lowerCase 29 | if char.isupper(): 30 | char = char.lower() 31 | 32 | # creating string only with characters by string concatination 33 | charString += char 34 | 35 | # recursive function call 36 | ans = isPalindromeHelper(0, len(charString)-1, charString) 37 | 38 | return ans 39 | 40 | """ 41 | Algorithm 42 | Tc : O(n) 43 | Sc : O(n) 44 | """ -------------------------------------------------------------------------------- /Recursion/Lecture 06/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Reverse The Array 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 06/CodeStudio/Reverse The Array.cpp: -------------------------------------------------------------------------------- 1 | void reverse(int l, int r, vector &arr) 2 | { 3 | // base condition 4 | if (l >= r) 5 | return; 6 | 7 | // do the small task 8 | swap(arr[l], arr[r]); 9 | 10 | // ask recursion to do the remaining task 11 | reverse(l + 1, r - 1, arr); 12 | } 13 | void reverseArray(vector &arr, int m) 14 | { 15 | // Write your code here. 16 | return reverse(m + 1, arr.size() - 1, arr); 17 | } 18 | 19 | /* 20 | time complexity : O(n) 21 | space complexity : O(n) 22 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 06/CodeStudio/Reverse The Array.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Collections; 3 | public class Solution 4 | { 5 | static int helper(int l, int r,ArrayList arr){ 6 | // base condition 7 | if(l>=r) return 1; 8 | 9 | // do the small task 10 | Collections.swap(arr, l, r); 11 | 12 | // ask recursion to do the remaining task 13 | return helper(l+1,r-1,arr); 14 | } 15 | public static void reverseArray(ArrayList arr, int m) 16 | { 17 | // Write your code here. 18 | helper(m+1,arr.size()-1,arr); 19 | } 20 | } 21 | 22 | 23 | /* 24 | time complexity : O(n) 25 | space complexity : O(n) 26 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 06/CodeStudio/Reverse The Array.py: -------------------------------------------------------------------------------- 1 | def reverseArray(arr, m): 2 | 3 | # Function to reverse the required position of array 4 | def helper(l, r): 5 | 6 | # base case 7 | if l >= r: 8 | return arr 9 | 10 | #swapping the indices of the arr 11 | arr[l], arr[r] = arr[r], arr[l] 12 | 13 | # recursive call 14 | return helper(l+1, r-1) 15 | 16 | return helper(m+1, len(arr)-1) 17 | """ 18 | Algorithm 19 | TC : O(m/2) 20 | Sc : O(1) || O(m/2) i.e stack memory for recursive call 21 | 22 | NOTE 23 | considering 0 based indexing so the subarray {5, 6} will be reversed and our output array will be {1, 2, 3, 4, 6, 5} """ 24 | -------------------------------------------------------------------------------- /Recursion/Lecture 07/CodeStudio/Power Set.cpp: -------------------------------------------------------------------------------- 1 | void helper(vector &v, int i, vector &subSet, vector> &ans) 2 | { 3 | // base condition 4 | if (i == v.size()) 5 | { 6 | ans.push_back(subSet); 7 | return; 8 | } 9 | 10 | // pick the ith element 11 | subSet.push_back(v[i]); 12 | helper(v, i + 1, subSet, ans); 13 | 14 | // backtrack & undo the changes that were made 15 | subSet.pop_back(); 16 | 17 | // skip the ith element 18 | helper(v, i + 1, subSet, ans); 19 | } 20 | 21 | vector> pwset(vector v) 22 | { 23 | vector> ans; 24 | vector subSet; 25 | helper(v, 0, subSet, ans); 26 | return ans; 27 | } 28 | 29 | /* 30 | time complexity : O(2^n) 31 | space complexity : O(n) 32 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 07/CodeStudio/Power Set.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | public class Solution 3 | { 4 | static void helper(ArrayList v, int i, ArrayList subSet, ArrayList> ans) 5 | { 6 | // base condition 7 | 8 | if (i == v.size()) 9 | { 10 | ans.add(new ArrayList(subSet)); 11 | return; 12 | } 13 | 14 | // pick the ith element 15 | 16 | subSet.add(v.get(i)); 17 | helper(v, i + 1, subSet, ans); 18 | 19 | // backtrack & undo the changes that were made 20 | 21 | subSet.remove(subSet.size()-1); 22 | 23 | // skip the ith element 24 | 25 | helper(v, i + 1, subSet, ans); 26 | } 27 | public static ArrayList> pwset(ArrayList arr) 28 | { 29 | ArrayList> ans = new ArrayList<>(); 30 | ArrayList subSet = new ArrayList<>(); 31 | helper(arr, 0, subSet, ans); 32 | return ans; 33 | } 34 | } 35 | 36 | /* 37 | time complexity : O(2^n) 38 | space complexity : O(n) 39 | */ 40 | -------------------------------------------------------------------------------- /Recursion/Lecture 07/CodeStudio/Power Set.py: -------------------------------------------------------------------------------- 1 | def pwset(v): 2 | def helper(v, i, subSet, ans): 3 | 4 | # Our base case will hit when our i pointer reaches the end of given array v[] 5 | if i == len(v): 6 | ans.append(subSet.copy()) 7 | return 8 | 9 | # we pick ith Element 10 | subSet.append(v[i]) 11 | 12 | # We ask recursion to do rest of the task 13 | helper(v, i+1, subSet, ans) 14 | 15 | # Backtrack and Undo the change we have done 16 | subSet.pop() 17 | 18 | # We don't pick the ith element 19 | helper(v, i+1, subSet, ans) 20 | 21 | # varibles in pwset() scope 22 | ans = [] 23 | subSet = [] 24 | # Helper will store the ans in ans list 25 | helper(v, 0, subSet, ans) 26 | return ans 27 | -------------------------------------------------------------------------------- /Recursion/Lecture 07/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Power Set -------------------------------------------------------------------------------- /Recursion/Lecture 07/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 78. Subsets 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 07/LeetCode/Subsets.cpp: -------------------------------------------------------------------------------- 1 | /* At any stage of our Recursion, we will have 2 choices only - 2 | a) Pick the i-th Element 3 | b) Don't Pick the i-th Elemenent 4 | 5 | As all our elements are Unique, our Subsets generated will be Unique as well 6 | */ 7 | 8 | class Solution { 9 | private : 10 | 11 | void helper(int i , vector &subSet , vector &nums , vector> &ans) 12 | { 13 | // Our base case will hit when our i pointer reaches the end of given array nums[] 14 | 15 | if(i == nums.size() ) 16 | { 17 | ans.push_back(subSet) ; 18 | return ; 19 | } 20 | 21 | // We pick i-th Element 22 | 23 | subSet.push_back(nums[i]) ; 24 | 25 | // We ask recursion to do rest of the task 26 | helper(i + 1 , subSet , nums , ans) ; 27 | 28 | // Backtrack and Undo the change we have done 29 | 30 | subSet.pop_back() ; 31 | 32 | // We don't pick the i-th element 33 | 34 | helper(i + 1 , subSet , nums , ans) ; 35 | 36 | return ; 37 | } 38 | 39 | public: 40 | vector> subsets(vector& nums) { 41 | 42 | vector> ans ; 43 | vector subSet ; 44 | 45 | helper(0 , subSet , nums , ans) ; 46 | 47 | return ans ; 48 | } 49 | }; 50 | 51 | /* 52 | Time Complexity : O(2^N) 53 | Space Complexity : O(N) 54 | */ 55 | -------------------------------------------------------------------------------- /Recursion/Lecture 07/LeetCode/Subsets.java: -------------------------------------------------------------------------------- 1 | /* At any stage of our Recursion, we will have 2 choices only - 2 | a) Pick the i-th Element 3 | b) Don't Pick the i-th Elemenent 4 | As all our elements are Unique, our Subsets generated will be Unique as well 5 | */ 6 | 7 | class Solution 8 | { 9 | public List> subsets(int[] nums) 10 | { 11 | List> ans = new ArrayList<>(); 12 | helper(nums , 0, new ArrayList() , ans); 13 | return ans; 14 | } 15 | void helper(int nums[],int ci,List subset,List> ans) 16 | { 17 | // Our base case will hit when our i pointer reaches the end of given array nums[] 18 | 19 | if(ci==nums.length) 20 | { 21 | ans.add(new ArrayList<>(subset)); 22 | return ; 23 | } 24 | 25 | // We pick i-th Element 26 | 27 | subset.add(nums[ci]); 28 | 29 | // We ask recursion to do rest of the task 30 | 31 | helper(nums, ci + 1, subset, ans); 32 | 33 | // Backtrack and Undo the change we have done 34 | 35 | subset.remove(subset.size() - 1); 36 | 37 | // We don't pick the i-th element 38 | 39 | helper(nums, ci + 1, subset, ans); 40 | return ; 41 | } 42 | } 43 | 44 | /* 45 | Time Complexity : O(2^N) 46 | Space Complexity : O(N) 47 | */ 48 | -------------------------------------------------------------------------------- /Recursion/Lecture 07/LeetCode/Subsets.py: -------------------------------------------------------------------------------- 1 | """ 2 | At any stage of our Recursion, we will have 2 choices only - 3 | a) Pick the i-th Element 4 | b) Don't Pick the i-th Elemenent 5 | As all our elements are Unique, our Subsets generated will be Unique as well 6 | """ 7 | class Solution: 8 | def subsets(self, nums: List[int]) -> List[List[int]]: 9 | 10 | def helper(i, subSet, nums, ans): 11 | 12 | # Our base case will hit when our i pointer reaches the end of given array nums[] 13 | if i == len(nums): 14 | ans.append(subSet.copy()) 15 | return 16 | 17 | # we pick ith Element 18 | subSet.append(nums[i]) 19 | 20 | # We ask recursion to do rest of the task 21 | helper(i+1, subSet, nums, ans) 22 | 23 | # Backtrack and Undo the change we have done 24 | subSet.pop() 25 | 26 | # We don't pick the ith element 27 | helper(i+1, subSet, nums, ans) 28 | 29 | return 30 | 31 | # Global Variables for helper functions 32 | ans = [] 33 | subSet = [] 34 | # Helper will store the ans in ans list 35 | helper(0, subSet, nums, ans) 36 | 37 | return ans 38 | 39 | """ 40 | Time Complexity : O(2^N) 41 | Space Complexity : O(N) 42 | """ 43 | -------------------------------------------------------------------------------- /Recursion/Lecture 08/CodeStudio/Permutations of a String.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | void helper(int pos, string &str, vector &ans) 3 | { 4 | // when we have traversed the entire str, then we should put str into ans[] 5 | if (pos >= str.size()) 6 | { 7 | ans.push_back(str); 8 | } 9 | 10 | // Iterating from currentposition till size of str and trying to generate all possible Permutations 11 | for (int i = pos; i < str.size(); i++) 12 | { 13 | // swapping the ith element with the current element 14 | swap(str[pos], str[i]); 15 | 16 | // ask recursion to do the remaining task 17 | helper(pos + 1, str, ans); 18 | 19 | // backtrack & undo the changes 20 | swap(str[pos], str[i]); 21 | } 22 | } 23 | vector generatePermutations(string &str) 24 | { 25 | 26 | // to keep the final result in store 27 | vector ans; 28 | 29 | helper(0, str, ans); 30 | 31 | // Specific to this problem because we want the strings sorted in lexicographical order 32 | sort(ans.begin(), ans.end()); 33 | return ans; 34 | } 35 | 36 | /* 37 | time complexity : O(n * n!) 38 | space complexity : O(n) 39 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 08/CodeStudio/Permutations of a String.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class Solution { 4 | private static void permute(ArrayList ans, String str, int curr, int n) 5 | { 6 | // when we have traversed the entire str, then we should put str into ans[] 7 | if (curr == n) 8 | ans.add(str); 9 | else 10 | { 11 | // Iterating from currentposition till size of str and trying to generate all possible Permutations 12 | for (int i = curr; i < n; i++) 13 | { 14 | // call swap function for swapping the ith element with the current element 15 | str = swap(str,curr,i); 16 | 17 | // ask recursion to do the remaining task 18 | permute(ans, str, curr+1, n); 19 | 20 | // backtrack & undo the changes 21 | str = swap(str,curr,i); 22 | } 23 | } 24 | } 25 | 26 | // function that will swap the ith element with the current element 27 | public static String swap(String s, int i, int j) 28 | { 29 | char temp; 30 | char[] strArray = s.toCharArray(); 31 | temp = strArray[i] ; 32 | strArray[i] = strArray[j]; 33 | strArray[j] = temp; 34 | return String.valueOf(strArray); 35 | } 36 | 37 | public static ArrayList generatePermutations(String str) { 38 | // Write your code here 39 | ArrayList ans = new ArrayList<>(); 40 | int n = str.length(); 41 | permute(ans, str, 0, n); 42 | 43 | // Specific to this problem because we want the strings sorted in lexicographical order 44 | Collections.sort(ans); 45 | return ans; 46 | } 47 | } 48 | 49 | /* 50 | time complexity : O(n * n!) 51 | space complexity : O(n) 52 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 08/CodeStudio/Permutations of a String.py: -------------------------------------------------------------------------------- 1 | def generatePermutations(str): 2 | 3 | # Swap API | As sting in python is imutable we have to take use of extra space using an list to swap the indices, 4 | def swap(i, j, s): 5 | # Converting string to a list of string[i] where 0<= i <= len(s)-1 6 | arr = list(s) 7 | # Swaping in the list 8 | arr[i], arr[j] = arr[j], arr[i] 9 | # concatinating the swaped indece to a empty string 10 | s = "" 11 | for i in arr: 12 | s += i 13 | return s 14 | 15 | def helper(pos, str, ans, n): 16 | 17 | # If we have reached the end of str, we have found a Valid Permutations of str 18 | if pos >= len(str): 19 | # appending a copy of str, else it wold be passed by referemced, 20 | # any change to str will change the appended ans. Don't worry about the extra space, Garbage 21 | # collector will handel the extra space 22 | ans.append(str[:]) 23 | return 24 | 25 | # Otherwise we iterate over all the other elements and try to generate Permutations by swapping str[pos] with str[i] 26 | 27 | for i in range(pos, len(str)): 28 | 29 | # We create one Unique Permutation by swapping str[i] with str[pos] 30 | 31 | str = swap(pos, i, str) 32 | 33 | # And we ask Recursion to handle rest of the task 34 | 35 | helper(pos+1, str, ans, n) 36 | 37 | # But after we come back, we must backtrack and undo the changes we have done 38 | 39 | str = swap(pos, i, str) 40 | 41 | ans = [] 42 | n = len(str) 43 | helper(0, str, ans, n) 44 | return sorted(ans) 45 | 46 | """ 47 | Time Complexity : O(N * N!) 48 | Space Complexity : O(N) 49 | """ 50 | -------------------------------------------------------------------------------- /Recursion/Lecture 08/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Permutations of a String -------------------------------------------------------------------------------- /Recursion/Lecture 08/LeetCode/Permutations.cpp: -------------------------------------------------------------------------------- 1 | /* The idea is to generate all Possible Permutations by swapping the nums[currentIndex] with nums[i] 2 | As all the characters are Unique, the Permutations generated will also be Unique 3 | We make neccessary changes in nums[] vector only. We don't use any other data structure 4 | For Permutations, order doesn't matter 5 | */ 6 | 7 | class Solution { 8 | private : 9 | 10 | void helper(int pos , int n , vector &nums , vector> &ans) 11 | { 12 | // If we have reached the end of nums[], we have found a Valid Permutations of nums[] 13 | 14 | if(pos >= n) 15 | { 16 | ans.push_back(nums) ; 17 | return ; 18 | } 19 | 20 | // Otherwise we iterate over all the other elements and try to generate Permutations by swapping nums[pos] with nums[i] 21 | 22 | for(int i = pos ; i < n ; i++) 23 | { 24 | // We create one Unique Permutation by swapping nums[pos] with nums[i] 25 | 26 | swap(nums[pos] , nums[i]) ; 27 | 28 | // And we ask Recursion to handle rest of the task 29 | 30 | helper(pos + 1 , n , nums , ans) ; 31 | 32 | // But after we come back, we must backtrack and undo the changes we have done 33 | 34 | swap(nums[pos] , nums[i]) ; 35 | } 36 | 37 | return ; 38 | } 39 | 40 | public: 41 | vector> permute(vector& nums) { 42 | 43 | vector> ans ; 44 | 45 | helper(0 , nums.size() , nums , ans) ; 46 | 47 | return ans ; 48 | } 49 | }; 50 | /* 51 | Time Complexity : O(N * N!) 52 | Space Complexity : O(N) 53 | */ 54 | -------------------------------------------------------------------------------- /Recursion/Lecture 08/LeetCode/Permutations.java: -------------------------------------------------------------------------------- 1 | /* The idea is to generate all Possible Permutations by swapping the nums[currentIndex] with nums[i] 2 | As all the characters are Unique, the Permutations generated will also be Unique 3 | We make neccessary changes in nums[] vector only. We don't use any other data structure 4 | For Permutations, order doesn't matter 5 | 6 | NOTE : In java there are no swap function so we need to create our own swap function 7 | 8 | NOTE : The array must be converted into List before storing it in answer 9 | */ 10 | 11 | 12 | class Solution 13 | { 14 | public void helper(int pos , int n , int[] nums , List> ans) 15 | { 16 | // If we have reached the end of nums, we have found a Valid Permutations of nums 17 | 18 | if(pos >= n) 19 | { 20 | List permutation = ConverttoArray(nums); 21 | ans.add(new ArrayList(permutation)) ; 22 | return ; 23 | } 24 | 25 | // Otherwise we iterate over all the other elements and try to generate Permutations by swapping element at pos with element at i 26 | 27 | for(int i = pos ; i < n ; i++) 28 | { 29 | // We create one Unique Permutation by swapping 30 | 31 | swap(pos , i, nums) ; 32 | 33 | // And we ask Recursion to handle rest of the task 34 | 35 | helper(pos + 1 , n , nums , ans) ; 36 | 37 | // But after we come back, we must backtrack and undo the changes we have done 38 | 39 | swap(pos , i, nums) ; 40 | } 41 | 42 | return ; 43 | } 44 | 45 | public void swap (int i, int j, int[] nums) 46 | { 47 | // Swaping the elements 48 | 49 | int temp = nums[i]; 50 | nums[i] = nums[j]; 51 | nums[j] = temp; 52 | } 53 | 54 | public List ConverttoArray(int[] nums) 55 | { 56 | // Converting the array into List 57 | 58 | List ans = new ArrayList<>(); 59 | for(int ele : nums) 60 | ans.add(ele); 61 | return ans; 62 | } 63 | 64 | public List> permute(int[] nums) 65 | { 66 | List> ans = new ArrayList<>(); 67 | 68 | helper(0 , nums.length , nums , ans) ; 69 | 70 | return ans ; 71 | } 72 | } 73 | 74 | /* 75 | Time Complexity : O(N * N!) 76 | Space Complexity : O(N) 77 | */ 78 | -------------------------------------------------------------------------------- /Recursion/Lecture 08/LeetCode/Permutations.py: -------------------------------------------------------------------------------- 1 | """ 2 | * The idea is to generate all Possible Permutations by swapping the nums[currentIndex] with nums[i] 3 | * As all the characters are Unique, the Permutations generated will also be Unique 4 | * We make neccessary changes in nums[] vector only. We don't use any other data structure 5 | * For Permutations, order doesn't matter 6 | """ 7 | class Solution: 8 | def permute(self, nums: List[int]) -> List[List[int]]: 9 | 10 | # makes swaps in nums array 11 | def swap(i, j): 12 | nums[i], nums[j] = nums[j], nums[i] 13 | return 14 | 15 | def helper(pos, n, nums, ans): 16 | 17 | # If we have reached the end of nums[], we have found a Valid Permutations of nums[] 18 | if pos >= n: 19 | # appending a copy of nums, else it wold be passed by referemced, 20 | # any change to nums will change the appended ans. Don't worry about the extra space, Garbage 21 | # collector will handel the extra space 22 | ans.append(nums.copy()) 23 | return 24 | 25 | # Otherwise we iterate over all the other elements and try to generate Permutations by swapping nums[pos] with nums[i] 26 | 27 | for i in range(pos, n): 28 | 29 | # We create one Unique Permutation by swapping nums[i] with nums[pos] 30 | 31 | swap(i, pos) 32 | 33 | # And we ask Recursion to handle rest of the task 34 | 35 | helper(pos+1, n, nums, ans) 36 | 37 | # But after we come back, we must backtrack and undo the changes we have done 38 | 39 | swap(i, pos) 40 | 41 | ans = [] 42 | 43 | helper(0, len(nums), nums, ans) 44 | 45 | return ans 46 | 47 | """ 48 | Time Complexity : O(N * N!) 49 | Space Complexity : O(N) 50 | """ 51 | 52 | -------------------------------------------------------------------------------- /Recursion/Lecture 08/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 46. Permutations 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/CodeStudio/All Unique Permutations lecture code.py: -------------------------------------------------------------------------------- 1 | def uniquePermutations(arr, n): 2 | def helper(pos, n): 3 | 4 | # Base Case executes when we have traversed the entire nums[] 5 | if pos >= n: 6 | ans.append(arr.copy()) 7 | return 8 | 9 | # The rest logic remains exactly the same 10 | 11 | for i in range(pos, n): 12 | 13 | # We simply use our swapping logic to create Permutations 14 | 15 | arr[i], arr[pos] = arr[pos], arr[i] 16 | 17 | # And we ask Recursion to handle rest of the task 18 | # To ensure we're not storing any duplicate | we check if the hash(nums) is already not present in the numsMap 19 | if arr not in ans: 20 | helper(pos+1, n) 21 | 22 | # Backtrack and undo the change we have done 23 | 24 | arr[i], arr[pos] = arr[pos], arr[i] 25 | return 26 | 27 | ans = [] 28 | 29 | # Dictionary to store each permutation of nums as key | before storing it in key we need to convert nums [] to a String, as list are not hashable 30 | 31 | helper(0, len(arr)) 32 | 33 | return ans 34 | 35 | 36 | """ 37 | Time Complexity : O(N * N!) 38 | Space Complexity : O(N) 39 | """ 40 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/CodeStudio/All Unique Permutations.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | void helper(int pos, int n, vector &arr, vector> &ans) 3 | { 4 | // If we have traversed entire arr[], we have got an Unique Permutation this push it into the ans 5 | if (pos >= n) 6 | { 7 | ans.push_back(arr); 8 | } 9 | unordered_set m; 10 | for (int i = pos; i < n; i++) 11 | { 12 | // First check whether we have already taken arr[i] in our Permutation or not 13 | if (m.find(arr[i]) != m.end()) 14 | continue; 15 | 16 | // If not we insert it in our current unordered_set 17 | m.insert(arr[i]); 18 | 19 | // We use our simple swapping logic to generate all Permutations 20 | swap(arr[pos], arr[i]); 21 | 22 | // Ask recursion to do the remaining task 23 | helper(pos + 1, n, arr, ans); 24 | 25 | // Backtrack and undo the changes 26 | swap(arr[pos], arr[i]); 27 | } 28 | } 29 | vector> uniquePermutations(vector &arr, int n) 30 | { 31 | // Write your code here. 32 | vector> ans; 33 | 34 | // Call the Recursive function to generate all the Unique Permutations 35 | helper(0, n, arr, ans); 36 | 37 | sort(ans.begin(), ans.end()); 38 | return ans; 39 | } 40 | 41 | /* 42 | time complexity : O(N * N!) 43 | space complexity : O(N) 44 | */ 45 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/CodeStudio/All Unique Permutations.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | public class Solution 3 | { 4 | public static void helper(int pos , int n , ArrayList nums , ArrayList> ans) 5 | { 6 | // If we have reached the end of nums, we have found a Valid Permutations of nums 7 | 8 | if(pos >= n) 9 | { 10 | ans.add(new ArrayList(nums)) ; 11 | return ; 12 | } 13 | 14 | // Otherwise we iterate over all the other elements and try to generate Permutations by swapping element at pos with element at i 15 | 16 | // Hashset ensures we are not taking duplicates and thus not making Duplicate Permutation 17 | 18 | HashSet set = new HashSet<>(); 19 | 20 | for(int i = pos ; i < n ; i++) 21 | { 22 | // If we have encountered the element before, we will simply skip the rest of iterations 23 | 24 | if(set.contains( nums.get(i) )) 25 | continue; 26 | 27 | // We insert nums[i] so that we don't create Duplicate Permutations 28 | 29 | set.add(nums.get(i)); 30 | 31 | // We create one Unique Permutation by swapping 32 | 33 | Collections.swap( nums, pos , i) ; 34 | 35 | // And we ask Recursion to handle rest of the task 36 | 37 | helper(pos + 1 , n , nums , ans) ; 38 | 39 | // But after we come back, we must backtrack and undo the changes we have done 40 | 41 | Collections.swap( nums, pos , i) ; 42 | } 43 | 44 | return ; 45 | } 46 | 47 | public static ArrayList> uniquePermutations(ArrayList arr, int n) 48 | { 49 | ArrayList> ans = new ArrayList<>(); 50 | 51 | helper(0 , arr.size() , arr , ans) ; 52 | 53 | return ans ; 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/CodeStudio/All Unique Permutations_Optimised.py: -------------------------------------------------------------------------------- 1 | def uniquePermutations(arr, n): 2 | def hashKey(arr): 3 | s = "" 4 | for i in arr: 5 | s += str(i) 6 | return s 7 | 8 | def helper(pos, n, key): 9 | 10 | # Base Case executes when we have traversed the entire nums[] 11 | if pos >= n: 12 | ans.append(arr.copy()) 13 | numsMap[key] = 1 14 | return 15 | 16 | # The rest logic remains exactly the same 17 | 18 | for i in range(pos, n): 19 | 20 | # We simply use our swapping logic to create Permutations 21 | 22 | arr[i], arr[pos] = arr[pos], arr[i] 23 | 24 | # hasing the nums arry to a string, to store in numsMap dictionary 25 | 26 | key = hashKey(arr) 27 | 28 | # And we ask Recursion to handle rest of the task 29 | # To ensure we're not storing any duplicate | we check if the hash(nums) is already not present in the numsMap 30 | if key not in numsMap: 31 | helper(pos+1, n, key) 32 | 33 | # Backtrack and undo the change we have done 34 | 35 | arr[i], arr[pos] = arr[pos], arr[i] 36 | return 37 | 38 | ans = [] 39 | 40 | # Dictionary to store each permutation of nums as key | before storing it in key we need to convert nums [] to a String, as list are not hashable 41 | # Dictionary is used to optimise the Time complexit as search TC is O(1) 42 | numsMap = {} 43 | 44 | helper(0, len(arr), hashKey(arr)) 45 | 46 | return ans 47 | 48 | """ 49 | Time Complexity : O(N * N!) 50 | Space Complexity : O(N) 51 | """ 52 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## All Unique Permutations 2 | 3 | ### NOTE 4 | #### FOR PYTON CODE ONLY 5 | 1. "All Unique Permutations.py" code following lecture | As we can't store list in python set(), We have to search in ans arry to check for duplicate permutation of nums array. which would cost TC : O(N). 6 | 2. "All Unique Permutations lecture code.py" | In this code we have used python dictionary to store permutations of nums[]. On searching for duplicate it would cost TC : (1). 7 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/LeetCode/Permutations II.cpp: -------------------------------------------------------------------------------- 1 | /* This question is exactly similar to Permutations - I 2 | Only difference being we have duplicate elements in nums[]. But we need to print Unique Permutations only 3 | For that purpose, we have used a local unordered_set data structure which tells us if that particular element has been previosuly encountered or not 4 | If we have taken / chosen the element before, we will not include it anymore. 5 | But if we haven't included the element, we will include it now 6 | */ 7 | 8 | class Solution { 9 | private : 10 | 11 | void helper(int pos , int n , vector &nums , vector> &ans) 12 | { 13 | // Base Case executes when we have traversed the entire nums[] 14 | 15 | if(pos >= n) 16 | { 17 | ans.push_back(nums) ; 18 | return ; 19 | } 20 | 21 | // Unordered_set ensures we are not taking duplicates and thus not making Duplicate Permutation 22 | 23 | unordered_set set ; 24 | 25 | // The rest logic remains exactly the same 26 | 27 | for(int i = pos ; i < n ; i++) 28 | { 29 | // If we have encountered the element before, we will simply skip the rest of iterations 30 | 31 | if(set.find(nums[i]) != set.end() ) 32 | continue ; 33 | 34 | // We insert nums[i] so that we don't create Duplicate Permutations 35 | 36 | set.insert(nums[i]) ; 37 | 38 | // We simply use our swapping logic to create Permutations 39 | 40 | swap(nums[pos] , nums[i]) ; 41 | 42 | // Ask recursion to do rest of the task 43 | 44 | helper(pos + 1 , n , nums , ans) ; 45 | 46 | // Backtrack and undo the change we have done 47 | 48 | swap(nums[pos] , nums[i]) ; 49 | } 50 | 51 | return ; 52 | } 53 | 54 | public: 55 | vector> permuteUnique(vector& nums) { 56 | 57 | vector> ans ; 58 | 59 | helper(0 , nums.size() , nums , ans) ; 60 | 61 | return ans ; 62 | 63 | } 64 | }; 65 | 66 | /* 67 | Time Complexity = O(N * N!) 68 | Space Complexity = O(N) 69 | */ 70 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/LeetCode/Permutations II.py: -------------------------------------------------------------------------------- 1 | """ 2 | This question is exactly similar to Permutations - I 3 | Only difference being we have duplicate elements in nums[]. But we need to print Unique Permutations only 4 | For that purpose, we have used a local unordered_set data structure which tells us if that particular element has been previosuly encountered or not 5 | If we have taken / chosen the element before, we will not include it anymore. 6 | But if we haven't included the element, we will include it now 7 | """ 8 | class Solution: 9 | def permuteUnique(self, nums: List[int]) -> List[List[int]]: 10 | 11 | def helper(pos, n): 12 | 13 | # Base Case executes when we have traversed the entire nums[] 14 | if pos >= n: 15 | 16 | ans.append(nums.copy()) 17 | return 18 | 19 | # The rest logic remains exactly the same 20 | 21 | for i in range(pos, n): 22 | 23 | # We simply use our swapping logic to create Permutations 24 | 25 | nums[i], nums[pos] = nums[pos], nums[i] 26 | 27 | # And we ask Recursion to handle rest of the task 28 | # To ensure we're not storing any duplicate | we check if the nums is already not present in the ans [] 29 | if nums not in ans: 30 | helper(pos+1, n) 31 | 32 | # Backtrack and undo the change we have done 33 | 34 | nums[i], nums[pos] = nums[pos], nums[i] 35 | return 36 | 37 | ans = [] 38 | 39 | 40 | helper(0, len(nums)) 41 | 42 | return ans 43 | 44 | """ 45 | Time Complexity : O(N * N!) 46 | Space Complexity : O(N) 47 | """ 48 | -------------------------------------------------------------------------------- /Recursion/Lecture 09/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 47. Permutation II 2 | 3 | 4 | ### NOTE 5 | #### FOR PYTON CODE ONLY 6 | 1. PERMUTATIONII.PY code following lecture | As we can't store list in python set(), We have to search in ans arry to check for duplicate permutation of nums []. which would cost TC : O(N). 7 | 2. PERMUTATIONII.PY OPTIMISED CODE | In this code we have used python dictionary to store permutations of nums[]. On searching for duplicate it would cost TC : (1) 8 | -------------------------------------------------------------------------------- /Recursion/Lecture 10/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Subsets II -------------------------------------------------------------------------------- /Recursion/Lecture 10/CodeStudio/Subsets II.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | void helper(int i, vector &arr, vector &subset, vector> &ans) 3 | { 4 | // when we have traversed the entire arr[], then we should put arr into ans[] 5 | if (i >= arr.size()) 6 | { 7 | ans.push_back(subset); 8 | return; 9 | } 10 | 11 | // pick the ith element 12 | subset.push_back(arr[i]); 13 | 14 | // picked ith element and recursion will find the remaining subsets with ith element 15 | helper(i + 1, arr, subset, ans); 16 | 17 | // firstly, we need to backtrack and undo the changes that we have made 18 | subset.pop_back(); 19 | 20 | // ensure we don't pick any other occurrences ofi-th element in order to generate Unique Subsets 21 | while (i + 1 < arr.size() && arr[i] == arr[i + 1]) i++; 22 | 23 | // currentIndex will now point to the Last Occurrence of ith Element 24 | // we ignored ith element and now recursion will do find the remaining subsets without the ith element 25 | // skip the ith element 26 | helper(i + 1, arr, subset, ans); 27 | } 28 | 29 | vector> uniqueSubsets(int n, vector &arr) 30 | { 31 | // Write your code here. 32 | vector> ans; 33 | vector subset; 34 | 35 | // to ensure our logic work,we need a sorted array 36 | sort(arr.begin(), arr.end()); 37 | helper(0, arr, subset, ans); 38 | 39 | // this is specific to the given problem, they wanted each subset in sorted order 40 | sort(ans.begin(), ans.end()); 41 | return ans; 42 | } 43 | 44 | /* 45 | time complexity : O(2^n) 46 | space complexity : O(n) 47 | */ 48 | -------------------------------------------------------------------------------- /Recursion/Lecture 10/CodeStudio/Subsets II.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | def uniqueSubsets(n :int,arr :List[int]) -> List[List[int]]: 4 | 5 | def helper(i, subset, arr, ans): 6 | 7 | #Base Case, When we have reached the end of nums[] , we have generated a Valid Unique Subset for sure 8 | 9 | if i >= len(arr): 10 | ans.append(subset.copy()) 11 | return 12 | 13 | # pick the ith element 14 | subset.append(arr[i]) 15 | 16 | # picked ith element and recursion will find the remaining subsets with ith element | Left Subtree 17 | 18 | helper(i+1, subset, arr, ans) 19 | 20 | # firstly, we need to backtrack and undo the changes that we have made 21 | 22 | subset.pop() 23 | 24 | # ensure we don't pick any other occurrences ofi-th element in order to generate Unique Subsets 25 | 26 | while i+1 < len(arr) and arr[i] == arr[i+1]:#Preventon step 27 | i += 1 28 | 29 | # currentIndex will now point to the Last Occurrence of ith Element 30 | # we ignored ith element and now recursion will do find the remaining subsets without the ith element 31 | # skip the ith element 32 | 33 | helper(i+1, subset, arr, ans) 34 | 35 | # For our logic to work, we need to sort the given nums[] vector 36 | arr.sort() 37 | 38 | ans = [] 39 | 40 | subset= [] 41 | 42 | helper(0, subset, arr, ans) 43 | 44 | # this is specific to the given problem, they wanted each subset in sorted order 45 | ans.sort() 46 | return ans 47 | 48 | """ 49 | Time Complexity : O(2^N) 50 | Space Complexity : O(N) 51 | """ 52 | -------------------------------------------------------------------------------- /Recursion/Lecture 10/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## Subsets II 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 10/LeetCode/Subsets II.cpp: -------------------------------------------------------------------------------- 1 | /* This Question is exactly similar to Subsets - I. 2 | Instead of All Unique Elements we have given an array nums[] containing Dupicate Elements 3 | Our Logic remains the same. We will generate Subsets by using - Pick & Don't Pick condition only 4 | Only difference is that, while we are not picking any element, we must skip all it's Duplicate occrurrences in nums[] . 5 | This can be acheived by using a While Loop. Also we need to sort nums[] as the array might be given as unsorted 6 | */ 7 | 8 | class Solution { 9 | private : 10 | 11 | void helper(int i , vector &subset , vector &nums , vector> &ans) 12 | { 13 | // When we have reached the end of nums[] , we have generated a Valid Unique Subset for sure 14 | 15 | if(i >= nums.size() ) 16 | { 17 | ans.push_back(subset) ; 18 | return ; 19 | } 20 | 21 | // Otherwise we will use our Pick & Don't Pick Logic 22 | 23 | // Consider the Element 24 | 25 | subset.push_back(nums[i]) ; 26 | 27 | // Ask Recursion to do rest of the task 28 | 29 | helper(i + 1 , subset , nums , ans) ; 30 | 31 | // Backtrack and undo the change you have done 32 | 33 | subset.pop_back() ; 34 | 35 | // While using Don't Pick option, we must ensure we skip all the Duplicate Occurrences of nums[i] 36 | 37 | while(i < nums.size() - 1 && (nums[i] == nums[i + 1] ) ) 38 | { 39 | i++ ; 40 | } 41 | 42 | // Our i pointer will stop on the last Duplciate Occurencce of nums[i] 43 | 44 | // Don't Consider the Element and Ask Recursion to generate Unique Subsets 45 | 46 | helper(i + 1 , subset , nums , ans) ; 47 | 48 | return ; 49 | } 50 | 51 | public: 52 | vector> subsetsWithDup(vector& nums) { 53 | 54 | // For our logic to work, we need to sort the given nums[] vector 55 | 56 | sort(nums.begin() , nums.end() ) ; 57 | 58 | vectorsubset ; 59 | 60 | vector > ans ; 61 | 62 | // Call the helper() function to generate all Unique Subsets 63 | 64 | helper(0 , subset , nums , ans) ; 65 | 66 | return ans ; 67 | } 68 | }; 69 | 70 | /* 71 | Time Complexity : O(2^N) 72 | Space Complexity : O(N) 73 | */ 74 | -------------------------------------------------------------------------------- /Recursion/Lecture 10/LeetCode/Subsets II.java: -------------------------------------------------------------------------------- 1 | /* This Question is exactly similar to Subsets - I. 2 | Instead of All Unique Elements we have given an array nums[] containing Dupicate Elements 3 | Our Logic remains the same. We will generate Subsets by using - Pick & Don't Pick condition only 4 | Only difference is that, while we are not picking any element, we must skip all it's Duplicate occrurrences in nums[] . 5 | This can be acheived by using a While Loop. Also we need to sort nums[] as the array might be given as unsorted 6 | */ 7 | class Solution 8 | { 9 | public List> subsetsWithDup(int[] nums) 10 | { 11 | 12 | // In this logic we to sort the array 13 | 14 | Arrays.sort(nums); 15 | 16 | List> ans = new ArrayList<>(); 17 | 18 | helper(nums , 0, new ArrayList() , ans); 19 | 20 | return ans; 21 | } 22 | 23 | void helper(int nums[],int i,List subset,List> ans) 24 | { 25 | // Our base case will hit when our i pointer reaches the end of given array nums[] 26 | 27 | if(i==nums.length) 28 | { 29 | ans.add(new ArrayList<>(subset)); 30 | return ; 31 | } 32 | 33 | // We pick i-th Element 34 | 35 | subset.add(nums[i]); 36 | 37 | // We ask recursion to do rest of the task 38 | 39 | helper(nums, i + 1, subset, ans); 40 | 41 | // Backtrack and Undo the change we have done 42 | 43 | subset.remove(subset.size() - 1); 44 | 45 | // While using Don't Pick option, we must ensure we skip all the Duplicate Occurrences of nums[i] 46 | 47 | while(i < nums.length - 1 && (nums[i] == nums[i + 1] ) ) 48 | { 49 | i++ ; 50 | } 51 | 52 | // Our i pointer will stop on the last Duplciate Occurencce of nums[i] 53 | 54 | // Don't Consider the Element and Ask Recursion to generate Unique Subsets 55 | 56 | helper(nums, i + 1, subset, ans); 57 | return ; 58 | } 59 | } 60 | 61 | /* 62 | Time Complexity : O(2^N) 63 | Space Complexity : O(N) 64 | */ 65 | -------------------------------------------------------------------------------- /Recursion/Lecture 10/LeetCode/Subsets II.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: 3 | 4 | def helper(i, subset, nums, ans): 5 | 6 | #Base Case When we have reached the end of nums[] , we have generated a Valid Unique Subset for sure 7 | 8 | if i >= len(nums): #LVI 9 | ans.append(subset.copy()) 10 | return 11 | 12 | subset.append(nums[i]) 13 | 14 | # Ask Recursion to do rest of the task | Left Subtree 15 | 16 | helper(i+1, subset, nums, ans) 17 | 18 | # Backtrack and undo the change you have done 19 | 20 | subset.pop() 21 | 22 | # While using Don't Pick option, we must ensure we skip all the Duplicate Occurrences of nums[i] 23 | 24 | while i+1 < len(nums) and nums[i] == nums[i+1]:#Preventon step 25 | i += 1 26 | 27 | # Our i pointer will stop on the last Duplciate Occurencce of nums[i] 28 | # Don't Consider the Element and Ask Recursion to generate Unique Subsets | Right subtree 29 | 30 | helper(i+1, subset, nums, ans) 31 | 32 | # For our logic to work, we need to sort the given nums[] vector 33 | nums.sort() 34 | 35 | ans = [] 36 | 37 | subset= [] 38 | 39 | helper(0, subset, nums, ans) 40 | 41 | return ans 42 | 43 | """ 44 | Time Complexity : O(2^N) 45 | Space Complexity : O(N) 46 | """ 47 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/CodeStudio/Combinations.cpp: -------------------------------------------------------------------------------- 1 | void help(int i, int n, int k, vector &subSet, vector> &ans) 2 | { 3 | // base condition 4 | if (k == 0) 5 | { 6 | ans.push_back(subSet); 7 | return; 8 | } 9 | 10 | // if the required element (k) is greater than the remaining element (n - i + 1) in that case return because we are in the wrong direction & there is no point going any further down in this direction 11 | if (k > n - i + 1) 12 | return; 13 | 14 | if (i > n) 15 | return; 16 | 17 | // pick the ith element 18 | subSet.push_back(i); 19 | 20 | // ask recursion to do the remaining task 21 | help(i + 1, n, k - 1, subSet, ans); 22 | 23 | // backtrack & undo the changes that has been made 24 | subSet.pop_back(); 25 | 26 | // skip the ith element 27 | help(i + 1, n, k, subSet, ans); 28 | } 29 | 30 | vector> combinations(int n, int k) 31 | { 32 | vector subSet; 33 | vector> ans; 34 | help(1, n, k, subSet, ans); 35 | return ans; 36 | } 37 | 38 | /* 39 | time complexity : O(2^n) 40 | space complexity : O(n) 41 | */ 42 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/CodeStudio/Combinations.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | public class Solution 3 | { 4 | static void help(int i, int n, int k, ArrayList subSet, ArrayList> ans) 5 | { 6 | // If k is equal to 0, we have generated a Valid Subset of K length 7 | 8 | if (k == 0) 9 | { 10 | ans.add(new ArrayList(subSet)); 11 | return; 12 | } 13 | 14 | // If we don't have enough elements to make our subset, we shouldn't proceed further 15 | 16 | if (k > n - i + 1) 17 | return; 18 | 19 | // If i becomes greater than N, we should stop going forward 20 | 21 | if (i > n) 22 | return; 23 | 24 | // Our logic remains exactly same as Generating Subsets 25 | 26 | // Pick i-th Element 27 | 28 | subSet.add(i); 29 | 30 | // Ask Recursion to do the Rest of the Task 31 | 32 | help(i + 1, n, k - 1, subSet, ans); 33 | 34 | // Backtrack and undo the change 35 | 36 | subSet.remove(subSet.size()-1); 37 | 38 | // Don't pick the i-th Element 39 | 40 | help(i + 1, n, k, subSet, ans); 41 | } 42 | public static ArrayList> combinations(int n, int k) 43 | { 44 | ArrayList> ans = new ArrayList<>() ; 45 | ArrayList subSet = new ArrayList<>() ; 46 | 47 | help(1 , n , k , subSet , ans) ; 48 | 49 | return ans ; 50 | } 51 | 52 | } 53 | 54 | /* 55 | Time Complexity : O(2^N) 56 | Space Complexity : O(N) 57 | */ 58 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/CodeStudio/Combinations.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | 4 | def combinations(n :int,k :int) -> List[List[int]]: 5 | 6 | def helper(i, n, k): 7 | 8 | # base case | If k is equal to 0, we have generated a Valid Subset of K length 9 | if k == 0: 10 | ans.append(subSet.copy()) 11 | return 12 | 13 | # If we don't have enough elements to make our subset, we shouldn't proceed further 14 | if k > n-i+1: 15 | return 16 | 17 | # If i becomes greater than N, we should stop going forward 18 | if i > n: 19 | return 20 | 21 | # Our logic remains exactly same as Generating Subsets 22 | 23 | # Pick i-th Element 24 | subSet.append(i) 25 | 26 | # Ask Recursion to do the Rest of the Task 27 | helper(i + 1, n, k - 1) 28 | # Backtrack and undo the change 29 | subSet.pop() 30 | # Don't pick the i-th Element 31 | helper(i + 1, n, k) 32 | 33 | """ 34 | Note : we've to pass ans, subSet array by their references so we've not included it on the helper function's parameter 35 | """ 36 | ans = [] 37 | subSet = [] 38 | 39 | helper(1, n, k) 40 | return ans 41 | 42 | """ 43 | Time Complexity : O(2^N) 44 | Space Complexity : O(N) 45 | 46 | """ 47 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Combinations -------------------------------------------------------------------------------- /Recursion/Lecture 11/LeetCode/Combinations.cpp: -------------------------------------------------------------------------------- 1 | /* Generating Combinations is exactly similar to generating Subsets. 2 | At every stage we will - a) Pick i-th Element 3 | b) Don't Pick i-th Element 4 | Instead of giving us an array or vector, we are asked to generate all Combinations from 1 to N (both inclsive) and length of each Subset should be exactly K 5 | We use the same Pick & Don't Pick Logic to solve the Question 6 | We should always remember - Relative order matters in Combination just like Subsets 7 | */ 8 | 9 | class Solution { 10 | private : 11 | 12 | void help(int i, int n, int k, vector &subSet, vector> &ans) 13 | { 14 | // If k is equal to 0, we have generated a Valid Subset of K length 15 | 16 | if (k == 0) 17 | { 18 | ans.push_back(subSet); 19 | return; 20 | } 21 | 22 | // If we don't have enough elements to make our subset, we shouldn't proceed further 23 | 24 | if (k > n - i + 1) 25 | return; 26 | 27 | // If i becomes greater than N, we should stop going forward 28 | 29 | if (i > n) 30 | return; 31 | 32 | // Our logic remains exactly same as Generating Subsets 33 | 34 | // Pick i-th Element 35 | 36 | subSet.push_back(i); 37 | 38 | // Ask Recursion to do the Rest of the Task 39 | 40 | help(i + 1, n, k - 1, subSet, ans); 41 | 42 | // Backtrack and undo the change 43 | subSet.pop_back(); 44 | 45 | // Don't pick the i-th Element 46 | 47 | help(i + 1, n, k, subSet, ans); 48 | } 49 | 50 | public: 51 | vector> combine(int n, int k) { 52 | 53 | vector> ans ; 54 | vector subSet ; 55 | 56 | help(1 , n , k , subSet , ans) ; 57 | 58 | return ans ; 59 | } 60 | }; 61 | 62 | /* 63 | Time Complexity : O(2^N) 64 | Space Complexity : O(N) 65 | */ 66 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/LeetCode/Combinations.java: -------------------------------------------------------------------------------- 1 | /* Generating Combinations is exactly similar to generating Subsets. 2 | At every stage we will - a) Pick i-th Element 3 | b) Don't Pick i-th Element 4 | Instead of giving us an array or vector, we are asked to generate all Combinations from 1 to N (both inclsive) and length of each Subset should be exactly K 5 | We use the same Pick & Don't Pick Logic to solve the Question 6 | We should always remember - Relative order matters in Combination just like Subsets 7 | */ 8 | 9 | class Solution 10 | { 11 | public void help(int i, int n, int k, List subSet, List> ans) 12 | { 13 | // If k is equal to 0, we have generated a Valid Subset of K length 14 | 15 | if (k == 0) 16 | { 17 | ans.add(new ArrayList(subSet)); 18 | return; 19 | } 20 | 21 | // If we don't have enough elements to make our subset, we shouldn't proceed further 22 | 23 | if (k > n - i + 1) 24 | return; 25 | 26 | // If i becomes greater than N, we should stop going forward 27 | 28 | if (i > n) 29 | return; 30 | 31 | // Our logic remains exactly same as Generating Subsets 32 | 33 | // Pick i-th Element 34 | 35 | subSet.add(i); 36 | 37 | // Ask Recursion to do the Rest of the Task 38 | 39 | help(i + 1, n, k - 1, subSet, ans); 40 | 41 | // Backtrack and undo the change 42 | 43 | subSet.remove(subSet.size()-1); 44 | 45 | // Don't pick the i-th Element 46 | 47 | help(i + 1, n, k, subSet, ans); 48 | } 49 | public List> combine(int n, int k) 50 | { 51 | List> ans = new ArrayList<>() ; 52 | List subSet = new ArrayList<>() ; 53 | 54 | help(1 , n , k , subSet , ans) ; 55 | 56 | return ans ; 57 | } 58 | } 59 | 60 | /* 61 | Time Complexity : O(2^N) 62 | Space Complexity : O(N) 63 | */ 64 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/LeetCode/Combinations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generating Combinations is exactly similar to generating Subsets. 3 | At every stage we will - a) Pick i-th Element 4 | b) Don't Pick i-th Element 5 | Instead of giving us an array or vector, we are asked to generate all Combinations from 1 to N (both inclsive) and length of each Subset should be exactly K 6 | We use the same Pick & Don't Pick Logic to solve the Question 7 | We should always remember - Relative order matters in Combination just like Subsets 8 | 9 | 10 | """ 11 | 12 | class Solution: 13 | def combine(self, n: int, k: int) -> List[List[int]]: 14 | 15 | def helper(i, n, k): 16 | 17 | # base case | If k is equal to 0, we have generated a Valid Subset of K length 18 | if k == 0: 19 | ans.append(subSet.copy()) 20 | return 21 | 22 | # If we don't have enough elements to make our subset, we shouldn't proceed further 23 | if k > n-i+1: 24 | return 25 | 26 | # If i becomes greater than N, we should stop going forward 27 | if i > n: 28 | return 29 | 30 | # Our logic remains exactly same as Generating Subsets 31 | 32 | # Pick i-th Element 33 | 34 | subSet.append(i) 35 | 36 | # Ask Recursion to do the Rest of the Task 37 | 38 | helper(i + 1, n, k - 1) 39 | 40 | # Backtrack and undo the change 41 | subSet.pop() 42 | 43 | # Don't pick the i-th Element 44 | 45 | helper(i + 1, n, k) 46 | 47 | """ 48 | Note : we've to pass ans, subSet array by their references so we've not included it on the helper function's parameter 49 | """ 50 | ans = [] 51 | subSet = [] 52 | 53 | helper(1, n, k) 54 | return ans 55 | 56 | """ 57 | Time Complexity : O(2^N) 58 | Space Complexity : O(N) 59 | 60 | """ 61 | -------------------------------------------------------------------------------- /Recursion/Lecture 11/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 77. Combinations 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 12/CodeStudio/Combination Sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | void help(int i, vector &arr, int B, int sumTillNow, vector &subSet, vector> &ans) 5 | { 6 | // base condition 7 | // if sumTillNow == required sum (B) this means that we have reached a Valid Combination thus include it into the vector> ans 8 | if (sumTillNow == B) 9 | { 10 | ans.push_back(subSet); 11 | return; 12 | } 13 | 14 | // base condition 15 | // if sumTillNow > required sum (B) this means that we are exceeding the limit of required sum therefore simply return 16 | if (sumTillNow > B) 17 | return; 18 | 19 | // base condition 20 | // if current Index (i) is exceeding the array size then return 21 | if (i >= arr.size()) 22 | return; 23 | 24 | // skip the ith element 25 | help(i + 1, arr, B, sumTillNow, subSet, ans); 26 | 27 | // pick the ith element 28 | sumTillNow += arr[i]; 29 | subSet.push_back(arr[i]); 30 | 31 | // ask recursion to do the remaining task 32 | help(i, arr, B, sumTillNow, subSet, ans); 33 | 34 | // backtrack & undo the changes that were made while picking the ith element 35 | sumTillNow -= arr[i]; 36 | subSet.pop_back(); 37 | } 38 | 39 | vector> combSum(vector &ARR, int B) 40 | { 41 | vector subSet; 42 | int sumTillNow = 0; 43 | vector> ans; 44 | 45 | // as elements in each combination need to be sorted, therefore we are sorting ARR[] vector to ensure that our combinations are also generated in sorted manner 46 | sort(ARR.begin(), ARR.end()); 47 | help(0, ARR, B, sumTillNow, subSet, ans); 48 | return ans; 49 | } 50 | 51 | /* 52 | Time Complexity: O(Exponential) 53 | Space Complexity: O(TargetSum) {Recursive Stack Space} 54 | */ 55 | -------------------------------------------------------------------------------- /Recursion/Lecture 12/CodeStudio/Combination Sum.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | public class Solution 3 | { 4 | static void help(int i, ArrayList arr, int B, int sumTillNow, ArrayList subSet, ArrayList> ans) 5 | { 6 | 7 | // If our sumTillNow is equal to B(Target), we have reached a Valid Combination 8 | 9 | if(sumTillNow == B) 10 | { 11 | ans.add(new ArrayList(subSet)); 12 | return; 13 | } 14 | 15 | // If our sumTillNow exceeds B(Target), there's no point in proceeding further 16 | 17 | if(sumTillNow > B) return; 18 | 19 | // If we have reached the end of arr, we cannot go further as we don't have anymore elements 20 | 21 | if(i >= arr.size()) return; 22 | 23 | // We skip the i-th element 24 | 25 | help(i + 1, arr, B, sumTillNow, subSet, ans); 26 | 27 | // We include the i-th into our sumTillNow 28 | 29 | sumTillNow += arr.get(i); 30 | 31 | // We push the i-th Element into our subSet 32 | 33 | subSet.add(arr.get(i)); 34 | 35 | // We keep on the i-th Element & ask recursion to do rest of the task 36 | 37 | help(i, arr, B, sumTillNow, subSet, ans); 38 | 39 | // When we come back, we need to backtrack & undo the change 40 | 41 | sumTillNow -= arr.get(i); 42 | 43 | subSet.remove(subSet.size()-1); 44 | } 45 | public static ArrayList> combSum(ArrayList arr, int b) 46 | { 47 | ArrayList subSet = new ArrayList<>(); 48 | 49 | int sumTillNow = 0; 50 | 51 | ArrayList> ans = new ArrayList<>(); 52 | 53 | // This sorting ensures all the elements in each Subset are also in sorted order 54 | 55 | Collections.sort(arr); 56 | 57 | help(0, arr, b, sumTillNow, subSet, ans); 58 | 59 | return ans; 60 | } 61 | } 62 | 63 | /* 64 | Time Complexity: O(Expoential) or O(2^n) 65 | Space Complexity: O(n+m) n for stack memory and m = size of ans array 66 | */ 67 | -------------------------------------------------------------------------------- /Recursion/Lecture 12/CodeStudio/Combination Sum.py: -------------------------------------------------------------------------------- 1 | def combSum(ARR, B): 2 | 3 | def helper(i, sumTillNow): 4 | 5 | # base condition 6 | # if sumTillNow == required sum (B) this means that we have reached a Valid Combination thus include it into the ans [] 7 | 8 | if sumTillNow == B: 9 | ans.append(subSet.copy()) 10 | return 11 | # base condition 12 | # if sumTillNow > required sum (B) this means that we are exceeding the limit of required sum therefore simply return 13 | 14 | if sumTillNow > B: 15 | return 16 | 17 | # Base Case 18 | # if current Index (i) is exceeding the array size then return 19 | 20 | if i >= len(ARR): 21 | return 22 | 23 | # We skip the i-th element 24 | 25 | helper(i+1, sumTillNow) 26 | 27 | # We pick the ith element 28 | 29 | sumTillNow += ARR[i] 30 | subSet.append(ARR[i]) 31 | 32 | # We keep the i-th Element & ask recursion to do rest of the task 33 | 34 | helper(i, sumTillNow) 35 | 36 | # backtrack & undo the changes that were made while picking the ith element 37 | 38 | sumTillNow -= ARR[i] 39 | subSet.pop() 40 | 41 | # Global Scope reference variables 42 | subSet = [] 43 | ans = [] 44 | sumTillNow = 0 45 | 46 | # This sorting ensures all the elements in each Subset are also in sorted order 47 | 48 | ARR.sort() 49 | 50 | helper(0, sumTillNow) 51 | 52 | return ans 53 | 54 | """ 55 | Time Complexity: O(Exponential) or O(n^2) 56 | 57 | Explanation: : As it's very difficult to predict how many children one 58 | particular node can have, evident from the Recursive Tree, as one 59 | element can occur multiple times and also we won't be generating 60 | all the subsets in one go. So, the Time Complexity can be said to be 61 | Exponential only!! 62 | 63 | 64 | Space Complexity: O(n+m) | n for stack memory and m = size of ans array 65 | 66 | Explanation: Space Complexity will be equal to height of the recursive 67 | tree, Which in the worst Case is equal to Target-Sum if we had 1 in 68 | arr[] and we kept on picking only 1 till we reach Target-Sum. That's 69 | why Time complexity is (Target-Sum) 70 | """ 71 | -------------------------------------------------------------------------------- /Recursion/Lecture 12/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Combination Sum -------------------------------------------------------------------------------- /Recursion/Lecture 12/LeetCode/Combination Sum-1.cpp: -------------------------------------------------------------------------------- 1 | /* The idea of this question is to return all such combinations whose individual sum is equal to Target 2 | We use the same logic as generating Combinations - only difference is that we calculate the sum of each subset every time. 3 | We can use an element as many times as we want 4 | Our given vector arr[] contains only Unique Subsets that's for sure 5 | */ 6 | 7 | class Solution { 8 | private : 9 | 10 | void help(int i, vector &arr, int B, int sumTillNow, vector &subSet, vector> &ans) { 11 | 12 | // If our sumTillNow is equal to B(Target), we have reached a Valid Combination 13 | 14 | if(sumTillNow == B) 15 | { 16 | ans.push_back(subSet); 17 | return; 18 | } 19 | 20 | // If our sumTillNow exceeds B(Target), there's no point in proceeding further 21 | 22 | if(sumTillNow > B) return; 23 | 24 | // If we have reached the end of arr[], we cannot go further as we don't have anymore elements 25 | 26 | if(i >= arr.size()) return; 27 | 28 | // We skip the i-th element 29 | 30 | help(i + 1, arr, B, sumTillNow, subSet, ans); 31 | 32 | // We include the i-th into our sumTillNow 33 | 34 | sumTillNow += arr[i]; 35 | 36 | // We push the i-th Element into our subSet 37 | 38 | subSet.push_back(arr[i]); 39 | 40 | // We keep on the i-th Element & ask recursion to do rest of the task 41 | 42 | help(i, arr, B, sumTillNow, subSet, ans); 43 | 44 | // When we come back, we need to backtrack & undo the change 45 | 46 | sumTillNow -= arr[i]; 47 | 48 | subSet.pop_back(); 49 | } 50 | 51 | 52 | public: 53 | vector> combinationSum(vector& candidates, int target) { 54 | 55 | vector subSet; 56 | 57 | int sumTillNow = 0; 58 | 59 | vector> ans; 60 | 61 | // This sorting ensures all the elements in each Subset are also in sorted order 62 | 63 | sort(candidates.begin(), candidates.end()); 64 | 65 | help(0, candidates, target, sumTillNow, subSet, ans); 66 | 67 | return ans; 68 | } 69 | }; 70 | 71 | /* 72 | Time Complexity: O(Exponential) 73 | Space Complexity: O(TargetSum) {Recursive Stack Space} 74 | */ 75 | -------------------------------------------------------------------------------- /Recursion/Lecture 12/LeetCode/Combination Sum.java: -------------------------------------------------------------------------------- 1 | 2 | /* The idea of this question is to return all such combinations whose individual sum is equal to Target 3 | We use the same logic as generating Combinations - only difference is that we calculate the sum of each subset every time. 4 | We can use an element as many times as we want 5 | Our given array arr[] contains only Unique Subsets that's for sure 6 | */ 7 | 8 | class Solution 9 | { 10 | public void help(int i, int[] arr, int B, int sumTillNow, List subSet, List> ans) 11 | { 12 | 13 | // If our sumTillNow is equal to B(Target), we have reached a Valid Combination 14 | 15 | if(sumTillNow == B) 16 | { 17 | ans.add(new ArrayList(subSet)); 18 | return; 19 | } 20 | 21 | // If our sumTillNow exceeds B(Target), there's no point in proceeding further 22 | 23 | if(sumTillNow > B) return; 24 | 25 | // If we have reached the end of arr[], we cannot go further as we don't have anymore elements 26 | 27 | if(i >= arr.length) return; 28 | 29 | // We skip the i-th element 30 | 31 | help(i + 1, arr, B, sumTillNow, subSet, ans); 32 | 33 | // We include the i-th into our sumTillNow 34 | 35 | sumTillNow += arr[i]; 36 | 37 | // We push the i-th Element into our subSet 38 | 39 | subSet.add(arr[i]); 40 | 41 | // We keep on the i-th Element & ask recursion to do rest of the task 42 | 43 | help(i, arr, B, sumTillNow, subSet, ans); 44 | 45 | // When we come back, we need to backtrack & undo the change 46 | 47 | sumTillNow -= arr[i]; 48 | 49 | subSet.remove(subSet.size()-1); 50 | } 51 | public List> combinationSum(int[] candidates, int target) 52 | { 53 | List subSet = new ArrayList<>(); 54 | 55 | int sumTillNow = 0; 56 | 57 | List> ans = new ArrayList<>(); 58 | 59 | // This sorting ensures all the elements in each Subset are also in sorted order 60 | 61 | Arrays.sort(candidates); 62 | 63 | help(0, candidates, target, sumTillNow, subSet, ans); 64 | 65 | return ans; 66 | } 67 | } 68 | 69 | /* 70 | Time Complexity: O(Expoential) or O(2^n) 71 | Space Complexity: O(n+m) n for stack memory and m = size of ans array 72 | */ 73 | -------------------------------------------------------------------------------- /Recursion/Lecture 12/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 39. Combination Sum 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 13/CodeStudio/Combination Sum II.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace std; 4 | 5 | void help(int i, vector &arr, int n, vector &subSet, vector> &powerSet, int sum, int target) 6 | { 7 | // base condition 8 | // when sum == target this means that we have reached a Valid Combination thus include it into the vector> powerSet 9 | if (sum == target) 10 | { 11 | powerSet.push_back(subSet); 12 | return; 13 | } 14 | 15 | // base condition 16 | // when sum > target this means that we are exceeding the limit of the required sum (target) therefore simply return 17 | if (sum > target) 18 | return; 19 | 20 | // base condition 21 | // if current Index (i) is exceeding the array size then return 22 | if (i == n) 23 | return; 24 | 25 | // pick the ith element 26 | subSet.push_back(arr[i]); 27 | sum += arr[i]; 28 | 29 | // ask recursion to do the remaining task 30 | help(i + 1, arr, n, subSet, powerSet, sum, target); 31 | 32 | // backtrack & undo the changes that were made while picking the ith element 33 | subSet.pop_back(); 34 | sum -= arr[i]; 35 | 36 | // loop to ensure that we don't pick any other occurrences of ith element 37 | while (i + 1 < arr.size() && arr[i] == arr[i + 1]) 38 | i++; 39 | 40 | // skip the ith element 41 | help(i + 1, arr, n, subSet, powerSet, sum, target); 42 | } 43 | 44 | vector> combinationSum2(vector &arr, int n, int target) 45 | { 46 | vector subSet; 47 | vector> powerSet; 48 | int sum = 0; 49 | 50 | // as we have to bring all the similar elements together therefore we need to sort arr[] 51 | // now as all the similar elements comes together therefore we will be able to ignore all the duplicate occurences of elements 52 | sort(arr.begin(), arr.end()); 53 | help(0, arr, n, subSet, powerSet, sum, target); 54 | return powerSet; 55 | } 56 | 57 | /* 58 | time complexity : O(2^n) 59 | space complexity : O(n) 60 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 13/CodeStudio/Combination Sum II.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.*; 3 | public class Solution 4 | { 5 | static void help(int i, ArrayList arr, int n, ArrayList subSet, ArrayList> powerSet, int sum, int target) 6 | { 7 | 8 | // If sum is equal to target, we have reached a Valid Combination 9 | 10 | if(sum == target) 11 | { 12 | powerSet.add(new ArrayList(subSet)) ; 13 | return; 14 | } 15 | 16 | // If at any moment, sum becomes greater than target, we don't need to proceed further 17 | 18 | if(sum > target) return ; 19 | 20 | // If we reach the end of arr, we cannot go any further so we return back 21 | 22 | if(i == n) return; 23 | 24 | // Include the i-th Element into our Subset & Sum 25 | 26 | subSet.add(arr.get(i)) ; 27 | sum += arr.get(i) ; 28 | 29 | // Ask recursion to do rest of the task 30 | help(i + 1, arr, n, subSet, powerSet, sum, target) ; 31 | 32 | // Backtrack and undo the change we have done 33 | 34 | subSet.remove(subSet.size()-1); 35 | sum -= arr.get(i); 36 | 37 | // Use the While Loop to skip all the duplicate occurrences of i-th Element 38 | 39 | while(i + 1 < arr.size() && arr.get(i) == arr.get(i+1)) i++ ; 40 | 41 | // Don't pick the i-th Element and ask recursion to do rest of the task 42 | 43 | help(i + 1, arr, n, subSet, powerSet, sum, target) ; 44 | } 45 | public static ArrayList> combinationSum2(ArrayList arr, int n, int target) 46 | { 47 | ArrayList subSet = new ArrayList<>() ; 48 | ArrayList> powerSet = new ArrayList<>() ; 49 | int sum = 0; 50 | Collections.sort(arr) ; 51 | 52 | help(0, arr, n, subSet, powerSet, sum, target) ; 53 | 54 | return powerSet ; 55 | } 56 | } 57 | 58 | /* 59 | Time Complexity: O(2^N) 60 | Space Complexity: O(N) 61 | */ 62 | -------------------------------------------------------------------------------- /Recursion/Lecture 13/CodeStudio/Combination Sum-II.py: -------------------------------------------------------------------------------- 1 | """ 2 | This question is exactly similar to Combination Sum -I. 3 | The only difference is that we have duplicates inside the given arr[]. 4 | We need to skip the duplicate elements. Else they would generate Duplicate Combinations which we don't want. 5 | To skip the Duplicate Elements, we will sort candidates [] and use a While Loop to skip all the Duplicate Elements. 6 | 7 | In python we need to pass candidates [], powerSet [] to pass by reference so we are'nt including those in the helper() parameter. 8 | 9 | Note : 10 | Please reffer this article befoe solving the problem to understand the naming convention. 11 | """ 12 | # link - https://leetcode.com/discuss/interview-question/2357412/Subarray-vs-Subsequence-vs-Subset-vs-Powerset 13 | 14 | def combinationSum2(arr, n, target): 15 | 16 | def helper(i, n, subsetSum): 17 | 18 | # BASE CONDITIONS 19 | # If sum is equal to target, we have reached a Valid Combination 20 | 21 | if subsetSum == target: 22 | powerSet.append(subset.copy()) 23 | return 24 | 25 | # If at any moment, sum becomes greater than target, we don't need to proceed further 26 | 27 | if subsetSum > target: 28 | return 29 | # If we reach the end of arr[], we cannot go any further so we return back 30 | 31 | if i == n: 32 | return 33 | 34 | # include the i-th element into our subseq & subseqSum 35 | 36 | subset.append(arr[i]) 37 | subsetSum += arr[i] 38 | 39 | # Ask recursion to do rest of the task 40 | 41 | helper(i+1, n, subsetSum) 42 | 43 | # Backtrack and undo the change we have done 44 | 45 | subset.pop() 46 | subsetSum -= arr[i] 47 | 48 | # use the While Loop to skip all the duplicate occurrences of i-th Element 49 | 50 | while i+1 < len(arr) and arr[i] == arr[i+1]: 51 | i += 1 52 | # Don't pick the i-th Element and ask recursion to do rest of the task 53 | 54 | helper(i+1, n, subsetSum) 55 | 56 | subset = [] 57 | powerSet = [] 58 | subsetSum = 0 59 | 60 | arr.sort() 61 | 62 | helper(0, n, subsetSum) 63 | 64 | return powerSet 65 | 66 | """ 67 | Time Complexity: O(2^N) 68 | Space Complexity: O(N) 69 | """ 70 | -------------------------------------------------------------------------------- /Recursion/Lecture 13/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Combination Sum II -------------------------------------------------------------------------------- /Recursion/Lecture 13/LeetCode/Combination Sum II.java: -------------------------------------------------------------------------------- 1 | /* This question is exactly similar to Combination Sum -I. 2 | The only difference is that we have duplicates inside the given array arr[] 3 | We need to skip the duplicate elements. Else they would generate Duplicate Combinations which we don't want 4 | To skip the Duplicate Elements, we will sort arr[] and use a While Loop to skip all the Duplicate Elements 5 | */ 6 | 7 | class Solution 8 | { 9 | public void help(int i, int[] arr, int n, List subSet, List> powerSet, int sum, int target) 10 | { 11 | 12 | // If sum is equal to target, we have reached a Valid Combination 13 | 14 | if(sum == target) 15 | { 16 | powerSet.add(new ArrayList(subSet)) ; 17 | return; 18 | } 19 | 20 | // If at any moment, sum becomes greater than target, we don't need to proceed further 21 | 22 | if(sum > target) return ; 23 | 24 | // If we reach the end of arr[], we cannot go any further so we return back 25 | 26 | if(i == n) return; 27 | 28 | // Include the i-th Element into our Subset & Sum 29 | 30 | subSet.add(arr[i]) ; 31 | sum += arr[i] ; 32 | 33 | // Ask recursion to do rest of the task 34 | help(i + 1, arr, n, subSet, powerSet, sum, target) ; 35 | 36 | // Backtrack and undo the change we have done 37 | 38 | subSet.remove(subSet.size()-1); 39 | sum -= arr[i]; 40 | 41 | // Use the While Loop to skip all the duplicate occurrences of i-th Element 42 | 43 | while(i + 1 < arr.length && arr[i] == arr[i + 1]) i++ ; 44 | 45 | // Don't pick the i-th Element and ask recursion to do rest of the task 46 | 47 | help(i + 1, arr, n, subSet, powerSet, sum, target) ; 48 | } 49 | public List> combinationSum2(int[] candidates, int target) 50 | { 51 | List subSet = new ArrayList<>() ; 52 | List> powerSet = new ArrayList<>() ; 53 | int sum = 0; 54 | int n = candidates.length ; 55 | Arrays.sort(candidates) ; 56 | 57 | help(0, candidates, n, subSet, powerSet, sum, target) ; 58 | 59 | return powerSet ; 60 | } 61 | } 62 | 63 | /* 64 | Time Complexity: O(2^N) 65 | Space Complexity: O(N) 66 | */ 67 | -------------------------------------------------------------------------------- /Recursion/Lecture 13/LeetCode/Combination Sum-2.cpp: -------------------------------------------------------------------------------- 1 | /* This question is exactly similar to Combination Sum -I. 2 | The only difference is that we have duplicates inside the given vector arr[] 3 | We need to skip the duplicate elements. Else they would generate Duplicate Combinations which we don't want 4 | To skip the Duplicate Elements, we will sort arr[] and use a While Loop to skip all the Duplicate Elements 5 | */ 6 | 7 | class Solution { 8 | private : 9 | 10 | void help(int i, vector &arr, int n, vector &subSet, vector> &powerSet, int sum, int target) { 11 | 12 | // If sum is equal to target, we have reached a Valid Combination 13 | 14 | if(sum == target) 15 | { 16 | powerSet.push_back(subSet) ; 17 | return; 18 | } 19 | 20 | // If at any moment, sum becomes greater than target, we don't need to proceed further 21 | 22 | if(sum > target) return ; 23 | 24 | // If we reach the end of arr[], we cannot go any further so we return back 25 | 26 | if(i == n) return; 27 | 28 | // Include the i-th Element into our Subset & Sum 29 | 30 | subSet.push_back(arr[i]) ; 31 | sum += arr[i] ; 32 | 33 | // Ask recursion to do rest of the task 34 | help(i + 1, arr, n, subSet, powerSet, sum, target) ; 35 | 36 | // Backtrack and undo the change we have done 37 | 38 | subSet.pop_back(); 39 | sum -= arr[i]; 40 | 41 | // Use the While Loop to skip all the duplicate occurrences of i-th Element 42 | 43 | while(i + 1 < arr.size() && arr[i] == arr[i + 1]) i++ ; 44 | 45 | // Don't pick the i-th Element and ask recursion to do rest of the task 46 | 47 | help(i + 1, arr, n, subSet, powerSet, sum, target) ; 48 | } 49 | 50 | 51 | public: 52 | vector> combinationSum2(vector& candidates, int target) { 53 | 54 | vector subSet ; 55 | vector> powerSet ; 56 | int sum = 0; 57 | int n = candidates.size() ; 58 | sort(candidates.begin(), candidates.end()) ; 59 | 60 | help(0, candidates, n, subSet, powerSet, sum, target) ; 61 | 62 | return powerSet ; 63 | } 64 | }; 65 | 66 | /* 67 | Time Complexity: O(2^N) 68 | Space Complexity: O(N) 69 | */ 70 | -------------------------------------------------------------------------------- /Recursion/Lecture 13/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 40. Combination Sum II 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 14/CodeStudio/Combination Sum III.cpp: -------------------------------------------------------------------------------- 1 | void help(int i, int k, int sumTillNow, int n, vector &subSet, vector> &ans) 2 | { 3 | // base condition 4 | // if the sumTillNow becomes greater than n, then we don't need to proceed further 5 | if (sumTillNow > n) 6 | return; 7 | 8 | // base condition 9 | // if k becomes equal to zero(0) , then check if the sumTillNow is equal to n or not 10 | if (k == 0) 11 | { 12 | // if the sumTillNow is equal to n, then include the subset into ans[][] 13 | if (sumTillNow == n) 14 | { 15 | ans.push_back(subSet); 16 | } 17 | 18 | // else we simply return without including the subset 19 | return; 20 | } 21 | 22 | // base condition 23 | // if i becomes equal to 10, then we don't need to proceed any further 24 | if (i == 10) 25 | return; 26 | 27 | // pick the ith element 28 | sumTillNow += i; 29 | subSet.push_back(i); 30 | 31 | // ask recursion to do the rest of the task 32 | help(i + 1, k - 1, sumTillNow, n, subSet, ans); 33 | 34 | // backtrack and undo the changes that have been done 35 | sumTillNow -= i; 36 | subSet.pop_back(); 37 | 38 | // skip ith element 39 | help(i + 1, k, sumTillNow, n, subSet, ans); 40 | } 41 | vector> combinationSum3(int k, int n) 42 | { 43 | // Write your code here. 44 | vector subSet; 45 | vector> ans; 46 | help(1, k, 0, n, subSet, ans); 47 | return ans; 48 | } 49 | 50 | /* 51 | time complexity: O(2^K) 52 | space complexity: O(K) 53 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 14/CodeStudio/Combination Sum III.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | public class Solution 3 | { 4 | static void help(int i, int k, int sumTillNow, int n, ArrayList subSet, ArrayList> ans) 5 | { 6 | // If the Sum-Till-Now becomes greater than n, we don't need to proceed further 7 | 8 | if(sumTillNow > n) 9 | return ; 10 | 11 | // If k becomes equal to zero(0) , we need to check if the Sum-Till-Now is equal to n or not 12 | 13 | if(k == 0) 14 | { 15 | // If the Sum-Till-Now is equal to n, we include the Subset into our ans 16 | 17 | if(sumTillNow == n) 18 | { 19 | ans.add(new ArrayList(subSet)); 20 | } 21 | 22 | // Else we simply return without including the Subset 23 | 24 | return; 25 | } 26 | 27 | // If i becomes equal to 10, we don't need to proceed any further 28 | 29 | if(i == 10) 30 | return ; 31 | 32 | // We include the i-th Number into our Sum-Till-Now & also into our Subset 33 | 34 | sumTillNow += i ; 35 | subSet.add(i) ; 36 | 37 | // Ask Recursion to do the rest of the task 38 | 39 | help(i + 1, k - 1, sumTillNow, n, subSet, ans) ; 40 | 41 | // Backtrack and undo the change we have done 42 | 43 | sumTillNow -= i ; 44 | subSet.remove(subSet.size()-1) ; 45 | 46 | // We don't include the i-th Number and ask recursion to do the rest of the Combinations 47 | 48 | help(i + 1, k, sumTillNow, n, subSet, ans); 49 | 50 | } 51 | static ArrayList> combinationSum3(int k, int n) 52 | { 53 | ArrayList subSet = new ArrayList<>(); 54 | 55 | ArrayList> ans = new ArrayList<>(); 56 | 57 | help(1, k, 0, n, subSet, ans) ; 58 | 59 | return ans ; 60 | } 61 | } 62 | 63 | /* 64 | Time Complexity: O(2^N) 65 | Space Complexity: O(K) 66 | */ 67 | -------------------------------------------------------------------------------- /Recursion/Lecture 14/CodeStudio/Combination Sum-III.py: -------------------------------------------------------------------------------- 1 | """ 2 | This question is exactly similar to Combination Sum -I. 3 | The only difference is that we have duplicates inside the given vector arr[] 4 | We need to skip the duplicate elements. Else they would generate Duplicate Combinations which we don't want 5 | To skip the Duplicate Elements, we will sort arr[] and use a While Loop to skip all the Duplicate Elements 6 | 7 | NOTE: 8 | As we haev to pass subset [] and ans [] by it's reference I haven't incuded it in heper() parameter 9 | """ 10 | def combinationSum3(K: int, N: int) -> [[]]: 11 | 12 | def helper(i, k, sumTillNow , n): 13 | 14 | # If the Sum-Till-Now becomes greater than n, we don't need to proceed further 15 | 16 | if sumTillNow > n: 17 | return 18 | 19 | # If k becomes equal to zero(0) , we need to check if the Sum-Till-Now is equal to n or not 20 | 21 | if k == 0: 22 | 23 | # If the Sum-Till-Now is equal to n, we include the Subset into our ans[][] 24 | 25 | if sumTillNow == n: 26 | ans.append(subset.copy()) 27 | 28 | # else we simply return without including the Subset 29 | 30 | return 31 | 32 | # If i becomes equal to 10, we don't need to proceed any further 33 | 34 | if i == 10: 35 | return 36 | 37 | # We include the i-th Number into our Sum-Till-Now & also into our Subset[] 38 | 39 | sumTillNow += i 40 | subset.append(i) 41 | 42 | # Ask Recursion to do the rest of the task 43 | 44 | helper(i+1, k-1, sumTillNow, n) 45 | 46 | # Backtrack and undo the change we have done 47 | 48 | subset.pop() 49 | sumTillNow -= i 50 | 51 | # We don't include the i-th Number and ask recursion to do the rest of the Combinations 52 | helper(i+1, k, sumTillNow, n) 53 | 54 | subset = [] 55 | 56 | ans = [] 57 | 58 | helper(1, K, 0, N) 59 | 60 | return ans 61 | 62 | """ 63 | Time Complexity: O(2^N) 64 | Space Complexity: O(K) 65 | """ 66 | -------------------------------------------------------------------------------- /Recursion/Lecture 14/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Combination Sum III -------------------------------------------------------------------------------- /Recursion/Lecture 14/LeetCode/Combination Sum III.java: -------------------------------------------------------------------------------- 1 | /* This question is the continuation of Combination Sum 1 & 2 2 | The only difference is that, instead of giving us an array 3 | We are asked to print all possible combinations using numbers 1 to 9 (both inclusive) 4 | */ 5 | 6 | class Solution 7 | { 8 | public void help(int i, int k, int sumTillNow, int n, List subSet, List> ans) 9 | { 10 | // If the Sum-Till-Now becomes greater than n, we don't need to proceed further 11 | 12 | if(sumTillNow > n) 13 | return ; 14 | 15 | // If k becomes equal to zero(0) , we need to check if the Sum-Till-Now is equal to n or not 16 | 17 | if(k == 0) 18 | { 19 | // If the Sum-Till-Now is equal to n, we include the Subset into our ans 20 | 21 | if(sumTillNow == n) 22 | { 23 | ans.add(new ArrayList(subSet)); 24 | } 25 | 26 | // Else we simply return without including the Subset 27 | 28 | return; 29 | } 30 | 31 | // If i becomes equal to 10, we don't need to proceed any further 32 | 33 | if(i == 10) 34 | return ; 35 | 36 | // We include the i-th Number into our Sum-Till-Now & also into our Subset 37 | 38 | sumTillNow += i ; 39 | subSet.add(i) ; 40 | 41 | // Ask Recursion to do the rest of the task 42 | 43 | help(i + 1, k - 1, sumTillNow, n, subSet, ans) ; 44 | 45 | // Backtrack and undo the change we have done 46 | 47 | sumTillNow -= i ; 48 | subSet.remove(subSet.size()-1) ; 49 | 50 | // We don't include the i-th Number and ask recursion to do the rest of the Combinations 51 | 52 | help(i + 1, k, sumTillNow, n, subSet, ans); 53 | 54 | } 55 | public List> combinationSum3(int k, int n) 56 | { 57 | List subSet = new ArrayList<>(); 58 | 59 | List> ans = new ArrayList<>(); 60 | 61 | help(1, k, 0, n, subSet, ans) ; 62 | 63 | return ans ; 64 | } 65 | } 66 | 67 | /* 68 | Time Complexity: O(2^N) 69 | Space Complexity: O(K) 70 | */ 71 | -------------------------------------------------------------------------------- /Recursion/Lecture 14/LeetCode/Combination Sum-3.cpp: -------------------------------------------------------------------------------- 1 | /* This question is the continuation of Combination Sum 1 & 2 2 | The only difference is that, instead of giving us an array / vector, 3 | We are asked to print all possible combinations using numbers 1 to 9 (both inclusive) 4 | */ 5 | 6 | class Solution { 7 | private : 8 | 9 | void help(int i, int k, int sumTillNow, int n, vector &subSet, vector> &ans) 10 | { 11 | // If the Sum-Till-Now becomes greater than n, we don't need to proceed further 12 | 13 | if(sumTillNow > n) 14 | return ; 15 | 16 | // If k becomes equal to zero(0) , we need to check if the Sum-Till-Now is equal to n or not 17 | 18 | if(k == 0) 19 | { 20 | // If the Sum-Till-Now is equal to n, we include the Subset into our ans[][] 21 | 22 | if(sumTillNow == n) 23 | { 24 | ans.push_back(subSet); 25 | } 26 | 27 | // Else we simply return without including the Subset 28 | 29 | return; 30 | } 31 | 32 | // If i becomes equal to 10, we don't need to proceed any further 33 | 34 | if(i == 10) 35 | return ; 36 | 37 | // We include the i-th Number into our Sum-Till-Now & also into our Subset[] 38 | 39 | sumTillNow += i ; 40 | subSet.push_back(i) ; 41 | 42 | // Ask Recursion to do the rest of the task 43 | 44 | help(i + 1, k - 1, sumTillNow, n, subSet, ans) ; 45 | 46 | // Backtrack and undo the change we have done 47 | 48 | sumTillNow -= i ; 49 | subSet.pop_back() ; 50 | 51 | // We don't include the i-th Number and ask recursion to do the rest of the Combinations 52 | 53 | help(i + 1, k, sumTillNow, n, subSet, ans); 54 | 55 | } 56 | 57 | public: 58 | vector> combinationSum3(int k, int n) { 59 | 60 | vector subSet ; 61 | 62 | vector> ans ; 63 | 64 | help(1, k, 0, n, subSet, ans) ; 65 | 66 | return ans ; 67 | } 68 | }; 69 | 70 | /* 71 | Time Complexity: O(2^N) 72 | Space Complexity: O(K) 73 | */ 74 | -------------------------------------------------------------------------------- /Recursion/Lecture 14/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 216. Combination Sum III 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 15/CodeStudio/Letter Combinations of a Phone Number.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | void help(int i, string &s, string &temp, vector &ans, unordered_map &m) 5 | { 6 | // base condition 7 | // i : current Index 8 | // if we have reached till the end of the string s then include temp into ans[][] 9 | if (i == s.size()) 10 | { 11 | ans.push_back(temp); 12 | return; 13 | } 14 | 15 | // this gives the entire string that is present in the map m corresponding to the ith element in the string s 16 | // eg: s = 2 3, i = 1 17 | // str = m[s[i]] = m[s[1]] = m[3] = def 18 | string str = m[s[i]]; 19 | 20 | // loop for traversing every element in str 21 | for (int j = 0; j < str.size(); j++) 22 | { 23 | // do the small task 24 | temp.push_back(str[j]); 25 | 26 | // ask recursion to do the remaining task 27 | help(i + 1, s, temp, ans, m); 28 | 29 | // backtrack & undo the changes that were made 30 | temp.pop_back(); 31 | } 32 | } 33 | 34 | vector combinations(string s) 35 | { 36 | // for solving this problem we need to know what all characters are represented by each of the numbers 37 | // therefore we are storing all the corresponding characters from digit 2 to 9 in the unordered_map m 38 | unordered_map m; 39 | m['2'] = "abc"; 40 | m['3'] = "def"; 41 | m['4'] = "ghi"; 42 | m['5'] = "jkl"; 43 | m['6'] = "mno"; 44 | m['7'] = "pqrs"; 45 | m['8'] = "tuv"; 46 | m['9'] = "wxyz"; 47 | 48 | vector ans; 49 | string temp; 50 | help(0, s, temp, ans, m); 51 | return ans; 52 | } 53 | 54 | /* 55 | time complexity: O(3^N) 56 | space complexity: O(N) 57 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 15/CodeStudio/Letter Combinations of a Phone Number.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.*; 3 | public class Solution 4 | { 5 | static void help(int i, String s, String temp, ArrayList ans, HashMap m) 6 | { 7 | // If i has reached till the end of given string, we have reached a Valid Combination 8 | // We should include it into ans and return back 9 | 10 | if (i == s.length()) 11 | { 12 | ans.add(temp); 13 | return; 14 | } 15 | 16 | // Since, we have mapped all the digits with their corresponding Letters 17 | // m.get( s.charAt(i) ) will give us the actual string corresponding to that digit using HashMap m 18 | 19 | char chr = s.charAt(i); 20 | String str = m.get(chr); 21 | 22 | // loop for traversing every element in str 23 | 24 | for (int j = 0; j < str.length(); j++) 25 | { 26 | 27 | char c = str.charAt(j); 28 | 29 | // Ask recursion to do rest of the task 30 | 31 | help(i + 1, s, temp + c, ans, m); 32 | 33 | } 34 | } 35 | public static ArrayList combinations(String s) 36 | { 37 | // To solve this question, we need to map all the letters of a particular digit with it's corresponding digit. This is done with the help of HashMap m. 38 | 39 | HashMap m = new HashMap<>(); 40 | m.put('2',"abc"); 41 | m.put('3',"def"); 42 | m.put('4',"ghi"); 43 | m.put('5',"jkl"); 44 | m.put('6',"mno"); 45 | m.put('7',"pqrs"); 46 | m.put('8',"tuv"); 47 | m.put('9',"wxyz"); 48 | 49 | ArrayList ans = new ArrayList<>(); 50 | 51 | if(s.length() == 0) 52 | return ans; 53 | 54 | String temp = ""; 55 | 56 | help(0 , s , temp , ans , m) ; 57 | 58 | return ans; 59 | } 60 | } 61 | 62 | /* 63 | Time Complexity: O(3^N) 64 | Space Complexity: O(N) 65 | */ 66 | -------------------------------------------------------------------------------- /Recursion/Lecture 15/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Letter Combinations of a Phone Number -------------------------------------------------------------------------------- /Recursion/Lecture 15/LeetCode/Letter Combination of a Phone Number.cpp: -------------------------------------------------------------------------------- 1 | /* This question requries us to print all Valid Combinations of the given string digits which comprises of digits from 2 to 9. 2 | The only thing we require extra in this question is to map all the letter combinations of the phone number to its corresponding digits. 3 | The rest part of the question remains exactly same 4 | */ 5 | 6 | class Solution { 7 | private: 8 | 9 | void help(int i, string &s, string &temp, vector &ans, unordered_map &m) 10 | { 11 | // If i has reached till the end of given string, we have reached a Valid Combination 12 | // We should include it into ans[][] and return back 13 | 14 | if (i == s.size()) 15 | { 16 | ans.push_back(temp); 17 | return; 18 | } 19 | 20 | // Since, we have mapped all the digits with their corresponding Letters 21 | // m[s[i]] will give us the actual string corresponding to that digit using unordered_map m 22 | 23 | string str = m[s[i]]; 24 | 25 | // loop for traversing every element in str 26 | 27 | for (int j = 0; j < str.size(); j++) 28 | { 29 | // Push the i-th character of str into our temp string 30 | 31 | temp.push_back(str[j]); 32 | 33 | // Ask recursion to do rest of the task 34 | 35 | help(i + 1, s, temp, ans, m); 36 | 37 | // Backtrack and undo the change we have already done 38 | 39 | temp.pop_back(); 40 | } 41 | } 42 | 43 | public: 44 | vector letterCombinations(string digits) { 45 | 46 | // As per the problem, for an empty string, we need to return an empty vector 47 | 48 | if(digits.size() == 0) 49 | return {} ; 50 | 51 | // To solve this question, we need to map all the letters of a particular digit with it's corresponding digit. This is done with the help of unordered_map m. 52 | 53 | unordered_map m; 54 | m['2'] = "abc"; 55 | m['3'] = "def"; 56 | m['4'] = "ghi"; 57 | m['5'] = "jkl"; 58 | m['6'] = "mno"; 59 | m['7'] = "pqrs"; 60 | m['8'] = "tuv"; 61 | m['9'] = "wxyz"; 62 | 63 | vector ans ; 64 | 65 | string temp ; 66 | 67 | help(0 , digits , temp , ans , m) ; 68 | 69 | return ans; 70 | 71 | } 72 | }; 73 | 74 | /* 75 | Time Complexity: O(3^N) 76 | Space Complexity: O(N) 77 | */ 78 | -------------------------------------------------------------------------------- /Recursion/Lecture 15/LeetCode/Letter Combinations of a Phone Number.java: -------------------------------------------------------------------------------- 1 | /* This question requries us to print all Valid Combinations of the given string digits which comprises of digits from 2 to 9. 2 | The only thing we require extra in this question is to map all the letter combinations of the phone number to its corresponding digits. 3 | The rest part of the question remains exactly same 4 | */ 5 | 6 | class Solution 7 | { 8 | void help(int i, String s, String temp, List ans, HashMap m) 9 | { 10 | // If i has reached till the end of given string, we have reached a Valid Combination 11 | // We should include it into ans and return back 12 | 13 | if (i == s.length()) 14 | { 15 | ans.add(temp); 16 | return; 17 | } 18 | 19 | // Since, we have mapped all the digits with their corresponding Letters 20 | // m.get( s.charAt(i) ) will give us the actual string corresponding to that digit using HashMap m 21 | 22 | char chr = s.charAt(i); 23 | String str = m.get(chr); 24 | 25 | // loop for traversing every element in str 26 | 27 | for (int j = 0; j < str.length(); j++) 28 | { 29 | 30 | char c = str.charAt(j); 31 | 32 | // Ask recursion to do rest of the task 33 | 34 | help(i + 1, s, temp + c, ans, m); 35 | 36 | } 37 | } 38 | 39 | public List letterCombinations(String digits) 40 | { 41 | 42 | // To solve this question, we need to map all the letters of a particular digit with it's corresponding digit. This is done with the help of HashMap m. 43 | 44 | HashMap m = new HashMap<>(); 45 | m.put('2',"abc"); 46 | m.put('3',"def"); 47 | m.put('4',"ghi"); 48 | m.put('5',"jkl"); 49 | m.put('6',"mno"); 50 | m.put('7',"pqrs"); 51 | m.put('8',"tuv"); 52 | m.put('9',"wxyz"); 53 | 54 | List ans = new ArrayList<>(); 55 | 56 | if(digits.length() == 0) 57 | return ans; 58 | 59 | String temp = ""; 60 | 61 | help(0 , digits , temp , ans , m) ; 62 | 63 | return ans; 64 | } 65 | } 66 | 67 | /* 68 | Time Complexity: O(3^N) 69 | Space Complexity: O(N) 70 | */ 71 | -------------------------------------------------------------------------------- /Recursion/Lecture 15/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 17. Letter Combinations of a Phone Number 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 16/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Partition to K equal sum subsets 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 16/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## Partition to K Equal Sum Subsets 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 17/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Maximum Length of a Concatenated String with Unique Characters -------------------------------------------------------------------------------- /Recursion/Lecture 17/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 1239. Maximum Length of a Concatenated String with Unique Characters 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 18/CodeStudio/Flood Fill Algorithm.cpp: -------------------------------------------------------------------------------- 1 | void flood(int i, int j, vector> &image, int oldColor, int newColor, int n, int m) 2 | { 3 | // [i][j] denotes the current cell 4 | // n*m is the size of the images which is also denoting the boundary of the image 5 | 6 | // base condition 7 | if (i < 0 || j < 0 || i == n || j == m || image[i][j] != oldColor) 8 | return; 9 | 10 | // change the current cell to newColor 11 | image[i][j] = newColor; 12 | 13 | // recursive call in the downward direction 14 | flood(i + 1, j, image, oldColor, newColor, n, m); 15 | 16 | // recursive call in the upward direction 17 | flood(i - 1, j, image, oldColor, newColor, n, m); 18 | 19 | // recursive call in the right direction 20 | flood(i, j + 1, image, oldColor, newColor, n, m); 21 | 22 | // recursive call in the left direction 23 | flood(i, j - 1, image, oldColor, newColor, n, m); 24 | } 25 | 26 | vector> floodFill(vector> &image, int x, int y, int newColor) 27 | { 28 | // it is denoting the oldcolor 29 | int oldColor = image[x][y]; 30 | 31 | // incase the oldColor & newColor is same then there is a possibility of forming an infinite recursion therefore to avoid such type of situation we are putting this condition over here if oldColor != newColor then it will proceed else it will return us the same image 32 | if (oldColor == newColor) 33 | return image; 34 | 35 | int n = image.size(), m = image[0].size(); 36 | 37 | // recursion call 38 | flood(x, y, image, oldColor, newColor, n, m); 39 | 40 | return image; 41 | } 42 | 43 | /* 44 | time complexity: O(M * N) 45 | space complexity: O(M * N) 46 | */ -------------------------------------------------------------------------------- /Recursion/Lecture 18/CodeStudio/Flood Fill Algorithm.java: -------------------------------------------------------------------------------- 1 | /* This Question asks us to color all the Neighbouring Cells of (x , y) with the given Color 2 | By Neighbouring we can move in 4 directions - a) Up , b) Down , c) Left , d) Right 3 | And we change colors of only those Neighbouring Cells which have the same color as the Original Cell(x , y) 4 | If old-Color of (x , y) is same as New-Color, we don't need to modify anything. Just return the previous Matrix 5 | */ 6 | 7 | public class Solution 8 | { 9 | static void flood(int i, int j, int[][] image, int oldColor, int newColor, int n, int m) 10 | { 11 | 12 | // If we move out of the Matrix Or oldColor is not equal to newColor, we just return back 13 | 14 | if (i < 0 || j < 0 || i == n || j == m || image[i][j] != oldColor) 15 | return; 16 | 17 | // We change the color of the Current-Cell to newColor 18 | 19 | image[i][j] = newColor; 20 | 21 | // Recursive call in Downward direction 22 | 23 | flood(i + 1, j, image, oldColor, newColor, n, m); 24 | 25 | // Recursive call in the Upward direction 26 | 27 | flood(i - 1, j, image, oldColor, newColor, n, m); 28 | 29 | // Recursive call in the Right direction 30 | 31 | flood(i, j + 1, image, oldColor, newColor, n, m); 32 | 33 | // Recursive call in the left direction 34 | 35 | flood(i, j - 1, image, oldColor, newColor, n, m); 36 | } 37 | 38 | public static int[][] floodFill(int[][] image, int x, int y, int newColor) 39 | { 40 | // We calculate oldColor first using the coordinates (sr , sc) 41 | 42 | int oldColor = image[x][y]; 43 | 44 | // Incase the oldColor & new Color is same, we can simply return the Original Image 45 | 46 | if (oldColor == newColor) 47 | return image; 48 | 49 | // We calculate the Dimmensions of image matrix[] 50 | 51 | int n = image.length, m = image[0].length; 52 | 53 | flood(x , y , image, oldColor, newColor , n, m); 54 | 55 | // We return the new image[][] matrix after changing all the Neighbouring Cells of (sr , sc) having OldColor to Color 56 | 57 | return image; 58 | } 59 | } 60 | 61 | /* 62 | Time Complexity: O(N * M) 63 | Space Complexity: O(N * M) 64 | */ 65 | -------------------------------------------------------------------------------- /Recursion/Lecture 18/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Flood Fill Algorithm -------------------------------------------------------------------------------- /Recursion/Lecture 18/LeetCode/Flood Fill Algorithm.java: -------------------------------------------------------------------------------- 1 | /* This Question asks us to color all the Neighbouring Cells of (sr , sc) with the given Color 2 | By Neighbouring we can move in 4 directions - a) Up , b) Down , c) Left , d) Right 3 | And we change colors of only those Neighbouring Cells which have the same color as the Original Cell(sr, sc) 4 | If old-Color of (sr , sc) is same as New-Color, we don't need to modify anything. Just return the previous Matrix 5 | */ 6 | 7 | class Solution 8 | { 9 | public void flood(int i, int j, int[][] image, int oldColor, int newColor, int n, int m) 10 | { 11 | 12 | // If we move out of the Matrix Or oldColor is not equal to newColor, we just return back 13 | 14 | if (i < 0 || j < 0 || i == n || j == m || image[i][j] != oldColor) 15 | return; 16 | 17 | // We change the color of the Current-Cell to newColor 18 | 19 | image[i][j] = newColor; 20 | 21 | // Recursive call in Downward direction 22 | 23 | flood(i + 1, j, image, oldColor, newColor, n, m); 24 | 25 | // Recursive call in the Upward direction 26 | 27 | flood(i - 1, j, image, oldColor, newColor, n, m); 28 | 29 | // Recursive call in the Right direction 30 | 31 | flood(i, j + 1, image, oldColor, newColor, n, m); 32 | 33 | // Recursive call in the left direction 34 | 35 | flood(i, j - 1, image, oldColor, newColor, n, m); 36 | } 37 | 38 | public int[][] floodFill(int[][] image, int sr, int sc, int color) 39 | { 40 | // We calculate oldColor first using the coordinates (sr , sc) 41 | 42 | int oldColor = image[sr][sc]; 43 | 44 | // Incase the oldColor & given Color is same, we can simply return the Original Image 45 | 46 | if (oldColor == color) 47 | return image; 48 | 49 | // We calculate the Dimmensions of image matrix[] 50 | 51 | int n = image.length, m = image[0].length; 52 | 53 | flood(sr , sc , image, oldColor, color , n, m); 54 | 55 | // We return the new image[][] matrix after changing all the Neighbouring Cells of (sr , sc) having OldColor to Color 56 | 57 | return image; 58 | } 59 | } 60 | 61 | /* 62 | Time Complexity: O(N * M) 63 | Space Complexity: O(N * M) 64 | */ 65 | -------------------------------------------------------------------------------- /Recursion/Lecture 18/LeetCode/Flood Fill.cpp: -------------------------------------------------------------------------------- 1 | /* This Question asks us to color all the Neighbouring Cells of (sr , sc) with the given Color 2 | By Neighbouring we can move in 4 directions - a) Up , b) Down , c) Left , d) Right 3 | And we change colors of only those Neighbouring Cells which have the same color as the Original Cell(sr, sc) 4 | If old-Color of (sr , sc) is same as New-Color, we don't need to modify anything. Just return the previous Matrix 5 | */ 6 | 7 | class Solution { 8 | private : 9 | 10 | void flood(int i, int j, vector> &image, int oldColor, int newColor, int n, int m) 11 | { 12 | 13 | // If we move out of the Matrix Or oldColor is not equal to newColor, we just return back 14 | 15 | if (i < 0 || j < 0 || i == n || j == m || image[i][j] != oldColor) 16 | return; 17 | 18 | // We change the color of the Current-Cell to newColor 19 | 20 | image[i][j] = newColor; 21 | 22 | // Recursive call in Downward direction 23 | 24 | flood(i + 1, j, image, oldColor, newColor, n, m); 25 | 26 | // Recursive call in the Upward direction 27 | 28 | flood(i - 1, j, image, oldColor, newColor, n, m); 29 | 30 | // Recursive call in the Right direction 31 | 32 | flood(i, j + 1, image, oldColor, newColor, n, m); 33 | 34 | // Recursive call in the left direction 35 | 36 | flood(i, j - 1, image, oldColor, newColor, n, m); 37 | } 38 | 39 | public: 40 | vector> floodFill(vector>& image, int sr, int sc, int color) { 41 | 42 | // We calculate oldColor first using the coordinates (sr , sc) 43 | 44 | int oldColor = image[sr][sc]; 45 | 46 | // Incase the oldColor & given Color is same, we can simply return the Original Image 47 | 48 | if (oldColor == color) 49 | return image; 50 | 51 | // We calculate the Dimmensions of image matrix[] 52 | 53 | int n = image.size(), m = image[0].size(); 54 | 55 | flood(sr , sc , image, oldColor, color , n, m); 56 | 57 | // We return the new image[][] matrix after changing all the Neighbouring Cells of (sr , sc) having OldColor to Color 58 | 59 | return image; 60 | } 61 | }; 62 | 63 | /* 64 | Time Complexity: O(N * M) 65 | Space Complexity: O(N * M) 66 | */ 67 | -------------------------------------------------------------------------------- /Recursion/Lecture 18/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 733. Flood Fill 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 19/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Word Search - l 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 19/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 79. Word Search 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 20/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## Rat In A Maze 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 21/CodeStudio/README.md: -------------------------------------------------------------------------------- 1 | ## N Queens 2 | -------------------------------------------------------------------------------- /Recursion/Lecture 21/LeetCode/README.md: -------------------------------------------------------------------------------- 1 | ## 51. N-Queens 2 | --------------------------------------------------------------------------------