📌  相关文章
📜  圆形数组中的最大和,使得没有两个元素相邻 | 2套(1)

📅  最后修改于: 2023-12-03 15:23:05.701000             🧑  作者: Mango

题目描述

给定一个圆形整数数组,找到一个子数组,使得该子数组的元素之和最大,要求不能选择相邻的两个元素。

解题思路

两套解法:动态规划和状态压缩。

动态规划

首先,我们可以将圆形数组转化为一条直线数组,令 $dp[i]$ 表示以第 $i$ 个数字为结尾的最大子序和,则:

$$ dp[i] = \max{dp[i-2]+nums[i], dp[i-3]+nums[i]} $$

其中 $nums$ 为原始数组,如果我们选择了第 $i$ 个数字,则不能选择第 $i-1$ 个数字。因此,我们将状态分为两种情况:选择了 $i$ 和未选择 $i$。未选择 $i$ 的情况包括 $i-1$ 是否选择都可以。

因为该数组是圆形的,所以我们需要分别处理两种情况:不选数组的第一个和最后一个元素。最终的答案即为:

$$ \max{dp[n-1], dp[n-2]} $$

其中 $n$ 为数组长度。

时间复杂度:$O(n)$

状态压缩

第二种方法是使用状态压缩。我们可以将每个元素分为两种状态:包含和不包含。用 $S$ 表示一个状态,则:

$$ S = (S << 1) & k + nums[i] $$

其中 $<<$ 表示左移操作,$&$ 表示按位与操作,$k$ 是一个二进制数,表示最多相邻的 $1$ 的个数。由于 $nums[i]$ 的取值范围为 $[-10000, 10000]$,所以 $k$ 的取值范围为 $[0, 14]$。

最终的答案即为:

$$ \max{dp[k], dp[k-1]} $$

其中 $dp[k]$ 表示所有状态包含 $k$ 个 $1$ 的状态的最大和,$dp[k-1]$ 表示所有状态包含 $k-1$ 个 $1$ 的状态的最大和。

时间复杂度:$O(n)$

代码实现

动态规划
def max_sum(nums):
    n = len(nums)
    
    if n == 1:
        return nums[0]
    
    dp1 = [0] * (n+1)
    dp2 = [0] * (n+1)

    dp1[0] = dp2[1] = nums[0]
    dp1[1] = nums[1]
    dp2[2] = nums[2]

    for i in range(2, n):
        dp1[i] = max(dp1[i-2]+nums[i], dp1[i-1])
        dp2[i+1] = max(dp2[i-1]+nums[i], dp2[i])

    return max(dp1[n-2], dp2[n-1])

状态压缩
def max_sum(nums):
    n = len(nums)
    
    if n == 1:
        return nums[0]
    
    dp = [0] * 2
    
    for i in range(n):
        new_dp = [0] * 2
        for j in range(2):
            s = ((dp[j] << 1) & ((1 << 15) - 1)) + nums[i]
            new_dp[s >> 14] = max(new_dp[s >> 14], dp[j] + nums[i])
        dp = new_dp

    return max(dp)

总结

本题考察了对动态规划和状态压缩的理解和应用。在解题过程中,注意考虑数组为圆形的情况,以及边界条件的处理。同时,状态转移方程也需要根据实际情况设计。最后,可以考虑使用两种方法解题,从而加深对这两种算法的理解和应用。