Skip to content

Commit 8c630bc

Browse files
committed
Add Flag.md
1 parent 9660f42 commit 8c630bc

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

  • codility_training/lessons.lesson10.PrimeAndCompositeNumbers.Flags
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Flag
2+
3+
## Description
4+
5+
`O(N)` preprocessing (done inplace):
6+
7+
```js
8+
A[i] := next peak or end position after or at position i
9+
(i for a peak itself, len(A) after last peak)
10+
```
11+
12+
If we can plant `k` flags then we can certainly plant `k' < k` flags as well. If we can not plant `k` flags then we certainly can not plant `k' > k` flags either. We can always set 0 flags. Let us assume we can not set `X` flags. Now we can use binary search to find out exactly how many flags can be planted.
13+
14+
```js
15+
Steps:
16+
1. X/2
17+
2. X/2 +- X/4
18+
3. X/2 +- X/4 +- X/8
19+
...
20+
log2(X) steps in total
21+
```
22+
23+
With the preprocessing done before, each step testing whether `k` flags can be planted can be performed in `O(k)` operations:
24+
25+
- flag(0) = next(0)
26+
- flag(1) = next(flag(1) + k) ...
27+
- flag(k-1) = next(flag(k-2) + k)
28+
29+
total cost - worst case - when `X - 1` flags can be planted:
30+
31+
> == X * (1/2 + 3/4 + ... + (2^k - 1)/(2^k))
32+
> == X * (log2(X) - 1 + (<1))
33+
> <= X * log(X)
34+
35+
Using `X == N` would work, and would most likely also be sublinear, but is not good enough to use in a proof that the total upper bound for this algorithm is under `O(N)`.
36+
37+
Now everything depends on finding a good `X`, and it since `k` flags take about `k^2` positions to fit, it seems like a good upper limit on the number of flags should be found somewhere around `sqrt(N)`.
38+
39+
If `X == sqrt(N)` or something close to it works, then we get an upper bound of `O(sqrt(N) * log(sqrt(N)))` which is definitely sublinear and since `log(sqrt(N)) == 1/2 * log(N)` that upper bound is equivalent to `O(sqrt(N) * log(N))`.
40+
41+
Let's look for a more exact upper bound on the number of required flags around `sqrt(N)`:
42+
43+
- we know `k` flags requires `Nk := k^2 - k + 3` flags
44+
- by solving the equation `k^2 - k + 3 - N = 0` over `k` we find that if `k >= 3`, then any number of flags <= the resulting `k` can fit in some sequence of length N and a larger one can not; solution to that equation is `1/2 * (1 + sqrt(4N - 11))`
45+
- for `N >= 9` we know we can fit 3 flags ==> for `N >= 9`, `k = floor(1/2 * (1 + sqrt(4N - 11))) + 1` is a strict upper bound on the number of flags we can fit in `N`
46+
- for `N < 9` we know 3 is a strict upper bound but those cases do not concern us for finding the big-O algorithm complexity
47+
48+
> floor(1/2 * (1 + sqrt(4N - 11))) + 1
49+
> == floor(1/2 + sqrt(N - 11/4)) + 1
50+
> <= floor(sqrt(N - 11/4)) + 2
51+
> <= floor(sqrt(N)) + 2
52+
53+
==> `floor(sqrt(N)) + 2` is also a good strict upper bound for a number of flags that can fit in `N` elements + this one holds even for `N < 9` so it can be used as a generic strict upper bound in our implementation as well
54+
55+
If we choose `X = floor(sqrt(N)) + 2` we get the following total algorithm upper bound:
56+
57+
```js
58+
O((floor(sqrt(N)) + 2) * log(floor(sqrt(N)) + 2))
59+
{floor(...) <= ...}
60+
O((sqrt(N) + 2) * log(sqrt(N) + 2))
61+
{for large enough N >= 4: sqrt(N) + 2 <= 2 * sqrt(N)}
62+
O(2 * sqrt(N) * log(2 * sqrt(N)))
63+
{lose the leading constant}
64+
O(sqrt(N) * (log(2) + loq(sqrt(N)))
65+
O(sqrt(N) * log(2) + sqrt(N) * log(sqrt(N)))
66+
{lose the lower order bound}
67+
O(sqrt(N) * log(sqrt(N)))
68+
{as noted before, log(sqrt(N)) == 1/2 * log(N)}
69+
O(sqrt(N) * log(N))
70+
QED
71+
```

0 commit comments

Comments
 (0)