Second Minimum Time to Reach Destination - Dijkstra's Algorithm [JS]

Description 

Solution: Dijkstra's Algorithm w/ Two Minimum Times

Dijkstra's algorithm, except we store two minimum times for each node instead of just one.
We only visit a neighbor node if:

  1. The neighbor has less than two minimum times stored so far and the new time is not equal to the minimum time (since the second minimum time must be strictly larger than the minimum value)
  2. The new time is not equal to the minimum time and the new time is smaller than the second minimum time.

Calculate time to travel from one node to another:

  • Green light: Math.floor(curr time / change) % 2 === 0
    • time to travel: curr time + time
  • Red light: Math.floor(curr time / change) % 2 === 1
    • time to travel: curr time + time + time until next green light
    • time to wait until next green light = change - (curr time % change)

V = number of citiesE = number of edges
Time Complexity: O((V + E) * log(V)) 1088ms
Space Complexity: O(V + E)115.2MB

var secondMinimum = function(n, edges, time, change) {
  let graph = Array(n + 1).fill(0).map(() => []);
  for (let [u, v] of edges) {
    graph[u].push(v);
    graph[v].push(u);
  }
  let heap = new PriorityQueue((a, b) => a[1] - b[1]); // [node, time]  
  let minTime = Array(n + 1).fill(0).map(() => []);
  minTime[1].push(0);
  heap.add([1, 0]);
  while (!heap.isEmpty()) {
    let [node, currTime] = heap.remove();
    if (node === n && minTime[node].length === 2) return Math.max(...minTime[node]);
    
    let isGreenLight = Math.floor(currTime / change) % 2 === 0;
    let timeUntilGreenLight = change - (currTime % change);
    let newTime = isGreenLight ? currTime + time : currTime + time + timeUntilGreenLight;
    for (let nei of graph[node]) {
      if ((minTime[nei].length <= 1 && minTime[nei][0] !== newTime) || (minTime[nei][0] !== newTime && minTime[nei][1] > newTime)) {
        minTime[nei].push(newTime);
        minTime[nei].sort((a, b) => a - b);
        if (minTime[nei].length > 2) minTime[nei].pop(); // pop out largest time if length exceeds 2
        heap.add([nei, newTime]);
      }
    }
  }
};

class PriorityQueue {
  constructor(comparator = ((a, b) => a - b)) {
    this.values = [];
    this.comparator = comparator;
    this.size = 0;
  }
  add(val) {
    this.size++;
    this.values.push(val);
    let idx = this.size - 1, parentIdx = Math.floor((idx - 1) / 2);
    while (parentIdx >= 0 && this.comparator(this.values[parentIdx], this.values[idx]) > 0) {
      [this.values[parentIdx], this.values[idx]] = [this.values[idx], this.values[parentIdx]];
      idx = parentIdx;
      parentIdx = Math.floor((idx - 1) / 2);
    }
  }
  remove() {
    if (this.size === 0) return -1;
    this.size--;
    if (this.size === 0) return this.values.pop();
    let removedVal = this.values[0];
    this.values[0] = this.values.pop();
    let idx = 0;
    while (idx < this.size && idx < Math.floor(this.size / 2)) {
      let leftIdx = idx * 2 + 1, rightIdx = idx * 2 + 2;
      if (rightIdx === this.size) {
        if (this.comparator(this.values[leftIdx], this.values[idx]) > 0) break;
        [this.values[leftIdx], this.values[idx]] = [this.values[idx], this.values[leftIdx]];
        idx = leftIdx;
      } else if (this.comparator(this.values[leftIdx], this.values[idx]) < 0 || this.comparator(this.values[rightIdx], this.values[idx]) < 0) {
        if (this.comparator(this.values[leftIdx], this.values[rightIdx]) <= 0) {
          [this.values[leftIdx], this.values[idx]] = [this.values[idx], this.values[leftIdx]];
          idx = leftIdx;
        } else {
          [this.values[rightIdx], this.values[idx]] = [this.values[idx], this.values[rightIdx]];
          idx = rightIdx;
        }
      } else {
        break;
      }
    }
    return removedVal;
  }
  top() {
    return this.values[0];
  }
  isEmpty() {
    return this.size === 0;
  }
}

Comments

Popular posts from this blog

Maximum Value of an Ordered Triplet II - Two Solutions [JS]

Maximum Sum of Distinct Subarrays With Length K - Sliding Window w/ Two Pointers & Set [JS]

Sum of Prefix Scores of Strings - Trie [JS]

Maximum Count of Positive Integer and Negative Integer - Binary Search [JS]

Count Subarrays With Median K - Count Left & Right Balance [JS]