剑指offer专项突击版第38天

剑指 Offer II 111. 计算除法

BFS

  1. 仔细思考发现,他们除法运算的关系就是图的数据结构, a / b a / b a/b 就相当于与从 a a a 走到 b b b 的边权乘积,边权就是他们的倍数关系 v a l u e s values values
  2. 为了更高效的构造邻接表,使用哈希表,将变量对映射成整数,然后对于每个 q u e r y query query 只需 B F S BFS BFS 从起点走到终点即可。
class Solution {
public:
    typedef pair<int,double> PID;
    unordered_map<string,int> um;

    double bfs(string &a, string &b, vector<vector<PID>> &edges) {
        if(a == b) return 1;
        int st = um[a], ed = um[b];
        queue<int> que; que.emplace(st);
        vector<double> dis(um.size(),-1);
        dis[st] = 1;
        while(que.size()) {
            auto u = que.front(); que.pop();
            for(auto &[v,val]: edges[u]) {
                if(dis[v] == -1) {
                    dis[v] = dis[u] * val;
                    if(v == ed) return dis[v];
                    que.emplace(v);
                }
            }
        }
        return -1;
    }

    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        int idx = 0;
        for(int i = 0; i < equations.size(); i++) { //将变量哈希成整数
            if(!um.count(equations[i][0])) um[equations[i][0]] = idx++;
            if(!um.count(equations[i][1])) um[equations[i][1]] = idx++; 
        }
        vector<vector<PID>> edges(um.size());
        for(int i = 0; i < equations.size(); i++) { //构造邻接表
            auto &x = equations[i][0], &y = equations[i][1];
            int u = um[x], v = um[y];
            edges[u].emplace_back(v, values[i]);
            edges[v].emplace_back(u, 1/values[i]); //反方向就是倒数
        }
        vector<double> res;
        for(auto query: queries) {
            auto &a = query[0], &b = query[1];
            if(!um.count(a) || !um.count(b)) {
                res.emplace_back(-1);
            } else {
                res.emplace_back(bfs(a,b,edges)); //bfs获得a到b路径上的乘积
            }
        }
        return res;
    }
};

剑指 Offer II 112. 最长递增路径

记忆化搜索

比较简单就不赘述了。

class Solution {
public:
    int ne[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};
    int n, m;
    int dfs(int x,int y, vector<vector<int>> &matrix, vector<vector<int>> &f) {
        if(f[x][y]) return f[x][y];
        f[x][y]++;
        for(int i = 0; i < 4; i++) {
            int tx = x + ne[i][0];
            int ty = y + ne[i][1];
            if(tx < 0 || tx >= n || ty < 0 || ty >= m) continue;
            if(matrix[x][y] < matrix[tx][ty]) {
                f[x][y] = max(f[x][y], dfs(tx,ty,matrix,f) + 1);
            }
        }
        return f[x][y];
    }
    int longestIncreasingPath(vector<vector<int>>& matrix) {
        n = matrix.size(), m = matrix[0].size();
        vector<vector<int>> f(n, vector<int>(m,0));
        int res = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                res = max(res, dfs(i,j,matrix,f));
        return res;
    }

};

拓扑排序(BFS)
将所有元素小的指向大的这就生成了有向图,然后拓扑排序一下,然后这里拓扑排序的层数就是答案,也就是最长的升序序列。

class Solution {
public:
    static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int rows, columns;

    int longestIncreasingPath(vector< vector<int> > &matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return 0;
        }
        rows = matrix.size();
        columns = matrix[0].size();
        auto outdegrees = vector< vector<int> > (rows, vector <int> (columns));
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                for (int k = 0; k < 4; ++k) {
                    int newRow = i + dirs[k][0], newColumn = j + dirs[k][1];
                    if (newRow >= 0 && newRow < rows && newColumn >= 0 && newColumn < columns && matrix[newRow][newColumn] > matrix[i][j]) {
                        ++outdegrees[i][j];
                    }
                }
            }
        }
        queue < pair<int, int> > q;
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                if (outdegrees[i][j] == 0) {
                    q.push({i, j});
                }
            }
        }
        int ans = 0;
        while (!q.empty()) {
            ++ans;
            int size = q.size();
            for (int i = 0; i < size; ++i) {
                auto cell = q.front(); q.pop();
                int row = cell.first, column = cell.second;
                for (int k = 0; k < 4; ++k) {
                    int newRow = row + dirs[k][0], newColumn = column + dirs[k][1];
                    if (newRow >= 0 && newRow < rows && newColumn >= 0 && newColumn < columns && matrix[newRow][newColumn] < matrix[row][column]) {
                        --outdegrees[newRow][newColumn];
                        if (outdegrees[newRow][newColumn] == 0) {
                            q.push({newRow, newColumn});
                        }
                    }
                }
            }
        }
        return ans;
    }
};

剑指 Offer II 113. 课程顺序

简单的拓扑排序

  1. 首先构造课程的拓扑图,将所有需要先完成的课程指向想要学习的课程。
  2. 将所有入度为0的都加入队列中,然后 b f s bfs bfs 依次弹出所有的点,这个顺序就是答案了。
class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        int n = prerequisites.size();
        vector<int> res;
        if(n == 0) {
            for(int i = 0; i < numCourses; i++) res.emplace_back(i);
            return res;
        }
        vector<vector<int>> adj(numCourses);
        vector<int> in(numCourses);
        for(int i = 0; i < n; i++) {
            int &u = prerequisites[i][1], &v = prerequisites[i][0]; 
            adj[u].emplace_back(v);
            in[v]++;
        }
        
        queue<int> que;
        for(int i = 0; i < numCourses; i++)
            if(in[i] == 0) que.emplace(i);

        while(que.size()) {
            int u = que.front(); que.pop();
            res.emplace_back(u);
            for(int v: adj[u]) {
                in[v]--;
                if(in[v] == 0) que.emplace(v);
            }
        }
        return res.size() < numCourses? vector<int>{}: res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值