Variables
In this answer I will use the following names for the variables:
- The
n
variable refers to the initial value of length
(in the case above this is 4)
- The
isl
(input string length) variable refers to the length of the input string (11 in the case above)
- The
index
variable refers to the index of the output array.
Approach
To solve the problem and find a solution, we should first look at the details we got.
Input
The formula or algorithm we are looking for receives the following inputs:
- The
index
of the output_array
- The
isl
(length of the input string)
But this is not the only input. It also knows the initial value of length
(in your example above it's 4). As mentioned above, we will call this value n
.
Facts
From the algorithm you described in your question, we can derive the following facts:
Partitions of the output array
The output_array
will have n
partitions corresponding to the n
different lengths (in your example above the lengths from 4 to 1).
Each partition i
has a length of $$\text{isl}-(n-i)+1$$ where i
(the partition number) starts at 0.
We notice, that the first partition is the smallest one and the last partition (where the sequences
have a length of 1) is the largest one with a length of isl
. From the formula we also see, that the length of the partitions increases from the first partition to last partition by 1.
Note: We count partitions starting at 0.
Deducting the Formula
We need two formulas. One for the length
of the sequence
at index
and one for the offset
of that same sequence
in the input string.
The formula for length
The formula for the length
must look something like this: $$\text{length} = \overbrace{\text{n}}^{\text{minuend}} - \overbrace{\text{something depending on index}}^{\text{subtrahend}}$$
For the first partition (partition 0) the subtrahend
shall be 0. For the second (partition 1) it shall be 1 and so on.
Indicator function
As we can see, we need a function, which can tell us, in which partition the index
is in. A thing with such a property is like an indicator function. It could look like:
$$\text{partition_number}(\text{index}) = \begin{cases}0,&\text{if index in partition 0}\\1,&\text{if index in partition 1}\\\ldots\end{cases}$$
An easy way to find such a function is to have an indicator function, which can tell us, if index
is in a partition a
, where a
is at least i
. Something like:
$$f(\text{index},i) = \begin{cases}1,&\text{if index in partition a > i}\\0,&\text{else}\end{cases}$$
Because then we would just have to sum the result of f
for all partitions and would directly have our subtrahend.
To define such a function f
, we need to know at least the left boundary of partition i
. We can obtain the left bound of partition i
by:
$$\text{left_bound}(i) = i*\overbrace{(\text{isl}-n+1)}^{\text{Size of first partition}}+\overbrace{\frac{1}{2}*(i-1)*i}^{\text{Correction number for partition growth}}$$
So our indicator function looks like:
$$f(\text{index},i) = \begin{cases}1,&\text{if } \text{left_bound}(i)<=\text{index}\\0,&\text{else}\end{cases}$$
With this function we can now define our partition_number
function as following:
$$\text{partition_number}(\text{index})=\sum_{i=0}^{n-1}{f(\text{index},i)}-1$$
With the partition_number
for our subtrahend we can now define our formula for the length_at_index
:
$$\text{length_at_index}=n-\text{partition_number}(\text{index})=n-\sum_{i=0}^{n-1}{f(\text{index},i)}+1$$
The formula for offset
We can directly make use of the partition_number
and left_bound
function we defined above:
$$\text{offset_at_index} = \text{index}-\text{left_bound}(\text{partition_number}(\text{index}))$$
A Solution in Javascript
And here the solution of above written in Javascript:
function getLeftBoundOfPartitionI(i, isl, n) {
return i * (isl - n + 1) + .5 * (i - 1) * i
}
function isIndexInPartitionI(index, i, isl, n) {
return index >= getLeftBoundOfPartitionI(i, isl, n) ? 1 : 0
}
function getPartitionNumber(index, isl, n) {
partition = 0
for(var i = 0; i < n; i++) {
partition += isIndexInPartitionI(index, i, isl, n)
}
return partition - 1
}
function lengthAtIndex(index, isl, n) {
return n - getPartitionNumber(index, isl, n)
}
function offsetAtIndex(index, isl, n) {
partitionNumber = getPartitionNumber(index, isl, n)
return index - getLeftBoundOfPartitionI(partitionNumber, isl, n)
}
document.body.innerHTML = offsetAtIndex(16, 11, 4) // yields 8