20.环形子数组的最大和(medium)

1.题目链接:

918. 环形子数组的最大和 - 力扣(LeetCode)918. 环形子数组的最大和 - 给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], ..., nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。 示例 1:输入:nums = [1,-2,3,-2]输出:3解释:从子数组 [3] 得到最大和 3示例 2:输入:nums = [5,-3,5]输出:10解释:从子数组 [5,5] 得到最大和 5 + 5 = 10示例 3:输入:nums = [3,-2,2,-3]输出:3解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3 提示: * n == nums.length * 1 <= n <= 3 * 104 * -3 * 104 <= nums[i] <= 3 * 104https://leetcode.cn/problems/maximum-sum-circular-subarray/description/2.题目描述:

给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。​
    环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i +     1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。​
    子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 nums[i], nums[i +          1], ..., nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n 。​
    示例 1:​
               输入:nums = [1,-2,3,-2]​
               输出:3​
    解释:

           从子数组 [3] 得到最大和 3​
示例 2:​
           输入:nums = [5,-3,5]​
           输出:10​
解释:

               从子数组 [5,5] 得到最大和 5 + 5 = 10​
3. 解法(动态规划):

算法思路:
        本题与「最大子数组和」的区别在于,考虑问题的时候不仅要分析「数组内的连续区域」,还要考   虑「数组首尾相连」的一部分。结果的可能情况分为以下两种:
                 i.     结果在数组的内部,包括整个数组;
                 ii. 结果在数组首尾相连的一部分上。

其中,对于第一种情况,我们仅需按照「最大子数组和」的求法就可以得到结果,记为 fmax 。​对于第二种情况,我们可以分析一下:

i.

如果数组首尾相连的一部分是最大的数组和,那么数组中间就会空出来一部分;

  ii. 因为数组的总和 sum  是不变的,那么中间连续的一部分的和一定是最小的;​因此,我们就可以得出一个结论,对于第二种情况的最大和,应该等于 sum - gmin ,其中 gmin  表示数组内的「最小子数组和」。​
两种情况下的最大值,就是我们要的结果。

但是,由于数组内有可能全部都是负数,第一种情况下的结果是数组内的最大值(是个负数),第二种情况下的 gmin == sum ,求的得结果就会是 0 。若直接求两者的最大值,就会是 0 。但是实际的结果应该是数组内的最大值。对于这种情况,我们需要特殊判断一下。

        由于「最大子数组和」的方法已经讲过,这里只提一下「最小子数组和」的求解过程,其实与「最       大子数组和」的求法是一致的。用 f  表示最大和,g  表示最小和。​
1. 状态表示:
          g[i]  表示:以 i  做结尾的「所有子数组」中和的最小值。​

2. 状态转移方程:
          g[i]  的所有可能可以分为以下两种:​

i.

子数组的长度为 1 :此时 g[i] = nums[i] ;​

  ii. 子数组的长度大于 1 :此时 g[i]  应该等于 以 i - 1  做结尾的「所有子数组」中和的            最小值再加上 nums[i] ,也就是 g[i - 1] + nums[i] 。​
由于我们要的是最小子数组和,因此应该是两种情况下的最小值,因此可得转移方程:
g[i] = min(nums[i], g[i - 1] + nums[i])

3. 初始化:
        可以在最前面加上一个辅助结点,帮助我们初始化。使用这种技巧要注意两个点:      i.     辅助结点里面的值要保证后续填表是正确的;

ii. 下标的映射关系。

在本题中,最前面加上一个格子,并且让 g[0] = 0  即可。​

4. 填表顺序:

根据状态转移方程易得,填表顺序为「从左往右」。

5. 返回值:

a. 先找到 f  表里面的最大值 -> fmax ;​

b. 找到 g  表里面的最小值 -> gmin ;​

c. 统计所有元素的和 -> sum ;​

b. 返回 sum == gmin ? fmax : max(fmax, sum - gmin) 。​

Java算法代码:

class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        // 1.创建dp表
        // 2.初始化
        // 3.填表
        // 4.返回值
        int n = nums.length;
        int[] f = new int[n+1];
        int[] g = new int[n+1];
        int sum = 0,fmax= Integer.MIN_VALUE,gmin=Integer.MAX_VALUE;
        for(int i = 1; i <= n; i++){
            int x = nums[i-1];
            f[i] = Math.max(x,x + f[i-1]);
            fmax = Math.max(fmax,f[i]);
            g[i] = Math.min(x,x + g[i-1]);
            gmin = Math.min(gmin,g[i]);
            sum +=x;
        }
        return sum == gmin ? fmax : Math.max(fmax,sum - gmin);
    }
}

执行结果:

动态规划:

STM32环形队列是一种用于解决串口接收数据处理速度小于数据接收速度的问题的缓存机制。它通过使用带有头指针和尾指针的数组来实现。头指针指向环形缓冲区中可读的数据,尾指针指向环形缓冲区中可写的缓冲空间。当串口接收到新的数据时,将数据保存到环形缓冲区中,并将尾指针加1以保存下一个数据。应用程序在读取数据时,将头指针加1以读取下一个数据。当尾指针超过数组大小时,尾指针重新指向数组的首元素,从而形成环形缓冲区。有效数据区域在头指针和尾指针之间。这样,未来得及处理的数据可以被缓存起来,待系统空闲时再进行处理,从而避免数据丢失现象的发生。\[2\] 在STM32中,可以使用相应的函数来实现环形队列的操作。例如,可以使用ReadRingBuffer函数从环形队列中读取指定长度的字节数据。该函数会遍历环形队列,将每个字节读取到指定的缓冲区中。如果环形队列为空或者指针为空,函数会打印相应的错误信息并返回。\[1\] 另外,可以使用WriteOneByteToRingBuffer函数将一个字节的数据写入环形队列。在写入之前,函数会先判断队列是否已满。如果队列已满,则函数会返回FALSE,表示写入失败。否则,函数会将数据写入队列,并更新尾指针。为了防止越界,尾指针会通过取模运算来保证在环形缓冲区的范围内。函数会返回TRUE,表示写入成功。\[3\] #### 引用[.reference_title] - *1* *3* [基于STM32 环形队列来实现串口接收数据](https://blog.csdn.net/u012846795/article/details/126080189)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [基于STM32的串口数据环形缓冲队列](https://blog.csdn.net/Utotao/article/details/88700959)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值