Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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扩展到更大的数组。所以对于本题,动态规划的思路才是更加通用的做法。