Intuition¶
For each index, prefixGcd[i] = gcd(nums[i], max of the prefix ending at i).
After sorting this array, pairs are formed as (smallest, largest), (second
smallest, second largest), and so on. The middle element is unused when n is
odd. Sum the GCD of each such pair.
Approach: Prefix Max + Sort + Two Pointers¶
- Scan
numsleft to right, tracking the running maximummaxI. Appendgcd(maxI, nums[i])toprefixGcd(fori = 0, this is justnums[0]). - Sort
prefixGcdin non-decreasing order. - With two pointers
landrfrom both ends, addgcd(prefixGcd[l], prefixGcd[r])whilel < r. - Return the accumulated sum as a 64-bit integer.
Complexity¶
- Time complexity: $$O(n \log n + n \log A)$$, where
nisnums.lengthandAis the maximum value — sorting dominates; each GCD is $$O(\log A)$$. - Space complexity: $$O(n)$$ for the
prefixGcdarray.
Code¶
Go¶
import "sort"
func gcdSum(nums []int) int64 {
n := len(nums)
maxI := 0
prefixGcd := make([]int, 0, n)
maxI = nums[0]
prefixGcd = append(prefixGcd, nums[0])
for _, num := range nums[1:] {
maxI = max(maxI, num)
prefixGcd = append(prefixGcd, gcd(maxI, num))
}
sort.Ints(prefixGcd)
ans := 0
for l, r := 0, n-1; l < r; l, r = l+1, r-1 {
ans += gcd(prefixGcd[l], prefixGcd[r])
}
return int64(ans)
}
func gcd(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
Rust¶
impl Solution {
pub fn gcd_sum(nums: Vec<i32>) -> i64 {
let n = nums.len();
let mut prefix_gcd = Vec::with_capacity(n);
prefix_gcd.push(nums[0]);
let mut max_i = nums[0];
for &num in nums.iter().skip(1) {
max_i = max_i.max(num);
prefix_gcd.push(Self::gcd(max_i, num));
}
prefix_gcd.sort_unstable();
let (mut l, mut r) = (0, n - 1);
let mut ans = 0;
while l < r {
ans += Self::gcd(prefix_gcd[l], prefix_gcd[r]) as i64;
l += 1;
r -= 1;
}
ans
}
pub fn gcd(mut a: i32, mut b: i32) -> i32 {
while b != 0 {
(a, b) = (b, a % b);
}
a
}
}