LeetCode-华为面试题库做题笔记五

第五次

Posted by ZXY on March 22, 2020

写在前面

华为面试题库刷题第五次整理。

582. 杀死进程

给 n 个进程,每个进程都有一个独一无二的 PID (进程编号)和它的 PPID (父进程编号)。
每一个进程只有一个父进程,但是每个进程可能会有一个或者多个孩子进程。它们形成的关系就像一个树状结构。只有一个进程的 PPID 是 0 ,意味着这个进程没有父进程。所有的 PID 都会是唯一的正整数。
我们用两个序列来表示这些进程,第一个序列包含所有进程的 PID ,第二个序列包含所有进程对应的 PPID。
现在给定这两个序列和一个 PID 表示你要杀死的进程,函数返回一个 PID 序列,表示因为杀这个进程而导致的所有被杀掉的进程的编号。
当一个进程被杀掉的时候,它所有的孩子进程和后代进程都要被杀掉。
你可以以任意顺序排列返回的 PID 序列。

示例 1:
输入:
pid = [1, 3, 10, 5]
ppid = [3, 0, 5, 3]
kill = 5
输出: [5,10]

解法:

dfs(超时)

搜,就嗯搜,O(N^N),不超时就有鬼了。

代码:

class Solution {
private:
    vector<int> res;
public:
    void helper(vector<int>& a, vector<int>& b, int k){
        res.push_back(k);
        for(int i=0; i<b.size(); i++){
            if(b[i]==k)
                helper(a,b,a[i]);
        }
        return;
    }
    vector<int> killProcess(vector<int>& pid, vector<int>& ppid, int kill) {
        helper(pid,ppid, kill);
        return res;
    }
};

哈希+dfs

其实上一种做法是可行的,只是每一次递归的时候都需要遍历数组找儿子,很费时间,所以用哈希表存一下,查找的时间就剩下来了。

代码:

class Solution {
private:
    vector<int> res;
public:
    void helper(unordered_map<int,vector<int>>& m, int kill){
        auto pos = m.find(kill);
        if(pos!=m.end()){
            for(auto id : m[kill]){
                res.push_back(id);
                helper(m,id);
            }
        }
    }
    vector<int> killProcess(vector<int>& pid, vector<int>& ppid, int kill) {
        unordered_map<int,vector<int>> m;
        for(int i=0; i<ppid.size(); i++){
            if(ppid[i]>0){
                m[ppid[i]].push_back(pid[i]);
            }
        }
        res.clear();
        res.push_back(kill);
        helper(m,kill);
        return res;
    }
};

哈希+bfs

存储阶段和上一种方法一样,不过用队列模拟了bfs过程。

代码:

class Solution {
private:
    vector<int> res;
public:
    vector<int> killProcess(vector<int>& pid, vector<int>& ppid, int kill) {
        unordered_map<int,vector<int>> m;
        for(int i=0; i<ppid.size(); i++){
            if(ppid[i]>0){
                m[ppid[i]].push_back(pid[i]);
            }
        }
        res.clear();
        queue<int> q;
        q.push(kill);
        while(!q.empty()){
            int r = q.front();
            q.pop();
            res.push_back(r);
            auto pos = m.find(r);
            if(pos!=m.end()){
                for(auto id : m[r])
                    q.push(id);
            }
        }
        return res;
    }
};

539. 最小时间差

给定一个 24 小时制(小时:分钟)的时间列表,找出列表中任意两个时间的最小时间差并已分钟数表示。

示例:
输入: [“23:59”,”00:00”]
输出: 1

备注:

  1. 列表中时间数在 2~20000 之间。
  2. 每个时间取值在 00:00~23:59 之间。

解法:排序,然后求差就行了。注意最后一个时间和第一个也要作差。

代码:

class Solution {
public:
    struct time{
        int min;
        int hour;
    };
    int findMinDifference(vector<string>& a) {
        sort(a.begin(),a.end());
        int res = INT_MAX;
        string c1,c2;
        int tt;
        time t1,t2;
        for(int i=1; i<a.size(); i++){
            c1 = a[i-1].substr(0,2);
            c2 = a[i-1].substr(3,2);
            t1.hour= stoi(c1);
            t1.min = stoi(c2);
            c1 = a[i].substr(0,2);
            c2 = a[i].substr(3,2);
            t2.hour= stoi(c1);
            t2.min = stoi(c2);
            if(t1.hour==t2.hour) tt = t2.min-t1.min;
            else tt = (60-t1.min) + t2.min + 60 * (t2.hour-t1.hour-1);
            res = min(res,tt);
        }
        
        c1 = a[a.size()-1].substr(0,2);
        c2 = a[a.size()-1].substr(3,2);
        t1.hour= stoi(c1);
        t1.min = stoi(c2);
        c1 = a[0].substr(0,2);
        c2 = a[0].substr(3,2);
        t2.hour= stoi(c1);
        t2.min = stoi(c2);
        tt = 60*(24-t1.hour-1) + (60-t1.min) + t2.hour * 60 + t2.min;
        return min(res,tt);
    }
};

881. 救生艇

第 i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
返回载到每一个人所需的最小船数。(保证每个人都能被船载)。

示例 3:
输入:people = [3,5,3,4], limit = 5
输出:4
解释:4 艘船分别载 (3), (3), (4), (5)

提示:

  1. 1 <= people.length <= 50000
  2. 1 <= people[i] <= limit <= 30000

解法:

贪心+双指针

先排序,然后两个指针,从数组两段开始走,如果最轻和最终的可以一起,就一起坐船,否则胖子自己坐,因为那已经是最轻的了。

代码:

class Solution {
public:
    int numRescueBoats(vector<int>& a, int limit) {
        sort(a.begin(),a.end());
        int res = 0;
        int i(0),j(a.size()-1);
        while(i<=j){
            if(a[i]+a[j]<=limit){
                ++res;
                ++i;
                --j;
            }
            else{
                ++res;
                --j;
            }
        }
        return res;
    }
};

227. 基本计算器 II

实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。

示例:
输入: “3+2*2”
输出: 7

说明:

  1. 你可以假设所给定的表达式都是有效的。
  2. 请不要使用内置的库函数 eval。

表达式计算最经典的做法,就是栈,符号是* /就直接计算,符号是+ -就先存起来,最后会只剩下一个只有+ -的算式,算一遍就行了。

代码:

class Solution {
public:
    int calculate(string s) {
        vector<int> a;//存放数字
        vector<char> b;//存放运算符
        string t = "";
        for(char c : s)
            if(isdigit(c) || c=='+' || c=='-' || c=='*' || c== '/')
                t += c;
        int i=0;
        string curr = "";
        while(i<t.length() && isdigit(t[i])){
            curr += t[i];
            ++i;
        }
        int currn = stoi(curr);
        a.push_back(currn);
        while(i<t.length()){
            b.push_back(t[i]);
            ++i;
            curr.clear();
            while(i<t.length() && isdigit(t[i])){
                curr += t[i];
                ++i;
            }
            currn = stoi(curr);
            if(b.back()=='*' || b.back()=='/'){
                if(b.back()=='*')
                    currn *= a.back();
                else
                    currn = a.back()/currn;
                b.pop_back();
                a.pop_back();
                a.push_back(currn);
            }
            else{
                a.push_back(currn);
            }
        }
        for(int i=0; i<a.size(); i++)
            cout<<a[i]<<' ';
        cout<<endl;
        for(int i=0; i<b.size(); i++)
            cout<<b[i]<<' ';
        cout<<endl;
        int res = a[0];
        for(int i=1; i<a.size(); i++){
            if(b[i-1]=='+')
                res+=a[i];
            else
                res-=a[i];
        }
        return res;
    }
};

1139. 最大的以 1 为边界的正方形

给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0。

示例 1:
输入:grid = [[1,1,1],[1,0,1],[1,1,1]]
输出:9

提示:

  1. 1 <= grid.length <= 100
  2. 1 <= grid[0].length <= 100
  3. grid[i][j] 为 0 或 1

解法:用两个数组分别存放横向和竖向的连续1的长度,然后在每个有1的位置,向左上方判断。(有点蠢)

代码:

class Solution {
public:
    int largest1BorderedSquare(vector<vector<int>>& a) {
        if(a.empty()) return 0;
        int m = a.size();
        int n = a[0].size();
        vector<vector<int>> dp1(m+1,vector<int>(n+1,0));
        vector<vector<int>> dp2(m+1,vector<int>(n+1,0));
        for(int i=0; i<m; i++)
            dp1[i][0] = a[i][0];
        for(int i=0; i<m; i++)
            for(int j=1; j<n; j++)
                if(a[i][j])
                    dp1[i][j] = dp1[i][j-1] + 1;
        
        for(int i=0; i<n; i++)
            dp2[0][i] = a[0][i];
        for(int j=0; j<n; j++)
            for(int i=1; i<m; i++)
                if(a[i][j])
                    dp2[i][j] = dp2[i-1][j] + 1;
        int res = 0;

        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++)
                cout<<dp1[i][j]<<' ';
            cout<<endl;
        }
        cout<<"---------"<<endl;
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++)
                cout<<dp2[i][j]<<' ';
            cout<<endl;
        }

        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(a[i][j]){
                    int s = 1;
                    int x = i;
                    int y = j;
                    int t = dp1[i][j]-1;
                    res = max(res,1);
                    while(t>0){
                        if(y-s>=0 && x-s>=0 && dp1[x-s][y]>s && dp2[x][y]>s && dp2[x][y-s]>s){
                            res = max(res,s+1);
                        }
                        ++s;
                        --t;
                    }
                }
            }
        }
        return res*res;
    }
};