Sort a 2D matrix diagonally

Last Updated : 29 Jun, 2026

Given an n x m matrix, rearrange the elements such that:

  • Every diagonal in the lower-left triangle of the matrix is sorted in ascending order.
  • Every diagonal in the upper-right triangle of the matrix is sorted in descending order.
  • The main diagonal, starting from the top-left corner, is left unchanged.

Input: matrix[][] = [[3, 6, 3, 8, 2], [4, 1, 9, 5, 9], [5, 7, 2, 4, 8], [8, 3, 1, 7, 6]]
Output: [[3, 9, 8, 9, 2], [1, 1, 6, 5, 8], [3, 4, 2, 6, 3], [8, 5, 7, 7, 4]]
Explanation:

2056958377
2056958378

Each diagonal below the main diagonal is sorted ascending, each diagonal above the main diagonal is sorted descending, and the main diagonal (3, 1, 2, 7) stays unchanged.

Try It Yourself
redirect icon

[Expected Approach] Using Diagonal Grouping and Sorting - O(n × m × log(min(n, m))) Time and O(min(n, m)) Space

Every cell on the same diagonal shares the same value of row minus column. Grouping all cells by this value separates the matrix into independent diagonals, each of which can be sorted on its own - ascending if it lies below the main diagonal, descending if above, and left untouched if it is the main diagonal itself.

  • Group every cell's value into a collection keyed by row - col, which identifies its diagonal.
  • Sort each diagonal's collected values: ascending if the key is positive (below the main diagonal), descending if the key is negative (above the main diagonal), and leave the main diagonal (key equal to 0) untouched.
  • Walk through the matrix again in the same row-by-row, left-to-right order, placing the sorted values back into their diagonal's positions in sequence.
C++
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

void diagonalSort(vector<vector<int>> &matrix)
{
    int n = matrix.size();
    int m = matrix[0].size();
    unordered_map<int, vector<int>> diagonals;

    // Group elements by their diagonal index (row - col)
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            diagonals[i - j].push_back(matrix[i][j]);

    // Sort each diagonal: ascending below main, descending above main
    for (auto &[diff, vals] : diagonals)
    {
        if (diff > 0)
            sort(vals.begin(), vals.end());
        else if (diff < 0)
            sort(vals.rbegin(), vals.rend());
    }

    // Track how many elements have been placed back per diagonal
    unordered_map<int, int> pos;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            int diff = i - j;
            if (diff == 0)
                continue;
            matrix[i][j] = diagonals[diff][pos[diff]++];
        }
    }
}

int main()
{
    vector<vector<int>> matrix = {{3, 6, 3, 8, 2}, {4, 1, 9, 5, 9}, {5, 7, 2, 4, 8}, {8, 3, 1, 7, 6}};
    diagonalSort(matrix);
    for (auto &row : matrix)
    {
        for (int x : row)
            cout << x << " ";
        cout << endl;
    }
    return 0;
}
Java
import java.util.*;

class GfG {
    static void diagonalSort(int[][] matrix)
    {
        int n = matrix.length;
        int m = matrix[0].length;
        Map<Integer, List<Integer> > diagonals
            = new HashMap<>();

        // Group elements by their diagonal index (row -
        // col)
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                diagonals
                    .computeIfAbsent(i - j,
                                     x -> new ArrayList<>())
                    .add(matrix[i][j]);

        // Sort each diagonal: ascending below main,
        // descending above main
        for (Map.Entry<Integer, List<Integer> > entry :
             diagonals.entrySet()) {
            int diff = entry.getKey();
            List<Integer> vals = entry.getValue();
            if (diff > 0)
                Collections.sort(vals);
            else if (diff < 0)
                Collections.sort(
                    vals, Collections.reverseOrder());
        }

        // Track how many elements have been placed back per
        // diagonal
        Map<Integer, Integer> pos = new HashMap<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int diff = i - j;
                if (diff == 0)
                    continue;
                int idx = pos.getOrDefault(diff, 0);
                matrix[i][j] = diagonals.get(diff).get(idx);
                pos.put(diff, idx + 1);
            }
        }
    }

    public static void main(String[] args)
    {
        int[][] matrix = { { 3, 6, 3, 8, 2 },
                           { 4, 1, 9, 5, 9 },
                           { 5, 7, 2, 4, 8 },
                           { 8, 3, 1, 7, 6 } };
        diagonalSort(matrix);
        for (int[] row : matrix)
            System.out.println(Arrays.toString(row));
    }
}
Python
def diagonalSort(matrix):
    n = len(matrix)
    m = len(matrix[0])
    diagonals = {}

    # Group elements by their diagonal index (row - col)
    for i in range(n):
        for j in range(m):
            diff = i - j
            diagonals.setdefault(diff, []).append(matrix[i][j])

    # Sort each diagonal: ascending below main, descending above main
    for diff in diagonals:
        if diff > 0:
            diagonals[diff].sort()
        elif diff < 0:
            diagonals[diff].sort(reverse=True)

    # Track how many elements have been placed back per diagonal
    pos = {}
    for i in range(n):
        for j in range(m):
            diff = i - j
            if diff == 0:
                continue
            idx = pos.get(diff, 0)
            matrix[i][j] = diagonals[diff][idx]
            pos[diff] = idx + 1


if __name__ == "__main__":
    matrix = [[3, 6, 3, 8, 2], [4, 1, 9, 5, 9],
              [5, 7, 2, 4, 8], [8, 3, 1, 7, 6]]
    diagonalSort(matrix)
    for row in matrix:
        print(row)
C#
using System;
using System.Collections.Generic;
using System.Linq;

class GfG {
    static void diagonalSort(int[][] matrix)
    {
        int n = matrix.Length;
        int m = matrix[0].Length;
        Dictionary<int, List<int> > diagonals
            = new Dictionary<int, List<int> >();

        // Group elements by their diagonal index (row -
        // col)
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int diff = i - j;
                if (!diagonals.ContainsKey(diff))
                    diagonals[diff] = new List<int>();
                diagonals[diff].Add(matrix[i][j]);
            }
        }

        // Sort each diagonal: ascending below main,
        // descending above main
        foreach(var diff in diagonals.Keys.ToList())
        {
            if (diff > 0)
                diagonals[diff].Sort();
            else if (diff < 0)
                diagonals[diff].Sort((a, b) =
                                         > b.CompareTo(a));
        }

        // Track how many elements have been placed back per
        // diagonal
        Dictionary<int, int> pos
            = new Dictionary<int, int>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int diff = i - j;
                if (diff == 0)
                    continue;
                int idx
                    = pos.ContainsKey(diff) ? pos[diff] : 0;
                matrix[i][j] = diagonals[diff][idx];
                pos[diff] = idx + 1;
            }
        }
    }

    static void Main()
    {
        int[][] matrix = { new int[] { 3, 6, 3, 8, 2 },
                           new int[] { 4, 1, 9, 5, 9 },
                           new int[] { 5, 7, 2, 4, 8 },
                           new int[] { 8, 3, 1, 7, 6 } };
        diagonalSort(matrix);
        foreach(var row in matrix)
            Console.WriteLine(string.Join(" ", row));
    }
}
JavaScript
function diagonalSort(matrix)
{
    const n = matrix.length;
    const m = matrix[0].length;
    const diagonals = new Map();

    // Group elements by their diagonal index (row - col)
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            const diff = i - j;
            if (!diagonals.has(diff))
                diagonals.set(diff, []);
            diagonals.get(diff).push(matrix[i][j]);
        }
    }

    // Sort each diagonal: ascending below main, descending
    // above main
    for (const [diff, vals] of diagonals) {
        if (diff > 0)
            vals.sort((a, b) => a - b);
        else if (diff < 0)
            vals.sort((a, b) => b - a);
    }

    // Track how many elements have been placed back per
    // diagonal
    const pos = new Map();
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            const diff = i - j;
            if (diff === 0)
                continue;
            const idx = pos.get(diff) || 0;
            matrix[i][j] = diagonals.get(diff)[idx];
            pos.set(diff, idx + 1);
        }
    }
}

// Driver code
const matrix = [
    [ 3, 6, 3, 8, 2 ], [ 4, 1, 9, 5, 9 ], [ 5, 7, 2, 4, 8 ],
    [ 8, 3, 1, 7, 6 ]
];
diagonalSort(matrix);
matrix.forEach(row => console.log(row.join(" ")));

Output
3 9 8 9 2 
1 1 6 5 8 
3 4 2 6 3 
8 5 7 7 4 
Comment