diff --git a/README.md b/README.md index e01a6c6..76c09c0 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,11 @@ The listing below is sorted based on LeetCode #. If you are interested to see my | 1491 | [Average Salary Excluding the Minimum and Maximum Salary](/problems/average-salary-excluding-the-minimum-and-maximum-salary) | Easy | Array, Sort | | 1492 | [The kth Factor of n](/problems/the-kth-factor-of-n) | Medium | Math | | 1493 | [Longest Subarray of 1's After Deleting One Element](/problems/longest-subarray-of-1s-after-deleting-one-element) | Medium | Array | +| 1572 | [Matrix Diagonal Sum](/problems/matrix-diagonal-sum) | Easy | Array | +| 1574 | [Shortest Subarray to be Removed to Make Array Sorted](/problems/shortest-subarray-to-be-removed-to-make-array-sorted) | Medium | Array, Binary Search | +| 1576 | [Replace All ?'s to Avoid Consecutive Repeating Characters](/problems/replace-all-s-to-avoid-consecutive-repeating-characters) | Easy | String | +| 1577 | [Number of Ways Where Square of Number Is Equal to Product of Two Numbers](/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers) | Medium | Hash Table, Math | +| 1578 | [Minimum Deletion Cost to Avoid Repeating Letters](/problems/minimum-deletion-cost-to-avoid-repeating-letters) | Medium | Greedy | ## Questions / Issues diff --git a/package-lock.json b/package-lock.json index b4bb764..ca4ef44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "leetcode", - "version": "1.28.1", + "version": "1.29.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5902ea4..563a247 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "leetcode", - "version": "1.28.1", + "version": "1.29.0", "description": "My solutions for LeetCode problems.", "main": "index.js", "scripts": { diff --git a/problems/matrix-diagonal-sum/README.md b/problems/matrix-diagonal-sum/README.md new file mode 100644 index 0000000..f369715 --- /dev/null +++ b/problems/matrix-diagonal-sum/README.md @@ -0,0 +1,49 @@ +# Matrix Diagonal Sum + +LeetCode #: [1572](https://leetcode.com/problems/matrix-diagonal-sum/) + +Difficulty: Easy + +Topics: Array. + +## Problem + +Given a square matrix `mat`, return the sum of the matrix diagonals. + +Only include the sum of all the elements on the primary diagonal and all the elements on the secondary diagonal that are not part of the primary diagonal. + +Example 1: + +![Example 1](https://assets.leetcode.com/uploads/2020/08/14/sample_1911.png) + +```text +Input: mat = [[1,2,3], + [4,5,6], + [7,8,9]] +Output: 25 +Explanation: Diagonals sum: 1 + 5 + 9 + 3 + 7 = 25 +Notice that element mat[1][1] = 5 is counted only once. +``` + +Example 2: + +```text +Input: mat = [[1,1,1,1], + [1,1,1,1], + [1,1,1,1], + [1,1,1,1]] +Output: 8 +``` + +Example 3: + +```text +Input: mat = [[5]] +Output: 5 +``` + +Constraints: + +- `n == mat.length == mat[i].length` +- `1 <= n <= 100` +- `1 <= mat[i][j] <= 100` diff --git a/problems/matrix-diagonal-sum/diagonalSum.js b/problems/matrix-diagonal-sum/diagonalSum.js new file mode 100644 index 0000000..bc58fe3 --- /dev/null +++ b/problems/matrix-diagonal-sum/diagonalSum.js @@ -0,0 +1,21 @@ +/** + * @param {number[][]} mat + * @return {number} + */ +const diagonalSum = (mat) => { + const length = mat.length + let sum = 0 + + for (let i = 0; i < length; i++) { + sum += mat[i][i] + mat[i][length - 1 - i] + } + + if (length % 2 === 1) { + const middleIndex = (length - 1) / 2 + sum -= mat[middleIndex][middleIndex] + } + + return sum +} + +module.exports = diagonalSum diff --git a/problems/matrix-diagonal-sum/diagonalSum.test.js b/problems/matrix-diagonal-sum/diagonalSum.test.js new file mode 100644 index 0000000..f02529e --- /dev/null +++ b/problems/matrix-diagonal-sum/diagonalSum.test.js @@ -0,0 +1,34 @@ +const diagonalSum = require('./diagonalSum') + +test('Example 1', () => { + const mat = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] + ] + + const result = diagonalSum(mat) + + expect(result).toBe(25) +}) + +test('Example 2', () => { + const mat = [ + [1, 1, 1, 1], + [1, 1, 1, 1], + [1, 1, 1, 1], + [1, 1, 1, 1] + ] + + const result = diagonalSum(mat) + + expect(result).toBe(8) +}) + +test('Example 3', () => { + const mat = [[5]] + + const result = diagonalSum(mat) + + expect(result).toBe(5) +}) diff --git a/problems/minimum-deletion-cost-to-avoid-repeating-letters/README.md b/problems/minimum-deletion-cost-to-avoid-repeating-letters/README.md new file mode 100644 index 0000000..10769be --- /dev/null +++ b/problems/minimum-deletion-cost-to-avoid-repeating-letters/README.md @@ -0,0 +1,46 @@ +# Minimum Deletion Cost to Avoid Repeating Letters + +LeetCode #: [1578](https://leetcode.com/problems/minimum-deletion-cost-to-avoid-repeating-letters/) + +Difficulty: Medium + +Topics: Greedy. + +## Problem + +Given a string `s` and an array of integers `cost` where `cost[i]` is the cost of deleting the character `i` in `s`. + +Return the minimum cost of deletions such that there are no two identical letters next to each other. + +Notice that you will delete the chosen characters at the same time, in other words, after deleting a character, the costs of deleting other characters will not change. + +Example 1: + +```text +Input: s = "abaac", cost = [1,2,3,4,5] +Output: 3 +Explanation: Delete the letter "a" with cost 3 to get "abac" (String without two identical letters next to each other). +``` + +Example 2: + +```text +Input: s = "abc", cost = [1,2,3] +Output: 0 +Explanation: You don't need to delete any character because there are no identical letters next to each other. +``` + +Example 3: + +```text +Input: s = "aabaa", cost = [1,2,3,4,1] +Output: 2 +Explanation: Delete the first and the last character, getting the string ("aba"). +``` + +Constraints: + +- `s.length == cost.length` +- `1 <= s.length, cost.length <= 10^5` +- `1 <= cost[i] <= 10^4` +- `s` contains only lowercase English letters. diff --git a/problems/minimum-deletion-cost-to-avoid-repeating-letters/minCost.js b/problems/minimum-deletion-cost-to-avoid-repeating-letters/minCost.js new file mode 100644 index 0000000..9475c07 --- /dev/null +++ b/problems/minimum-deletion-cost-to-avoid-repeating-letters/minCost.js @@ -0,0 +1,27 @@ +/** + * @param {string} s + * @param {number[]} cost + * @return {number} + */ +const minCost = function (s, cost) { + let result = 0 + let max = cost[0] + let sum = cost[0] + + for (let i = 1; i < s.length; i++) { + if (s[i] !== s[i - 1]) { + result += sum - max + sum = cost[i] + max = cost[i] + } else { + sum += cost[i] + max = Math.max(max, cost[i]) + } + } + + result += sum - max + + return result +} + +module.exports = minCost diff --git a/problems/minimum-deletion-cost-to-avoid-repeating-letters/minCost.test.js b/problems/minimum-deletion-cost-to-avoid-repeating-letters/minCost.test.js new file mode 100644 index 0000000..122ce22 --- /dev/null +++ b/problems/minimum-deletion-cost-to-avoid-repeating-letters/minCost.test.js @@ -0,0 +1,37 @@ +const minCost = require('./minCost') + +test('Example 1', () => { + const s = 'abaac' + const cost = [1, 2, 3, 4, 5] + + const result = minCost(s, cost) + + expect(result).toBe(3) +}) + +test('Example 2', () => { + const s = 'abc' + const cost = [1, 2, 3] + + const result = minCost(s, cost) + + expect(result).toBe(0) +}) + +test('Example 3', () => { + const s = 'aabaa' + const cost = [1, 2, 3, 4, 1] + + const result = minCost(s, cost) + + expect(result).toBe(2) +}) + +test('caaac', () => { + const s = 'caaac' + const cost = [0, 2, 4, 3, 0] + + const result = minCost(s, cost) + + expect(result).toBe(5) +}) diff --git a/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/README.md b/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/README.md new file mode 100644 index 0000000..b790a2e --- /dev/null +++ b/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/README.md @@ -0,0 +1,55 @@ +# Number of Ways Where Square of Number Is Equal to Product of Two Numbers + +LeetCode #: [1577](https://leetcode.com/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/) + +Difficulty: Medium + +Topics: Hash Table, Math. + +## Problem + +Given two arrays of integers `nums1` and `nums2`, return the number of triplets formed (type 1 and type 2) under the following rules: + +- Type 1: Triplet (i, j, k) if `nums1[i]2 == nums2[j] * nums2[k]` where `0 <= i < nums1.length` and `0 <= j < k < nums2.length`. +- Type 2: Triplet (i, j, k) if `nums2[i]2 == nums1[j] * nums1[k]` where `0 <= i < nums2.length` and `0 <= j < k < nums1.length`. + +Example 1: + +```text +Input: nums1 = [7,4], nums2 = [5,2,8,9] +Output: 1 +Explanation: Type 1: (1,1,2), nums1[1]^2 = nums2[1] * nums2[2]. (4^2 = 2 * 8). +``` + +Example 2: + +```text +Input: nums1 = [1,1], nums2 = [1,1,1] +Output: 9 +Explanation: All Triplets are valid, because 1^2 = 1 * 1. +Type 1: (0,0,1), (0,0,2), (0,1,2), (1,0,1), (1,0,2), (1,1,2). nums1[i]^2 = nums2[j] * nums2[k]. +Type 2: (0,0,1), (1,0,1), (2,0,1). nums2[i]^2 = nums1[j] * nums1[k]. +``` + +Example 3: + +```text +Input: nums1 = [7,7,8,3], nums2 = [1,2,9,7] +Output: 2 +Explanation: There are 2 valid triplets. +Type 1: (3,0,2). nums1[3]^2 = nums2[0] * nums2[2]. +Type 2: (3,0,1). nums2[3]^2 = nums1[0] * nums1[1]. +``` + +Example 4: + +```text +Input: nums1 = [4,7,9,11,23], nums2 = [3,5,1024,12,18] +Output: 0 +Explanation: There are no valid triplets. +``` + +Constraints: + +- `1 <= nums1.length, nums2.length <= 1000` +- `1 <= nums1[i], nums2[i] <= 10^5` diff --git a/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/numTriplets.js b/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/numTriplets.js new file mode 100644 index 0000000..c0be511 --- /dev/null +++ b/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/numTriplets.js @@ -0,0 +1,40 @@ +const sortBy = require('lodash/sortBy') +const sortedIndexOf = require('lodash/sortedIndexOf') +const sortedLastIndexOf = require('lodash/sortedLastIndexOf') + +const getNum = (sorted1, sorted2) => { + let result = 0 + + for (const num1 of sorted1) { + const squared = num1 * num1 + + for (let aIndex = 0; aIndex < sorted2.length; aIndex++) { + const a = sorted2[aIndex] + const b = squared / a + + const bIndex = sortedIndexOf(sorted2, b) + const bLastIndex = sortedLastIndexOf(sorted2, b) + + if (aIndex <= bLastIndex) { + const count = (bLastIndex - Math.max(aIndex + 1, bIndex) + 1) + result += count + } + } + } + + return result +} + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const numTriplets = function (nums1, nums2) { + const sorted1 = sortBy(nums1) + const sorted2 = sortBy(nums2) + + return getNum(sorted1, sorted2) + getNum(sorted2, sorted1) +} + +module.exports = numTriplets diff --git a/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/numTriplets.test.js b/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/numTriplets.test.js new file mode 100644 index 0000000..5fadec4 --- /dev/null +++ b/problems/number-of-ways-where-square-of-number-is-equal-to-product-of-two-numbers/numTriplets.test.js @@ -0,0 +1,37 @@ +const numTriplets = require('./numTriplets') + +test('Example 1', () => { + const nums1 = [7, 4] + const nums2 = [5, 2, 8, 9] + + const result = numTriplets(nums1, nums2) + + expect(result).toBe(1) +}) + +test('Example 2', () => { + const nums1 = [1, 1] + const nums2 = [1, 1, 1] + + const result = numTriplets(nums1, nums2) + + expect(result).toBe(9) +}) + +test('Example 3', () => { + const nums1 = [7, 7, 8, 3] + const nums2 = [1, 2, 9, 7] + + const result = numTriplets(nums1, nums2) + + expect(result).toBe(2) +}) + +test('Example 4', () => { + const nums1 = [4, 7, 9, 11, 23] + const nums2 = [3, 5, 1024, 12, 18] + + const result = numTriplets(nums1, nums2) + + expect(result).toBe(0) +}) diff --git a/problems/replace-all-s-to-avoid-consecutive-repeating-characters/README.md b/problems/replace-all-s-to-avoid-consecutive-repeating-characters/README.md new file mode 100644 index 0000000..b2af1ef --- /dev/null +++ b/problems/replace-all-s-to-avoid-consecutive-repeating-characters/README.md @@ -0,0 +1,50 @@ +# Replace All ?'s to Avoid Consecutive Repeating Characters + +LeetCode #: [1576](https://leetcode.com/problems/replace-all-s-to-avoid-consecutive-repeating-characters/) + +Difficulty: Easy + +Topics: String. + +## Problem + +Given a string `s` containing only lower case English letters and the '?' character, convert all the '?' characters into lower case letters such that the final string does not contain any consecutive repeating characters. You cannot modify the non '?' characters. + +It is guaranteed that there are no consecutive repeating characters in the given string except for '?'. + +Return the final string after all the conversions (possibly zero) have been made. If there is more than one solution, return any of them. It can be shown that an answer is always possible with the given constraints. + +Example 1: + +```text +Input: s = "?zs" +Output: "azs" +Explanation: There are 25 solutions for this problem. From "azs" to "yzs", all are valid. Only "z" is an invalid modification as the string will consist of consecutive repeating characters in "zzs". +``` + +Example 2: + +```text +Input: s = "ubv?w" +Output: "ubvaw" +Explanation: There are 24 solutions for this problem. Only "v" and "w" are invalid modifications as the strings will consist of consecutive repeating characters in "ubvvw" and "ubvww". +``` + +Example 3: + +```text +Input: s = "j?qg??b" +Output: "jaqgacb" +``` + +Example 4: + +```text +Input: s = "??yw?ipkj?" +Output: "acywaipkja" +``` + +Constraints: + +- `1 <= s.length <= 100` +- `s` contains only lower case English letters and `'?'`. diff --git a/problems/replace-all-s-to-avoid-consecutive-repeating-characters/modifyString.js b/problems/replace-all-s-to-avoid-consecutive-repeating-characters/modifyString.js new file mode 100644 index 0000000..f99b47d --- /dev/null +++ b/problems/replace-all-s-to-avoid-consecutive-repeating-characters/modifyString.js @@ -0,0 +1,31 @@ +const convertChar = (arr, i) => { + if (arr[i] !== '?') { + return arr[i] + } + + if (arr[i - 1] !== 'a' && arr[i + 1] !== 'a') { + return 'a' + } + + if (arr[i - 1] !== 'b' && arr[i + 1] !== 'b') { + return 'b' + } + + return 'c' +} + +/** + * @param {string} s + * @return {string} + */ +const modifyString = function (s) { + const arr = s.split('') + + for (let i = 0; i < s.length; i++) { + arr[i] = convertChar(arr, i) + } + + return arr.join('') +} + +module.exports = modifyString diff --git a/problems/replace-all-s-to-avoid-consecutive-repeating-characters/modifyString.test.js b/problems/replace-all-s-to-avoid-consecutive-repeating-characters/modifyString.test.js new file mode 100644 index 0000000..e62af01 --- /dev/null +++ b/problems/replace-all-s-to-avoid-consecutive-repeating-characters/modifyString.test.js @@ -0,0 +1,33 @@ +const modifyString = require('./modifyString') + +test('Example 1', () => { + const s = '?zs' + + const result = modifyString(s) + + expect(result).toBe('azs') +}) + +test('Example 2', () => { + const s = 'ubv?w' + + const result = modifyString(s) + + expect(result).toBe('ubvaw') +}) + +test('Example 3', () => { + const s = 'j?qg??b' + + const result = modifyString(s) + + expect(result).toBe('jaqgacb') +}) + +test('Example 4', () => { + const s = '??yw?ipkj?' + + const result = modifyString(s) + + expect(result).toBe('abywaipkja') +}) diff --git a/problems/shortest-subarray-to-be-removed-to-make-array-sorted/README.md b/problems/shortest-subarray-to-be-removed-to-make-array-sorted/README.md new file mode 100644 index 0000000..10b4659 --- /dev/null +++ b/problems/shortest-subarray-to-be-removed-to-make-array-sorted/README.md @@ -0,0 +1,56 @@ +# Shortest Subarray to be Removed to Make Array Sorted + +LeetCode #: [1574](https://leetcode.com/problems/shortest-subarray-to-be-removed-to-make-array-sorted/) + +Difficulty: Medium + +Topics: Array, Binary Search. + +## Problem + +Given an integer array `arr`, remove a subarray (can be empty) from `arr` such that the remaining elements in `arr` are non-decreasing. + +A subarray is a contiguous subsequence of the array. + +Return the length of the shortest subarray to remove. + +Example 1: + +```text +Input: arr = [1,2,3,10,4,2,3,5] +Output: 3 +Explanation: The shortest subarray we can remove is [10,4,2] of length 3. The remaining elements after that will be [1,2,3,3,5] which are sorted. +Another correct solution is to remove the subarray [3,10,4]. +``` + +Example 2: + +```text +Input: arr = [5,4,3,2,1] +Output: 4 +Explanation: Since the array is strictly decreasing, we can only keep a single element. Therefore we need to remove a subarray of length 4, either [5,4,3,2] or [4,3,2,1]. +``` + +Example 3: + +```text +Input: arr = [1,2,3] +Output: 0 +Explanation: The array is already non-decreasing. We do not need to remove any elements. +``` + +Example 4: + +```text +Input: arr = [1] +Output: 0 +``` + +Constraints: + +- `1 <= arr.length <= 10^5` +- `0 <= arr[i] <= 10^9` + +## Solution Explanation + +Reference: [C++ O(N) Sliding window; Explanation with Illustrations](https://leetcode.com/problems/shortest-subarray-to-be-removed-to-make-array-sorted/discuss/830480/C%2B%2B-O(N)-Sliding-window-Explanation-with-Illustrations) by [lzl124631x](https://leetcode.com/lzl124631x) diff --git a/problems/shortest-subarray-to-be-removed-to-make-array-sorted/findLengthOfShortestSubarray.js b/problems/shortest-subarray-to-be-removed-to-make-array-sorted/findLengthOfShortestSubarray.js new file mode 100644 index 0000000..3871275 --- /dev/null +++ b/problems/shortest-subarray-to-be-removed-to-make-array-sorted/findLengthOfShortestSubarray.js @@ -0,0 +1,38 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const findLengthOfShortestSubarray = function (arr) { + const length = arr.length + let left = 0 + let right = length - 1 + + while (left + 1 < length && arr[left] <= arr[left + 1]) { + left++ + } + + if (left === length - 1) { + return 0 + } + + while (right > left && arr[right - 1] <= arr[right]) { + right-- + } + + let result = Math.min(length - 1 - left, right) + let i = 0 + let j = right + + while (i <= left && j < length) { + if (arr[i] <= arr[j]) { + result = Math.min(result, j - 1 - i) + i++ + } else { + j++ + } + } + + return result +} + +module.exports = findLengthOfShortestSubarray diff --git a/problems/shortest-subarray-to-be-removed-to-make-array-sorted/findLengthOfShortestSubarray.test.js b/problems/shortest-subarray-to-be-removed-to-make-array-sorted/findLengthOfShortestSubarray.test.js new file mode 100644 index 0000000..7e5ff60 --- /dev/null +++ b/problems/shortest-subarray-to-be-removed-to-make-array-sorted/findLengthOfShortestSubarray.test.js @@ -0,0 +1,73 @@ +const findLengthOfShortestSubarray = require('./findLengthOfShortestSubarray') + +test('Example 1', () => { + const arr = [1, 2, 3, 10, 4, 2, 3, 5] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(3) +}) + +test('Example 2', () => { + const arr = [5, 4, 3, 2, 1] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(4) +}) + +test('Example 3', () => { + const arr = [1, 2, 3] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(0) +}) + +test('Example 4', () => { + const arr = [1] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(0) +}) + +test('135792468, remove 2468', () => { + const arr = [1, 3, 5, 7, 9, 2, 4, 6, 8] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(4) +}) + +test('1324, remove 3 or 2', () => { + const arr = [1, 3, 2, 4] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(1) +}) + +test('remove tail', () => { + const arr = [10, 13, 17, 21, 15, 15, 9, 17, 22, 22, 13] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(7) +}) + +test('remove head', () => { + const arr = [16, 10, 0, 3, 22, 1, 14, 7, 1, 12, 15] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(8) +}) + +test('[1, 2, 3, 10, 0, 7, 8, 9] should return 2 (remove 10 and 0)', () => { + const arr = [1, 2, 3, 10, 0, 7, 8, 9] + + const result = findLengthOfShortestSubarray(arr) + + expect(result).toBe(2) +})