Array Manipulation : HackerRank Questions : JAVA

不羁岁月 提交于 2019-12-06 08:57:13

First of all, in case you don't realize it, Terminated due to timeout is not a compilation error, it means that your implementation is too slow. The challenge is not to implement any correct solution to the problem. The solution must also be efficient. Since your solution is inefficient, it fails for large inputs due to being too slow.

Since the number of queries seems to be 2 orders of magnitude smaller than the length of the array (100K vs. 10M in the 3 test cases you posted), it would be more efficient to work just with the queries instead of actually updating the array.

I'm not going to give you an implementation, but I'll suggest an algorithm that should be more efficient than your current implementation.

I suggest you process the queries as follows:

  1. Add the first query to a list of processed queries, which will contain queries with disjoint sub-array ranges. This list will be sorted by the first array index (you will keep it sorted by adding new elements in the proper position).

  2. For each query not processed yet, find all the processed queries that overlap it (you can do it using binary search to improve performence).

    • Split the current query in a way that the resulting queries will each be either fully contained in an existing processed query or not contained in each existing processed query.

    • For each of the queries created in the split:

      • if their range is equal to the range of an existing processed query, add the value of the query to the processed query.
      • If their range is not contained in any existing processed query, add that query as a new processed query.
      • If their range is partially contained in an existing processed query, split the processed query.

I'm not sure if my explanation is clear enough. I'll show an example with the

1 5 3
4 8 7
6 9 1

input:

Add 1 5 3 to the list of processed queries.

Process 4 8 7: There is one processed query the overlaps it - 1 5 3.

Split 4 8 7 into two sub-queries : 4 5 7 and 6 8 7.

4 5 7 is contained in 1 5 3, so split 1 5 3 into 1 3 3 and 4 5 3+7

6 8 7 is not contained in any processed queries, so add it as is.

Now the processed queries are:

1 3 3
4 5 10
6 8 7

Process 6 9 1: There is one processed query that overlaps it: 6 8 7.

Split 6 9 1 into two sub queries : 6 8 1 and 9 9 1.

6 8 1 has the same range a 6 8 7, which will become 6 8 7+1

9 9 1 is not contained in any processed queries, so add it as is.

Now the processed queries are:

1 3 3
4 5 10
6 8 8
9 9 1

As you process the queries you keep track of the max processed query value, so after you process all the queries you know that the max value is 10.

Brute-force solution is not going to work here due to the given time constraint. That is the reason you will get the time out error.

So you need to optimize your code which can be done with the help of prefix sum array.

instead of adding k to all the elements within a range from a to b in an array, accumulate the difference array

Whenever we add anything at any index into an array and apply prefix sum algorithm the same element will be added to every element till the end of the array.

ex- n=5, m=1, a=2 b=5 k=5

    i     0.....1.....2.....3.....4.....5.....6   //take array of size N+2 to avoid index out of bound
  A[i]    0     0     0     0     0     0     0

Add k=5 to at a=2

A[a]=A[a]+k // start index from where k element should be added

     i    0.....1.....2.....3.....4.....5.....6 
   A[i]   0     0     5     0     0     0     0

now apply prefix sum algorithm

     i    0.....1.....2.....3.....4.....5.....6 
  A[i]    0     0     5     5     5     5     5

so you can see K=5 add to all the element till the end after applying prefix sum but we don't have to add k till the end. so to negate this effect we have to add -K also after b+1 index so that only from [a,b] range only will have K element addition effect.

A[b+1]=A[b]-k // to remove the effect of previously added k element after bth index. that's why adding -k in the initial array along with +k.

    i    0.....1.....2.....3.....4.....5.....6 
  A[i]   0     0     5     0     0     0    -5

Now apply prefix sum Array

    i    0.....1.....2.....3.....4.....5.....6 
  A[i]   0     0     5     5     5     5     0

You can see now K=5 got added from a=2 to b=5 which was expected. Here we are only updating two indices for every query so complexity will be O(1).

Now apply the same algorithm in the input

         # 0.....1.....2.....3.....4.....5.....6    //taken array of size N+2 to avoid index out of bound
5 3      # 0     0     0     0     0     0     0
1 2 100  # 0    100    0   -100    0     0     0       
2 5 100  # 0    100   100  -100    0     0   -100
3 4 100  # 0    100   100    0     0  -100   -100

To calculate the max prefix sum, accumulate the difference array to 𝑁 while taking the maximum accumulated prefix.

After performing all the operation now apply prefix sum Array

    i      0.....1.....2.....3.....4.....5.....6 
  A[i]     0     100   200  200   200   100    0

Now you can traverse this array to find max which is 200. traversing the array will take O(N) time and updating the two indices for each query will take O(1)* number of queries(m)

overall complexity=O(N)+O(M) = O(N+M)

it means = (10^7+10^5) which is less than 10^8 (per second)

Note: If searching for video tutorial , you must check it out here for detailed explanation.

import java.io.*;
import java.util.InputMismatchException;
import java.util.Random;

public class Solution {
    public static void main(String[] args) {

        InputStream inputStream = System.in;
        InputReader in = new InputReader(inputStream);

        int n = in.readInt();
        int m = in.readInt();

        long[] list = new long[n+3];

        while(m-- > 0) {
            int a = in.readInt();
            int b = in.readInt();
            long k = in.readLong();

            list[a] += k;
            list[b+1] -= k;
        }

        long max = 0;
        long c = 0;
        for (int i = 1; i <= n; i++) {
            c += list[i];
            max = Math.max(max, c);
        }
        System.out.println(max);
    }
}

class InputReader {

    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar;
    private int numChars;
    private SpaceCharFilter filter;

    public InputReader(InputStream stream) {
        this.stream = stream;
    }

    public int read() {
        if (numChars == -1)
            throw new InputMismatchException();
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar++];
    }

    public int peek() {
        if (numChars == -1)
            return -1;
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                return -1;
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar];
    }

    public int readInt() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        int sgn = 1;
        if (c == '-') {
            sgn = -1;
            c = read();
        }
        int res = 0;
        do {
            if (c < '0' || c > '9')
                throw new InputMismatchException();
            res *= 10;
            res += c - '0';
            c = read();
        } while (!isSpaceChar(c));
        return res * sgn;
    }

    public long readLong() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        int sgn = 1;
        if (c == '-') {
            sgn = -1;
            c = read();
        }
        long res = 0;
        do {
            if (c < '0' || c > '9')
                throw new InputMismatchException();
            res *= 10;
            res += c - '0';
            c = read();
        } while (!isSpaceChar(c));
        return res * sgn;
    }

    public boolean isSpaceChar(int c) {
        if (filter != null)
            return filter.isSpaceChar(c);
        return isWhitespace(c);
    }

    public static boolean isWhitespace(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public boolean isExhausted() {
        int value;
        while (isSpaceChar(value = peek()) && value != -1)
            read();
        return value == -1;
    }

    public interface SpaceCharFilter {
        public boolean isSpaceChar(int ch);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!