法一:递推
class Solution { public: //在删掉元素的结果数组中,最长的且只包含 1 的非空子数组存在两种情况: //1.这个子数组在原数组中本身就是连续的,无论删或者不删其他的元素,它都是最长的且只包含 1 的非空子数组; //2.这个子数组原本不连续,而是两个连续的全 1 子数组,中间夹着一个 0,把这个 0 删掉以后,左右两个子数组组合成一个最长的且只包含 1 的非空子数组。 //我们可以枚举被删除的位置,假设下标为 i,我们希望知道「以第 i−1 位结尾的最长连续全 1 子数组」和「以第 i+1 位开头的最长连续全 1 子数组」的长度分别是多少 //这两个量的和就是删除第 i 位之后最长的且只包含 1 的非空子数组的长度。假设我们可以得到这两个量,我们只要枚举所有的 i,就可以得到最终的答案。 //我们可以对原数组做一次正向遍历,预处理出 pre,再做一次反向遍历,预处理出 suf。 //最后我们枚举所有的元素作为待删除的元素,计算出删除这些元素之后最长的且只包含 1 的非空子数组的长度,比较并取最大值。 int longestSubarray(vector<int>& nums) { int size = nums.size(),resMax = 0; vector<int> pre(size),suf(size); pre[0] = nums[0];//数组pre[i]表示以 pre[i] 结尾的最长连续 1 的长度 for(int i = 1;i < size;i++){ if(nums[i] == 0) pre[i] = 0; else pre[i] = pre[i-1] + 1; } suf[size - 1] = nums[size - 1];//suf[i]表示以 suf[i] 开头的最长连续 1 的长度 for(int i = size-2;i >= 0;i--){ if(nums[i] == 0) suf[i] = 0; else suf[i] = suf[i+1] + 1; } for(int i = 0;i < size;i++){ int preSum,sufSum; if(i == 0) preSum = 0;//单防i = 0 else preSum = pre[i-1]; if(i == size-1) sufSum = 0;//单防i = size-1 else sufSum = suf[i+1]; resMax = max(resMax,preSum + sufSum); } return resMax; } };
法二:递推优化
class Solution { public: //进一步优化,使用一次递推 //记p0(i) 为「以第 i 位结尾的最长连续全 1 子数组」 //同时,我们记 p1(i) 为「以第 i 位结尾,并且可以在某个位置删除一个 0 的最长连续全 1 子数组」。 //注意这里我们规定了只删除 0,而不是任意一个元素,这是因为只要数组中的元素不全为 1,那么删除 1 就没有任何意义。 //当我们遇到 1 时,p1(i)的递推式与p0(i)相同;而当我们遇到 0 时,由于p1(i)允许删除一个 0,那么我们可以把这个 0 删除,将p0(i−1) 的值赋予p1(i)。 //最后的答案即为p1(i) 中的最大值。当遇到数组中的元素全为 1 的特殊情况时,我们需要将答案减去 1,这是因为在这种情况下,我们不得不删除一个 1。 //注意到递推式中所有的 p0(i),p1(i) 只和 p0(i−1),p1(i−1) 相关,因此我们可以直接使用两个变量进行递推,减少空间复杂度。 int longestSubarray(vector<int>& nums) { int resMax = 0,p0 = 0,p1 = 0; for(int &num : nums){ if(num == 0){ p1 = p0; p0 = 0; } else{ ++p0;++p1; } resMax = max(resMax,p1); } if(resMax == nums.size()) --resMax; return resMax; } };
标签:suf,p0,p1,resMax,删掉,1493,数组,leetcode,size From: https://www.cnblogs.com/uacs2024/p/18592516