Two pointers travelling the same direction at different speeds: a slow
write head marking the slot the next kept value goes into, and a fast
read head scanning ahead. Anything that isn't val gets copied
back to write; anything that is simply never gets copied. The invariant is
the whole problem — nums[0, write) is a finished answer after every
single step, the order of what survives is irrelevant, and everything past the returned length is junk.
nums[k..n) may hold anything.