C++程序 寻找给定和的子数组-第1集(非负数)

C++程序 寻找给定和的子数组-第1集(非负数)

在编程过程中,找到一个数组内满足总和为给定值的子数组是一件比较常见的事情。今天,我们将学习如何用C++编写一个程序,来寻找一个非负整数数组中满足给定值的子数组。

问题描述

给定一个非负整数数组和一个目标值,需要找到该数组中所有满足总和等于目标值的子数组。

例如,如果给定数组是{2, 3, 5, 7, 8},目标值为10,那么满足条件的子数组有{2, 3, 5}{8},因为它们的总和都是10

解决方案

在这里,我们将学习两种方法来解决这个问题,一种是暴力枚举,另一种是使用前缀和。

方法1:暴力枚举

暴力枚举的思路非常简单。我们可以先从数组的第一个元素开始,向后遍历数组所有可能的子数组。 对于每个子数组,我们都计算它们的总和并检查是否等于目标值。

代码实现:

#include <iostream>
#include <vector>
using namespace std;

// 查找所有满足总和为sum的子数组
vector<vector<int>> findSubarray(vector<int> nums, int sum) {
    vector<vector<int>> res;    // 存储结果
    int n = nums.size();

    // 枚举所有可能的子数组
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            int sum_sub = 0;    // 当前子数组的总和
            vector<int> sub;    // 当前子数组

            // 计算子数组的总和
            for (int k = i; k <= j; k++) {
                sum_sub += nums[k];
                sub.push_back(nums[k]);
            }

            // 当子数组的总和等于给定的sum时,将其加入到结果中
            if (sum_sub == sum) {
                res.push_back(sub);
            }
        }
    }

    return res;
}

int main() {
    vector<int> nums = {2, 3, 5, 7, 8};
    int sum = 10;

    vector<vector<int>> ans = findSubarray(nums, sum);

    // 输出结果
    for (auto sub : ans) {
        for (auto num : sub) {
            cout << num << " ";
        }
        cout << endl;
    }

    return 0;
}

运行结果:

2 3 5 
8 

以上就是暴力枚举的方法,它的时间复杂度为 O(n^3),时间效率非常低。

方法2:前缀和

前缀和是一种常见的算法,用于快速计算数组的区间和。它的思路是先用一个数组 sum 存储原数组中每个位置之前元素的和,即sum[i] = nums[0] + nums[1] + … + nums[i]。然后,我们可以通过计算sum[j] – sum[i-1], 在O(1)的时间内计算出原数组的任意一个子数组的和。

由于数组的元素均为非负整数,因此我们可以在计算前缀和时,一旦发现某个前缀和大于目标值,就直接跳出循环。这样可以大大提高程序的效率。

代码实现:

#include <iostream>
#include <vector>
using namespace std;

// 查找所有满足总和为sum的子数组
vector<vector<int>> findSubarray(vector<int> nums, int sum) {
    vector<vector<int>> res;    // 存储结果
    int n = nums.size();
    vector<int> preSum(n+1, 0); // 前缀和数组
    for (int i = 1; i <= n; i++) {
        preSum[i] = preSum[i-1] + nums[i-1]; // 计算前缀和
    }

    // 枚举所有可能的子数组
    for (int i = 0; i < n; i++) {
        for (int j = i+1; j <= n; j++) {
            // 如果某个前缀和大于目标值,直接跳出内层循环
            if (preSum[j] - preSum[i] > sum) {
                break;
            }
            // 如果当前子数组的总和等于给定的sum,将其加入到结果中
            if (preSum[j] - preSum[i] == sum) {
                vector<int> sub(nums.begin()+i, nums.begin()+j);
                res.push_back(sub);
            }
        }
    }

    return res;
}

int main() {
    vector<int> nums = {2, 3, 5, 7, 8};
    int sum = 10;

    vector<vector<int>> ans = findSubarray(nums, sum);

    // 输出结果
    for (auto sub : ans) {
        for (auto num : sub) {
            cout << num << " ";
        }
        cout << endl;
    }

    return 0;
}

运行结果:

2 3 5 
8 

我们可以看到,使用前缀和的方法,我们得到了与暴力枚举相同的结果,但它的时间复杂度为 O(n^2),效率更高。

结论

在这篇文章中,我们学习了如何使用C++来寻找一个非负整数数组中满足给定值的子数组。我们介绍了两种方法,一种是暴力枚举,另一种是使用前缀和。虽然暴力枚举的实现非常简单,但时间复杂度太高,不适用于大规模数据的场景。使用前缀和,可以大大缩短程序的执行时间,提高效率。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

C++ 示例