Open In App

Path with smallest difference between consecutive cells (Path with minimum effort)

Last Updated : 28 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a 2D array arr[] of size N x M, where arr[i][j] represents the value of cell (i, j). You are situated in the top-left cell, (0, 0), and you hope to travel to the bottom-right cell, (n-1, m-1). You can move up, down, left, or right, and you wish to find a path such that the maximum absolute difference in values between two consecutive cells of the path is minimized.

Examples:

Input: N = 3, M = 3, arr[][] = [[1, 2, 2], [3, 8, 2], [5, 3, 5]]
Output: 2
Explanation: The route of [1, 3, 5, 3, 5] has a maximum absolute difference of 2 in consecutive cells.

minimumEffort

Input: N = 4, M = 5, arr[][] = [[1, 2, 1, 1, 1], [1, 2, 1, 2, 1], [1, 2, 1, 2, 1], [1, 1, 1, 2, 1]]
Output: 0
Explanation: The route of [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] has a maximum absolute difference of 0 in consecutive cells.

Approach: To solve the problem, follow the idea below:

The task is to traverse from the starting cell (0,0) to the last cell (N-1, M-1) in a grid, ensuring that the effort involved is minimized. The effort for each step is defined as the maximum difference between the current cell and the next cell along the path from the start to the end. Among all possible paths, our goal is to find the one that requires the least maximum absolute difference in values between two consecutive cells. This can be done by applying Dijkstra’s Algorithm. This approach is similar to Dijkstra’s, but instead of updating the distance from the source, it updates the absolute difference from the parent node. The cell with the lower difference value is prioritized in the queue. In our approach, we continuously update the maximum absolute difference value each time we find a path that has a smaller difference than the current maximum difference. This ensures that we are always considering the path with the least maximum absolute difference. .

Step-by-step algorithm:

  • Creating a queue {dist,(row, col)}
  • Create a dist[][] matrix with each cell initialized with a very large number (1e9).
  • Initialize the source cell marked as ‘0’
  • Push the source cell to the queue with distance 0
  • Pop the element at the front of the queue
  • Check if each adjacent cell is within the matrix’s boundaries
  • Update the difference in the matrix and push the cell into the queue if the current difference is better than the previous one
  • Repeat the above three steps until the queue is empty or we encounter the destination node
  • Return the max difference if r==n-1 and c==m-1
  • If the queue becomes empty and we don’t encounter the destination, return 0

Below is the implementation of the algorithm:

C++
#include <bits/stdc++.h>
using namespace std;

int minAbsoluteValue(vector<vector<int> >& arr)
{
    int N = arr.size(), M = arr[0].size();

    // priority queue containing pairs of cells and their
    // respective distance from the source cell in the form
    // {diff, {row of cell, col of cell}}
    priority_queue<pair<int, pair<int, int> >,
                vector<pair<int, pair<int, int> > >,
                greater<pair<int, pair<int, int> > > >
        pq;

    // distance matrix with initially all the cells marked
    // as unvisited
    vector<vector<int> > d(N, vector<int>(M, 1e9));
    // distance for source cell (0,0) is 0
    d[0][0] = 0;
    pq.push({ 0, { 0, 0 } });

    // array to traverse in all four directions
    int dx[] = { -1, 0, 1, 0 };
    int dy[] = { 0, 1, 0, -1 };

    // Iterate through the matrix by popping the elements
    // out of the queue and pushing whenever a shorter
    // distance to a cell is found
    while (!pq.empty()) {
        int diff = pq.top().first;
        int r = pq.top().second.first;
        int c = pq.top().second.second;
        pq.pop();
        // return the current value of difference (which
        // will be min) if we reach the destination
        if (r == N - 1 && c == M - 1)
            return diff;
        for (int i = 0; i < 4; i++) {
            // r-1, c
            // r, c+1
            // r-1, c
            // r, c-1
            int nx = dx[i] + r;
            int ny = dy[i] + c;

            // checking validity of the cell
            if (nx >= 0 && nx < N && ny >= 0 && ny < M) {
                // effort can be calculated as the max value
                // of differences between the values of the
                // node and its adjacent nodes
                int nf = max(abs(arr[r][c] - arr[nx][ny]),
                            diff);

                // if the calculated effort is less than the
                // prev value update as we need the min
                // effort
                if (nf < d[nx][ny]) {
                    d[nx][ny] = nf;
                    pq.push({ nf, { nx, ny } });
                }
            }
        }
    }
    // if unreachable
    return -1;
}

// Driver Code
int main()
{
    // Example 1
    vector<vector<int> > arr
        = { { 1, 2, 2 }, { 3, 8, 2 }, { 5, 3, 5 } };
    cout << minAbsoluteValue(arr) << endl;

    // Example 2
    arr = { { 1, 2, 1, 1, 1 },
            { 1, 2, 1, 2, 1 },
            { 1, 2, 1, 2, 1 },
            { 1, 1, 1, 2, 1 } };
    cout << minAbsoluteValue(arr) << endl;

    return 0;
}
Java
import java.util.PriorityQueue;

class Main {
    static int minAbsoluteValue(int[][] arr)
    {
        int N = arr.length;
        int M = arr[0].length;

        // Priority queue containing pairs of cells and
        // their respective distance from the source cell
        PriorityQueue<int[]> pq = new PriorityQueue<>(
            (a, b) -> Integer.compare(a[0], b[0]));

        // Distance matrix with initially all the cells
        // marked as unvisited
        int[][] d = new int[N][M];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                d[i][j] = Integer.MAX_VALUE;
            }
        }

        // Distance for the source cell (0, 0) is 0
        d[0][0] = 0;
        pq.add(new int[] { 0, 0, 0 });

        // Array to traverse in all four directions
        int[] dx = { -1, 0, 1, 0 };
        int[] dy = { 0, 1, 0, -1 };

        // Iterate through the matrix by popping the
        // elements out of the queue and pushing whenever a
        // shorter distance to a cell is found
        while (!pq.isEmpty()) {
            int[] cell = pq.poll();
            int diff = cell[0];
            int r = cell[1];
            int c = cell[2];

            // Return the current value of difference (which
            // will be min) if we reach the destination
            if (r == N - 1 && c == M - 1)
                return diff;

            for (int i = 0; i < 4; i++) {
                int nx = dx[i] + r;
                int ny = dy[i] + c;

                // Checking validity of the cell
                if (nx >= 0 && nx < N && ny >= 0
                    && ny < M) {
                    // Effort can be calculated as the max
                    // value of differences between the
                    // values of the node and its adjacent
                    // nodes
                    int nf = Math.max(
                        Math.abs(arr[r][c] - arr[nx][ny]),
                        diff);

                    // If the calculated effort is less than
                    // the previous value update as we need
                    // the min effort
                    if (nf < d[nx][ny]) {
                        d[nx][ny] = nf;
                        pq.add(new int[] { nf, nx, ny });
                    }
                }
            }
        }
        // If unreachable
        return -1;
    }

    // Driver Code
    public static void main(String[] args)
    {
        // Example 1
        int[][] arr1
            = { { 1, 2, 2 }, { 3, 8, 2 }, { 5, 3, 5 } };
        System.out.println(minAbsoluteValue(arr1));

        // Example 2
        int[][] arr2 = { { 1, 2, 1, 1, 1 },
                         { 1, 2, 1, 2, 1 },
                         { 1, 2, 1, 2, 1 },
                         { 1, 1, 1, 2, 1 } };
        System.out.println(minAbsoluteValue(arr2));
    }
}

// This code is contributed by akshitaguprzj3
C#
//code by flutterfly
using System;
using System.Collections.Generic;

class Program
{
    static int MinAbsoluteValue(List<List<int>> arr)
    {
        int N = arr.Count, M = arr[0].Count;

        // priority queue containing tuples of cells and their
        // respective distance from the source cell in the form
        // (diff, (row of cell, col of cell))
        var pq = new PriorityQueue<Tuple<int, Tuple<int, int>>>(Comparer<Tuple<int, Tuple<int, int>>>.Create((x, y) => x.Item1.CompareTo(y.Item1)));

        // distance matrix with initially all the cells marked
        // as unvisited
        var d = new int[N][];
        for (int i = 0; i < N; i++)
        {
            d[i] = new int[M];
            for (int j = 0; j < M; j++)
                d[i][j] = int.MaxValue;
        }

        // distance for source cell (0,0) is 0
        d[0][0] = 0;
        pq.Enqueue(new Tuple<int, Tuple<int, int>>(0, new Tuple<int, int>(0, 0)));

        // array to traverse in all four directions
        int[] dx = { -1, 0, 1, 0 };
        int[] dy = { 0, 1, 0, -1 };

        // Iterate through the matrix by popping the elements
        // out of the queue and pushing whenever a shorter
        // distance to a cell is found
        while (pq.Count > 0)
        {
            var current = pq.Dequeue();
            int diff = current.Item1;
            int r = current.Item2.Item1;
            int c = current.Item2.Item2;

            // return the current value of difference (which
            // will be min) if we reach the destination
            if (r == N - 1 && c == M - 1)
                return diff;

            for (int i = 0; i < 4; i++)
            {
                int nx = dx[i] + r;
                int ny = dy[i] + c;

                // checking validity of the cell
                if (nx >= 0 && nx < N && ny >= 0 && ny < M)
                {
                    // effort can be calculated as the max value
                    // of differences between the values of the
                    // node and its adjacent nodes
                    int nf = Math.Max(Math.Abs(arr[r][c] - arr[nx][ny]), diff);

                    // if the calculated effort is less than the
                    // prev value update as we need the min
                    // effort
                    if (nf < d[nx][ny])
                    {
                        d[nx][ny] = nf;
                        pq.Enqueue(new Tuple<int, Tuple<int, int>>(nf, new Tuple<int, int>(nx, ny)));
                    }
                }
            }
        }
        // if unreachable
        return -1;
    }

    static void Main(string[] args)
    {
        // Example 1
        var arr1 = new List<List<int>> {
            new List<int> { 1, 2, 2 },
            new List<int> { 3, 8, 2 },
            new List<int> { 5, 3, 5 }
        };
        Console.WriteLine(MinAbsoluteValue(arr1));

        // Example 2
        var arr2 = new List<List<int>> {
            new List<int> { 1, 2, 1, 1, 1 },
            new List<int> { 1, 2, 1, 2, 1 },
            new List<int> { 1, 2, 1, 2, 1 },
            new List<int> { 1, 1, 1, 2, 1 }
        };
        Console.WriteLine(MinAbsoluteValue(arr2));
    }
}

public class PriorityQueue<T>
{
    private List<T> data;
    private readonly IComparer<T> comparer;

    public PriorityQueue(IComparer<T> comparer)
    {
        this.data = new List<T>();
        this.comparer = comparer;
    }

    public void Enqueue(T item)
    {
        data.Add(item);
        int ci = data.Count - 1;
        while (ci > 0)
        {
            int pi = (ci - 1) / 2;
            if (comparer.Compare(data[ci], data[pi]) >= 0)
                break;
            T tmp = data[ci]; data[ci] = data[pi]; data[pi] = tmp;
            ci = pi;
        }
    }

    public T Dequeue()
    {
        int li = data.Count - 1;
        T frontItem = data[0];
        data[0] = data[li];
        data.RemoveAt(li);

        --li;
        int pi = 0;
        while (true)
        {
            int ci = pi * 2 + 1;
            if (ci > li) break;
            int rc = ci + 1;
            if (rc <= li && comparer.Compare(data[rc], data[ci]) < 0)
                ci = rc;
            if (comparer.Compare(data[pi], data[ci]) <= 0) break;
            T tmp = data[pi]; data[pi] = data[ci]; data[ci] = tmp;
            pi = ci;
        }
        return frontItem;
    }

    public T Peek()
    {
        T frontItem = data[0];
        return frontItem;
    }

    public int Count
    {
        get { return data.Count; }
    }
}
Javascript
class PriorityQueue {
    constructor() {
        // Initialize an empty heap for the priority queue
        this.heap = [];
    }

    // Function to push a value into the priority queue
    push(value) {
        // Push the value and sort the heap based on the first element of each pair
        this.heap.push(value);
        this.heap.sort((a, b) => a[0] - b[0]);
    }

    // Function to pop the top element from the priority queue
    pop() {
        // Remove and return the first element from the heap
        return this.heap.shift();
    }

    // Function to check if the priority queue is empty
    isEmpty() {
        // Return true if the heap is empty, false otherwise
        return this.heap.length === 0;
    }
}

// Function to find the minimum absolute difference value
function minAbsoluteValue(arr) {
    const N = arr.length;
    const M = arr[0].length;

    // Create a priority queue
    const pq = new PriorityQueue();

    // Create a distance matrix with initially all cells marked as unvisited
    const d = Array.from({ length: N }, () => Array(M).fill(1e9));
    
    // Distance for the source cell (0, 0) is 0
    d[0][0] = 0;

    // Push the source cell into the priority queue
    pq.push([0, [0, 0]]);

    // Array to traverse in all four directions
    const dx = [-1, 0, 1, 0];
    const dy = [0, 1, 0, -1];

    // Iterate through the matrix by popping elements from the queue
    // and pushing whenever a shorter distance to a cell is found
    while (!pq.isEmpty()) {
        const [diff, [r, c]] = pq.pop();

        // Return the current value of difference (min) if we reach the destination
        if (r === N - 1 && c === M - 1)
            return diff;

        for (let i = 0; i < 4; i++) {
            const nx = dx[i] + r;
            const ny = dy[i] + c;

            // Checking the validity of the cell
            if (nx >= 0 && nx < N && ny >= 0 && ny < M) {
                // Effort can be calculated as the max value
                // of differences between the values of the
                // node and its adjacent nodes
                const nf = Math.max(Math.abs(arr[r][c] - arr[nx][ny]), diff);

                // If the calculated effort is less than the
                // previous value, update it as we need the min effort
                if (nf < d[nx][ny]) {
                    d[nx][ny] = nf;
                    pq.push([nf, [nx, ny]]);
                }
            }
        }
    }

    // If unreachable
    return -1;
}

// Example 1
const arr1 = [[1, 2, 2], [3, 8, 2], [5, 3, 5]];
console.log(minAbsoluteValue(arr1));

// Example 2
const arr2 = [
    [1, 2, 1, 1, 1],
    [1, 2, 1, 2, 1],
    [1, 2, 1, 2, 1],
    [1, 1, 1, 2, 1]
];
console.log(minAbsoluteValue(arr2));
Python3
import heapq

def min_absolute_value(arr):
    N = len(arr)
    M = len(arr[0])

    # Priority queue containing pairs of cells and their respective distance from the source cell
    pq = []
    heapq.heapify(pq)

    # Distance matrix with initially all the cells marked as unvisited
    d = [[float('inf')] * M for _ in range(N)]
    # Distance for source cell (0,0) is 0
    d[0][0] = 0
    heapq.heappush(pq, (0, (0, 0)))

    # Array to traverse in all four directions
    dx = [-1, 0, 1, 0]
    dy = [0, 1, 0, -1]

    # Iterate through the matrix by popping the elements out of the queue
    # and pushing whenever a shorter distance to a cell is found
    while pq:
        diff, (r, c) = heapq.heappop(pq)
        # Return the current value of difference (which will be min) if we reach the destination
        if r == N - 1 and c == M - 1:
            return diff
        for i in range(4):
            nx = dx[i] + r
            ny = dy[i] + c

            # Checking validity of the cell
            if 0 <= nx < N and 0 <= ny < M:
                # Effort can be calculated as the max value of differences between the values of the
                # node and its adjacent nodes
                nf = max(abs(arr[r][c] - arr[nx][ny]), diff)

                # If the calculated effort is less than the prev value update as we need the min effort
                if nf < d[nx][ny]:
                    d[nx][ny] = nf
                    heapq.heappush(pq, (nf, (nx, ny)))

    # If unreachable
    return -1

# Example 1
arr1 = [[1, 2, 2], [3, 8, 2], [5, 3, 5]]
print(min_absolute_value(arr1))

# Example 2
arr2 = [[1, 2, 1, 1, 1],
        [1, 2, 1, 2, 1],
        [1, 2, 1, 2, 1],
        [1, 1, 1, 2, 1]]
print(min_absolute_value(arr2))

Output
2
0

Time complexity: O((N * M) * log(N * M)), where N is the number of rows and M is the number of columns in the matrix arr[][].
Auxiliary Space: O(N * M)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads