leetcode/16: brute and double pointer solutions#383
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new solution for the "3Sum Closest" LeetCode problem (Algorithm 16), featuring both brute-force and double-pointer implementations, accompanied by tests and documentation. It also applies minor idiomatic refactorings across several existing LeetCode solutions (Algorithms 1697, 2322, 2353, 502, and 721) to simplify iterators, sorting, and map operations. The review feedback highlights critical safety improvements in the new implementations: specifically, addressing a potential integer underflow in the double-pointer solution when the input has fewer than two elements, and replacing unsafe unwrap() calls with unwrap_or(0) to prevent panics on small inputs. Additionally, using Option::map_or is recommended to make the code more concise and idiomatic.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| let mut answer = None; | ||
| for i in 0..nums.len() { | ||
| for j in i + 1..nums.len() { | ||
| for k in j + 1..nums.len() { | ||
| let sum = nums[i] + nums[j] + nums[k]; | ||
| let Some(current) = answer else { | ||
| answer = Some(sum); | ||
| continue; | ||
| }; | ||
| if sum.abs_diff(target) < current.abs_diff(target) { | ||
| answer = Some(sum); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| answer.unwrap() |
There was a problem hiding this comment.
The current implementation can be simplified and made safer. Using Option::map_or allows us to express the conditional update of answer more concisely and idiomatically, avoiding the let Some(...) else block and continue. Additionally, using unwrap_or(0) instead of unwrap() prevents potential panics if the input slice has fewer than 3 elements.
let mut answer = None;
for i in 0..nums.len() {
for j in i + 1..nums.len() {
for k in j + 1..nums.len() {
let sum = nums[i] + nums[j] + nums[k];
if answer.map_or(true, |ans| sum.abs_diff(target) < ans.abs_diff(target)) {
answer = Some(sum);
}
}
}
}
answer.unwrap_or(0)| let mut answer = None; | ||
| for i in 0..nums.len() - 2 { | ||
| let mut left = i + 1; | ||
| let mut right = nums.len() - 1; | ||
| while left < right { | ||
| let current = nums[i] + nums[left] + nums[right]; | ||
| match target.cmp(¤t) { | ||
| Ordering::Less => right -= 1, | ||
| Ordering::Greater => left += 1, | ||
| Ordering::Equal => return target, | ||
| } | ||
| let Some(current_answer) = answer else { | ||
| answer = Some(current); | ||
| continue; | ||
| }; | ||
| if current_answer.abs_diff(target) > current.abs_diff(target) { | ||
| answer = Some(current); | ||
| } | ||
| } | ||
| } | ||
| answer.unwrap() |
There was a problem hiding this comment.
If nums.len() < 2, the expression nums.len() - 2 will underflow and cause a panic in debug mode. We can prevent this by using nums.len().saturating_sub(2). Additionally, we can simplify the conditional update of answer using Option::map_or and use unwrap_or(0) to make the function completely panic-free.
let mut answer = None;
for i in 0..nums.len().saturating_sub(2) {
let mut left = i + 1;
let mut right = nums.len() - 1;
while left < right {
let current = nums[i] + nums[left] + nums[right];
match target.cmp(¤t) {
Ordering::Less => right -= 1,
Ordering::Greater => left += 1,
Ordering::Equal => return target,
}
if answer.map_or(true, |ans| current.abs_diff(target) < ans.abs_diff(target)) {
answer = Some(current);
}
}
}
answer.unwrap_or(0)
No description provided.