CS202 Lecture notes -- Topcoder for Lab


In your labs, I will give you one to three topcoder problems to solve. I used to have you use Topcoder's software to do this, but now you can simply work on your own computer with your own compiler.

(As of 2021, I have started to add Leetcode problems to the mix -- so, wherever you see "Topcoder", you can also substitute "Leetcode").

For each topcoder problem, I will give you a web link to one of my directories. For example, the first one that I will give you in lab is to the problem "FauxPalindromes". This was from SRM #564 (Topcoder tournaments are called "Single Round Matches" or SRMs). It was in Division two (there are two divisions, D1 for experts and D2 for novices), worth 250 points (typically there are three problems: 250, 500 and 1000 points).

Here's the link: http://web.eecs.utk.edu/~jplank/topcoder-writeups/2012/FauxPalindromes/index.html.

The web pages that I give you will have links to the description of the problem on Topcoder. You can try that link, but sometimes it doesn't work. I'll also have a section entitled "In Case Topcoder's Servers Are Down," which gives you a summary description of the problem, and then examples. Then, I have a few files to help you:

Go ahead and copy all four of these files to your own directory (right-click the links and do "save link as"). The way you use main.cpp is a little quirky. As you can see, the first line includes "FauxPalindromes.cpp":
UNIX> ls -l
total 40
-rw-r--r--@ 1 jplank  staff   322 Aug 28 17:39 FauxPalindromes.cpp
-rw-r--r--@ 1 jplank  staff   947 Aug 28 17:39 answers.txt
-rw-r--r--@ 1 jplank  staff   965 Aug 28 17:39 main.cpp
-rw-r--r--@ 1 jplank  staff  5614 Aug 28 17:36 tests.sh
UNIX> head -n 1 main.cpp
#include "FauxPalindromes.cpp"
UNIX> 
That is not something you normally want to do, but it is convenient here. If you compile main.cpp, it will include FauxPalindromes.cpp and compile into an a.out that you can use for testing. Let's look at FauxPalindromes.cpp

#include <string>
#include <vector>
#include <list>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

class FauxPalindromes {
  public:
    string classifyIt(string word);
};

string FauxPalindromes::classifyIt(string word)
{
  return "";
}

We compile it by compiling main.cpp (which includes it):

UNIX> g++ main.cpp
UNIX> ls -l a.out
-rwxr-xr-x  1 plank  staff  21460 Aug 28 17:42 a.out
UNIX> 
Now when we run it, we can give the example number on the command line:
UNIX> ./a.out 0

UNIX> 
We can also give it the argument "-", and enter an example string on standard input:
UNIX> echo FRED | ./a.out -

UNIX> 
Of course, in both cases, it prints an empty line. That's because the return value of FauxPalindromes::classifyIt(), is the empty string. Let's modify FauxPalindromes.cpp so that it returns the string word:
UNIX> vi FauxPalindromes.cpp       # Change the program so that it returns word instead of "".
UNIX> g++ main.cpp
UNIX> ./a.out 0
ANA
UNIX> ./a.out 1
AAAAANNAA
UNIX> echo FRED | ./a.out -
FRED
UNIX> 
Now, let's solve the problem. The way I'll solve it is to create three additional strings:
  1. rword is the string word reversed.
  2. p is the string word without duplicate characters.
  3. r is the string p reversed.
You use these to test for the proper conditions: Here's the code:

#include <iostream>
using namespace std;

class FauxPalindromes 
{ 
  public:
    string classifyIt(string word);
};

string FauxPalindromes::classifyIt(string word) {
  string rword, p, r;
  size_t i;
  int j;
  
  for (j = word.size()-1; j >= 0; j--) rword.push_back(word[j]);     // rword is the reverse of word.
  if (word == rword) return "PALINDROME";
  
  p.push_back(word[0]);                                              // p is word, but without any repeated characters.
  for (i = 1; i < word.size(); i++) {
    if (word[i] != word[i-1]) p.push_back(word[i]);
  }

  for (j = p.size()-1; j >= 0; j--) r.push_back(p[j]);               // r is the reverse of p.

  if (r == p) return "FAUX";
  return "NOT EVEN FAUX";
}

Now, when we compile main.cpp, it incorporates the changes, and we are getting answers correct!

UNIX> g++ main.cpp
UNIX> ./a.out 0
PALINDROME
UNIX> ./a.out 1
FAUX
UNIX> echo ABBA | ./a.out -
PALINDROME
UNIX> echo AAAABA | ./a.out -
FAUX
UNIX> echo FRED | ./a.out -
NOT EVEN FAUX
UNIX> 
Now, the shell script tests.sh runs a bunch of examples. It assumes that your program is compiled to a.out. Run it as follows:
UNIX> sh tests.sh
NOT EVEN FAUX
FAUX
PALINDROME
FAUX
....
UXNI>
Now, to test yourself, run tests.sh and redirect standard output to a file (I'll use junk.txt). Then compare this file to answers.txt using the program diff or openssl:
UNIX> sh tests.sh > junk.txt
UNIX> diff junk.txt answers.txt                      # If they are identical, this will produce no output
UNIX> openssl md5 junk.txt answers.txt               # If they are identical, their MD5 hashes will be identical
MD5(junk.txt)= 6e0336d91bff65fa3938c2ed9a5919c2
MD5(answers.txt)= 6e0336d91bff65fa3938c2ed9a5919c2
UNIX> 
tests.sh is not hard to read -- it just does a test per line:
UNIX> head tests.sh
echo ICJGJCFGEGHIAFFFFAIHGEGFCJGJC | ./a.out -
echo ENHPIECCMPEGPJJJPGEPMCEIPHNE | ./a.out -
echo OOCBCLDNCEMOFDALNLADFOMECNDLCBCOO | ./a.out -
echo CPPRRXXAGGGKKSUUUMUUUUUSSSKGGAAAXRPC | ./a.out -
echo JKKKNFKLNFHJJGPIMMMGJGMMIPPGJHFFNLKKFNNKKJJ | ./a.out -
echo DBBMMMBBIIIMMBDQQMMMMMQQDDBMMIIIBBMMMBBBDD | ./a.out -
echo BAEBAFFCGDEGDDGEDGCFFABEAB | ./a.out -
echo DDIAHDCBBDBGDADGBDBBCDHAIDD | ./a.out -
echo JLDNFNFGEOFNCCNFOEGFNFNDLJ | ./a.out -
echo KCKAAGMGGIGJJKKKGCDDJCOIIIOOCJDCGKKKJGIGGMMGAAKKCK | ./a.out -
UNIX> 
In lab, you need to demonstrate to your TA that your program works. I include MD5 hashes for tests.sh and answers.txt so that you cannot modify them.

A final aside about including the cpp file from main.cpp

That #include "FauxPalindromes.cpp" statement is something you don't see every day, and that is for good reason. In general, it's a bad thing to do, so please don't do it in your code, and if you do end up doing it, please don't say that I taught it to you. It will make both you and me look bad...

In case you want to use the topcoder Arena

You don't need to do this -- I simply include it in case you want to try using Topcoder's software

In this set of lecture notes, I will go over an example of doing this, how you sometimes have to fight topcoder, and how you can do a problem without Topcoder's servers working.

Suppose in lab, I say to do the problem "FauxPalindromes". Often, I will give you a URL to some notes on the problem, for example: http://web.eecs.utk.edu/~jplank/topcoder-writeups/2012/FauxPalindromes/index.html.

This is how I anticipate that you do the problem. First, you'll need to create an account with topcoder. Then, go to https://arena.topcoder.com. You'll see a screen something like the following:

Now, move your mouse to the green icon, which is the icon circled below, and click on it. That should get you to the "practice problems" page:

The "practice problems" page looks like the screenshot below:

Type "FauxPalindromes" into the search bar, and you'll see the problem, click on it, and you'll get a screen that looks as follows (As they warn you, this may take a minute or two. When I was writing these notes, it took over a minute. Evidently, Topcoder uses a server farm of Raspberry Pi's to hold their problems.)

Go ahead and read the problem description, including the constraints and examples. Think about how to solve it. My strategy for solving this problem would be as follows:

Time to start writing the code. You'll note that there is a section called "Definition", which gives you the class and method definitions that you should implement:

Start off by defining the class, and implementing the method so that it simply returns an empty string. I've done that below (I clicked on the icon to expand the "coding area"):

Click on "compile" to make sure that you have these details correct. You'll get a warning (since you didn't use the argument "word"), but that's fine. Now you're ready to actually write code. Here's my implementation. The comments are for you, by the way. I typically don't comment when I'm doing Topcoder. (Oh, and if you click on the picture, you can see the screenshot in its full size -- that's true with most of the screenshots here).

Compile this, and then click on the "Test Panel". This allows you to run your program on the examples. I clicked on the "Click All" button and then ran, and the window brings up that I failed cases two and four. Crap!!!

You can debug however you want. I pretty much knew my error right away -- I'm calling r.push_back(p[i]) instead of r.push_back(p[j]). If you put cout or printf() statements into your code, you'll see standard output in the window after clicking "Run". When you're satisfied and you want to submit, then you click "submit" and it will tell you how many points you've gotten. That doesn't mean that your program is right, though. To see that, click on "Run System Tests". If all has gone well, then you'll see the following:

Otherwise, you'll have to go back, fix your code and resubmit. When you fail, it doesn't appear to tell you why. That's a drag. Also, if you want to add test cases to the "Test Panel," click on "+Add" and you can create your own test cases.