I have an implementation that I believe works (coded in C#):
public static int[] LastKHighestValues(int[] array, int k)
{
int[] maxes = new int[array.Length];
int indexOfCurrentMax = 0;
int indexOfNextMax = 0;
for (int i = 0; i < array.Length; i++)
{
if (indexOfNextMax <= indexOfCurrentMax ||
array[i] > array[indexOfNextMax])
{
indexOfNextMax = i;
}
if (i - indexOfCurrentMax >= k)
{
indexOfCurrentMax = indexOfNextMax;
}
if (array[i] > array[indexOfCurrentMax])
{
indexOfCurrentMax = i;
}
maxes[i] = array[indexOfCurrentMax];
}
return maxes;
}
The idea is that you keep two "pointers": one to the current max, and one to the next thing to go to after the current max expires. This can be implemented in one pass through the array (so O(n)).
I have a few passing tests, but I'm far from certain I've covered every corner case:
Puzzle.LastKHighestValues(new[] {4, 3, 1}, 1).Should().Equal(new[] {4, 3, 1});
Puzzle.LastKHighestValues(new[] { 7, 7, 7 }, 3).Should().Equal(new[] { 7, 7, 7 });
Puzzle.LastKHighestValues(new[] { 7, 7, 7 }, 4).Should().Equal(new[] { 7, 7, 7 });
Puzzle.LastKHighestValues(new[] { 3, 2, 1 }, 2).Should().Equal(new[] { 3, 3, 2 });
Puzzle.LastKHighestValues(new[] { 7, 1, 4, 1, 1 }, 3).Should().Equal(new[] { 7, 7, 7, 4, 4 });
Puzzle.LastKHighestValues(new[] { 7, 8, 4, 9, 10 }, 2).Should().Equal(new[] { 7, 8, 8, 9, 10 });