#[must_use]
pub fn permutation_is_odd<T: PartialEq + Clone>(from: &[T], to: &[T]) -> Option<bool> {
if from.len() != to.len() {
return None;
}
let mut cur = from.to_vec();
let mut swaps = 0usize;
for (i, want) in to.iter().enumerate() {
if cur[i] == *want {
continue;
}
let j = (i + 1..cur.len()).find(|&j| cur[j] == *want)?;
cur.swap(i, j);
swaps += 1;
}
Some(swaps % 2 == 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parity_alternates_with_each_transposition() {
let base = [10u32, 20, 30, 40];
assert_eq!(permutation_is_odd(&base, &base), Some(false));
assert_eq!(permutation_is_odd(&base, &[20, 10, 30, 40]), Some(true));
assert_eq!(permutation_is_odd(&base, &[20, 30, 10, 40]), Some(false));
assert_eq!(permutation_is_odd(&base, &[40, 30, 20, 10]), Some(false));
assert_eq!(permutation_is_odd(&base, &[10, 20, 40, 30]), Some(true));
}
#[test]
fn a_mismatched_multiset_is_unanswerable_not_even() {
assert_eq!(permutation_is_odd(&[1u32, 2, 3], &[1, 2]), None, "长度不同");
assert_eq!(
permutation_is_odd(&[1u32, 2, 3], &[1, 2, 4]),
None,
"元素不同"
);
assert_eq!(
permutation_is_odd(&[1u32, 1, 2], &[1, 2, 2]),
None,
"重数不同"
);
assert_eq!(permutation_is_odd::<u32>(&[], &[]), Some(false));
}
#[test]
fn repeated_elements_still_have_a_parity() {
assert_eq!(
permutation_is_odd(&[1u32, 1, 2, 3], &[1, 1, 3, 2]),
Some(true)
);
assert_eq!(
permutation_is_odd(&[1u32, 1, 2, 3], &[1, 1, 2, 3]),
Some(false)
);
}
}