diff --git a/src/main/ts/com_github_leetcode/node.ts b/src/main/ts/com_github_leetcode/node.ts index 773e6db..1230145 100644 --- a/src/main/ts/com_github_leetcode/node.ts +++ b/src/main/ts/com_github_leetcode/node.ts @@ -10,7 +10,7 @@ class Node { toString(): string { const result: string[] = [] - let curr: Node | null = this + let curr: Node | null = this //NOSONAR while (curr !== null) { const result2: string[] = [] result2.push(String(curr.val)) @@ -18,7 +18,7 @@ class Node { result2.push('null') } else { let randomIndex = 0 - let curr2: Node | null = this + let curr2: Node | null = this //NOSONAR while (curr2?.next !== null && curr2 !== curr.random) { randomIndex++ curr2 = curr2.next diff --git a/src/main/ts/g0001_0100/s0002_add_two_numbers/solution.ts b/src/main/ts/g0001_0100/s0002_add_two_numbers/solution.ts index ae37aea..06d0a56 100644 --- a/src/main/ts/g0001_0100/s0002_add_two_numbers/solution.ts +++ b/src/main/ts/g0001_0100/s0002_add_two_numbers/solution.ts @@ -23,8 +23,8 @@ function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | nul let curr: ListNode | null = dummyHead let carry: number = 0 while (p !== null || q !== null) { - const x: number = p !== null ? p.val : 0 - const y: number = q !== null ? q.val : 0 + const x: number = p === null ? 0 : p.val + const y: number = q === null ? 0: q.val const sum: number = carry + x + y carry = Math.floor(sum / 10) curr.next = new ListNode(sum % 10) diff --git a/src/main/ts/g0001_0100/s0003_longest_substring_without_repeating_characters/solution.ts b/src/main/ts/g0001_0100/s0003_longest_substring_without_repeating_characters/solution.ts index c5514eb..71bffed 100644 --- a/src/main/ts/g0001_0100/s0003_longest_substring_without_repeating_characters/solution.ts +++ b/src/main/ts/g0001_0100/s0003_longest_substring_without_repeating_characters/solution.ts @@ -10,7 +10,7 @@ function lengthOfLongestSubstring(s: string): number { let start: number = 0 for (let i = 0; i < s.length; i++) { const cur: string = s.charAt(i) - const charCode: number = cur.charCodeAt(0) + const charCode: number = cur.codePointAt(0)! if (lastIndices[charCode] < start) { lastIndices[charCode] = i curLen++ diff --git a/src/main/ts/g0001_0100/s0008_string_to_integer_atoi/solution.ts b/src/main/ts/g0001_0100/s0008_string_to_integer_atoi/solution.ts index fd80851..17acbb1 100644 --- a/src/main/ts/g0001_0100/s0008_string_to_integer_atoi/solution.ts +++ b/src/main/ts/g0001_0100/s0008_string_to_integer_atoi/solution.ts @@ -3,7 +3,7 @@ function myAtoi(s: string): number { s = s.trim() if (s.length === 0) return 0 - let result = parseInt(s) || 0 + let result = Number.parseInt(s) || 0 if (-1 * 2 ** 31 <= result && result <= 2 ** 31 - 1) { return result } else if (result < -1 * 2 ** 31) { diff --git a/src/main/ts/g0001_0100/s0014_longest_common_prefix/solution.ts b/src/main/ts/g0001_0100/s0014_longest_common_prefix/solution.ts index 4747f5b..40374ac 100644 --- a/src/main/ts/g0001_0100/s0014_longest_common_prefix/solution.ts +++ b/src/main/ts/g0001_0100/s0014_longest_common_prefix/solution.ts @@ -17,10 +17,10 @@ function longestCommonPrefix(strs: string[]): string { temp = temp.substring(0, strs[i].length) } cur = strs[i].substring(0, temp.length) - if (cur !== temp) { - temp = temp.substring(0, temp.length - 1) - } else { + if (cur === temp) { i++ + } else { + temp = temp.substring(0, temp.length - 1) } } return temp diff --git a/src/main/ts/g0001_0100/s0017_letter_combinations_of_a_phone_number/solution.ts b/src/main/ts/g0001_0100/s0017_letter_combinations_of_a_phone_number/solution.ts index 7bf7035..8b53f44 100644 --- a/src/main/ts/g0001_0100/s0017_letter_combinations_of_a_phone_number/solution.ts +++ b/src/main/ts/g0001_0100/s0017_letter_combinations_of_a_phone_number/solution.ts @@ -20,7 +20,7 @@ function findCombinations(start: number, nums: string, letters: string[], curr: return } for (let i = start; i < nums.length; i++) { - const n = parseInt(nums.charAt(i)) + const n = Number.parseInt(nums.charAt(i)) for (let j = 0; j < letters[n].length; j++) { const ch = letters[n].charAt(j) curr.push(ch) diff --git a/src/main/ts/g0001_0100/s0027_remove_element/solution.ts b/src/main/ts/g0001_0100/s0027_remove_element/solution.ts index a6a348b..576e4b1 100644 --- a/src/main/ts/g0001_0100/s0027_remove_element/solution.ts +++ b/src/main/ts/g0001_0100/s0027_remove_element/solution.ts @@ -2,33 +2,15 @@ // #2025_03_31_Time_0_ms_(100.00%)_Space_56.09_MB_(20.94%) function removeElement(nums: number[], val: number): number { - if (!nums || nums.length === 0) { - return 0 - } - let len = nums.length - let j = len - 1 - let occurTimes = 0 - for (let i = 0; i < len; i++) { - if (nums[i] === val) { - occurTimes++ - if (j === i) { - return len - occurTimes - } - while (nums[j] === val) { - j-- - occurTimes++ - if (j === i) { - return len - occurTimes - } - } - nums[i] = nums[j] - j-- - } - if (i === j) { - return len - occurTimes + let k = 0 + + for (const num of nums) { + if (num !== val) { + nums[k++] = num } } - return len - occurTimes + + return k } export { removeElement } diff --git a/src/main/ts/g0001_0100/s0030_substring_with_concatenation_of_all_words/solution.ts b/src/main/ts/g0001_0100/s0030_substring_with_concatenation_of_all_words/solution.ts index 069a034..95449d2 100644 --- a/src/main/ts/g0001_0100/s0030_substring_with_concatenation_of_all_words/solution.ts +++ b/src/main/ts/g0001_0100/s0030_substring_with_concatenation_of_all_words/solution.ts @@ -2,41 +2,80 @@ // #2025_04_01_Time_13_ms_(97.44%)_Space_63.70_MB_(46.03%) function findSubstring(s: string, words: string[]): number[] { - let ans: number[] = [] - let n1 = words[0].length - let n2 = s.length - let map1 = new Map() - for (let ch of words) { - map1.set(ch, (map1.get(ch) ?? 0) + 1) + if (words.length === 0) return [] + + const result: number[] = [] + const wordLen = words[0].length + const totalLen = words.length * wordLen + const limit = s.length + + const target = buildFreqMap(words) + + for (let offset = 0; offset < wordLen; offset++) { + scanWindow(s, offset, wordLen, totalLen, limit, target, result) } - for (let i = 0; i < n1; i++) { - let left = i - let j = i - let c = 0 - let map2 = new Map() - while (j + n1 <= n2) { - let word1 = s.substring(j, j + n1) - j += n1 - if (map1.has(word1)) { - map2.set(word1, (map2.get(word1) ?? 0) + 1) - c++ - while ((map2.get(word1) ?? 0) > (map1.get(word1) ?? 0)) { - let word2 = s.substring(left, left + n1) - map2.set(word2, (map2.get(word2) ?? 0) - 1) - left += n1 - c-- - } - if (c === words.length) { - ans.push(left) - } - } else { - map2.clear() - c = 0 - left = j - } + + return result +} + +function buildFreqMap(words: string[]): Map { + const map = new Map() + for (const w of words) { + map.set(w, (map.get(w) ?? 0) + 1) + } + return map +} + +function scanWindow( + s: string, + start: number, + wordLen: number, + totalLen: number, + limit: number, + target: Map, + result: number[], +): void { + let left = start + let count = 0 + const window = new Map() + + for (let right = start; right + wordLen <= limit; right += wordLen) { + const word = s.substring(right, right + wordLen) + + if (!target.has(word)) { + window.clear() + count = 0 + left = right + wordLen + continue } + + window.set(word, (window.get(word) ?? 0) + 1) + count++ + + shrinkWindowIfNeeded(s, word, window, target, wordLen, () => { + const removed = s.substring(left, left + wordLen) + window.set(removed, (window.get(removed) ?? 0) - 1) + left += wordLen + count-- + }) + + if (count * wordLen === totalLen) { + result.push(left) + } + } +} + +function shrinkWindowIfNeeded( + _s: string, + word: string, + window: Map, + target: Map, + _wordLen: number, + shrink: () => void, +): void { + while ((window.get(word) ?? 0) > (target.get(word) ?? 0)) { + shrink() } - return ans } export { findSubstring } diff --git a/src/main/ts/g0001_0100/s0036_valid_sudoku/solution.ts b/src/main/ts/g0001_0100/s0036_valid_sudoku/solution.ts index 2ca47a4..3ec429e 100644 --- a/src/main/ts/g0001_0100/s0036_valid_sudoku/solution.ts +++ b/src/main/ts/g0001_0100/s0036_valid_sudoku/solution.ts @@ -10,7 +10,7 @@ function isValidSudoku(board: string[][]): boolean { if (board[i][j] === '.') { continue } - let val = board[i][j].charCodeAt(0) - '0'.charCodeAt(0) + let val = board[i][j].codePointAt(0)! - '0'.codePointAt(0)! let boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3) if (rowSet[i] & (1 << val) || colSet[j] & (1 << val) || boxSet[boxIndex] & (1 << val)) { return false diff --git a/src/main/ts/g0001_0100/s0049_group_anagrams/solution.ts b/src/main/ts/g0001_0100/s0049_group_anagrams/solution.ts index 8df43fb..a8c27db 100644 --- a/src/main/ts/g0001_0100/s0049_group_anagrams/solution.ts +++ b/src/main/ts/g0001_0100/s0049_group_anagrams/solution.ts @@ -7,9 +7,9 @@ function groupAnagrams(strs: string[]): string[][] { if (strs.length === 1) return [strs] const map = new Map() function getKey(str: string): string { - const charCount = Array(26).fill(0) + const charCount = new Array(26).fill(0) for (const char of str) { - charCount[char.charCodeAt(0) - 'a'.charCodeAt(0)]++ + charCount[char.codePointAt(0)! - 'a'.codePointAt(0)!]++ } return charCount.join('#') } diff --git a/src/main/ts/g0001_0100/s0050_powx_n/solution.ts b/src/main/ts/g0001_0100/s0050_powx_n/solution.ts index ec47d5f..d55b8d1 100644 --- a/src/main/ts/g0001_0100/s0050_powx_n/solution.ts +++ b/src/main/ts/g0001_0100/s0050_powx_n/solution.ts @@ -3,7 +3,7 @@ function myPow(x: number, n: number): number { let nn = BigInt(n) - let res = 1.0 + let res = 1 if (n < 0) { nn = -nn } @@ -16,7 +16,7 @@ function myPow(x: number, n: number): number { nn /= 2n } } - return n < 0 ? 1.0 / res : res + return n < 0 ? 1 / res : res } export { myPow } diff --git a/src/main/ts/g0001_0100/s0051_n_queens/solution.ts b/src/main/ts/g0001_0100/s0051_n_queens/solution.ts index e89d7fe..eb69bf5 100644 --- a/src/main/ts/g0001_0100/s0051_n_queens/solution.ts +++ b/src/main/ts/g0001_0100/s0051_n_queens/solution.ts @@ -4,7 +4,7 @@ function solveNQueens(n: number): string[][] { const result: string[][] = [] const board: number[] = [] - const BOARD_ROW = Array(n).fill('.').join('') + const BOARD_ROW = new Array(n).fill('.').join('') const printBoard = () => board.map((col) => `${BOARD_ROW.slice(0, col)}Q${BOARD_ROW.slice(col + 1)}`) const isSafePlace = (c: number): boolean => { for (let row = 0; row < board.length; row++) { diff --git a/src/main/ts/g0001_0100/s0062_unique_paths/solution.ts b/src/main/ts/g0001_0100/s0062_unique_paths/solution.ts index 6a301dd..1ef4f02 100644 --- a/src/main/ts/g0001_0100/s0062_unique_paths/solution.ts +++ b/src/main/ts/g0001_0100/s0062_unique_paths/solution.ts @@ -4,9 +4,9 @@ // #Big_O_Time_O(m*n)_Space_O(m*n) #2025_03_23_Time_0_ms_(100.00%)_Space_55.15_MB_(43.54%) function uniquePaths(m: number, n: number): number { - let aboveRow = Array(n).fill(1) + let aboveRow = new Array(n).fill(1) for (let row = 1; row < m; row++) { - let currentRow = Array(n).fill(1) + let currentRow = new Array(n).fill(1) for (let col = 1; col < n; col++) { currentRow[col] = currentRow[col - 1] + aboveRow[col] } diff --git a/src/main/ts/g0001_0100/s0063_unique_paths_ii/solution.ts b/src/main/ts/g0001_0100/s0063_unique_paths_ii/solution.ts index 14dd49c..b9ac96c 100644 --- a/src/main/ts/g0001_0100/s0063_unique_paths_ii/solution.ts +++ b/src/main/ts/g0001_0100/s0063_unique_paths_ii/solution.ts @@ -1,37 +1,26 @@ // #Medium #Array #Dynamic_Programming #Matrix #Dynamic_Programming_I_Day_15 // #Top_Interview_150_Multidimensional_DP #2025_04_02_Time_0_ms_(100.00%)_Space_55.75_MB_(56.77%) -function uniquePathsWithObstacles(obstacleGrid: number[][]): number { - if (obstacleGrid[0][0] === 1) { - return 0 - } - obstacleGrid[0][0] = 1 - const m = obstacleGrid.length - const n = obstacleGrid[0].length - for (let i = 1; i < m; i++) { - if (obstacleGrid[i][0] === 1) { - obstacleGrid[i][0] = 0 - } else { - obstacleGrid[i][0] = obstacleGrid[i - 1][0] - } - } - for (let j = 1; j < n; j++) { - if (obstacleGrid[0][j] === 1) { - obstacleGrid[0][j] = 0 - } else { - obstacleGrid[0][j] = obstacleGrid[0][j - 1] - } - } - for (let i = 1; i < m; i++) { - for (let j = 1; j < n; j++) { - if (obstacleGrid[i][j] === 1) { - obstacleGrid[i][j] = 0 - } else { - obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1] +function uniquePathsWithObstacles(grid: number[][]): number { + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[0].length; j++) { + if (grid[i][j] === 1) { + grid[i][j] = 0 + continue } + + if (i === 0 && j === 0) { + grid[i][j] = 1 + continue + } + + const fromTop = grid[i - 1]?.[j] ?? 0 + const fromLeft = grid[i]?.[j - 1] ?? 0 + grid[i][j] = fromTop + fromLeft } } - return obstacleGrid[m - 1][n - 1] + + return grid.at(-1)!.at(-1)! } export { uniquePathsWithObstacles } diff --git a/src/main/ts/g0001_0100/s0067_add_binary/solution.ts b/src/main/ts/g0001_0100/s0067_add_binary/solution.ts index bfcc3ae..b847f09 100644 --- a/src/main/ts/g0001_0100/s0067_add_binary/solution.ts +++ b/src/main/ts/g0001_0100/s0067_add_binary/solution.ts @@ -9,8 +9,8 @@ function addBinary(a: string, b: string): string { let j = bArray.length - 1 let carry = 0 while (i >= 0 || j >= 0) { - const digitA = i >= 0 ? parseInt(aArray[i]) : 0 - const digitB = j >= 0 ? parseInt(bArray[j]) : 0 + const digitA = i >= 0 ? Number.parseInt(aArray[i]) : 0 + const digitB = j >= 0 ? Number.parseInt(bArray[j]) : 0 const sum = digitA + digitB + carry sb.push((sum % 2).toString()) carry = Math.floor(sum / 2) @@ -20,7 +20,8 @@ function addBinary(a: string, b: string): string { if (carry !== 0) { sb.push(carry.toString()) } - return sb.reverse().join('') + sb.reverse() + return sb.join('') } export { addBinary } diff --git a/src/main/ts/g0001_0100/s0068_text_justification/solution.ts b/src/main/ts/g0001_0100/s0068_text_justification/solution.ts index ed43ef6..2ce94f1 100644 --- a/src/main/ts/g0001_0100/s0068_text_justification/solution.ts +++ b/src/main/ts/g0001_0100/s0068_text_justification/solution.ts @@ -2,55 +2,61 @@ // #2025_04_05_Time_0_ms_(100.00%)_Space_55.70_MB_(38.14%) function fullJustify(words: string[], maxWidth: number): string[] { - const output: string[] = [] - let sb: string[] = [] - let lineTotal = 0 - let numWordsOnLine = 0 - let startWord = 0 - for (let i = 0; i < words.length - 1; i++) { - lineTotal += words[i].length - numWordsOnLine++ - if (lineTotal + numWordsOnLine + words[i + 1].length > maxWidth) { - sb = [] - if (numWordsOnLine === 1) { - sb.push(words[i]) - while (lineTotal++ < maxWidth) { - sb.push(' ') - } - } else { - const spaces = Math.floor((maxWidth - lineTotal) / (numWordsOnLine - 1)) - let extraSp = (maxWidth - lineTotal) % (numWordsOnLine - 1) - - for (let j = startWord; j < startWord + numWordsOnLine - 1; j++) { - sb.push(words[j]) - sb.push(' '.repeat(spaces + (extraSp-- > 0 ? 1 : 0))) - } - sb.push(words[startWord + numWordsOnLine - 1]) - } - output.push(sb.join('')) - startWord = i + 1 - numWordsOnLine = lineTotal = 0 + const result: string[] = [] + let start = 0 + let lineLen = 0 + + for (let i = 0; i < words.length; i++) { + if (lineLen + words[i].length + (i - start) > maxWidth) { + result.push(justifyLine(words, start, i - 1, lineLen, maxWidth)) + start = i + lineLen = 0 } + lineLen += words[i].length } - // Handle last line - sb = [] - lineTotal = 0 - for (let i = startWord; i < words.length; i++) { - lineTotal += words[i].length - sb.push(words[i]) - if (lineTotal < maxWidth) { - sb.push(' ') - lineTotal++ - } + result.push(leftJustify(words, start, words.length - 1, maxWidth)) + return result +} + +function leftJustify( + words: string[], + start: number, + end: number, + maxWidth: number +): string { + let line = words.slice(start, end + 1).join(' ') + return padRight(line, maxWidth) +} + + +function justifyLine( + words: string[], + start: number, + end: number, + lineLen: number, + maxWidth: number +): string { + if (start === end) { + return padRight(words[start], maxWidth) } - while (lineTotal < maxWidth) { - sb.push(' ') - lineTotal++ + + const gaps = end - start + const totalSpaces = maxWidth - lineLen + const base = Math.floor(totalSpaces / gaps) + let extra = totalSpaces % gaps + + let line = '' + for (let i = start; i < end; i++) { + line += words[i] + line += ' '.repeat(base + (extra-- > 0 ? 1 : 0)) } - output.push(sb.join('')) + return line + words[end] +} - return output +function padRight(text: string, width: number): string { + return text + ' '.repeat(width - text.length) } + export { fullJustify } diff --git a/src/main/ts/g0001_0100/s0082_remove_duplicates_from_sorted_list_ii/solution.ts b/src/main/ts/g0001_0100/s0082_remove_duplicates_from_sorted_list_ii/solution.ts index aac4eee..905e012 100644 --- a/src/main/ts/g0001_0100/s0082_remove_duplicates_from_sorted_list_ii/solution.ts +++ b/src/main/ts/g0001_0100/s0082_remove_duplicates_from_sorted_list_ii/solution.ts @@ -16,9 +16,10 @@ import { ListNode } from '../../com_github_leetcode/listnode' * } */ function deleteDuplicates(head: ListNode | null): ListNode | null { - if (!head || !head.next) { + if (!head?.next) { return head } + const dummy = new ListNode(0) dummy.next = head let prev: ListNode = dummy