One pointer per string, both starting at index 0, both only ever moving right — so the entire
design question is which one advances this step. Here the rule is deliberately lopsided:
j walks t on every step, while i
walks s only when the two heads agree. Greedy is safe because consuming the
earliest occurrence of s[i] can never cost you a later match —
it leaves the longest possible tail of t for whatever is left of s.
Worth knowing the follow-up, because it changes the answer: if you have many s
queries against one fixed t, this scan is the wrong shape. You preprocess t
once into a next-occurrence table nxt[pos][c] and then jump through it,
answering each query in O(|s|) instead of re-walking all of t.
j advances unconditionally, i advances only on a match. For k queries against one t, switch to the nxt[pos][c] table instead.