leetcode重点题目分类别记录(四)图论深入

news/2024/4/26 23:15:56/文章来源:https://blog.csdn.net/baiduwaimai/article/details/130271552

文章目录

  • 入度出度
    • 最大网络秩
    • 可以到达所有点的最少点数目
  • 并查集
    • 省份数量
    • 等式方程的可满足性
    • 按字典序排列最小的等效字符串
    • 以图判树
  • 二分图
    • 判断二分图
  • 深度优先搜索
    • 封闭岛屿数量
    • 太平洋大西洋水流问题
  • 广度优先搜索
    • 树上逃逸最短路径
    • 多源最短路径
  • 拓扑排序
    • DFS解决拓扑排序
    • BFS解决拓扑排序

入度出度

最大网络秩

在这里插入图片描述

直接相连的道路即为节点的度,如果两个节点是相连的,那么度将会重复计算,因此,统计每个节点的度,和节点相连的情况,每个每一对城市,计算最大网络秩。

    int maximalNetworkRank(int n, vector<vector<int>>& roads) {vector<vector<bool>> connect(n, vector<bool>(n, false));vector<int> degree(n, 0);for (vector<int> &r : roads) {connect[r[0]][r[1]] = true;connect[r[1]][r[0]] = true;++degree[r[0]];++degree[r[1]];}int ans = 0, cur = 0;for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {cur = degree[i] + degree[j] + (connect[i][j] ? -1 : 0);ans = max(ans, cur);}}return ans;}

可以到达所有点的最少点数目

在这里插入图片描述
理解题意发现,每个入度为0的节点必须作为出发点。
因此统计入度为0的节点个数即可。

    vector<int> findSmallestSetOfVertices(int n, vector<vector<int>>& edges) {// 统计入度为0的节点数vector<int> ins(n);for (auto e : edges) ++ins[e[1]];vector<int> ans;for (int i = 0; i < n; ++i) {if (ins[i] == 0) ans.push_back(i);}return ans;}

并查集

并查集用于求解连通分量,两个关键词,连通分量,分量就是一个集合,连通,代表集合之间可以合并。

省份数量

在这里插入图片描述
省份地图是连通量问题标准题目:

class Solution {
public:class UF {private:// 一个数组,用来指定每个成员的根节点是谁int *parent;// 当前的连通量数/集合数int cnt;public:UF(int val) {// 传递成员数 初始时每个成员的根节点指向为自身parent = new int[val];for (int i = 0; i < val; ++i) parent[i] = i;cnt = val;}int find(int val) {if (val != parent[val]) {// 路径压缩:递归的将当前成员的父节点指向为根成员parent[val] = find(parent[val]);}return parent[val];}// 判断是否连通,只需判断是否同父节点bool connected (int p, int q) {return find(p) == find(q);}// 连通两个分量,判断是否是非连接的,将一个成员的根挂在另一个成员父节点的根上,注意将连通分量数减一void unite(int p, int q) {if (!connected(p, q)) {parent[find(p)] = find(q);--cnt;}}int count() {return cnt;}};int findCircleNum(vector<vector<int>>& isConnected) {int n = isConnected.size();UF uf(n);for (int i = 1; i < n; ++i) {for (int j = 0; j < i; ++j) {if (isConnected[i][j] == 1) {uf.unite(i, j);}}}return uf.count();}
};

等式方程的可满足性

在这里插入图片描述
多个变量之间等或者不等的关系,就类似连通分量问题中,多个成员属于同一个连通量或者不属于。因此也可以使用并查集来做,这里仅仅关心等式是否有违背,那么我们根据所有的等式建立连通关系,建立后,查看每个不等式是否有违背,即不等式中是否有属于同一分量的。

class Solution {
public:class UF {private:int* parent;public:UF() {parent = new int[26];for (int i = 0; i < 26; ++i) parent[i] = i;}int find (int val) {if (parent[val] != val) {parent[val] = find(parent[parent[val]]);}return parent[val];}bool connected(int p, int q) {return find(p) == find(q);}void unite(int p, int q) {if (!connected(p, q)) {parent[find(p)] = find(q);}}};bool equationsPossible(vector<string>& equations) {UF uf;for (const string& e : equations) {int a = e[0] - 'a', b = e[3] - 'a';if (e[1] == '=') uf.unite(a, b);}for (const string& e : equations) {int a = e[0] - 'a', b = e[3] - 'a';if (e[1] == '!') {if (uf.connected(a, b)) return false;}}return true;}
};

按字典序排列最小的等效字符串

在这里插入图片描述
前边的例子中,我们先连通两个分量时的做法为:
默认是把p的根接在了q的根上边

 void unite(int p, int q) {if (!connected(p, q)) {parent[find(p)] = find(q);}}

这题要求按照字典序排列最小,那么我们当然希望的时每个字符是最小的,因此可以在连通时,选择小的那个作为根:

 void unite(int p, int q) {if (!connected(p, q)) {int rootp = find(p), rootq = find(q);if (rootp < rootq) {parent[rootq] = rootp;} else {parent[rootp] = rootq;}}}

这样就保证了,每个等价关系中,根节点是最小的那个字符。
那么我们只需要根据并查集建立等号连通关系,将字符替换为并查集中的根即可。

    string smallestEquivalentString(string s1, string s2, string baseStr) {UF uf;for (int i = 0; i < s1.size(); ++i) uf.unite(s1[i] - 'a', s2[i] - 'a');for (int i = 0; i < baseStr.size(); ++i) {int cur = baseStr[i] - 'a';int p = uf.find(cur);baseStr[i] = 'a' + p;}return baseStr;}

以图判树

在这里插入图片描述

一个合法的树,所有节点都相连,且无环,节点数等于边数 + 1;
根据这个思路,先判断边与节点数关系。
如果节点数等于边数+1,那么只需要判断图是否只有一个部分即可。
使用visited记录遍历情况.

    bool validTree(int n, vector<vector<int>>& edges) {if (n - 1 != edges.size()) return false; // 判断节点数与边数是否符合// 构图vector<vector<int>> graph(n);for (auto& e : edges) {graph[e[0]].push_back(e[1]);graph[e[1]].push_back(e[0]);}// dfs遍历,注意跳过遍历过的节点vector<bool> visited(n, false);function<void(int)> dfs = [&](int cur) {visited[cur] = true;for (auto e : graph[cur]) {if (visited[e]) continue;dfs(e);}};// 从任意节点遍历dfs(0);// 检测是否能够遍历每一个节点for (int i = 0; i < n; ++i) if (!visited[i]) return false;return true;}

考虑另外一种思路:并查集。
如果满足边数等于节点数减一,且整个图只有一个连通量,那么其实就类似上边达到了判断图只有一个完整的部分。

    class UF {private:int* parent;int cnt;public:    UF(int val) {parent = new int[val];for (int i = 0; i < val; ++i) parent[i] = i;cnt = val;}int find(int val) {if (parent[val] != val) {parent[val] = find(parent[val]);}return parent[val];}bool connected(int p, int q) {return find(p) == find(q);}void unite(int p, int q) {if (!connected(p, q)) {parent[find(p)] = find(q);--cnt;}}int count(){return cnt;}};bool validTree(int n, vector<vector<int>>& edges) {if (n - 1 != edges.size()) return false;UF uf(n);for (auto e : edges) {uf.unite(e[0], e[1]);}   return uf.count() == 1;}

二分图

判断二分图

在这里插入图片描述
在这里插入图片描述
二分染色法:
一个visited数组记录遍历情况,一个color数组记录染色情况,遍历每个节点,如果相邻节点未被染色,则将它染成与当前节点相反颜色,否则如果已经染色,检查相邻节点是否同色,如果同色说明不可二分。

    bool isBipartite(vector<vector<int>>& graph) {int n = graph.size();vector<int> visited(n, false), color(n, false);bool ans = true;function<void(int)> dfs = [&](int cur) {if (!ans || visited[cur]) return;visited[cur] = true;for (int c : graph[cur]) {if (!visited[c]) {// 没遍历过的节点是未染色的,染成与cur相反的颜色color[c] = !color[cur];dfs(c);} else {// 遍历过的节点是染色的,检查是否符合// 如果不符合,将全局的ans设置为false,返回if (color[cur] == color[c]) {ans = false;return;}}}};// 可能存在多个子图,需要遍历每个节点for (int i = 0; i < n; ++i) {dfs(i);if (!ans) return false;}return ans;}

深度优先搜索

封闭岛屿数量

在这里插入图片描述

    int closedIsland(vector<vector<int>>& grid) {// 把与相连边的0(陆地)全部赋值为1// 统计0的区域数int m = grid.size(), n = grid[0].size();int dx[4] = {0, 0, -1, 1}, dy[4] = {1, -1, 0, 0};function<void(int, int)> dfs = [&](int x, int y) {grid[x][y] = 1;for (int i = 0; i < 4; ++i) {int cx = x + dx[i], cy = y + dy[i];if (cx >= 0 && cx < m && cy >= 0 && cy < n && grid[cx][cy] == 0) dfs(cx, cy);}};for (int i = 0; i < m; ++i) {if (grid[i][0] == 0) dfs(i, 0);if (grid[i][n - 1] == 0) dfs(i, n - 1);}for (int j = 0; j < n; ++j) {if (grid[0][j] == 0) dfs(0, j);if (grid[m - 1][j] == 0) dfs(m - 1, j);}int ans = 0;for (int i = 1; i < m - 1; ++i) {for (int j = 1; j < n - 1; ++j) {if (grid[i][j] == 0) {++ans;dfs(i, j);}}}return ans;}

太平洋大西洋水流问题

在这里插入图片描述
寻找可以到达太平洋,也可到达大西洋的坐标。
我们可以反向考虑水流,从边界出发,向周围更高的地方搜索能够到达海岸的位置。
pacificatlantic数组分别表示i,j位置是否可以达到太平洋和大西洋。

在边界上执行dfs后,搜索pacificatlantic都为true的位置。

    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {int m = heights.size(), n = heights[0].size();vector<vector<int>> ans;vector<vector<bool>> pacific(m, vector<bool>(n, false));vector<vector<bool>> atlantic(m, vector<bool>(n, false));int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};function<void(int, int, vector<vector<bool>>&)> dfs = [&](int x, int y, vector<vector<bool>> &ocean) {if (ocean[x][y]) return;ocean[x][y] = true;for (int k = 0; k < 4; ++k) {int cx = x + dx[k], cy = y + dy[k];if (cx >= 0 && cx < m && cy >= 0 && cy < n && heights[cx][cy] >= heights[x][y]) dfs(cx, cy, ocean);}};for (int i = 0; i < m; ++i) dfs(i, 0, pacific);for (int i = 0; i < m; ++i) dfs(i, n - 1, atlantic);for (int j = 0; j < n; ++j) dfs(0, j, pacific);for (int j = 0; j < n; ++j) dfs(m - 1, j, atlantic);for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (pacific[i][j] && atlantic[i][j]) ans.push_back({i, j});}}return ans;}

广度优先搜索

树上逃逸最短路径

在这里插入图片描述
在这里插入图片描述
这题树是以图的形式给出的,而且没有指定方向所以是无向图
为了保证遍历时是一直向前了,我们遍历时带上了父节点,避免了走回头路。
使用bfs找叶子节点,叶子节点是除了根节点外,另外一种只有一个相邻节点的节点

最短路径在我们遍历过的路径中,根据叶子节点和父节点,逆向找到起始点。

随后构建出题目要求的路径。

void question2() {// 树上找最短路径:bfsint n;cin >> n;int edge;cin >> edge;// 构图vector<vector<int>> g(n);for (int i = 0; i < edge; ++i) {int x, y;cin >> x >> y;g[x].push_back(y);g[y].push_back(x);}// 标记阻塞点int bolck;cin >> bolck;vector<bool> isblock(n, false);for (int i = 0; i < bolck; ++i) {int index;cin >> index;isblock[index] = true;}// 找到叶子节点说明有路,为了标记路径,需要记录每个节点的父节点,pair: 当前节点,当前节点的父节点vector<pair<int, int>> path;queue<pair<int, int>> que;que.push({0, -1}); // 初始节点的父节点设置为-1isblock[0] = true;int endIndex = -1;// bfs搜索while (!que.empty()) {path.push_back(que.front());int cur = que.front().first, fa = que.front().second;que.pop();// 除根节点外,又遍历到只有一个相邻节点的节点, 说明是叶子节点,记录位置,退出if (cur != 0 && g[cur].size() == 1) {endIndex = cur;break;}for (int e : g[cur]) {if (isblock[e]) continue;que.push({e, cur});isblock[e] = true;}}// path中记录了所有宽度优先遍历的结果,需从中找到路径,根据末尾节点位置和每个节点的父节点往上找string ans;vector<int> res;if (endIndex != -1) {int t = endIndex;for (int i = path.size() - 1; i >= 0; --i) {if (path[i].first == t) {res.push_back(t);t = path[i].second;if (t == -1) break;}}}// 根据路径打印结果for (int i = res.size() - 1; i >= 0; --i) {ans += to_string(res[i]);if (i != 0) ans += "->";}cout << ans << endl;
}

多源最短路径

在这里插入图片描述
要求A到C的距离最短的路径之和。
由于不确定A离那个C最近,我们可以从C反向BFS搜索A。每遍历一轮,将ans加上当前的轮次(即当前走的step),然后把A所在的地方再加入到队列。

void ques() {int n;cin >> n;vector<vector<char>> maze(n, vector<char>(n));for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {cin >> maze[i][j];}}int ans = 0;int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};queue<pair<int, int>> que;for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {if(maze[i][j] == 'C') {que.emplace(i, j);maze[i][j] = 'B';}}}int epoch = 1;while (!que.empty()){int sz = que.size();for (int i = 0; i < sz; ++i) {int x = que.front().first, y = que.front().second;que.pop();for (int j = 0; j < 4; ++j) {int cx = x + dx[j], cy = y + dy[j];if (cx >= 0 && cx < n && cy >= 0 && cy < n && maze[cx][cy] == 'A') {ans += epoch;maze[cx][cy] = 'B';que.emplace(cx, cy);}} }++epoch;}cout << ans << endl;
}

拓扑排序

在这里插入图片描述

DFS解决拓扑排序

dfs求解时,我们根据依赖关系构图,然后获取后序遍历结果,反向后序遍历结果,即为所求。

因为我们在构图时,是先修课程指向了后修课程。
在这里插入图片描述

后序遍历结果保证了,先有孩子节点后有父节点,而我们的拓扑排序要求与此相反,我们需要先有父节点(先修),再由孩子节点(后序),因此需要反向post。
在这里插入图片描述

    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> g(numCourses);for (auto p : prerequisites) {g[p[1]].push_back(p[0]);}bool hasCircle = false;vector<bool> visited(numCourses, false), onPath(numCourses, false);vector<int> post;function<void(int)> dfs = [&](int cur) {if (hasCircle) return;if (onPath[cur]) {hasCircle =  true;return;}if (visited[cur]) return;visited[cur] = true;onPath[cur] = true;for (auto e : g[cur]) {dfs(e);}post.push_back(cur);onPath[cur] = false;};for (int i = 0; i < numCourses; ++i) {dfs(i);if (hasCircle) return vector<int>{};}reverse(post.begin(), post.end());return post;}

BFS解决拓扑排序

bfs解决拓扑排序依赖于对入度的计算,首先入度为0的节点表示这个节点不依赖任何其他节点,所以可以学习,把他们加入队列,并将与它们相邻的阶段入度减一(表示这个依赖已经解决),如果新产生了入度为0的节点,说明又有新的不依赖节点,加入队列。如果这个过程接收后,所有节点都入队一次,说明无环且构建好了拓扑排序。

    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> g(numCourses);vector<int> ins(numCourses);for (auto p : prerequisites) {g[p[1]].push_back(p[0]);++ins[p[0]];}queue<int> que;for(int i = 0; i < numCourses; ++i) if (ins[i] == 0) que.push(i);vector<int> ans;while (!que.empty()) {int cur = que.front();que.pop();ans.push_back(cur);for (auto e : g[cur]) {--ins[e];if (ins[e] == 0) que.push(e);}}return ans.size() == numCourses ? ans : vector<int>{};}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_103014.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++关联容器】set的成员函数

目录 set 1. 构造、析构和赋值运算符重载 1.1 构造函数 1.2 析构函数 1.3 赋值运算符重载 2. 迭代器 3. 容量 4. 修改器 5. 观察者 6. 操作 7. 分配器 set set是按照特定顺序存储唯一元素的容器。 在一个set中&#xff0c;一个元素的值也是它的标识&#xff08;值…

mybatis中大数据量foreach插入效率对比

1.controller代码 RequestMapping("/testInsert")public String testInsert(Integer sum){testService.testInsert(sum);return "发送成功";}2.service代码 Overridepublic void testInsert(Integer sum) {long start System.currentTimeMillis();List<…

修炼汇编语言第一章:汇编基础知识概述

目录 前言 一、汇编语言的组成 二&#xff1a;存储器 三&#xff1a;指令和数据 四&#xff1a;存储单元 五&#xff1a;CPU对存储器的读写 地址总线 控制总线 数据总线 前言 汇编语言是数据结构&#xff0c;操作系统&#xff0c;微机原理等重要课程的基础&#xff0…

QT中TCP的学习

文章目录 qt中TCP的实现 qt中TCP的实现 学习视频 QT中可以通过TCP协议让服务器和客户端之间行通信。服务器和客户端的具体流程 下方的信号都是系统提供的&#xff0c;我们只需要写相应的槽函数 A、服务器&#xff1a; 创建QTcpServer对象启动服务器&#xff08;监听&…

【C语言】指针进阶[上] (字符、数组指针、指针数组、数组传参和指针传参)

简单不先于复杂&#xff0c;而是在复杂之后。 目录 1. 字符指针 面试题 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名 VS 数组名 3.3 数组指针的使用 4. 数组参数、指针参数 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二…

后端大厂面试总结大全六

目录&#xff1a; 1、Transactional注解控制事务有哪些不生效的场景2、MySQL的优化 1、Transactional注解控制事务有哪些不生效的场景 数据库引擎不支持事务数据源没有配置事务管理器没有被spring管理方法不是public的同一个类中方法调用&#xff0c;导致Transactional失效 举…

操作系统原理 —— 进程状态切换具体做了哪些事情?(八)

什么是进程控制&#xff1f; 进程控制的主要功能是&#xff1a;对系统中的所有进程实施有效的管理&#xff0c;它具有创建新进程、撤销已有进程、实现进程状态转换等功能。 简单来说&#xff0c;就是进程控制就是要现实进程状态的转换。 那如何实现进程的控制呢&#xff1f;…

手推FlinkML2.2(一)

Java 快速入门 # 本文档提供了一个关于如何使用Flink ML的快速入门。阅读本文档的用户将被指导提交一个简单的Flink作业&#xff0c;用于训练机器学习模型并提供预测服务。 求助&#xff0c;我卡住了&#xff01;# 如果你遇到困难&#xff0c;请查看社区支持资源。特别是&…

Java线程间通信方式

前文了解了线程的创建方式和状态切换&#xff0c;在实际开发时&#xff0c;一个进程中往往有很多个线程&#xff0c;大多数线程之间往往不是绝对独立的&#xff0c;比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上&#xff0c;又或者比较典型的消费者-生产…

【论文写作】如何写引言?应该思考什么问题?总体架构!!!

结构 大多数的科技论文都聚焦于简单地说明&#xff0c;做了什么&#xff0c;发现了什么&#xff1f;虽然这个可以帮助你写出一篇研究型论文当中的核心的东西&#xff08;方法论和结果&#xff09;&#xff0c;但是不能完全把引言的部分完成。在这篇文章当中&#xff0c;将展示…

4 redis高可用

所谓的高可用&#xff0c;也叫HA&#xff08;High Availability&#xff09;&#xff0c;是分布式系统架构设计中必须考虑的因素之一&#xff0c;它通常是指&#xff0c;通过设计减少系统不能提供服务的时间。如果在实际生产中&#xff0c;如果redis只部署一个节点&#xff0c;…

从FMCW毫米波雷达系统的性能参数理解4D成像毫米波雷达的设计思路

本文编辑&#xff1a;调皮哥的小助理 站在设计雷达的角度看&#xff0c;其实无论是传统的3D毫米波雷达&#xff0c;还是如今的4D毫米波成像雷达&#xff0c;其雷达系统性能参数都遵循一个原则&#xff0c;即&#xff1a; d res ⋅ v res ⋅ θ res d max ⁡ ⋅ v max ⁡ ⋅ …

ESP8266通过MQTT协议连接onenet云平台

中国移动onenet平台 文章目录 中国移动onenet平台前言一、onenet平台二、ESP82661.完整代码2.联网代码3.连云代码4.数据处理 总结 前言 最近在弄onenet平台&#xff0c;用arduino结合esp8266&#xff0c;就是不知道怎么回事&#xff0c;一直连不上wifi&#xff0c;然后就用esp…

Linux下使用Mysql 第一天

目录 安装mysql 更改账户名和密码 启动/关闭mysql mysql的基本操作 数据库CURD 创建数据库 查看数据库 修改数据库 删除数据库 表的CURD 创建表 查看表 修改表 删除表 表数据的CURD create数据 Retrieve数据 update数据 delete数据 DML和DDL的区别&#xf…

高分辨率光学遥感图像水体分类综述2022.03

本文是Water body classification from high-resolution optical remote sensing imagery: Achievements and perspectives的学习笔记。 相关资源被作者整理到&#xff1a;这里 文章目录 Introduction基本知识 挑战和机遇挑战1. 有限的光谱信息和小场景覆盖2. 形状、大小和分布…

【JAVA-模块五 数组】

JAVA-模块五 数组 一、数组&#xff08;一维&#xff09;1.1数组是什么&#xff1f;1.2java中数组静态初始化&#xff1a;&#xff08;存&#xff09;两种定义格式&#xff1a;数组初始化格式&#xff1a;静态初始化后&#xff0c;打印数组名&#xff1a; 1.3 数组元素访问&…

javaweb学生在线考试系统dzkf10程序

打分&#xff09;、系统管理&#xff08;数据备份&#xff09;等功能操作。 以学生的身份在登录页面输入账号和密码&#xff0c;经过数据库身份验证&#xff0c;验证成功后登录系统主页&#xff0c;可以使用个人资料管理、试卷查看、在线考试、在线答疑、个人考试成绩查询等功能…

Oracle的学习心得和知识总结(二十三)|Oracle数据库Real Application Testing之Database Replay相关视图

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《Oracle Database SQL Language Reference》 2、参考书籍&#xff1a;《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…

LVS负载均衡-DR

1.DR模式中每台主机都有一个VIP地址 虚拟网址放在lo网卡上&#xff08;回环网卡&#xff09; arp_ignore1 Arp_announce2 系统不使用IP包的源地址来设置ARP请求的源地址&#xff0c;而选择发送接口的IP地址 2.内核参数修改 3.vim /etc/rc.conf 开机自启动 Chmod x /etc/rc.d…

【翻译一下官方文档】之uniapp的导航条设置

目录 uni.setNavigationBarTitle(OBJECT) uni.setNavigationBarColor(OBJECT) uni.hideHomeButton(OBJECT) uni.setNavigationBarTitle(OBJECT) 动态设置当前页面的标题。 OBJECT参数说明 参数类型必填说明titleString是页面标题successFunction否接口调用成功的回调函数fai…