【2023-4-10 网易春招笔试题 开发岗】

1. 采蘑菇机器人最优路径

题目:

采蘑菇机器人在一个m*n的萨菇矩阵内,从起点坐标(0,0)出发,可以向右或向下两个方向移动,每个方格种植着不同价值的蘑菇,现在向机器人输入蘑菇采集任务x,即一次采集萨菇的总价值的最小值,请你设计一个函数,帮助机器人计算完成任务所需要移动的最少移动次数。

输入描述:

第一行输入三个整数:m n x
第二行输入 m * n 个整数,表示从左往右,从上往下的方格内蘑菇的价值

输出描述:

机器人完成任务所需移动的最少次数,不存在则返回-1

示例1:
输入输出示例仅供调试,后台判题数据一般不包含示例

输入:

1 1 10
10

输出:

0

说明:

机器人起点位置即可完成任务,不需要移动

示例2:
输入输出示例仅供调试,后台判题数据一般不包含示例

输入:

2 2 5
1 2
1 2

输出:

2

说明:

需要向右移动一次,再向下移动一次

动态规划方法:

经典dp,二维矩阵中只能往右或往下走,所以走到某一个格子的移动距离是确定的(行数+列数)。求机器人采一定价值蘑菇的最少移动距离,即求机器人走到每一个格子的最大总价值。
初始状态中,起点(0,0)的总价值 = 起点(0,0)的蘑菇价值,第一行其他点只能从其左边一格移动而来,第一列其他点只能从其上边一格移动而来,逐个价值累加。
此外其他点都可以从左边或上边移动而来,选取更大价值的那条路径。
最后,在二维矩阵中找到满足价值任务的移动次数最少的点。

代码1:

#include 
#include 
#include 
using namespace std;

int main()
{
    int m,n,x;
    while(~scanf("%d %d %d", &m, &n, &x)) {
        if(m == 0 || n == 0) {
            cout << -1 << endl;
            continue;
        }
        vector<vector<int>> a(m, vector<int>(n));
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                cin >> a[i][j];
            }
        }
        vector<vector<int>> value(m, vector<int>(n, 0)); //价值
        value[0][0] = a[0][0];
        for(int i = 1; i < m; i++)
        {
            value[i][0] = value[i-1][0] + a[i][0];
        }
        for(int j = 1; j < m; j++)
        {
            value[0][j] = value[0][j-1] + a[0][j];
        }
        for(int i = 1; i < m; i++)
        {
            for(int j = 1; j < n; j++)
            {
                value[i][j] = max(value[i-1][j] + a[i][j], value[i][j-1] + a[i][j]);
            }
        }
        int ans = m + n + 1;
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(value[i][j] >= x && i + j < ans) ans = i + j;
            }
        }
        if(ans == m + n + 1) cout << -1 << endl;
        else cout << ans << endl;
    }
    return 0;
}

时间复杂度O(m * n),空间复杂度O(m * n)。

2. 二叉树按以下规则进行字符串编码序列化存储并统计相同子树

题目:

二叉树按以下规则进行字符串编码序列化存储:

  1. 如果当前树为空,则表示为X;
  2. 如果当前树不为空,则表示为(left_sub_tree)current_value(right_sub_tree);
    left_sub_tree:左子树按此规则序列化后得到的字符串
    right_sub_tree:右子树按此规则序列化后得到的字符串

例如:
【2023-4-10 网易春招笔试题 开发岗】_第1张图片
对应的字符串编码如下:

((X)2(X))1(((X)4(X))3((X)5(X)))

请编写代码实现从输入的字符串反序列化出对应的二叉树结构,并找出其中所有重复的子树,输出一共存在重复子树的个数,相同子树只计一次

输入描述:

输入字符串编码的二叉树

输出描述:

重复子树的个数

示例1:
输入输出示例仅供试,后台判题数据一般不包含示例

输入:

((X)2(X))1((()4())3((X)2(X)))

输出:

1

说明:

存在相同叶节点2,因此输出1

字符串括号匹配 + 哈希表统计子串出现次数:

看起来是二叉树的问题,其实题目在误导你,根本和二叉树没有关系,反序列建立二叉树和遍历查找重复子树的过程根本是不需要的。本题只需要对给出的原始字符串进行括号匹配和切割,然后对子串进行哈希统计找重复即可,因为子串可以完全等价于序列化的子树,处理字符串就相当于处理树。

具体做法如下:
逐个字符遍历字符串,将遍历到的字符装入一个字符栈中,每当遍历到一个右括号 ‘)’ 就按括号匹配的规则进行出栈(出栈的右括号和左括号数量一样多)。一个括号匹配完成,就将出栈的字符组成一个子串,在哈希表中统计该子串出现的次数,然后再将该子串按原顺序重新装填回字符栈中,继续遍历。此时,一个子串即代表一个子树,统计子串出现的次数就是统计子树出现的次数。最后,在哈希表中找出重复出现的子串数量(除了空节点 “(X)” 以外),即为答案。

代码2:

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    string str;
    while(cin >> str) {
        unordered_map<string, int> hash;
        stack<char> a;
        for(auto s : str) {
            a.emplace(s);
            if(s == ')') {
                stack<char> b;
                int n = 0;
                while(!a.empty()) {
                    char c = a.top();
                    b.emplace(c);
                    a.pop();
                    if(c == ')') n++;
                    if(c == '(') {
                        n--;
                        if(n == 0) break;
                    }
                }
                string ss;
                while(!b.empty()) {
                    char c = b.top();
                    ss += c;
                    a.emplace(c);
                    b.pop();
                }
                hash[ss]++;
            }
        }
        int ans = 0;
        for(auto it = hash.begin(); it != hash.end(); it++)
        {
            if(it->first == "(X)") continue;
            if(it->second >= 2) ans++;
        }
        cout << ans << endl;
    }
    return 0;
}

复杂度分析:

最坏时间复杂度O(N2),最好时间复杂度O(N*logN),空间复杂度O(M)。其中,N为树的节点个数,M为字符串长度。

最坏时间复杂度在树退化为链表时取得(每个节点都要在每一层中重复出栈统计),最好时间复杂度在树是完全二叉树时取得。

最坏时间复杂度:树有N个节点,每个节点为一层,每层节点都要将以其为根节点的子树全部出栈,所以计算次数为1+2+3+…+N = (N*(N+1)) / 2,即O(N2)。
最好时间复杂度:树有N个节点,为一棵完全二叉树,树的深度为M = log2N,树的每层有2M-1个节点。每层节点都要将以其为根节点的子树全部出栈,所以计算次数为2M-1 + 2M-2 * (22-1) + 2M-3 * (23-1) + … = 2M * M + 2M-1 - 2M-2 - 2M-3 - …,即O(2M * M) = O(N * log2N)。

你可能感兴趣的:(刷题,算法,数据结构,c++,动态规划,哈希)