No difference here. In general, mem::swap can also work in cases where you only have &mut references to the values in question, whereas (already_seen, first_seen) = (first_seen, already_seen); is restricted to cases where you ownalready_seen and first_seen, so you can move out of them.
The limitation is a bit arbitrary for this particular case, but in general, it ensures that programs stay well-behaved in the presence of panics. Feel free to click here for more details…
Technically evaluating the right-hand side of (already_seen, first_seen) = (first_seen, already_seen); moves the value out of first_seen and already_seen, leaving them in a de-initialized state, until the assignment itself then re-initializes both values to their new (now swapped) values. If you did this in two steps
let values = (first_seen, already_seen);
(already_seen, first_seen) = values;
then you could start doing something else in the middle
let values = (first_seen, already_seen);
something_else();
(already_seen, first_seen) = values;
and if something_else(); panics, it means that the values will be dropped and first_seen, already_seen both left uninitialized - which is something you can only do if you own them, whereas mutable borrows promise the owner that something will still be there when the borrow ends.