Taro Logo

Diagonal Traverse II

Medium
Apple logo
Apple
1 view
Topics:
Arrays

You are given a 2D integer array called nums. Your task is to return all the elements of nums in diagonal order, as shown in the examples below. Diagonal order means traversing the array in diagonals, alternating the direction of traversal for each diagonal.

Example 1:

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

Explanation: The diagonals are:

  • Diagonal 1: [1]
  • Diagonal 2: [4, 2]
  • Diagonal 3: [7, 5, 3]
  • Diagonal 4: [8, 6]
  • Diagonal 5: [9]

The output is formed by concatenating these diagonals in order, reversing the even numbered diagonals (starting from 2).

Example 2:

Input: nums = [[1,2,3,4,5],[6,7],[8],[9,10,11],[12,13,14,15,16]]
Output: [1,6,2,8,7,3,9,4,12,10,5,13,11,14,15,16]

Constraints:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i].length <= 10^5
  • 1 <= sum(nums[i].length) <= 10^5
  • 1 <= nums[i][j] <= 10^5

Can you implement a function that takes the 2D array nums as input and returns a 1D array containing all the elements in diagonal order?

Solution


Naive Solution

A brute force approach would involve iterating through the 2D array in a way that simulates the diagonal traversal. This would involve nested loops and careful index manipulation to access elements along each diagonal. This approach is generally inefficient, especially if the rows have varying lengths.

Optimal Solution

  1. Group by Diagonal: Realize that elements on the same diagonal have the same row + col value. We can use a hash map (or in this case, an array of lists) to group elements by their diagonal index (row + col).
  2. Reverse Even Diagonals: Since we need to traverse diagonals in opposite directions (top-right to bottom-left, then bottom-left to top-right), we reverse the order of elements in even-numbered diagonals before concatenating the results.
from collections import defaultdict

def diagonal_order(nums):
    diagonals = defaultdict(list)
    for row in range(len(nums)):
        for col in range(len(nums[row])):
            diagonals[row + col].append(nums[row][col])

    result = []
    for diag_index in sorted(diagonals.keys()):
        if diag_index % 2 == 0:
            result.extend(reversed(diagonals[diag_index]))
        else:
            result.extend(diagonals[diag_index])
    return result

Edge Cases

  • Empty Input: If the input array is empty, return an empty list.
  • Uneven Rows: The algorithm should handle cases where the rows have different lengths.
  • Single Element: If the array contains only one element, return an array containing that element.

Time and Space Complexity

  • Time Complexity: O(N), where N is the total number of elements in the input array. This is because we iterate through each element once to group them by diagonal, and then iterate through the diagonals to construct the result.
  • Space Complexity: O(N). In the worst case, the diagonals dictionary can store all the elements of the input array if they all belong to different diagonals. The result list also stores all the elements.