Short problems with techniques that transfer: maximum subarray, majority and heavy hitters, circular arrays and rotations, and in-place permutation tricks.

Maximum subarray (Kadane)

cur is the best sum of a subarray ending at : extend it or start fresh.

ll best = LLONG_MIN, cur = 0;
for (ll x : a) { cur = max(x, cur + x); best = max(best, cur); }   // non-empty subarray

The prefix-sum view generalises better:

VariantMethod
empty subarray allowedstart best = 0
length keep
length in sliding window minimum of prefixes
sum , maximiseset of prefixes, lower_bound(p_r - K)
max producttrack both max and min ending here (negatives swap them); zeros reset
circular; if all are negative, the second term is the empty array, so use plain Kadane
disjoint subarrays DP with states (used , inside or not); for large use the Aliens trick, since the answer is concave in
2D max submatrixfix a pair of rows, collapse columns, Kadane:
delete at most one elementDP with states “deletion used / not used”
with point updates, range queriessegment tree node
stock buy-sell, max profit, one transactionKadane on consecutive price differences
struct Node { ll sum, pre, suf, best; };
Node merge(Node a, Node b) {
    return {a.sum + b.sum, max(a.pre, a.sum + b.pre), max(b.suf, b.sum + a.suf),
            max({a.best, b.best, a.suf + b.pre})};
}

This four-value node is the standard example of a richer segment tree merge, and it shows up again in Segment Tree and in dynamic DP.

Majority and heavy hitters

Boyer-Moore voting: pair each candidate occurrence with a different element and cancel them. A true majority (more than ) survives every cancellation.

int cand = 0, cnt = 0;
for (int x : a) { if (!cnt) cand = x; cnt += x == cand ? 1 : -1; }
// verify: count(cand) * 2 > n, since a majority may not exist
  • More than (Misra-Gries): keep counters; a new value with no free counter decrements all of them. Verify each surviving candidate. time, memory.
  • Sorting: a majority occupies index after sorting.
  • Bitwise: with a majority guaranteed, take the majority bit in each position.
MethodTimeSpaceNote
Boyer-Moore votingoptimal; needs verification
hash map countingsimplest; also gives all counts
sort, take the middlethe majority must occupy index
randomised sampling expectedpick a random element, verify; succeeds with probability per trial
bit-by-bit majorityfor each bit, take the majority bit
divide and conquerthe majority of the whole is a majority of some half
  • Range majority :
    • Randomised: sample about 25 random positions and verify each candidate with binary search over that value’s position list. The failure probability is about .
    • Deterministic: (candidate, count) pairs merge like Boyer-Moore, so a segment tree gives a candidate in ; verify with position lists.
    • Persistent segment tree over values: descend to the half that holds more than .
  • Streaming relatives: Count-Min sketch (approximate frequencies), HyperLogLog (distinct count), reservoir sampling.

Circular arrays

TechniqueWhen
double the arraywindows that may wrap; cyclic shifts as substrings
total minus complementcircular max subarray
rotation starting after the minimum prefix”a start where every prefix is valid”
fix whether element 0 is usedcircular DP: solve twice with element 0 forced in or out
break at a known pointthe cycle has an element that is certainly a cut, such as the global maximum

Gas station: with , a valid start exists iff , and it’s the position right after the minimum prefix sum. Equivalently, scan with a tank and restart from whenever the tank goes negative: no station in a failed stretch can be a start.

Cycle lemma (Raney). If integers sum to , exactly one cyclic shift has all partial sums positive. If each and the sum is , exactly shifts do. That proves the ballot theorem and (cyclic shifts of a sequence with ups and downs, made to sum to 1).

Minimum refuelling stops: drive until stuck, then retroactively refuel at the biggest station passed (max-heap). The same “take it, regret the worst later” shape appears in regret greedy.

Rotations and in-place rearrangement

  • Rotate left by : reverse , reverse , reverse all, since . Normalise with ((k % n) + n) % n. std::rotate does it directly.
  • Apply a permutation in place: walk its cycles, or mark visited by negating or adding to values. The juggling algorithm rotates left by the same way, in place, by walking cycles directly (no reversal) — same time, extra space as the triple-reversal trick, one pass instead of three but with worse cache behaviour, so the reversal method is usually faster in practice despite doing more total work.
  • Minimum swaps to sort: number of cycles of the permutation mapping positions to sorted positions.
  • Find the duplicate in values from without modifying the array: Floyd’s cycle detection on .
  • Missing number(s): XOR of against the array; for two missing numbers, split by any set bit of their XOR.
  • First missing positive in and memory: cyclic-sort each value into slot , then scan.
  • Next permutation: find the last with , swap with the last element greater than it, reverse the suffix. The -th permutation comes from the factorial number system.

More in-place patterns:

TaskTechnique
remove duplicates from a sorted arraytwo pointers: unique(all(a))
partition by a predicateDutch national flag
move zeros to the enda write pointer trailing a read pointer
reverse in groups of repeated reverse on subranges

Matrix transformations

Rotations are compositions of transpose and reversals:

OperationRecipeMap for an matrix
rotate 90° clockwisetranspose, then reverse each row
rotate 90° counter-clockwisetranspose, then reverse row order
rotate 180°reverse row order and each row
flip top-bottom / left-rightreverse row order / each row
main-diagonal mirrortranspose
anti-diagonal mirrorreverse rows, transpose, reverse rows

In the transpose loop start j at i + 1, otherwise every pair is swapped twice. For an matrix, allocate a result: res[j][r-1-i] = m[i][j].

Derive, don't memorise

Rotate the corner in your head and see where it lands. Transpose sends ; reversing rows sends . Composing gives , which is exactly clockwise rotation. Two seconds of checking beats a memorised table you might have backwards.

Diagonals: anti-diagonals are indexed by and main diagonals by (offset by ). Grid DPs that move right/down process anti-diagonals in order.

Spiral order needs the two guards before the bottom row and left column passes, or a single remaining row or column is printed twice.