Task
You are given two non-empty arrays A and B consisting of N integers. These arrays represent N planks. More precisely, A[K] is the start and B[K] the end of the K−th plank.
Next, you are given a non-empty array C consisting of M integers. This array represents M nails. More precisely, C[I] is the position where you can hammer in the I−th nail.
We say that a plank (A[K], B[K]) is nailed if there exists a nail C[I] such that A[K] ≤ C[I] ≤ B[K].
The goal is to find the minimum number of nails that must be used until all the planks are nailed. In other words, you should find a value J such that all planks will be nailed after using only the first J nails. More precisely, for every plank (A[K], B[K]) such that 0 ≤ K < N, there should exist a nail C[I] such that I < J and A[K] ≤ C[I] ≤ B[K].
Write a function:
int solution(vector<int> &A, vector<int> &B, vector<int> &C);
that, given two non-empty arrays A and B consisting of N integers and a non-empty array C consisting of M integers, returns the minimum number of nails that, used sequentially, allow all the planks to be nailed.
If it is not possible to nail all the planks, the function should return −1.
Write an efficient algorithm for the following assumptions:
- N and M are integers within the range [1..30,000];
- each element of arrays A, B, C is an integer within the range [1..2*M];
- A[K] ≤ B[K].
Solution
int minNailIndex(int pos, int end,const vector<vector<int>> &minNails) {
int minIndex = __INT32_MAX__;
int step = 0x10000; //1 << 16;
for (int pow = 15; pow >= 0; pow–) {
step >>= 1;
if (pos + step <= end + 1) {
minIndex = min(minIndex, minNails[pow][pos]);
pos += step;
}
if(pos >= end+1) break;
}
return minIndex ;
}
int solution(vector<int> &A, vector<int> &B, vector<int> &C) {
size_t N = A.size();
assert(N == B.size());
size_t M = C.size();
vector<vector<int>> minNails(16); // 2^15 = 32K
// max M is 30000, values can be up to 2*M inclusive
for (int i = 0; i < 16; i++) {
minNails[i] = vector<int>(60001, __INT32_MAX__); // > max val
}
for (int i = 0; i < (int)M; i++) {
int nailPos = C[i];
minNails[0][nailPos] = min(minNails[0][nailPos], i);
}
int step = 1;
for (int pow = 1; pow < 16; pow++) {
for (int pos = 0; pos < (int)60001 – step; pos++) {
minNails[pow][pos] = min(minNails[pow – 1][pos], minNails[pow – 1][pos + step]);
}
step <<=1;
}
int minIndex = -2;
for (size_t i = 0; i < N; i++) {
int thisPlankMin = minNailIndex(A[i], B[i], minNails);
if(thisPlankMin == __INT32_MAX__) return -1;
minIndex = max(minIndex, thisPlankMin);
}
return minIndex + 1;
}
Results
Codility Results
Correctness | 100% |
Performance | 100% |
Reported Time Complexity | O((N + M) * log(M)) |
Test Function
This code tests the solution
int main() {
const int N = 30000;
vector<int> A(N);
vector<int> B(N);
vector<int> C(N);
for (size_t i = 0; i < N; i++) {
A[i] = 2*i+1;
B[i] = 60000;
C[i] = 2*i+1;
}
check(A,B,C,N);
check({1}, {4}, {4}, 1);
check({1, 4, 5, 8}, {4, 5, 9, 10}, {4, 6, 7, 10, 2}, 4);
check({1, 4}, {4, 5}, {4, 6, 7, 10, 2}, 1);
check({1, 4, 5}, {4, 5, 9}, {4, 6, 7, 10, 2}, 2);
check({1}, {4}, {5}, -1);
check({1000, 4000, 5000, 8000}, {4000, 5000, 9000, 10000}, {4000, 6000, 7000, 10000, 2000}, 4);
}
Other Solutions
O(N * (log(M)+M))
run time.O((N + M) * log(M))
but use less memory than my solution.