• + 67 comments

    Java solution - passes 100% of test cases

    From my HackerRank solutions.

    Runtime: O(n + m)
    Space Complexity: O(n)

    Make sure to use long instead of int to avoid integer overflow.

    Don't update all values in your array. Just update the interval's endpoint values as shown below.

    import java.util.Scanner;
    
    public class Solution {
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
            int N = scan.nextInt();
            int M = scan.nextInt();
            
            /* Save interval endpoint's "k" values in array */
            long [] array = new long[N + 1];
            while (M-- > 0) {
                int a = scan.nextInt();
                int b = scan.nextInt();
                int k = scan.nextInt();
                array[a-1] += k;
                array[b]   -= k;
            }
            scan.close();
            
            /* Find max value */
            long sum = 0;
            long max = 0;
            for (int i = 0; i < N; i++) {
                sum += array[i];
                max = Math.max(max, sum);
            }
            
            System.out.println(max);
        }
    }
    

    For each of the "m" operations, we do not want to take O(n) time to process it. That's because our runtime will end up being O(nm). To get a O(n+m) runtime, we have to process each operation in O(1) time. To do so, we keep track of just the endpoints, which are just 2 numbers, instead of the O(n) numbers in between the endpoints. This is the main idea to decrease our runtime.

    For a value k, we can mark its left endpoint a in the original array, along with its right endpoint b in the original array. To distinguish between a and b we can store +k for a and -k for b. Now, we technically have stored all information that the m operations represent, into an array. Most importantly, we stored it in O(m) time.

    The next step is to actually find the maximum value based off of our unique representation of the data. We traverse our array from left to right. Whenever we reach a left endpoint a (which we represented with a positive number), we just add that to our sum. Whenever we reach a right endpoint b (which we represented with a negative number), we subtract that from our sum (well, technically we add a negative value). By doing so, the value sum represents the value that array[i] would have if we had applied all m operations to it. The maximum value of sum that we get while traversing the array is the value we return. If this algorithm is still unclear to you, try walking through HackerRank's Testcase 0 with the code above.


    Let's try an example

    Let's try to walk through an example. If we have 1 query and it wants to add 100 to elements 2 through 4 inclusive in a 7-element array, we want to have:

    [0, 0, 100, 100, 100, 0, 0]
    

    The idea is that we can represent this initially as:

    [0, 0, 100, 0, 0, -100, 0]
    

    It's important to realize that this above array is not our final answer. We will walk through the array from array[0] to array[6] to create our final answer. When we reach array[2], it basically tells us that every element from here and to the right of it (array[2] to array[6]) should have 100 added to them. When we reach array[5], it tells us the same thing, except that every element should have -100 added to it. By following these 2 rules, we get

    array[0] = 0;
    array[1] = 0;
    array[2] = 0 + 100 = 100;
    array[3] = 0 + 100 = 100;
    array[4] = 0 + 100 = 100;
    array[5] = 0 + 100 - 100 = 0;
    array[5] = 0 + 100 - 100 = 0;
    

    giving us the final array of

    [0, 0, 100, 100, 100, 0, 0]
    

    I hope this helps. It was challenging for me to explain.

    Let me know if you have any questions.

    • + 3 comments

      Could you explain why this works?

      • + 3 comments

        Hi. I added a detailed answer to your question in my original post. Hopefully it helps, it was tough to explain.

        HackerRank solutions.

        • + 0 comments

          Awesome that definitely helped a lot! Thank you so much! :D

        • + 2 comments

          you are a great thinker rshaghoulian sir....Proud of you how to think like you... guide me

          • + 2 comments

            Hi. Thank you. Just keep coding and solving problems on HackerRank and you will steadily improve. Being active on the discussion forums is also a great learning experience. Best of luck.

            • + 0 comments

              I know this is kinda late, but holy, that is some genius work right here.

            • + 0 comments

              Lots of thanks for spending sooo much time and efforts to help us!

          • + 0 comments

            His thinking is his own skill/achievement, Why you are proud of him or his achievement???

        • [deleted]
          + 1 comment

          Thanks for the amazing explanation!

      • + 4 comments

        You can watch this video : https://youtu.be/JtJKn_c9lB4 Really short video of 7 mins and explained awesome

        • + 0 comments

          Thanks for it : )

        • + 0 comments

          Thanks for the vid, this helped me greatly!

        • + 0 comments

          Thanks ! If only all lthe explanations above said these words , "cumulative Slope algorithm works, when we add the value K only to the starting index(and assume it is being added until the end), but the Qs wants us to add only until till a index B, Therefore to stop the continous assumtion of adding K even after index B, we must put the index b+1 as -K. Thus from the working of our algorithm all the places form b+1 to end(inclusive) will be summed as (+K )+(-K), this way every new queries have to be started from their A index and ended at B by -K at B+ 1 , Now whe we cumulative add upto each index and replace it with the sum we get the previos ans array which we were getting from brute force "

    • + 2 comments

      why we are subtracting k at b interval? why you are subtracting k to a[b] not a[b-1]?

      • + 2 comments

        Hi. As for why we subtract k, I just added a detailed example to help answer your question in my original post.

        Regarding the exact values of a and b, it's a little tricky since a and b are 1-indexed but our array is 0-indexed. So we want to subtract 1 from both a and b. However, for b we re-add 1 because we want to change values from a to b inclusive as stated in the problem, so we want the end of the interval to be 1 to the right of b which is why we re-add the 1.

        Hope this helps.

        HackerRank solutions.

        • + 1 comment
          [deleted]
          • + 1 comment

            can u guyz tell me whats wrong in my code?

            long arrayManipulation(int n, vector> queries) {

            long int arr[n+1];
            memset(arr,0,sizeof(arr));
            long int m = queries.size();
            long int max = 0;
            long int sum = 0;
            for(int i=0;i<m;i++)
            {
                long int a = queries[i][0];
                long int b = queries[i][1];
                long int k = queries[i][2];
            
                arr[a-1] += k;
                arr[b] -= k;
            }
            for(int x=0;x<n;x++)
            {
                sum += arr[x];
                if(max < sum)
                    max = sum;
            }
            return max;
            

            }

            • + 2 comments

              Addition needs to be done at a and subtraction at b+1. Also,avoid memset on hackerrank sometimes it doesn't work fine. Lastly,the final loop would run till <=n.

              • + 0 comments

                actually this code works fine in 1st 3 test cases... and my code is for 0-indexed that is why I used a-1 and b does it wrong?

    • + 5 comments

      Same algorithm in python3

      from sys import stdin
      
      if __name__ == '__main__':
          (N, M) = [int(i) for i in stdin.readline().split()]
      
          vals = [0] * N
      
          for i in range(M):
              (a, b, k) = [int(i) for i in stdin.readline().split()]
              vals[a-1] += k
              try:
                  vals[b] -= k
              except:
                  # out of range of list (at the end)
                  pass
      
          prev = 0
          for i in range(len(vals)):
              prev += vals[i]
              vals[i] = prev
      
          print(max(vals))
      

      Small difference is that the array is not N+1 long, but handle out of range via catching the exception.

      • + 0 comments

        of course,

        prev = 0
        max_val = 0
        for i in range(len(vals)):
            prev += vals[i]
            vals[i] = prev
            if prev > max_val:
            	max_val = prev
                
        print(max_val)
        

        Should be faster by a constant factor.

      • + 2 comments
        • vals[b] -= k* please explain this line.why your are subtracting
        • + 0 comments

          The substraction is because at the end when are adding the values in vals array together, we shall add "k" to all values in val between "a" and "b", knowing when to stop adding "k" is impossible so we just add k upto the end of the list but subtract it starting from "b"

      • + 1 comment
        [deleted]
      • + 0 comments

        This code still gives me a time error

      • + 0 comments

        This is giving "Runtime Error" in some test cases (when the input is big).

    • + 1 comment

      Same solution in Swift 3:

      import Foundation
      
      var nAndMArr: [Int] = readLine()!.components(separatedBy: " ").map { Int($0)! }
      
      let n = nAndMArr[0]
      let m = nAndMArr[1]
      
      var arr: [Int64] = Array(repeating: 0, count: n + 1)
      
      for x in 1...m {
          let aBKArr = readLine()!.components(separatedBy: " ").map{ Int($0)! }
          let a: Int = aBKArr[0]
          let b: Int = aBKArr[1]
          let k: Int = aBKArr[2]
          
          arr[a-1] += k
          arr[b] -= k
      }
      
      var sum: Int64 = 0
      var maximum: Int64 = 0
      
      for y in 0..<n {
          sum += arr[y]
          maximum = max(sum, maximum)
      }
      
      print(maximum)
      
      • + 0 comments

        Updated version:

        var arr = Array(repeating: 0, count: n+1)
        
        for query in queries {
            let a = query[0] - 1
            let b = query[1]
            let k = query[2]
        
            arr[a] += k
            arr[b] -= k
        }
        
        var largestValue = Int.min
        var sum = 0
        for n in arr {
            sum += n
            largestValue = max(sum, largestValue)
        }
        
        return largestValue
        
    • + 0 comments

      Cool, representing the array in unique way reduced O(mn) to just O(m+n). The explanation was good. Keep sharing knowledge, thanks !!

    • + 0 comments

      Thank you for the description, skipped right past the code.

    • + 0 comments

      Thanks man.. its ExtraOrdinary!!.. thanks again

    • + 0 comments

      thats a nice explaination...

    • + 0 comments

      awesome explanation,thank you

    • + 0 comments

      absolutely awesome explanation,thank you

    • + 1 comment

      can u tell me why u have taken size of array n+1

      • + 1 comment

        I have written array[b] in the code. Since b can have a maximum value of N (according to the problem description), we must have N+1 elements so that array[b] = array[N] does not crash the program.

        HackerRank solutions.

        • + 0 comments

          thanq.... i got it..:)

    • + 0 comments

      Wow! I am so glad I found this explanation. Banging my head against this since a long time. Thanks a lot for taking out the time to add this explanation.:)

    • + 1 comment

      Disclaimer: Please correct me if i am wrong, I am just trying to provide a different explanation in the way that it clicked into my head while viewing your solution.

      First Loop, Pt 1

      I am first going to start off with why the indexes are chosen the way they are. This will lead into the next part of the same loop.         
      
      Ok, the first part is array[a - 1], Because the "indexes" given to us in the problem are actually the index + 1,which is something calles 1-indexed, which means the array its based off starts at 1, to stay true to the inclusive rule told to us in the problem, we must start at the beginning index.       
      
      We stop at array[b-1] beacuse, like the lat one, the var b given is not a accurate index so we must subtract one from it to get the starting point. To describe when to stop the set (more on this in a second), we need to put the -k one past the index where the k is being applied. Remebering that b is not a true index, we do array[(b-1) + 1]. The b - 1 gives us the true index of the end of the subarray that k is being applied to. But simplifying it gives us b as the index we need to use.
      

      First Loop, Pt 2 and Second Loop

      This part of the loop, in my opinion, is the hardest to understand. The start of the subarray is array[a - 1], which was explained up top. This marks where, in the second loop, sum will add that value to itself. Ex. 0,0,100,0,0,-100,0. This is an example of 1 query array implented in the way shown in the above solutuon. Think of of sum as a way to temporarily view what the index would look like at that period in time and adding numbers to starts this. For example, when the second loop hits the index with 100, sum, until it hits the -100, will be 100. Imagine the zeroes are basically saying "No other modifiers here like another set being in this set or an end of another set in the middle of this set". The -k at b is very interesting. The solution above says its a marker but it serves to strip the sum in the second loop of k. This is saying that because the loop has ended, we need a way to make the next indexes reflect that it has ended and remove k from the ongoing sum. The combination of multiple implmentations of this will allow the array to take full shape. We then find the max based on these multiple implmentations. It can be like the index viewed could be 500 but if you were to break it apart it could actually be (300 + -100 + 300). Which could mean many diffrent things, the 300s could repersent the start of diffrent sub lists and the -100 repsersents the end of another list. They all come together to repersent a mean. Adding this to a sum allows to find a max which will give us our answer.         
      

      Conclusion
      So, in conclusion, the solution handles the array like diffrent points in time and adding up these points allows us to find a max.

      • + 0 comments

        Perfect explanation! Thanks buddy!

    • + 0 comments

      Nice Explaination.Good Approch.Thanks dude.

    • + 0 comments

      Thanks - today is my second day here in hackerrank and I totally did not expect such a problem and nimble sulution.

      Mind=blown

    • + 0 comments

      That is amazing! Incredible logic! Thanks! ^_^

    • + 0 comments

      ITs very inciteful THANK YOU

    • + 0 comments

      Wow man!! Thank you so much!!

    • + 0 comments

      Awesome!

    • + 1 comment

      Great job! If you don't mind answering, roughly how long did it take you to think of this solution initially?

      • + 1 comment

        I didn't come up with this solution. I think I was told the solution, and I coded it myself.

        HackerRank solutions.

        • + 0 comments

          I appreciate your honesty here Rodney, it makes me feel a little less inadequte! Your solution is beautiful either way.

    • + 0 comments

      thanks for the explaination :D

    • + 0 comments

      Good idea, I have just copied your idea too :) Thanks!

    • + 0 comments

      Your example showing how the expected array can be derived from the range-based array is a perfect explanation. Thank you!

    • + 1 comment

      @RodneyShag Finally understood the logic. Thanks a lot

      • + 0 comments

        Glad to hear. Glad I could help.

    • + 0 comments

      Amazing explaination.Thanks.

    • + 1 comment

      great solution. thank you.

      Same algorithm on C++ // Complete the arrayManipulation function below. long arrayManipulation(int n, vector> queries) {

      vector<long> v(n, 0);
      for(vector<int> q: queries)
      {
          v[q[0]-1] += q[2];
          v[q[1]] -= q[2];
      }
      long max = 0;
      long sum = 0;
      for(long l: v)
      {
          sum += l;
          if(max < sum)
          {
              max = sum;
          }
      }
      
      return max;
      

      }

      • + 0 comments

        This code has a little bug. This is the code fixed:

        long arrayManipulation(int n, vector> queries) {
          vector<long> v(n, 0);
          for(vector<int> q: queries)
          {
            v[q[0]-1] += q[2];
            if (q[1] < v.size()) v[q[1]] -= q[2];
          }
        
          long max = 0;
          long sum = 0;
        
          for(long l: v)
          {
            sum += l;
            if(max < sum)
            {
                max = sum;
            }
          }
        
          return max;
        }
        
    • + 0 comments

      Great solution. Very interesting to see how you can use edges to your advantage on these problems that deal with uniformly changing segments of arrays at a time. Saves time and helps with analysis. Incredible.

    • + 0 comments

      extra array[5] = 0 + 100 - 100 = 0; is a typo?

    • + 0 comments

      Got stuck with bad runtime O(nm), but didn't want to spend much time figuring it out on my own.

      Then I saw your explanation.

      You did a nice job explaining.

      The example helped, too.

    • + 0 comments

      great idea!

    • + 0 comments

      Awesome work! Thanks for your explanation :)

    • + 0 comments

      impressive solution

    • + 0 comments

      In the original code, " sum +=array[i] " adds up all the elements in the array at the end ...could you please tell me at what point we get the as 200 for " max "..??

    • + 0 comments

      Nicely explained! Thanks.

    • + 0 comments

      Absolutely brilliant!

    • + 0 comments

      This explanation should be at the top. Was having a hard time wrapping my head around the solution till I read this explanation.

    • + 0 comments

      Brilliant job explaining! thanks

    • + 0 comments

      Very clever

    • + 0 comments

      great :)

    • + 0 comments

      Good explaination. Finally I got it. Thank you.

    • + 0 comments

      Thank you! your explanation was very clear to me.

    • + 0 comments

      this is very clear, thank you!

    • + 0 comments

      Really good explaination and example. Thanks!

    • + 0 comments

      Similar solution in C#:

      static long ArrayManipulation(int n, int[][] queries) {    
          var additions = new long[n + 1];
          foreach (var query in queries) {
              var start = query[0];
              var end = query[1];
              var valueToAdd = query[2];
              additions[start] += valueToAdd;
              if (end + 1 < additions.Length)
                  additions[end + 1] -= valueToAdd;            
          }        
          long sum = 0;
          long max = 0;
          for (var x = 1; x < additions.Length; x ++) {
              sum += additions[x];
              max = sum > max ? sum : max;
          }
          return max;
      }
      
    • + 0 comments

      what is the issue if i just traverse from assuming j= a to b and modify array[j] by array[j]+=k more efficient isn't it!!?

    • + 0 comments

      Brilliant!!! It took me hours to solve but some failed due to timeout and next hours to read some hints in the discussion. I was stuck until I saw your explaination. Thanks.

    • + 0 comments

      Great solution

    • + 0 comments

      was breakin my head as to how this solution works. thank you for the detailed explanation ... especially the code walkthrough

    • + 0 comments

      Very good explanation

    • + 0 comments

      Great Explanation! Thanks :)

    • + 0 comments

      Great explanation, thank you very much! That was an amazing approach

    • + 0 comments

      works perfectly. Thanks

    • + 0 comments

      you are genius , thank you

    • + 0 comments

      Thanks for the tip about using long, debugged that issue for a while.

    • + 0 comments

      mam I do this challenges in c# and could understand that C# and java are not different. i am not able to get to all the test cases passed somehow. are you sure it is working 100%? just want to understand in my IDE first so that i can get some idea

    • + 0 comments

      thanks for explaining

    • + 0 comments

      Hi, thanks for the wonderful explanation. Can you please check where I am wrong in this java code which I feel is similar to the one you posted.

      public static long arrayManipulation(int n, List> queries) {

          long[] baseArr = new long[n+1];
          long maxSum = 0;
          if(queries == null || queries.size() ==0){
              return 0;
          }
          for(List<Integer> query : queries){
              int start = query.get(0)-1;
              int end = query.get(1) - 1;
              baseArr[start]+= query.get(2);
              baseArr[end+1]-= query.get(2);
          }
          int sum=0;
          for(long item : baseArr){
              sum+=item;
              maxSum = Math.max(sum,maxSum);
          }
          return maxSum;
      }
      
    • + 0 comments

      Great explanation. Took me a few minutes to grab it but it's really impressive.

    • + 0 comments

      Thanks for providing such a good explanation. The code snippets help, but I definitely get more from you examples and explanations in the discussions. It was an easy translation from Java to C++ :)

    • + 0 comments

      Thanks, It made me to think with a different POV to solve in Python

      def arrayManipulation(n, queries):

      res = [0]*(n+1)
      for q in queries:
          res[q[0]-1] += q[2]
          res[q[1]] -= q[2]
      s = 0
      m = 0
      for l in res:
          s += l
          m = max(m,s)  
      
      return m
      
    • + 0 comments

      i'm impressed with this solution.)) brilliant

    • + 0 comments

      good