diff --git a/Easy/Adjacent Increasing Subarrays Detection I.java b/Easy/Adjacent Increasing Subarrays Detection I.java new file mode 100644 index 00000000..5be82de7 --- /dev/null +++ b/Easy/Adjacent Increasing Subarrays Detection I.java @@ -0,0 +1,20 @@ +class Solution { + public boolean hasIncreasingSubarrays(List nums, int k) { + int n = nums.size(); + for (int i = 0; i <= n - 2 * k; i++) { + if (isStrictlyIncreasing(nums, i, k) && isStrictlyIncreasing(nums, i + k, k)) { + return true; + } + } + return false; + } + + private boolean isStrictlyIncreasing(List nums, int idx, int k) { + for (int start = idx; start < idx + k - 1; start++) { + if (nums.get(start) >= nums.get(start + 1)) { + return false; + } + } + return true; + } +} diff --git a/Easy/Apply Operations to an Array.java b/Easy/Apply Operations to an Array.java index b0a663a2..3b2bca86 100644 --- a/Easy/Apply Operations to an Array.java +++ b/Easy/Apply Operations to an Array.java @@ -1,21 +1,20 @@ class Solution { public int[] applyOperations(int[] nums) { - for (int i = 0; i < nums.length - 1; i++) { + int n = nums.length; + for (int i = 0; i < n - 1; i++) { if (nums[i] == nums[i + 1]) { nums[i] *= 2; nums[i + 1] = 0; } } - int startIdx = 0; - int endIdx = 0; - while (endIdx < nums.length) { - if (nums[endIdx] != 0) { - nums[startIdx++] = nums[endIdx]; + int start = 0; + for (int i = 0; i < n; i++) { + if (nums[i] != 0) { + nums[start++] = nums[i]; } - endIdx++; } - while (startIdx < nums.length) { - nums[startIdx++] = 0; + while (start < n) { + nums[start++] = 0; } return nums; } diff --git a/Easy/Button with Longest Push Time.java b/Easy/Button with Longest Push Time.java new file mode 100644 index 00000000..650bb1e4 --- /dev/null +++ b/Easy/Button with Longest Push Time.java @@ -0,0 +1,18 @@ +class Solution { + public int buttonWithLongestTime(int[][] events) { + int maxTime = 0; + int resultIdx = 0; + int prevTime = 0; + for (int i = 0; i < events.length; i++) { + int timePressed = events[i][1] - prevTime; + if (timePressed > maxTime) { + maxTime = timePressed; + resultIdx = events[i][0]; + } else if (timePressed == maxTime && resultIdx > events[i][0]) { + resultIdx = events[i][0]; + } + prevTime = events[i][1]; + } + return resultIdx; + } +} diff --git a/Easy/Check if One String Swap Can Make Strings Equal.java b/Easy/Check if One String Swap Can Make Strings Equal.java index 3f26dac9..fca6fc9d 100644 --- a/Easy/Check if One String Swap Can Make Strings Equal.java +++ b/Easy/Check if One String Swap Can Make Strings Equal.java @@ -1,16 +1,21 @@ class Solution { - public boolean areAlmostEqual(String s1, String s2) { - int mismatchIdx = -1; - for (int i = 0; i < s1.length(); i++) { - if (s1.charAt(i) != s2.charAt(i)) { - if (mismatchIdx != -1) { - return s1.charAt(mismatchIdx) == s2.charAt(i) && - s1.charAt(i) == s2.charAt(mismatchIdx) && - s1.substring(i + 1).equals(s2.substring(i + 1)); + public boolean areAlmostEqual(String s1, String s2) { + int swapIdx = -1; + boolean swapped = false; + for (int i = 0; i < s1.length(); i++) { + if (s1.charAt(i) != s2.charAt(i)) { + if (swapped) { + return false; + } + if (swapIdx != -1) { + if (!(s1.charAt(swapIdx) == s2.charAt(i) && s1.charAt(i) == s2.charAt(swapIdx))) { + return false; + } + swapped = true; + } + swapIdx = i; + } } - mismatchIdx = i; - } + return swapIdx == -1 || (swapIdx != -1 && swapped); } - return mismatchIdx == -1; - } } diff --git a/Easy/Count Partitions with Even Sum Difference.java b/Easy/Count Partitions with Even Sum Difference.java new file mode 100644 index 00000000..0390a5a1 --- /dev/null +++ b/Easy/Count Partitions with Even Sum Difference.java @@ -0,0 +1,17 @@ +class Solution { + public int countPartitions(int[] nums) { + int n = nums.length; + int[] prefixSum = new int[n]; + for (int i = 0; i < n; i++) { + prefixSum[i] = nums[i]; + prefixSum[i] += i == 0 ? 0 : prefixSum[i - 1]; + } + int partitions = 0; + for (int i = 0; i < n - 1; i++) { + int leftSum = prefixSum[i]; + int rightSum = prefixSum[n - 1] - prefixSum[i]; + partitions += (rightSum - leftSum) % 2 == 0 ? 1 : 0; + } + return partitions; + } +} diff --git a/Easy/Count Subarrays of Length Three With a Condition.java b/Easy/Count Subarrays of Length Three With a Condition.java new file mode 100644 index 00000000..4694fb65 --- /dev/null +++ b/Easy/Count Subarrays of Length Three With a Condition.java @@ -0,0 +1,11 @@ +class Solution { + public int countSubarrays(int[] nums) { + int count = 0; + for (int i = 0; i < nums.length - 2; i++) { + if (2 * (nums[i] + nums[i + 2]) == nums[i + 1]) { + count++; + } + } + return count; + } +} diff --git a/Easy/Count Symmetric Integers.java b/Easy/Count Symmetric Integers.java index f32301e1..8ae9c320 100644 --- a/Easy/Count Symmetric Integers.java +++ b/Easy/Count Symmetric Integers.java @@ -1,17 +1,27 @@ class Solution { public int countSymmetricIntegers(int low, int high) { - int result = 0; + int count = 0; for (int i = low; i <= high; i++) { - String s = String.valueOf(i); - int diff = 0; - int n = s.length(); - for (int j = 0; j < n / 2; j++) { - diff += s.charAt(j) - s.charAt(n - j - 1); - } - if (n % 2 == 0 && diff == 0) { - result++; + if (isSymmetric(i)) { + count++; } } - return result; + return count; + } + + private static boolean isSymmetric(int num) { + String s = String.valueOf(num); + int n = s.length(); + if (n % 2 != 0) { + return false; + } + int sum = 0; + for (int i = 0; i < n / 2; i++) { + sum += Character.getNumericValue(s.charAt(i)); + } + for (int i = n / 2; i < n; i++) { + sum -= Character.getNumericValue(s.charAt(i)); + } + return sum == 0; } } diff --git a/Easy/Find Closest Person.java b/Easy/Find Closest Person.java new file mode 100644 index 00000000..0d178230 --- /dev/null +++ b/Easy/Find Closest Person.java @@ -0,0 +1,7 @@ +class Solution { + public int findClosest(int x, int y, int z) { + int diffOne = Math.abs(x - z); + int diffTwo = Math.abs(y - z); + return diffOne == diffTwo ? 0 : (diffOne < diffTwo ? 1 : 2); + } +} diff --git a/Easy/Find Indices of Stable Mountains.java b/Easy/Find Indices of Stable Mountains.java new file mode 100644 index 00000000..3e0fbd79 --- /dev/null +++ b/Easy/Find Indices of Stable Mountains.java @@ -0,0 +1,11 @@ +class Solution { + public List stableMountains(int[] height, int threshold) { + List result = new ArrayList<>(); + for (int i = 1; i < height.length; i++) { + if (height[i - 1] > threshold) { + result.add(i); + } + } + return result; + } +} diff --git a/Easy/Find Minimum Log Transportation Cost.java b/Easy/Find Minimum Log Transportation Cost.java new file mode 100644 index 00000000..3820474e --- /dev/null +++ b/Easy/Find Minimum Log Transportation Cost.java @@ -0,0 +1,12 @@ +class Solution { + public long minCuttingCost(int n, int m, int k) { + long cost = 0; + if (n > k) { + cost += ((long) (n - k)) * (k); + } + if (m > k) { + cost += ((long) (m - k)) * (k); + } + return cost; + } +} diff --git a/Easy/Find the Original Typed String I.java b/Easy/Find the Original Typed String I.java new file mode 100644 index 00000000..dd6a5177 --- /dev/null +++ b/Easy/Find the Original Typed String I.java @@ -0,0 +1,17 @@ +class Solution { + public int possibleStringCount(String word) { + int idx = 0; + int result = 1; + while (idx < word.length()) { + int currIdx = idx; + char c = word.charAt(currIdx); + while (currIdx < word.length() && word.charAt(currIdx) == c) { + currIdx++; + } + int segement = currIdx - idx; + result += segement - 1; + idx = currIdx; + } + return result; + } +} diff --git a/Easy/Fruits Into Baskets II.java b/Easy/Fruits Into Baskets II.java new file mode 100644 index 00000000..e0afa848 --- /dev/null +++ b/Easy/Fruits Into Baskets II.java @@ -0,0 +1,20 @@ +class Solution { + public int numOfUnplacedFruits(int[] fruits, int[] baskets) { + int count = 0; + for (int fruit : fruits) { + int idx = -1; + for (int i = 0; i < baskets.length; i++) { + if (baskets[i] >= fruit) { + idx = i; + break; + } + } + if (idx == -1) { + count++; + } else { + baskets[idx] = -1; + } + } + return count; + } +} diff --git a/Easy/Generate Tag for Video Caption.java b/Easy/Generate Tag for Video Caption.java new file mode 100644 index 00000000..420bce85 --- /dev/null +++ b/Easy/Generate Tag for Video Caption.java @@ -0,0 +1,26 @@ +class Solution { + public String generateTag(String caption) { + StringBuilder sb = new StringBuilder(); + sb.append('#'); + int idx = 0; + int n = caption.length(); + while (idx < n && caption.charAt(idx) == ' ') { + idx++; + } + boolean upperCase = false; + while (idx < n) { + if (Character.isLetter(caption.charAt(idx))) { + if (upperCase) { + sb.append(Character.toUpperCase(caption.charAt(idx))); + upperCase = false; + } else { + sb.append(Character.toLowerCase(caption.charAt(idx))); + } + } else if (caption.charAt(idx) == ' ') { + upperCase = true; + } + idx++; + } + return sb.toString().substring(0, Math.min(sb.length(), 100)); + } +} diff --git a/Easy/Longest Strictly Increasing or Strictly Decreasing Subarray.java b/Easy/Longest Strictly Increasing or Strictly Decreasing Subarray.java new file mode 100644 index 00000000..c1ed1c36 --- /dev/null +++ b/Easy/Longest Strictly Increasing or Strictly Decreasing Subarray.java @@ -0,0 +1,22 @@ +class Solution { + public int longestMonotonicSubarray(int[] nums) { + int max = 1; + int idx = 0; + int n = nums.length; + while (idx < n) { + if (idx == n - 1 || nums[idx + 1] == nums[idx]) { + idx++; + continue; + } + boolean increase = nums[idx + 1] > nums[idx]; + int start = idx; + while (idx + 1 < n && ( + (increase && nums[idx + 1] > nums[idx]) || + (!increase && nums[idx + 1] < nums[idx]))) { + idx++; + } + max = Math.max(max, idx - start + 1); + } + return max; + } +} diff --git a/Easy/Maximum Ascending Subarray Sum.java b/Easy/Maximum Ascending Subarray Sum.java index fb436414..fd64c04c 100644 --- a/Easy/Maximum Ascending Subarray Sum.java +++ b/Easy/Maximum Ascending Subarray Sum.java @@ -1,14 +1,15 @@ class Solution { - public int maxAscendingSum(int[] nums) { - int maximumSum = 0; - int idx = 0; - while (idx < nums.length) { - int currSum = nums[idx++]; - while (idx < nums.length && nums[idx] > nums[idx - 1]) { - currSum += nums[idx++]; - } - maximumSum = Math.max(maximumSum, currSum); + public int maxAscendingSum(int[] nums) { + int maxSum = 0; + int idx = 0; + int n = nums.length; + while (idx < n) { + int currSum = nums[idx++]; + while (idx < n && nums[idx] > nums[idx - 1]) { + currSum += nums[idx++]; + } + maxSum = Math.max(maxSum, currSum); + } + return maxSum; } - return maximumSum; - } } diff --git a/Easy/Maximum Containers on a Ship.java b/Easy/Maximum Containers on a Ship.java new file mode 100644 index 00000000..e113027d --- /dev/null +++ b/Easy/Maximum Containers on a Ship.java @@ -0,0 +1,8 @@ +class Solution { + public int maxContainers(int n, int w, int maxWeight) { + if (n * n * w <= maxWeight) { + return n * n; + } + return maxWeight / w; + } +} diff --git a/Easy/Maximum Difference Between Even and Odd Frequency I.java b/Easy/Maximum Difference Between Even and Odd Frequency I.java new file mode 100644 index 00000000..ec68c06f --- /dev/null +++ b/Easy/Maximum Difference Between Even and Odd Frequency I.java @@ -0,0 +1,19 @@ +class Solution { + public int maxDifference(String s) { + Map map = new HashMap<>(); + for (char c : s.toCharArray()) { + map.put(c, map.getOrDefault(c, 0) + 1); + } + int maxOdd = Integer.MIN_VALUE; + int minEven = Integer.MAX_VALUE; + for (Character key : map.keySet()) { + Integer value = map.get(key); + if (value % 2 == 0) { + minEven = Math.min(minEven, value); + } else { + maxOdd = Math.max(maxOdd, value); + } + } + return maxOdd - minEven; + } +} diff --git a/Easy/Maximum Product of Two Digits.java b/Easy/Maximum Product of Two Digits.java new file mode 100644 index 00000000..c61f3c3a --- /dev/null +++ b/Easy/Maximum Product of Two Digits.java @@ -0,0 +1,17 @@ +class Solution { + public int maxProduct(int n) { + int maximum = Integer.MIN_VALUE; + int secondMaximum = Integer.MIN_VALUE; + while (n > 0) { + int num = n % 10; + n /= 10; + if (num > maximum) { + secondMaximum = maximum; + maximum = num; + } else if (num > secondMaximum) { + secondMaximum = num; + } + } + return maximum * secondMaximum; + } +} diff --git a/Easy/Maximum Unique Subarray Sum After Deletion.java b/Easy/Maximum Unique Subarray Sum After Deletion.java new file mode 100644 index 00000000..e0a6a2ae --- /dev/null +++ b/Easy/Maximum Unique Subarray Sum After Deletion.java @@ -0,0 +1,17 @@ +class Solution { + public int maxSum(int[] nums) { + int max = nums[0]; + int sum = 0; + Set set = new HashSet<>(); + for (int num : nums) { + max = Math.max(num, max); + if (num > 0 && set.add(num)) { + sum += num; + } + } + if (max < 0) { + return max; + } + return sum; + } +} diff --git a/Easy/Minimum Cost to Reach Every Position.java b/Easy/Minimum Cost to Reach Every Position.java new file mode 100644 index 00000000..1b142d2c --- /dev/null +++ b/Easy/Minimum Cost to Reach Every Position.java @@ -0,0 +1,13 @@ +class Solution { + public int[] minCosts(int[] cost) { + int n = cost.length; + int[] result = new int[n]; + int minCost = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + int curr = cost[i]; + minCost = Math.min(minCost, curr); + result[i] = minCost; + } + return result; + } +} diff --git a/Easy/Minimum Number of Operations to Make Elements in Array Distinct.java b/Easy/Minimum Number of Operations to Make Elements in Array Distinct.java new file mode 100644 index 00000000..a61239e7 --- /dev/null +++ b/Easy/Minimum Number of Operations to Make Elements in Array Distinct.java @@ -0,0 +1,18 @@ +class Solution { + public int minimumOperations(int[] nums) { + Set set = new HashSet<>(); + int index = -1; + for (int i = nums.length - 1; i >= 0; i--) { + if (set.contains(nums[i])) { + index = i; + break; + } + set.add(nums[i]); + } + if (index == -1) { + return 0; + } + index++; + return index % 3 == 0 ? index / 3 : (index / 3) + 1; + } +} diff --git a/Easy/Minimum Operations to Make Array Sum Divisible by K.java b/Easy/Minimum Operations to Make Array Sum Divisible by K.java new file mode 100644 index 00000000..c941b50a --- /dev/null +++ b/Easy/Minimum Operations to Make Array Sum Divisible by K.java @@ -0,0 +1,9 @@ +class Solution { + public int minOperations(int[] nums, int k) { + int sum = 0; + for (int num : nums) { + sum += num; + } + return sum % k; + } +} diff --git a/Easy/Rank Transform of an Array.java b/Easy/Rank Transform of an Array.java index 401c317b..3f9192fd 100644 --- a/Easy/Rank Transform of an Array.java +++ b/Easy/Rank Transform of an Array.java @@ -1,20 +1,19 @@ class Solution { - public int[] arrayRankTransform(int[] arr) { - PriorityQueue pq = new PriorityQueue<>(); - for (int num : arr) { - pq.add(num); + public int[] arrayRankTransform(int[] arr) { + int[] copyArr = Arrays.copyOf(arr, arr.length); + Arrays.sort(arr); + int rank = 1; + Map numToRank = new HashMap<>(); + for (int num : arr) { + if (numToRank.containsKey(num)) { + continue; + } + numToRank.put(num, rank++); + } + int[] result = new int[arr.length]; + for (int i = 0; i < arr.length; i++) { + result[i] = numToRank.get(copyArr[i]); + } + return result; } - int rank = 1; - Map map = new HashMap<>(); - while (!pq.isEmpty()) { - int removed = pq.poll(); - if (!map.containsKey(removed)) { - map.put(removed, rank++); - } - } - for (int i = 0; i < arr.length; i++) { - arr[i] = map.get(arr[i]); - } - return arr; - } } diff --git a/Easy/Reverse Degree of a String.java b/Easy/Reverse Degree of a String.java new file mode 100644 index 00000000..db8f4e91 --- /dev/null +++ b/Easy/Reverse Degree of a String.java @@ -0,0 +1,9 @@ +class Solution { + public int reverseDegree(String s) { + int result = 0; + for (int i = 0; i < s.length(); i++) { + result += (i + 1) * (26 - (s.charAt(i) - 'a')); + } + return result; + } +} diff --git a/Easy/Sum of Variable Length Subarrays.java b/Easy/Sum of Variable Length Subarrays.java new file mode 100644 index 00000000..5dc7d585 --- /dev/null +++ b/Easy/Sum of Variable Length Subarrays.java @@ -0,0 +1,19 @@ +class Solution { + public int subarraySum(int[] nums) { + int n = nums.length; + int[] prefixSum = new int[n]; + int sum = 0; + int result = 0; + for (int i = 0; i < n; i++) { + sum += nums[i]; + prefixSum[i] = sum; + int start = Math.max(0, i - nums[i]); + int subarraySum = prefixSum[i]; + if (start > 0) { + subarraySum -= prefixSum[start - 1]; + } + result += subarraySum; + } + return result; + } +} diff --git a/Hard/Height of Binary Tree After Subtree Removal Queries.java b/Hard/Height of Binary Tree After Subtree Removal Queries.java new file mode 100644 index 00000000..ebd9acbe --- /dev/null +++ b/Hard/Height of Binary Tree After Subtree Removal Queries.java @@ -0,0 +1,48 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + public int[] treeQueries(TreeNode root, int[] queries) { + Map result = new HashMap<>(); + Map heightCache = new HashMap<>(); + dfs(root, 0, 0, result, heightCache); + int[] answer = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + answer[i] = result.get(queries[i]); + } + return answer; + } + + private void dfs(TreeNode node, int depth, int maxDepth, Map result, Map heightCache) { + if (node == null) { + return; + } + result.put(node.val, maxDepth); + dfs(node.left, depth + 1, Math.max(maxDepth, depth + 1 + height(node.right, heightCache)), result, heightCache); + dfs(node.right, depth + 1, Math.max(maxDepth, depth + 1 + height(node.left, heightCache)), result, heightCache); + } + + private int height(TreeNode node, Map heightCache) { + if (node == null) { + return -1; + } + if (heightCache.containsKey(node)) { + return heightCache.get(node); + } + int currHeight = 1 + Math.max(height(node.left, heightCache), height(node.right, heightCache)); + heightCache.put(node, currHeight); + return currHeight; + } +} diff --git a/Hard/K-th Smallest in Lexicographical Order.java b/Hard/K-th Smallest in Lexicographical Order.java new file mode 100644 index 00000000..9063cd56 --- /dev/null +++ b/Hard/K-th Smallest in Lexicographical Order.java @@ -0,0 +1,27 @@ +class Solution { + public int findKthNumber(int n, int k) { + int curr = 1; + k--; + while (k > 0) { + int count = countNumsWithPrefix(n, curr, curr + 1); + if (count <= k) { + curr++; + k -= count; + } else { + curr *= 10; + k--; + } + } + return curr; + } + + private int countNumsWithPrefix(int n, long start, long end) { + int count = 0; + while (start <= n) { + count += Math.min(n + 1, end) - start; + start *= 10; + end *= 10; + } + return count; + } +} diff --git a/Hard/Minimum Number of Removals to Make Mountain Array.java b/Hard/Minimum Number of Removals to Make Mountain Array.java new file mode 100644 index 00000000..b74f6feb --- /dev/null +++ b/Hard/Minimum Number of Removals to Make Mountain Array.java @@ -0,0 +1,30 @@ +class Solution { + public int minimumMountainRemovals(int[] nums) { + int n = nums.length; + int[] leftIncreasingLength = new int[n]; + int[] rightDecreasingLength = new int[n]; + Arrays.fill(leftIncreasingLength, 1); + Arrays.fill(rightDecreasingLength, 1); + for (int i = 0; i < n; i++) { + for (int j = i - 1; j >= 0; j--) { + if (nums[i] > nums[j]) { + leftIncreasingLength[i] = Math.max(leftIncreasingLength[i], leftIncreasingLength[j] + 1); + } + } + } + for (int i = n - 1; i >= 0; i--) { + for (int j = i + 1; j < n; j++) { + if (nums[i] > nums[j]) { + rightDecreasingLength[i] = Math.max(rightDecreasingLength[i], rightDecreasingLength[j] + 1); + } + } + } + int minRemovals = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (leftIncreasingLength[i] > 1 && rightDecreasingLength[i] > 1) { + minRemovals = Math.min(minRemovals, n - leftIncreasingLength[i] - rightDecreasingLength[i] + 1); + } + } + return minRemovals; + } +} diff --git a/Hard/Parsing A Boolean Expression.java b/Hard/Parsing A Boolean Expression.java index 2c419aa8..97a56130 100644 --- a/Hard/Parsing A Boolean Expression.java +++ b/Hard/Parsing A Boolean Expression.java @@ -1,72 +1,43 @@ class Solution { public boolean parseBoolExpr(String expression) { - char[] chars = expression.toCharArray(); - Stack operations = new Stack<>(); - Stack boolValues = new Stack<>(); - - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (c == '!' || c == '&' || c == '|') { - operations.push(c); - } - else if (c == '(') { - boolValues.push('#'); - } - else if (c == 't' || c == 'f') { - boolValues.push(chars[i]); - } - else if (c == ',') { - continue; - } - else { - List list = new ArrayList<>(); - while (!boolValues.isEmpty()) { - char temp = boolValues.pop(); - if (temp == '#') { - break; - } - - list.add(temp); + Stack stack = new Stack<>(); + for (char c : expression.toCharArray()) { + if (c == ')') { + List values = new ArrayList<>(); + while (stack.peek() != '(') { + values.add(stack.pop()); } - - boolValues.push(performOperation(list, operations.pop())); + stack.pop(); + char operation = stack.pop(); + char result = evaluate(operation, values); + stack.push(result); + } else if (c != ',') { + stack.push(c); } } - - return boolValues.peek() == 't' ? true : false; + return stack.peek() == 't'; } - private Character performOperation(List list, Character operation) { - if (operation == '|') { - return performOr(list); - } - else if (operation == '&') { - return performAnd(list); + private static char evaluate(char operation, List values) { + if (operation == '!') { + return values.get(0) == 't' ? 'f' : 't'; } - else { - return list.get(0) == 't' ? 'f' : 't'; - } - } - - private Character performAnd(List list) { - boolean val = getBooleanValue(list.get(0)); - for (int i = 1; i < list.size(); i++) { - val &= getBooleanValue(list.get(i)); + if (operation == '&') { + for (char value : values) { + if (value == 'f') { + return 'f'; + } + } + return 't'; } - - return val ? 't' : 'f'; - } - - private Character performOr(List list) { - boolean val = getBooleanValue(list.get(0)); - for (int i = 1; i < list.size(); i++) { - val |= getBooleanValue(list.get(i)); + if (operation == '|') { + for (char value : values) { + if (value == 't') { + return 't'; + } + } + return 'f'; } - - return val ? 't' : 'f'; - } - - private boolean getBooleanValue(Character character) { - return character == 't' ? true : false; + return 'f'; } } diff --git a/Hard/Recover a Tree From Preorder Traversal.java b/Hard/Recover a Tree From Preorder Traversal.java index 69f3fe55..b851ca44 100644 --- a/Hard/Recover a Tree From Preorder Traversal.java +++ b/Hard/Recover a Tree From Preorder Traversal.java @@ -4,41 +4,45 @@ * int val; * TreeNode left; * TreeNode right; - * TreeNode(int x) { val = x; } + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } * } */ class Solution { - public TreeNode recoverFromPreorder(String S) { - Map map = new HashMap<>(); + public TreeNode recoverFromPreorder(String traversal) { + Stack stack = new Stack<>(); int idx = 0; - int n = S.length(); - - while (idx < n) { - int level = 0; - StringBuilder sb = new StringBuilder(); - - while (idx < n && S.charAt(idx) == '-') { - level++; + while (idx < traversal.length()) { + int depth = 0; + while (idx < traversal.length() && traversal.charAt(idx) == '-') { + depth++; idx++; } - - while (idx < n && Character.isDigit(S.charAt(idx))) { - sb.append(S.charAt(idx++)); + int value = 0; + while (idx < traversal.length() && Character.isDigit(traversal.charAt(idx))) { + value = value * 10 + Character.getNumericValue(traversal.charAt(idx++)); } - - TreeNode currNode = new TreeNode(Integer.parseInt(sb.toString())); - map.put(level, currNode); - if (level > 0) { - TreeNode parent = map.get(level - 1); - if (parent.left == null) { - parent.left = currNode; - } - else { - parent.right = currNode; + TreeNode node = new TreeNode(value); + while (stack.size() > depth) { + stack.pop(); + } + if (!stack.isEmpty()) { + if (stack.peek().left == null) { + stack.peek().left = node; + } else { + stack.peek().right = node; } } + stack.push(node); + } + while (stack.size() > 1) { + stack.pop(); } - - return map.get(0); + return stack.peek(); } } diff --git a/Hard/Shortest Palindrome.java b/Hard/Shortest Palindrome.java new file mode 100644 index 00000000..3ff38e40 --- /dev/null +++ b/Hard/Shortest Palindrome.java @@ -0,0 +1,23 @@ +class Solution { + public String shortestPalindrome(String s) { + int n = s.length(); + if (n == 0) { + return s; + } + int left = 0; + for (int right = n - 1; right >= 0; right--) { + if (s.charAt(right) == s.charAt(left)) { + left++; + } + } + if (left == n) { + return s; + } + String nonPalindromeSuffix = s.substring(left); + StringBuilder reverseSuffix = new StringBuilder(nonPalindromeSuffix).reverse(); + return reverseSuffix + .append(shortestPalindrome(s.substring(0, left))) + .append(nonPalindromeSuffix) + .toString(); + } +} diff --git a/Hard/Sliding Window Median.java b/Hard/Sliding Window Median.java index 944af371..e37c289d 100644 --- a/Hard/Sliding Window Median.java +++ b/Hard/Sliding Window Median.java @@ -1,72 +1,59 @@ class Solution { - List list; - double[] ans; - boolean isEven; - - public double[] medianSlidingWindow(int[] nums, int k) { - list = new ArrayList<>(); - ans = new double[nums.length - k + 1]; - isEven = k % 2 == 0; - - for (int i=0; i list.get(list.size() - 1)) { - return list.size(); - } - - int start = 0; - int end = list.size(); - - while (start < end) { - int mid = (start + end) / 2; - - if (list.get(mid) < num) { - start = mid + 1; - } - else { - end = mid; + public double[] medianSlidingWindow(int[] nums, int windowSize) { + double[] medians = new double[nums.length - windowSize + 1]; + Map delayedRemovals = new HashMap<>(); + PriorityQueue maxHeap = new PriorityQueue<>(Collections.reverseOrder()); + PriorityQueue minHeap = new PriorityQueue<>(); + int currentIndex = 0; + while (currentIndex < windowSize) { + maxHeap.add(nums[currentIndex++]); + } + for (int j = 0; j < windowSize / 2; j++) { + minHeap.add(maxHeap.poll()); + } + int medianIndex = 0; + while (true) { + if (windowSize % 2 == 1) { + medians[medianIndex++] = maxHeap.peek(); + } else { + medians[medianIndex++] = ((double) maxHeap.peek() + (double) minHeap.peek()) / 2.0; } - } - - return end; - } - - private void removeElement(int num) { - for (int i=0; i= nums.length) { break; } + int outNum = nums[currentIndex - windowSize]; + int inNum = nums[currentIndex++]; + int balance = 0; + // Handle outgoing number + balance += (outNum <= maxHeap.peek() ? -1 : 1); + delayedRemovals.put(outNum, delayedRemovals.getOrDefault(outNum, 0) + 1); + // Handle incoming number + if (!maxHeap.isEmpty() && inNum <= maxHeap.peek()) { + balance++; + maxHeap.add(inNum); + } else { + balance--; + minHeap.add(inNum); + } + // Rebalance heaps + if (balance < 0) { + maxHeap.add(minHeap.poll()); + balance++; + } + if (balance > 0) { + minHeap.add(maxHeap.poll()); + balance--; + } + // Remove invalid numbers from the top of the heaps + while (delayedRemovals.getOrDefault(maxHeap.peek(), 0) > 0) { + delayedRemovals.put(maxHeap.peek(), delayedRemovals.get(maxHeap.peek()) - 1); + maxHeap.poll(); + } + while (!minHeap.isEmpty() && delayedRemovals.getOrDefault(minHeap.peek(), 0) > 0) { + delayedRemovals.put(minHeap.peek(), delayedRemovals.get(minHeap.peek()) - 1); + minHeap.poll(); + } } - } - - private double getMedian() { - if (isEven) { - return (double) (list.get(list.size()/2) + list.get(list.size()/2 - 1)) / 2; - } - else { - return (double) list.get(list.size()/2); - } + return medians; } } diff --git a/Hard/Smallest Range Covering Elements from K Lists.java b/Hard/Smallest Range Covering Elements from K Lists.java new file mode 100644 index 00000000..4e814027 --- /dev/null +++ b/Hard/Smallest Range Covering Elements from K Lists.java @@ -0,0 +1,29 @@ +class Solution { + public int[] smallestRange(List> nums) { + PriorityQueue pq = new PriorityQueue<>( + Comparator.comparingInt(a -> a[0])); + int max = Integer.MIN_VALUE; + int start = 0; + int end = Integer.MAX_VALUE; + for (int i = 0; i < nums.size(); i++) { + pq.add(new int[]{nums.get(i).get(0), i, 0}); + max = Math.max(max, nums.get(i).get(0)); + } + while (pq.size() == nums.size()) { + int[] removed = pq.poll(); + int min = removed[0]; + int row = removed[1]; + int col = removed[2]; + if (max - min < end - start) { + start = min; + end = max; + } + if (col + 1 < nums.get(row).size()) { + int next = nums.get(row).get(col + 1); + pq.add(new int[]{next, row, col + 1}); + max = Math.max(max, next); + } + } + return new int[]{start, end}; + } +} diff --git a/Medium/Binary Search Tree Iterator II.java b/Medium/Binary Search Tree Iterator II.java index 9f98110c..61ab1d10 100644 --- a/Medium/Binary Search Tree Iterator II.java +++ b/Medium/Binary Search Tree Iterator II.java @@ -14,49 +14,47 @@ * } */ class BSTIterator { - - private Deque stack; - private List arr; - private TreeNode lastNode; - private int pointer; - - public BSTIterator(TreeNode root) { - this.stack = new ArrayDeque(); - this.arr = new ArrayList<>(); - this.lastNode = root; - this.pointer = -1; - } - public boolean hasNext() { - return !this.stack.isEmpty() || lastNode != null || this.pointer < arr.size() - 1; - } + private final Deque primary; + private final List secondary; + private int index; - public int next() { - this.pointer++; - if (this.pointer == this.arr.size()) { - updateStack(lastNode); - TreeNode curr = this.stack.pop(); - lastNode = curr.right; - this.arr.add(curr.val); + public BSTIterator(TreeNode root) { + this.primary = new ArrayDeque<>(); + this.secondary = new ArrayList<>(); + this.index = -1; + traverse(root); + } + + public boolean hasNext() { + return !primary.isEmpty() || index < secondary.size() - 1; + } + + public int next() { + index++; + if (index == secondary.size()) { + TreeNode curr = primary.pop(); + secondary.add(curr.val); + traverse(curr.right); + } + return secondary.get(index); + } + + public boolean hasPrev() { + return index > 0; + } + + public int prev() { + index--; + return secondary.get(index); } - return this.arr.get(this.pointer); - } - - public boolean hasPrev() { - return this.pointer > 0; - } - public int prev() { - this.pointer--; - return this.arr.get(this.pointer); - } - - private void updateStack(TreeNode node) { - while (node != null) { - this.stack.push(node); - node = node.left; + private void traverse(TreeNode root) { + while (root != null) { + primary.push(root); + root = root.left; + } } - } } /** diff --git a/Medium/Bitwise XOR of All Pairings.java b/Medium/Bitwise XOR of All Pairings.java new file mode 100644 index 00000000..88dfbd41 --- /dev/null +++ b/Medium/Bitwise XOR of All Pairings.java @@ -0,0 +1,20 @@ +class Solution { + public int xorAllNums(int[] nums1, int[] nums2) { + int m = nums1.length; + int n = nums2.length; + Map freq = new HashMap<>(); + for (int num : nums1) { + freq.put(num, freq.getOrDefault(num, 0) + n); + } + for (int num : nums2) { + freq.put(num, freq.getOrDefault(num, 0) + m); + } + int result = 0; + for (Integer key : freq.keySet()) { + if (freq.get(key) % 2 == 1) { + result ^= key; + } + } + return result; + } +} diff --git a/Medium/Calculate Score After Performing Instructions.java b/Medium/Calculate Score After Performing Instructions.java new file mode 100644 index 00000000..789e5669 --- /dev/null +++ b/Medium/Calculate Score After Performing Instructions.java @@ -0,0 +1,19 @@ +class Solution { + public long calculateScore(String[] instructions, int[] values) { + long result = 0; + int n = values.length; + int idx = 0; + Set executed = new HashSet<>(); + while (idx < n && idx >= 0) { + if (!executed.add(idx)) { + break; + } + if (instructions[idx].equals("add")) { + result += values[idx++]; + } else { + idx += values[idx]; + } + } + return result; + } +} diff --git a/Medium/Check If Array Pairs Are Divisible by k.java b/Medium/Check If Array Pairs Are Divisible by k.java new file mode 100644 index 00000000..d942915f --- /dev/null +++ b/Medium/Check If Array Pairs Are Divisible by k.java @@ -0,0 +1,20 @@ +class Solution { + public boolean canArrange(int[] arr, int k) { + Map map = new HashMap<>(); + for (int num : arr) { + int remainder = ((num % k) + k) % k; + map.put(remainder, map.getOrDefault(remainder, 0) + 1); + } + for (int num : arr) { + int remainder = ((num % k) + k) % k; + if (remainder == 0) { + if (map.get(remainder) % 2 == 1) { + return false; + } + } else if (!map.get(remainder).equals(map.get(k - remainder))) { + return false; + } + } + return true; + } +} diff --git a/Medium/Check if a Parentheses String Can Be Valid.java b/Medium/Check if a Parentheses String Can Be Valid.java new file mode 100644 index 00000000..c240176d --- /dev/null +++ b/Medium/Check if a Parentheses String Can Be Valid.java @@ -0,0 +1,30 @@ +class Solution { + public boolean canBeValid(String s, String locked) { + if (s.length() % 2 != 0) { + return false; + } + Stack openBrackets = new Stack<>(); + Stack unlocked = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (locked.charAt(i) == '0') { + unlocked.push(i); + } else if (c == '(') { + openBrackets.push(i); + } else if (c == ')') { + if (!openBrackets.isEmpty()) { + openBrackets.pop(); + } else if (!unlocked.isEmpty()) { + unlocked.pop(); + } else { + return false; + } + } + } + while (!openBrackets.isEmpty() && !unlocked.isEmpty() && openBrackets.peek() < unlocked.peek()) { + openBrackets.pop(); + unlocked.pop(); + } + return openBrackets.isEmpty(); + } +} diff --git a/Medium/Construct Binary Tree from Preorder and Postorder Traversal.java b/Medium/Construct Binary Tree from Preorder and Postorder Traversal.java new file mode 100644 index 00000000..ca7aa35d --- /dev/null +++ b/Medium/Construct Binary Tree from Preorder and Postorder Traversal.java @@ -0,0 +1,40 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + public TreeNode constructFromPrePost(int[] preorder, int[] postorder) { + int n = preorder.length; + Map postorderIndex = new HashMap<>(); + for (int i = 0; i < n; i++) { + postorderIndex.put(postorder[i], i); + } + return constructTree(0, n - 1, 0, preorder, postorderIndex); + } + + private TreeNode constructTree(int preStart, int preEnd, int postStart, int[] preorder, Map postorderIndex) { + if (preStart > preEnd) { + return null; + } + if (preStart == preEnd) { + return new TreeNode(preorder[preStart]); + } + int leftRoot = preorder[preStart + 1]; + int leftCount = postorderIndex.get(leftRoot) - postStart + 1; + TreeNode root = new TreeNode(preorder[preStart]); + root.left = constructTree(preStart + 1, preStart + leftCount, postStart, preorder, postorderIndex); + root.right = constructTree(preStart + leftCount + 1, preEnd, postStart + leftCount, preorder, postorderIndex); + return root; + } +} diff --git a/Medium/Construct Smallest Number From DI String.java b/Medium/Construct Smallest Number From DI String.java new file mode 100644 index 00000000..64e39262 --- /dev/null +++ b/Medium/Construct Smallest Number From DI String.java @@ -0,0 +1,15 @@ +class Solution { + public String smallestNumber(String pattern) { + StringBuilder result = new StringBuilder(); + Stack stack = new Stack<>(); + for (int i = 0; i <= pattern.length(); i++) { + stack.push(i + 1); + if (i == pattern.length() || pattern.charAt(i) == 'I') { + while (!stack.isEmpty()) { + result.append(stack.pop()); + } + } + } + return result.toString(); + } +} diff --git a/Medium/Count Days Without Meetings.java b/Medium/Count Days Without Meetings.java new file mode 100644 index 00000000..1630e6df --- /dev/null +++ b/Medium/Count Days Without Meetings.java @@ -0,0 +1,24 @@ +class Solution { + public int countDays(int days, int[][] meetings) { + Arrays.sort(meetings, (o1, o2) -> { + int c = Integer.compare(o1[0], o2[0]); + if (c != 0) { + return c; + } + return Integer.compare(o2[1], o1[1]); + }); + int meetingDays = 0; + int idx = 0; + while (idx < meetings.length) { + int start = meetings[idx][0]; + int end = meetings[idx][1]; + idx++; + while (idx < meetings.length && meetings[idx][0] <= end) { + end = Math.max(end, meetings[idx][1]); + idx++; + } + meetingDays += (end - start + 1); + } + return days - meetingDays; + } +} diff --git a/Medium/Count Mentions Per User.java b/Medium/Count Mentions Per User.java new file mode 100644 index 00000000..7fa42668 --- /dev/null +++ b/Medium/Count Mentions Per User.java @@ -0,0 +1,61 @@ +class Solution { + public int[] countMentions(int numberOfUsers, List> eventLog) { + List events = eventLog.stream() + .map(Event::buildEvent) + .sorted() + .collect(Collectors.toList()); + Map offlineUsers = new HashMap<>(); + int[] mentions = new int[numberOfUsers]; + for (Event event : events) { + if (event.message().equals("OFFLINE")) { + offlineUsers.put(Integer.parseInt(event.mentionString()), event.timestamp()); + } else { + int timestamp = event.timestamp(); + List onlineUsers = offlineUsers.entrySet() + .stream() + .filter(t -> timestamp - t.getValue() >= 60) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + onlineUsers.forEach(offlineUsers::remove); + String mentionString = event.mentionString(); + if (mentionString.equals("ALL")) { + for (int i = 0; i < numberOfUsers; i++) { + mentions[i]++; + } + } else if (mentionString.equals("HERE")) { + for (int i = 0; i < numberOfUsers; i++) { + if (!offlineUsers.containsKey(i)) { + mentions[i]++; + } + } + } else { + String[] usersMentioned = mentionString.split(" "); + for (String user : usersMentioned) { + int userId = Integer.parseInt(user.substring(2)); + mentions[userId]++; + } + } + } + } + return mentions; + } + + private record Event(String message, int timestamp, String mentionString) implements Comparable { + + public static Event buildEvent(List event) { + String message = event.get(0); + int timestamp = Integer.parseInt(event.get(1)); + String mentionString = event.get(2); + return new Event(message, timestamp, mentionString); + } + + @Override + public int compareTo(Event o) { + int c = this.timestamp - o.timestamp; + if (c != 0) { + return c; + } + return o.message().compareTo(this.message()); + } + } +} diff --git a/Medium/Count Number of Maximum Bitwise-OR Subsets.java b/Medium/Count Number of Maximum Bitwise-OR Subsets.java new file mode 100644 index 00000000..973e1818 --- /dev/null +++ b/Medium/Count Number of Maximum Bitwise-OR Subsets.java @@ -0,0 +1,23 @@ +class Solution { + public int countMaxOrSubsets(int[] nums) { + int n = nums.length; + int maxValue = 0; + for (int num : nums) { + maxValue |= num; + } + Integer[][] dp = new Integer[n][maxValue + 1]; + return countMaxOrSubsets(nums, 0, 0, maxValue, dp); + } + + private int countMaxOrSubsets(int[] nums, int idx, int current, int maxValue, Integer[][] dp) { + if (idx == nums.length) { + return (current == maxValue) ? 1 : 0; + } + if (dp[idx][current] != null) { + return dp[idx][current]; + } + int countWithout = countMaxOrSubsets(nums, idx + 1, current, maxValue, dp); + int countWith = countMaxOrSubsets(nums, idx + 1, current | nums[idx], maxValue, dp); + return dp[idx][current] = countWith + countWithout; + } +} diff --git a/Medium/Count Total Number of Colored Cells.java b/Medium/Count Total Number of Colored Cells.java new file mode 100644 index 00000000..81c10a8c --- /dev/null +++ b/Medium/Count Total Number of Colored Cells.java @@ -0,0 +1,11 @@ +class Solution { + public long coloredCells(int n) { + long count = 1; + int increment = 4; + while (n-- > 1) { + count += increment; + increment += 4; + } + return count; + } +} diff --git a/Medium/Count the Number of Complete Components.java b/Medium/Count the Number of Complete Components.java new file mode 100644 index 00000000..d198b0b2 --- /dev/null +++ b/Medium/Count the Number of Complete Components.java @@ -0,0 +1,38 @@ +class Solution { + public int countCompleteComponents(int n, int[][] edges) { + Map> graph = new HashMap<>(); + for (int[] edge : edges) { + int nodeOne = edge[0]; + int nodeTwo = edge[1]; + graph.computeIfAbsent(nodeOne, k -> new HashSet<>()).add(nodeTwo); + graph.computeIfAbsent(nodeTwo, k -> new HashSet<>()).add(nodeOne); + } + int count = 0; + Set visited = new HashSet<>(); + for (int i = 0; i < n; i++) { + if (visited.add(i)) { + int[] componentInfo = new int[2]; + dfs(i, graph, visited, componentInfo); + if (componentInfo[0] * (componentInfo[0] - 1) == componentInfo[1]) { + count++; + } + } + } + return count; + } + + private void dfs( + int node, + Map> graph, + Set visited, + int[] componentInfo) { + componentInfo[0]++; + Set connections = graph.getOrDefault(node, new HashSet<>()); + componentInfo[1] += connections.size(); + for (Integer conn : connections) { + if (visited.add(conn)) { + dfs(conn, graph, visited, componentInfo); + } + } + } +} diff --git a/Medium/Cousins in Binary Tree II.java b/Medium/Cousins in Binary Tree II.java new file mode 100644 index 00000000..ee1b4b21 --- /dev/null +++ b/Medium/Cousins in Binary Tree II.java @@ -0,0 +1,44 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + public TreeNode replaceValueInTree(TreeNode root) { + Queue queue = new LinkedList<>(); + queue.add(root); + int prevLevelSum = root.val; + while (!queue.isEmpty()) { + int size = queue.size(); + int levelSum = 0; + for (int i = 0; i < size; i++) { + TreeNode node = queue.remove(); + node.val = prevLevelSum - node.val; + int siblingSum = (node.left != null ? node.left.val : 0) + + (node.right != null ? node.right.val : 0); + if (node.left != null) { + levelSum += node.left.val; + node.left.val = siblingSum; + queue.add(node.left); + } + if (node.right != null) { + levelSum += node.right.val; + node.right.val = siblingSum; + queue.add(node.right); + } + } + prevLevelSum = levelSum; + } + return root; + } +} diff --git a/Medium/Design Circular Deque.java b/Medium/Design Circular Deque.java index 86949d4a..66667ed5 100644 --- a/Medium/Design Circular Deque.java +++ b/Medium/Design Circular Deque.java @@ -1,104 +1,90 @@ class MyCircularDeque { - - private Node head; - private Node tail; - private int k; - private int currSize; - public MyCircularDeque(int k) { - this.k = k; - this.currSize = 0; - this.head = new Node(-1); - this.tail = new Node(-1); - this.head.next = this.tail; - this.tail.prev = this.head; - } + private final Node head; + private final Node tail; + private final int capacity; + private int size; - public boolean insertFront(int value) { - if (isFull()) { - return false; + public MyCircularDeque(int k) { + head = new Node(-1); + tail = new Node(-1); + head.next = tail; + tail.prev = head; + capacity = k; + size = 0; } - Node node = new Node(value); - Node nextToHead = head.next; - head.next = node; - node.prev = head; - node.next = nextToHead; - nextToHead.prev = node; - currSize++; - return true; - } - public boolean insertLast(int value) { - if (isFull()) { - return false; + public boolean insertFront(int value) { + if (size == capacity) { + return false; + } + Node node = new Node(value); + node.next = head.next; + node.prev = head; + head.next.prev = node; + head.next = node; + size++; + return true; } - Node node = new Node(value); - Node prevToTail = tail.prev; - tail.prev = node; - node.next = tail; - prevToTail.next = node; - node.prev = prevToTail; - currSize++; - return true; - } - public boolean deleteFront() { - if (isEmpty()) { - return false; + public boolean insertLast(int value) { + if (size == capacity) { + return false; + } + Node node = new Node(value); + node.prev = tail.prev; + node.next = tail; + tail.prev.next = node; + tail.prev = node; + size++; + return true; } - Node toDelete = head.next; - deleteNode(toDelete); - return true; - } - public boolean deleteLast() { - if (isEmpty()) { - return false; + public boolean deleteFront() { + if (size == 0) { + return false; + } + head.next.next.prev = head; + head.next = head.next.next; + size--; + return true; } - Node toDelete = tail.prev; - deleteNode(toDelete); - return true; - } - public int getFront() { - if (isEmpty()) { - return -1; + public boolean deleteLast() { + if (size == 0) { + return false; + } + tail.prev.prev.next = tail; + tail.prev = tail.prev.prev; + size--; + return true; } - return head.next.val; - } - public int getRear() { - if (isEmpty()) { - return -1; + public int getFront() { + return head.next.value; } - return tail.prev.val; - } - public boolean isEmpty() { - return currSize == 0; - } + public int getRear() { + return tail.prev.value; + } + + public boolean isEmpty() { + return size == 0; + } + + public boolean isFull() { + return size == capacity; + } + + static class Node { + int value; + Node next; + Node prev; - public boolean isFull() { - return currSize == k; - } - - private void deleteNode(Node node) { - Node prevToNode = node.prev; - Node nextToNode = node.next; - prevToNode.next = nextToNode; - nextToNode.prev = prevToNode; - currSize--; - } - - private static class Node { - int val; - Node next; - Node prev; - - public Node(int val) { - this.val = val; + Node(int value) { + this.value = value; + } } - } } /** diff --git a/Medium/Design Spreadsheet.java b/Medium/Design Spreadsheet.java new file mode 100644 index 00000000..e41fc142 --- /dev/null +++ b/Medium/Design Spreadsheet.java @@ -0,0 +1,47 @@ +class Spreadsheet { + + private final Map> sheet; + + public Spreadsheet(int rows) { + sheet = new HashMap<>(); + for (char c = 'A'; c <= 'Z'; c++) { + sheet.put(c, new HashMap<>()); + } + } + + public void setCell(String cell, int value) { + char column = cell.charAt(0); + int rowNumber = Integer.parseInt(cell.substring(1)); + Map row = sheet.get(column); + row.put(rowNumber, value); + } + + public void resetCell(String cell) { + setCell(cell, 0); + } + + public int getValue(String formula) { + String[] split = formula.split("\\+"); + String cellOne = split[0].substring(1); + String cellTwo = split[1]; + return getCellValue(cellOne) + getCellValue(cellTwo); + } + + private int getCellValue(String cell) { + if (!Character.isLetter(cell.charAt(0))) { + return Integer.parseInt(cell); + } + char column = cell.charAt(0); + int rowNumber = Integer.parseInt(cell.substring(1)); + Map row = sheet.get(column); + return row.getOrDefault(rowNumber, 0); + } +} + +/** + * Your Spreadsheet object will be instantiated and called as such: + * Spreadsheet obj = new Spreadsheet(rows); + * obj.setCell(cell,value); + * obj.resetCell(cell); + * int param_3 = obj.getValue(formula); + */ diff --git a/Medium/Design a Number Container System.java b/Medium/Design a Number Container System.java new file mode 100644 index 00000000..26a3e843 --- /dev/null +++ b/Medium/Design a Number Container System.java @@ -0,0 +1,34 @@ +class NumberContainers { + + private final Map> numberToIndex; + private final Map indexToNumber; + + public NumberContainers() { + this.numberToIndex = new HashMap<>(); + this.indexToNumber = new HashMap<>(); + } + + public void change(int index, int number) { + if (indexToNumber.containsKey(index)) { + int prevNumber = indexToNumber.get(index); + numberToIndex.get(prevNumber).remove(index); + } + indexToNumber.put(index, number); + numberToIndex.computeIfAbsent(number, k -> new TreeSet<>()).add(index); + } + + public int find(int number) { + TreeSet indices = numberToIndex.getOrDefault(number, new TreeSet<>()); + if (indices.isEmpty()) { + return -1; + } + return indices.first(); + } +} + +/** + * Your NumberContainers object will be instantiated and called as such: + * NumberContainers obj = new NumberContainers(); + * obj.change(index,number); + * int param_2 = obj.find(number); + */ diff --git a/Medium/Design a Stack With Increment Operation.java b/Medium/Design a Stack With Increment Operation.java index 9164401b..9e4ec3a3 100644 --- a/Medium/Design a Stack With Increment Operation.java +++ b/Medium/Design a Stack With Increment Operation.java @@ -1,40 +1,40 @@ class CustomStack { - - private Stack stack; - private int[] incrementArray; - private int maxSize; - - public CustomStack(int maxSize) { - this.stack = new Stack<>(); - this.incrementArray = new int[maxSize]; - this.maxSize = maxSize; - } - public void push(int x) { - if (this.stack.size() < this.maxSize) { - this.stack.push(x); - } - } + private final int maxSize; + private final Stack stack; + private int[] increment; - public int pop() { - int idx = this.stack.size() - 1; - if (idx < 0) { - return -1; + public CustomStack(int maxSize) { + this.maxSize = maxSize; + this.stack = new Stack<>(); + this.increment = new int[maxSize]; } - if (idx > 0) { - this.incrementArray[idx - 1] += this.incrementArray[idx]; + + public void push(int x) { + if (stack.size() < maxSize) { + stack.push(x); + } } - int result = this.stack.pop() + this.incrementArray[idx]; - this.incrementArray[idx] = 0; - return result; - } - - public void increment(int k, int val) { - int idx = Math.min(k, this.stack.size()) - 1; - if (idx >= 0) { - this.incrementArray[idx] += val; + + public int pop() { + int idx = stack.size() - 1; + if (idx < 0) { + return -1; + } + if (idx > 0) { + increment[idx - 1] += increment[idx]; + } + int result = stack.pop() + increment[idx]; + increment[idx] = 0; + return result; + } + + public void increment(int k, int val) { + int idx = Math.min(k, stack.size()) - 1; + if (idx >= 0) { + increment[idx] += val; + } } - } } /** diff --git a/Medium/Different Ways to Add Parentheses.java b/Medium/Different Ways to Add Parentheses.java new file mode 100644 index 00000000..706fcf6c --- /dev/null +++ b/Medium/Different Ways to Add Parentheses.java @@ -0,0 +1,42 @@ +class Solution { + public List diffWaysToCompute(String expression) { + List result = new ArrayList<>(); + if (expression.length() == 0) { + return result; + } + if (expression.length() == 1) { + result.add(Integer.parseInt(expression)); + return result; + } + if (expression.length() == 2 && Character.isDigit(expression.charAt(0))) { + result.add(Integer.parseInt(expression)); + return result; + } + for (int i = 0; i < expression.length(); i++) { + char c = expression.charAt(i); + if (Character.isDigit(c)) { + continue; + } + List leftResult = diffWaysToCompute(expression.substring(0, i)); + List rightResult = diffWaysToCompute(expression.substring(i + 1)); + for (int leftVal : leftResult) { + for (int rightVal : rightResult) { + int value = 0; + switch(c) { + case '+': + value = leftVal + rightVal; + break; + case '-': + value = leftVal - rightVal; + break; + case '*': + value = leftVal * rightVal; + break; + } + result.add(value); + } + } + } + return result; + } +} diff --git a/Medium/Distribute Candies Among Children II.java b/Medium/Distribute Candies Among Children II.java new file mode 100644 index 00000000..aa9648f2 --- /dev/null +++ b/Medium/Distribute Candies Among Children II.java @@ -0,0 +1,14 @@ +class Solution { + public long distributeCandies(int n, int limit) { + long result = 0; + for (int i = 0; i <= Math.min(limit, n); i++) { + // distribution not possible as we will have to allocate at least one child with + // more than limit candies + if (n - i > 2 * limit) { + continue; + } + result += Math.min(n - i, limit) - Math.max(0, n - i - limit) + 1; + } + return result; + } +} diff --git a/Medium/Divide Intervals Into Minimum Number of Groups.java b/Medium/Divide Intervals Into Minimum Number of Groups.java new file mode 100644 index 00000000..b58d0dcb --- /dev/null +++ b/Medium/Divide Intervals Into Minimum Number of Groups.java @@ -0,0 +1,21 @@ +class Solution { + public int minGroups(int[][] intervals) { + Arrays.sort(intervals, (o1, o2) -> { + int c = Integer.compare(o1[0], o2[0]); + if (c == 0) { + return Integer.compare(o1[1], o2[1]); + } + return c; + }); + int max = 0; + PriorityQueue pq = new PriorityQueue<>(); + for (int[] interval : intervals) { + while (!pq.isEmpty() && pq.peek() < interval[0]) { + pq.poll(); + } + pq.add(interval[1]); + max = Math.max(max, pq.size()); + } + return max; + } +} diff --git a/Medium/Divide Players Into Teams of Equal Skill.java b/Medium/Divide Players Into Teams of Equal Skill.java index bebcec21..41a5f1f7 100644 --- a/Medium/Divide Players Into Teams of Equal Skill.java +++ b/Medium/Divide Players Into Teams of Equal Skill.java @@ -1,19 +1,25 @@ class Solution { public long dividePlayers(int[] skill) { - Arrays.sort(skill); + int n = skill.length; + int totalSkill = 0; + Map map = new HashMap<>(); + for (int s : skill) { + totalSkill += s; + map.put(s, map.getOrDefault(s, 0) + 1); + } + if (totalSkill % (n / 2) != 0) { + return -1; + } + int targetSkill = totalSkill / (n / 2); long totalChemistry = 0; - int start = 0; - int end = skill.length - 1; - int totalSkill = skill[start] + skill[end]; - while (start < end) { - int currTotal = skill[start] + skill[end]; - if (currTotal != totalSkill) { + for (int currSkill : map.keySet()) { + int partnerSkill = targetSkill - currSkill; + int currSkillFreq = map.get(currSkill); + if (!map.containsKey(partnerSkill) || currSkillFreq != map.get(partnerSkill)) { return -1; } - totalChemistry += skill[start] * skill[end]; - start++; - end--; + totalChemistry += (long) currSkill * (long) partnerSkill * (long) currSkillFreq; } - return totalChemistry; + return totalChemistry / 2; } } diff --git a/Medium/Find Kth Bit in Nth Binary String.java b/Medium/Find Kth Bit in Nth Binary String.java new file mode 100644 index 00000000..e98b29c7 --- /dev/null +++ b/Medium/Find Kth Bit in Nth Binary String.java @@ -0,0 +1,22 @@ +class Solution { + public char findKthBit(int n, int k) { + return nthString(n).charAt(k - 1); + } + + private String nthString(int n) { + if (n == 1) { + return "0"; + } + String prevString = nthString(n - 1); + return prevString + "1" + reverseAndInvert(prevString); + } + + private String reverseAndInvert(String s) { + char[] chars = s.toCharArray(); + for (int i = 0; i < s.length(); i++) { + chars[i] = chars[i] == '1' ? '0' : '1'; + } + StringBuilder sb = new StringBuilder(String.valueOf(chars)); + return sb.reverse().toString(); + } +} diff --git a/Medium/Find Minimum Time to Reach Last Room I.java b/Medium/Find Minimum Time to Reach Last Room I.java new file mode 100644 index 00000000..0247baa4 --- /dev/null +++ b/Medium/Find Minimum Time to Reach Last Room I.java @@ -0,0 +1,36 @@ +class Solution { + + private static final int[][] DIRS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; + + public int minTimeToReach(int[][] moveTime) { + int n = moveTime.length; + int m = moveTime[0].length; + boolean[][] visited = new boolean[n][m]; + Integer[][] minTime = new Integer[n][m]; + minTime[0][0] = 0; + PriorityQueue pq = new PriorityQueue<>((a, b) -> a[2] - b[2]); + pq.add(new int[]{0, 0, 0}); + while (!pq.isEmpty()) { + int[] removed = pq.remove(); + int x = removed[0]; + int y = removed[1]; + if (visited[x][y]) { + continue; + } + visited[x][y] = true; + for (int[] dir : DIRS) { + int newX = x + dir[0]; + int newY = y + dir[1]; + if (newX >= 0 && newY >= 0 && newX < n && newY < m) { + int distance = Math.max(minTime[x][y], moveTime[newX][newY]) + 1; + int currMinTime = minTime[newX][newY] == null ? Integer.MAX_VALUE : minTime[newX][newY]; + if (currMinTime > distance) { + minTime[newX][newY] = distance; + pq.add(new int[]{newX, newY, distance}); + } + } + } + } + return minTime[n - 1][m - 1]; + } +} diff --git a/Medium/Find Unique Binary String.java b/Medium/Find Unique Binary String.java new file mode 100644 index 00000000..80cdfa9e --- /dev/null +++ b/Medium/Find Unique Binary String.java @@ -0,0 +1,25 @@ +class Solution { + + private static final char[] BINARY_CHARS = {'1', '0'}; + + public String findDifferentBinaryString(String[] nums) { + int n = nums.length; + Set binaryStrings = new HashSet<>(); + backtrack(new StringBuilder(), n, binaryStrings); + Set binaryStringsPresent = Arrays.stream(nums).collect(Collectors.toSet()); + binaryStrings.removeAll(binaryStringsPresent); + return binaryStrings.isEmpty() ? "" : binaryStrings.iterator().next(); + } + + private void backtrack(StringBuilder sb, int n, Set binaryStrings) { + if (sb.length() == n) { + binaryStrings.add(sb.toString()); + return; + } + for (char c : BINARY_CHARS) { + sb.append(c); + backtrack(sb, n, binaryStrings); + sb.deleteCharAt(sb.length() - 1); + } + } +} diff --git a/Medium/Find the Lexicographically Largest String From the Box I.java b/Medium/Find the Lexicographically Largest String From the Box I.java new file mode 100644 index 00000000..1133cb93 --- /dev/null +++ b/Medium/Find the Lexicographically Largest String From the Box I.java @@ -0,0 +1,16 @@ +class Solution { + public String answerString(String word, int numFriends) { + if (numFriends == 1) { + return word; + } + int n = word.length(); + String result = ""; + for (int i = 0; i < n; i++) { + String curr = word.substring(i, Math.min(i + n - numFriends + 1, n)); + if (result.compareTo(curr) <= 0) { + result = curr; + } + } + return result; + } +} diff --git a/Medium/Find the Longest Substring Containing Vowels in Even Counts.java b/Medium/Find the Longest Substring Containing Vowels in Even Counts.java new file mode 100644 index 00000000..66e33ef9 --- /dev/null +++ b/Medium/Find the Longest Substring Containing Vowels in Even Counts.java @@ -0,0 +1,22 @@ +class Solution { + public int findTheLongestSubstring(String s) { + int prefixXor = 0; + char[] frequency = new char[26]; + frequency['a' - 'a'] = 1; + frequency['e' - 'a'] = 2; + frequency['i' - 'a'] = 4; + frequency['o' - 'a'] = 8; + frequency['u' - 'a'] = 16; + int[] indexMap = new int[32]; + Arrays.fill(indexMap, -1); + int result = 0; + for (int i = 0; i < s.length(); i++) { + prefixXor ^= frequency[s.charAt(i) - 'a']; + if (indexMap[prefixXor] == -1 && prefixXor != 0) { + indexMap[prefixXor] = i; + } + result = Math.max(result, i - indexMap[prefixXor]); + } + return result; + } +} diff --git a/Medium/Find the Number of Distinct Colors Among the Balls.java b/Medium/Find the Number of Distinct Colors Among the Balls.java new file mode 100644 index 00000000..428e5406 --- /dev/null +++ b/Medium/Find the Number of Distinct Colors Among the Balls.java @@ -0,0 +1,23 @@ +class Solution { + public int[] queryResults(int limit, int[][] queries) { + Map ballToColor = new HashMap<>(); + Map colorToBallCount = new HashMap<>(); + int n = queries.length; + int[] result = new int[n]; + for (int i = 0; i < queries.length; i++) { + int ball = queries[i][0]; + int color = queries[i][1]; + if (ballToColor.containsKey(ball)) { + int prevColor = ballToColor.get(ball); + colorToBallCount.put(prevColor, colorToBallCount.get(prevColor) - 1); + if (colorToBallCount.get(prevColor) == 0) { + colorToBallCount.remove(prevColor); + } + } + ballToColor.put(ball, color); + colorToBallCount.put(color, colorToBallCount.getOrDefault(color, 0) + 1); + result[i] = colorToBallCount.size(); + } + return result; + } +} diff --git a/Medium/Find the Prefix Common Array of Two Arrays.java b/Medium/Find the Prefix Common Array of Two Arrays.java index bd747227..e6312a17 100644 --- a/Medium/Find the Prefix Common Array of Two Arrays.java +++ b/Medium/Find the Prefix Common Array of Two Arrays.java @@ -1,14 +1,17 @@ class Solution { public int[] findThePrefixCommonArray(int[] A, int[] B) { - Map map = new HashMap<>(); int count = 0; - int[] result = new int[A.length]; - for (int i = 0; i < A.length; i++) { - map.put(A[i], map.getOrDefault(A[i], 0) + 1); - map.put(B[i], map.getOrDefault(B[i], 0) + 1); - count += map.get(A[i]) == 2 ? 1 : 0; - if (A[i] != B[i]) { - count += map.get(B[i]) == 2 ? 1 : 0; + int n = A.length; + int[] result = new int[n]; + int[] frequency = new int[n + 1]; + for (int i = 0; i < n; i++) { + frequency[A[i]]++; + if (frequency[A[i]] == 2) { + count++; + } + frequency[B[i]]++; + if (frequency[B[i]] == 2) { + count++; } result[i] = count; } diff --git a/Medium/First Unique Number.java b/Medium/First Unique Number.java index d5406335..6affb411 100644 --- a/Medium/First Unique Number.java +++ b/Medium/First Unique Number.java @@ -1,68 +1,27 @@ class FirstUnique { - - private Node head; - private Node tail; - private Map map; - - public FirstUnique(int[] nums) { - this.head = new Node(-1); - this.tail = new Node(-1); - this.head.next = this.tail; - this.tail.prev = this.head; - this.map = new HashMap<>(); - for (int num : nums) { - if (map.containsKey(num)) { - deleteNode(map.get(num)); - } else { - Node node = new Node(num); - map.put(num, node); - addToTail(node); - } - } - } - public int showFirstUnique() { - return this.head.next.val; - } + private Map map; + private Queue queue; - public void add(int value) { - if (map.containsKey(value)) { - deleteNode(map.get(value)); - return; + public FirstUnique(int[] nums) { + map = new HashMap<>(); + queue = new LinkedList<>(); + for (int num : nums) { + add(num); + } } - Node node = new Node(value); - map.put(value, node); - addToTail(node); - } - - private void addToTail(Node node) { - Node prevToTail = this.tail.prev; - prevToTail.next = node; - node.next = this.tail; - node.prev = prevToTail; - this.tail.prev = node; - } - - private void deleteNode(Node node) { - if (node == null) { - return; + + public int showFirstUnique() { + while (!queue.isEmpty() && map.get(queue.peek()) > 1) { + queue.remove(); + } + return queue.isEmpty() ? -1 : queue.peek(); } - map.put(node.val, null); - Node prevToNode = node.prev; - Node nextToNode = node.next; - prevToNode.next = nextToNode; - nextToNode.prev = prevToNode; - } - - private static class Node { - int val; - Node next; - Node prev; - public Node(int val) { - this.val = val; + public void add(int value) { + queue.add(value); + map.put(value, map.getOrDefault(value, 0) + 1); } - } } /** diff --git a/Medium/Flip Equivalent Binary Trees.java b/Medium/Flip Equivalent Binary Trees.java index 7829ff4d..8590505e 100644 --- a/Medium/Flip Equivalent Binary Trees.java +++ b/Medium/Flip Equivalent Binary Trees.java @@ -1,31 +1,31 @@ -i/** +/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; - * TreeNode(int x) { val = x; } + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } * } */ class Solution { - public boolean flipEquiv(TreeNode root1, TreeNode root2) { - if (root1 == null && root2 == null) { - return true; + public boolean flipEquiv(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return true; + } + if (root1 == null || root2 == null) { + return false; + } + if (root1.val != root2.val) { + return false; + } + boolean noSwap = flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right); + boolean swap = flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left); + return noSwap || swap; } - if (root1 == null || root2 == null) { - return false; - } - if (root1.val != root2.val) { - return false; - } - return ( - ( - flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right) - ) || - ( - flipEquiv(root1.left, root2.right) && - flipEquiv(root1.right, root2.left) - ) - ); - } } diff --git a/Medium/Largest Combination With Bitwise AND Greater Than Zero.java b/Medium/Largest Combination With Bitwise AND Greater Than Zero.java new file mode 100644 index 00000000..1399f1bb --- /dev/null +++ b/Medium/Largest Combination With Bitwise AND Greater Than Zero.java @@ -0,0 +1,17 @@ +class Solution { + public int largestCombination(int[] candidates) { + int[] bitCount = new int[24]; + for (int i = 0; i < 24; i++) { + for (int candidate : candidates) { + if ((candidate & (1 << i)) != 0) { + bitCount[i]++; + } + } + } + int result = 0; + for (int count : bitCount) { + result = Math.max(count, result); + } + return result; + } +} diff --git a/Medium/Lexicographical Numbers.java b/Medium/Lexicographical Numbers.java index c0ccab5e..4476017b 100644 --- a/Medium/Lexicographical Numbers.java +++ b/Medium/Lexicographical Numbers.java @@ -1,19 +1,18 @@ class Solution { - public List lexicalOrder(int n) { - List result = new ArrayList<>(); - for (int i = 1; i < 10; i++) { - dfs(i, n, result); + public List lexicalOrder(int n) { + List result = new ArrayList<>(); + int curr = 1; + for (int i = 0; i < n; i++) { + result.add(curr); + if (curr * 10 <= n) { + curr *= 10; + } else { + while (curr % 10 == 9 || curr == n) { + curr /= 10; + } + curr++; + } + } + return result; } - return result; - } - - private void dfs(int curr, int n, List result) { - if (curr > n) { - return; - } - result.add(curr); - for (int i = 0; i < 10; i++) { - dfs(10 * curr + i, n, result); - } - } } diff --git a/Medium/Lexicographically Minimum String After Removing Stars.java b/Medium/Lexicographically Minimum String After Removing Stars.java new file mode 100644 index 00000000..794ee712 --- /dev/null +++ b/Medium/Lexicographically Minimum String After Removing Stars.java @@ -0,0 +1,28 @@ +class Solution { + public String clearStars(String s) { + Deque[] count = new Deque[26]; + for (int i = 0; i < 26; i++) { + count[i] = new ArrayDeque<>(); + } + char[] letters = s.toCharArray(); + for (int i = 0; i < letters.length; i++) { + if (letters[i] != '*') { + count[letters[i] - 'a'].push(i); + } else { + for (int j = 0; j < 26; j++) { + if (!count[j].isEmpty()) { + letters[count[j].pop()] = '*'; + break; + } + } + } + } + StringBuilder sb = new StringBuilder(); + for (char c : letters) { + if (c != '*') { + sb.append(c); + } + } + return sb.toString(); + } +} diff --git a/Medium/Lexicographically Smallest Equivalent String.java b/Medium/Lexicographically Smallest Equivalent String.java index c5856615..f4d01c21 100644 --- a/Medium/Lexicographically Smallest Equivalent String.java +++ b/Medium/Lexicographically Smallest Equivalent String.java @@ -1,31 +1,46 @@ class Solution { - public String smallestEquivalentString(String s1, String s2, String baseStr) { - int[] graph = new int[26]; - for (int i = 0; i < 26; i++) { - graph[i] = i; + public String smallestEquivalentString(String s1, String s2, String baseStr) { + UnionFind unionFind = new UnionFind(26); + for (int i = 0; i < s1.length(); i++) { + char c1 = s1.charAt(i); + char c2 = s2.charAt(i); + unionFind.union(c1 - 'a', c2 - 'a'); + } + StringBuilder result = new StringBuilder(); + for (char c : baseStr.toCharArray()) { + result.append((char) (unionFind.find(c - 'a') + 'a')); + } + return result.toString(); } - for (int i = 0; i < s1.length(); i++) { - int idxOne = s1.charAt(i) - 'a'; - int idxTwo = s2.charAt(i) - 'a'; - int parentOne = find(graph, idxOne); - int parentTwo = find(graph, idxTwo); - if(parentOne < parentTwo) { - graph[parentTwo] = parentOne; - } else { - graph[parentOne] = parentTwo; - } + + class UnionFind { + private int[] parent; + + public UnionFind(int n) { + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int node) { + if (parent[node] == node) { + return node; + } + parent[node] = find(parent[node]); + return parent[node]; + } + + public void union(int nodeOne, int nodeTwo) { + int parentOne = find(nodeOne); + int parentTwo = find(nodeTwo); + if (parentOne != parentTwo) { + if (parentOne < parentTwo) { + parent[parentTwo] = parentOne; + } else { + parent[parentOne] = parentTwo; + } + } + } } - StringBuilder sb = new StringBuilder(); - for (char c : baseStr.toCharArray()) { - sb.append((char) ('a' + find(graph, c - 'a'))); - } - return sb.toString(); - } - - private int find(int[] graph, int idx) { - while(graph[idx] != idx) { - idx = graph[idx]; - } - return idx; - } } diff --git a/Medium/Longest Happy String.java b/Medium/Longest Happy String.java index 145fd638..4af8f747 100644 --- a/Medium/Longest Happy String.java +++ b/Medium/Longest Happy String.java @@ -1,42 +1,42 @@ class Solution { - public String longestDiverseString(int a, int b, int c) { - PriorityQueue priorityQueue = new PriorityQueue<>((o1, o2) -> o2[1] - o1[1]); - if (a > 0) { - priorityQueue.add(new int[]{0, a}); - } - if (b > 0) { - priorityQueue.add(new int[]{1, b}); - } - if (c > 0) { - priorityQueue.add(new int[]{2, c}); - } - StringBuilder sb = new StringBuilder("zz"); - while (!priorityQueue.isEmpty()) { - int[] temp = {-1, -1}; - char peekChar = (char) ('a' + priorityQueue.peek()[0]); - if (peekChar == sb.charAt(sb.length() - 1) && - peekChar == sb.charAt(sb.length() - 2)) { - temp[0] = priorityQueue.peek()[0]; - temp[1] = priorityQueue.peek()[1]; - priorityQueue.poll(); - if (priorityQueue.isEmpty()) { - break; + public String longestDiverseString(int a, int b, int c) { + PriorityQueue pq = + new PriorityQueue<>((p, q) -> q.frequency() - p.frequency()); + if (a > 0) { + pq.add(new LetterFrequencyPair('a', a)); + } + if (b > 0) { + pq.add(new LetterFrequencyPair('b', b)); + } + if (c > 0) { + pq.add(new LetterFrequencyPair('c', c)); } - } - peekChar = (char) ('a' + priorityQueue.peek()[0]); - if (peekChar != sb.charAt(sb.length() - 1) || - peekChar != sb.charAt(sb.length() - 2)) { - int[] removed = priorityQueue.poll(); - sb.append(peekChar); - removed[1]--; - if (removed[1] > 0) { - priorityQueue.add(removed); + StringBuilder sb = new StringBuilder(); + while (!pq.isEmpty()) { + LetterFrequencyPair removed = pq.remove(); + int frequency = removed.frequency(); + int resultLength = sb.length(); + if (resultLength >= 2 && + sb.charAt(resultLength - 1) == removed.letter() && + sb.charAt(resultLength - 2) == removed.letter()) { + if (pq.isEmpty()) { + break; + } + LetterFrequencyPair temp = pq.remove(); + sb.append(temp.letter()); + if (temp.frequency() - 1 > 0) { + pq.add(new LetterFrequencyPair(temp.letter(), temp.frequency() - 1)); + } + } else { + sb.append(removed.letter()); + frequency--; + } + if (frequency > 0) { + pq.add(new LetterFrequencyPair(removed.letter(), frequency)); + } } - } - if (temp[0] != -1) { - priorityQueue.add(temp); - } + return sb.toString(); } - return sb.substring(2).toString(); - } + + private record LetterFrequencyPair(char letter, int frequency) {} } diff --git a/Medium/Longest Square Streak in an Array.java b/Medium/Longest Square Streak in an Array.java new file mode 100644 index 00000000..141abdee --- /dev/null +++ b/Medium/Longest Square Streak in an Array.java @@ -0,0 +1,25 @@ +class Solution { + + private static final int LIMIT = 100_000; + + public int longestSquareStreak(int[] nums) { + Set uniqueNums = new HashSet<>(); + for (int num : nums) { + uniqueNums.add(num); + } + int result = 0; + for (int num : nums) { + int currStreak = 0; + long curr = num; + while (uniqueNums.contains((int) curr)) { + currStreak++; + if (curr * curr > LIMIT) { + break; + } + curr *= curr; + } + result = Math.max(result, currStreak); + } + return result < 2 ? -1 : result; + } +} diff --git a/Medium/Longest Subarray With Maximum Bitwise AND.java b/Medium/Longest Subarray With Maximum Bitwise AND.java new file mode 100644 index 00000000..63c1ca55 --- /dev/null +++ b/Medium/Longest Subarray With Maximum Bitwise AND.java @@ -0,0 +1,20 @@ +class Solution { + public int longestSubarray(int[] nums) { + int result = 0; + int max = 0; + int count = 0; + for (int num : nums) { + if (max < num) { + max = num; + result = count = 0; + } + if (max == num) { + count++; + } else { + count = 0; + } + result = Math.max(result, count); + } + return result; + } +} diff --git a/Medium/Longest Word With All Prefixes.java b/Medium/Longest Word With All Prefixes.java index 567aea3a..a2a69a0f 100644 --- a/Medium/Longest Word With All Prefixes.java +++ b/Medium/Longest Word With All Prefixes.java @@ -1,53 +1,59 @@ class Solution { - public String longestWord(String[] words) { - TrieNode root = new TrieNode(); - root.isWord = true; - Map> map = new TreeMap<>((o1, o2) -> o2 - o1); - for (String word : words) { - addToTrie(word, root); - map.computeIfAbsent(word.length(), k -> new PriorityQueue<>(String::compareTo)).add(word); - } - for (Integer key : map.keySet()) { - PriorityQueue priorityQueue = map.get(key); - while (!priorityQueue.isEmpty()) { - String candidateWord = priorityQueue.poll(); - if (wordContainAllPrefixes(candidateWord, root)) { - return candidateWord; + public String longestWord(String[] words) { + TrieNode root = new TrieNode(); + for (String word : words) { + root.insert(word); + } + String longestValidWord = ""; + for (String word : words) { + if (root.hasAllPrefixes(word)) { + if (word.length() > longestValidWord.length() || + (word.length() == longestValidWord.length() && word.compareTo(longestValidWord) < 0)) { + longestValidWord = word; + } + } } - } + return longestValidWord; } - return ""; - } - private boolean wordContainAllPrefixes(String word, TrieNode root) { - TrieNode curr = root; - for (int i = 0; i < word.length(); i++) { - if (!curr.isWord) { - return false; - } - curr = curr.children.get(word.charAt(i)); - } - return curr.isWord; - } + static class TrieNode { + private final Map children; + private boolean isWord; - private void addToTrie(String word, TrieNode root) { - TrieNode curr = root; - for (int i = 0; i < word.length(); i++) { - if (!curr.children.containsKey(word.charAt(i))) { - curr.children.put(word.charAt(i), new TrieNode()); - } - curr = curr.children.get(word.charAt(i)); - } - curr.isWord = true; - } + public TrieNode() { + this.children = new HashMap<>(); + } - private static class TrieNode { - Map children; - boolean isWord; + public void insert(String word) { + TrieNode curr = this; + for (char c : word.toCharArray()) { + curr = curr.getOrCreateChild(c); + } + curr.isWord = true; + } + + public boolean hasAllPrefixes(String word) { + TrieNode curr = this; + for (char c : word.toCharArray()) { + TrieNode child = curr.children.getOrDefault(c, null); + if (child == null) { + return false; + } + if (!child.isWord) { + return false; + } + curr = child; + } + return true; + } - public TrieNode() { - this.children = new HashMap<>(); - this.isWord = false; + private TrieNode getOrCreateChild(char c) { + if (children.containsKey(c)) { + return children.get(c); + } + TrieNode node = new TrieNode(); + children.put(c, node); + return node; + } } - } } diff --git a/Medium/Make Sum Divisible by P.java b/Medium/Make Sum Divisible by P.java new file mode 100644 index 00000000..ee94817a --- /dev/null +++ b/Medium/Make Sum Divisible by P.java @@ -0,0 +1,26 @@ +class Solution { + public int minSubarray(int[] nums, int p) { + int n = nums.length; + int sum = 0; + for (int num : nums) { + sum = (sum + num) % p; + } + int target = sum % p; + if (target == 0) { + return 0; + } + Map map = new HashMap<>(); + map.put(0, -1); + int currSum = 0; + int result = n; + for (int i = 0; i < n; i++) { + currSum = (currSum + nums[i]) % p; + int needed = (currSum - target + p) % p; + if (map.containsKey(needed)) { + result = Math.min(result, i - map.get(needed)); + } + map.put(currSum, i); + } + return result == n ? -1 : result; + } +} diff --git a/Medium/Max Sum of a Pair With Equal Sum of Digits.java b/Medium/Max Sum of a Pair With Equal Sum of Digits.java index 597e0658..1d8d89ae 100644 --- a/Medium/Max Sum of a Pair With Equal Sum of Digits.java +++ b/Medium/Max Sum of a Pair With Equal Sum of Digits.java @@ -1,25 +1,25 @@ class Solution { - public int maximumSum(int[] nums) { - int maxSum = -1; - Map map = new HashMap<>(); - for (int num : nums) { - int digitSum = getDigitSum(num); - if (map.containsKey(digitSum)) { - maxSum = Math.max(maxSum, map.get(digitSum) + num); - map.put(digitSum, Math.max(map.get(digitSum), num)); - } else { - map.put(digitSum, num); - } + public int maximumSum(int[] nums) { + Map map = new HashMap<>(); + int maxSum = -1; + for (int num : nums) { + int digitSum = calculateDigitSum(num); + if (map.containsKey(digitSum)) { + maxSum = Math.max(maxSum, map.get(digitSum) + num); + map.put(digitSum, Math.max(map.get(digitSum), num)); + } else { + map.put(digitSum, num); + } + } + return maxSum; } - return maxSum; - } - - private int getDigitSum(int num) { - int sum = 0; - while (num > 0) { - sum += num % 10; - num /= 10; + + private int calculateDigitSum(int num) { + int sum = 0; + while (num > 0) { + sum += num % 10; + num /= 10; + } + return sum; } - return sum; - } } diff --git a/Medium/Maximum Coins Heroes Can Collect.java b/Medium/Maximum Coins Heroes Can Collect.java new file mode 100644 index 00000000..1e98abf9 --- /dev/null +++ b/Medium/Maximum Coins Heroes Can Collect.java @@ -0,0 +1,40 @@ +class Solution { + public long[] maximumCoins(int[] heroes, int[] monsters, int[] coins) { + List monsterEntities = new ArrayList<>(); + int n = monsters.length; + for (int i = 0; i < n; i++) { + monsterEntities.add(new MonsterEntity(monsters[i], coins[i])); + } + Collections.sort(monsterEntities, (a, b) -> (a.health() - b.health())); + long[] prefixCoinSum = new long[n]; + for (int i = 0; i < n; i++) { + prefixCoinSum[i] = i == 0 ? 0 : prefixCoinSum[i - 1]; + prefixCoinSum[i] += monsterEntities.get(i).coin(); + } + int m = heroes.length; + long[] result = new long[m]; + for (int i = 0; i < m; i++) { + int idx = binarySearch(monsterEntities, heroes[i]); + result[i] = idx != Integer.MIN_VALUE ? prefixCoinSum[idx] : 0; + } + return result; + } + + private int binarySearch(List monsterEntities, int heroHealth) { + int left = 0; + int right = monsterEntities.size() - 1; + int idx = Integer.MIN_VALUE; + while (left <= right) { + int mid = (left + right) / 2; + if (monsterEntities.get(mid).health() <= heroHealth) { + idx = Math.max(idx, mid); + left = mid + 1; + } else { + right = mid - 1; + } + } + return idx; + } + + private static record MonsterEntity(int health, int coin) {} +} diff --git a/Medium/Maximum Number of Moves in a Grid.java b/Medium/Maximum Number of Moves in a Grid.java new file mode 100644 index 00000000..014425f8 --- /dev/null +++ b/Medium/Maximum Number of Moves in a Grid.java @@ -0,0 +1,40 @@ +class Solution { + + private static final int[] DIRS = {-1, 0, 1}; + + public int maxMoves(int[][] grid) { + int rows = grid.length; + int cols = grid[0].length; + Queue queue = new LinkedList<>(); + boolean[][] visited = new boolean[rows][cols]; + for (int i = 0; i < rows; i++) { + visited[i][0] = true; + queue.add(new int[]{i, 0, 0}); + } + int result = 0; + while (!queue.isEmpty()) { + int size = queue.size(); + while (size-- > 0) { + int[] removed = queue.remove(); + int row = removed[0]; + int col = removed[1]; + int count = removed[2]; + result = Math.max(result, count); + for (int dir : DIRS) { + int nextRow = row + dir; + int nextCol = col + 1; + if (nextRow >= 0 && + nextCol >= 0 && + nextRow < rows && + nextCol < cols && + !visited[nextRow][nextCol] && + grid[row][col] < grid[nextRow][nextCol]) { + visited[nextRow][nextCol] = true; + queue.add(new int[]{nextRow, nextCol, count + 1}); + } + } + } + } + return result; + } +} diff --git a/Medium/Maximum Size Subarray Sum Equals k.java b/Medium/Maximum Size Subarray Sum Equals k.java index 97d37973..dce7007a 100644 --- a/Medium/Maximum Size Subarray Sum Equals k.java +++ b/Medium/Maximum Size Subarray Sum Equals k.java @@ -1,18 +1,17 @@ class Solution { - public int maxSubArrayLen(int[] nums, int k) { - Map map = new HashMap<>(); - int res = 0; - int sum = 0; - for (int i = 0; i < nums.length; i++) { - sum += nums[i]; - if (sum == k) { - res = i + 1; - } - else if (map.containsKey(sum - k)) { - res = Math.max(res, i - map.get(sum - k)); - } - map.putIfAbsent(sum, i); + public int maxSubArrayLen(int[] nums, int k) { + Map map = new HashMap<>(); + int prefixSum = 0; + int max = 0; + for (int i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixSum == k) { + max = i + 1; + } else if (map.containsKey(prefixSum - k)) { + max = Math.max(max, i - map.get(prefixSum - k)); + } + map.putIfAbsent(prefixSum, i); + } + return max; } - return res; - } } diff --git a/Medium/Maximum Swap.java b/Medium/Maximum Swap.java index 5d30c780..c12fb12e 100644 --- a/Medium/Maximum Swap.java +++ b/Medium/Maximum Swap.java @@ -1,29 +1,20 @@ class Solution { - public int maximumSwap(int num) { - String stringValue = Integer.toString(num); - Map valToIndexMap = new HashMap<>(); - int[] digits = new int[String.valueOf(num).length()]; - for (int i = digits.length - 1; i >= 0; i--) { - int digit = num % 10; - num /= 10; - digits[i] = digit; - valToIndexMap.putIfAbsent(digit, i); - } - for (int i = 0; i < digits.length; i++) { - for (int k = 9; k > digits[i]; k--) { - if (valToIndexMap.getOrDefault(k, -1) > i) { - int swapIndex = valToIndexMap.get(k); - return Integer.parseInt( - stringValue.substring(0, i) // Digits before swap index - + k // Swapped value - + stringValue.substring(i + 1, swapIndex) // Digits after original index(i) and before swappedIndex - + digits[i] // Digit at original index(i) - + ((swapIndex + 1) != stringValue.length() // Check if swapIndex is last digit of num - ? stringValue.substring(swapIndex + 1) // If not then add digits that come after the swapIndex - : "")); // Else add an empty string + public int maximumSwap(int num) { + char[] digits = String.valueOf(num).toCharArray(); + int n = digits.length; + int[] maxRightIdx = new int[n]; + maxRightIdx[n - 1] = n - 1; + for (int i = n - 2; i >= 0; i--) { + maxRightIdx[i] = (digits[i] > digits[maxRightIdx[i + 1]]) ? i : maxRightIdx[i + 1]; + } + for (int i = 0; i < n; i++) { + if (digits[i] < digits[maxRightIdx[i]]) { + char temp = digits[i]; + digits[i] = digits[maxRightIdx[i]]; + digits[maxRightIdx[i]] = temp; + return Integer.parseInt(String.valueOf(digits)); + } } - } + return num; } - return Integer.parseInt(stringValue); - } } diff --git a/Medium/Maximum Width Ramp.java b/Medium/Maximum Width Ramp.java index 37eb1862..2463f02b 100644 --- a/Medium/Maximum Width Ramp.java +++ b/Medium/Maximum Width Ramp.java @@ -1,21 +1,18 @@ class Solution { - public int maxWidthRamp(int[] A) { + public int maxWidthRamp(int[] nums) { + int n = nums.length; Stack stack = new Stack<>(); - int ans = 0; - int n = A.length; - - for (int i=0; i A[i]) { - stack.add(i); + for (int i = 0; i < n; i++) { + if (stack.isEmpty() || nums[stack.peek()] > nums[i]) { + stack.push(i); } } - - for (int i=n-1; i>=ans; i--) { - while (!stack.isEmpty() && A[stack.peek()] <= A[i]) { - ans = Math.max(ans, i - stack.pop()); + int result = 0; + for (int i = n - 1; i >= 0; i--) { + while (!stack.isEmpty() && nums[stack.peek()] <= nums[i]) { + result = Math.max(result, i - stack.pop()); } } - - return ans; + return result; } } diff --git a/Medium/Minimize XOR.java b/Medium/Minimize XOR.java new file mode 100644 index 00000000..cc5e87a3 --- /dev/null +++ b/Medium/Minimize XOR.java @@ -0,0 +1,24 @@ +class Solution { + public int minimizeXor(int num1, int num2) { + int result = 0; + int targetSetBitCount = Integer.bitCount(num2); + int setBitCount = 0; + int currBit = 31; + while (setBitCount < targetSetBitCount) { + if (isSet(num1, currBit) || (targetSetBitCount - setBitCount > currBit)) { + result = setBit(result, currBit); + setBitCount++; + } + currBit--; + } + return result; + } + + private boolean isSet(int x, int bit) { + return (x & (1 << bit)) != 0; + } + + private int setBit(int x, int bit) { + return x | (1 << bit); + } +} diff --git a/Medium/Minimized Maximum of Products Distributed to Any Store.java b/Medium/Minimized Maximum of Products Distributed to Any Store.java new file mode 100644 index 00000000..70a46016 --- /dev/null +++ b/Medium/Minimized Maximum of Products Distributed to Any Store.java @@ -0,0 +1,36 @@ +class Solution { + public int minimizedMaximum(int n, int[] quantities) { + int left = 0; + int right = 0; + for (int quantity : quantities) { + right = Math.max(right, quantity); + } + while (left < right) { + int mid = (left + right) / 2; + if (isPossible(n, mid, quantities)) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } + + private boolean isPossible(int n, int min, int[] quantities) { + int idx = 0; + int remaining = quantities[idx]; + for (int i = 0; i < n; i++) { + if (remaining <= min) { + idx++; + if (idx == quantities.length) { + return true; + } else { + remaining = quantities[idx]; + } + } else { + remaining -= min; + } + } + return false; + } +} diff --git a/Medium/Minimum Add to Make Parentheses Valid.java b/Medium/Minimum Add to Make Parentheses Valid.java index f119bfe7..7fcfc88d 100644 --- a/Medium/Minimum Add to Make Parentheses Valid.java +++ b/Medium/Minimum Add to Make Parentheses Valid.java @@ -1,18 +1,14 @@ class Solution { - public int minAddToMakeValid(String s) { - int count = 0; - Stack stack = new Stack<>(); - for (char c : s.toCharArray()) { - if (c == '(') { - stack.push(c); - } else { - if (stack.isEmpty()) { - count++; - } else { - stack.pop(); + public int minAddToMakeValid(String s) { + int open = 0; + int count = 0; + for (char c : s.toCharArray()) { + open += c == '(' ? 1 : -1; + if (open < 0) { + count += Math.abs(open); + open = 0; + } } - } + return count + open; } - return count + stack.size(); - } } diff --git a/Medium/Minimum Number of Swaps to Make the String Balanced.java b/Medium/Minimum Number of Swaps to Make the String Balanced.java new file mode 100644 index 00000000..79935f13 --- /dev/null +++ b/Medium/Minimum Number of Swaps to Make the String Balanced.java @@ -0,0 +1,24 @@ +class Solution { + public int minSwaps(String s) { + char[] chars = s.toCharArray(); + Stack openBrackets = new Stack<>(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] == '[') { + openBrackets.push(i); + } + } + int open = 0; + int swaps = 0; + for (int i = 0; i < chars.length; i++) { + open += chars[i] == '[' ? 1 : -1; + if (open < 0) { + swaps++; + int endIdx = openBrackets.pop(); + chars[endIdx] = ']'; + chars[i] = '['; + open += 2; + } + } + return swaps; + } +} diff --git a/Medium/Minimum Operations to Exceed Threshold Value II.java b/Medium/Minimum Operations to Exceed Threshold Value II.java new file mode 100644 index 00000000..9a6c2b09 --- /dev/null +++ b/Medium/Minimum Operations to Exceed Threshold Value II.java @@ -0,0 +1,17 @@ +class Solution { + public int minOperations(int[] nums, int k) { + PriorityQueue pq = new PriorityQueue<>(); + for (int num : nums) { + pq.add((long) num); + } + int operations = 0; + while (pq.peek() < k) { + long smallest = pq.poll(); + long secondSmallest = pq.poll(); + long newValue = Math.min(smallest, secondSmallest) * 2 + Math.max(smallest, secondSmallest); + pq.add(newValue); + operations++; + } + return operations; + } +} diff --git a/Medium/Most Beautiful Item for Each Query.java b/Medium/Most Beautiful Item for Each Query.java new file mode 100644 index 00000000..5d2f75db --- /dev/null +++ b/Medium/Most Beautiful Item for Each Query.java @@ -0,0 +1,17 @@ +class Solution { + public int[] maximumBeauty(int[][] items, int[] queries) { + Arrays.sort(items, (a, b) -> (a[0] - b[0])); + TreeMap map = new TreeMap<>(); + map.put(0, 0); + int currMax = 0; + for (int[] item : items) { + currMax = Math.max(currMax, item[1]); + map.put(item[0], currMax); + } + int[] result = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + result[i] = map.floorEntry(queries[i]).getValue(); + } + return result; + } +} diff --git a/Medium/Neighboring Bitwise XOR.java b/Medium/Neighboring Bitwise XOR.java new file mode 100644 index 00000000..6e46025c --- /dev/null +++ b/Medium/Neighboring Bitwise XOR.java @@ -0,0 +1,16 @@ +class Solution { + public boolean doesValidArrayExist(int[] derived) { + int n = derived.length; + int[] original = new int[n + 1]; + for (int i = 0; i < derived.length; i++) { + original[i + 1] = derived[i] ^ original[i]; + } + boolean checkForZero = (original[0] == original[n]); + original[0] = 1; + for (int i = 0; i < n; i++) { + original[i + 1] = derived[i] ^ original[i]; + } + boolean checkForOne = (original[0] == original[n]); + return checkForZero || checkForOne; + } +} diff --git a/Medium/Number of Same-End Substrings.java b/Medium/Number of Same-End Substrings.java new file mode 100644 index 00000000..4003737d --- /dev/null +++ b/Medium/Number of Same-End Substrings.java @@ -0,0 +1,28 @@ +class Solution { + public int[] sameEndSubstringCount(String s, int[][] queries) { + int n = s.length(); + int[][] prefixSum = new int[26][n]; + for (int i = 0; i < n; i++) { + prefixSum[s.charAt(i) - 'a'][i]++; + } + for (int i = 0; i < 26; i++) { + for (int j = 1; j < n; j++) { + prefixSum[i][j] += prefixSum[i][j - 1]; + } + } + int[] result = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + int left = queries[i][0]; + int right = queries[i][1]; + int count = 0; + for (int c = 0; c < 26; c++) { + int leftFreq = left == 0 ? 0 : prefixSum[c][left - 1]; + int rightFreq = prefixSum[c][right]; + int freqInRange = rightFreq - leftFreq; + count += (freqInRange * (freqInRange + 1)) / 2; + } + result[i] = count; + } + return result; + } +} diff --git a/Medium/Remove All Occurrences of a Substring.java b/Medium/Remove All Occurrences of a Substring.java index 08fa1f78..e46ad3f2 100644 --- a/Medium/Remove All Occurrences of a Substring.java +++ b/Medium/Remove All Occurrences of a Substring.java @@ -1,12 +1,32 @@ class Solution { - public String removeOccurrences(String s, String part) { - while (true) { - int idx = s.indexOf(part); - if (idx == -1) { - break; - } - s = s.substring(0, idx) + s.substring(idx + part.length()); + public String removeOccurrences(String s, String part) { + Stack stack = new Stack<>(); + int n = s.length(); + int partLength = part.length(); + for (int i = 0; i < n; i++) { + stack.push(s.charAt(i)); + if (stack.size() >= partLength && check(stack, part, partLength)) { + for (int j = 0; j < partLength; j++) { + stack.pop(); + } + } + } + StringBuilder sb = new StringBuilder(); + while (!stack.isEmpty()) { + sb.append(stack.pop()); + } + return sb.reverse().toString(); + } + + private boolean check(Stack stack, String part, int partLength) { + Stack temp = new Stack<>(); + temp.addAll(stack); + for (int i = partLength - 1; i >= 0; i--) { + if (temp.isEmpty() || temp.peek() != part.charAt(i)) { + return false; + } + temp.pop(); + } + return true; } - return s; - } } diff --git a/Medium/Remove Sub-Folders from the Filesystem.java b/Medium/Remove Sub-Folders from the Filesystem.java index 2d91c97e..62f67bcd 100644 --- a/Medium/Remove Sub-Folders from the Filesystem.java +++ b/Medium/Remove Sub-Folders from the Filesystem.java @@ -1,24 +1,67 @@ class Solution { - public List removeSubfolders(String[] folder) { - Set set = new HashSet<>(); - Arrays.sort(folder, new Comparator(){ - public int compare(String s1, String s2) { - return s1.length() - s2.length(); - } - }); - for (String fl : folder) { - String[] files = fl.split("/"); - StringBuilder sb = new StringBuilder(); - for (int i = 1; i < files.length; i++) { - sb.append("/").append(files[i]); - if (set.contains(sb.toString())) { - break; + public List removeSubfolders(String[] folder) { + TrieNode root = new TrieNode(); + for (String file : folder) { + TrieNode curr = root; + String[] splits = file.split("/"); + for (int i = 1; i < splits.length; i++) { + Optional nextNode = curr.getChild(splits[i]); + if (nextNode.isEmpty()) { + TrieNode newNode = curr.addChild(splits[i]); + curr = newNode; + } else { + curr = nextNode.get(); + } + } + curr.markIsFolder(); + } + List result = new ArrayList<>(); + for (String file : folder) { + TrieNode curr = root; + String[] splits = file.split("/"); + boolean isSubfolder = false; + for (int i = 1; i < splits.length; i++) { + TrieNode nextNode = curr.getChild(splits[i]).get(); + if (nextNode.isFolder() && i != splits.length - 1) { + isSubfolder = true; + break; + } + curr = nextNode; + } + if (!isSubfolder) { + result.add(file); + } + } + return result; + } + + class TrieNode { + private boolean isFolder; + private Map children; + + public TrieNode() { + this.children = new HashMap<>(); + } + + public TrieNode addChild(String childKey) { + TrieNode node = new TrieNode(); + children.put(childKey, node); + return node; + } + + public Optional getChild(String childKey) { + if (!children.containsKey(childKey)) { + return Optional.empty(); + } + return Optional.of(children.get(childKey)); + } + + public void markIsFolder() { + isFolder = true; + } + + public boolean isFolder() { + return isFolder; } - } - if (sb.length() > 0) { - set.add(sb.toString()); - } } - return new ArrayList<>(set); - } } diff --git a/Medium/Resulting String After Adjacent Removals.java b/Medium/Resulting String After Adjacent Removals.java new file mode 100644 index 00000000..efa43bf6 --- /dev/null +++ b/Medium/Resulting String After Adjacent Removals.java @@ -0,0 +1,21 @@ +class Solution { + public String resultingString(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()) { + if (!stack.isEmpty() && isAdjacent(stack.peek(), c)) { + stack.pop(); + } else { + stack.push(c); + } + } + StringBuilder result = new StringBuilder(); + for (char c : stack) { + result.append(c); + } + return result.toString(); + } + + private static boolean isAdjacent(char first, char second) { + return Math.abs(first - second) == 1 || (first == 'a' && second == 'z') || (first == 'z' && second == 'a'); + } +} diff --git a/Medium/Sentence Similarity III.java b/Medium/Sentence Similarity III.java index e85bb024..506dc110 100644 --- a/Medium/Sentence Similarity III.java +++ b/Medium/Sentence Similarity III.java @@ -1,31 +1,26 @@ class Solution { - public boolean areSentencesSimilar(String sentence1, String sentence2) { - return isSimilar(sentence1.split(" "), sentence2.split(" ")) || isSimilar(sentence2.split(" "), - sentence1.split(" ")); - } - - private boolean isSimilar(String[] matcher, String[] target) { - int targetStartIdx = 0; - int matcherCurrentIdx = 0; - while (targetStartIdx < target.length && matcherCurrentIdx < matcher.length) { - if (!matcher[matcherCurrentIdx].equals(target[targetStartIdx])) { - break; - } - targetStartIdx++; - matcherCurrentIdx++; + public boolean areSentencesSimilar(String sentence1, String sentence2) { + int idxOneStart = 0; + int idxTwoStart = 0; + String[] wordsOne = sentence1.split("\\s+"); + String[] wordsTwo = sentence2.split("\\s+"); + while (idxOneStart < wordsOne.length && idxOneStart < wordsTwo.length && wordsOne[idxOneStart].equals(wordsTwo[idxTwoStart])) { + idxOneStart++; + idxTwoStart++; + } + boolean startFound = idxOneStart > 0; + if (idxOneStart == wordsOne.length && idxTwoStart == wordsTwo.length) { + return true; + } + int idxOneEnd = wordsOne.length - 1; + int idxTwoEnd = wordsTwo.length - 1; + while (idxOneEnd >= idxOneStart && idxTwoEnd >= idxTwoStart && wordsOne[idxOneEnd].equals(wordsTwo[idxTwoEnd])) { + idxOneEnd--; + idxTwoEnd--; + } + if (idxOneEnd != idxOneStart - 1 && idxTwoEnd != idxTwoStart - 1) { + return false; + } + return true; } - if (targetStartIdx == target.length) { - return true; - } - int targetEndIdx = target.length - 1; - matcherCurrentIdx = matcher.length - 1; - while (targetEndIdx >= targetStartIdx && matcherCurrentIdx >= 0) { - if (!matcher[matcherCurrentIdx].equals(target[targetEndIdx])) { - return false; - } - targetEndIdx--; - matcherCurrentIdx--; - } - return targetEndIdx == targetStartIdx - 1; - } } diff --git a/Medium/Separate Black and White Balls.java b/Medium/Separate Black and White Balls.java new file mode 100644 index 00000000..5fc4900f --- /dev/null +++ b/Medium/Separate Black and White Balls.java @@ -0,0 +1,13 @@ +class Solution { + public long minimumSteps(String s) { + int whitePos = 0; + long swaps = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '0') { + swaps += i - whitePos; + whitePos++; + } + } + return swaps; + } +} diff --git a/Medium/Shortest Subarray to be Removed to Make Array Sorted.java b/Medium/Shortest Subarray to be Removed to Make Array Sorted.java new file mode 100644 index 00000000..4ddb25e2 --- /dev/null +++ b/Medium/Shortest Subarray to be Removed to Make Array Sorted.java @@ -0,0 +1,18 @@ +class Solution { + public int findLengthOfShortestSubarray(int[] arr) { + int right = arr.length - 1; + while (right > 0 && arr[right] >= arr[right - 1]) { + right--; + } + int result = right; + int left = 0; + while (left < right && (left == 0 || arr[left - 1] <= arr[left])) { + while (right < arr.length && arr[left] > arr[right]) { + right++; + } + result = Math.min(result, right - left - 1); + left++; + } + return result; + } +} diff --git a/Medium/Smallest Common Region.java b/Medium/Smallest Common Region.java new file mode 100644 index 00000000..4d8ce894 --- /dev/null +++ b/Medium/Smallest Common Region.java @@ -0,0 +1,32 @@ +class Solution { + public String findSmallestRegion(List> regions, String region1, String region2) { + Map regionToParentMap = new HashMap<>(); + for (List region : regions) { + String parent = region.getFirst(); + for (int i = 1; i < region.size(); i++) { + regionToParentMap.put(region.get(i), parent); + } + } + List pathOne = trace(region1, regionToParentMap); + List pathTwo = trace(region2, regionToParentMap); + int idxOne = 0; + int idxTwo = 0; + while (idxOne < pathOne.size() && idxTwo < pathTwo.size() && pathOne.get(idxOne).equals(pathTwo.get(idxTwo))) { + idxOne++; + idxTwo++; + } + return pathOne.get(idxOne - 1); + } + + private List trace(String region, Map regionToParentMap) { + List path = new ArrayList<>(); + path.add(region); + while (regionToParentMap.containsKey(region)) { + String parent = regionToParentMap.get(region); + path.add(parent); + region = parent; + } + Collections.reverse(path); + return path; + } +} diff --git a/Medium/Split a String Into the Max Number of Unique Substrings.java b/Medium/Split a String Into the Max Number of Unique Substrings.java new file mode 100644 index 00000000..3e418df7 --- /dev/null +++ b/Medium/Split a String Into the Max Number of Unique Substrings.java @@ -0,0 +1,21 @@ +class Solution { + public int maxUniqueSplit(String s) { + Set seen = new HashSet<>(); + return backtrack(s, 0, seen); + } + + private int backtrack(String s, int idx, Set seen) { + if (idx == s.length()) { + return 0; + } + int count = 0; + for (int end = idx + 1; end <= s.length(); end++) { + String substring = s.substring(idx, end); + if (seen.add(substring)) { + count = Math.max(count, 1 + backtrack(s, end, seen)); + seen.remove(substring); + } + } + return count; + } +} diff --git a/Medium/String Compression III.java b/Medium/String Compression III.java new file mode 100644 index 00000000..03a6737c --- /dev/null +++ b/Medium/String Compression III.java @@ -0,0 +1,16 @@ +class Solution { + public String compressedString(String word) { + StringBuilder sb = new StringBuilder(); + int idx = 0; + while (idx < word.length()) { + char c = word.charAt(idx); + int count = 0; + while (idx < word.length() && word.charAt(idx) == c && count < 9) { + idx++; + count++; + } + sb.append(count).append(c); + } + return sb.toString(); + } +} diff --git a/Medium/Take K of Each Character From Left and Right.java b/Medium/Take K of Each Character From Left and Right.java new file mode 100644 index 00000000..4b878ce0 --- /dev/null +++ b/Medium/Take K of Each Character From Left and Right.java @@ -0,0 +1,27 @@ +class Solution { + public int takeCharacters(String s, int k) { + int[] counter = new int[3]; + int n = s.length(); + for (char c : s.toCharArray()) { + counter[c - 'a']++; + } + for (int i = 0; i < 3; i++) { + if (counter[i] < k) { + return -1; + } + } + int[] window = new int[3]; + int left = 0; + int maxWindow = 0; + for (int right = 0; right < n; right++) { + window[s.charAt(right) - 'a']++; + while (left <= right && + (counter[0] - window[0] < k || counter[1] - window[1] < k || counter[2] - window[2] < k)) { + window[s.charAt(left) - 'a']--; + left++; + } + maxWindow = Math.max(maxWindow, right - left + 1); + } + return n - maxWindow; + } +} diff --git a/Medium/The Number of the Smallest Unoccupied Chair.java b/Medium/The Number of the Smallest Unoccupied Chair.java new file mode 100644 index 00000000..6bd41ad2 --- /dev/null +++ b/Medium/The Number of the Smallest Unoccupied Chair.java @@ -0,0 +1,35 @@ +class Solution { + public int smallestChair(int[][] times, int targetFriend) { + PriorityQueue pq = new PriorityQueue<>((o1, o2) -> { + int c = o1[0] - o2[0]; + if (c == 0) { + return o1[1] - o2[1]; + } + return c; + }); + for (int i = 0; i < times.length; i++) { + pq.add(new int[]{times[i][0], times[i][1], i}); + } + PriorityQueue occupiedChairs = new PriorityQueue<>(Comparator.comparingInt(o -> o[0])); + PriorityQueue emptyChairs = new PriorityQueue<>(); + int currChair = 0; + while (!pq.isEmpty()) { + int[] time = pq.poll(); + while (!occupiedChairs.isEmpty() && occupiedChairs.peek()[0] <= time[0]) { + int[] chair = occupiedChairs.poll(); + emptyChairs.add(chair[1]); + } + if (time[2] == targetFriend) { + return emptyChairs.isEmpty() ? currChair : emptyChairs.poll(); + } + if (emptyChairs.isEmpty()) { + occupiedChairs.add(new int[]{time[1], currChair}); + currChair++; + } else { + int chair = emptyChairs.poll(); + occupiedChairs.add(new int[]{time[1], chair}); + } + } + return -1; + } +} diff --git a/Medium/The k-th Lexicographical String of All Happy Strings of Length n.java b/Medium/The k-th Lexicographical String of All Happy Strings of Length n.java new file mode 100644 index 00000000..413b67d5 --- /dev/null +++ b/Medium/The k-th Lexicographical String of All Happy Strings of Length n.java @@ -0,0 +1,28 @@ +class Solution { + private static final char[] CHARS = {'a', 'b', 'c'}; + + public String getHappyString(int n, int k) { + Set set = new HashSet<>(); + backtrack(set, new StringBuilder(), n); + if (set.size() < k) { + return ""; + } + List list = new ArrayList<>(set); + Collections.sort(list); + return list.get(k - 1); + } + + private void backtrack(Set set, StringBuilder sb, int n) { + if (sb.length() == n) { + set.add(sb.toString()); + return; + } + for (char c : CHARS) { + if (sb.isEmpty() || sb.charAt(sb.length() - 1) != c) { + sb.append(c); + backtrack(set, sb, n); + sb.deleteCharAt(sb.length() - 1); + } + } + } +} diff --git a/Medium/Total Characters in String After Transformations I.java b/Medium/Total Characters in String After Transformations I.java new file mode 100644 index 00000000..3751ab7e --- /dev/null +++ b/Medium/Total Characters in String After Transformations I.java @@ -0,0 +1,25 @@ +class Solution { + + private static final int MOD = 1000_0000_07; + + public int lengthAfterTransformations(String s, int t) { + int[] frequency = new int[26]; + for (char c : s.toCharArray()) { + frequency[c - 'a']++; + } + for (int round = 0; round < t; round++) { + int[] next = new int[26]; + next[0] = frequency[25]; // Transformation from 'z' + next[1] = (frequency[25] + frequency[0]) % MOD; // Transformation from either 'z' or 'a' + for (int i = 2; i < 26; i++) { + next[i] = frequency[i - 1]; // Transformation for next character + } + frequency = next; + } + int result = 0; + for (int i = 0; i < 26; i++) { + result = (result + frequency[i]) % MOD; + } + return result; + } +} diff --git a/Medium/Using a Robot to Print the Lexicographically Smallest String.java b/Medium/Using a Robot to Print the Lexicographically Smallest String.java new file mode 100644 index 00000000..8d9c2064 --- /dev/null +++ b/Medium/Using a Robot to Print the Lexicographically Smallest String.java @@ -0,0 +1,31 @@ +class Solution { + public String robotWithString(String s) { + int[] counter = new int[26]; + for (char c : s.toCharArray()) { + counter[c - 'a']++; + } + Stack stack = new Stack<>(); + StringBuilder sb = new StringBuilder(); + for (char c : s.toCharArray()) { + stack.push(c); + counter[c - 'a']--; + while (!stack.isEmpty() && isSmallest(stack.peek(), counter)) { + sb.append(stack.pop()); + } + } + while (!stack.isEmpty()) { + sb.append(stack.pop()); + } + return sb.toString(); + } + + private boolean isSmallest(char c, int[] counter) { + int limit = c - 'a'; + for (int i = 0; i < limit; i++) { + if (counter[i] > 0) { + return false; + } + } + return true; + } +} diff --git a/Medium/XOR Queries of a Subarray.java b/Medium/XOR Queries of a Subarray.java new file mode 100644 index 00000000..0bdfc9ca --- /dev/null +++ b/Medium/XOR Queries of a Subarray.java @@ -0,0 +1,24 @@ +class Solution { + public int[] xorQueries(int[] arr, int[][] queries) { + int n = arr.length; + int[] prefixXors = new int[n]; + int xor = 0; + for (int i = 0; i < n; i++) { + xor = xor ^ arr[i]; + prefixXors[i] = xor; + } + n = queries.length; + int[] result = new int[n]; + for (int i = 0; i < n; i++) { + int[] query = queries[i]; + int left = query[0]; + int right = query[1]; + int xorResult = prefixXors[right]; + if (left != 0) { + xorResult = xorResult ^ prefixXors[left - 1]; + } + result[i] = xorResult; + } + return result; + } +} diff --git a/Medium/Zero Array Transformation I.java b/Medium/Zero Array Transformation I.java new file mode 100644 index 00000000..2b9ab602 --- /dev/null +++ b/Medium/Zero Array Transformation I.java @@ -0,0 +1,24 @@ +class Solution { + public boolean isZeroArray(int[] nums, int[][] queries) { + int n = nums.length; + int[] diff = new int[n + 1]; + for (int[] query : queries) { + int left = query[0]; + int right = query[1]; + diff[left] += 1; + diff[right + 1] -= 1; + } + int[] operation = new int[n + 1]; + int currOperation = 0; + for (int i = 0; i < n + 1; i++) { + currOperation += diff[i]; + operation[i] = currOperation; + } + for (int i = 0; i < n; i++) { + if (operation[i] < nums[i]) { + return false; + } + } + return true; + } +} diff --git a/README.md b/README.md index a90fb07e..617cd951 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Solutions to Leetcode problems in Java -## [Current Leetcode profile: Solved 1600+ Problems](https://leetcode.com/varunsjsu/) +## [Current Leetcode profile: Solved 1700+ Problems](https://leetcode.com/varunsjsu/) ## [Previous Leetcode profile: Solved 759 Problems](https://leetcode.com/varunu28/) Problem Category | Count