Leetcode 1334. 阈值距离内邻居最少的城市

Leetcode 1334. 阈值距离内邻居最少的城市

1、问题分析

题目链接:https://leetcode-cn.com/problems/find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance/
  本质上就是一个求全源最短路径问题,但是需要注意的是leetCode内存检测机制造成的内存泄露问题(其实是没有内存泄露的,是个bug),然后就是注意节点到节点本身的距离,可能通过其他节点过来的,这时 distanceThreshold 阈值可能影响结果,需要额外处理一下。代码我已经进行了详细的注释,理解应该没有问题,读者可以作为参考,如果看不懂(可以多看几遍),欢迎留言哦!我看到会解答一下。

2、问题解决

  笔者以C++方式解决。

#include "iostream"

using namespace std;

#include "algorithm"
#include "vector"
#include "queue"
#include "set"
#include "map"
#include "cstring"
#include "stack"

class Solution {
private:
	// 定义邻接矩阵(存放的是在 distanceThreshold 之内的节点)
	vector<vector<int>> Adu;
	// 定义最大节点个数
	const static int MAXV = 101;
	// 定义节点个数
	int n_all;
	// 定义节点间距离函数,例如: dis[0][1] 代表 0 <------> 1 之间的距离
	// 这里需要初始化为一个很大的距离(代表节点之间不连通)
	int dis[MAXV][MAXV];
	// 定义节点之间不连通距离大小
	const int INF = 10001;
public:
	int findTheCity(int n, vector<vector<int>> &edges, int distanceThreshold) {
		// 初始化邻接矩阵
		Adu.resize(n);
		// 初始化节点个数
		n_all = n;
		// 初始化 dis 距离数组
		init(edges);
		// 使用佛洛依德算法 求全源最短路径
		folyd();

		// 根据距离数组 和 distanceThreshold 初始化邻接矩阵(存放的是在 distanceThreshold 之内的节点)
		for (int i = 0; i < n_all; ++i) {
			for (int j = 0; j < n_all; ++j) {
				// 由于经过folyd 算法,本身的节点距离会通过其他节点在转过来形成 自己到自己的状态
				// 所以需要将  自己到自己的状态 排除
				if (dis[i][j] <= distanceThreshold && i != j) {
					// 这里无向图仍然是双向的,会有重复的元素,但是没有关系,2*n , 可以使用  set 去重
					Adu[i].push_back(j);
					Adu[j].push_back(i);
				}
			}
		}

		// 结果城市
		int result = 0;
		// 最小城市数
		int minSize = 1000;
		for (int i = 0; i < n; ++i) {
			// 由于需要相同值 取编号较大的值 所以这里有 等号 
			if (Adu[i].size() <= minSize) {
				minSize = Adu[i].size();
				result = i;
			}
		}

		return result;
	}

	/**
	*
	* @param edges
	*/
	void init(vector<vector<int>> &edges) {
		// 其实用 fill 函数初始化是最好的,但是LeetCode 会报错
		/**
		* Line 37: Char 29: runtime error: index 10201 out of bounds for type 'int [101]' (solution.cpp)
		SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:47:29
		解释是:LeetCode 使用了AddressSanitizer检查是否存在内存非法访问,但是我们是二维数组,应该是一个bug
		*/
		// fill(dis[0], dis[0] + MAXV * MAXV, INF);

		// 只能手动初始化距离数组,并将其设置成不可达的距离
		for (int i = 0; i < n_all; ++i) {
			for (int j = 0; j < n_all; ++j) {
				dis[i][j] = INF;
			}
		}

		// 根据题目 edges 数组,初始化 各节点的距离 0 1 2 分别代表 from to weights
		for (int i = 0; i < edges.size(); ++i) {
			// 因为这里是无向图 所以 a->b 的距离也是 b->a 的距离
			dis[edges[i][0]][edges[i][1]] = edges[i][2];
			dis[edges[i][1]][edges[i][0]] = edges[i][2];
		}
	}

	// folyd 算法
	void folyd() {
		for (int k = 0; k < n_all; ++k) {
			for (int i = 0; i < n_all; ++i) {
				for (int j = 0; j < n_all; ++j) {
					if (dis[i][k] != INF && dis[k][j] != INF && dis[i][k] + dis[k][j] < dis[i][j]) {
						// 找到更短的路径
						dis[i][j] = dis[i][k] + dis[k][j];
					}
				}
			}
		}
	}
};

int main() {
	int n = 5;
	vector<vector<int>> edges = { { 0, 1, 2 },
	{ 0, 4, 8 },
	{ 1, 2, 3 },
	{ 1, 4, 2 },
	{ 2, 3, 1 },
	{ 3, 4, 1 } };
	int distanceThreshold = 2;

	//    int n = 4;
	//    vector<vector<int>> edges = {{0, 1, 3},
	//                                 {1, 2, 1},
	//                                 {1, 3, 4},
	//                                 {2, 3, 1}};
	//    int distanceThreshold = 4;


	Solution *pSolution = new Solution;
	int i = pSolution->findTheCity(n, edges, distanceThreshold);
	cout << i << endl;
	system("pause");
	return 0;
}

运行结果

在这里插入图片描述

有点菜,有时间再优化一下。

在这里插入图片描述

这就是内存泄露问题.

Line 37: Char 29: runtime error: index 10201 out of bounds for type 'int [101]' (solution.cpp)
           SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:47:29

解释是:LeetCode 使用了AddressSanitizer检查是否存在内存非法访问,但是我们是二维数组,应该是一个bug

3、总结

  书上的代码直接运行绝大部分是对的,但是总有一些软件的更新使得作者无能为力。之前的API是对的,但是之后就废弃了或修改了是常有的事。所以我们需要跟踪源代码。这只是一个小小的问题,如果没有前辈的无私奉献,很难想象我们自己一天能学到多少内容。感谢各位前辈的辛勤付出,让我们少走了很多的弯路!

点个赞再走呗!欢迎留言哦!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值