可被三整除的最大和【LC1262】
给你一个整数数组
nums,请你找出并返回能被三整除的元素最大和。
-
思路
题目要求求出能被3整除的最大和,那么我们可以记录每种余数对应的最大和【贪心,相同余数的情况下取最大值】,那么答案即为
val[0]。枚举每一个数,将其与目前的最大和相加得到三个可能的答案,然后存入数组中记录最大值 -
实现
class Solution { public int maxSumDivThree(int[] nums) { // 哈希表 int[] val = new int[3];// 记录余数对应的最大和->那么答案即为val[0] for (int num : nums){ int a = val[0] + num; int b = val[1] + num; int c = val[2] + num; val[a % 3] = Math.max(a, val[a % 3]); val[b % 3] = Math.max(b, val[b % 3]); val[c % 3] = Math.max(c, val[c % 3]); } return val[0]; } }-
复杂度分析
- 时间复杂度:O(n)O(n)O(n)
- 空间复杂度:O(1)O(1)O(1)
-
dp:选或不选
-
思路:选或不选
-
子问题:
- 选x=nums[n−1]x=nums[n-1]x=nums[n−1],那么问题变为在nums[:n−2]nums[:n-2]nums[:n−2]中选择最大的x数之和aaa使其与nums[n−1]nums[n-1]nums[n−1]之和能够整除3【aaa和xxx的对三取余为0,那么(a+x)%3==0(a+x)\%3==0(a+x)%3==0->a%3=(0−x)%3a\%3=(0-x)\%3a%3=(0−x)%3】
- 不选nums[n−1]nums[n-1]nums[n−1],那么问题变为在nums[:n−2]nums[:n-2]nums[:n−2]中选择最大的x数之和能够整除3
- 这是一个和原问题相似的子问题,因此我们可以用递归/dp解决。
- 递归的过程中有两个变量:元素范围以及和的余数值,因此在记忆化需要用二维memo记录这两个变量固定时对应的值
-
递归函数定义:定义dfs(i,j)dfs(i,j)dfs(i,j)为从nums[0]nums[0]nums[0]至nums[i]nums[i]nums[i]中选数,**所选数字之和对3取模为jjj**时的最大和,那么dfs(n−1,0)dfs(n-1,0)dfs(n−1,0)即为答案。
-
状态转移:
- 选xxx,问题变为从nums[0]nums[0]nums[0]至nums[i−1]nums[i-1]nums[i−1]中选数,所选数字之和对3取模为jjj时的最大和
- 不选xxx,问题变为从nums[0]nums[0]nums[0]至nums[i−1]nums[i-1]nums[i−1]中选数,所选数字之和对3取模为(j+x)%3(j+x)\% 3(j+x)%3时的最大和
取最大值返回
dfs(i,j)=max(dfs(i−1,j),dfs(i−1,(j+x)%3+nums[i])) dfs(i,j)=max(dfs(i-1,j),dfs(i-1,(j+x)\%3 + nums[i])) dfs(i,j)=max(dfs(i−1,j),dfs(i−1,(j+x)%3+nums[i])) -
递归边界
- dfs(−1,0)=0dfs(-1,0)=0dfs(−1,0)=0
- dfs(−1,1)=−∞dfs(-1,1)=- \infindfs(−1,1)=−∞
- dfs(−1,2)=−∞dfs(-1,2)=- \infindfs(−1,2)=−∞
-
-
实现
class Solution { public int maxSumDivThree(int[] nums) { int n = nums.length; var memo = new int[n][3]; for (int i = 0; i < n; i++) Arrays.fill(memo[i], -1); // -1 表示没有计算过 return dfs(memo, nums, n - 1, 0); } private int dfs(int[][] memo, int[] nums, int i, int j) { if (i < 0) return j == 0 ? 0 : Integer.MIN_VALUE; if (memo[i][j] != -1) return memo[i][j]; // 之前计算过 return memo[i][j] = Math.max(dfs(memo, nums, i - 1, j), dfs(memo, nums, i - 1, (j + nums[i]) % 3) + nums[i]); } } 作者:灵茶山艾府 链接:https://leetcode.cn/problems/greatest-sum-divisible-by-three/solutions/2313700/liang-chong-suan-fa-tan-xin-dong-tai-gui-tsll/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -
递推
扩展一维找到边界
class Solution { public int maxSumDivThree(int[] nums) { int n = nums.length; var f = new int[n + 1][3]; f[0][1] = f[0][2] = Integer.MIN_VALUE; for (int i = 0; i < n; i++) for (int j = 0; j < 3; j++) f[i + 1][j] = Math.max(f[i][j], f[i][(j + nums[i]) % 3] + nums[i]); return f[n][0]; } } 作者:灵茶山艾府 链接:https://leetcode.cn/problems/greatest-sum-divisible-by-three/solutions/2313700/liang-chong-suan-fa-tan-xin-dong-tai-gui-tsll/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

文章介绍了如何解决寻找数组中能被三整除的最大和的问题。两种主要思路是贪心算法和动态规划。贪心策略是维护每个余数对应的最大和,动态规划则是通过递归或一维数组f来跟踪不同余数状态下的最大和。两种方法都以O(n)的时间复杂度和O(1)的空间复杂度实现。
16万+

被折叠的 条评论
为什么被折叠?



