Facebook Pixel

2614. Prime In Diagonal

EasyArrayMathMatrixNumber Theory
Leetcode Link

Problem Description

You are given a 2D integer array nums with equal rows and columns (a square matrix). Your task is to find the largest prime number that appears on either of the two main diagonals of this matrix.

The two diagonals are:

  1. Primary diagonal: Elements where row index equals column index (nums[i][i])
  2. Secondary diagonal: Elements where the row index i corresponds to column index nums.length - i - 1

For example, in a 3×3 matrix:

  • Primary diagonal contains elements at positions [0][0], [1][1], [2][2]
  • Secondary diagonal contains elements at positions [0][2], [1][1], [2][0]

A prime number is defined as an integer greater than 1 that has no positive divisors other than 1 and itself.

If no prime numbers exist on either diagonal, return 0.

The solution iterates through each row of the matrix and checks two elements:

  • The element on the primary diagonal at position [i][i]
  • The element on the secondary diagonal at position [i][n-i-1]

For each element, it uses the is_prime function to determine if it's prime. The is_prime function checks divisibility from 2 up to the square root of the number. The algorithm keeps track of the maximum prime number found and returns it at the end.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to find the largest prime number on the diagonals, which naturally breaks down into two subproblems: identifying which elements are on the diagonals and checking if they are prime.

For the diagonal elements, we can observe a pattern. In a square matrix of size n×n, the primary diagonal elements follow the pattern where both indices are the same: [0][0], [1][1], [2][2], etc. The secondary diagonal has a complementary relationship: when we're at row i, the column index is n-i-1. This makes sense because as we go down rows (increasing i), we need to go left in columns (decreasing from n-1 to 0).

Since we need to find the maximum prime, we need to check all elements on both diagonals. We can do this efficiently in a single pass through the rows. For each row i, we check exactly two elements: nums[i][i] and nums[i][n-i-1]. Note that when n is odd, the center element nums[n//2][n//2] appears on both diagonals, but checking it twice doesn't affect our maximum calculation.

For prime checking, we use the standard optimization of only checking divisors up to sqrt(x). This works because if a number x has a divisor greater than sqrt(x), it must also have a corresponding divisor less than sqrt(x). So if we don't find any divisors up to sqrt(x), the number is prime.

The overall strategy is straightforward: traverse once through the matrix rows, check the two diagonal elements in each row for primality, and keep track of the maximum prime found. If no primes are found, the answer remains 0.

Learn more about Math patterns.

Solution Approach

The solution uses a straightforward simulation approach with mathematical optimization for prime checking.

Prime Checking Function: The is_prime function implements an optimized primality test:

  • First, it handles the edge case where x < 2, returning False since numbers less than 2 are not prime
  • For numbers ≥ 2, it checks if any number from 2 to sqrt(x) divides x
  • The expression all(x % i for i in range(2, int(sqrt(x)) + 1)) returns True only if x is not divisible by any number in this range
  • This optimization reduces time complexity from O(n) to O(√n) for each prime check

Main Algorithm: The solution iterates through the matrix once:

  1. Initialize ans = 0 to store the maximum prime found
  2. Get the matrix dimension n = len(nums)
  3. For each row index i and corresponding row row:
    • Check the primary diagonal element row[i]:
      • If it's prime, update ans = max(ans, row[i])
    • Check the secondary diagonal element row[n - i - 1]:
      • If it's prime, update ans = max(ans, row[n - i - 1])

Time Complexity Analysis:

  • We visit each row once: O(n) iterations
  • For each row, we check at most 2 elements for primality
  • Each prime check takes O(√m) where m is the value being checked
  • Overall: O(n × √m) where m is the maximum value in the diagonals

Space Complexity:

  • The solution uses O(1) extra space, only storing the answer and loop variables
  • The is_prime function's range generator uses O(1) space due to lazy evaluation

The algorithm efficiently finds the answer in a single pass without storing diagonal elements separately, making it both time and space efficient.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with a concrete example to illustrate how the algorithm works.

Consider the following 4×4 matrix:

nums = [[11, 2,  3,  4],
        [5,  6,  7,  8],
        [9,  10, 11, 12],
        [13, 14, 15, 17]]

Step 1: Initialize variables

  • ans = 0 (to track the maximum prime)
  • n = 4 (matrix dimension)

Step 2: Process each row

Row 0 (i=0):

  • Primary diagonal element: nums[0][0] = 11
    • Check if 11 is prime: Test divisors from 2 to √11 ≈ 3
    • 11 % 2 = 1 (not divisible)
    • 11 % 3 = 2 (not divisible)
    • 11 is prime! Update ans = max(0, 11) = 11
  • Secondary diagonal element: nums[0][4-0-1] = nums[0][3] = 4
    • Check if 4 is prime: 4 % 2 = 0 (divisible by 2)
    • 4 is not prime, ans remains 11

Row 1 (i=1):

  • Primary diagonal element: nums[1][1] = 6
    • Check if 6 is prime: 6 % 2 = 0 (divisible by 2)
    • 6 is not prime, ans remains 11
  • Secondary diagonal element: nums[1][4-1-1] = nums[1][2] = 7
    • Check if 7 is prime: Test divisors from 2 to √7 ≈ 2
    • 7 % 2 = 1 (not divisible)
    • 7 is prime! Update ans = max(11, 7) = 11

Row 2 (i=2):

  • Primary diagonal element: nums[2][2] = 11
    • Check if 11 is prime: Yes (same check as before)
    • Update ans = max(11, 11) = 11
  • Secondary diagonal element: nums[2][4-2-1] = nums[2][1] = 10
    • Check if 10 is prime: 10 % 2 = 0 (divisible by 2)
    • 10 is not prime, ans remains 11

Row 3 (i=3):

  • Primary diagonal element: nums[3][3] = 17
    • Check if 17 is prime: Test divisors from 2 to √17 ≈ 4
    • 17 % 2 = 1, 17 % 3 = 2, 17 % 4 = 1 (not divisible by any)
    • 17 is prime! Update ans = max(11, 17) = 17
  • Secondary diagonal element: nums[3][4-3-1] = nums[3][0] = 13
    • Check if 13 is prime: Test divisors from 2 to √13 ≈ 3
    • 13 % 2 = 1, 13 % 3 = 1 (not divisible by any)
    • 13 is prime! Update ans = max(17, 13) = 17

Step 3: Return result The algorithm returns ans = 17, which is the largest prime number found on either diagonal.

Summary of diagonal elements checked:

  • Primary diagonal: [11, 6, 11, 17] → primes: [11, 11, 17]
  • Secondary diagonal: [4, 7, 10, 13] → primes: [7, 13]
  • Maximum prime found: 17

Solution Implementation

1from typing import List
2from math import sqrt
3
4class Solution:
5    def diagonalPrime(self, nums: List[List[int]]) -> int:
6        """
7        Find the largest prime number on the diagonals of a square matrix.
8      
9        Args:
10            nums: A square matrix of integers
11          
12        Returns:
13            The largest prime number found on either diagonal, or 0 if none exist
14        """
15      
16        def is_prime(num: int) -> bool:
17            """
18            Check if a number is prime.
19          
20            Args:
21                num: Integer to check for primality
22              
23            Returns:
24                True if the number is prime, False otherwise
25            """
26            # Numbers less than 2 are not prime
27            if num < 2:
28                return False
29          
30            # Check divisibility from 2 to sqrt(num)
31            # If num is divisible by any number in this range, it's not prime
32            for divisor in range(2, int(sqrt(num)) + 1):
33                if num % divisor == 0:
34                    return False
35          
36            return True
37      
38        # Get the dimension of the square matrix
39        n = len(nums)
40      
41        # Initialize the maximum prime found to 0
42        max_prime = 0
43      
44        # Iterate through each row of the matrix
45        for i in range(n):
46            # Check the main diagonal element (top-left to bottom-right)
47            main_diagonal_element = nums[i][i]
48            if is_prime(main_diagonal_element):
49                max_prime = max(max_prime, main_diagonal_element)
50          
51            # Check the anti-diagonal element (top-right to bottom-left)
52            anti_diagonal_element = nums[i][n - i - 1]
53            if is_prime(anti_diagonal_element):
54                max_prime = max(max_prime, anti_diagonal_element)
55      
56        return max_prime
57
1class Solution {
2    /**
3     * Finds the largest prime number on the diagonals of a square matrix.
4     * Checks both the main diagonal (top-left to bottom-right) and 
5     * the anti-diagonal (top-right to bottom-left).
6     * 
7     * @param nums The input square matrix
8     * @return The largest prime number found on the diagonals, or 0 if none exists
9     */
10    public int diagonalPrime(int[][] nums) {
11        int n = nums.length;
12        int maxPrime = 0;
13      
14        // Iterate through each row to check diagonal elements
15        for (int i = 0; i < n; i++) {
16            // Check main diagonal element at position (i, i)
17            if (isPrime(nums[i][i])) {
18                maxPrime = Math.max(maxPrime, nums[i][i]);
19            }
20          
21            // Check anti-diagonal element at position (i, n - i - 1)
22            if (isPrime(nums[i][n - i - 1])) {
23                maxPrime = Math.max(maxPrime, nums[i][n - i - 1]);
24            }
25        }
26      
27        return maxPrime;
28    }
29
30    /**
31     * Determines whether a given number is prime.
32     * A prime number is a natural number greater than 1 that has no positive divisors
33     * other than 1 and itself.
34     * 
35     * @param x The number to check for primality
36     * @return true if the number is prime, false otherwise
37     */
38    private boolean isPrime(int x) {
39        // Numbers less than 2 are not prime
40        if (x < 2) {
41            return false;
42        }
43      
44        // Check for divisors from 2 up to sqrt(x)
45        // Using i * i <= x condition to avoid computing square root
46        for (int i = 2; i * i <= x; i++) {
47            if (x % i == 0) {
48                return false;  // Found a divisor, not prime
49            }
50        }
51      
52        return true;  // No divisors found, number is prime
53    }
54}
55
1class Solution {
2public:
3    /**
4     * Find the largest prime number on the diagonals of a square matrix.
5     * @param nums - n x n matrix of integers
6     * @return The largest prime number found on either diagonal, or 0 if none exists
7     */
8    int diagonalPrime(vector<vector<int>>& nums) {
9        int matrixSize = nums.size();
10        int largestPrime = 0;
11      
12        // Iterate through each row to check both diagonals
13        for (int row = 0; row < matrixSize; ++row) {
14            // Check main diagonal element (top-left to bottom-right)
15            int mainDiagonalElement = nums[row][row];
16            if (isPrime(mainDiagonalElement)) {
17                largestPrime = max(largestPrime, mainDiagonalElement);
18            }
19          
20            // Check anti-diagonal element (top-right to bottom-left)
21            int antiDiagonalElement = nums[row][matrixSize - row - 1];
22            if (isPrime(antiDiagonalElement)) {
23                largestPrime = max(largestPrime, antiDiagonalElement);
24            }
25        }
26      
27        return largestPrime;
28    }
29
30private:
31    /**
32     * Check if a number is prime.
33     * @param number - The integer to check for primality
34     * @return true if the number is prime, false otherwise
35     */
36    bool isPrime(int number) {
37        // Numbers less than 2 are not prime
38        if (number < 2) {
39            return false;
40        }
41      
42        // Check for divisors up to sqrt(number)
43        // Using i <= number / i to avoid potential overflow with i * i
44        for (int divisor = 2; divisor <= number / divisor; ++divisor) {
45            if (number % divisor == 0) {
46                return false;  // Found a divisor, not prime
47            }
48        }
49      
50        return true;  // No divisors found, number is prime
51    }
52};
53
1/**
2 * Finds the maximum prime number on the diagonals of a square matrix
3 * @param nums - A square matrix of numbers
4 * @returns The largest prime number found on the main or anti-diagonal, or 0 if none exist
5 */
6function diagonalPrime(nums: number[][]): number {
7    const matrixSize: number = nums.length;
8    let maxPrime: number = 0;
9  
10    // Iterate through each row to check diagonal elements
11    for (let rowIndex = 0; rowIndex < matrixSize; rowIndex++) {
12        // Check main diagonal element (top-left to bottom-right)
13        const mainDiagonalElement: number = nums[rowIndex][rowIndex];
14        if (isPrime(mainDiagonalElement)) {
15            maxPrime = Math.max(maxPrime, mainDiagonalElement);
16        }
17      
18        // Check anti-diagonal element (top-right to bottom-left)
19        const antiDiagonalElement: number = nums[rowIndex][matrixSize - rowIndex - 1];
20        if (isPrime(antiDiagonalElement)) {
21            maxPrime = Math.max(maxPrime, antiDiagonalElement);
22        }
23    }
24  
25    return maxPrime;
26}
27
28/**
29 * Determines whether a given number is prime
30 * @param x - The number to check for primality
31 * @returns true if the number is prime, false otherwise
32 */
33function isPrime(x: number): boolean {
34    // Numbers less than 2 are not prime
35    if (x < 2) {
36        return false;
37    }
38  
39    // Check for divisors from 2 up to sqrt(x)
40    // Using x/i as the loop condition to avoid Math.sqrt calculation
41    for (let divisor = 2; divisor <= Math.floor(x / divisor); divisor++) {
42        if (x % divisor === 0) {
43            return false; // Found a divisor, not prime
44        }
45    }
46  
47    return true; // No divisors found, number is prime
48}
49

Time and Space Complexity

Time Complexity: O(n × √M)

The algorithm iterates through each row of the n×n matrix exactly once, giving us O(n) iterations. For each row, we check at most 2 diagonal elements (primary diagonal element at position [i][i] and anti-diagonal element at position [i][n-i-1]). For each diagonal element, we call the is_prime function.

The is_prime function has a time complexity of O(√x) where x is the value being checked. In the worst case, x can be as large as the maximum value M in the matrix. The function iterates from 2 to √x to check divisibility.

Therefore, the overall time complexity is O(n) iterations × O(√M) per prime check = O(n × √M).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space:

  • Variable n to store the matrix dimension
  • Variable ans to track the maximum prime found
  • Variable i for iteration
  • Variables within the is_prime function (parameter x and loop variable i)

No additional data structures that grow with input size are used, resulting in constant space complexity O(1).

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Counting the Center Element Twice in Odd-Sized Matrices

One of the most common mistakes is not recognizing that in odd-sized square matrices, the center element belongs to both diagonals. For example, in a 3×3 matrix, the element at position [1][1] is part of both the primary diagonal and the secondary diagonal.

The Issue: When iterating through the matrix, the code checks both nums[i][i] and nums[i][n-i-1]. For the middle row of an odd-sized matrix where i = n//2, both expressions point to the same element. While this doesn't affect correctness (we're looking for the maximum, so checking the same element twice doesn't change the result), it leads to unnecessary duplicate work.

Solution: Add a condition to skip the duplicate check:

for i in range(n):
    # Check main diagonal
    if is_prime(nums[i][i]):
        max_prime = max(max_prime, nums[i][i])
  
    # Check anti-diagonal only if it's not the same element
    if i != n - i - 1:  # Avoid checking center element twice
        if is_prime(nums[i][n - i - 1]):
            max_prime = max(max_prime, nums[i][n - i - 1])

2. Inefficient Prime Checking for Small Numbers

The is_prime function can be optimized for small numbers by handling special cases explicitly. Currently, it performs a loop even for numbers like 2 and 3, which are trivially prime.

Solution: Add early returns for small primes:

def is_prime(num: int) -> bool:
    if num < 2:
        return False
    if num == 2:
        return True
    if num % 2 == 0:  # Even numbers > 2 are not prime
        return False
  
    # Only check odd divisors starting from 3
    for divisor in range(3, int(sqrt(num)) + 1, 2):
        if num % divisor == 0:
            return False
    return True

3. Not Handling Edge Cases in Prime Checking

The current implementation handles negative numbers correctly (returns False for num < 2), but developers sometimes forget that 1 is not a prime number. Additionally, the square root calculation could theoretically cause issues with very large numbers due to floating-point precision.

Solution: Use integer arithmetic to avoid floating-point issues:

def is_prime(num: int) -> bool:
    if num < 2:
        return False
  
    divisor = 2
    while divisor * divisor <= num:  # Avoids sqrt calculation
        if num % divisor == 0:
            return False
        divisor += 1
    return True

4. Assuming Matrix is Always Non-Empty

While the problem states we have a square matrix, defensive programming suggests checking for empty matrices to avoid index errors.

Solution: Add a guard clause:

def diagonalPrime(self, nums: List[List[int]]) -> int:
    if not nums or not nums[0]:
        return 0
  
    n = len(nums)
    # ... rest of the code
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which algorithm should you use to find a node that is close to the root of the tree?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More