给定一个由N 个整数组成的数组arr[] ,任务是找到总和等于K的最小子数组的长度。
例子:
Input: arr[] = {2, 4, 6, 10, 2, 1}, K = 12
Output: 2
Explanation:
All possible subarrays with sum 12 are {2, 4, 6} and {10, 2}.
Input: arr[] = { 1, 2, 4, 3, 2, 4, 1 }, K = 7
Output: 2
朴素方法:解决问题的最简单方法是生成所有可能的子数组,并为每个子数组检查其总和是否等于K。打印所有此类子数组的最小长度。
时间复杂度: O(N 2 )
辅助空间: O(1)
高效的方法:可以使用Prefix Sum技术和HashMap进一步优化上述方法。请按照以下步骤解决问题:
- 计算每个索引的前缀总和并将(索引,前缀总和)存储为映射中的键值对。
- 遍历前缀和数组并计算前缀和与所需和之间的差值。
- 如果 HashMap 中存在差值,则表示存在一个总和等于K的子数组,然后将子数组的长度与得到的最小长度进行比较,并相应地更新最小长度。
下面是上述方法的实现:
C++
// C++ Program to implement
// the above approach
#include
using namespace std;
// Function to find the length of the
// smallest subarray with sum K
int subArraylen(int arr[], int n, int K)
{
// Stores the frequency of
// prefix sums in the array
unordered_map mp;
mp[arr[0]] = 0;
for (int i = 1; i < n; i++) {
arr[i] = arr[i] + arr[i - 1];
mp[arr[i]] = i;
}
// Initialize len as INT_MAX
int len = INT_MAX;
for (int i = 0; i < n; i++) {
// If sum of array till i-th
// index is less than K
if (arr[i] < K)
// No possible subarray
// exists till i-th index
continue;
else {
// Find the exceeded value
int x = arr[i] - K;
// If exceeded value is zero
if (x == 0)
len = min(len, i);
if (mp.find(x) == mp.end())
continue;
else {
len = min(len, i - mp[x]);
}
}
}
return len;
}
// Driver Code
int main()
{
int arr[] = { 1, 2, 4, 3, 2, 4, 1 };
int n = sizeof(arr) / sizeof(arr[0]);
int K = 7;
int len = subArraylen(arr, n, K);
if (len == INT_MAX) {
cout << "-1";
}
else {
cout << len << endl;
}
return 0;
}
Java
// Java Program to implement
// the above approach
import java.util.*;
class GFG{
// Function to find the length of the
// smallest subarray with sum K
static int subArraylen(int arr[], int n, int K)
{
// Stores the frequency of
// prefix sums in the array
HashMap mp = new HashMap();
mp.put(arr[0], 0);
for (int i = 1; i < n; i++)
{
arr[i] = arr[i] + arr[i - 1];
mp.put(arr[i], i);
}
// Initialize len as Integer.MAX_VALUE
int len = Integer.MAX_VALUE;
for (int i = 0; i < n; i++)
{
// If sum of array till i-th
// index is less than K
if (arr[i] < K)
// No possible subarray
// exists till i-th index
continue;
else
{
// Find the exceeded value
int x = K - arr[i];
// If exceeded value is zero
if (x == 0)
len = Math.min(len, i);
if (mp.containsValue(x))
continue;
else
{
len = Math.min(len, i );
}
}
}
return len;
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 1, 2, 4, 3, 2, 4, 1 };
int n = arr.length;
int K = 7;
int len = subArraylen(arr, n, K);
if (len == Integer.MAX_VALUE)
{
System.out.print("-1");
}
else
{
System.out.print(len + "\n");
}
}
}
// This code is contributed by Rohit_ranjan
Python3
# Python3 program to implement
# the above approach
from collections import defaultdict
import sys
# Function to find the length of the
# smallest subarray with sum K
def subArraylen(arr, n, K):
# Stores the frequency of
# prefix sums in the array
mp = defaultdict(lambda : 0)
mp[arr[0]] = 0
for i in range(1, n):
arr[i] = arr[i] + arr[i - 1]
mp[arr[i]] = i
# Initialize ln
ln = sys.maxsize
for i in range(n):
# If sum of array till i-th
# index is less than K
if(arr[i] < K):
# No possible subarray
# exists till i-th index
continue
else:
# Find the exceeded value
x = K - arr[i]
# If exceeded value is zero
if(x == 0):
ln = min(ln, i)
if(x in mp.keys()):
continue
else:
ln = min(ln, i - mp[x])
return ln
# Driver Code
arr = [ 1, 2, 4, 3, 2, 4, 1 ]
n = len(arr)
K = 7
ln = subArraylen(arr, n, K)
# Function call
if(ln == sys.maxsize):
print("-1")
else:
print(ln)
# This code is contributed by Shivam Singh
C#
// C# Program to implement
// the above approach
using System;
using System.Collections.Generic;
class GFG{
// Function to find the length of the
// smallest subarray with sum K
static int subArraylen(int []arr, int n, int K)
{
// Stores the frequency of
// prefix sums in the array
Dictionary mp = new Dictionary();
mp.Add(arr[0], 0);
for (int i = 1; i < n; i++)
{
arr[i] = arr[i] + arr[i - 1];
mp.Add(arr[i], i);
}
// Initialize len as int.MaxValue
int len = int.MaxValue;
for (int i = 0; i < n; i++)
{
// If sum of array till i-th
// index is less than K
if (arr[i] < K)
// No possible subarray
// exists till i-th index
continue;
else
{
// Find the exceeded value
int x = K - arr[i];
// If exceeded value is zero
if (x == 0)
len = Math.Min(len, i);
if (mp.ContainsValue(x))
continue;
else
{
len = Math.Min(len, i );
}
}
}
return len;
}
// Driver Code
public static void Main(String[] args)
{
int []arr = { 1, 2, 4, 3, 2, 4, 1 };
int n = arr.Length;
int K = 7;
int len = subArraylen(arr, n, K);
if (len == int.MaxValue)
{
Console.Write("-1");
}
else
{
Console.Write(len + "\n");
}
}
}
// This code is contributed by Rohit_ranjan
Javascript
C++
// C++ implementation of problem to find a sub-array with
// given sum.
#include
using namespace std;
// Implementation function
void smallestSubArrayWithGivenSum(vector& arr,
int reqSum)
{
// There would be no sub-array as an answer
// if the array in the question is empty.
if (arr.size() == 0) {
cout << "There exists no sub-array with sum="
<< reqSum << "\n";
return;
}
// Initializing variables.
int len = INT_MAX, left = 0, right = 0, startIndex = -1,
currSum = arr[0], n = arr.size();
// Traversing the array.
while (right < n) {
// When both the index-holders have
// the same value.
if (left == right) {
// Modifying length and startingIndex
// both both 'left' and 'right' are
// same and have the value of the
// required sum.
if (currSum == reqSum) {
len = min(1, len);
startIndex = left;
}
// Incrementing 'right; and adding the
// value at that index to the current
// sum.
right++;
currSum += arr[right];
continue;
}
// Dropping the element at index 'left'
// from the current sum if current sum
// becomes greater than the required value.
if (currSum > reqSum) {
currSum -= arr[left];
left++;
}
else {
// Modifying length and starting index
// if current sum is equal to the required
// sum.
if (reqSum == currSum
&& right - left + 1 < len) {
len = min(len, right - left + 1);
startIndex = left;
}
// Incrementing 'right; and adding the
// value at that index to the current
// sum.
right++;
currSum += arr[right];
}
}
// If the length of the answer sub-array results over
// the length of the initial array, it means that the
// answer does not exist.
if (len > n) {
cout << "There exists no sub-array with sum="
<< reqSum << "\n";
return;
}
// Printing the answer sub-array.
cout << "The smallest sub-array with sum = " << reqSum
<< " is: ";
for (int i = startIndex; i < startIndex + len; i++)
cout << arr[i] << " ";
}
// Driver code
int main()
{
vector arr = { 2, 4, 6, 10, 2, 1 };
int K = 12;
smallestSubArrayWithGivenSum(arr, K);
return 0;
}
输出
2
时间复杂度: O(NlogN)
辅助空间: O(N)
更有效的方法:
可以使用双指针技术进一步优化当前问题的解决方案。这是它的工作原理:
- 设置两个索引持有者变量 – left和right ,初始化为 0。
- 将当前总和初始化为第一个元素的值,长度为 INT_MAX,起始索引为 -1。
- 如果当前总和小于所需总和,则向右递增并将当前总和增加索引right处元素的值。
- 如果当前总和大于所需总和,则将当前总和减少索引左侧元素的值。增量离开。
- 如果当前的总和等于所需的总和,则将 length 设置为 length 和right – left +1 中的最小值。将起始索引设置为左。递增吧。
- 当两个指针都指向同一个元素时,检查它是否是所需的总和。如果是这样,请按照第 5 步操作。如果不是,则增加right 。
- 按照上述步骤直到右边小于数组的大小。
起始索引和长度在最后给出结果子数组。
执行:
C++
// C++ implementation of problem to find a sub-array with
// given sum.
#include
using namespace std;
// Implementation function
void smallestSubArrayWithGivenSum(vector& arr,
int reqSum)
{
// There would be no sub-array as an answer
// if the array in the question is empty.
if (arr.size() == 0) {
cout << "There exists no sub-array with sum="
<< reqSum << "\n";
return;
}
// Initializing variables.
int len = INT_MAX, left = 0, right = 0, startIndex = -1,
currSum = arr[0], n = arr.size();
// Traversing the array.
while (right < n) {
// When both the index-holders have
// the same value.
if (left == right) {
// Modifying length and startingIndex
// both both 'left' and 'right' are
// same and have the value of the
// required sum.
if (currSum == reqSum) {
len = min(1, len);
startIndex = left;
}
// Incrementing 'right; and adding the
// value at that index to the current
// sum.
right++;
currSum += arr[right];
continue;
}
// Dropping the element at index 'left'
// from the current sum if current sum
// becomes greater than the required value.
if (currSum > reqSum) {
currSum -= arr[left];
left++;
}
else {
// Modifying length and starting index
// if current sum is equal to the required
// sum.
if (reqSum == currSum
&& right - left + 1 < len) {
len = min(len, right - left + 1);
startIndex = left;
}
// Incrementing 'right; and adding the
// value at that index to the current
// sum.
right++;
currSum += arr[right];
}
}
// If the length of the answer sub-array results over
// the length of the initial array, it means that the
// answer does not exist.
if (len > n) {
cout << "There exists no sub-array with sum="
<< reqSum << "\n";
return;
}
// Printing the answer sub-array.
cout << "The smallest sub-array with sum = " << reqSum
<< " is: ";
for (int i = startIndex; i < startIndex + len; i++)
cout << arr[i] << " ";
}
// Driver code
int main()
{
vector arr = { 2, 4, 6, 10, 2, 1 };
int K = 12;
smallestSubArrayWithGivenSum(arr, K);
return 0;
}
输出
The smallest sub-array with sum=6 is: 2 4
时间复杂度: O(N)
辅助空间: O(1)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。