机试指南:Ch5:线性数据结构 Ch6:递归与分治

文章目录

  • [第5章 线性数据结构](#第5章 线性数据结构)
    • [1.向量 vector](#1.向量 vector)
    • [2.队列 queue](#2.队列 queue)
    • [3.栈 stack](#3.栈 stack)
      • (1)栈的特点、应用
      • (2)基本操作
      • (3)例题
        • [例题1:编排字符串 (难度:简单)](#例题1:编排字符串 (难度:简单))
        • [例题2:括号匹配 (难度:中等)](#例题2:括号匹配 (难度:中等))
        • [例题3:计算表达式 (难度:困难)](#例题3:计算表达式 (难度:困难))
      • (4)习题
        • [习题1:堆栈的使用 (难度:简单)](#习题1:堆栈的使用 (难度:简单))
        • [习题2:模拟出入栈游戏 (难度:中等)](#习题2:模拟出入栈游戏 (难度:中等))
        • [习题3:简单计算器 (难度:困难)](#习题3:简单计算器 (难度:困难))
  • [第6章 递归与分治](#第6章 递归与分治)
    • 1.递归
      • (1)原理
      • (2)例题
        • [例题1:n的阶乘 (难度:入门)](#例题1:n的阶乘 (难度:入门))
        • [例题2:汉诺塔Ⅲ (难度:简单)【分治法-递归】](#例题2:汉诺塔Ⅲ (难度:简单)【分治法-递归】)
    • 2.分治
      • (1)原理
      • (2)例题
      • (3)习题
        • [习题1:Fibonacci (难度:入门)](#习题1:Fibonacci (难度:入门))
        • [习题2:二叉树 (难度:简单)【递归】](#习题2:二叉树 (难度:简单)【递归】)
        • [习题3:骨牌铺地砖 (难度:简单) 【动态规划】](#习题3:骨牌铺地砖 (难度:简单) 【动态规划】)
        • [习题4:矩阵幂 (难度:中等) 【矩阵计算】](#习题4:矩阵幂 (难度:中等) 【矩阵计算】)
        • [习题5:全排列 (难度:困难)【递归回溯法 - DFS】](#习题5:全排列 (难度:困难)【递归回溯法 - DFS】)

第5章 线性数据结构

1.当定义的数组特别大,达到1千万时,不能定义在函数内部,会崩溃。栈比较小,但快。

要定义在全局位置,数据段中。

【局部大数组会崩溃,全局大数组不会崩溃】

2.标准模板库STL

1.向量 vector

vector是动态数组,长度可改变。 vector<int> vec;//创建空向量,长度为0

普通静态数组长度是固定不变的。int arr[100];//创建长度为100的静态数组

1.头文件

cpp 复制代码
#include <vector>
using namespace std;

2.声明向量

cpp 复制代码
vector<int> vec;//长度为0

3.赋初值

cpp 复制代码
vector<int> vec2 = {1,2,3};

4.申请一定空间的向量,所有元素初值默认为0

cpp 复制代码
vector<int> vec3(10000);

※5.尾部插入:尾部扩容 push_back(元素) 。效率最高,插入n个为O(n),插入1个为O(1)。

cpp 复制代码
vec.push_back(1);//vec[0]=1
vec.push_back(3);//vec[1]=3

※6.任意位置插入:

cpp 复制代码
vec.insert(pos,[个数,]内容);

//头部插入字符串
vec.insert(vec.begin(),str);

※7.尾部删除:弹出尾部元素 pop_back()

cpp 复制代码
vec.pop_back();

※8.下标访问

cpp 复制代码
vec[i] //下标>=n时,数组越界

9.长度计算

cpp 复制代码
vec.size();

10.两种遍历方法

①下标遍历

cpp 复制代码
for(unsigned int i = 0; i < vec.size(); ++i){
	printf("vec[%d] = %d\n",i,vec[i]);
}

②迭代器遍历

cpp 复制代码
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it){
	printf("vec[] = %d\n",*it);
}

11.随机位置的插入:insert(位置,元素)

cpp 复制代码
vector<int>::iterator it1 = vec.begin()+1;//迭代器指针指向vector的第二个位置
vec.insert(it1,3);//在vector第二个位置插入元素3

12.随机位置的删除:erase(位置);

cpp 复制代码
vec.erase(vec.begin());//删除vector的第一个位置的元素

13.vector的实现原理

(1)vector的组成、申请空间(堆上)

vector是类类型,包括size容量、capacity内存大小、ptr首地址

首地址存放在栈上,但vector申请的内存空间在堆区上,堆区比栈区大,因此vector可申请空间比静态数组在栈上申请的空间可以大很多。【静态数组 - 栈 - 小空间。 vector - 堆- 大空间】

(2)vector的扩容机制

2.队列 queue

(1)队列的特点、应用

1.队列的特点

队列queue是受限制的线性表

先进先出,FIFO
队尾入队,队头出队

2.队列应用:

广度优先遍历 BFS

(2)基本操作

0.头文件

cpp 复制代码
#include <queue>
using namespace std;

queue<int> myQueue;

1.队尾入队 .push(变量名)

cpp 复制代码
for(int i = 0;i <= 5;++i){
	myQueue.push(i);
}

2.队头出队 .pop()

3.判空 .empty()

4.队首元素 .front()

5.队尾元素 .back()

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main() {
    //队列初始化
    queue<int> myQueue;
    //判空
    if(myQueue.empty()){
        cout << "myQueue is empty!" << endl;
    }
    //队尾入队
    for(int i = 0 ; i < 10; ++i){
        myQueue.push(i);
        //打印队首、队尾
        cout << "队首:" << myQueue.front() << "  队尾:" << myQueue.back() << endl;
    }
    cout << "---------------" << endl;
    //队首出队
    for(int i = 0 ; i < 9; ++i){
        myQueue.pop();
        //打印队首、队尾
        cout << "队首:" << myQueue.front() << "  队尾:" << myQueue.back() << endl;
    }
    return 0;
}

(3)例题

例题1:约瑟夫问题2 (难度:中等)

提交网址:http://bailian.openjudge.cn/practice/3254


思路:队头元素插入队尾,然后队头元素出队,以此实现循环队列

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> myQueue;
    int n,p,m;
    while(cin >> n >> p >> m){
        if(n==0 && p==0 && m==0)  break;
        //初始化队列
        for(int i = 1; i <= n; ++i){
            myQueue.push(i);
        }
        //将编号为p旋转到队头
        for(int i = 1; i < p; ++i) {  //将1到p-1号元素从队头调整到队尾
            myQueue.push(myQueue.front()); //队头元素插入队尾
            myQueue.pop(); //队头出队
        }
        //开始计数过程
        while(!myQueue.empty()){
            //将m-1个元素从队头调整到队尾
            for(int i = 1; i < m; ++i){
                myQueue.push(myQueue.front());
                myQueue.pop();
            }
            //打印并移除第m个元素
            cout << myQueue.front();
            if(myQueue.size() > 1) cout << ",";
            myQueue.pop();
        }
        cout << endl;
    }
    return 0;
}

(4)习题

习题1:排队打饭 (难度:中等)

提交网址:https://www.acwing.com/problem/content/description/5063/


几个注意事项:

①可能前面有连续几个没打上饭的,得用int记录而不是bool

②有些数值超过了int的表示范围,将数组由int类型改为long long

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int n;
    long long a[100010],t[100010],b[100010],res[100010]; //a[i]为到达时刻,t[i]为打饭耗时,b[i]为最大等待时长,res[i]为打饭时刻或-1
    cin >> n;
    for(int i = 1; i <= n; ++i){
        cin >> a[i] >> t[i] >> b[i];
    }
    res[1] = a[1];  //第一位同学到达后立即开始打饭
    cout << res[1] <<" ";
    int count = 0; //count记录前面有连续多少位同学没有打上饭
    for(int i = 2; i <= n; ++i){
        if(a[i]+b[i] < res[i-1-count]+t[i-1-count]){ //上一位开始打饭时间+打饭耗时超过了该同学最大等待时间,则放弃打饭
            cout << "-1 ";
            count++;
        }else{
            res[i] = max(res[i-1-count]+t[i-1-count],a[i]); //max(最早可以打饭时刻,该同学到达时间)
            cout << res[i] << " ";
            count = 0;
        }
    }
    cout << endl;
    return 0;
}

3.栈 stack

(1)栈的特点、应用

1.栈的特点

栈也是操作受限的线性表,只能一端进出。
后进先出

栈,禁止操作的一端称为盲端 。允许元素插入和删除的一端称为栈顶

2.栈的应用

①深度优先遍历 DFS:逆序输出

②表达式解析、表达式求值

③递归

④括号匹配

(2)基本操作

0.头文件

cpp 复制代码
#include <stack>
using namespace std;

1.初始化

cpp 复制代码
stack<typename> myStack//定义

2.方法
.push():压栈,将元素加入栈中
.pop():弹栈
.top():获取栈顶内容
.size():栈大小
.empty():判断栈是否为空

cpp 复制代码
#include <iostream>
#include <stack>
using namespace std;

int main() {
    //栈初始化
    stack<int> myStack;
    //栈判空
    if(myStack.empty()){
        cout << "myStack is empty!" << endl;
    }
    //入栈(压栈)
    for(int i = 0; i < 10 ; ++i){
        myStack.push(i);
        cout << "top is " << myStack.top() << endl;
    }
    cout << "---------------" <<endl;
    //出栈(弹栈)
    for(int i = 0 ; i < 9; ++i){
        myStack.pop();
        cout << "top is " << myStack.top() << endl;
    }
    return 0;
}

(3)例题

例题1:编排字符串 (难度:简单)

提交网址:https://www.acwing.com/problem/content/3578/

思路:准备一个临时栈,用于演示弹栈

cpp 复制代码
#include <iostream>
#include <stack>
#include <string>
using namespace std;

int main() {
    string str;
    stack<string> myStack,tempStack;
    int m;
    cin >> m;
    for(int i = 0; i < m; ++i){
        cin >> str;
        myStack.push(str);
        tempStack = myStack;
        for(int i = 1; !tempStack.empty(); ++i){
            if(i > 4) break;  //最多输出4个字符串
            cout << i << "=" << tempStack.top() << " ";
            tempStack.pop();
        }
        cout << endl;
    }
    return 0;
}
例题2:括号匹配 (难度:中等)

提交网址:https://www.acwing.com/problem/content/3696/

思路:栈实现。遇到右括号都是同一种思路,写好一个else if,后面都是复制了

cpp 复制代码
#include <iostream>
#include <string>
#include <stack>
using namespace std;

int main() {
    stack<char> myStack;
    string str;
    cin >> str;
    for(int i = 0; i < str.size(); ++i){
        //1.遇到左括号,入栈
        if(str[i] == '<' || str[i] == '(' || str[i] == '[' || str[i] == '{'){
            myStack.push(str[i]);
        }
        //2.遇到右尖括号
        else if(str[i] == '>'){
            if(myStack.empty() || myStack.top()!='<'){
                cout << "no" << endl;
                return 0;
            }else{  //栈顶就是左尖括号,匹配
                myStack.pop();
            }
        }
        //3.遇到右小括号
        else if(str[i] == ')'){
            if(myStack.empty() || myStack.top()!='('){
                cout << "no" << endl;
                return 0;
            }else{  //栈顶就是左小括号,匹配
                myStack.pop();
            }
        }
        //4.遇到右中括号
        else if(str[i] == ']'){
            if(myStack.empty() || myStack.top()!='['){
                cout << "no" << endl;
                return 0;
            }else{  //栈顶就是左中括号,匹配
                myStack.pop();
            }
        }
        //5.遇到右大括号
        else if(str[i] == '}'){
            if(myStack.empty() || myStack.top()!='{'){
                cout << "no" << endl;
                return 0;
            }else{  //栈顶就是左大括号,匹配
                myStack.pop();
            }
        }
    }
    if(myStack.empty())    cout << "yes" << endl;
    else                   cout << "no"  << endl;
    return 0;
}
例题3:计算表达式 (难度:困难)

提交网址:http://t.cn/AiKKJjJ5

cpp 复制代码
#include <stdio.h>
#include <string>
#include <stack>
#include <map>
using namespace std;
int main() {
    char str[1000] = { 0 };
    map<char, int> priority = {
        {'\0',0},
        {'+',1},{'-',1},
        {'*',2},{'/',2}
    };
    while (scanf("%s", str) != EOF) {
        string numStr = "";
        stack<char> opStack;
        stack<double> numStack;
        for (int i = 0; ; ++i) {
            if (str[i] >= '0' && str[i] <= '9') {
                numStr.push_back(str[i]);
            }
            else {
                double num = stod(numStr);
                numStr = "";
                numStack.push(num);
                // 什么时候弹栈? 栈非空 && 新op的优先级 不高于 栈顶的优先级
                // 循环弹栈和计算
                while (!opStack.empty() &&
                    priority[str[i]] <= priority[opStack.top()]) {
                    double rhs = numStack.top();
                    numStack.pop();
                    double lhs = numStack.top();
                    numStack.pop();
                    char curOp = opStack.top();
                    opStack.pop();

                    if (curOp == '+') {
                        numStack.push(lhs + rhs);
                    }
                    else if (curOp == '-') {
                        numStack.push(lhs - rhs);
                    }
                    else if (curOp == '*') {
                        numStack.push(lhs * rhs);
                    }
                    else if (curOp == '/') {
                        numStack.push(lhs / rhs);
                    }
                }
                // 栈为空 或者 新op的优先级高于栈顶
                if (str[i] == '\0') {
                    printf("%d\n", (int)numStack.top());
                    break;
                }
                else {
                    opStack.push(str[i]);
                }
            }
        }
    }
    return 0;
}

(4)习题

习题1:堆栈的使用 (难度:简单)

提交网址:http://t.cn/AiKKM6F6

cpp 复制代码
#include <iostream>
#include <stack>
using namespace std;

int main() {
    int n;
    while(cin >> n){
        stack<int> myStack;
        char c;
        int a;
        for(int i = 0; i < n; ++i){
            cin >> c;
            if(c == 'A'){
                if(myStack.empty()) cout << "E" << endl;
                else                cout << myStack.top() << endl;
            }else if(c == 'P'){
                cin >> a;
                myStack.push(a);
            }else if(c == 'O'){
                if(!myStack.empty())    myStack.pop();
            }
        }
    }
    return 0;
}
习题2:模拟出入栈游戏 (难度:中等)

提交网址:https://www.acwing.com/problem/content/3681/

注意,栈的初始化放在while循环里。放在外面可能会因为上一轮未清空,受脏数据影响

cpp 复制代码
#include <iostream>
#include <stack>
#include <string>
using namespace std;

int main() {
    string str1 = "abcdefghijklmnopqrstuvwxyz",str2;
    while(cin >> str2){
        stack<char> stk;
        int k = 0;
        for(int i = 0 ; i < str1.size(); ++i){
            stk.push(str1[i]);
            while(stk.size() && k < str2.size() && stk.top() == str2[k]){//核心while循环:
                stk.pop();                            //比较栈顶元素和字符串str2中当前位置的字符是否相等
                k++;
            }
        }
        if(stk.empty())  cout << "yes" << endl;
        else             cout << "no"  << endl;
    }
    return 0;
}
习题3:简单计算器 (难度:困难)

提交网址:http://t.cn/AiKoGS94

第6章 递归与分治

1.递归

(1)原理

1.什么是递归?

函数在函数体内调用自身函数的行为叫做递归

(在函数定义中调用本函数,叫做递归)

2.递归的原理:

①代码段:PC走到被调函数的入口

②栈区:栈帧压入栈内

逐过程、逐语句


3.如何使用递归?

递归一定要有递归出口

②每次递归,变量条件向着递归出口靠近

4.递归与分治的关系:

分治是一种思想,分而治之;递归是一种实现方法,函数调用自己。

分治思想可用递归来实现,也可以用其他方法来实现。递归作为一种方法,不止可以用于实现递归思想,也可以用来实现其他思想。

但总的来说,一般都用递归方法来实现分治的思想。故两者本不是同一纬度的概念,但是经常放在一起谈论。

常见的分治:求斐波那契数列、快速排序

常见的递归:求n的阶乘

5.2023旧版本内容:

从函数到递归

①大问题→小问题,等价条件
②确定最小问题,即递归出口

①函数

C语言编写的代码,以函数定义为单位。

call:把PC移到被调函数

ret:把PC移回主调函数

②递归

递归关注的两个点:

①大问题转化为小问题:规模n→规模n-1

②最小问题:递归出口

(2)例题

例题1:n的阶乘 (难度:入门)

提交网址:https://www.nowcoder.com/share/jump/2891302591709206218373

C++:

cpp 复制代码
#include <iostream>
using namespace std;

long long factorial(int n){
    if(n == 0 || n == 1)    return n;
    else{
        return n * factorial(n-1);
    }
}

int main(){
    int n;
    cin >> n;
    cout << factorial(n);
    return 0;
}

C语言:

cpp 复制代码
#include <cstdio>

long long int Factorial(int n){
    if(n == 0){
        return 1;
    }else{
        return n*Factorial(n-1);
    }
}

int main(){
    int n;
    while(scanf("%d",&n) != EOF){
        printf("%lld",Factorial(n));
    }
    return 0;
}
例题2:汉诺塔Ⅲ (难度:简单)【分治法-递归】


思路:

①n-1片为整体,先由第一柱搬到第三柱,最大片由第一柱搬到第二柱;[Hanoi(n-1) + 1]

②n-1片从第三柱搬回第一柱,最大片由第二柱搬到第三柱; [Hanoi(n-1) + 1]

③n-1片由第一柱搬到第三柱,完成。[Hanoi(n-1)]

cpp 复制代码
#include <iostream>
using namespace std;

long long Hanoi(int n){ //搬运n片共需要Hanoi(n)步
    if(n == 1){
        return 2; 
    }else{
        return 3 * Hanoi(n-1) + 2; 
    }
}

int main() {
    int n;
    while(cin >> n){
        cout << Hanoi(n) << endl;
    }
    return 0;
}

2.分治

(1)原理

1.名称解释

分治法,分而治之 (divide-and-conquer method)

2.分治法的两个要素

①大问题转化为相似的小问题,直至转化为最小问题

②最小问题的解决方案

3.分治法的代码模板

①分解:大问题拆成小问题

②治理:找到等价条件,解决递归出口(最小问题)

③合并

(2)例题

例题1:跳台阶 (难度:简单)

提交网址:https://www.acwing.com/problem/content/823/

思路:因为每次只能走1级或2级台阶,所以走n级台阶只会是从n-1或n-2级台阶上去的。根据加法原理,这两种方案的数量可以相加得到走n级台阶的方案。同样的,走n-1级的方案可以拆分为走n-2级和走n-3级方案之和。

cpp 复制代码
#include <iostream>
using namespace std;

int f(int n){
    if(n == 1){
        return 1;
    }else if(n == 2){
        return 2;
    }else{
        return f(n-1) + f(n-2);
    }
}

int main() {
    int n; //n级台阶
    while(cin >> n){
        cout << f(n) << endl;
    }
    return 0;
}

测试可得:

f(1)=1,f(2)=2,f(3)=3,f(4)=5,f(5)=8,f(6)=13,f(7)=21 ...

可知,跳台阶问题是斐波那契数列问题的变形,即后一个值是前两个值之和。

优化分析:

但是由栈帧示意图,我们发现很多f(n)会重复计算多次。当n很大时,该算法的效率会很低。我们自然而然地想到如何避免重复计算从而提高函数的效率。

cpp 复制代码
优化:用数组存储已经计算过的结果
例题2:不连续1的子串(难度:中等)

提交网址:https://www.acwing.com/problem/content/3709/

24炉灰老师:分解为小问题,并给出最小问题的解决方案(递归出口)

cpp 复制代码
#include <iostream>
using namespace std;

int f0(int n); // 函数声明写在前面,
int f1(int n); // 则这两个函数就可以交叉调用

int f0(int n){ // 末尾为0
    if(n == 1){
        return 1;
    }else{
       return f0(n-1) + f1(n-1);
    };
}

int f1(int n){ // 末尾为1
    if(n == 1){
        return 1;
    }else{
        return f0(n-1);
    }
}

int main() {
    int n;
    while(cin >> n){
        cout << f0(n)+f1(n) << endl;
    }
    return 0;
}
例题3:2的幂次方(难度:困难)

提交网址:https://www.acwing.com/problem/content/3486/

分析:由大问题分解为小问题,用分治法

将n转化为2的指数形式:

24炉灰老师

cpp 复制代码
#include <stdio.h>
#include <string>
#include <vector>
using namespace std;
string Get2sExponet(int n) {
    if (n == 0) {
        return "0";
    }
    vector<int> exp;
    for (int i = 15; i >= 0; --i) {
        if ((n & (1 << i)) != 0) {
            exp.push_back(i);
        }
    }
    // n = 2^(exp[0]) + 2^(exp[1]) + ... + 2^(exp[size-1])
    string res = "";
    for (int i = 0; i < exp.size(); ++i) {
        if (i != 0) {
            res += "+";
        }
        if (exp[i] == 1) {
            res += "2";
        }
        else {
            res += "2(" + Get2sExponet(exp[i]) + ")";
        }
    }
    return res;
}
int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        printf("%s\n", Get2sExponet(n).c_str());
    }
    return 0;
}

(3)习题

习题1:Fibonacci (难度:入门)

提交网址:http://t.cn/Ai0K3tU5

解法1:斐波那契数列,递归实现

C语言版本:

cpp 复制代码
#include <cstdio>

int Fibonacci(int n ){
    if(n == 0 || n == 1){
        return n;
    }else{
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

int main(){
    int n;
    while(scanf("%d",&n) != EOF){
        printf("%d\n",Fibonacci(n));
    }
    return 0;
}

C++版本:

cpp 复制代码
#include <iostream>
using namespace std;

int Fibonacci(int n){
    if(n == 0 || n == 1){
        return n;
    }else{
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

int main(){
    int n;
    while(cin >> n){
        cout << Fibonacci(n);
    }
    return 0;
}

解法2:斐波那契数列(非递归实现,循环实现)

cpp 复制代码
#include <cstdio>

int fib(int n){
    int n1 = 1;
    int n2 = 1;
    int ret = 0;
    if (n==1 || n==2){
        return 1;
    }
    for (int i = 3; i <= n; i++){ //通过循环计算n>=3时
        ret = n1 + n2;
        n1 = n2;
        n2 = ret;
    }
    return ret;
}

int main(){
    int n = 0;
    scanf("%d", &n);
    int ret = fib(n);
    printf("%d\n",ret);
    return 0;
}

解法3:斐波那契数列(非递归实现,动态规划实现)

cpp 复制代码
#include <cstdio>

int dp[91];

int Fibonacci(int n){
    dp[1] = 1;
    dp[2] = 2;
    for(int i = 3 ; i <= n; ++i){ //3-n
        dp[i] = dp[i-1] + dp[i-2];
    }
    return dp[n];
}

int main(){
    int n;
    while(scanf("%d",&n) != EOF){
        printf("%d\n",Fibonacci(n));
    }
    return 0;
}
习题2:二叉树 (难度:简单)【递归】

提交网址:http://t.cn/Ai0Ke6I0

C++版本:根结点 + 左子树 + 右子树

如图,编号为m的结点,左孩子编号为2m,右孩子编号为2m+1

cpp 复制代码
#include <iostream>
using namespace std;

int binarytree(int m,int n){
     if(m > n){
        return 0;
     }else{         //如图,编号为m的结点,左孩子编号为2m,右孩子编号为2m+1
        return 1 + binarytree(2*m,n) + binarytree(2*m+1,n); //根结点 + 左子树 + 右子树
     }
}

int main(){
    int m,n; //m为父结点编号,n为总结点数
    while(cin >> m >> n){
        if(m==0 && n==0) break;
        cout << binarytree(m,n) << endl;
    }
    return 0;
}

C语言版本:

cpp 复制代码
#include <cstdio>

int binaryTree(int m,int n){
    if(m>n){
        return 0;
    }else{
        return binaryTree(2*m,n) + binaryTree(2*m+1,n) + 1;
    }
}

int main(){
    int m,n;
    while(scanf("%d %d",&m,&n) != EOF){
        if(m<=0 && n<=0){
            break;
        }
        printf("%d\n",binaryTree(m,n));
    }
}
习题3:骨牌铺地砖 (难度:简单) 【动态规划】

提交网址:https://www.acwing.com/problem/content/3690/

思路:

用递归会超时,改用动态规划,数组保存计算结果,避免重复计算

cpp 复制代码
#include <iostream>
using namespace std;

int dp[10010];

long long Fibonacci(int n){
	dp[0] = 0;
    dp[1] = 1;
    dp[2] = 2;
    for(int i = 3; i <= n; ++i){
        dp[i] = (dp[i-1] + dp[i-2]) % 999983;
    }
    return dp[n];
}

int main() {
    int n;
    cin >> n;
    cout << Fibonacci(n);
    return 0;
}
习题4:矩阵幂 (难度:中等) 【矩阵计算】

提交网址:https://www.acwing.com/problem/content/3690/

学会计算 矩阵C = A×B

核心代码:

cpp 复制代码
for(int i = 0; i < n; ++i){
    for(int j = 0; j < n; ++j){
        for(int k = 0; k < n; ++k){      //矩阵C = 矩阵A × 矩阵B:
            C[i][j] += A[i][k]*B[k][j]; //C[i][j] = A的第i行×B的第j列所有对应元素
        }
    }
}

答案:

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 11;
int A[N][N],B[N][N],C[N][N];

int main() {
    int n,m; //n为矩阵的阶,m为矩阵的幂
    cin >> n >> m;
    memset(A,0,sizeof(A));
    //输入矩阵A
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            cin >> A[i][j];
        }
    }
    //计算m次幂
    //(1)若m为1,输出原矩阵
    if(m == 1){
        for(int i = 0; i < n; ++i){
            for(int j = 0; j < n; ++j){
                cout << A[i][j] << " ";
            }
            cout << endl;
        }
        return 0;
    }
    //(2)若m>1,计算 矩阵 C = A×B
    memcpy(B,A,sizeof(A));
    while(--m){
        memset(C,0,sizeof(C));
        for(int i = 0; i < n; ++i){
            for(int j = 0; j < n; ++j){
                for(int k = 0; k < n; ++k){      //矩阵C = 矩阵A × 矩阵B:
                    C[i][j] += A[i][k]*B[k][j]; //C[i][j] = A的第i行×B的第j列所有对应元素
                }
            }
        }
        memcpy(B,C,sizeof(C)); //这次的幂次运算结果C赋值给B
    }
    //输出矩阵C
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            cout << C[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}
习题5:全排列 (难度:困难)【递归回溯法 - DFS】

提交网址:https://www.acwing.com/problem/content/3690/

来自一位网友的答案:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
void backtracking(string tmp,string s)
{
    if(tmp.size()==s.size())
        cout<<tmp<<endl;
    else
    {
        for(int i=0;i<s.size();++i)
        {
            if(tmp.find(s[i])!=tmp.npos) continue;
            backtracking(tmp+s[i],s);
        }
    }
}
int main()
{
    string s,tmp=""; 
    while(cin>>s)
        backtracking(tmp,s);   
    return 0;
 } 
相关推荐
顶呱呱程序6 分钟前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
爱吃生蚝的于勒28 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~31 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
王哈哈^_^1 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城1 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz1 小时前
STL--哈希
c++·算法·哈希算法
kingmax542120081 小时前
初三数学,最优解问题
算法
一直学习永不止步2 小时前
LeetCode题练习与总结:赎金信--383
java·数据结构·算法·leetcode·字符串·哈希表·计数
小刘|2 小时前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法