pegitan/leetcode/
problem_416.rs

1use crate::Solution;
2
3impl Solution {
4    //  NOTE    ::  Naive implementation, simply collect the permutations as we go.
5    pub fn can_partition_naive(nums: Vec<i32>) -> bool {
6        let mut sum: i32 = nums.iter().sum();
7        let mut result: Vec<(i32, i32)> = Vec::new();
8        nums.iter().for_each(|&x| match result.len() {
9            0 => {
10                sum -= x;
11                result.push((x, 0))
12            }
13            _ => {
14                let right_result = result
15                    .iter()
16                    .map(|&(left, right)| (left, right + x))
17                    .collect::<Vec<(i32, i32)>>();
18                let left_result = result
19                    .iter()
20                    .map(|&(left, right)| (left + x, right))
21                    .collect::<Vec<(i32, i32)>>();
22                result.clear();
23                result.extend(left_result);
24                result.extend(right_result);
25            }
26        });
27        result
28            .iter()
29            .filter(|&&(left, right)| left == right)
30            .collect::<Vec<_>>()
31            .len()
32            != 0
33    }
34
35    //  NOTE    ::  Checks if no possible combination exists. We do this by taking the absolute
36    //              difference and checking if its more than the sum of the whats left.
37    pub fn can_partition_whats_left(nums: Vec<i32>) -> bool {
38        let mut sum: i32 = nums.iter().sum();
39        let mut result: Vec<(i32, i32)> = Vec::new();
40        nums.iter().for_each(|&x| match result.len() {
41            0 => {
42                sum -= x;
43                result.push((x, 0))
44            }
45            _ => {
46                let new_result = result
47                    .iter()
48                    .filter(|&&(left, right)| match left.cmp(&right) {
49                        std::cmp::Ordering::Greater => left - right <= sum,
50                        _ => right - left <= sum,
51                    })
52                    .map(|&(left, right)| vec![(left + x, right), (left, right + x)])
53                    .flatten()
54                    .collect::<Vec<(i32, i32)>>();
55                result = new_result;
56                sum -= x;
57            }
58        });
59        result
60            .iter()
61            .filter(|&&(left, right)| left == right)
62            .collect::<Vec<_>>()
63            .len()
64            != 0
65    }
66
67    //  NOTE    ::  This function cannot produce false positive!
68    pub fn can_partition_sort_and_try(mut nums: Vec<i32>) -> bool {
69        nums.sort_by(|x, y| y.cmp(x));
70        nums.iter().fold(0, |acc, &x| match acc > 0 {
71            true => acc - x,
72            false => acc + x,
73        }) == 0
74    }
75
76    //  NOTE    ::  This implementation is horse-crap :3
77    pub fn can_partition_odd_even_counter(nums: Vec<i32>) -> bool {
78        // Must sanitize
79        let sum: i32 = nums.iter().sum();
80        let sanitize = nums.iter().fold(true, |acc, &x| acc && (sum - x) >= x);
81        if !sanitize {
82            return false;
83        }
84        // Perform actual algorithm...
85        let (mut twos, mut ones) = (0, 0);
86        nums.iter().for_each(|&x| match x % 2 == 0 {
87            true => {
88                twos += x / 2;
89            }
90            false => {
91                ones += 1;
92                twos += (x - 1) / 2;
93            }
94        });
95        if twos % 2 != 0 && ones >= 2 {
96            twos -= 1;
97            ones -= 2;
98        }
99        twos % 2 == 0 && ones % 2 == 0
100    }
101
102    pub fn can_partition_dp_top_down(
103        nums: &Vec<i32>,
104        start_from: usize,
105        whats_left: i32,
106        goal_amount: i32,
107    ) -> bool {
108        // Exit if we have ran through every possible integers
109        if start_from >= nums.len() {
110            return false;
111
112        // Exit if the goal amount is larger than whats left in the array, meaning even if we
113        // consider every element afterwards, we will still fail
114        } else if goal_amount > whats_left {
115            return false;
116
117        // Exit with true if considering this value means that we found a summation that yields
118        // whats left of sum/2 after all the considerations made beforehand.
119        } else if goal_amount == whats_left {
120            return true;
121        } else {
122            // Else, generate 2 recursive calls that:
123            // 1. considers this value (if possible)
124            // 2. does not consider this value
125            // And returning the OR or those calls.
126            let next_start_from = start_from + 1;
127            let current_value = nums[start_from];
128            let next_whats_left = whats_left - current_value;
129            match goal_amount.cmp(&current_value) {
130                std::cmp::Ordering::Greater => {
131                    return Solution::can_partition_dp_top_down(
132                        &nums,
133                        next_start_from,
134                        next_whats_left,
135                        goal_amount - current_value,
136                    ) || Solution::can_partition_dp_top_down(
137                        &nums,
138                        next_start_from,
139                        next_whats_left,
140                        goal_amount,
141                    );
142                }
143                std::cmp::Ordering::Equal => {
144                    return true;
145                }
146                std::cmp::Ordering::Less => {
147                    return Solution::can_partition_dp_top_down(
148                        &nums,
149                        next_start_from,
150                        next_whats_left,
151                        goal_amount,
152                    );
153                }
154            }
155        }
156    }
157
158    pub fn can_partition(mut nums: Vec<i32>) -> bool {
159        let sum: i32 = nums.iter().sum();
160        if sum % 2 != 0 {
161            false
162        } else {
163            nums.sort_by(|x, y| y.cmp(x));
164            Solution::can_partition_dp_top_down(&nums, 0, sum, sum / 2)
165        }
166    }
167}
168
169#[test]
170fn problem_416_test() {
171    assert_eq!(Solution::can_partition(vec![1, 5, 11, 5]), true);
172    assert_eq!(Solution::can_partition(vec![5, 3, 4, 4]), true);
173    assert_eq!(Solution::can_partition(vec![3, 3, 1, 94]), false);
174    assert_eq!(Solution::can_partition(vec![5, 3, 1, 4]), false);
175    assert_eq!(Solution::can_partition(vec![3, 3, 3, 4, 5]), true);
176    assert_eq!(Solution::can_partition(vec![1, 2, 5]), false);
177    assert_eq!(
178        Solution::can_partition(vec![
179            100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
180            100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
181            100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
182            100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
183            100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
184            100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100
185        ]),
186        true
187    );
188    assert_eq!(Solution::can_partition(vec![2, 2, 3, 5]), false);
189    assert_eq!(
190        Solution::can_partition(vec![
191            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
192            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
193            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
194            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 100
195        ]),
196        false
197    );
198}
199
200#[test]
201pub fn problem_416_failing() {}