[LeetCode] Minimum Size Subarray Sum

简介: The problem statement has stated that there are both O(n) and O(nlogn) solutions to this problem. Let's see the O(n) solution first (taken from this link), which is pretty clever and short.

The problem statement has stated that there are both O(n) and O(nlogn) solutions to this problem. Let's see the O(n) solution first (taken from this link), which is pretty clever and short.

 1 class Solution {
 2 public:
 3     int minSubArrayLen(int s, vector<int>& nums) {
 4         int start = 0, sum = 0, minlen = INT_MAX;
 5         for (int i = 0; i < (int)nums.size(); i++) {
 6             sum += nums[i];
 7             while (sum >= s) {
 8                 minlen = min(minlen, i - start + 1);
 9                 sum -= nums[start++];
10             }
11         }
12         return minlen == INT_MAX ? 0 : minlen;
13     }
14 };

Well, you may wonder how can it be O(n) since it contains an inner while loop. Well, the key is that the while loop executes at most once for each starting position start. Then start is increased by 1 and the while loop moves to the next element. Thus the inner while loop runs at most O(n) times during the whole for loop from 0 to nums.size() - 1. Thus both the forloop and while loop has O(n) time complexity in total and the overall running time is O(n).

There is another O(n) solution in this link, which is easier to understand and prove it is O(n). I have rewritten it below.

 1 class Solution {
 2 public:
 3     int minSubArrayLen(int s, vector<int>& nums) {
 4         int n = nums.size();
 5         int left = 0, right = 0, sum = 0, minlen = INT_MAX;
 6         while (right < n) {
 7             do sum += nums[right++];
 8             while (right < n && sum < s);
 9             while (left < right && sum - nums[left] >= s)
10                 sum -= nums[left++];
11             if (sum >= s) minlen = min(minlen, right - left);
12         }
13         return minlen == INT_MAX ? 0 : minlen;
14     }
15 };

Now let's move on to the O(nlogn) solution. Well, this less efficient solution is far more difficult to come up with. The idea is to first maintain an array of accumulated summations of elements innums. Specifically, for nums = [2, 3, 1, 2, 4, 3] in the problem statement, sums = [0, 2, 5, 6, 8, 12, 15]. Then for each element in sums, if it is not less than s, we search for the first element that is greater than sums[i] - s (in fact, this is just what the upper_bound function does) in sumsusing binary search.

Let's do an example. Suppose we reach 12 in sums, which is greater than s = 7. We then search for the first element in sums that is greater than sums[i] - s = 12 - 7 = 5 and we find 6. Then we know that the elements in nums that correspond to 6, 8, 12 sum to a number 12 - 5 = 7 which is not less than s = 7. Let's check for that: 6 in sums corresponds to 1 in nums8 insums corresponds to 2 in nums12 in sums corresponds to 4 in nums1, 2, 4 sum to 7, which is 12 in sums minus 5 in sums.

We add a 0 in the first position of sums to account for cases like nums = [3], s = 3.

The code is as follows.

 1 class Solution {
 2 public:
 3     int minSubArrayLen(int s, vector<int>& nums) {
 4         vector<int> sums = accumulate(nums);
 5         int minlen = INT_MAX;
 6         for (int i = 1; i <= nums.size(); i++) {
 7             if (sums[i] >= s) {
 8                 int p = upper_bound(sums, 0, i, sums[i] - s);
 9                 if (p != -1) minlen = min(minlen, i - p + 1);
10             }
11         }
12         return minlen == INT_MAX ? 0 : minlen;
13     }
14 private:
15     vector<int> accumulate(vector<int>& nums) {
16         vector<int> sums(nums.size() + 1, 0);
17         for (int i = 1; i <= nums.size(); i++)
18             sums[i] = nums[i - 1] + sums[i - 1];
19         return sums;
20     }
21     int upper_bound(vector<int>& sums, int left, int right, int target) {
22         int l = left, r = right;
23         while (l < r) {
24             int m = l + ((r - l) >> 1);
25             if (sums[m] <= target) l = m + 1;
26             else r = m;
27         }
28         if (sums[r] > target) return r;
29         if (sums[l] > target) return l;
30         return -1;
31     }
32 };

 

目录
相关文章
Leetcode 53.Maximum Subarray
题意简单,给出一个数组,求出其中最大的子数组和。 这种简单题目背后蕴藏着很巧妙的解题方法。其实只需要遍历一次数组就可以求得解。 思路是这样的,你想想看,如果一段子数组的和是负数, 那么这一段子数组不可能是最大和数组的一部分,丢掉重新从下一个位置开始选。
53 0
LeetCode 209. Minimum Size Subarray Sum
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
128 0
LeetCode 209. Minimum Size Subarray Sum
LeetCode 152. Maximum Product Subarray
给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
60 0
LeetCode 152. Maximum Product Subarray
LeetCode 53. Maximum Subarray
给定整数数组nums,找到具有最大总和的子数组(数组要求连续)并且返回数组的和,给定的数组包含至少一个数字。
50 0
|
人工智能 C++ Python
LeetCode 961. N-Repeated Element in Size 2N Array
LeetCode 961. N-Repeated Element in Size 2N Array
198 0
|
Python
[Leetcode][python]Maximum Subarray/最大子序和
题目大意 由 N 个整数元素组成的一维数组 (A[0], A[1],…,A[n-1], A[n]),这个数组有很多连续子数组,那么其中数组之和的最大值是什么呢? 子数组必须是连续的。 不需要返回子数组的具体位置。 数组中包含:正整数,零,负整数。
112 0
Leetcode-Medium 152. Maximum Product Subarray
Leetcode-Medium 152. Maximum Product Subarray
126 0
|
4月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
5月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
69 6
|
5月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
137 2