HackerRank ‘Array Manipulation’ (Hard) Solution

Solved live by M. Kirschner in Sept 2018 ACiDS Meeting at NU

Originally in Reponse to D. Leschev’s Interview with ‘——‘ (ask Denis, AI company in Toronto/Montreal)

Prompt

Starting with a 1-indexed array of zeros and a list of operations, for each operation add a value to each of the array element between two given indices, inclusive. Once all operations have been performed, return the maximum value in your array.

For example, the length of your array of zeros $n=10$. Your list of queries is as follows:

    a b k
    1 5 3
    4 8 7
    6 9 1

Add the values of $k$ between the indices $a$ and $b$ inclusive:

 1 2 3  4  5 6 7 8 9 10  <---index
[0,0,0, 0, 0,0,0,0,0, 0]
[3,3,3, 3, 3,0,0,0,0, 0]
[3,3,3,10,10,7,7,7,0, 0]
[3,3,3,10,10,8,8,8,1, 0]

The largest value is 10 after all operations are performed.

Sample Input
5 3
1 2 100
2 5 100
3 4 100
Sample Output
200

Starting Wrapper

#!/bin/python3

import math
import os
import random
import re
import sys

def arrayManipulation(n, queries):
********CODE GOES HERE********

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    nm = input().split()

    n = int(nm[0])

    m = int(nm[1])

    queries = []

    for _ in range(m):
        queries.append(list(map(int, input().rstrip().split())))

    result = arrayManipulation(n, queries)

    fptr.write(str(result) + '\n')

    fptr.close()

Good Solution

def arrayManipulation(n, queries):
    arr = [0]*n
    for i in queries:
        for j in range(i[0], i[1] + 1):
            arr[j - 1] += i[2]
    return max(arr)

We loop over the rows in the query, and then sub-loop over the elements of the array than need summation. This approach works, but it will not pass (in an acceptable amount of time) the higher tests in when $n$ is very large e.g. the first line is 10000000 100000 ($n=10000000$ and # queries$=100000$).

Better Solution

def arrayManipulation(n, queries):
    arr = [0]*n
    for i in queries:
        arr[i[0] - 1] += i[2]
        arr[i[1]] -= i[2]
    maxval = 0
    itt = 0
    print(arr)
    for q in arr:
        itt += q
        if itt > maxval:
            maxval = itt
    return maxval

The insight here is that the sum only needs to be calculated for each step or fall in the array rather than every individual element. This is easier understand if you draw a picture, but ultimately it allows us to do a single loop for calculating the two steps in the array, and another for accounting for the maximum step height.

Best Solution

There still remains the edge-case where arr[i[1]] -= i[2] doesn’t work because if i[1] == len(arr), adding ‘fall’ to the ‘step’ is erroneous. So simply add in a conditional before arr[i[1]] -= i[2]

def arrayManipulation(n, queries):
    arr = [0]*n
    for i in queries:
        arr[i[0] - 1] += i[2]
        if i[1] != len(arr):
            arr[i[1]] -= i[2]
    maxval = 0
    itt = 0
    print(arr)
    for q in arr:
        itt += q
        if itt > maxval:
            maxval = itt
    return maxval