0
votes

HackerRank Diagonal Difference Problem.

Print the absolute difference between the sums of the matrix's two diagonals as a single integer.

Link to problem: https://www.hackerrank.com/challenges/diagonal-difference/problem

I have been trying for hours to solve this problem in Ruby. I happened upon an answer that someone else figured out.

I am now please asking for help in understanding how this method works. I want to understand what it is doing. I am confused by the entirety of the loop.

a.each_with_index do |array, index|
  left_right += array[index]
  right_left += array[-index-1]

Could someone please explain step-by-step what is happening in this block of code so I can learn and better understand Ruby? Thank you.

def diagonalDifference(a)
  left_right=0
  right_left=0
  a.each_with_index do |array, index|
    left_right += array[index]
    right_left += array[-index-1]
  end
  v = right_left - left_right
  return v.abs
end
4
Plug [[1,2],[3,4]] into diagonalDifference and follow the steps. If you don't know how each_with_index works then have a look at the documentation. - Sagar Pandya

4 Answers

4
votes

The main skew diagonal (or main secondary diagonal) of a nxn matrix a is comprised of the elements a[n-1][0], a[n-2][1],..., a[1][n-2], a[0][n-1]].

Part of the problem is that the variables have not been given descriptive names. I would write that as follows.

def diagonal_difference(arr)
  main_diagonal_sum=0
  main_skew_diagonal_sum=0
  arr.each_with_index do |row, i|
    main_diagonal_sum += row[i]
    main_skew_diagonal_sum += row[-i-1]
  end
  (main_diagonal_sum - main_skew_diagonal_sum).abs
end

I expect row[-i-1] might be the most confusing part of the code. Suppose i = 0, then row[-0-1] #=> row[-1], which is the last element of row. When i = 1, row[-1-1] #=> row[-2], which is the next-to-last element of row, and so on. That could instead be written row[row.size-i-1].

Note return is not needed if, as here, the return value of the last statement executed (before the method returns) is to be returned by the method.

Let's add some puts statements in the method and work through an example.

def diagonal_difference(arr)
  puts "arr=#{arr}"
  main_diagonal_sum=0
  main_skew_diagonal_sum=0
  arr.each_with_index do |row, i|
    puts "row=#{row}, i=#{i}"
    main_diagonal_sum += row[i]
    puts "  row[#{i}]=#{row[i]}, main_diagonal_sum=#{main_diagonal_sum}"
    main_skew_diagonal_sum += row[-i-1]
    puts "  row[-#{i}-1]=#{row[-i-1]}, main_skew_diagonal_sum=#{main_skew_diagonal_sum}"
  end
  (main_diagonal_sum - main_skew_diagonal_sum).abs
end

arr = [[1,2,3],
       [4,5,6],
       [9,8,7]]

The main diagonal sum is 1+5+7 #=> 13 and the main skew diagonal sum is 3+5+9 #=> 17, so we expect the method to return (13-17).abs #=> 4.

diagonal_difference(arr)
  #=> 4

prints the following.

arr=[[1, 2, 3], [4, 5, 6], [9, 8, 7]]
row=[1, 2, 3], i=0
  row[0]=1, main_diagonal_sum=1
  row[-0-1]=3, main_skew_diagonal_sum=3
row=[4, 5, 6], i=1
  row[1]=5, main_diagonal_sum=6
  row[-1-1]=5, main_skew_diagonal_sum=8
row=[9, 8, 7], i=2
  row[2]=7, main_diagonal_sum=13
  row[-2-1]=9, main_skew_diagonal_sum=17
2
votes

See following

11 2 4
4 5 6
10 8 -12
So, a = [ [11, 2, 4], [4, 5, 6], [10, 8, -12] ]

Now ref each_with_index method for a.each_with_index do |array, index|. during first iteration array will be [11, 2, 4] & index will be 0. array[0] = 11 & array[-0-1] i.e. array[-1] = 4 Similarly for second iteration array[1] = 5 & array[-1-1] i.e. array[-2] = 5& so on.

You'll get

2.3.1 :360 > left_right # 11 + 5 - 12
 => 4 
2.3.1 :361 > right_left # 4 + 5 + 10
 => 19 
2.3.1 :362 > v = right_left - left_right
 => 15 

v.abs is used to return absolute difference in case v is negative, Ref abs method of Numeric class.

Note:- return keyword is optional if it is the last non comment line in a method.

2
votes

You can use the Matrix library as proposed in this answer.

require 'matrix'
(Matrix[*arr].tr - Matrix[*arr.reverse].tr).abs

Where arr is an array of depth 2 with length n and each sub-array is also of length n e.g. [[a,b],[c,d]].

1
votes

Sidenote: NB I am posting this as an answer, not a comment, for the sake of formatting; it should not be upvoted.

The more ruby idiomatic version of the snippet you have posted would be:

def diagonal_difference(a)
  a.each.with_object([0, 0]).with_index do |(e, left_right), idx|
    left_right[0] += array[idx]
    right_left[1] += array[-idx-1]
  end.reduce(:-).abs
end