【算法】Greatest Sum Divisible by Three 可被三整除的最大和- 动态规划

文章目录

  • Greatest Sum Divisible by Three 可被三整除的最大和-动态规划
    • 问题描述:
    • 分析
    • 代码
    • Tag

Greatest Sum Divisible by Three 可被三整除的最大和-动态规划

问题描述:

给你一个整数数组 nums,请你找出并返回能被三整除的元素最大和。

nums.length 范围[1,40000] , n u m s [ i ] nums[i] nums[i] 范围[1,10000]

分析

贪心策略的减法,虽然时间复杂度和操作性简单,但是适用性并不广泛。
以01背包的思路来思考这个问题,对于 a [ i ] a[i] a[i]来说,如果选择,而 a [ i ] m o d    3 = = k a[i]\mod3==k a[i]mod3==k,即 k = 0 , 1 , 2 k=0,1,2 k=0,1,2.
如果 k=0,需要找到 0 → i − 1 0\rightarrow i-1 0i1的最大和 s m o d    3 = = 0 s\mod3==0 smod3==0
如果 k=1,需要找到 0 → i − 1 0\rightarrow i-1 0i1的最大和 s m o d    3 = = 2 s\mod3==2 smod3==2
如果 k=2,需要找到 0 → i − 1 0\rightarrow i-1 0i1的最大和 s m o d    3 = = 1 s\mod3==1 smod3==1
如果不选
当前的位置就对应 a [ 0 ] → a [ i − 1 ] a[0]\rightarrow a[i-1] a[0]a[i1]的最大和s。
用$f[i][j] $表示 前 0 → i − 1 0\rightarrow i-1 0i1个元素可以得到的最大和 s s s,并且 s m o d    3 = = j s\mod3==j smod3==j .
令a[i] = x
不选a[i], f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i1][j]
选a[i], f [ i ] [ j ] = f [ i − 1 ] [ ( j − x ) m o d    3 ] f[i][j]= f[i-1][(j-x)\mod3] f[i][j]=f[i1][(jx)mod3]

( s + x ) m o d    3 = = j 转换 s m o d    3 = = ( ( j − x ) m o d    3 + 3 ) m o d    3 (s+x)\mod 3==j \\ 转换\\ s\mod 3 == ((j-x)\mod 3 + 3)\mod 3 \\ (s+x)mod3==j转换smod3==((jx)mod3+3)mod3
所以状态转移方程就长这个样子。

f [ i ] [ j ] = max ⁡ ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ ( ( j − x ) m o d    3 + 3 ) m o d    3 ] + a [ i ] ) f[i][j] = \max (f[i-1][j],f[i-1][((j-x)\mod3+3)\mod 3] + a[i] ) f[i][j]=max(f[i1][j],f[i1][((jx)mod3+3)mod3]+a[i])
如果这个方程看不明白,也可以换个角度。
f [ i ] [ j ] f[i][j] f[i][j]定义不变
f [ i + 1 ] [ j ] = f [ i ] [ j ] f[i+1][j] = f[i][j] f[i+1][j]=f[i][j]
f [ i + 1 ] [ j ] = f [ i ] [ ( j m o d    3 + x m o d    3 ) m o d    3 ] f[i+1][j] = f[i][(j\mod3+x\mod3) \mod 3] f[i+1][j]=f[i][(jmod3+xmod3)mod3]
f [ i + 1 ] [ j ] = max ⁡ ( f [ i ] [ j ] , f [ i ] [ ( j + a [ i ] ) m o d    3 ] + a [ i ] ) f[i+1][j] = \max (f[i][j],f[i][(j+ a[i])\mod3] + a[i] ) f[i+1][j]=max(f[i][j],f[i][(j+a[i])mod3]+a[i])
为了方便计算,对原始下标做一次偏移,初始化边界 f [ 0 ] [ 0 ] = 0 , f [ 0 ] [ 1 ] = I N T M I N , f [ 0 ] [ 2 ] = I N T M I N f[0][0]=0,f[0][1]=INTMIN,f[0][2]=INTMIN f[0][0]=0,f[0][1]=INTMIN,f[0][2]=INTMIN。即 f [ i ] f[i] f[i]表示对原数组的 a [ i − 1 ] a[i-1] a[i1]元素进行处理。

代码

class Solution {
    public int maxSumDivThree(int[] nums) { 
		int n = nums.length;
        int[][] f = new int[n + 1][3];
        f[0][1] = f[0][2] = Integer.MIN_VALUE;
        for (int i = 1; i <= n; i++){ 
            for (int j = 0; j < 3; j++){ 
                f[i][j] = f[i-1][j];
                int pre = ((j-nums[i-1])%3+3)%3;
                f[i][j] = Math.max(f[i][j],f[i-1][pre] + nums[i-1]);
            }
        }         
        return f[n][0]; 
    }
}

时间复杂度O(Nk)

空间复杂度O(Nk)

public int maxSumDivThree(int[] nums) { 
		int n = nums.length;
        int[][] 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++){  
                int pre = (j+nums[i])%3;
                f[i+1][j] = Math.max(f[i][j],f[i][pre] + nums[i]);
            }
        }         
        return f[n][0]; 
    }

时间复杂度O(Nk)

空间复杂度O(Nk)

因为状态转移方程的特点,空间可以进一步压缩,使用滚动数组可以把空间压缩到 O ( k ) O(k) O(k)

Tag

Array Dynamic Programming

你可能感兴趣的:(数据结构与算法,动态规划,算法)