Published on

Bug Notes Collection

  • Name
    Linkedin

Bug Notes Collection

This note summarizes common bugs encountered while solving Leetcode problems. Each section is organized by bug type and provides concise explanations and corrected code snippets.


🧵 String

Initialization of StringBuffer

When initializing an array of StringBuffer, use a loop instead of direct assignment.

StringBuffer[] sb = new StringBuffer[n]; // Wrong

// Each element must be initialized separately:
for(int i=0; i<n; i++) sb[i] = new StringBuffer();

Matching between source and target strings

When performing character-by-character matching between two strings:

  • Use while when matching continuously.
  • Use if when only comparing one position.
// Continuous matching
while(i < n && j < m && s.charAt(i) == t.charAt(j))

// Single position matching
if(haystack.charAt(i + j) != needle.charAt(j))

Fixed start, find the end in a sentence

In the sentence like " Hello World How are you. ", to re-organize the sentence to multiple lines, normally we need to find the [left, right] boundry of each line. When searching for a right boundary of word, remember to update pointers correctly.

start = i;
i++;

int right = left++;
while(right < words.length && curLen + 1 + words[right].length() <= width) {
    // do something
    // remember add the ' '
    curLen += words[right].length() + 1;
}

Edge case and empty String

When checking if string s is a substring of t, remember to handle the empty string case "".

    if(s == null || s.trim().isEmpty())

String split using pattern

When splitting strings by keywords like BEGIN and END, use word boundaries \b to avoid partial matches.

// Split by END
String[] words = line.split("\\bEND\\b\\s*");

// Split by BEGIN
String[] words2 = line2.split("\\bBEGIN\\b\\s*");

🔍 Two Pointers

Duplicate removal in 3Sum

When skipping duplicate elements after finding a valid triplet, ensure both i and j move correctly.

if(nums[i] + nums[j] == -nums[k]) {
     List<Integer> row = new ArrayList<>(Arrays.asList(nums[k], nums[i], nums[j]));
     ans.add(row);

     i++;
     j--;
     while(i < j && i != k + 1 && nums[i] == nums[i - 1]) i++;
     while(i < j && j != n - 1 && nums[j] == nums[j + 1]) j--;
}

🗺️ Map

Update and remove element in map

When replacing an element with the last element in an array and removing it, update the map carefully. If the element to remove is the same as the last element, update the map before removing it.

map.put(lastElem, oldPosition);
map.remove(val);

🔍 Sliding Window

Update i and j after calculating window length

In a sliding window, ensure updates to i and j happen after using j - i + 1 to calculate window length.

while(j < m) {
    remain[ss[j]]--;
    if(remain[ss[j]] == 0) cnt++;

    while(cnt == distinct) {
        remain[ss[i]]++;
        if(remain[ss[i]] == 1) cnt--;

        if(minLen > j - i + 1) {
             minLen = j - i + 1;
             start = i;
        }
        // i update at the end
        i++;
    }
    // j update at the end
    j++;
}

🧮 Matrix

Row and column tracking with maps

When using Map<Integer, Set<Integer>> to record numbers in each row or column, make sure to pass the correct index i.

boolean res = checkRowOrCol(rowMap, i, num)
           && checkRowOrCol(colMap, j, num)
           && checkGroup(groupMap, num, i, j);

Updating matrix boundaries

When traversing a matrix in spiral order, update the four boundaries (top, bottom, left, right) after completing each loop.

    for(int j=left;j<=right;j++) {
        ans.add(matrix[top][j]);
    }
    top++;

    for(int i=top;i<=bottom;i++) {
        ans.add(matrix[i][right]);
    }
    right--;

Diagonal transformation

When transposing or swapping along the diagonal, only operate on elements where j < i to avoid double swaps.

for(int i = 0; i < n; i++) {
  for(int j = 0; j < i; j++) {

Loop boundaries and zero row detection

When processing matrix rows:

  • The 0th row might already be checked.
  • Start looping from i = 1, but j should still start from 0.
for(int i = 1; i < m; i++) {
    for(int j = 0; j < n; j++) {

Direction array mistakes

When defining directions for 8-neighbor traversal, make sure the direction array is correctly written.

private int[][] dirs = {
    {-1, -1}, {-1, 0}, {-1, 1},
    {0, -1}, {0, 1},
    {1, -1}, {1, 0}, {1, 1}
};

Avoid boundary check bugs in nested loops

When looping over neighbors using index ranges, direct index loops may skip iteration if i = 0. Use dirs array instead.

// Wrong!
// Bug 1: 当 i=0 时,循环根本没进入
        // for(int row=i-1;row>=0 && row <= Math.min(i+1, M-1);row++) {
        //     for(int col=j-1; col >= 0 && col <= Math.min(j+1, N-1); col++) {
        //         // skip self
        //         if(row == i && col == j) continue;

        //         if(wasLive(board, row, col)) liveCnt++;
        //         else dieCnt++;
        //     }
        // } 


for(int[] dir: dirs) {
    int x = dir[0] + i, y = dir[1] + j;
}

Count all transitions correctly in state change

When counting alive cells in Game of Life: Include both ALIVE → ALIVE and ALIVE → DIE states.

liveCnt += (board[x][y] == ALIVE || board[x][y] == ALIVETODIED) ? 1 : 0;