"Name that Number" from USACO

by


Here is my solution to "Name that Number", from USACO.

Lessons learnt:

Two iterations over data might still be O(2N) which is same as O(N), but it will cross the 1 second time limit. Minimize operations, including iteration.
Also, reduce reliance on String, and prefer char arrays, specially when using recursion. Even StringBuffer/StringBuilder isn't good enough when compared to arrays.
Also, avoid writing custom binary search, as it'll take too much time, use java's inbuilt support instead.
Keep constant data/ result data structure at class level, recursive calls should use only the bare necessary arguments which are used to generate the output.

I wasted time on the Time limit exceeded. I first tried to optimize away the I/O. Again, to optimize algorithm, it is better to look at the loops first rather than constant operations.

BTW, validNames() should get the dictionary. I hardcoded it to squeeze some performance, didn't help much though.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

public class namenum
{
private static String[] validNames = null;
private static char[][] map = createMap();
private static char[] numberc = null;
private static int[] number = null;
private static PrintWriter out=null;
private static boolean dataPresent = false;

public static void main(String[] args) throws IOException
{
validNames = getValidNames();

BufferedReader reader2 = new BufferedReader(new FileReader(new File("namenum.in")));
numberc = reader2.readLine().toCharArray();
number = new int[numberc.length];
int i=0;
for(char c : numberc) {
number[i++]=c-48;
}

out = new PrintWriter(new FileWriter(new File("namenum.out")));
createNames(0, "");

if(!dataPresent) {
out.println("NONE");
}
out.close();
System.exit(0);
}

private static void createNames(int numberIndex, String name)
{
if (numberIndex == number.length)
{
if (Arrays.binarySearch(validNames, name) >= 0)
{
dataPresent=true;
out.println(name);
}
}
else
{
for (char letter : map[number[numberIndex]])
{
createNames(numberIndex + 1, name + letter);
}
}
}

private static char[][] createMap()
{
char[][] map = new char[][] { {}, {}, { 'A', 'B', 'C' },
{ 'D', 'E', 'F' }, { 'G', 'H', 'I' }, {'J', 'K', 'L'} , { 'M', 'N', 'O' },
{ 'P', 'R', 'S' }, { 'T', 'U', 'V' }, { 'W', 'X', 'Y' }, };
return map;
}

private static String[] getValidNames()
{
               validNames = new String[] {"AARON" };
        }
}