Chapter 15 · Bits and matrices

Cancel bits, then move indices

XOR cancels pairs. Kernighan clears one set bit per loop. Rotate is transpose plus reverse. A fully sorted matrix is binary search with mid → (r, c). Job 10454435 still none.

← Arrays & Strings · How to use →

XOR single numberPairs cancel. The leftover bit-pattern is the unique value.
Count bits — Kernighann &= n-1 clears the lowest set bit. Loop that many times.
Rotate 90° clockwiseTranspose, then reverse each row.
Search a sorted 2D matrixTreat the grid as one sorted array. Mid maps to (r, c).
Bits then matrix XOR and Kernighan are word-level. Rotate and 2D search are index arithmetic. Longest increasing path in a matrix is DFS/DP — graphs/DP chapters, not this one. Job 10454435 still none.

Single number — XOR

Recognize it from — every value appears twice except one; find the unique. “All pairs plus one unique in a sorted array” can also be binary search on even/odd index — XOR is the linear fallback you name first.

What it actually does — XOR is commutative, associative, and x ^ x = 0, x ^ 0 = x. Pairing every duplicate with itself cancels those bits. Whatever remains is the unpaired number. You do not need extra memory and you do not sort.

Simple — read this first

int singleNumber(int[] a) {
    int x = 0;
    for (int v : a) x ^= v; // each duplicate cancels; the unique bits survive
    return x;
}

Interview — type this

int singleNumber(int[] a) {
    if (a == null || a.length == 0) throw new IllegalArgumentException("empty");
    int x = 0;
    for (int v : a) x ^= v;
    return x; // if they said "appears 3 times except one," XOR is the wrong tool — counts or bit-mod-3
}
Example 1 — simple

[2, 2, 1].

[2, 2, 1]
vx beforex ^= vx after
200 ^ 22
222 ^ 20
100 ^ 11

Answer: 1.

Example 2 — every step

[4, 1, 2, 1, 2]. Running XOR, binary shown.

Running XOR — [4, 1, 2, 1, 2]
vv binaryx beforex after (binary)x after (dec)
41000001004
10011001015
20101011117
10011111106
20101101004

Answer: 4. The two 1s cancelled, the two 2s cancelled, 4 remained.

Time O(n) Space O(1)
Why XOR, not a set A HashSet of “seen once vs twice” is O(n) extra and correct. XOR is the O(1) extra they want when the prompt is exactly “pairs plus one.” Sorted unique-in-pairs can be log n binary search on even indices — name XOR first, then the log n follow-up.
Common mistakes
  • Using XOR when the unique appears once and others appear three times. Bits need a mod-3 count.
  • Initializing x to a[0] and then also XORing a[0] again — you cancel the first element.
  • Thinking XOR finds a duplicate. It finds the unpaired pattern; two copies of everything including the “unique” yields 0.
ProblemPatternLinks
Single element in a sorted paired arrayXOR is O(n); even/odd-index binary search is O(log n) — same cheat card also has LL sum-0cheat card

Count set bits — Kernighan n &= n-1

Recognize it from — Hamming weight, “how many 1-bits,” bit-check of a flag. Looping 32 times with (n >> i) & 1 is correct and slower to think about; Kernighan loops once per set bit.

What it actually does — in two’s complement, n - 1 flips everything from the lowest 1-bit through the trailing zeros. AND with n clears that lowest 1 and leaves the higher 1s. Repeat until n is 0. The iteration count is the popcount.

Simple — read this first

int bitCount(int n) {
    int c = 0;
    while (n != 0) {
        n &= n - 1; // drop the lowest set bit
        c++;
    }
    return c;
}
boolean testBit(int n, int k) {
    return (n & (1 << k)) != 0; // is bit k set? (k from the right, 0-based)
}

Interview — type this

int hammingWeight(int n) {
    int c = 0;
    while (n != 0) {
        n &= n - 1;
        c++;
    }
    return c; // Integer.bitCount(n) exists; they often want the loop
}
boolean allPowerOfTwo(int n) {
    return n > 0 && (n & (n - 1)) == 0; // exactly one bit set
}
Example 1 — simple

n = 7 = 1112. Three set bits.

n = 7
n beforebinaryn − 1n &= n−1c
71116 (110)110 = 61
61105 (101)100 = 42
41003 (011)000 = 03

Answer: 3. Loop stops.

Example 2 — every step

n = 12 = 11002. Every unset of a 1-bit. Two set bits (not four — the trailing zeros are already 0).

n = 12 — every n &= n−1
Itern before (bin)Lowest 1-bitn−1 (bin)AND (bin)n afterc
11100 (12)bit 2 (value 4)1011 (11)100081
21000 (8)bit 3 (value 8)0111 (7)000002

Answer: 2. A 32-step shift loop would also return 2; it would iterate through the zeros too.

Time O(set bits) Shift loop O(32) Space O(1)
Why n &= n−1 You only touch bits that are on. Power-of-two is the one-iteration special case: n & (n-1) == 0. Java Integer.bitCount is fine to name; type the loop if they want to see the trick.
Common mistakes
  • while (n > 0) on a sign bit: if they pass a negative int, use n != 0 and treat it as 32-bit two’s complement (or use n >>> 1 in a shift version).
  • Writing n = n - 1 without the AND — that is just a countdown, not a popcount.
  • Off-by-one on “bit k”: 0 is the least significant bit.

No extra named-IE card required for Kernighan. Do not invent a Job 10454435 bit prompt.

Rotate matrix 90° clockwise — transpose + reverse rows

Recognize it from — n×n matrix, rotate in place 90° clockwise. Anti-clockwise is transpose then reverse columns (ask). Spiral print is a different IO (walk layers). Search 2D is the next card.

What it actually does — the mapping is (i, j) → (j, n-1-i). Doing that with a temp matrix is the brute. In place: first swap across the diagonal (transpose), then reverse each row. Transpose sends (i,j) to (j,i); reversing the row sends (j,i) to (j, n-1-i).

Simple — read this first

void rotateCopy(int[][] m) {
    int n = m.length;
    int[][] t = new int[n][n];          // extra matrix — name this, then drop it
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            t[j][n - 1 - i] = m[i][j];  // the closed-form map
    for (int i = 0; i < n; i++)
        m[i] = t[i];
}

Interview — type this

void rotate(int[][] m) {
    int n = m.length;
    for (int i = 0; i < n; i++) {                 // transpose: only j > i so you do not swap twice
        for (int j = i + 1; j < n; j++) {
            int t = m[i][j]; m[i][j] = m[j][i]; m[j][i] = t;
        }
    }
    for (int i = 0; i < n; i++) {                 // reverse each row
        for (int l = 0, r = n - 1; l < r; l++, r--) {
            int t = m[i][l]; m[i][l] = m[i][r]; m[i][r] = t;
        }
    }
}
Example 1 — simple

2×2: [[1, 2], [3, 4]] → [[3, 1], [4, 2]].

1 2 1 3 3 1 3 4 → 2 4 → 4 2 transpose reverse rows
2×2
PassSwap / reverseMatrix
transpose(0,1) ↔ (1,0) = 2 ↔ 3[[1, 3], [2, 4]]
reverse row 01 ↔ 3[[3, 1], [2, 4]]
reverse row 12 ↔ 4[[3, 1], [4, 2]]

Answer: [[3, 1], [4, 2]].

Example 2 — every step

3×3. Every transpose swap, then every row reverse.

1 2 3 4 5 6 7 8 9
3×3 — every swap, then every reverse
StepActionMatrix after
start—[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transpose i=0,j=12 ↔ 4[[1, 4, 3], [2, 5, 6], [7, 8, 9]]
transpose i=0,j=23 ↔ 7[[1, 4, 7], [2, 5, 6], [3, 8, 9]]
transpose i=1,j=26 ↔ 8[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
reverse row 01 ↔ 7 (4 stays)[[7, 4, 1], [2, 5, 8], [3, 6, 9]]
reverse row 12 ↔ 8 (5 stays)[[7, 4, 1], [8, 5, 2], [3, 6, 9]]
reverse row 23 ↔ 9 (6 stays)[[7, 4, 1], [8, 5, 2], [9, 6, 3]]

Answer: [[7, 4, 1], [8, 5, 2], [9, 6, 3]].

Time O(n²) In-place space O(1)
Why transpose then reverse The closed form (i,j)→(j, n-1-i) needs four-cell cycles or extra memory if you assign in place naively. Two familiar passes (swap across the diagonal, reverse a row — you already reverse arrays for next-perm) are easy to type without mixing indices.
Common mistakes
  • Transposing with j from 0, so you swap each pair twice and undo the transpose.
  • Reversing columns when they asked clockwise (that is anti-clockwise after transpose).
  • Assuming a non-square matrix. This recipe is n×n. Rectangular rotate is a different prompt.
ProblemPatternLinks
Rotate image 90°Transpose + reverse rows. AUTA R2 with next-perm similar — other loop.cheat card · clue

Search a 2D matrix — treat as a sorted array

Recognize it from — each row sorted, first of row i+1 greater than last of row i (one globally sorted sequence). Target present or not. Row-with-max-1s is a different walk (staircase from the top-right on a 0/1 row-sorted matrix). Search-II (columns also sorted, but not globally) is also a staircase, not this binary search.

What it actually does — flatten the index space in your head: cell k is m[k / cols][k % cols]. Binary search lo..hi on [0, rows*cols - 1]. Mid maps to a row and column; compare that value to the target with Integer.compare. You never allocate a 1D copy.

Simple — read this first

boolean searchMatrix(int[][] m, int target) {
    int rows = m.length, cols = m[0].length;
    int lo = 0, hi = rows * cols - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;   // overflow-safe mid
        int r = mid / cols, c = mid % cols;
        int v = m[r][c];
        if (v == target) return true;
        if (v < target) lo = mid + 1;
        else hi = mid - 1;
    }
    return false;
}

Interview — type this

boolean searchMatrix(int[][] m, int target) {
    if (m == null || m.length == 0 || m[0].length == 0) return false;
    int rows = m.length, cols = m[0].length;
    int lo = 0, hi = rows * cols - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        int r = mid / cols, c = mid % cols;
        int cmp = Integer.compare(m[r][c], target);
        if (cmp == 0) return true;
        if (cmp < 0) lo = mid + 1;
        else hi = mid - 1;
    }
    return false; // missing target — Ex2
}
Example 1 — simple

2×2: [[1, 3], [5, 7]], target 3. Flattened: 1, 3, 5, 7. Indices 0..3.

Find 3 in 2×2
lohimid(r, c)m[r][c]Compare to 3
031(0, 1)3equal → true

Answer: true, at (0, 1).

Example 2 — every step

3×4, find a missing value 13. Every mid mapped to (r, c).

1 3 5 7 row 0 10 11 16 20 row 1 23 30 34 60 row 2 cols = 4, indices 0..11 k → (k/4, k%4)
Find 13 (absent) — every mid
lohimid = lo+(hi-lo)/2r = mid/4c = mid%4valueInteger.compare vs 13Next
01151111< 0lo = 6
61182023> 0hi = 7
6761216> 0hi = 5
65————lo > histop, false

Answer: false. 13 sits between 11 and 16 in the flattened order; the search never hits a cell equal to 13.

Time O(log (rows·cols)) Space O(1)
Why flatten indices, not nested loops The matrix is one sorted sequence of length R·C. Binary search on that length is the same code as 1D search; only the address translation changes. Staircase from the top-right is the right tool when rows and columns are sorted but the next row does not start after the previous row’s last value (Search-II), or when you want the leftmost 1 in a 0/1 row.
Common mistakes
  • (lo + hi) / 2 overflow habit. Use lo + (hi-lo)/2.
  • Mapping mid with the wrong dimension: row = mid / cols, not / rows.
  • Using this recipe on a matrix that is only row-sorted (Search-II). Then 13 could sit “between” rows incorrectly.
ProblemPatternLinks
Row with max 1s (row-sorted 0/1)Staircase from top-right O(m+n) — not flatten-binary-searchcheat card · clue
Sudoku validateRows / cols / boxes seen-sets — matrix, not binary searchcheat card · R4 coding

See also on this topic

Longest increasing path in a matrix is DFS + memo (graph/DP), not a rotate. It sits in chapter 05 if you need the Java card. Sudoku is constraint sets on a 9×9, not search-as-array. Job 10454435 still none.

ProblemPatternLinks
Longest increasing path in a matrixGraph DFS / DP — not this chapter’s rotate or 2D searchJava in ch.05

← Arrays & Strings · How to use →