1. 程式人生 > >154、網路延遲時間

154、網路延遲時間

題目描述
有 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;*/
	    }