题目描述
有 N 个网络节点,标记为 1 到 N。
给定一个列表 times,表示信号经过有向边的传递时间。 times[i] = (u, v, w),其中 u 是源节点,v 是目标节点, w 是一个信号从源节点传递到目标节点的时间。
现在,我们向当前的节点 K 发送了一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1。
注意:
N 的范围在 [1, 100] 之间。
K 的范围在 [1, N] 之间。
times 的长度在 [1, 6000] 之间。
所有的边 times[i] = (u, v, w) 都有 1 <= u, v <= N 且 1 <= w <= 100。
理解了就变得很简单:
就是用一个数组表示距离,
class Solution {
public int networkDelayTime(int[][] times, int N, int K) {
int distance [] = new int[N+1];
//遍历过的list
List<Integer> already = new ArrayList<>();
for (int i = 1; i < distance.length; i++) {
//首先初始化时最远距离,这里使用的是Integer的最大值代替
distance[i] = Integer.MAX_VALUE;
}
distance[K] = 0;
int lop = 1;
while (lop != 0) {
lop--;
for (int i = 0; i < times.length; i++) {
if(distance[times[i][0]] != Integer.MAX_VALUE){
int t = distance[times[i][1]];
if(times[i][2] + distance[times[i][0]] < distance[times[i][1]]){
distance[times[i][1]] = times[i][2] + distance[times[i][0]];
lop = 1;
}
}
}
}
// System.out.println(Arrays.toString(distance));
int max = distance[1];
for (int i = 1; i < distance.length; i++) {
int j = distance[i];
//存在不可到达的点
if(j==Integer.MAX_VALUE){
return -1;
}
if(max < j){
max = j;
}
}
return max;
}
}
排名靠前的代码
class Solution {
public int networkDelayTime(int[][] times, int N, int K) {
int limit = 99999999;
int[][] matrix = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; ++j){
matrix[i][j] = -1;
}
}
for (int[] uvw : times) {
matrix[uvw[0] - 1][uvw[1] - 1] = uvw[2];
}
// Dijkstra算法
int last_p = K - 1;
int[] done = new int[N];
done[last_p] = 1;
int[] compare_buf = new int[N];
int[] result_buf = new int[N];
int[] front_node = new int[N];
for (int i = 0; i < N; i++) {
compare_buf[i] = limit;
result_buf[i] = limit;
front_node[i] = -1;
}
result_buf[K - 1] = 0;
int maxresult = -limit;
while (true){
// 对last点进行遍历,更新compare_buf
for (int i = 0; i < matrix[last_p].length; i++) {
int v = matrix[last_p][i];
if (done[i] == 1 || v == -1)
continue;
int value = v + result_buf[last_p];
// 松弛操作relax
if (value < compare_buf[i]){
compare_buf[i] = value;
front_node[i] = last_p;
}
}
int temp_min = limit;
int temp_node = -1;
for (int i = 0; i < compare_buf.length; i++) {
int value = compare_buf[i];
if (done[i] == 1 || value == limit)
continue;
if (value < temp_min){
temp_min = value;
temp_node = i;
}
}
if (temp_node == -1)
break;
else{
done[temp_node] = 1;
last_p = temp_node;
result_buf[temp_node] = temp_min;
maxresult = Math.max(temp_min, maxresult);
}
}
for (int d : done){
if (d == 0)
return -1;
}
return maxresult;
}
}
第一次使用队列的问题,我刚了一个小时才知道,原来你更新了end距离后,不是根据是否遍历过来判断是否加入队列,而是就是要加入(如果队列中没有),因为你的end距离发生了变化,那么以end作为起点的距离都可能发生变化,因此就是需要加入,所有以后要认真和全面考虑问题
改过的代码如下:
public int networkDelayTime(int[][] times, int N, int K) {
//我理解的Dijkstra 最短路算法,首先定义一个list存放所有没有遍历的点,然后定义一个数组,存放K到各个节点的距离,N个点,长度为N+1,那么下标为
//K的长度就是0,因为本身到本身就是0,接着我们用一个队列存放所有点的出点,在进行存放时要注意的是:已经遍历的点不能放进去
//每次从队列中取出一个点时,我们计算该点到另一个点的距离,并且更新距离数组,之后判断是否要将目的点放入到队列,如果已经放入过那么无需放入队列,否则
//放入队列
//具体实现:
//距离数组
int distance [] = new int[N+1];
//遍历过的list
List<Integer> already = new ArrayList<>();
for (int i = 1; i < distance.length; i++) {
//首先初始化时最远距离,这里使用的是Integer的最大值代替
distance[i] = Integer.MAX_VALUE;
}
distance[K] = 0;
distance[K] = 0;
already.add(K);
//设置当前遍历的队列
Queue<Integer> Traversing = new LinkedList<>();
Traversing.offer(K);
while (!Traversing.isEmpty()) {
//从节点中遍历所有的点,并且更新距离数组
//int[][] times数组是n行三列,其中第一列是起点,第二列是终点
//从队列中取出一个点
int tem = Traversing.poll();
// System.out.println("点的顺序为"+ tem);
for (int i = 0; i < times.length; i++) {
//times[i][0]表示的是起点
if(times[i][0] == tem){
// System.out.println("当前起点为"+tem + "距离为"+ distance[tem]);
//等于当前的起点
//取出终点
int end = times[i][1];
int distem = times[i][2];
if(distance[end] > distem + distance[tem]){
distance[end] = distem + distance[tem];
// System.out.println("当前到"+end+"点的最小距离为"+ distance[end]);
if(!Traversing.contains(end)){
Traversing.offer(end);
}
}
}
}
}
int max = distance[0];
for (int i = 0; i < distance.length; i++) {
int j = distance[i];
//存在不可到达的点
if(j==Integer.MAX_VALUE){
return -1;
}
if(max < j){
max = j;
}
}
System.out.println(Arrays.toString(distance));
return max;
/*
*
*
* int lop = 1;
while (lop != 0) {
lop--;
for (int i = 0; i < times.length; i++) {
if(distance[times[i][0]] != Integer.MAX_VALUE){
//int t = distance[times[i][1]];
if(times[i][2] + distance[times[i][0]] < distance[times[i][1]]){
distance[times[i][1]] = times[i][2] + distance[times[i][0]];
lop = 1;
}
}
}
}
System.out.println(Arrays.toString(distance));
int max = distance[1];
for (int i = 1; i < distance.length; i++) {
int j = distance[i];
//存在不可到达的点
if(j==Integer.MAX_VALUE){
return -1;
}
if(max < j){
max = j;
}
}
return max;*/
/* //初始化起点为0,因为起点到起点就是0
distance[K] = 0;
already.add(K);
//设置当前遍历的队列
Queue<Integer> Traversing = new LinkedList<>();
Traversing.offer(K);
while (!Traversing.isEmpty()) {
//从节点中遍历所有的点,并且更新距离数组
//int[][] times数组是n行三列,其中第一列是起点,第二列是终点
//从队列中取出一个点
int tem = Traversing.poll();
// System.out.println("点的顺序为"+ tem);
for (int i = 0; i < times.length; i++) {
//times[i][0]表示的是起点
if(times[i][0] == tem){
// System.out.println("当前起点为"+tem + "距离为"+ distance[tem]);
//等于当前的起点
//取出终点
int end = times[i][1];
int distem = times[i][2];
if(distance[end] > distem + distance[tem]){
distance[end] = distem + distance[tem];
// System.out.println("当前到"+end+"点的最小距离为"+ distance[end]);
}
//判断是否要进入队列,进行下一次的遍历
if(already.contains(end)){
}else {
//没有遍历过则继续
already.add(end);
Traversing.offer(end);
}
}
}
}
int max = distance[0];
for (int i = 0; i < distance.length; i++) {
int j = distance[i];
//存在不可到达的点
if(j==Integer.MAX_VALUE){
return -1;
}
if(max < j){
max = j;
}
}
System.out.println(Arrays.toString(distance));
return max;*/
}