Wednesday, November 19, 2008

Solution to the Weighted Cities Problem

As promised, here's the code for the Weighted Cities Problem.

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

import java.util.*;

public class City {

String CityName;
int Population; //cumulative population

City (String S, int pop){

CityName = S;
Population = pop;
}
}

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

import java.util.*;

class CityGenerator {

List Cities;
List CumulativePops; //cumulative population
Random rGen;
int CurrentTotalPopulation;
int FinalTotalPopulation;

public CityGenerator(List Cities_List) {
Cities = Cities_List;
City CurrentCity;
rGen = new Random();
CumulativePops = new ArrayList();
CurrentTotalPopulation = 0;

//Calculate the cumulative totals
for (City c : Cities){
CurrentCity = c;
CurrentTotalPopulation += CurrentCity.Population;
CumulativePops.add(CurrentTotalPopulation);
}
FinalTotalPopulation = CurrentTotalPopulation;
}

public City getCity()
{
//runs in log(n) time as it uses a binary search
int randCumulativePop = rGen.nextInt(FinalTotalPopulation);
int cityIndex = Collections.binarySearch(CumulativePops,randCumulativePop);
//binarySearch returns minus one unless its an exact match
if(cityIndex < 0) {
cityIndex *= -1;
cityIndex -= 1;
}
City city = Cities.get(cityIndex);
return (city);
}


public String verifySample(int sampleSize)
{
int citycount = Cities.size();
int[] IncrementTotals = new int[citycount];
int CityIndex;
Integer count;
City C1, C2;
HashMap hm = new HashMap();

for(int i=0;i C1 = getCity();
count = (Integer)(hm.get(C1));
if (count == null) {hm.put(C1, 1);}
else {hm.put(C1,new Integer(count.intValue()+1)); }
}

String output = new String();
for(int j=0;j C2 = Cities.get(j);
output += C2.CityName + ": " + hm.get(C2) + "\n";
}
return output;
}

public static void CreateData (List Cities) {

Cities.add(new City("San Francisco", 20000));
Cities.add(new City("New York", 50000));
Cities.add(new City("Boston", 20000));
Cities.add(new City("Toronto", 7500));
Cities.add(new City("Cambridge", 2500));
}

public static void main(String[] args) {

List Cities = new ArrayList();
CreateData(Cities); //Add sample data
CityGenerator cGen = new CityGenerator(Cities);
System.out.println(cGen.verifySample(100000)); //Verify with large test run
}
}


Here's a brief summary of what's happening. Define a class City that associates each cities name with its population, and create a List of all the cities in your sample data. Pass this to the constructor of CityGenerator, and use it to build a second list of cumulative totals. From here, all the action happens in the getCity() method. In this method, we generate a random number between 1 and the final total population, then we do a binary search on our list of cumulative totals to pull out a random city name. This approach gives us each city name with a proability that is proportional to its population over total population of all the cities, which was the requirement. The method verifySample() simply runs a high volume of tests, and stores all the results in a frequency table, implemented via a HashMap.

Sunday, November 16, 2008

Singing about Beer

Rejoice, for today is an auspicious day. Today, you will be learning about Java while singing about beer.

Let's start with a speed challenge. What happens when you run the following code? Does it compile? Does it run? Is there a small bug somewhere? If so, how quickly can you spot it? How quickly can you fix it?

------------------- BEER 1 -------------------

public class BottlesOfBeer {

int numberBottles;

BottlesOfBeer(int num){
numberBottles = num;
}

public void SingBeerSong() {

String bottle = "bottles";

while (numberBottles > 0) {

if (numberBottles ==1){ bottle = "bottle"; }
System.out.println (numberBottles + " " + bottle + " of beer on the wall...");
System.out.println (numberBottles + " " + bottle + " of beer! ");
System.out.println ("Take one down and pass it around");
numberBottles--;

System.out.println (numberBottles + " " + bottle + " of beer on the wall!\n");

}
} // end of SingBeerSong

public static void main(String[] args){

BottlesOfBeer b = new BottlesOfBeer(99);
b.SingBeerSong();

}
} // End of BottlesOfBeer Class

------------------- BEER 2 -------------------

Here's a less concise version:

27 public class NinetyNineBottles {
28
29 private static int NUMBER_BOTTLES_OF_BEER_ON_THE_WALL = 99;
30
31
32 /**
33 * Print the 99 bottles of beer song to the console.
34 */
35 public void printSong()
36 {
37 int nBottles = NUMBER_BOTTLES_OF_BEER_ON_THE_WALL;
38 while (nBottles > 0) {
39 String verse = "";
40 if (nBottles > 1) verse += verseForNBottles(nBottles);
41 else verse += finalVerse();
42
43 System.out.println(verse);
44
45 nBottles--;
46 }
47
48 }
49
50
51 public static void main(String[] args) {
52 NinetyNineBottles nnb = new NinetyNineBottles();
53 nnb.printSong();
54 }
55
56 //private methods
57
58 /**
59 * Return verse for N bottles of beer (where N is > 1)
60 * @param nBottles the current number of bottles of beer on the wall.
61 * @return verse appropriate for the number of bottles of beer on the wall.
62 */
63 private String verseForNBottles(int nBottles)
64 {
65 if (nBottles <= 0) return "";
66
67 String verse = nBottles + " bottles of beer on the wall,\n" +
68 nBottles + " bottles of beer!\n" +
69 " Take one down,\n" +
70 " Pass it around,\n";
71 int bottlesLeft = nBottles - 1;
72 if (bottlesLeft > 1)
73 verse += bottlesLeft + " bottles of beer on the wall!\n\n";
74 else
75 verse += "1 bottle of beer on the wall!\n\n";
76
77 return verse;
78 }
79
80
81 /**
82 * Print final verse for one bottle of beer.
83 * @return the final verse (one bottle of beer on the wall).
84 */
85 private String finalVerse()
86 {
87 return "1 bottle of beer on the wall,\n" +
88 "1 bottle of beer!\n" +
89 " Take one down,\n" +
90 " Pass it around,\n" +
91 "No more bottles of beer on the wall!\n\n";
92 }
93
94 }
95

------------------- BEER 3 -------------------

Here's a more concise version:

class bottles
{
public static void main(String args[])
{
String s = "s";
for (int beers=99; beers>-1;)
{
System.out.print(beers + " bottle" + s + " of beer on the wall, ");
System.out.println(beers + " bottle" + s + " of beer, ");
if (beers==0)
{
System.out.print("Go to the store, buy some more, ");
System.out.println("99 bottles of beer on the wall.\n");
System.exit(0);
}
else
System.out.print("Take one down, pass it around, ");
s = (--beers == 1)?"":"s";
System.out.println(beers + " bottle" + s + " of beer on the wall.\n");
}
}
}

------------------- BEER 4 -------------------

Here's a relatively clean, minimalist version (my favorite!)

class B {
public static void main(String[]a) {
int n=99;
String o=" bottle";
String e=" of beer";
String w=" on the wall\n";
String f1= "No more bottles of beer on the wall, no more bottles of beer\n";
String f2= "Go to the store and buy some more, 99 bottles of beer on the wall\n";
String b,v;

while(n>0){
b=n+o+(n==1?"":'s')+e;
v = b+w+b+"\nTake one down, and pass it around\n";
System.out.println(v);
if (--n==0)System.out.println(f1+f2);
}
}
}

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

If you're still thirsty for more, I've just discovered a
website with literally thousands of implementations.

Check it out: http://www.99-bottles-of-beer.net/

Tuesday, November 11, 2008

Weighted Cities Problem

Here's an interesting challenge problem:

A given list of city names and their corresponding populations is provided. Write a method in Java that will return a random city from a list of cities. Ensure that for each call to this method, a city name is returned with probability proportional to its population over total population of all cities. Your final solution should be working code that runs in O(log N) time.

Example:

City Name Population

San Francisco = 20,000
New York = 50,000
Boston = 20,000
Toronto = 7,500
Cambridge = 2,500

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

run (10,000 iterations)

San Francisco: 1898
New York: 4943
Boston: 2140
Toronto: 768
Cambridge: 251

I'll publish a solution to this in a few days.

Monday, November 10, 2008

The Repeating Substring Problem

Here's a fun algorithm problem.

Given a string, find the longest repeating substring (if more than one exists of the same length, return the substring that is ordered first in accord with the natural ordering of Strings)

Example: "to be or not to be, that is the question"

Result: to be

There are various ways to solve this problem.

Here is one solution that includes an application of a suffix tree.

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

import java.util.Arrays;

public class CommonString {
static int loopCnt = 0;
public static void main(String[] args) {
String a = "to be or not to be, that is the question";
String ret = commonString(a);
System.out.println(ret);
}
public static String commonString(String s) {

int totalLength = s.length();
String[] suffixTree = new String[totalLength];
for (int i = 0; i < totalLength; i++) {
suffixTree[i] = s.substring(i, totalLength);
}
Arrays.sort(suffixTree);
String ret = "";
for (int i = 0; i < totalLength - 1; i++) {
loopCnt++;
String temp = commonPrefix(suffixTree[i], suffixTree[i+1]);
if (temp.length() > ret.length())
ret = temp;
}
System.out.println("Length = " + totalLength + " loopCnt = " + loopCnt);
return ret;
}

public static String commonPrefix(String s, String t) {
int lower = s.length();
if(t.length() lower=t.length();
for (int i = 0; i < lower; i++) {
if (s.charAt(i) != t.charAt(i))
return s.substring(0, i);
}
return s.substring(0, lower);
}

}

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

Arrays.sort(suffixTree);

Since it's used in the above program, lets briefly discuss the Arrays class.

This class contains various methods for manipulating arrays (such as sorting and searching). Arrays is also a member of the Java Collection Framework. In this case, we're invoking the sort method while passing the method an array of Objects, so this method will sort the specified array of objects into ascending order, according to the natural ordering of its elements. I haven't double checked this, but I'm guessing that for Strings, this relates to the ASCII values or Unicode values of its characters.

After reflecting a bit on this problem, it seems to me that you could also solve it by hashing, as follows:

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

for (i =1; i {
select all substrings of length string.length()-i and hash them, with the string as the key, and the frequencies as the value.

as soon as you find a substring where frequency = 2, finish hashing the substrings of this length and then break out of the for loop.
}

Traverse the substrings of length (string.length-i), to build a list of all substrings with frequency >=2, sort these according to the natural ordering of strings, and return the first one in your list.
------------------------------------------------------------------------

In total, there are (n(n+1))/2 possible substrings. The hashing is constant time, the traversals are linear time, and I assume that the final sorting at the end is n*log(n), so the total complexity remains n squared in a worst case.

I haven't thought about it too much, but my impression is that the above algorithm is probably just as fast as the suffix tree approach. Anyone care to comment on this?


Sunday, November 2, 2008

Iterators, and the Enhanced For Loop

As soon as you've learned about the Iterator, Java lets you hide it while still using it. Once you get past the initial complexity of this, the result is clean, elegant code.

-------------------------------------------------------
import java.util.*;

public class ExampleClass {

public static void main(String[] args){

ArrayList list1 = new ArrayList();
list1.add("STRING1");
list1.add("STRING2");
list1.add("STRING3");

TestMethod(list1);
}

static void TestMethod(Collection c) {
for (Iterator i = c.iterator(); i.hasNext();){
System.out.println (i.next()); }
}
}

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

Let's review the ideas from the previous post. Object c instantiates an ArrayList of Strings. ArrayList is an implementation of Collection, which extends Iterable. Iterable is an interface that includes method iterator(), which returns an Iterator object. We're assigning this Iterator object to i, then we're invoking its hasNext() and next() methods to iterate through the Collection. Got it?

It all works, yet there is some clutter here. The iterator variable "i" occurs three times in each loop, which allows for various kinds of subtle mistakes.

In comparison, the enhanced for loop clears out all of this clutter. Take a look at the following code:

void TestMethod(Collection c) {
for (String s : c) { System.out.println (s); }
}

When you see the colon (:) read it as “in.” The loop above reads as “for each String s in Collection c.” This term "For Each" is a general idiom for traversing items in a collection, and is found other object oriented languages such as Perl, PHP, Python, .NET, and many others. Whether you refer to it as the enhanced for loop or the "For Each" loop, it's all the same. This enhanced for loop doesn't require you to explicitly declare the Iterator, but behind the scenes, the compiler is using it implicitly.

This enhanced for loop can also be used with arrays. Instead of hiding the iterator, it hides the index variable. For example, here's a way to calculate the sum of the values in an int array:

// Returns the sum of the elements in the array

int getSum(int[] a) {
int sum = 0;
for (int i : a) // "for each integer 'i' in array 'a' "
sum+= i;
return sum;
}

Before we wrap up Iterators, there are a few more points to discuss.

- - - - -

import java.util.*;

public class ExampleClass {
public static void main(String[] args) {
ArrayList list1 = null;
for (String s : list1) {
System.out.println("Next String: " + s); }
}
}

Will this code compile? The answer is yes, but a null pointer exception will be thrown. The compiler doesn't do null pointer checks before iterating over collections.

- - - - -

What happens if the underlying Collection is modified while the iteration is in progress? I suppose this is roughly equivalent to asking what happens if you modify the track just before a train passes over it. Maybe nothing. Or maybe a train wreck.

How to prevent this? So far we've seen two of the three methods in the iterator interface, hasNext() and next(). The third method is remove(). This method removes the last element returned by the iterator, and can only be invoked once for each call to next().

Here's an example:

static void TestMethod(Collection c) {
for (Iterator i = c.iterator(); i.hasNext(); i.next() )
{ i.remove(); }

As long as you use the remove() method, you should be safe. If you try to do something else, you're on your own.

The Java API documenation puts it this way:

"The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method."

sounds ominous, doesn't it?

Now for a few last details. If the remove method is part of the Iterator, and if the Iterator is hidden within the design of the enhanced for loop, how can you remove objects from the collection while you're iterating through it? The answer is, you can't.

This is a limitation of the enhanced for loop. If you need to call remove(), then don't hide your Iterator.

As for other types of changes to the Collection, I'm not yet clear how you'd create them anyway. If you try to assign a new object to your collection during the iteration, the new object will NOT be assigned to the collection element.

For example:

--------------------------------------------------------
import java.util.*;


class Demo {

int x;

Demo(int t)
{x = t;}

void setValue (int t) { x = t; }

int getValue () { return x; }

}


public class ExampleClass {

public static Collection DemoCollection() {

ArrayList list = new ArrayList();

list.add(new Demo(1));
list.add(new Demo(2));
list.add(new Demo(3));
return list;
}

public static void main(String[] args) {
ExampleClass ec = new ExampleClass();
Collection list = DemoCollection();
for (Demo d : list) {
d = new Demo(5);}
for (Demo d : list) {
System.out.println(d.getValue());
}
}
}

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

This program prints out

run:
1
2
3

As you can see, the original values are still intact.


Question:

In the code above, what happens if you replace

for (Demo d : list) {
d = new Demo(5);}

with

for (Demo d : list) {
d.setValue(5);}

?

Will the output change? If so, why is this?

Saturday, November 1, 2008

A brief look at the interfaces in the java collections framework

Prior to JDK 1.2, the data structures provided by the Java platform included certain limitations that could complicate application development. For example, deleting or adding to an array would require reshuffling, and sorting required extra code. To improve on these issues, The Java Collections Framework was created; you can access it by importing java.util.

There's a lot to say about this Framework. The tools here are incredibly useful. Questions about this Framework often provide the first filter in technical interviews.

Let's take a look at the six interfaces contained in this Framework.

Collection (extends Iterable)

The Collection interface serves as the main root of the framework hierarchy. A collection simply represents a group of objects known as its elements. Some types of collections allow duplicate elements, others don't. Some order their elements, and some don't. Notice how the Collection interface extends Iterable. We'll come back to this later.

Set (extends Collection)

A Set is a Collection that doesn't allow for duplicate elements.

SortedSet (extends Set)

A SortedSet is still a Set, so it also doesn't allow for duplicate elements. In addition, it maintains its elements in some kind of ascending order. The rules that define this order are part of each particular implementation.

Map

If you've used Hashtable, you're familiar with the idea of a Map. The Map collection lets you store pairs of elements, termed "keys" and "values". A Map can't contain duplicate keys; each key maps to at most one value.

SortedMap (extends Map)

A SortedMap is a Map that maintains its mappings in ascending key order.

List (extends Collection)

A List is an ordered Collection that allows for duplicates. A List allows each element to be accessed by its integer index, giving precise control over where each element is inserted.

Queue (extends Collection)

The Queue interface implements the Collection interface and usually supports a FIFO (First In First Out) ordering. Along with the basic Collection operations, a Queue also includes additional insertion, extraction, and inspection operations.

The FIFO ordering doesn't always get implemented. A priority queue is an example of this, which orders elements according to some kind of priority structure. However the ordering is implemented, the head of the queue is always defined as the element that is next removed. In a FIFO queue, new elements are inserted at the tail of the queue, but that's not the case for other kinds of queues. Every implementation of Queue must specify its own ordering rules.

-----

Earlier we noted that the Collection interface extends an interface named Iterable. This detail can create some initial confusion, so let's unpack this.

There are two separate interfaces to keep track of here, one is named Iterable, and the other is named Iterator.

Iterable includes just one method, named "iterator", which returns an Iterator object over a set of elements. The point here is that if you're creating an object from a class that extends Iterable, you can be sure that there's a rule for iterating through these objects.

Iterator is an interface that defines an iterator over a collection. This Iterator ensures that you have the basic methods you need for this iteration. There are just three methods:

hasNext();

next();

remove();

What does this buy us? The answer is more elegant code.

Since all Collections extend this Iterable interface, we can create an enhanced version of the for loop that uses an Iterator to iterate through the objects contained in a Collection. We'll cover this in the next post.

You should note that Map and SortedMap do not extend Collection, and hence are not inherently Iterable. As a result, Maps do not provide an iterator() method. A Set of keys can be obtained from the Map, and one can iterate over that. This means that the ordering depends on the type of Map you're working with.

TreeMap elements are ordered by key.

HashMap elements will be in an unpredictable order.

LinkedHashMap elements will be ordered by entry order or last reference order, depending on the type of LinkedHashMap.

---------------------------------------------
Here are some review questions to help ground this theory with a few example situations:

For each of the following types of data, what interface should be used?

* Names of people standing in line

* Words used in a book, and their associated frequencies

* Names randomly chosen from a lottery

* A list of conference rooms in a building

* People waiting to receive a liver donation

* A schedule of classes

* A shuffled deck of cards

Challenge: See if you can write the code for an implementation of one these interfaces.

First Post

















This is a blog for anyone who wants to know more about Java. If you're just starting out and haven't yet studied basic data types and operators, methods, classes, interfaces, inheritance, exception handling, or multithreading, you'll find these posts a bit difficult to follow. Once you have covered these essentials, everything should make sense. I'm striving to make each post clear and easy to understand. If I slip up on this, please point it out to me and I'll fix it.

Alex

lessonsinjava@gmail.com