Hackerrank | Solution of Diagonal Difference in Golang
In this post we will solve the question diagonal difference from hackerrank in golang. We will learn how to create and use a 2-D matrix in Golang and how to traverse over it. Let's get started.
Problem Statement
The question can be found at this link. The problem statement states that we need to calculate the absolute difference of sum of elements of left and diagonal of a square matrix(a 2-D array whose rows and columns length are same).
Couple of things to note here is
- We need to take the size of the matrix as input
- In golang array length are fixed
- Logic to deduce if an element belongs to left, right or none of the diagonals
- Some way to calculate absolute difference
- we are solving this in golang (assuming you have either seen my previous posts or are comfortable with basics of golang. In case you need a refresher, refer to my older posts.)
Challenges
- Choose our preferred language as golang on hackerrank. The moment we do that, we get some 50-60 lines of code which are very unfamiliar to someone who is new to language.
- To solve the problem we need to know couple of things
- To declare a 2-D array
- To take inputs for the matrix
- Deduce the logic to determine if a given element belongs to left or right diagonal
- Doing the calculations required to get to our desired output
Solution
This is the template you get on hackerrank for this problem statement.
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
// Complete the diagonalDifference function below.
func diagonalDifference(arr [][]int32) int32 {
}
func main() {
reader := bufio.NewReaderSize(os.Stdin, 1024 * 1024)
stdout, err := os.Create(os.Getenv("OUTPUT_PATH"))
checkError(err)
defer stdout.Close()
writer := bufio.NewWriterSize(stdout, 1024 * 1024)
nTemp, err := strconv.ParseInt(readLine(reader), 10, 64)
checkError(err)
n := int32(nTemp)
var arr [][]int32
for i := 0; i < int(n); i++ {
arrRowTemp := strings.Split(readLine(reader), " ")
var arrRow []int32
for _, arrRowItem := range arrRowTemp {
arrItemTemp, err := strconv.ParseInt(arrRowItem, 10, 64)
checkError(err)
arrItem := int32(arrItemTemp)
arrRow = append(arrRow, arrItem)
}
if len(arrRow) != int(n) {
panic("Bad input")
}
arr = append(arr, arrRow)
}
result := diagonalDifference(arr)
fmt.Fprintf(writer, "%d\n", result)
writer.Flush()
}
func readLine(reader *bufio.Reader) string {
str, _, err := reader.ReadLine()
if err == io.EOF {
return ""
}
return strings.TrimRight(string(str), "\r\n")
}
func checkError(err error) {
if err != nil {
panic(err)
}
}
- First go ahead and delete everything in the pre-existing template.
- Replace it with the template that we have been following till now.
Now your code should look something like this
package main
import (
"fmt"
)
func main(){
}
First thing we need is to make sure is that we have a variable to take the matrix size as input. So let's declare a variable and take a input.
var n int
fmt.Scan(&n)
Now comes the interesting part.
Multi Dimensional Arrays in Golang
If you remember from our previous posts, we declared an array using var a [3]int
, so you must be thinking, that is good enough, we will declare a 2-D matrix using var a [n][n]int
right? WRONG!!! If you notice in the first case, the number inside the square brackets, is a constant, it's a number. The value of 3 won't change, it will always be 3. But in second case, we are giving the length n
, which is a variable. In golang the length of an array needs to be fixed, a constant. It cannot be a variable.
Now you must be thinking, let's go ahead and change var
to const
to make sure n
is a constant. That would have worked if we had assigned the value of n
while declaring it, but that is not the case. We need to take it as an input in the next line. Const
requires you to initialize your constants at the time of creation. So in simple terms we can't make n
a constant, and we can't use [][]
syntax here. Can we do something else? Yes, we will use make
to allocate memory for our array. Let's see how we can do this.
...
a := make([][]int, n)
In the above code snippet, we are creating a 2-D array a
of int
type, and stating that it will hold n
number of rows. We have just allocated the memory for n
rows, we still have to specify number of columns for each row and allocate memory for it. Somehow we need to loop over the number of rows, and for each row allocate n
columns of memory. So at this point of time it is pretty clear that , we are going to loop over the rows, now can we just create another inner loop to loop over columns, take each input and do our calculations? Yes we can, and that is exactly what we are going to do.
...
lsum,rsum := 0,0
for i:=0;i<n;i++{
a[i] = make([]int,n)
for j:=0;j<n;j++{
fmt.Scan(&a[i][j])
// calculate lsum here
// calculate rsum here
}
}
Okay, here we have a bunch of code, let's start exploring what they mean. On the first line, I am declaring and initializing two variables to store our left diagonal and right diagonal sum. Next we are looping over the number of rows and allocating memory for n
columns for each row of the matrix. Again we are using make
to allocate memory and are specifying that a[i]
will be an array of int
type of length n
. Next we are looping over the number of columns for each row. Now that we have successfully created our nested loops which would traverse over the matrix in the order that we want, we are ready to take inputs for each index. Next we are taking inputs for each index. Now we will write the logic to determine if the element belongs to left diagonal or right diagonal and add it to correct variable accordingly.
Left and Right Diagonals
Refer the picture below, and forgive me for my bad drawing, still learning how to use some of the drawing tools
The elements in green and brown are the elements that belong to left diagonal, while the element which are in yellow and brown belong to the right diagonal. Notice the indexing in the boxes, if you look the indexes for the left diagonal, both the row number and the column number are same. Here we got our first condition to determine if an element belongs to left diagonal. For the right diagonal, if you notice, the sum of the indexes are always 2
in our case, I want you to try it out for other higher order matrix, say 4*4 matrix. You'll notice that it always equal to size - 1
of matrix. Now we got both of our conditions to determine the elements of left and right diagonal. Let's replace the comments with original sum logic
...
if i==j {
lsum += a[i][j]
}
if i+j == n-1 {
rsum += a[i][j]
}
Now that we have our sum in place we need absolute difference of these two sums. To calculate absolute difference we need couple of things
math
package from golangAbs
function from packagemath
- The difference of
lsum
andrsum
infloat64
So we will use Abs
function from math
package to get absolute difference of lsum
and rsum
and Abs
function take float64
as argument, so we need some type casting on the original difference. Let's look at steps. We will add these after our nested for loops
...
diff := math.Abs(float64(lsum-rsum))
fmt.Println(diff)
Very simple steps here, we taking difference of lsum and rsum, we could have done it vice-versa too, since we need absolute value, the order doesn't matter. We are then type casting it to float64
and calling Abs
function . Then assigning the result to diff
and printing it. Now we are using a new library here math
, so we need to import it here. Change our import statement to
...
import(
"fmt"
"math"
)
...
Now that we have completed our code, the complete one should look like
package main
import (
"fmt"
"math"
)
func main(){
var n int
fmt.Scan(&n)
a := make([][]int, n)
lsum,rsum := 0,0
for i:=0;i<n;i++{
a[i] = make([]int,n)
for j:=0;j<n;j++{
fmt.Scan(&a[i][j])
if i == j {
lsum += a[i][j]
}
if i+j == n-1 {
rsum += a[i][j]
}
}
}
diff := math.Abs(float64(lsum - rsum))
fmt.Println(diff)
}
We learned a lot of good stuff in this one, and we are definitely making good progress on our hackerrank golang journey. That's it for this one. See you in the next one.
There you go guys, you made it to the end of the blog. Please check out the video below if you still have any doubts. Subscribe to my youtube channel and my mailing list below for regular updates. Follow me on twitter , drop me a mail or leave a comment here if you still have any doubts and I will try my best to help you out. Thanks
Stay tuned and see you around :)