HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Optimal code without using for, while and if

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withoutwhileoptimalandusingforcode

Problem

I presented a code solution to a startup as part of their interview polity.

The problem statement is to find the frequency of words occurring in a sentence. I got the code rejected saying, "Evaluating code is always subjective, but people generally leave a "fingerprint" with their design approach and the nature of their code (comments, tests, multiple solution paths, validation). The hiring manager has a high bar, and has rejected many working solutions because he didn't like the approach or the number of trees used or linear scaling vs. ^2 scaling."

I have pasted my solution. The hiring manager specified not to use collection API. I would like some opinions as to how I would have improved the code.

import java.io.*;
import java.util.*;

class FreqWord {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new
        InputStreamReader(System. in ));
        String str[] = new String[30];
        StringTokenizer st;
        int i = 0, j, k, ctr, size = 0;
        System.out.println(" Enter the String :");
        String str1 = br.readLine();
        st = new StringTokenizer(str1, " \n");
        while (st.hasMoreTokens()) {
            str[i] = st.nextToken();
            size++;
            i++;
        }
        System.out.println("\n-------------");
        System.out.println("\nWord" + "\t" + "freq");
        System.out.println("\n-------------");
        for (i = 0; i = 0; k--) {
                if (str[k].equals(str[i])) {
                    ctr = 0;
                    break;
                }
            }
            if (ctr != 0) {
                System.out.println(str[i] + "\t" + ctr);
            }
        }
        System.out.println("\n------------");
    }
}

Solution

I am not a fan of this type of interview process... but ... you can assume that you need to differentiate yourself from the other candidates in some way.

Your solution may work, but does not show much in the way of 'clever' algorithms. You do the minimum to get the answer right, but not in the best way.

Things I think you could do better are:

  • Do not load the entire document in to memory. It may be large. Instead, use a mechanism for counting the words in a streaming way. It will save memory.



  • What about handling mixed-case words "The quick brown fox jumped over the sleeping dog" has the word 'the' twice, note the words 'The' and 'the' once each.



  • Consider a faster method for processing the data than a linnear scan through the words. A binary search and adding data to a sorted array would differentiate you.



EDIT: I took the liberty of copying and running the code, and it does not work. I changed the code to be:

BufferedReader br = new BufferedReader(new
    InputStreamReader(new FileInputStream(new File("src/FreqWord.java"))));


and this produced the result:

Enter the String :

-------------

Word    freq

-------------
import  1
java.io.*;  1

------------


This is obviously not correct, so I will take a moment and write what I consider to be a 'good' solution. This will also answer the comment below about the Binary Search.

EDIT 2: Here's an answer that demonstrates the three issues I mentioned (just the main method), and as a bonus it gets the right answer.... :

public static void main(String[] args) throws IOException {
    // show you know the Java7 language changes...
    try (BufferedReader br = new BufferedReader(new InputStreamReader(
            new FileInputStream(new File("src/FreqWord.java"))))) {
        int wordcount = 0; // the number of unique words we have

        String [] wordvalues = new String[32];
        int [] counts = new int[32];

        String line = null;
        // Using regular expressions is a differentiator
        final Pattern pattern = Pattern.compile("\\w+");
        while ((line = br.readLine()) != null) {
            // Only keep one line at a time in memory.
            Matcher matcher = pattern.matcher(line);
            while (matcher.find()) {
                // use toLowerCase() to show a grasp of the problem
                String word = matcher.group().toLowerCase();
                // use BinarySearch to order the words, which is faster than a scan.
                int ip = Arrays.binarySearch(wordvalues, 0, wordcount, word);
                if (ip >>2));
                        counts = Arrays.copyOf(counts, wordvalues.length);
                    }
                    // insert the word in sorted order.
                    System.arraycopy(wordvalues,  ip, wordvalues,  ip+1, wordcount-ip);
                    System.arraycopy(counts, ip, counts, ip+1, wordcount-ip);
                    wordvalues[ip] = word;
                    wordcount++;
                }
                counts[ip]++;
            }
        }
        // output the words in alphabetical order.
        System.out.println("\n-------------");
        System.out.println("\nWord" + "\t" + "freq");
        System.out.println("\n-------------");
        for (int i = 0; i < wordcount; i++) {
            System.out.println(wordvalues[i] + "\t" + counts[i]);
        }
        System.out.println("\n------------");
    }
}

Code Snippets

BufferedReader br = new BufferedReader(new
    InputStreamReader(new FileInputStream(new File("src/FreqWord.java"))));
Enter the String :

-------------

Word    freq

-------------
import  1
java.io.*;  1

------------
public static void main(String[] args) throws IOException {
    // show you know the Java7 language changes...
    try (BufferedReader br = new BufferedReader(new InputStreamReader(
            new FileInputStream(new File("src/FreqWord.java"))))) {
        int wordcount = 0; // the number of unique words we have

        String [] wordvalues = new String[32];
        int [] counts = new int[32];

        String line = null;
        // Using regular expressions is a differentiator
        final Pattern pattern = Pattern.compile("\\w+");
        while ((line = br.readLine()) != null) {
            // Only keep one line at a time in memory.
            Matcher matcher = pattern.matcher(line);
            while (matcher.find()) {
                // use toLowerCase() to show a grasp of the problem
                String word = matcher.group().toLowerCase();
                // use BinarySearch to order the words, which is faster than a scan.
                int ip = Arrays.binarySearch(wordvalues, 0, wordcount, word);
                if (ip < 0) {
                    // word we have not yet seen.
                    ip = -ip - 1;
                    if (wordcount == wordvalues.length) {
                        // grow the word array by about 25% each time we need to.
                        wordvalues = Arrays.copyOf(wordvalues, wordcount + 1 + (wordcount >>>2));
                        counts = Arrays.copyOf(counts, wordvalues.length);
                    }
                    // insert the word in sorted order.
                    System.arraycopy(wordvalues,  ip, wordvalues,  ip+1, wordcount-ip);
                    System.arraycopy(counts, ip, counts, ip+1, wordcount-ip);
                    wordvalues[ip] = word;
                    wordcount++;
                }
                counts[ip]++;
            }
        }
        // output the words in alphabetical order.
        System.out.println("\n-------------");
        System.out.println("\nWord" + "\t" + "freq");
        System.out.println("\n-------------");
        for (int i = 0; i < wordcount; i++) {
            System.out.println(wordvalues[i] + "\t" + counts[i]);
        }
        System.out.println("\n------------");
    }
}

Context

StackExchange Code Review Q#33593, answer score: 10

Revisions (0)

No revisions yet.