At most two copies of each value survive. The generalisation is one character wide:
keep nums[read] when write < 2 || nums[read] != nums[write-2].
If the slot two behind the write head already holds this value, two copies are in
the answer and this is the third. Swap the 2 for k and the same template solves
“at most k duplicates”. The trap: looking back at nums[read-2] instead.
read walks the original array while write walks the answer
you are building, and the moment they separate those are two different arrays.
write < 2 || nums[read] != nums[write-2] — replace the 2 with k for “at most k duplicates”.