Journal: Watch Me Struggle Through 4 LeetCode Problems
Four LeetCode Problems. One Long Day. Zero Shortcuts
Full-stack Engineer specializing in Node.js, Nest.js, MERN. Expert in building scalable APIs & real-time apps. Focus on clean code, Security, and performance.
This article is part of my journal. Read more
Encode and Decode Strings (NeetCode)
Yesterday I started with a NeetCode problem: encode and decode strings. The idea was to take a list of strings, encode them into a single string, send that over the network, then decode it back to the original list.
The trick was figuring out how to tell where one string ended and the next began. What I landed on was a simple format: for each string, prefix it with its length followed by a special character as a separator — so something like 5:hello3:hey. Concatenate all of them together and you had your encoded string.
Decoding worked by scanning for the special character. Whatever came before it was the length. I used that length to slice out the original string, then moved the pointer forward and repeated until everything was recovered.
Here is the final code
class Solution {
/**
* @param {string[]} strs
* @returns {string}
*/
encode(strs) {
return strs.map(str => `\({str.length}:\){str}`).join('')
}
/**
* @param {string} str
* @returns {string[]}
*/
decode(str) {
const output = []
let i = 0
while (i < str.length) {
const delimiter = str.indexOf(':', i)
const length = +str.slice(i, delimiter)
output.push(str.slice(delimiter + 1, delimiter + 1 + length))
i = delimiter + 1 + length
}
return output
}
}
Product of Array Except Self (LeetCode #238)
Next up was LeetCode 238. The problem: given an array of numbers, return a new array where each index held the product of all the other numbers — no division allowed, O(n) time.
The solution used the prefix sum pattern, but with multiplication. I looped from start to end keeping a running left-side product, and assigned it to each index. Then did the same from right to left with a running right-side product, multiplying into what was already there.
I also worked out a trick to handle both directions in a single loop — using length - currentIndex - 1 to get the mirrored index, so I could update from both ends simultaneously without two separate passes.
The key insight: the product of everything except the current element was just the product of everything to its left multiplied by everything to its right. Prefix products gave me exactly that.
Here is the final code
function productExceptSelf(nums: number[]): number[] {
const ans = new Array(nums.length).fill(1)
let leftProduct = 1
let rightProduct = 1
for (let i = 0; i < nums.length; i++) {
ans[i] *= leftProduct
leftProduct *= nums[i]
const rightI = nums.length - i - 1
ans[rightI] *= rightProduct
rightProduct *= nums[rightI]
}
return ans
};
Valid Sudoku (LeetCode #36)
Then I worked through LeetCode 36 — checking whether a Sudoku board was valid. Each row, column, and 3×3 box had to contain 1–9 with no repeats.
My approach was to initialize three 2D arrays — one for rows, one for columns, one for boxes — then loop through the grid with nested loops. If a cell was empty (marked as .) I skipped it. If it was a number, I subtracted 1 to get a zero-based index, then checked the corresponding slot in each tracking array. If it was already marked true, the board was invalid. Otherwise I marked it and moved on.
Rows and columns were straightforward. The tricky part was finding the correct box index. The formula I worked out:
boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3)
This took a while to reason through. Dividing the row index by 3 gave which box row I was in (0, 1, or 2). Multiplying by 3 scaled it so there was room for the column offset. Adding the column index divided by 3 gave the final box index from 0 to 8. I wrote a quick test loop to console log the output and verify it matched what I expected — and it clicked into place.
Here is the final code
function isValidSudoku(board: string[][]): boolean {
const rows = Array.from({length: 9}, () => Array(9).fill(false))
const cols = Array.from({length: 9}, () => Array(9).fill(false))
const cube = Array.from({length: 9}, () => Array(9).fill(false))
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
const value = board[i][j]
if (value === '.') continue
const index = +value - 1
const boxIndex = Math.floor(i/3) * 3 + Math.floor(j / 3)
if (rows[i][index] || cols[j][index] || cube[boxIndex][index]) return false
rows[i][index] = cols[j][index] = cube[boxIndex][index] = true
}
}
return true
};
Longest Consecutive Sequence (LeetCode #128)
The last problem of the day was LeetCode 128 — finding the longest consecutive sequence in an unsorted integer array. Had to run in O(n) time.
I converted the array to a Set to remove duplicates and allow O(1) lookups. Then looped through the set. For each number, I checked if number - 1 existed. If it did, that number wasn't the start of a sequence — skip it. If it didn't exist, that number was the start. I began counting upward, kept incrementing and checking if the next number existed, tracking the count until the sequence broke. Then compared against the running max.
I caught a bug mid-implementation: I was looping over the original input array instead of the set. That meant doing redundant work on duplicate values. Once I switched to looping over the set, everything worked correctly.
Here is the final code
function longestConsecutive(nums: number[]): number {
const set = new Set(nums)
let longestSequence = 0
for (let num of set) {
if (!set.has(num - 1)) {
let newLongest = 1
while (set.has(num + newLongest)) {
newLongest++
}
longestSequence = Math.max(longestSequence, newLongest)
}
}
return longestSequence
};
Conclusion
Four problems yesterday. Good mix of encoding tricks, array manipulation, grid logic, and set-based searching. The Sudoku box index formula was the most satisfying thing to work out.

