Leetcode 1262. Greatest Sum Divisible by Three
Woodyiiiiiii opened this issue · comments
1262. Greatest Sum Divisible by Three
1262. Greatest Sum Divisible by Three
可被三整除的最大和——中文题解
这道题我思考了很久,觉得挺有意思的。
一开始我就想到要用余数%去排除一些元素。然后我就想着对数组排序,然后找到除以3余数为1的数与除以3余数为2的数配对,为0的数则全部加上。
但问题在于,如何选择?示例3就给了一个很好的例子,[1,2,3,4,4],答案是取[4,4,1],跳过了取2。
一、贪心 + 逆向思维
然后我又卡了很久,推翻了之前的做法。我想着不如从贪心和余数入手?首先求出所有数字之和,然后分类讨论,假设除以3为0,则直接返回结果;为1,则有两种方式,要么减去一个最小的余数为1的数字,要么减去两个余数为2的数字;为2,同理,两种方式,要么减去一个最小的余数为2的数字,要么减去两个余数为1的数字。
func maxSumDivThree(nums []int) int {
ans := 0
sort.Ints(nums)
a, b := 0, 0
c, d, cnt1, cnt2 := 0, 0, 0, 0
for i := 0; i < len(nums); i++ {
ans += nums[i]
if nums[i]%3 == 1 && a == 0 {
a = nums[i]
}
if nums[i]%3 == 2 && b == 0 {
b = nums[i]
}
if nums[i]%3 == 1 && cnt1 < 2 {
cnt1++
c += nums[i]
}
if nums[i]%3 == 2 && cnt2 < 2 {
cnt2++
d += nums[i]
}
}
//println(ans, a, b, c, d, cnt1, cnt2)
if ans%3 == 1 {
t1, t2 := ans, ans
if a != 0 {
t1 -= a
}
if cnt2 >= 2 {
t2 -= d
}
if t1 != ans && t2 != ans {
ans = max(t1, t2)
} else if t1 != ans {
ans = t1
} else {
ans = t2
}
} else if ans%3 == 2 {
t1, t2 := ans, ans
if b != 0 {
t1 -= b
}
if cnt1 >= 2 {
t2 -= c
}
if t1 != ans && t2 != ans {
ans = max(t1, t2)
} else if t1 != ans {
ans = t1
} else {
ans = t2
}
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
二、动态规划
既然有关与选择或者选或不选,那么可以用动态规划吗?
问题是,如何定义所有状态?要包含所有状态,所以不妨学习之前01字符串的解法,设长度为3的dp数组,3个位置分别表示余数为0、1、2的最大和。
状态转移:遍历数组,每次加入一个元素,就考虑在这三个状态上更新。这样能够保证每个位置的最大值,达到选择的目的。
func maxSumDivThree(nums []int) int {
dp := make([]int, 3)
for i := 0; i < len(nums); i++ {
a,b,c := dp[0] + nums[i], dp[1] + nums[i], dp[2] + nums[i]
dp[a % 3] = max(dp[a % 3], a)
dp[b % 3] = max(dp[b % 3], b)
dp[c % 3] = max(dp[c % 3], c)
}
return dp[0]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
动态规划的好处在于,可以由3扩展到更大的数组。所以对于本题,动态规划的思路才是更加通用的做法。