Skip to content

1262. Greatest Sum Divisible by Three

Description

Given an integer array nums, return the maximum possible sum of elements of the array such that it is divisible by three.

 

Example 1:

Input: nums = [3,6,5,1,8]
Output: 18
Explanation: Pick numbers 3, 6, 1 and 8 their sum is 18 (maximum sum divisible by 3).

Example 2:

Input: nums = [4]
Output: 0
Explanation: Since 4 is not divisible by 3, do not pick any number.

Example 3:

Input: nums = [1,2,3,4,4]
Output: 12
Explanation: Pick numbers 1, 3, 4 and 4 their sum is 12 (maximum sum divisible by 3).

 

Constraints:

  • 1 <= nums.length <= 4 * 104
  • 1 <= nums[i] <= 104

Solutions

Solution 1: Dynamic Programming

Thinking

We want the maximum subsequence sum divisible by \(3\). \(n \le 4\times 10^4\) forbids subsets. A sum has only three remainders modulo \(3\), and taking or skipping the current value moves among those three.

\(f[i][j]\) is the best sum of the first \(i\) numbers with remainder \(j\). Skip inherits; take adds \(x\) from remainder \(j-x\). The answer is \(f[n][0]\). Remainders collapse the constraint to a constant number of states.

We define \(f[i][j]\) as the maximum sum of several numbers selected from the first \(i\) numbers, such that the sum modulo \(3\) equals \(j\). Initially, \(f[0][0]=0\), and the rest are \(-\infty\).

For \(f[i][j]\), we can consider the state of the \(i\)th number \(x\):

  • If we do not select \(x\), then \(f[i][j]=f[i-1][j]\);
  • If we select \(x\), then \(f[i][j]=f[i-1][(j-x \bmod 3 + 3)\bmod 3]+x\).

Therefore, we can get the state transition equation:

\[ f[i][j]=\max\{f[i-1][j],f[i-1][(j-x \bmod 3 + 3)\bmod 3]+x\} \]

The final answer is \(f[n][0]\).

The time complexity is \(O(n)\), and the space complexity is \(O(n)\). Where \(n\) is the length of the array \(nums\).

1
2
3
4
5
6
7
8
9
class Solution:
    def maxSumDivThree(self, nums: List[int]) -> int:
        n = len(nums)
        f = [[-inf] * 3 for _ in range(n + 1)]
        f[0][0] = 0
        for i, x in enumerate(nums, 1):
            for j in range(3):
                f[i][j] = max(f[i - 1][j], f[i - 1][(j - x) % 3] + x)
        return f[n][0]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
    public int maxSumDivThree(int[] nums) {
        int n = nums.length;
        final int inf = 1 << 30;
        int[][] f = new int[n + 1][3];
        f[0][1] = f[0][2] = -inf;
        for (int i = 1; i <= n; ++i) {
            int x = nums[i - 1];
            for (int j = 0; j < 3; ++j) {
                f[i][j] = Math.max(f[i - 1][j], f[i - 1][(j - x % 3 + 3) % 3] + x);
            }
        }
        return f[n][0];
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution {
public:
    int maxSumDivThree(vector<int>& nums) {
        int n = nums.size();
        const int inf = 1 << 30;
        int f[n + 1][3];
        f[0][0] = 0;
        f[0][1] = f[0][2] = -inf;
        for (int i = 1; i <= n; ++i) {
            int x = nums[i - 1];
            for (int j = 0; j < 3; ++j) {
                f[i][j] = max(f[i - 1][j], f[i - 1][(j - x % 3 + 3) % 3] + x);
            }
        }
        return f[n][0];
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func maxSumDivThree(nums []int) int {
    n := len(nums)
    const inf = 1 << 30
    f := make([][3]int, n+1)
    f[0] = [3]int{0, -inf, -inf}
    for i, x := range nums {
        i++
        for j := 0; j < 3; j++ {
            f[i][j] = max(f[i-1][j], f[i-1][(j-x%3+3)%3]+x)
        }
    }
    return f[n][0]
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function maxSumDivThree(nums: number[]): number {
    const n = nums.length;
    const inf = 1 << 30;
    const f: number[][] = Array(n + 1)
        .fill(0)
        .map(() => Array(3).fill(-inf));
    f[0][0] = 0;
    for (let i = 1; i <= n; ++i) {
        const x = nums[i - 1];
        for (let j = 0; j < 3; ++j) {
            f[i][j] = Math.max(f[i - 1][j], f[i - 1][(j - (x % 3) + 3) % 3] + x);
        }
    }
    return f[n][0];
}

Solution 2: Dynamic Programming (Rolling Array)

Thinking

Solution 1 stores \(O(n)\) rows. Row \(i\) reads only three previous values, so a length-\(3\) rolling array suffices. Extra space is constant; the transition is unchanged.

\(f[i][j]\) depends only on the previous row's three residues, so an array of length \(3\) is enough. The space complexity is \(O(1)\).

1
2
3
4
5
6
7
8
9
class Solution:
    def maxSumDivThree(self, nums: List[int]) -> int:
        f = [0, -inf, -inf]
        for x in nums:
            g = f[:]
            for j in range(3):
                g[j] = max(f[j], f[(j - x) % 3] + x)
            f = g
        return f[0]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
    public int maxSumDivThree(int[] nums) {
        final int inf = 1 << 30;
        int[] f = new int[] {0, -inf, -inf};
        for (int x : nums) {
            int[] g = f.clone();
            for (int j = 0; j < 3; ++j) {
                g[j] = Math.max(f[j], f[(j - x % 3 + 3) % 3] + x);
            }
            f = g;
        }
        return f[0];
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    int maxSumDivThree(vector<int>& nums) {
        const int inf = 1 << 30;
        vector<int> f = {0, -inf, -inf};
        for (int& x : nums) {
            vector<int> g = f;
            for (int j = 0; j < 3; ++j) {
                g[j] = max(f[j], f[(j - x % 3 + 3) % 3] + x);
            }
            f = move(g);
        }
        return f[0];
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func maxSumDivThree(nums []int) int {
    const inf = 1 << 30
    f := [3]int{0, -inf, -inf}
    for _, x := range nums {
        g := [3]int{}
        for j := range f {
            g[j] = max(f[j], f[(j-x%3+3)%3]+x)
        }
        f = g
    }
    return f[0]
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function maxSumDivThree(nums: number[]): number {
    const inf = 1 << 30;
    const f: number[] = [0, -inf, -inf];
    for (const x of nums) {
        const g = [...f];
        for (let j = 0; j < 3; ++j) {
            f[j] = Math.max(g[j], g[(j - (x % 3) + 3) % 3] + x);
        }
    }
    return f[0];
}

Comments