【华为软件特战队2023.2.20笔试题】 最小缩进操作次数

【软件特战队2023.2.20笔试题】 最小缩进操作次数

朋友分享给我的,简单记录下

题目描述

请实现一个简单的代码缩进功能,把一段未缩进的代码,通过多次操作,最终实现每一行的缩进长度要求。

一次操作是指:
一次操作时缩进一个TAB长度
一次操作可以选择一行或者连续多行同时缩进。

给出的要缩进的代码长度用一个数组表示,要求计算出最少需要操作多少次。

输入描述:
一个整数n。表示代码总行数,取值范围【1,65535】
接下来一行有n个整数,依次表示第1~n行的最终缩进长度要求,取值范围:[0,1000000]。

示例1:
输入:
5
1 2 3 2 1
输出:
3
说明:最少需要操作三次,第1次操作全选所有行,缩进1个TAB;第二次操作选择2,3,4行,再缩进1个TAB;第三次才做选择第3行,再缩进1个TAB。

示例2:
输入:
9
0 1 2 0 2 4 2 1 0
输出:
6
说明:
第一次缩进后:0 0 1 0 2 4 2 1 0
第二次缩进后:0 0 0 0 2 4 2 1 0
第三次缩进后:0 0 0 0 1 3 1 0 0
第四次缩进后:0 0 0 0 0 2 0 0 0
第五次缩进后:0 0 0 0 0 1 0 0 0
第六次缩进后:0 0 0 0 0 0 0 0 0

解题思路

我们最终的目标是将一个连续数组的所有值通过操作都变成0,我们需要记录达到这个目标所用的最小的操作次数。
那么如何操作用的次数最少呢?我们采用以下策略:

  1. 对于连续的子数组,就对这里连续的数组所有的成员都执行一次缩进操作(即数值-1)。
  2. 对于不连续的数组,也就是单个的一个数据(以a[i]为例),就只能对a[i]执行a[i]次缩进,将它变成0。
    根据以上思路,我们的代码思路就是:
      1.寻找给出的数组的第一连续子数组:然后对这个这个子数组缩进x次(x表示这个连续数组中的所有成员的最小值),并记录操作的次数。
      2.重复上述操作,知道找不到任何一个连续子数组(也就表示着数组中所有成员的值都为0)。此时返回最小操作次数即可。

伪代码

int calMinTab(vector<int> tabVec, int nums) {
    
    
    int start = 0, end = 0;
    while (true) {
    
    
       //寻找第一个连续子数组,并记录begin和end,以及连续数组的最小值(minTab)
        if (findFirstContinusVec(tabVec, begin, end, minTab)) {
    
    
            //记录对此连续数组的操作次数
            rst = rst + minTab;
            //对所有数组中的值都减去操作的次数(模仿真正缩进操作)
            doTab(tabVec, beign, end);
            //如果找不到任何数组,说明数组为0了,退出循环。
        } else break;
    }
    return rst;
}

完整代码

#include <iostream>
#include <vector>
using namespace std;
class Solution {
    
    
public:
    vector<int> tabVec;
    int callMinTab() {
    
    
        if (tabVec.size() == 0) return 0;
        while (true) {
    
    
            //找到数组中第一个连续的数组
            if (findFirstContinusVec(tabVec)) {
    
    
                //找到了数组中第一个连续的数组
                //rst加上该连续数组中的最小值,
                rst += minNums;
                //对这个连续数组中的每个元素减去该最小值
                doTab(tabVec);
            }
            else return rst;
        }
        return rst;
    }
    void doTab(vector<int> &tabVec) {
    
    
        for (int i = begin; i <= end; i++) {
    
    
            tabVec[i] = tabVec[i] - minNums;
        }
    }
    //找到数组中第一个连续的数组,并且找到这个连续数组中的最小值minNums,开始位置begin,结束位置begin
    bool findFirstContinusVec(vector<int> tabVec) {
    
    
        //是否找到连续数组的第一个非零值
        bool ifFisrtNumsFind = false;
        int i = 0;
        for(;i< tabVec.size();i++) {
    
    
            //当找到连续数组的第一个非零值时
            if (ifFisrtNumsFind == true) {
    
    
                if (tabVec[i] == 0) {
    
    
                    //找到连续数组的最后一个非零值
                    end = i - 1;
                    return true;
                } else {
    
    
                    //更新最小值
                    if (tabVec[i] < minNums) minNums = tabVec[i];
                }
            }
            //当没有找到连续数组的第一个非零值时
            else if (ifFisrtNumsFind == false && tabVec[i] != 0) {
    
    
                //找到连续数组的第一个非零值
                minNums = tabVec[i];
                begin = i;
                ifFisrtNumsFind = true;
            } 
        } 
        if (ifFisrtNumsFind && i == tabVec.size()) {
    
    
            end = i -1;
            return true;
        }
        //没有找到任何连续数组,那么返回False
        return false;
}

private:
    int rst = 0;
    int minNums = INT_MAX;
    int begin = 0;
    int end = 0;
};

int main()
{
    
    
    int num, n;
    Solution t;
    while (cin >> num)
    {
    
    
        while (num--)
        {
    
    
            cin >> n;
            t.tabVec.push_back(n);
        }
        return t.callMinTab();
    }
}

结尾

本系列的所有题目都是面试实习群里的群友们面试完反馈的,想要加群一起交流分享新鲜的互联网面试经验的同学,请关注我的微信公众号:"奔跑的鲁班七号”,回复:“面试学习交流群” 获得群二维码,入群学习分享即可

猜你喜欢

转载自blog.csdn.net/weixin_41937380/article/details/129139816