SRM 603, D2, 250-Pointer (MiddleCode)

James S. Plank

Sun Jul 7 10:36:33 EDT 2019

I'm going to walk you through two solutions to a rather simple problem. This is the kind of thing that interviewers like to do on a job interview -- see you evaluate a simple-but-bad, and a harder-but-good solution to a problem. So walk through every detail of this one so that you could do this on a whiteboard in front of some job interviewers!



In case Topcoder's servers are down

Here is a summary of the problem:

The examples

Example s t
0
"word"
"ordw"
1
"aaaaa"
"aaaaa"
2
"abacaba"
"caabbaa"
3
"shjegr"
"ejghrs"
4
"adafaaaadafawafwfasdaa"
"afawadafawafaafsadadaa"

Let's walk through the first example:


Testing yourself

Like the Cryptography Problem, I have a shell script tests.sh, that you can use to test your program. When you run tests.sh, your answer should be identical to answers.txt.

An Expedient Solution

Because the constraints on this one are so low, you can solve it with an expedient solution that follows the algorithm above very closely: Go ahead and write that one -- it will be fast enough to pass Topcoder's system test (or tests.sh if Topcoder's servers are down).

Evaluating the Expedient Solution

As is often the case, the expedient solution is easy to write, but is not the best solution. In this case, think about how you "delete" the character from s, when it has n characters. The two s.substr() calls create a new string of size n-1, which means that they take n-1 operations, and you are left with a new s, whose size is n-1.

Let's add up the number of operations:

Size of s Operations to "delete" the character
nn-1
n-1n-2
n-2n-3
......
21
10

That's the sum of i for i = 0 to n-1, which is (n-1)*(n-2)/2 = (n2 - 3n + 2) / 2. That's a quadratic equation (later in the semester, we will call it O(n2)), which means it blows up as you increase n. For example, if the size of x is 500,000, then this solution takes 250,001,500,002 operations.

In the shell script test-harder.sh, I include some larger tests, the last of which uses a string with 500,000 characters as input. On my Macintosh (in 2019), it took three minutes and 51 seconds.


A Better Solution

The culprit here is how you "delete" the character from s. If you think about the problem some more, you'll see that you don't need to delete the character from s. You can simply keep track of the middle characters without deleting them.

Go ahead and try to write a solution that doesn't delete any characters of s. I'll outline it below, but give it a try on your own before reading further.

My solution relies on the observation that when s is even, you add one of the middle characters to t, and then you add the other one (because s is now odd, and that character is the middle one). In the example above, when you're considering 'o' and 'r', you first add the 'o' and then you add the 'r'. So, I did the following:

If you evaluate this solution, it does a handful of operations at each iteration, and there are n/2 iterations. Call it 10 operations. That means a total of 5n operations, which is linear rather than quadratic. Compare 5*500,000 = 2,500,000 operations to the 250,001,500,002 operations for the quadratic solution!

Try your new answer on test-harder.sh (check your correctness with tests.sh first), and it should be much faster. You can check your timing as follows:

UNIX> time sh -c 'sh test-harder.sh > /dev/null'
0.921u 0.068s 0:00.90 108.8%	0+0k 0+0io 0pf+0w
UNIX> 
Under a second for all of the tests!