Evaluate Division(LeetCode 339)

本文介绍了一种利用图论解决变量间复杂关系的问题。通过将变量映射为图中的节点,将变量间的数学关系转化为边,并利用深度优先搜索算法(DFS)非递归版本求解指定变量间的比值。

题目

  Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.

Example:
Given a / b = 2.0, b / c = 3.0.
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? .
return [6.0, 0.5, -1.0, 1.0, -1.0 ].

The input is: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries , where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>.

According to the example above:

equations = [ [“a”, “b”], [“b”, “c”] ],
values = [2.0, 3.0],
queries = [ [“a”, “c”], [“b”, “a”], [“a”, “e”], [“a”, “a”], [“x”, “x”] ].
The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.

题目大意

题目大概是说给若干个形如a/b=k的等式,其中a,b是字符串,k是double类型的常数,然后再给你几个同样形如a/b的式子,让你根据之前的等式求出这些式子的值,例如a/b=2.0,b/c=3.0,现在求a/c,值为6.0。
还有a/x,因为x这个字符串之前没给出,所以是不合法的值,定义为-1.0。这里还要注意一点,所有等式的值均为正值。

分析

这道题因为牵扯到很多变量之间的关系,那么考虑下我们学过什么模型或者算法里面牵扯到很多变量之间的关系?嗯,如果这里把每一个变量都看成是一个结点,k值看做是边的权值,那么是不是很像数据结构中的图论,当然这里是有向图,而且是带环的,毕竟自己除自己也是有意义的,值为1.0。上面的example对应的图画出来差不多就像下面这个样子:
这里写图片描述
每条边的权值都是它的弧尾/弧头的值,例如a/b=2,b/a=1.0/2.0。
    那么接下来就简单了,整个问题也就转换为了求从顶点i到
顶点j的路径的权值之积就好了,例如求c/a,那么只要c->b->a这条路径上的权值相乘就好了,也就是0.3333*2.0。那么现在只要找到c->a的路径就可以得到答案了。也就是对这个图做个dfs的事。

    不过这里要注意一点,如果dfs用递归实现,会提示running error,我放到vs下调试发现是stack over flow也就是递归导致内存溢出了,所以只好考虑用dfs的非递归的版本去实现。

    好了,下面先给出代码,然后再分析代码吧

class Solution {
public:
    vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
        unordered_map<string, int> symbol;
        int index = 0;
        vector<double> res;
        for (int i = 0; i<equations.size(); i++) {
            if (symbol.find(equations[i].first) == symbol.end()) {
                symbol[equations[i].first] = index++;
            }
            if (symbol.find(equations[i].second) == symbol.end()) {
                symbol[equations[i].second] = index++;
            }
        }
        vector<vector<double>> graph;/*define the graph*/
                                     /*init the graph*/
        for (int i = 0; i<index; i++) {
            graph.emplace_back(vector<double>());
            for (int j = 0; j<index; j++) {
                if (i == j)
                    graph[i].emplace_back(1.0);
                else
                    graph[i].emplace_back(-1.0);
            }
        }
        /*create all edges*/
        for (int i = 0; i<equations.size(); i++) {
            int a = symbol[equations[i].first];
            int b = symbol[equations[i].second];
            graph[a][b] = values[i];
            graph[b][a] = 1.0 / values[i];
        }
        /*get the result*/
        for (int i = 0; i<queries.size(); i++) {
            if (symbol.find(queries[i].first) == symbol.end() || symbol.find(queries[i].second) == symbol.end())
                res.emplace_back(-1.0);
            else
                res.emplace_back(getRes(symbol[queries[i].first], symbol[queries[i].second], graph));
        }
        return res;
    }
private:
    double getRes(int start, int end, vector<vector<double>> graph) {/*get the weight from start to end*/
        return dfs(start,end,graph);
    }
    double dfs(int start ,int end, vector<vector<double>> graph) {
        if (start == end)
            return 1.0;
        double temp = 1.0;
        double priortemp=1.0;
        vector<bool> visited;
        for (int i = 0; i < graph.size(); i++)
            visited.emplace_back(false);
        stack<int> m_stack;
        m_stack.push(start);
        visited[start] = true;
        while (!m_stack.empty()) {
            int tmp = m_stack.top();
            int i = 0;
            for (i = 0; i < graph.size(); i++) {
                if (visited[i]|| graph[tmp][i] == -1.0)
                    continue;
                m_stack.push(i);
                visited[i] = true;
                priortemp=temp;
                temp *= graph[tmp][i];
                if (i == end) {
                    return temp;
                }
                break;
            }
            if (i == graph.size()){/*back to the prior state*/
                m_stack.pop();
                temp=priortemp;
            }
        }
        return -1.0;
    }
};

calcEquation()先从这个函数开始吧。首先我懒的用邻接表去存储图,所以就想用邻接矩阵去存,但是这题目给了一大堆字符串,肯定不方便用下标去表示,于是我想到先用unordered_map先把这些字符串和下标绑定,接着直接用这些下标用vector建立一个邻接矩阵。之后就是对题目给定的表达式逐个求值了。再来讲讲dfs函数,这是一个简单的dfs非递归实现,但是要注意,我使用了一个priortemp变量来记录回溯时要用的值。嗯,差不多就这样吧

内容概要:本文详细介绍了“秒杀商城”微服务架构的设计与实战全过程,涵盖系统从需求分析、服务拆分、技术选型到核心功能开发、分布式事务处理、容器化部署及监控链路追踪的完整流程。重点解决了高并发场景下的超卖问题,采用Redis预减库存、消息队列削峰、数据库乐观锁等手段保障数据一致性,并通过Nacos实现服务注册发现与配置管理,利用Seata处理跨服务分布式事务,结合RabbitMQ实现异步下单,提升系统吞吐能力。同时,项目支持Docker Compose快速部署和Kubernetes生产级编排,集成Sleuth+Zipkin链路追踪与Prometheus+Grafana监控体系,构建可观测性强的微服务系统。; 适合人群:具备Java基础和Spring Boot开发经验,熟悉微服务基本概念的中高级研发人员,尤其是希望深入理解高并发系统设计、分布式事务、服务治理等核心技术的开发者;适合工作2-5年、有志于转型微服务或提升架构能力的工程师; 使用场景及目标:①学习如何基于Spring Cloud Alibaba构建完整的微服务项目;②掌握秒杀场景下高并发、超卖控制、异步化、削峰填谷等关键技术方案;③实践分布式事务(Seata)、服务熔断降级、链路追踪、统一配置中心等企业级中间件的应用;④完成从本地开发到容器化部署的全流程落地; 阅读建议:建议按照文档提供的七个阶段循序渐进地动手实践,重点关注秒杀流程设计、服务间通信机制、分布式事务实现和系统性能优化部分,结合代码调试与监控工具深入理解各组件协作原理,真正掌握高并发微服务系统的构建能力。
### 如何在 IntelliJ IDEA 中调试 LeetCode 插件 #### 安装并配置 LeetCode Editor 插件 为了能够在 Tools 下拉菜单中看到 LeetCode Plugin 的选项,必须先安装 LeetCode Editor 插件[^1]。 #### 设置项目结构 创建一个新的 Java 类文件用于编写解题代码。通常建议按照如下目录结构来组织项目: LeetcodeProject ├── src └── leetcode └── editor └── cn └── SixCE719.java 其中 `SixCE719` 是具体的题目编号或名称的一部分[^4]。 #### 编写测试用例 对于每一个要解决的问题,在相应的类里面定义好入口方法以及必要的辅助函数。可以参照官方文档中的模板来进行编码工作。同时还需要准备一些输入数据作为参数传递给这些方法以便于后续执行验证操作。 #### 启动调试模式 当一切就绪之后,可以通过点击左侧边栏上的绿色虫子图标进入 Debug Mode 。此时会弹出一个对话框询问是否允许启动远程连接;选择 Yes 即可继续下一步骤[^3]。 #### 进行单步跟踪 一旦程序暂停下来等待进一步指令,则可以在编辑器窗口下方的状态栏处发现几个常用按钮:Step Over (F8), Step Into (F7)Evaluate Expression...等等。利用它们可以帮助开发者逐步分析算法逻辑流程,并观察变量的变化情况。 需要注意的是,在这种环境下完成修改后的解决方案并不能直接通过插件上传至在线平台。如果想要正式提交答案的话,应该回到原始页面重新加载一次当前练习题目的框架代码片段再做相应调整。 ```java public class Solution { public int addTwoNumbers(int a, int b){ return a+b; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值