Problem
You are given a 0-indexed array nums
consisting of positive integers. You can choose two indices i
and j
, such that i != j
, and the sum of digits of the number nums[i]
is equal to that of nums[j]
.
Return the maximum value of nums[i] + nums[j]
that you can obtain over all possible indices i
and j
that satisfy the conditions.
Examples
Example 1:
Input: nums = [18,43,36,13,7]
Output: 54
Explanation: The pairs (i, j) that satisfy the conditions are:
- (0, 2), both numbers have a sum of digits equal to 9, and their sum is 18 + 36 = 54.
- (1, 4), both numbers have a sum of digits equal to 7, and their sum is 43 + 7 = 50.
So the maximum sum that we can obtain is 54.
Example 2:
Input: nums = [10,12,19,14]
Output: -1
Explanation: There are no two numbers that satisfy the conditions, so we return -1.
Constraints:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
Solution
Video explanation
Here is the video explaining below methods in detail. Please check it out:
Method 1 - Using Hashmap
The task is to find the maximum possible sum of two numbers in the array, nums
, such that their sum of digits is equal. This boils down to grouping numbers by their sum of digits and finding the two largest numbers in each group, if there are at least two numbers in that group.
Approach
- Step 1: Helper Function for Digit Sum - Calculate the sum of digits for a given number. This will be used to group numbers with the same digit sum.
- Step 2: Group Numbers by Digit Sum - Use a
HashMap
(in Java) ordefaultdict
(in Python) to store numbers based on their sum of digits as the key. - Step 3: Find Max Pair in Each Group - For each sum of digits, check if there are at least two numbers in that group. If so, find the two largest numbers and compute their sum. Keep track of the maximum sum across all groups.
Code
Java
class Solution {
public int maximumSum(int[] nums) {
Map<Integer, List<Integer>> groups = new HashMap<>();
// Group numbers by their digit_sum
for (int num : nums) {
int digitSum = sumDigits(num);
groups.putIfAbsent(digitSum, new ArrayList<>());
groups.get(digitSum).add(num);
}
int ans = -1;
// Iterate through each group
for (List<Integer> grp : groups.values()) {
if (grp.size() > 1) {
// Sort the group in descending order
Collections.sort(grp, Collections.reverseOrder());
ans = Math.max(ans, grp.get(0) + grp.get(1));
}
}
return ans;
}
// Helper function to calculate digit sum
private int sumDigits(int num) {
int ans = 0;
while (num > 0) {
ans += num % 10;
num /= 10;
}
return ans;
}
}
Python
class Solution:
def maximumSum(self, nums: List[int]) -> int:
def sum_digits(x: int) -> int:
"""Helper function to calculate the sum of digits of x."""
return sum(int(d) for d in str(x))
groups: defaultdict[int, List[int]] = defaultdict(list)
# Group numbers by their digit_sum
for num in nums:
digit_sum = sum_digits(num)
groups[digit_sum].append(num)
ans = -1
# Iterate through each group
for grp in groups.values():
if len(grp) > 1:
# Find the two largest numbers in the group
grp.sort(reverse=True)
ans = max(ans, grp[0] + grp[1])
return ans
Complexity
- ⏰ Time complexity:
O(n (log n + k))
, wheren
is the number of elements andk
is the number of digits in the largest number. - Finding the two largest numbers in each group:O(n)
combined. - 🧺 Space complexity:
O(n)
due to space used by the dictionary to group numbers
Method 2 - Two pass and Store just the pair
We don’t need to store all the groups. We can just keep 2
largest numbers. Hence, we can optimize the above code from time O(nlogn)
to O(n)
.
Code
Java
class Solution {
public int maximumSum(int[] nums) {
Map<Integer, List<Integer>> groups = new HashMap<>();
for (int n : nums) {
int digitSum = sumDigits(n);
groups.computeIfAbsent(digitSum, l -> new ArrayList<>()).add(n);
Collections.sort(groups.get(digitSum));
if (groups.get(digitSum).size() > 2) {
groups.get(digitSum).remove(0);
}
}
int max = -1;
for (List<Integer> l : groups.values()) {
if (l.size() == 2) {
max = Math.max(max, l.get(0) + l.get(1));
}
}
return max;
}
private int sumDigits(int num) {
int ans = 0;
while (num > 0) {
ans += num % 10;
num /= 10;
}
return ans;
}
}
Python
class Solution:
def maximumSum(self, nums: List[int]) -> int:
def sum_digits(num: int) -> int:
"""Helper function to compute the sum of digits of a number."""
ans = 0
while num > 0:
ans += num % 10
num //= 10
return ans
groups: Dict[int, List[int]] = defaultdict(list)
for n in nums:
digit_sum = sum_digits(n)
groups[digit_sum].append(n)
# Sort the group and maintain only the two largest elements
groups[digit_sum].sort()
if len(groups[digit_sum]) > 2:
groups[digit_sum].pop(0)
max_val = -1
for l in groups.values():
if len(l) == 2:
max_val = max(max_val, l[0] + l[1])
return max_val
Complexity
- ⏰ Time complexity:
O(n * k)
, as now sorting 2 elements takes constantO(2 log 2)
time. - 🧺 Space complexity:
O(n)
Method 3 - One Pass and store the pair
We dont need to run the loop twice to calculate the maximum. We can calculate the maximum in first iteration itself.
Code
Java
class Solution {
public int maximumSum(int[] nums) {
Map<Integer, List<Integer>> groups = new HashMap<>();
int max = -1;
for (int num : nums) {
int digitSum = sumDigits(num);
groups.computeIfAbsent(digitSum, l -> new ArrayList<>()).add(num);
List<Integer> list = groups.get(digitSum);
Collections.sort(list);
if (list.size() > 2) {
list.remove(0);
}
if (list.size() == 2) {
max = Math.max(max, list.get(0) + list.get(1));
}
}
return max;
}
private int sumDigits(int num) {
int ans = 0;
while (num > 0) {
ans += num % 10;
num /= 10;
}
return ans;
}
}
Python
class Solution:
def maximumSum(self, nums: List[int]) -> int:
def sum_digits(num: int) -> int:
"""Helper function to compute the sum of digits of a number."""
ans = 0
while num > 0:
ans += num % 10
num //= 10
return ans
groups = defaultdict(list) # Store numbers grouped by their digit sums
max_sum = -1
for num in nums:
digit_sum = sum_digits(num)
groups[digit_sum].append(num)
groups[digit_sum].sort() # Sort the group to keep the largest two numbers
# If the group has more than two elements, remove the smallest one
if len(groups[digit_sum]) > 2:
groups[digit_sum].pop(0)
# If the group has exactly two elements, calculate their sum
if len(groups[digit_sum]) == 2:
max_sum = max(max_sum, groups[digit_sum][0] + groups[digit_sum][1])
return max_sum
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(n)
Method 4 - One pass using max value
To solve the problem in a single pass, we can exploit the fact that the maximum sum of two numbers with the same digit sum will always involve the two largest numbers with that digit sum. The key idea is to:
- Keep track of only the largest number encountered so far for each digit sum.
- For each new number, check if adding it to the currently stored largest number for the same digit sum gives a new maximum.
This approach ensures that we only ever inspect relevant pairs and avoids unnecessary storage or processing of additional numbers.
Approach:
- Digit Sum Calculation:
- Write a helper method,
sumDigits
, that computes the sum of the digits of a number. This enables grouping of numbers by their digit sums.
- Write a helper method,
- Map Storage:
- Use a
HashMap
(orMap
) to map each digit sum to the largest number encountered so far with that digit sum.
- Use a
- Iterate Through the Array:
- For each number in
nums
, calculate its digit sum. - Check the map for an existing entry for this digit sum:
- If present, compute the sum of the current number and the stored value. Update the
result
value if this computed sum is larger.
- If present, compute the sum of the current number and the stored value. Update the
- Update the map entry for this digit sum with the larger of the current number or the stored value.
- For each number in
- Return the Result:
- After iterating through all elements, the
result
variable should hold the maximum sum of two numbers with the same digit sum. If no such pair exists, it will remain-1
.
- After iterating through all elements, the
Code
Java
class Solution {
public int maximumSum(int[] nums) {
int ans = -1;
Map<Integer, Integer> digitSumToMax = new HashMap<>();
for (int num : nums) {
int digitSum = sumDigits(num);
// Check if a number with this digit sum already exists in the map
if (digitSumToMax.containsKey(digitSum)) {
// Calculate the sum of the current number and the largest number with the same digit sum
ans = Math.max(ans, digitSumToMax.get(digitSum) + num);
}
// Update the mapping to keep the larger of the current or previous value for this digit sum
digitSumToMax.put(digitSum, Math.max(digitSumToMax.getOrDefault(digitSum, 0), num));
}
return ans;
}
private int sumDigits(int num) {
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}
}
Python
class Solution:
def maximumSum(self, nums: List[int]) -> int:
ans = -1
digitSumToMax = {}
for num in nums:
digit_sum = self.sum_digits(num)
# Check if a number with this digit sum already exists in the map
if digit_sum in digitSumToMax:
# Calculate the sum of the current number and the largest number with the same digit sum
ans = max(ans, digitSumToMax[digit_sum] + num)
# Update the mapping to keep the larger of the current or previous value for this digit sum
digitSumToMax[digit_sum] = max(digitSumToMax.get(digit_sum, 0), num)
return ans
def sum_digits(self, num: int) -> int:
digit_sum = 0
while num > 0:
digit_sum += num % 10
num //= 10
return digit_sum