omgkit_core/
permutation.rs1#[must_use]
24pub fn permutation_is_odd<T: PartialEq + Clone>(from: &[T], to: &[T]) -> Option<bool> {
25 if from.len() != to.len() {
26 return None;
27 }
28 let mut cur = from.to_vec();
29 let mut swaps = 0usize;
30 for (i, want) in to.iter().enumerate() {
31 if cur[i] == *want {
32 continue;
33 }
34 let j = (i + 1..cur.len()).find(|&j| cur[j] == *want)?;
35 cur.swap(i, j);
36 swaps += 1;
37 }
38 Some(swaps % 2 == 1)
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
47 fn parity_alternates_with_each_transposition() {
48 let base = [10u32, 20, 30, 40];
49 assert_eq!(permutation_is_odd(&base, &base), Some(false));
50 assert_eq!(permutation_is_odd(&base, &[20, 10, 30, 40]), Some(true));
51 assert_eq!(permutation_is_odd(&base, &[20, 30, 10, 40]), Some(false));
52 assert_eq!(permutation_is_odd(&base, &[40, 30, 20, 10]), Some(false));
53 assert_eq!(permutation_is_odd(&base, &[10, 20, 40, 30]), Some(true));
54 }
55
56 #[test]
61 fn a_mismatched_multiset_is_unanswerable_not_even() {
62 assert_eq!(permutation_is_odd(&[1u32, 2, 3], &[1, 2]), None, "长度不同");
63 assert_eq!(
64 permutation_is_odd(&[1u32, 2, 3], &[1, 2, 4]),
65 None,
66 "元素不同"
67 );
68 assert_eq!(
69 permutation_is_odd(&[1u32, 1, 2], &[1, 2, 2]),
70 None,
71 "重数不同"
72 );
73 assert_eq!(permutation_is_odd::<u32>(&[], &[]), Some(false));
75 }
76
77 #[test]
79 fn repeated_elements_still_have_a_parity() {
80 assert_eq!(
81 permutation_is_odd(&[1u32, 1, 2, 3], &[1, 1, 3, 2]),
82 Some(true)
83 );
84 assert_eq!(
85 permutation_is_odd(&[1u32, 1, 2, 3], &[1, 1, 2, 3]),
86 Some(false)
87 );
88 }
89}