test case1 input
7
0 1 2 3 8 9 11
test case1 output
3
test case2 input
8
0 1 3 5 6 8 12 17
test case2 output
17
test case3 input
80
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29 31 32 33 35 37 39 40 41 43 44 45 48 49 50 53 54 57 58 61 63 67 68 73 74 79 80 83 85 90 91 94 96 101 103 109 111 120 122 130 131 132 155 160 165 170 175 176 177 190 200 250
test case3 output(expected)
175
#include <iostream>
using namespace std;
int largestNumber = 0;
// search for a index at a given number
// search only bigger than given index
// given array is sorted
// return 0 if not found
int findIndex(int *numbers, int size, int target, int index)
{
for (int i = index + 1; i < size; i++)
{
if (numbers[i] == target)
{
return i;
}
}
return 0;
}
void findLargestNumberCanReach(int *numbers, int size, int k, int currentNumber, int currentIndex)
{
if (currentIndex == size - 1) // reached to the end of the array
{
largestNumber = currentNumber;
return;
}
else if (currentIndex == 0) // can't find next number
{
if (currentNumber - k > largestNumber) // last currentNumber is biggest
{
largestNumber = currentNumber - k;
}
return;
}
currentIndex = findIndex(numbers, size, currentNumber + (k - 3), currentIndex);
findLargestNumberCanReach(numbers, size, k - 3, currentNumber + (k - 3), currentIndex);
currentIndex = findIndex(numbers, size, currentNumber + (k), currentIndex);
findLargestNumberCanReach(numbers, size, k, currentNumber + (k), currentIndex);
currentIndex = findIndex(numbers, size, currentNumber + (k + 1), currentIndex);
findLargestNumberCanReach(numbers, size, k + 1, currentNumber + (k + 1), currentIndex);
currentIndex = findIndex(numbers, size, currentNumber + (k + 2), currentIndex);
findLargestNumberCanReach(numbers, size, k + 2, currentNumber + (k + 2), currentIndex);
return;
}
int main()
{
int size;
cin >> size;
int *input = new int[size];
for (int idx = 0; idx < size; idx++)
{
cin >> input[idx];
}
findLargestNumberCanReach(input, size, 1, 1, 1);
cout << largestNumber << endl;
delete[] input;
return 0;
}
This problem looks like a harder version of the LeetCode program "frog jump".
Forget about the array or dynamic programming for a while and look at it conceptually.
A state S is (n,k)
where n
is an element of the input array, and k
the difference to the previous number. The initial state S0 is (0, 1)
.
Successor states (n', k')
are then (n + k - 3, k - 3)
, (n + k, k)
, (n + k + 1, k + 1)
, (n + k + 2, k + 2)
, assuming that n'
is an element of the array and n' > n
.
States thus form a graph, and the question boils down to finding all successor states reachable from S0 and returning the state with the largest n
.
In terms of C++, you need a couple of ingredients:
std::set<int> in_array
that tells whether a given number is part of the input array. This gives you O(log n)
lookups. You could also use an std::unordered_set
.State
that represents a state (n, k)
. You can use a struct or a std::pair<int, int>
.std::set<State> seen
that keeps track of visited statesstd::stack<State> todo
that represents a list of states to visitThe main program is then a loop that takes an element from the stack and checks if the state has been visited already. If not, it marks the state as visited and adds the successors to the todo
list.
When the stack becomes empty, take the highest element of seen
. This is the largest array element reachable.
With all this, problem 3 without any extra compiler optimizations takes 30 ms on my system.