diff --git a/Topic2_LinkedList/dkhien/01ReverseLinkedList.java b/Topic2_LinkedList/dkhien/01ReverseLinkedList.java new file mode 100644 index 0000000..04b0f0a --- /dev/null +++ b/Topic2_LinkedList/dkhien/01ReverseLinkedList.java @@ -0,0 +1,30 @@ +// Time Complexity: O(n) +// Space Complexity: O(1) + +class Solution { + public ListNode reverseList(ListNode head) { + if (head == null) return null; + if (head.next == null) return head; + + ListNode newHead = new ListNode(); + newHead.next = null; + + while (head.next != null) { + // Copy value to current node of the new list + newHead.val = head.val; + + // Create the next node + ListNode next = new ListNode(); + next.val = head.next.val; + + // Connect next node to current node (next -> current) to reverse + next.next = newHead; + + // Iterate + newHead = next; + head = head.next; + } + + return newHead; + } +} \ No newline at end of file diff --git a/Topic2_LinkedList/dkhien/02MergeTwoSortedLists.java b/Topic2_LinkedList/dkhien/02MergeTwoSortedLists.java new file mode 100644 index 0000000..2f42424 --- /dev/null +++ b/Topic2_LinkedList/dkhien/02MergeTwoSortedLists.java @@ -0,0 +1,33 @@ +// Time Complexity: O(n) +// Space Complexity: O(1) + +class Solution { + public ListNode mergeTwoLists(ListNode list1, ListNode list2) { + ListNode result = new ListNode(); + ListNode current = result; + + while (list1 != null && list2 != null) { + // Choose the smaller value to add to the result list + if (list1.val <= list2.val) { + current.next = list1; + list1 = list1.next; + } else { + current.next = list2; + list2 = list2.next; + } + + // Iterate + current = current.next; + } + + // Add the remaining nodes to the result list + if (list1 != null) { + current.next = list1; + } else if (list2 != null) { + current.next = list2; + } + + return result.next; + + } +} \ No newline at end of file diff --git a/Topic2_LinkedList/dkhien/03ReorderList.java b/Topic2_LinkedList/dkhien/03ReorderList.java new file mode 100644 index 0000000..af676bb --- /dev/null +++ b/Topic2_LinkedList/dkhien/03ReorderList.java @@ -0,0 +1,37 @@ +// Time Complexity: O(n) +// Space Complexity: O(n) + +class Solution { + public void reorderList(ListNode head) { + List nodeList = new ArrayList<>(); + ListNode temp = head; + + while (temp != null) { + nodeList.add(temp); + temp = temp.next; + } + + // Traverse half of the list + for (int i = 0; i < nodeList.size() / 2; i++) { + ListNode node = nodeList.get(i); + + // The next node to link to should have index size - 1 - i + ListNode nextNode = nodeList.get(nodeList.size() - 1 - i); + + if (i == nodeList.size() / 2 - 1 && nodeList.size() % 2 == 0) { + // If the list has even number of nodes, the next node of the middle node should be null + nextNode.next = null; + } else if (i == nodeList.size() / 2 - 1 && nodeList.size() % 2 != 0) { + // If the list has odd number of nodes, the next node of the middle node should be the last node + nextNode.next = node.next; + nextNode.next.next = null; + } else { + // Normal case + nextNode.next = node.next; + } + + // Link the current node to the next node + node.next = nextNode; + } + } +} \ No newline at end of file diff --git a/Topic2_LinkedList/dkhien/04RemoveNthNodeFromEndOfList.java b/Topic2_LinkedList/dkhien/04RemoveNthNodeFromEndOfList.java new file mode 100644 index 0000000..9ee4ac8 --- /dev/null +++ b/Topic2_LinkedList/dkhien/04RemoveNthNodeFromEndOfList.java @@ -0,0 +1,29 @@ +// Time Complexity: O(n) +// Space Complexity: O(1) + +class Solution { + public ListNode removeNthFromEnd(ListNode head, int n) { + if (head == null || head.next == null) return null; + ListNode ptr1 = head; + ListNode ptr2 = head; + + // ptr2 starts first, n steps ahead of ptr1 + for (int i = 0; i < n; i++) { + if (ptr2.next == null) { + return head.next; + } + ptr2 = ptr2.next; + } + + // Move ptr1 and ptr2 until ptr2 reaches the end + while (ptr2.next != null) { + ptr1 = ptr1.next; + ptr2 = ptr2.next; + } + + // ptr1 should now be at the (n-1)th node from the end -> remove the next node + ptr1.next = ptr1.next.next; + + return head; + } +} \ No newline at end of file diff --git a/Topic2_LinkedList/dkhien/05CopyListWithRandomPointer.java b/Topic2_LinkedList/dkhien/05CopyListWithRandomPointer.java new file mode 100644 index 0000000..791e2a3 --- /dev/null +++ b/Topic2_LinkedList/dkhien/05CopyListWithRandomPointer.java @@ -0,0 +1,46 @@ +// Time Complexity: O(n) +// Space Complexity: O(n) + +class Solution { + public Node copyRandomList(Node head) { + if (head == null) return null; + + // Map original node to its clone + Map originalToClone = new HashMap<>(); + Node res = new Node(0); + Node dummy = res; + + // Idea: Clone the list linearly and avoid duplicate cloning by using a map + while (head != null) { + // Clone next node, if in map use the existing clone + Node nextClone; + if (originalToClone.containsKey(head)) { + nextClone = originalToClone.get(head); + } else { + nextClone = new Node(head.val); + originalToClone.put(head, nextClone); + } + + dummy.next = nextClone; + + // Clone random node, if in map use the existing clone + Node randomClone = null; + if (head.random != null) { + if (originalToClone.containsKey(head.random)) { + randomClone = originalToClone.get(head.random); + } else { + randomClone = new Node(head.random.val); + originalToClone.put(head.random, randomClone); + } + } + + dummy.next.random = randomClone; + + // Iterate + dummy = nextClone; + head = head.next; + } + + return res.next; + } +} \ No newline at end of file diff --git a/Topic2_LinkedList/dkhien/06AddTwoNumbers.java b/Topic2_LinkedList/dkhien/06AddTwoNumbers.java new file mode 100644 index 0000000..1e56e0d --- /dev/null +++ b/Topic2_LinkedList/dkhien/06AddTwoNumbers.java @@ -0,0 +1,48 @@ +// Time Complexity: O(n) +// Space Complexity: O(1) + +class Solution { + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + ListNode dummy = new ListNode(); + ListNode current = dummy; + int carry = 0; + + // Idea: Add each digit like in elementary school + while (true) { + + // Calculate the sum of the current digits + // If one of the lists is null, the value of that list is 0 + int sum; + if (l1 == null && l2 != null) { + sum = l2.val + carry; + l2 = l2.next; + } else if (l1 != null && l2 == null) { + sum = l1.val + carry; + l1 = l1.next; + } else if (l1 != null && l2 != null) { + sum = l1.val + l2.val + carry; + l1 = l1.next; + l2 = l2.next; + } else { + break; + } + + // Calculate the carry and the value of the current digit + carry = sum / 10; + sum %= 10; + + // Create a new node and link it to the result list + ListNode res = new ListNode(sum); + current.next = res; + current = res; + } + + // Add the last carry if any + if (carry > 0) { + ListNode carryNode = new ListNode(carry); + current.next = carryNode; + } + + return dummy.next; + } +} \ No newline at end of file diff --git a/Topic2_LinkedList/dkhien/07LinkedListCycle.java b/Topic2_LinkedList/dkhien/07LinkedListCycle.java new file mode 100644 index 0000000..6cd0e3f --- /dev/null +++ b/Topic2_LinkedList/dkhien/07LinkedListCycle.java @@ -0,0 +1,22 @@ +// Time Complexity: O(n) +// Space Complexity: O(1) + +public class Solution { + public boolean hasCycle(ListNode head) { + if (head == null) + return false; + ListNode slow = head; + ListNode fast = head; + + // Idea: The fast pointer will surely meet the slow pointer if there is a cycle + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/Topic3_StackQueue/dkhien/01ValidParetheses.java b/Topic3_StackQueue/dkhien/01ValidParetheses.java new file mode 100644 index 0000000..8be41ed --- /dev/null +++ b/Topic3_StackQueue/dkhien/01ValidParetheses.java @@ -0,0 +1,31 @@ +// Time complexity: O(n) +// Space complexity: O(n) + +import java.util.Stack; + +class Solution { + public boolean isValid(String s) { + Stack stack = new Stack<>(); + + for (char c : s.toCharArray()) { + // If c is an opening bracket, push it to the stack + if (c == '(' || c == '[' || c == '{') { + stack.push(c); + } else { + if (stack.isEmpty()) { + return false; + } + char top = stack.pop(); + + // If c is a closing bracket, check if it matches the top of the stack + // If not, return false (invalid) + if ((c == ')' && top != '(') || (c == ']' && top != '[') || (c == '}' && top != '{')) { + return false; + } + } + } + + // If the stack is empty, the string is valid because all brackets are matched + return stack.isEmpty(); + } +} \ No newline at end of file diff --git a/Topic3_StackQueue/dkhien/02MinStack.java b/Topic3_StackQueue/dkhien/02MinStack.java new file mode 100644 index 0000000..ad1e93f --- /dev/null +++ b/Topic3_StackQueue/dkhien/02MinStack.java @@ -0,0 +1,30 @@ +// Time complexity: O(1) for all operations +// Space complexity: O(n) for the stack + +class MinStack { + // Use a pair to store the value and the minimum value at that point + Stack> stack = new Stack<>(); + + public void push(int val) { + int min = val; + if (!stack.isEmpty()) { + // Get minimum between the current value and the minimum value of the previous element + min = Math.min(val, stack.peek().getValue()); + } + + // Push the value and the minimum value to the stack + stack.push(new Pair<>(val, min)); + } + + public void pop() { + stack.pop(); + } + + public int top() { + return stack.peek().getKey(); + } + + public int getMin() { + return stack.peek().getValue(); + } +} \ No newline at end of file diff --git a/Topic3_StackQueue/dkhien/03EvaluateReversePolishNotation.java b/Topic3_StackQueue/dkhien/03EvaluateReversePolishNotation.java new file mode 100644 index 0000000..63c665b --- /dev/null +++ b/Topic3_StackQueue/dkhien/03EvaluateReversePolishNotation.java @@ -0,0 +1,36 @@ +// Time complexity: O(n) +// Space complexity: O(n) + +class Solution { + public int evalRPN(String[] tokens) { + Stack stack = new Stack<>(); + + for (String token : tokens) { + // If token is an operator, pop 2 operands from the stack and perform the operation + if (token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")) { + Integer op2 = stack.pop(); + Integer op1 = stack.pop(); + switch (token) { + case "+": + stack.push(op1 + op2); + break; + case "-": + stack.push(op1 - op2); + break; + case "*": + stack.push(op1 * op2); + break; + case "/": + stack.push(op1 / op2); + break; + } + } else { + // If token is an operand, push it to the stack + stack.push(Integer.parseInt(token)); + } + } + + // The result is the only element left in the stack + return stack.pop(); + } +} \ No newline at end of file diff --git a/Topic3_StackQueue/dkhien/04DailyTemperatures.java b/Topic3_StackQueue/dkhien/04DailyTemperatures.java new file mode 100644 index 0000000..7d4a736 --- /dev/null +++ b/Topic3_StackQueue/dkhien/04DailyTemperatures.java @@ -0,0 +1,24 @@ +// Time complexity: O(n) +// Space complexity: O(n) + +class Solution { + public int[] dailyTemperatures(int[] temperatures) { + int[] result = new int[temperatures.length]; + + Stack stack = new Stack<>(); + + for (int i = 0; i < temperatures.length; i++) { + // If the current temperature is higher than the temperature at the top of the stack, then we have found the next warmer temperature. + while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) { + // Pop the index of the temperature that is lower than the current temperature + int top = stack.pop(); + // Calculate the distance between the current temperature and the temperature at the top of the stack + result[top] = i - top; + } + stack.push(i); + } + + return result; + + } +} \ No newline at end of file diff --git a/Topic3_StackQueue/dkhien/06MovingAverageFromDataStream.java b/Topic3_StackQueue/dkhien/06MovingAverageFromDataStream.java new file mode 100644 index 0000000..ee7b0d6 --- /dev/null +++ b/Topic3_StackQueue/dkhien/06MovingAverageFromDataStream.java @@ -0,0 +1,31 @@ +// Time complexity: O(n) +// Space complexity: O(n) + +public class MovingAverage { + int size; + Queue list = new LinkedList<>(); + + /* + * @param size: An integer + */public MovingAverage(int size) { + // do intialization if necessary + this.size = size; + } + + /* + * @param val: An integer + * @return: + */ + public double next(int val) { + // write your code here + list.add(val); + while (list.size() > size) { + list.remove(); + } + double res = 0; + for (int num : list) { + res += num; + } + return res / list.size(); + } +} \ No newline at end of file