华为机试刷题


  1. 服务器广播

题目:服务器连接方式包括直接相连,间接连接。 A 和 B 直接连接, B 和 c 直接连接,则 A 和 c 间接连接。直接连接和间接连接都可以发送广播。
给出一个 N * N 数组,代表 N 个服务器, matrix[i][j] == 1 ,则代表 i 和 j 直接连接;不等于 1 时,代表 i 和 j 不直接连接。 matrix[i][i]== 1 ,即自己和自己直接连接。 matrix[i][j]==matrix[j][i] 。计算初始需要给几台服务器广播,才可以使侮个服务器都收到广播。
输入描述: n * n 矩阵,

[[1,1,0],[1,1,0],[0,0,1]]
1
输出描述:整数

2

 int main () {
    
    //vector<vector<int>> v{{1,0,1,0,1,1},{0,1,0,1,0,0},{1,0,1,0,0,0},{0,1,0,1,0,0},{1,0,0,0,1,0},{1,0,0,0,0,1}};
    vector<vector<int>> v{{1,0,1,0,1,1},{0,1,0,0,0,0},{1,0,1,0,0,0},{0,0,0,1,0,0},{1,0,0,0,1,0},{1,0,0,0,0,1}};
    unordered_map<int,set<int>> a;
    auto len = v.size();
    for (int i = 0;i<len;i++) {
        for (int j=0;j<len;j++) {
            if (v[i][j] == 1) {
                a[i].insert(j);
            }
        }
    }
    for (auto iter = a.begin(); iter != a.end();iter++) {
        int num = iter->first;
        set<int> tmp =iter->second;
        for (int j : tmp) {
            if (num != j) {
                a[j].insert(tmp.begin(),tmp.end());
            }
        }
    }
    set<set<int>> ret;
    for (auto iter = a.begin(); iter != a.end();iter++) {
        set<int> tmp =iter->second;
        ret.insert(tmp);
    }
    cout << ret.size() << endl;

    return 0;
}

心路历程:用什么数据结构有时比算法重要,数据结构也能体现解决方法。
开始拿到题目,纸上画了画人工是怎么思考的,第一感觉是想到做过的一道题,一个矩阵,某元素为1的话会像炸弹那样令跟它同一行和同一列的元素都变成1,新生成的1不会有这个效果。画格子画了会没啥感觉,又想到这题从描述就天然是个图问题,用dfs递归下?但是天然的对dfs比较排斥,估计写不来,并没有做过多思考。再画两下,突然就画出了题解中的数据结构,map, 接下来就比较容易了。中间也考虑过用两层vector,一想内层的大小不一致不能用, 题解中答案写完后试了下内层的vector也是可变的,大小能任意变,这题数据结构改成vector<vector> 应该也可以,第一层的下标就相当于map的key, 但是直观想内层的vector还得去重吧,改成vector<set> 估计会更好;还碰到对set中insert set 的迟疑,需要手动考虑去重吗?答案是不需要,暴力insert就行了。两个set怎么合并 ? a.insert(b.begin(), b.end()) 即可。支持两层set吗?支持。怎么判定最后要多少个广播?不同的set个数。即相互连接的服务器的set最后里面的元素是一样的,为了保证能一样,所以用set没用unordered_set,而为了性能用了unordered_map。边界条件处理,这块得加强,没多少想法。如果有多个服务器每个都是孤岛,没跟外界连,是否最终会合并成一个?所以针对这种,要将v[i][i] 自己也放进set容器里

经验:
1.遇到报错一定要多检查括号写错没
ret.insert(tmp); 这句手误打成了 ret.insert< tmp >; 没检查出来,报错为:
reference to non-static member function must be called

2.对于迭代器使用不熟练,int num = iter->first; 写这块时不确定是
int num = *iter->first;
或者 int num = *(iter)->first)
或者 int num = *(iter->first); 浪费了几分钟时间

  1. 首先是优先级要记牢:(优先级越高越先)
    第一优先级: :: 仅此一个作用域解析符
    第二优先级:()[] -> .
    第三优先级:* &

  2. 迭代器:vector中 *iter就能访问到数据元素了,而map中不需要 * ,auto p = iter->first; 就能访问到第一个元素了

vector<int> bb{1,2,3,4};
for (auto i = bb.begin();i!=bb.end();i++) {     
    cout << *i << " ";
}
输出 : 1 2 3 4
unordered_map<int,set<int>> a;
for (auto iter = a.begin(); iter != a.end();iter++) {
        int num = iter->first;
        set<int> tmp =iter->second;
}

  1. 判断一个string能否转成int数

string str = "12388sf";
int ret = 0;
to_int(str, ret);

bool to_int(const string& str, int& ret) {
    int len = str.length();
    std::string::size_type sz;
    bool flag = false;
    try {
        ret = stoi(str,&sz);
        if (sz == len) {
            flag = true;
        }
    } catch (std::invalid_argument&) {
    } catch (std::out_of_range&) { // {}内可以是空语句的
    } catch (std::exception& e) {
        cout << e.what() << endl;
    } 
    //} catch (...) {
    //}
    return flag;
}
    

注意点:
stoi的原型为:
int stoi (const string& str, size_t* idx = 0, int base = 10);
第二个参数为能转成数字的下一位的下标,是指针。第三个参数为要将第一个参数中数字用什么进制解释。如果str的第一个字符不是字符0-9,则会出异常,报 invalid_argument , 如果范围超过了int,则报 out_of_range 异常,如果这两点都没问题,而 sz 的大小和 length 不相等,则说明数字后面还有非数字字符。所以这个函数用起来还是比较麻烦的,得自己check。
另一个用法举例:

std::string str_hex = "40c3";
int i_hex = std::stoi (str_hex,nullptr,16);
std::cout << str_hex << ": " << i_hex << '\n';

输出:

40c3:  16579

  • 字符串分割

题目:实现字符串分割算法split(str,delim),传入待分割字符串和分割字符,返回数组,如果delim参数不传,则对字符串逐个分割。
比如调用split(“abcbebb”,‘b’),返回为[“a”,“c”,“e”],调用split(‘abcd’),返回[‘a’,‘b’,‘c’,d’]

std::vector<std::string> split_string(const std::string& s, const char flag = ' ') {
    if (s.empty()) {
        return {};
    } 
    std::vector<std::string> str_vec;
    if (flag != '\0') { // 注意点一:用'\0'表示空字符,表示参数二没传入。这个一度阻塞了思路。同时记住'\0'很特殊,是ascii表的第一个,即是基准
        istringstream iss(s);
        std::string temp;
        while (getline(iss, temp, flag)) {
            if (!temp.empty()) {
                str_vec.push_back(temp);
            }
        }
    } else {
        for(char i : s) {
            string t;
            t.push_back(i); // 注意点二:将char转成string的方法:往新申请的string里push_back(char)即可。另外注意不要用to_string,这个传入的参数是int float double等数字型的变量
            str_vec.push_back(t);
        }
    }
    return char_vec;
}

  • 单词压缩编码

题目:给定一个单词列表,将这个列表编码成一个索引字符串 S 与一个索引列表 A。
例如,如果这个列表是 [“time”, “me”, “bell”],将其表示为 S = “time#bell#” 和 indexes = [0, 2, 5]。
对于每一个索引,可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复之前的单词列表。
输入描述:数组。
输出描述:成功对给定单词列表进行编码的最小字符串长度

class Solution {
public:
    int minimumLengthEncoding(vector<string>& words) {
        sort(words.begin(), words.end(), [](const string& a, const string& b) -> bool {return a.length() > b.length();});
        string ret = words[0] + "#";
        for (int i = 1; i < words.size(); ++i) {
            auto found = ret.find(words[i] + "#");
            if (found == string::npos) {
                ret += words[i] + "#";
            }
        }
        return ret.length();
    }
};

思路很简单,按长度依次处理是关键,另外需要注意题目要求必须以“#”结束,所以比如 time# 可以匹配 me,不能匹配 ti, 为此将每个word加上“#”后才进行find。解法的时空效率不怎么高


  • 打印任务排序

题目:某个打印机根据打印队列执行打印任务。打印任务分为九个优先级,分别采用数字1~9表示,数字越大优先级越高。打印机每次从队列头部取出第一个任务A,然后检查队列余下任务中有没有比A优先级更高的任务,如果有比A优先级高的任务,则将任务A放到队列尾部,否则执行任务A的打印。请编写一个程序,根据输入的打印队列,输出实际打印顺序

struct mydata{
    int n;
    int pos;
    mydata(int i, int j):n(i),pos(j) {}
};

bool comp(const mydata& a, const mydata& b) {
    return a.n < b.n;
}
int main () {
    int n = 0;
    while(cin>>n) {
        vector<int> p;
        deque<mydata> v;
        for(int i=0;i<n;i++) {
            int p = 0;
            cin >> p;
            mydata m(p,i);
            v.push_back(m);
        }
        while(!v.empty()) {
            auto m = *max_element(v.begin(), v.end(), comp);
            int nn = m.n;
            if (nn == v.front().n) {
                p.push_back(m.pos);
                v.pop_front();
            } else {
                auto t = v.front();
                v.push_back(t);
                v.pop_front();
            }
        }
        for(auto i : p) {
            cout << i << " ";
        }
        cout << endl;
    }
    return 0;
}

输入

6
1 1 9 1 1 1

输出

2 3 4 5 0 1
  1. 变量命名比较随意,机试先追求把题做出来,再追求命名、格式这些东西
  2. deque 可以pop_front,vector没有
  3. max_element 可以用于自定义对象,要自定义比较函数。同时有min_element,这两个的自定义比较函数中,对于数值型的统一用 return x < y; 如果需要取最小值,则用 min_element,如果要用最大值则用max_element。
  4. 同样的需要保留住原始输入的位置信息,所以创了个新数据类型
  • 0
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值