华为编程题目(实时更新)

1.大小端整数

计算机中对整型数据的表示有两种方式:大端序和小端序,大端序的高位字节在低地址,小端序的高位字节在高地址。例如:对数字 65538,其4字节表示的大端序内容为00 01 00 02,小端序内容为02 00 01 00

现输入一个字符串表示的十进制整数(含负数),请分别输出以4字节表示的大端序和小端序:

  • 负数以补码形式表示。
  • 如果输入的整数的值超出 [-2^31, 2^32) 范围,则输出字符串overflow
解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 64MB, 其他语言:128MB

输入

十进制整数,以负号-开头表示负数,其它为正整数;数字长度范围:[1,32]。

输入数字不含前导零。

输出

大端序 + \n + 小端序;或字符串overflow

大端序和小端序的输出格式:每个字节以两位16进制数字表示(16进制数中A-F要大写),字节之间以单空格分隔。

样例1

复制输入:

-10

复制输出:

FF FF FF F6 F6 FF FF FF

解释:

含负号表示为负整数。
该负整数的补码表示为 FF FF FF F6,其对应大端序和小端序内容分别为FF FF FF F6F6 FF FF FF
按输出格式要求输出其大端序和小端序内容,中间加换行符。

样例2

复制输入:

4027691818

复制输出:

F0 11 B3 2A 2A B3 11 F0

解释:

输入 4027691818 为正整数,按输出格式要求输出其大端序和小端序内容,中间加换行符。

样例3

复制输入:

1234567890123456789012345678900

复制输出:

overflow

解释:

输入数字超过[-2^31, 2^32) 范围,因此输出 overflow 。

C++代码:
#include <iostream>
#include <string>
#include <utility>
#include <algorithm>
#include <sstream>
#include <iomanip>
using namespace std;

class Solution {
public:
    // 待实现函数,在此函数中填入答题代码;
    string GetHexString(long long input)
    {
// Check for overflow
        if (input < -2147483648LL || input >= 4294967296LL) {
            return "overflow";
        }

        // Convert input to unsigned int
        unsigned int value = static_cast<unsigned int>(input);

        // Convert unsigned int to big endian and little endian strings
        stringstream bigEndianStream;
        bigEndianStream << uppercase << setfill('0') << setw(2) << hex << ((value >> 24) & 0xFF);
        bigEndianStream << " " << uppercase << setfill('0') << setw(2) << hex << ((value >> 16) & 0xFF);
        bigEndianStream << " " << uppercase << setfill('0') << setw(2) << hex << ((value >> 8) & 0xFF);
        bigEndianStream << " " << uppercase << setfill('0') << setw(2) << hex << (value & 0xFF);

        stringstream littleEndianStream;
        littleEndianStream << uppercase << setfill('0') << setw(2) << hex << (value & 0xFF);
        littleEndianStream << " " << uppercase << setfill('0') << setw(2) << hex << ((value >> 8) & 0xFF);
        littleEndianStream << " " << uppercase << setfill('0') << setw(2) << hex << ((value >> 16) & 0xFF);
        littleEndianStream << " " << uppercase << setfill('0') << setw(2) << hex << ((value >> 24) & 0xFF);

        // Concatenate big endian and little endian strings
        string bigEndianStr = bigEndianStream.str();
        string littleEndianStr = littleEndianStream.str();

        return bigEndianStr + "\n" + littleEndianStr;
    }
};

int main()
{   
    long long input;
    cin >> input;
    
    Solution solu;
    string result = solu.GetHexString(input);
    cout << result;
    return 0;
}


2.公共字符

公共字符

给定 m 个字符串,请计算有哪些字符在所有字符串中都出现过 n 次及以上。

解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 64MB, 其他语言:128MB

输入

首行是整数 n ,取值范围 [1,100]
第二行是整数 m ,表示字符串的个数,取值范围 [1,100]
接下来 m 行,每行一个仅由英文字母和数字组成的字符串,长度范围 [1,1000)

输出

按ASCII码升序输出所有符合要求的字符序列; 如果没有符合要求的字符,则输出空序列[]

样例1

复制输入:

2 3 aabbccFFFFx2x2 aaccddFFFFx2x2 aabcdFFFFx2x2

复制输出:

[2 F a x]

解释:

字符 a 在三个字符串中都出现 2次,符合要求;
字符 b 在第二三个字符串中分别出现 0次、1次,不符合要求;
字符 c 在第三个字符串中出现 1次,不符合要求;
字符 d 在第三个字符串中出现 1次,不符合要求;
字符 F 在三个字符串中都出现了 4 次,符合要求;
字符 x 在三个字符串中都出现了 2 次,符合要求;
字符 2 在三个字符串中都出现了 2 次,符合要求;

因此字符 a、F、x、2符合要求,按ASCII码升序输出为 [2 F a x]

样例2

复制输入:

2 3 aa bb cc

复制输出:

[]

C++代码:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <algorithm>
using namespace std;

class Solution {
public:
    // 待实现函数,在此函数中填入答题代码;
    vector<char> GetNTimesCharacter(int n, const vector<string> &strings)
    {
        // 存储所有字符串中字符出现至少n次的结果
        map<char, int> globalCharFreq;
        vector<char> result;
        for (int i = 0; i < strings.size(); ++i) {
            map<char, int> localCharFreq;
            for (char ch : strings[i]) {
                localCharFreq[ch]++;
            }
            for (auto &p : localCharFreq) {
                if (p.second >= n) {
                    if (i == 0) {
                        // 第一个字符串初始化计数
                        globalCharFreq[p.first] = 1;
                    } else if (globalCharFreq.find(p.first) != globalCharFreq.end()) {
                        // 后续字符串累加计数
                        globalCharFreq[p.first]++;
                    }
                }
            }
        }    
        // 遍历 globalCharFreq,将出现次数等于字符串数量的字符添加到结果中
        for (auto &p : globalCharFreq) {
            if (p.second == strings.size()) {
                result.push_back(p.first);
            }
        }

        // 按ASCII升序排列
        sort(result.begin(), result.end());
        return result;
    }
};
inline int ReadInt()
{
    int number;
    cin >> number;
    return number;
}

template<typename T>
inline vector<T> ReadVector(int size)
{
    vector<T> objects(size);
    for (int i = 0; i < size; ++i) {
        cin >> objects[i];
    }
    return objects;
}

template<typename T>
inline void WriteVector(const vector<T>& objects, char delimeter = ' ')
{
    auto it = objects.begin();
    if (it == objects.end()) {
        return;
    }
    cout << *it;
    for (++it; it != objects.end(); ++it) {
        cout << delimeter << *it;
    }
}

int main()
{   
    int n = ReadInt();
    int m = ReadInt();
    vector<string> strings = ReadVector<string>(m);
    
    Solution solu;
    auto result = solu.GetNTimesCharacter(n, strings);
    cout << "[";
    WriteVector(result);
    cout << "]" << endl;
    return 0;
}

3.呼叫转移

呼叫转移

呼叫转移是指您的电话无法接听或您不愿接电话,可以将来电转移到其它电话号码上。它是电信业一项传统通信业务,又称呼叫前转、呼入转移。

  • 用户被呼叫时的状态有4种:idlebusyno-responseunreachable
  • 用户可登记的5种呼叫转移,格式为type number,type代表转移种类, number代表转移号码:
    type为 0:无条件转移,优先级最高,用户处于任何状态都触发此转移
    type为 1:用户状态busy时触发此转移
    type为 2:用户状态no-response时触发此转移
    type为 3:用户状态unreachable时触发此转移
    type为 4:默认转移,优先级最低,用户不是idle状态时,且无法触发上述四种转移,触发此转移

注:同一个状态可登记多次,以最后一次登记为准。

现给出某一用户当前的用户状态,以及其登记的若干个呼叫转移号码,请输出最终的呼叫结果:

  • 若发生转移,则输出转移号码
  • 若用户状态为idle,且未发生转移时,则呼叫本机成功,输出success
  • 若呼叫失败:既没有发生转移,也没有呼叫本机成功,则输出failure。例如,用户状态为 busy,但用户既未登记 type 为 0 或 1 或 4 的呼叫转移,则呼叫失败。
解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 256MB, 其他语言:512MB

输入

第一行是数字 num 和 字符串 status:num代表呼叫转移登记的次数( 0 < N <= 20),status表示用户被呼叫时的状态。
接下来 num 行是用户的呼叫转移登记操作,转移号码长度 6-15位,用例保证输入合法。

输出

一个字符串,代表最终的呼叫结果

样例1

复制输入:

3 busy 2 18912345678 4 18912345678 4 13312345567

复制输出:

13312345567

解释:

用户busy,且没有登记 busy 转移,但登记默认转移,呼叫转移到默认转移号码。
默认转移号码已最后一次登记为准

样例2

复制输入:

1 no-response 3 075587678100

复制输出:

failure

解释:

用户no-response,没有登记no-response转移,也没有登记默认转移,呼叫失败。

样例3

复制输入:

1 idle 3 075587678100

复制输出:

success

解释:

用户idle,且没有登记无条件转移,呼叫成功

C++代码:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;

class Solution {
public:
    string Calling(const string &status, const vector<pair<int, string>> &regCallForwardNums)
    {
        unordered_map<int, string> callForwards;
        // 初始化呼叫状态映射
        unordered_map<string, int> statusMap = {
  {"idle", -1}, {"busy", 1}, {"no-response", 2}, {"unreachable", 3}};
        
        // 存储用户设置的呼叫转移
        for (auto &reg : regCallForwardNums) {
            callForwards[reg.first] = reg.second;
        }
        
        if (status == "idle" && callForwards.count(0) == 0) {
            // 用户状态为idle,且无无条件转移type=0
            return "success";
        }

        if (callForwards.count(0)) {
            // 检查是否有无条件转移
            return callForwards[0];
        } else if (statusMap.count(status) && callForwards.count(statusMap[status])) {
            // 检查用户状态对应的转移
            return callForwards[statusMap[status]];
        } else if (callForwards.count(4)) {
            // 检查默认转移
            return callForwards[4];
        }
        
        // 没有匹配的转移则失败
        return "failure";
    }
};

// 以下为考题输入输出框架,此部分代码不建议改动
inline string ReadLine()
{
    string line;
    getline(cin, line);
    return line;
}

inline vector<string> ReadLines(int size)
{
    vector<string> lines(size);
    for (int i = 0; i < size; ++i) {
        lines[i] = ReadLine();
    }
    return lines;
}

inline pair<string, string> SplitPair(const string& word, char delimeter)
{
    auto pos = word.find(delimeter);
    return make_pair(word.substr(0, pos), word.substr(pos + 1));
}

int main()
{
    pair<string, string> p = SplitPair(ReadLine(), ' ');
    int n = stoi(p.first);
    string status = p.second;
    vector<string> lines = ReadLines(n);
    vector<pair<int, string>> regCallForwardNums;
    for (auto s : lines) {
        p = SplitPair(s, ' ');
        regCallForwardNums.push_back(make_pair(stoi(p.first), p.second));
    }
    
    Solution solu;
    string out = solu.Calling(status, regCallForwardNums);
    cout << out << endl;
    return 0;
}

4.单板告警统计

假设某系统中有两块单板,这两块单板上产生的告警ID(以十六进制字符串表示)分别存储在列表 arrayA 和列表arrayB 中。
请统计并输出系统中的所有告警ID(即arrayA和arrayB的并集):

  • 如果告警ID存在重复,先需去重。
  • 然后以告警ID所表示值的升序排序输出
解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 256MB, 其他语言:512MB

输入

第一行1个整数,表示告警列表arrayA的长度,取值范围为:[0,1000]
第二行表示告警列表arrayA的数据,告警ID以单空格分隔
第三行1个整数,表示告警列表arrayB的长度,取值范围为:[0,1000]
第四行表示告警列表arrayB的数据,告警ID以单空格分隔

告警ID为无符号整数,以十六进制字符串表示,由数字字符、大写字母A~F组成,固定为 8 个字符。

输出

按升序排序的告警ID,以单空格分隔

样例1

复制输入:

2 00001001 00ABCD00 3 FFFFFAAB FFFFFAAB 00ABCD00

复制输出:

[00001001 00ABCD00 FFFFFAAB]

解释:

系统中共有三个告警ID:
00ABCD00,去重后保留一个;
FFFFFAAB,去重后保留一个;
00001001,只有一个。
按所表示值的大小升序排列,输出这三个告警ID为 [00001001 00ABCD00 FFFFFAAB] 。

样例2

复制输入:

0 1 FFFFFAAB

复制输出:

[FFFFFAAB]

解释:

提示

答题要求:您编写的代码需要符合CleanCode的要求(包括通用编码规范、安全编码规范和圈复杂度)

C++代码:
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;

class Solution {
public:
    // 待实现函数,在此函数中填入答题代码;
    vector<string> GetAllFault(const vector<string> &arrayA, const vector<string> &arrayB)
    {
        // Combine both arrays into one
        vector<string> combined(arrayA);
        combined.insert(combined.end(), arrayB.begin(), arrayB.end());

        // Remove duplicates
        sort(combined.begin(), combined.end());
        combined.erase(unique(combined.begin(), combined.end()), combined.end());

        // Convert hex strings to integers for sorting
        vector<pair<unsigned int, string>> converted;
        for (const string &hexStr : combined) {
            unsigned int value = stoul(hexStr, nullptr, 16);
            converted.push_back(make_pair(value, hexStr));
        }

        // Sort by integer value
        sort(converted.begin(), converted.end());

        // Extract the sorted strings back into the result
        vector<string> result;
        for (const auto &pair : converted) {
            result.push_back(pair.second);
        }

        return result;
    }
};

inline int ReadInt()
{
    int number;
    std::cin >> number;
    return number;
}

template<typename T>
inline std::vector<T> ReadVector(int size)
{
    std::vector<T> objects(size);
    for (int i = 0; i < size; ++i) {
        std::cin >> objects[i];
    }
    return objects;
}

template<typename T>
inline void WriteVector(const std::vector<T>& objects, char delimeter = ' ')
{
    auto it = objects.begin();
    if (it == objects.end()) {
        return;
    }
    std::cout << *it;
    for (++it; it != objects.end(); ++it) {
        std::cout << delimeter << *it;
    }
}

int main()
{
    int arrayANum = ReadInt();
    vector<string> arrayA = ReadVector<string>(arrayANum);
    int arrayBNum = ReadInt();
    vector<string> arrayB = ReadVector<string>(arrayBNum);

    Solution solu;
    auto result = solu.GetAllFault(arrayA, arrayB);
    cout << "[";
    WriteVector(result, ' ');
    cout << "]" << endl;
    return 0;
}

5.表达式计算

现给你一个字符串,代表一个后序遍历形式的四则运算表达式,请计算出表达式的结果(只输出整数部分)。

注:

  • 都是双目运算,不存在单目运算;
  • 中间计算结果范围:[-2^31, 2^31);
  • 除法只需保留整数部分,比如:5/4=1, (-5)/3=-1, 5/(-3)=-1,无需考虑余数;无需考虑除数为0的情况,用例不存在除零。
解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 64MB, 其他语言:128MB

输入

一个字符串,代表一个四则运算表达式,由若干操作数和运算符组成,操作数、运算符之间都用一个逗号隔开。长度范围:[1,50000)。
注:用例保证输入合法:1)一定有计算结果; 2)操作数是合法的整数; 3)运算符只包含+-*/四种。

输出

一个整数,表示表达式的计算结果,用例保证最终结果范围:-2,147,483,648 ~ 2,147,483,647。

样例1

复制输入:

9,3,5,-,2,*,+

复制输出:

5

样例2

复制输入:

3,-3,-,2,/,10,-

复制输出:

-7

C++:

#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <utility>
#include <algorithm>
using namespace std;

class Solution {
public:
    // 将字符串表达式分割成操作数和运算符的数组
    vector<string> SplitExpression(const string& expression) {
        vector<string> tokens;
        string token;
        for (char c : expression) {
            if (c == ',') {
                if (!token.empty()) {
                    tokens.push_back(token);
                    token.clear();
                }
            } else {
                token += c;
            }
        }
        if (!token.empty()) {
            tokens.push_back(token);
        }
        return tokens;
    }
    
    // 计算后序表达式
    int CalcExpression(const string &expression) {
        stack<int> st;
        vector<string> tokens = SplitExpression(expression);
        
        for (const string& token : tokens) {
            if (isdigit(token[0]) || token.size() > 1) { // 这个很关键!检查是否为操作数(可能是负数)
                st.push(stoi(token));
            } else {
                int r = st.top(); st.pop();
                int l = st.top(); st.pop();
                switch (token[0]) {
                    case '+': st.push(l + r); break;
                    case '-': st.push(l - r); break;
                    case '*': st.push(l * r); break;
                    case '/': st.push(l / r); break;
                }
            }
        }
        return st.top();
    }
};

inline string ReadLine()
{
    string line;
    getline(cin, line);
    return line;
}

int main()
{
    string expression = ReadLine();
    Solution solu;
    int result = solu.CalcExpression(expression);
    cout << result << endl;
    
    return 0;
}

6.话单发送

某核心网设备向计费网关发送话单(一个话单指一条通话记录的信息),发送规则如下:

  • 每个话单具有长度和优先级两个属性,优先级值越小表示优先级越高,高优先级的发送完,才能发送次优先级的。
  • 设备有一个承载规格,表示发送话单总容量的阈值,发送话单的总长度不能超过承载规格。

现给定设备的承载规格和待发送话单(长度和优先级)列表,请计算最多可以发送多少个话单。

解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 256MB, 其他语言:512MB

输入

第一行是正整数 cap ,表示设备的承载规格,取值范围:[1,10000]
第二行是正整数 num ,表示待发送话单的数量,取值范围:[0,100]
第三行 num 个整数,依次表示每个待发送话单的长度,每个值的范围:[0, 1000]
第四行 num 个整数,依次表示每个待发送话单的优先级,每个值的范围:[0,30]

第三行和第四行的数据一一对应,表示同一个话单的长度和优先级。

输出

输出一个整数,表示最多能发送话单的个数。

样例1

复制输入:

110 5 50 20 30 10 50 2 2 1 3 1

复制输出:

3

解释:

  • 首先尝试发送优先级为 1 的话单,长度分别是30和50,长度之和在承载规格范围内,优先级 1 的两个话单全部完成发送,剩余容量为30。
  • 接着尝试发送优先级为 2 的话单,长度20的被发送,剩余容量为10,长度50的无法发送。
  • 因优先级 2 的话单未发送完(仍剩余一条),优先级3的所有话单都无法发送。

所以,最多能发送的话单数为 3 。

C++代码:

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

class Solution {
public:
    // 待实现函数,在此函数中填入答题代码
    int GetMaxSendNum(int cap, const vector<int> &bill, const vector<int> &pri)
    {
        int num = bill.size();
        vector<pair<int, int>> bills(num);
        for (int i = 0; i < num; i++) {
            bills[i] = {pri[i], bill[i]};
        }
        sort(bills.begin(), bills.end());
        int res = 0;
        int curCap = 0;
        for (int i = 0; i < num; i++){
            if (curCap + bills[i].second <= cap) {
                res++;
                curCap += bills[i].second;
            }else {
                break;
            }
        }
        return res;
    }
};

// 以下为考题输入输出框架,此部分代码不建议改动
inline int ReadInt()
{
    int number;
    std::cin >> number;
    return number;
}

template<typename T>
inline std::vector<T> ReadVector(int size)
{
    std::vector<T> objects(size);
    for (int i = 0; i < size; ++i) {
        std::cin >> objects[i];
    }
    return objects;
}

int main()
{
    int cap = ReadInt();
    int n = ReadInt();
    vector<int> bill = ReadVector<int>(n);
    vector<int> pri = ReadVector<int>(n);
    Solution solu;
    int res = solu.GetMaxSendNum(cap, bill, pri);
    cout << res;
    return 0;
}

心得:

  • 核心就是利用hash结构的pair,将优先级和容量组成pair,然后利用优先级排序,最后在遍历即可!

7.字符排序

给定一个字符串,仅含英文字母和数字,请按如下规则对其进行排序:

  • 排序后,原位置是数字的,排序后仍然是数字;原位置是字母的,排序后仍然是字母。
  • 数字:按 0-9 升序。
  • 英文字母:大写字母大于小写字母,小写字母按 a-z 升序,大写字母按 A-Z 升序。
输入

输入为一行字符串,长度范围 [1,1000),字符串中不会出现除英文字母、数字以外的别的字符。

输出

输出排序后的字符串。

样例1

复制输入:

a2CB1c

复制输出:

a1cB2C

解释:

第二、五位置的数字分别为 2、1,排序后为1、2 ;
第一、三、四、六位置的字母分别为 a、C、B、c,小写字母a、c排在前;大写字母C、B排在后,并按 A-Z 升序为 B、C ;

因此最终输出为 a1cB2C

样例2

复制输入:

ab12C4Ac3B

复制输出:

ab12c3AB4C

解释:

C++代码:

#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;

class Solution {
public:
    // 待实现函数,在此函数中填入答题代码;
    string CharacterSort(const string &inputStr)
    {
        string result;
        vector<int> digits;
        vector<char> lowercase;
        vector<char> uppercase;
        // 分离字母和数字,并放入对应的容器中
        for (char c: inputStr) {
            if (isdigit(c)) {
                digits.push_back(c - '0'); // 将数字转为int是为了后面更好的排序!
            }else if (islower(c)) {
                lowercase.push_back(c);
            }else if (isupper(c)) {
                uppercase.push_back(c);
            }
        }
        // 分别对数字和字母进行排序
        sort(digits.begin(), digits.end());
        sort(lowercase.begin(), lowercase.end());
        sort(uppercase.begin(), uppercase.end());
        // 分别追踪数字和字母的迭代位置
        int digitsIndex = 0;
        int lowerIndex = 0;
        int upperIndex = 0;
        // 遍历原字符串,根据字符类型,从已排序容器中获取对应的字符
        for (int i = 0; i < inputStr.size(); ++i) {
            if (isdigit(inputStr[i])) {
                result += digits[digitsIndex++] + '0';
            }else {
                if (lowerIndex >= lowercase.size()) {
                    result += uppercase[upperIndex++];
                }else {
                    result += lowercase[lowerIndex++];
                }
            }
        }
        
        return result;
    }
};

inline string ReadLine()
{
    string line;
    getline(cin, line);
    return line;
}

int main()
{   
    string inputStr = ReadLine();
    
    Solution solu;
    string result = solu.CharacterSort(inputStr);
    cout << result;
    return 0;
}

8.统计无重复字符字串

统计无重复字符子串

给定一字符串,请统计位置连续,且无重复字符出现的子串数量。例如abc是无重复字符的子串,abb不是。
注:内容一样但位置不一样的子串,按不同子串参与统计。

一个字符串中任意个连续的字符组成的子序列称为该字符串的子串

解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 256MB, 其他语言:512MB

输入

一个字符串,仅由小写英文字母组成,其长度范围:[1, 1000000]

输出

一个整数,表示统计出的无重复字符的子串的数量。

样例1

复制输入:

abac

复制输出:

8

解释:

子串有 a、b、a、c、ab、ba、ac、aba、bac、abac, 无重复字符的子串为 a、b、a、c、ab、ba、ac、bac,因此统计结果为8。

样例2

复制输入:

xbmxbnh

复制输出:

21

解释:

无重复字符的子串为 x、b、m、x、b、n、h、xb、bm、mx、xb、bn、nh、xbm、bmx、mxb、xbn、bnh、mxbn、xbnh、mxbnh,因此统计结果为21。

C++代码:

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

class Solution {
   
public:
    // 待实现函数,在此函数中填入答题代码;
    int GetCountOfSubString(const string &input)
    {
   
        if (input.empty()) 
        {
   
            return 0;
        } 
        int n = input.size();
        int lastPos[26];
        fill_n(lastPos, 26, -1); // 初始化每个字符的最后位置为-1

        long long totalCount = 0; // 结果可能很大,使用更大的存储类型
        int start = 0; // 窗口的起始位置

        for (int end = 0; end < n; ++end) {
   
            char charIndex = input[end] - 'a';
            // 更新窗口的起始位置,确保窗口内没有重复字符
            if (lastPos[charIndex] != -1) {
   
                start = max(start, lastPos[charIndex] + 1);
            }
            // 以当前字符结尾的无重复字符子串的数量是窗口的长度
            totalCount += (end - start + 1);
            // 更新当前字符的最后出现位置
            lastPos[charIndex] = end;
        }
        
        return totalCount;
    }
};

int main()
{
   
    string input;
    cin >> input;

    Solution solu;
    cout << solu.GetCountOfSubString(input) << endl;

    return 0;
}


代码解读:

代码中使用了滑动窗口技术结合数组来追踪字符的最后出现位置,有效解决了要求无重复字符的子串计数问题。下面我将逐步详解这段代码的实现和逻辑:

初始化:
  1. 数组 lastPos:这个数组用于存储每个英文字母最后一次出现在字符串中的位置。因为字符串仅包含小写字母,所以数组大小为26。初始化为-1,表示开始时,没有任何字母被访问过。
int lastPos[26];
std::fill_n(lastPos, 26, -1);
变量定义:
  1. 变量 totalCount:用于累计满足条件的子串数量。由于字符串长度可能非常大(最大100万),所以使用 long long 类型以避免整数溢出。
  2. 窗口的指针 startendstart 是当前无重复子串的起始索引,end 是当前正在处理的字符的索引。
主逻辑循环:

对字符串 input 进行遍历。

  • 扩展窗口: 每次循环体内,end 指针每次都会向右移动一位(扩展窗口的右边界)。
for (int end = 0; end < n; ++end) {}
  • 检查并更新 start
    • 通过当前字符计算其在 lastPos 数组中的索引。
    • 如果当前的字符之前出现过(即在 lastPos 中的值不是-1),则可能需要调整窗口的起始位置 start,确保窗口内无重复字符。窗口的起始位置应该是之前该字符出现的位置的下一个位置(lastPos[charIndex] + 1)与当前 start 的较大值。
char charIndex = input[end] - 'a';
if (lastPos[charIndex] != -1) {
    start = std::max(start, lastPos[charIndex] + 1);
}
  • 计算子串数量:
    • 窗口内的字符都是不重复的,且以 end 指向的字符结尾的子串数量等于窗口长度。end - start + 1 表示从 startend(包括end)字符的数量。
totalCount += (end - start + 1);
  • 更新处理中的字符的最后出现位置:
lastPos[charIndex] = end;
返回结果:
  • 循环结束后,totalCount 存储了符合条件的所有子串的数量。
整体分析:

这段代码通过维护一个动态的滑动窗口来保持窗口内的字符唯一性,从而高效地统计所有可能的、不含重复字符的子串的数量。它的时间复杂度是线性的,也就是O(n),空间复杂度由于使用了固定大小的数组,是O(1)。这使得解法非常高效而适用于处理大数据量的输入。

9.手机壳库存管理

库存管理对于手机壳销售是否达成盈利最大化至关重要。

仓库中有一批不同型号的手机壳,每种型号手机壳的库存数量存在数组inventory中、总售价存在数组price中。每种型号手机壳的 销售收益 = 销售数量 * (price[i] / inventory[i]) 。

现给定市场上手机壳的最大需求量demand,请制定最佳销售策略以获得最大的总销售收益,并返回该值。

解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 256MB, 其他语言:512MB

输入

首行两个正整数 M 和 N,M 表示手机壳种类的个数,取值范围:[1, 1000]; N 表示市场最大需求量,取值范围:[1, 500] (单位为千部)。
第2行 M 个数字,表示每种型号手机壳的数量(单位为千部),每个数字的取值范围:(0.0,1000.0]
第3行 M 个数字,表示每种手机壳的总售价(单位为万元),顺序与第2行一一对应,每个数字的取值范围:(0.0,10000.0]。

输出

浮点数形式的最大收益值(万元为单位)

系统进行浮点数结果判断,误差在0.01之内即认为正确。

样例1

复制输入:

3 20 18 15.0 10 75.0 72 45

复制输出:

94.50

解释:

最大收益策略是卖出全部 15 千部第 2 种型号手机壳、以及 5 千部第 3 种型号手机壳,获得 72 + 45/2 = 94.5(万元)。

C++代码:

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 * Description: 上机编程认证
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 */
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <iomanip> 
using namespace std;

class Solution {
   
public:
    // 待实现函数,在此函数中填入答题代码;
    float PhoneSellManage(float demand, const vector<float> &inventory, const vector<float> &price)
    {
   
        int len = inventory.size();
        vector<pair<float, float>> profitPair(len);
        // 计算每种手机壳的单位收益并存储
        for (int i = 0; i < len; i++) {
   
            if (inventory[i] > 0) {
   
                profitPair[i] = {
   price[i] / inventory[i], inventory[i]};
            }else {
   
                profitPair[i] = {
   0.00, 0.00};
            }
        }
        // 根据单位收益从高到底排序
        sort(profitPair.rbegin(), profitPair.rend());
        float remainingDemand = demand;
        float salesSam = 0;
        for (const auto & pair: profitPair) {
   
            if (remainingDemand < 0) {
   
                break;
            }
            float mount = min(pair.second, remainingDemand);
            salesSam += pair.first * mount;
            remainingDemand -= mount;
        }
        return salesSam;
    }
};

inline int ReadInt()
{
   
    int number;
    std::cin >> number;
    return number;
}

template<typename T>
inline std::vector<T> ReadVector(int size)
{
   
    std::vector<T> objects(size);
    for (int i = 0; i < size; ++i) {
   
        std::cin >> objects[i];
    }
    return objects;
}

int main()
{
      
    int num;
    float demand;
    cin >> num >> demand;
    vector<float> inventory = ReadVector<float>(num);
    vector<float> price = ReadVector<float>(num);
    
    Solution solu;
    float result = solu.PhoneSellManage(demand, inventory, price);
    cout <<std::fixed << std::setprecision(2)<< result; //保留两位小数
    return 0;
}

10.日活月活统计

现有一份接口访问日志,每行日志格式如下,请统计日活数和月活数。
yyyy-mm-dd|client_ip|url|result

各字段说明:
yyyy-mm-dd:日志打印时间,一个日志文件中时间跨度保证都在同一个月内,但不保证每行是按日期有序的。
client_ip:为合法的点分十进制ipv4地址(1.1.1.1和1.01.001.1应视为同一个地址)。
url:访问的地址,格式如 /login.do,/query.html,仅包含字母、.、/和_。
result:接口访问结果,只有2种值:success 或 fail 。

日活数、月活数的统计规则

  • 日活数统计:统计当天有多少个不同的 client_ip 访问的地址是 /login.do,且结果为 success。
  • 月活数统计:统计当月有多少个不同的 client_ip 访问的地址是 /login.do,且结果为 success。
解答要求

时间限制: C/C++ 1000ms, 其他语言:2000ms

内存限制: C/C++ 256MB, 其他语言:512MB

输入

首行一个正整数 num ,表示日志行数,范围为 [1,50000]。
接下来 num 行字符串,每行字符串表示一条日志内容,每行字符串长度不超过150。

输出

32个整数,以单空格分隔。第1个整数表示月活数,第 2-32 个整数分别表示当月1-31天的日活数。

样例1

复制输入:

5 2020-02-01|192.168.218.218|/login.do|success 2020-02-01|192.168.218.218|/login.do|success 2020-02-01|192.168.210.210|/login.do|fail 2020-02-02|192.168.210.210|/login.do|success 2020-02-02|192.168.218.218|/login.do|success

复制输出:

2 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

解释:

二月的第一天即2月1日,有两条日志访问/login.do的结果为success,但都来自同一个ip(192.168.218.218),因此当天的日活数统计为1。
第二天有两条访问成功,来自两个不同的ip,因此日活数为 2。
当月仅有2个ip访问成功,因此月活数为2。注意:月活数不是日活数的简单累加。

样例2

复制输入:

3 2020-12-01|192.168.218.001|/login.do|success 2020-12-01|192.168.218.1|/login.do|success 2020-12-01|192.168.218.2|/to_login.do|success

复制输出:

1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

解释:

192.168.218.001和192.168.218.1视为同一个ip,/to_login.do 与 /login.do 不匹配,因此统计下来日活数为1,月活数为1。

要完成这个问题,关键在于解析日志并从中提取关心的数据:日期、客户端 IP 地址、URL 和结果。根据题意要求解析日志条目,只关注URL为/login.do且结果为success的日志条目。

详细步骤如下:

  1. 首先把每个客户端IP期望用set来消除重复,并确保 1.1.1.11.01.001.1 是相同的IP,可以通过整数化处理。
  2. 用一个哈希表(键为日期,值为客户端 IP 的集合)来存储每天有效的客户端IP以统计日活数。
  3. 用一个集合存储整个文件中有效的客户端IP来统计月活数。
  4. 日期可能不连续出现,但保证日志是同一月份的,用数组储存结果,大小固定为32(第一个位置存储月活数)。
C++代码:(思路非常清晰,行云流水!)

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2019. All rights reserved.
 * Description: 上机编程认证
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 */
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <sstream>
#include <set>
#include <unordered_map>

using namespace std;

class Solution {
   
public:
    // 待实现函数,在此函数中填入答题代码;;
    vector<int> GetActiveUserNum(const vector<string> &logs)
    {
   
        // 定义一个数组来统计每天的日活数,初始化31天,数组索引1-31对应于日期
        vector<int> daily_active(32, 0);

        // 一个哈希表记录每天成功登录的不同IP
        unordered_map<int, set<unsigned int
  • 31
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
华为机试题是一个Java编程题。以下是一个可能的答案: 这道题要求编写一个Java程序,实现如下功能: 在给定的整数数组中,找出出现次数最多的元素,并返回该元素。 解题思路如下: 1. 创建一个HashMap,用于存储每个元素及其出现的次数。 2. 遍历整数数组,对于数组中的每个元素: - 如果HashMap中已经存在该元素,则将该元素的计数加1; - 如果HashMap中不存在该元素,则将该元素加入HashMap,并将其计数设置为1。 3. 遍历HashMap的所有键值对,找出计数最大的元素。 4. 返回计数最大的元素。 以下是代码示例: import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3, 2, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4}; int result = findMostFrequentElement(arr); System.out.println("出现次数最多的元素是:" + result); } public static int findMostFrequentElement(int[] arr) { Map<Integer, Integer> map = new HashMap<>(); int maxCount = 0; int mostFrequentElement = 0; for (int i : arr) { if (map.containsKey(i)) { int count = map.get(i); map.put(i, count + 1); } else { map.put(i, 1); } } for (Map.Entry<Integer, Integer> entry : map.entrySet()) { int element = entry.getKey(); int count = entry.getValue(); if (count > maxCount) { maxCount = count; mostFrequentElement = element; } } return mostFrequentElement; } } 以上代码会输出"出现次数最多的元素是:4",因为在给定的数组中,元素4出现的次数最多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心之所向521

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值