codility:peaks: what's wrong with go implementation on performance parts testing? - algorithm

Divide an array into the maximum number of same-sized blocks, each of which should contain an index P such that A[P - 1] < A[P] > A[P + 1].
My Solution: golang solution
However partly performance testing fails without reason, anyone can add some suggestion?
func Solution(A []int) int {
peaks := make([]int, 0)
for i := 1; i < len(A)-1; i++ {
if A[i] > A[i-1] && A[i] > A[i+1] {
peaks = append(peaks, i)
}
}
if len(peaks) <= 0 {
return 0
}
maxBlocks := 0
// we only loop through the possible block sizes which are less than
// the size of peaks, in other words, we have to ensure at least one
// peak inside each block
for i := 1; i <= len(peaks); i++ {
// if i is not the divisor of len(A), which means the A is not
// able to be equally divided, we ignore them;
if len(A)%i != 0 {
continue
}
// we got the block size
di := len(A) / i
peakState := 0
k := 0
// this loop is for verifying whether each block has at least one
// peak by checking the peak is inside A[k]~A[2k]-1
// if current peak is not valid, we step down the next peak until
// valid, then we move to the next block for finding valid peak;
// once all the peaks are consumed, we can verify whether all the
// blocks are valid with peak inside by checking the k value,
// if k reaches the
// final state, we can make sure that this solution is acceptable
for {
if peakState > len(peaks)-1 {
break
}
if k >= i {
break
}
if peaks[peakState] >= di*k && peaks[peakState] <= di*(k+1)-1 {
peakState++
} else {
k++
}
}
// if all peaks are checked truly inside the block, we can make
// sure this divide solution is acceptable and record it in the
// global max block size
if k == i-1 && peakState == len(peaks) {
maxBlocks = i
}
}
return maxBlocks
}

Thanks for adding more comments to your code. The idea seems to make sense. If the judge is reporting a wrong answer, I would try it with random data and some edge cases and a brute-force control to see if you can catch a failing example that's reasonably sized, and analyse what is wrong.
My own thought about a possible approach so far was to record a prefix array so as to tell in O(1) if a block has a peak. Add 1 if the element is a peak, 0 otherwise. For input,
1, 2, 3, 4, 3, 4, 1, 2, 3, 4, 6, 2
we would have:
1, 2, 3, 4, 3, 4, 1, 2, 3, 4, 6, 2
0 0 0 1 1 2 2 2 2 2 3 3
now when we divide, we know if a block contains a peak if its relative sum is positive:
1, 2, 3, 4, 3, 4, 1, 2, 3, 4, 6, 2
0|0 0 0 1| 1 2 2 2| 2 2 3 3
a b c d
If the first block did not contain a peak, we would expect b - a to equal 0 but instead we get 1, meaning there's a peak. This method would guarantee O(num blocks) for each divisor test.
The second thing I would try is to iterate from the smallest divisor (largest block size) to the largest divisor (smallest block size), but skip divisors that can be divided by a smaller divisor that failed validation. For example, if 2 succeeded but 3 failed, there's no way 6 can succeed, but 4 still could.
1 2 3 4 5 6 7 8 9 10 11 12
2 |
3 | |
6 | | | | |
4 x |x | x| x

Related

Finding the maximum possible sum/product combination of integers

Given an input of a list of N integers always starting with 1, for example: 1, 4, 2, 3, 5. And some target integer T.
Processing the list in order, the algorithm decides whether to add or multiply the number by the current score to achieve the maximum possible output < T.
For example: [input] 1, 4, 2, 3, 5 T=40
1 + 4 = 5
5 * 2 = 10
10 * 3 = 30
30 + 5 = 35 which is < 40, so valid.
But
1 * 4 = 4
4 * 2 = 8
8 * 3 = 24
24 * 5 = 120 which is > 40, so invalid.
I'm having trouble conceptualizing this in an algorithm -- I'm just looking for advice on how to think about it or at most pseudo-code. How would I go about coding this?
My first instinct was to think about the +/* as 1/0, and then test permutations like 0000 (where length == N-1, I think), then 0001, then 0011, then 0111, then 1111, then 1000, etc. etc.
But I don't know how to put that into pseudo-code given a general N integers. Any help would be appreciated.
You can use recursive to implement the permutations. Python code below:
MINIMUM = -2147483648
def solve(input, T, index, temp):
# if negative value exists in input, remove below two lines
if temp >= T:
return MINIMUM
if index == len(input):
return temp
ans0 = solve(input, T, index + 1, temp + input[index])
ans1 = solve(input, T, index + 1, temp * input[index])
return max(ans0, ans1)
print(solve([1, 4, 2, 3, 5], 40, 1, 1))
But this method requires O(2^n) time complexity.

algorithmic puzzle for calculating the number of combinations of numbers sum to a fixed result

This is a puzzle i think of since last night. I have come up with a solution but it's not efficient so I want to see if there is better idea.
The puzzle is this:
given positive integers N and T, you will need to have:
for i in [1, T], A[i] from { -1, 0, 1 }, such that SUM(A) == N
additionally, the prefix sum of A shall be [0, N], while when the prefix sum PSUM[A, t] == N, it's necessary to have for i in [t + 1, T], A[i] == 0
here prefix sum PSUM is defined to be: PSUM[A, t] = SUM(A[i] for i in [1, t])
the puzzle asks how many such A's exist given fixed N and T
for example, when N = 2, T = 4, following As work:
1 1 0 0
1 -1 1 1
0 1 1 0
but following don't:
-1 1 1 1 # prefix sum -1
1 1 -1 1 # non-0 following a prefix sum == N
1 1 1 -1 # prefix sum > N
following python code can verify such rule, when given N as expect and an instance of A as seq(some people may feel easier reading code than reading literal description):
def verify(expect, seq):
s = 0
for j, i in enumerate(seq):
s += i
if s < 0:
return False
if s == expect:
break
else:
return s == expect
for k in range(j + 1, len(seq)):
if seq[k] != 0:
return False
return True
I have coded up my solution, but it's too slow. Following is mine:
I decompose the problem into two parts, a part without -1 in it(only {0, 1} and a part with -1.
so if SOLVE(N, T) is the correct answer, I define a function SOLVE'(N, T, B), where a positive B allows me to extend prefix sum to be in the interval of [-B, N] instead of [0, N]
so in fact SOLVE(N, T) == SOLVE'(N, T, 0).
so I soon realized the solution is actually:
have the prefix of A to be some valid {0, 1} combination with positive length l, and with o 1s in it
at position l + 1, I start to add 1 or more -1s and use B to track the number. the maximum will be B + o or depend on the number of slots remaining in A, whichever is less.
recursively call SOLVE'(N, T, B)
in the previous N = 2, T = 4 example, in one of the search case, I will do:
let the prefix of A be [1], then we have A = [1, -, -, -].
start add -1. here i will add only one: A = [1, -1, -, -].
recursive call SOLVE', here i will call SOLVE'(2, 2, 0) to solve the last two spots. here it will return [1, 1] only. then one of the combinations yields [1, -1, 1, 1].
but this algorithm is too slow.
I am wondering how can I optimize it or any different way to look at this problem that can boost the performance up?(I will just need the idea, not impl)
EDIT:
some sample will be:
T N RESOLVE(N, T)
3 2 3
4 2 7
5 2 15
6 2 31
7 2 63
8 2 127
9 2 255
10 2 511
11 2 1023
12 2 2047
13 2 4095
3 3 1
4 3 4
5 3 12
6 3 32
7 3 81
8 3 200
9 3 488
10 3 1184
11 3 2865
12 3 6924
13 3 16724
4 4 1
5 4 5
6 4 18
an exponential time solution will be following in general(in python):
import itertools
choices = [-1, 0, 1]
print len([l for l in itertools.product(*([choices] * t)) if verify(n, l)])
An observation: assuming that n is at least 1, every solution to your stated problem ends in something of the form [1, 0, ..., 0]: i.e., a single 1 followed by zero or more 0s. The portion of the solution prior to that point is a walk that lies entirely in [0, n-1], starts at 0, ends at n-1, and takes fewer than t steps.
Therefore you can reduce your original problem to a slightly simpler one, namely that of determining how many t-step walks there are in [0, n] that start at 0 and end at n (where each step can be 0, +1 or -1, as before).
The following code solves the simpler problem. It uses the lru_cache decorator to cache intermediate results; this is in the standard library in Python 3, or there's a recipe you can download for Python 2.
from functools import lru_cache
#lru_cache()
def walks(k, n, t):
"""
Return the number of length-t walks in [0, n]
that start at 0 and end at k. Each step
in the walk adds -1, 0 or 1 to the current total.
Inputs should satisfy 0 <= k <= n and 0 <= t.
"""
if t == 0:
# If no steps allowed, we can only get to 0,
# and then only in one way.
return k == 0
else:
# Count the walks ending in 0.
total = walks(k, n, t-1)
if 0 < k:
# ... plus the walks ending in 1.
total += walks(k-1, n, t-1)
if k < n:
# ... plus the walks ending in -1.
total += walks(k+1, n, t-1)
return total
Now we can use this function to solve your problem.
def solve(n, t):
"""
Find number of solutions to the original problem.
"""
# All solutions stick at n once they get there.
# Therefore it's enough to find all walks
# that lie in [0, n-1] and take us to n-1 in
# fewer than t steps.
return sum(walks(n-1, n-1, i) for i in range(t))
Result and timings on my machine for solve(10, 100):
In [1]: solve(10, 100)
Out[1]: 250639233987229485923025924628548154758061157
In [2]: %timeit solve(10, 100)
1000 loops, best of 3: 964 µs per loop

Merging of arrays containing duplicate elements using PRAM algorithm

I am learning PRAM algorithms. I stuck at one question. "There exists an algorithm which,given any two sorted m-element array of integers,where each integer belongs to the set{1,2,3...m} and where duplicate elements are allowed, merges the two arrays in O(1) time using PRAM with m common CRCW processors"
e.g.with m=4 ,it could merge the arrays<1,2,3,3>and<1,3,3,4> in O(1) time using 4 common CRCW processors
Please reply,
Thanks
as soon as you have M processors, and M-length arrays and I don't see any mention that final array should be sorted:
each processor can take 1 value from 1st array and 1 value from 2nd array and put them into final array, and this operation will be O(1)
try to look into this pseudo-code:
int array1[M] = {1, 2, 3, 4};
int array2[M] = {1, 3, 3, 4};
int output[M * 2] = {};
parallel for (i=0; i<M; i++) // each iteration of this loop runs on its own processor, so all iterations run at the same time and will finish in O(1) time simultaneously
{
output[i * 2] = array1[i];
output[i * 2 + 1] = array2[i];
}
so, operation in loop is obviously is O(1), and in general programming we can say that final complexity will be O(M), because of loop, but for M processors it will be only O(1)
So we have M processors Concurrent Read, Concurrent Write and 2 arrays: a,b.
We can do this (kind of sorting by counting the appearences of each number):
//index 0 1 2 3 4 5
int a[M] = {1, 1, 1, 1, 2, 6};
int b[M] = {1, 3, 3, 4, 4, 8};
int o[M * 2] = {};
int tem1[M * 2] = {};
int tem2[M * 2] = {};
parallel for (i=0; i<M; i++)
// each iteration of this loop runs on its own processor, so all iterations run at the same
// time and will finish in O(1) time simultaneously
// at reading/writing from/in the same location, processor i has higher priority than processor i+1, operations are queued
{
// step 1 (depending on how much the values repeat, there will be processors that wait for others with higher priority, // before performing their operations)
tem1[a[i]]++;
tem2[b[i]]++;
// index: 0 1 2 3 4 5 6 7 8 9 10 11 12
// -> tem1: 0 4 1 0 0 0 1 0 0 0 0 0 0
// -> tem2: 0 1 0 2 2 0 0 0 1 0 0 0 0
// step 2
// again, some processors might wait until they perform their operations, because they access the same memory location
o[tem1[a[i]+tem2[a[i]]-1] = a[i];
tem1[a[i]]--;
o[tem1[b[i]]+tem2[b[i]]-1] = b[i];
tem2[b[i]]--;
// index: 0 1 2 3 4 5 6 7 8 9 10 11 12
// -> o: 1 1 1 1 1 2 3 3 4 4 6 8
}
-> no loops, constant number of operations for each processor -> O(1)

Find algorithm to split sequence in 2 to minimize difference in sum [duplicate]

This question already has answers here:
Is partitioning an array into halves with equal sums P or NP?
(5 answers)
Closed 9 years ago.
Here's the problem: given a sequence of numbers, split these numbers into 2 sequences, so that the difference between the two sequences is the minimum. For example, given the sequence: [5, 4, 3, 3, 3] the solution is:
[5, 4] -> sum is 9
[3, 3, 3] -> sum is 9
The difference is 0
In other terms, can you find an algorithm (C language preferred) that given an input vector (variable size) of integers, can output two vector where the difference between the two sum is minimum?
Brutal force algorithm should be avoided.
To be sure to get the right solution, should be nice to compare in a benchmark the results between your algorithm and a brutal force algorithm.
It sounds like a sub-arrays problem (which is my interpretation of "sequences").
Meaning the only possibilities for 5, 4, 3, 3, 3 are:
| 5, 4, 3, 3, 3 => 0 - 18 => 18
5 | 4, 3, 3, 3 => 5 - 13 => 8
5, 4 | 3, 3, 3 => 9 - 9 => 0
5, 4, 3 | 3, 3 => 12 - 6 => 6
5, 4, 3, 3 | 3 => 15 - 3 => 12
5, 4, 3, 3, 3 | => 18 - 0 => 18 (same as first)
It is as simple as just comparing the sums on either side of every index.
Code: (untested)
int total = 0;
for (int i = 0; i < n; i++)
total += arr[i];
int best = INT_MAX, bestPos = -1, current = 0;
for (int i = 0; i < n; i++)
{
current += arr[i];
int diff = abs(current - total);
if (diff < best)
{
best = diff;
bestPos = i;
}
// else break; - optimisation, may not work
}
printf("The best position is at %d\n", bestPos);
The above is O(n), logically, you can't do much better than that.
You can slightly optimize the above by doing a binary-search-like process on the sequence to get down to n + log n rather than 2n, but both are O(n). Basic pseudo-code:
sum[0] = arr[0]
// sum[i] represents sum from indices 0 to i
for (i = 1:n)
sum[i] = sum[i-1] + arr[i]
total = sum[n]
start = 0
end = n
best = MAX
repeat:
if (start == end) stop
mid = (start + end) / 2
sumFromMidToN = sum[n] - sum[mid]
best = max(best, abs(sumFromMidToN - sum[mid]))
if (sum[mid] > sumFromMidToN)
end = mid
else if (sum[mid] < sumFromMidToN)
start = mid
else
stop
If it's actually subsets, then, as already mentioned, it appears to be the optimization version of the Partition problem, which is a lot more difficult.

Link list algorithm to find pairs adding up to 10

Can you suggest an algorithm that find all pairs of nodes in a link list that add up to 10.
I came up with the following.
Algorithm: Compare each node, starting with the second node, with each node starting from the head node till the previous node (previous to the current node being compared) and report all such pairs.
I think this algorithm should work however its certainly not the most efficient one having a complexity of O(n2).
Can anyone hint at a solution which is more efficient (perhaps takes linear time). Additional or temporary nodes can be used by such a solution.
If their range is limited (say between -100 and 100), it's easy.
Create an array quant[-100..100] then just cycle through your linked list, executing:
quant[value] = quant[value] + 1
Then the following loop will do the trick.
for i = -100 to 100:
j = 10 - i
for k = 1 to quant[i] * quant[j]
output i, " ", j
Even if their range isn't limited, you can have a more efficient method than what you proposed, by sorting the values first and then just keeping counts rather than individual values (same as the above solution).
This is achieved by running two pointers, one at the start of the list and one at the end. When the numbers at those pointers add up to 10, output them and move the end pointer down and the start pointer up.
When they're greater than 10, move the end pointer down. When they're less, move the start pointer up.
This relies on the sorted nature. Less than 10 means you need to make the sum higher (move start pointer up). Greater than 10 means you need to make the sum less (end pointer down). Since they're are no duplicates in the list (because of the counts), being equal to 10 means you move both pointers.
Stop when the pointers pass each other.
There's one more tricky bit and that's when the pointers are equal and the value sums to 10 (this can only happen when the value is 5, obviously).
You don't output the number of pairs based on the product, rather it's based on the product of the value minus 1. That's because a value 5 with count of 1 doesn't actually sum to 10 (since there's only one 5).
So, for the list:
2 3 1 3 5 7 10 -1 11
you get:
Index a b c d e f g h
Value -1 1 2 3 5 7 10 11
Count 1 1 1 2 1 1 1 1
You start pointer p1 at a and p2 at h. Since -1 + 11 = 10, you output those two numbers (as above, you do it N times where N is the product of the counts). Thats one copy of (-1,11). Then you move p1 to b and p2 to g.
1 + 10 > 10 so leave p1 at b, move p2 down to f.
1 + 7 < 10 so move p1 to c, leave p2 at f.
2 + 7 < 10 so move p1 to d, leave p2 at f.
3 + 7 = 10, output two copies of (3,7) since the count of d is 2, move p1 to e, p2 to e.
5 + 5 = 10 but p1 = p2 so the product is 0 times 0 or 0. Output nothing, move p1 to f, p2 to d.
Loop ends since p1 > p2.
Hence the overall output was:
(-1,11)
( 3, 7)
( 3, 7)
which is correct.
Here's some test code. You'll notice that I've forced 7 (the midpoint) to a specific value for testing. Obviously, you wouldn't do this.
#include <stdio.h>
#define SZSRC 30
#define SZSORTED 20
#define SUM 14
int main (void) {
int i, s, e, prod;
int srcData[SZSRC];
int sortedVal[SZSORTED];
int sortedCnt[SZSORTED];
// Make some random data.
srand (time (0));
for (i = 0; i < SZSRC; i++) {
srcData[i] = rand() % SZSORTED;
printf ("srcData[%2d] = %5d\n", i, srcData[i]);
}
// Convert to value/size array.
for (i = 0; i < SZSORTED; i++) {
sortedVal[i] = i;
sortedCnt[i] = 0;
}
for (i = 0; i < SZSRC; i++)
sortedCnt[srcData[i]]++;
// Force 7+7 to specific count for testing.
sortedCnt[7] = 2;
for (i = 0; i < SZSORTED; i++)
if (sortedCnt[i] != 0)
printf ("Sorted [%3d], count = %3d\n", i, sortedCnt[i]);
// Start and end pointers.
s = 0;
e = SZSORTED - 1;
// Loop until they overlap.
while (s <= e) {
// Equal to desired value?
if (sortedVal[s] + sortedVal[e] == SUM) {
// Get product (note special case at midpoint).
prod = (s == e)
? (sortedCnt[s] - 1) * (sortedCnt[e] - 1)
: sortedCnt[s] * sortedCnt[e];
// Output the right count.
for (i = 0; i < prod; i++)
printf ("(%3d,%3d)\n", sortedVal[s], sortedVal[e]);
// Move both pointers and continue.
s++;
e--;
continue;
}
// Less than desired, move start pointer.
if (sortedVal[s] + sortedVal[e] < SUM) {
s++;
continue;
}
// Greater than desired, move end pointer.
e--;
}
return 0;
}
You'll see that the code above is all O(n) since I'm not sorting in this version, just intelligently using the values as indexes.
If the minimum is below zero (or very high to the point where it would waste too much memory), you can just use a minVal to adjust the indexes (another O(n) scan to find the minimum value and then just use i-minVal instead of i for array indexes).
And, even if the range from low to high is too expensive on memory, you can use a sparse array. You'll have to sort it, O(n log n), and search it for updating counts, also O(n log n), but that's still better than the original O(n2). The reason the binary search is O(n log n) is because a single search would be O(log n) but you have to do it for each value.
And here's the output from a test run, which shows you the various stages of calculation.
srcData[ 0] = 13
srcData[ 1] = 16
srcData[ 2] = 9
srcData[ 3] = 14
srcData[ 4] = 0
srcData[ 5] = 8
srcData[ 6] = 9
srcData[ 7] = 8
srcData[ 8] = 5
srcData[ 9] = 9
srcData[10] = 12
srcData[11] = 18
srcData[12] = 3
srcData[13] = 14
srcData[14] = 7
srcData[15] = 16
srcData[16] = 12
srcData[17] = 8
srcData[18] = 17
srcData[19] = 11
srcData[20] = 13
srcData[21] = 3
srcData[22] = 16
srcData[23] = 9
srcData[24] = 10
srcData[25] = 3
srcData[26] = 16
srcData[27] = 9
srcData[28] = 13
srcData[29] = 5
Sorted [ 0], count = 1
Sorted [ 3], count = 3
Sorted [ 5], count = 2
Sorted [ 7], count = 2
Sorted [ 8], count = 3
Sorted [ 9], count = 5
Sorted [ 10], count = 1
Sorted [ 11], count = 1
Sorted [ 12], count = 2
Sorted [ 13], count = 3
Sorted [ 14], count = 2
Sorted [ 16], count = 4
Sorted [ 17], count = 1
Sorted [ 18], count = 1
( 0, 14)
( 0, 14)
( 3, 11)
( 3, 11)
( 3, 11)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 5, 9)
( 7, 7)
Create a hash set (HashSet in Java) (could use a sparse array if your numbers are well-bounded, i.e. you know they fall into +/- 100)
For each node, first check if 10-n is in the set. If so, you have found a pair. Either way, then add n to the set and continue.
So for example you have
1 - 6 - 3 - 4 - 9
1 - is 9 in the set? Nope
6 - 4? No.
3 - 7? No.
4 - 6? Yup! Print (6,4)
9 - 1? Yup! Print (9,1)
This is a mini subset sum problem, which is NP complete.
If you were to first sort the set, it would eliminate the pairs of numbers that needed to be evaluated.

Resources