# Given a string of a million numbers, return all repeating 3 digit numbers

I had an interview with a hedge fund company in New York a few months ago and unfortunately, I did not get the internship offer as a data/software engineer. (They also asked the solution to be in Python.)

I pretty much screwed up on the first interview problem...

Question: Given a string of a million numbers (Pi for example), write a function/program that returns all repeating 3 digit numbers and number of repetition greater than 1

For example: if the string was: `123412345123456`

then the function/program would return:

```
123 - 3 times
234 - 3 times
345 - 2 times
```

They did not give me the solution after I failed the interview, but they did tell me that the time complexity for the solution was constant of 1000 since all the possible outcomes are between:

000 --> 999

Now that I'm thinking about it, I don't think it's possible to come up with a constant time algorithm. Is it?

You got off lightly, you probably *don't* want to be working for a hedge fund where the quants don't understand basic algorithms :-)

There is *no* way to process an arbitrarily-sized data structure in `O(1)`

if, as in this case, you need to visit every element at least once. The *best* you can hope for is `O(n)`

in this case, where `n`

is the length of the string.

Although, as an aside, a nominal

`O(n)`

algorithmwillbe`O(1)`

for a fixed input size so, technically, they may have been correct here. However, that's not usually how people use complexity analysis.

It appears to me you could have impressed them in a number of ways.

First, by informing them that it's *not* possible to do it in `O(1)`

, unless you use the "suspect" reasoning given above.

Second, by showing your elite skills by providing Pythonic code such as:

```
inpStr = '123412345123456'
# O(1) array creation.
freq = [0] * 1000
# O(n) string processing.
for val in [int(inpStr[pos:pos+3]) for pos in range(len(inpStr) - 2)]:
freq[val] += 1
# O(1) output of relevant array values.
print ([(num, freq[num]) for num in range(1000) if freq[num] > 1])
```

This outputs:

```
[(123, 3), (234, 3), (345, 2)]
```

though you could, of course, modify the output format to anything you desire.

And, finally, by telling them there's almost certainly *no* problem with an `O(n)`

solution, since the code above delivers results for a one-million-digit string in well under half a second. It seems to scale quite linearly as well, since a 10,000,000-character string takes 3.5 seconds and a 100,000,000-character one takes 36 seconds.

And, if they *need* better than that, there are ways to parallelise this sort of stuff that can greatly speed it up.

Not within a *single* Python interpreter of course, due to the GIL, but you could split the string into something like (overlap indicated by `vv`

is required to allow proper processing of the boundary areas):

```
vv
123412 vv
123451
5123456
```

You can farm these out to separate workers and combine the results afterwards.

The splitting of input and combining of output are likely to swamp any saving with small strings (and possibly even million-digit strings) but, for much larger data sets, it may well make a difference. My usual mantra of *"measure, don't guess"* applies here, of course.

This mantra also applies to *other* possibilities, such as bypassing Python altogether and using a different language which may be faster.

For example, the following C code, running on the same hardware as the earlier Python code, handles a *hundred* million digits in 0.6 seconds, roughly the same amount of time as the Python code processed *one* million. In other words, *much* faster:

```
#include <stdio.h>
#include <string.h>
int main(void) {
static char inpStr[100000000+1];
static int freq[1000];
// Set up test data.
memset(inpStr, '1', sizeof(inpStr));
inpStr[sizeof(inpStr)-1] = '\0';
// Need at least three digits to do anything useful.
if (strlen(inpStr) <= 2) return 0;
// Get initial feed from first two digits, process others.
int val = (inpStr[0] - '0') * 10 + inpStr[1] - '0';
char *inpPtr = &(inpStr[2]);
while (*inpPtr != '\0') {
// Remove hundreds, add next digit as units, adjust table.
val = (val % 100) * 10 + *inpPtr++ - '0';
freq[val]++;
}
// Output (relevant part of) table.
for (int i = 0; i < 1000; ++i)
if (freq[i] > 1)
printf("%3d -> %d\n", i, freq[i]);
return 0;
}
```

From: stackoverflow.com/q/47581326