首页 > 编程语言 >c++ day7

c++ day7

时间:2023-07-11 21:55:05浏览次数:38  
标签:nums int day7 复杂度 c++ 数组 空间 maxSum

今天还是来理解空间复杂度

其实就是开摆一天

当讨论空间复杂度时,我们可以通过具体的代码示例来说明不同情况下的空间复杂度。

示例 1: 常数空间复杂度 O(1)

void printNumber(int num) {
    int count = 0; // 常数级别的额外空间
    for (int i = 0; i < num; i++) {
        cout << i << endl;
        count++;
    }
}

在这个示例中,我们定义了一个额外的整数变量 count,但它的空间占用是固定的,与输入参数 num 的大小无关。因此,该函数的空间复杂度是 O(1),即常数级别的空间复杂度。

示例 2: 线性空间复杂度 O(n)

void duplicateNumbers(const vector<int>& numbers) {
    unordered_set<int> duplicates; // 额外的线性空间
    for (int num : numbers) {
        if (duplicates.count(num) > 0) {
            cout << num << " is a duplicate number." << endl;
        } else {
            duplicates.insert(num);
        }
    }
}

在这个示例中,我们使用了一个无序集合 duplicates 来存储重复的数字。随着输入参数 numbers 的大小增加,集合的大小也会增加,因此额外空间的使用与输入规模成线性关系。因此,该函数的空间复杂度是 O(n),即线性级别的空间复杂度。

示例 3: 对数空间复杂度 O(log n)

int binarySearch(const vector<int>& sortedArray, int target) {
    int left = 0;
    int right = sortedArray.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (sortedArray[mid] == target) {
            return mid;
        } else if (sortedArray[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1;
}

在这个示例中,我们实现了一个二分查找算法。该算法的额外空间主要用于存储左边界和右边界的索引,它们的数量随着输入规模的增加而以对数方式增长。因此,该函数的空间复杂度是 O(log n),即对数级别的空间复杂度。

让我们考虑一个更经典的问题:

计算斐波那契数列的第n个数字。

斐波那契数列是一个以0和1开始,后续每个数字都是前两个数字之和的数列。斐波那契数列的前几个数字是:0, 1, 1, 2, 3, 5, 8, 13, 21, ...

我们将展示三种不同的解决方案,每种方案的空间复杂度不同。

  1. 常数空间复杂度解法(O(1)):
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    }

    int prev = 0;
    int current = 1;
    for (int i = 2; i <= n; i++) {
        int temp = current;
        current = prev + current;
        prev = temp;
    }

    return current;
}

这个解法使用了常数级别的额外空间。我们使用两个变量 prevcurrent 来迭代计算斐波那契数列的下一个数字,只需使用常数个变量来存储中间结果。因此,该解法的空间复杂度是 O(1)。

  1. 线性空间复杂度解法(O(n)):
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    }

    vector<int> fib(n + 1);
    fib[0] = 0;
    fib[1] = 1;

    for (int i = 2; i <= n; i++) {
        fib[i] = fib[i - 1] + fib[i - 2];
    }

    return fib[n];
}

这个解法使用了一个大小为 n+1 的数组 fib 来存储斐波那契数列的前 n 个数字。我们从 0 和 1 开始,迭代计算并存储每个数字。由于数组的大小与输入的 n 成线性关系,因此该解法的空间复杂度是 O(n)。

  1. 递归解法(指数空间复杂度):
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

这个解法使用了递归来计算斐波那契数列的第 n 个数字。每次递归调用都会产生两个新的递归调用,因此递归树的大小与输入 n 成指数关系。因此,该解法的空间复杂度是指数级别的。

其实空间复杂度对于过题没有时间复杂度重要。

这样可能不是蛮清楚,我这里写上一个我以前写过的题,不优化空间就过不了。

题目可能记不得正确了,但大概是对的

"最大子数组和"问题

给定一个整数数组,我们需要找到具有最大和的连续子数组。

例如,对于数组[-2, 1, -3, 4, -1, 2, 1, -5, 4],最大子数组和为[4, -1, 2, 1],其和为6。

如果不优化空间,我们可以使用动态规划来解决这个问题。下面是一个使用动态规划的解决方案,其空间复杂度为O(n):

int maxSubArray(vector<int>& nums) {
    int n = nums.size();
    vector<int> dp(n); // 创建一个大小为n的动态规划数组
    dp[0] = nums[0]; // 初始化第一个元素
    int maxSum = dp[0]; // 记录当前最大和

    for (int i = 1; i < n; i++) {
        dp[i] = max(dp[i-1] + nums[i], nums[i]); // 动态规划递推公式
        maxSum = max(maxSum, dp[i]); // 更新最大和
    }

    return maxSum;
}

在上面的解决方案中,我们使用了一个大小为n的动态规划数组dp来存储每个位置的最大子数组和。通过迭代计算每个位置的最大和,并不断更新最大和的值,最终得到最大子数组和。

然而,如果我们要优化空间复杂度,可以使用"滚动数组"的思想,将空间复杂度降低到O(1)。下面是一个使用滚动数组优化的解决方案:

int maxSubArray(vector<int>& nums) {
    int n = nums.size();
    int prevSum = nums[0]; // 用于记录前一个位置的最大和
    int maxSum = prevSum; // 记录当前最大和

    for (int i = 1; i < n; i++) {
        prevSum = max(prevSum + nums[i], nums[i]); // 动态规划递推公式
        maxSum = max(maxSum, prevSum); // 更新最大和
    }

    return maxSum;
}

在这个优化后的解决方案中,我们只使用了两个变量prevSummaxSum来记录前一个位置的最大和和当前最大和。通过不断更新这两个变量的值,我们得到了最大子数组和。

这个优化后的解决方案的空间复杂度为O(1),因为我们只使用了常数级别的额外空间来存储中间结果,而不需要创建大小为n的动态规划数组。

累了累了 先润了

 

标签:nums,int,day7,复杂度,c++,数组,空间,maxSum
From: https://www.cnblogs.com/jszs0013/p/17546046.html

相关文章

  • C/C++2022级C语言课程设计任务书[2023-07-06]
    C/C++2022级C语言课程设计任务书[2023-07-06]2022级C语言课程设计任务书【题目1】学籍管理系统一、设计题目学籍管理系统(用动态结构体数组实现)二、设计内容【题目描述】假设某校学生学籍基本信息主要包括:学号(整型)、姓名(字符数组型)、所在系、班级等,本系统应能对这些......
  • C++自助点餐系统[2023-07-06]
    C++自助点餐系统[2023-07-06]面向对象程序课程设计任务书【题目】自助点餐系统【目的】通过设计一个小型的自助点餐系统,训练综合运用所学知识处理实际问题的能力,强化面向对象的程序设计理念,使自己的程序设计与调试水平有一个明显的提高。【要求】1、每个学生必须独立完成;2......
  • C++停车场管理系统[2023-07-06]
    C++停车场管理系统[2023-07-06]停车场管理系统简介一、 问题描述设停车场是一个可停放若干辆辆汽车的狭多层平面区域,且只有一个大门可供汽车进出。若车场内已停满汽车,则后来的汽车只能在门外的狭长便道上等候,一旦停车场内有车开走,则排在便道上的第一辆车即可进入。每辆停放在车......
  • 《C++程序设计》[2023-07-06]
    《C++程序设计》[2023-07-06]智能与工程学院《C++程序设计》小组学习任务书第2次专业年级:2022级计算机指导教师:李佳佳2022-2023学年第2学期一、任务根据课程所学,利用C++泛型编程思想、STL、模板、I\O流和异常处理等,以小组为单位完成基于STL泛化......
  • 【C++学习笔记——前置声明:解决嵌套引用问题】
    在代码中,两个类相互引用的问题,那么我们就需要在头文件中相互写#include,这样会造成相互循环cpoy头文件,编译器报错,为了解决这个问题,设置了前置声明这个方法。A.h#ifndefA_H#defineA_HclassBclassA{typedefvector<string>::sizetypesize_type;B*b;}#endifB.h#if......
  • C/C++学生成绩管理系统[2023-07-06]
    C/C++学生成绩管理系统[2023-07-06]学生成绩管理系统开发一个可以管理学生成绩以及学生基本信息的一个信息系统,至少实现如下功能:信息管理,支持信息的增、删、改、查操作,具体信息类型如下:(1) 管理学生信息 ,包括学号,姓名,年龄,班级等等信息。(2) 班级信息,包括班级编号、班级人数,......
  • 【ChernoC++笔记】移动赋值运算符
    【90】【ChernoC++】【中字】stdmove与移动赋值操作符▶️移动构造与std::move接上节的String类,我们可以通过string来构造新的对象dest://拷贝构造Stringstring="Hello";Stringdest=string;为了使用移动构造函数,string需要cast为临时变量://移动构造Stringdest=(s......
  • 104.C++中标准库是什么?
    104.C++中标准库是什么?1.C++标准库可以分为两部分:1.1标准函数库:这个库是由通用的、独立的、不属于任何类的函数组成的。函数库继承自C语言。输入/输出I/O、字符串和字符处理、数学、时间、日期和本地化、动态分配、其他、宽字符函数*输入输出流:`<iostream>`头文件中的......
  • 98.C++如何处理多个异常的?
    98.C++如何处理多个异常的?C++中的异常情况:语法错误(编译错误):比如变量未定义、括号不匹配、关键字拼写错误等等编译器在编译时能发现的错误,这类错误可以及时被编译器发现,而且可以及时知道出错的位置及原因,方便改正。运行时错误:比如数组下标越界、系统内存不足等等。这类错误不易......
  • 77.C++中的指针参数传递和引用参数传递有什么区别?底层原理你知道吗?
    77.C++中的指针参数传递和引用参数传递有什么区别?底层原理你知道吗?1.指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传......