Initial part of finding second highest frequency characters in a text was discussed previously and covered the scenarios where a single character is the most frequent. Since this is the continuation post of that, I strongly recommend you to read the first part before this. The intention of this second post is to cover the scenarios at which the previous program failed, specifically the scenarios where multiple characters are of the same frequencies.Previous production codes can return only one character as the second most frequent. If there are multiple characters matching the criteria, the return type of the code most be modified to a character array. Along with that change, all the previous test cases must be modified to support the returned character array. When there are no matches, it is better to expect the code to return an empty array rather than null, so the test cases has to be modified to reflect that.
Similar to the previous post, new test cases are identified prior to writing any implementation code. While supporting these multiple character scenarios, both map based and sorting based programs are modified to satisfy the test cases. You can find those below in this post.
New Test Cases
1. shouldReturnCorrectWhenManyMostFrequentsAndOneSecondMostFrequent()> result should be this second most frequent character
2. shouldReturnCorrectWhenManyMostFrequentsAndManySecondMostFrequents()
> result should be these second most frequent characters
Above two test cases along with the modified previous test cases are written as follows.
package com.digizol.puzzle;
import static java.lang.Character.valueOf;
import static org.junit.Assert.assertEquals;
import java.util.*;
import org.junit.*;
public class SecondFrequentCharactersTest {
private MapBasedFrequentCharacters sut;
@Before
public void setup() {
sut = new MapBasedFrequentCharacters();
// sut = new SortBasedFrequentCharacters();
}
@Test
public void shouldReturnCorrectWhenManyMostFrequentsAndOneSecondMostFrequent() {
// both i & c are the most frequent, y is the second most frequent
assertEquals(valueOf('y'),
valueOf(sut.getSecondMostFrequent("iiixiiyycbcccc")[0]));
}
@Test
public void shouldReturnCorrectWhenManyMostFrequentsAndManySecondMostFrequents() {
// both i & c are the most frequent, x & y are the second most frequent
char[] secondMostFrequents = sut.getSecondMostFrequent("iiixxiiyycbcccc");
assertEquals(2, secondMostFrequents.length);
List<Character> expected = new ArrayList<Character>();
expected.add('x');
expected.add('y');
for (int i = 0; i < secondMostFrequents.length; i++) {
expected.remove(Character.valueOf(secondMostFrequents[i]));
}
assertEquals(0, expected.size());
}
// previous test cases are modified as below
@Test
public void shouldReturnNullForEmptyText() {
assertEquals(0, sut.getSecondMostFrequent("").length);
}
@Test
public void shouldReturnNullForTextOfSameCharacter() {
assertEquals(0, sut.getSecondMostFrequent("dddddddd").length);
}
@Test
public void shouldReturnCorrectCharWhenTextHasTwoCharsOneBeingMostFrequent() {
assertEquals(valueOf('y'), valueOf(sut.getSecondMostFrequent("iiiiiyiiiii")[0]));
}
@Test
public void shouldReturnCorrectOneForATextWithOneBeingSecondMostFrequent() {
// most frequent is 'i', second most is 'd'
assertEquals(valueOf('d'),
valueOf(sut.getSecondMostFrequent("iaibicidieidif")[0]));
}
}Production Code
Similar to previous post, map based solution is modified first followed by the sorting based one to satisfy all above test cases.Map based solution
Previous map based solution had the character frequencies recorded in the map. At the 'second most frequent character' finding logic, two 'char' variables were used. With the new scenarios there are be multiple characters for both most frequents and second most frequents, so the char variables can be replaced with two lists as shown below.package com.digizol.puzzle;
import java.util.*;
import java.util.Map.Entry;
public class MapBasedFrequentCharacters {
public char[] getSecondMostFrequent(String text) {
char[] charArray = text.toCharArray();
// calculate char frequencies
Map<Character, Integer> charFrequenciesMap = new HashMap<Character, Integer>();
// loop1
for (char c : charArray) {
int frequency = 1;
if (charFrequenciesMap.get(c) != null) {
frequency = charFrequenciesMap.get(c) + 1;
}
charFrequenciesMap.put(c, frequency);
}
int currentMostFrequency = 0;
int currentSecondMostFrequency = 0;
List<Character> mostFrequentChars = new ArrayList<Character>();
List<Character> secondMostChars = new ArrayList<Character>();
// find second most frequent char
Iterator<Entry<Character, Integer>> charFrequencies = charFrequenciesMap
.entrySet().iterator();
// loop2
while (charFrequencies.hasNext()) {
Entry<Character, Integer> entry = charFrequencies.next();
char currentChar = entry.getKey();
int frequency = entry.getValue();
if (frequency > currentMostFrequency) {
secondMostChars.clear();
secondMostChars.addAll(mostFrequentChars);
mostFrequentChars.clear();
mostFrequentChars.add(currentChar);
currentSecondMostFrequency = currentMostFrequency;
currentMostFrequency = frequency;
} else if (frequency == currentMostFrequency) {
mostFrequentChars.add(currentChar);
} else if (frequency > currentSecondMostFrequency) {
secondMostChars.clear();
secondMostChars.add(currentChar);
currentSecondMostFrequency = frequency;
} else if (frequency == currentSecondMostFrequency) {
secondMostChars.add(currentChar);
}
}
char[] result = new char[secondMostChars.size()];
for (int i = 0; i < secondMostChars.size(); i++) {
result[i] = secondMostChars.get(i);
}
return result;
}
}
Sorting based solution
Previous sorting based solution had sorted the list of 'Frequency' in the descending order of frequencies; and returned the second element in the list for the second most frequent. However with the new scenarios, there can be multiple most frequent characters so the second element may contain another most frequent character. Similarly, there can be multiple 'second most frequent' elements in the list. So it is required to traverse through the list from the start and extract an array of elements with the second most frequency. Following is the modified program.package com.digizol.puzzle;
import java.util.*;
public class SortBasedFrequentCharacters {
public char[] getSecondMostFrequent(String text) {
char[] charArray = text.toCharArray();
Arrays.sort(charArray);
List<Frequency> list = new ArrayList<Frequency>();
char previous = '\u0000';
Frequency f = null;
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
if (i == 0 || previous != c) {
f = new Frequency(1, c);
list.add(f);
previous = c;
} else {
f.count += 1;
}
}
Collections.sort(
list,
new Comparator<Frequency>() {
public int compare(Frequency fr0, Frequency fr1) {
// sort in descending order
return fr1.count - fr0.count;
}
}
);
// supporting multiple characters being most frequent
int currentFrequency = 0;
boolean secondMostFound = false;
int start = -1;
int end = -1;
for (int i = 0; i < list.size(); i++) {
Frequency frequency = list.get(i);
if (i == 0) {
currentFrequency = frequency.count;
} else if (currentFrequency != frequency.count) {
if (secondMostFound) {
end = i;
break;
} else {
secondMostFound = true;
start = i;
end = i;
}
}
}
char values[] = null;
if (secondMostFound) {
List<Frequency> secondMostFrequencies = list
.subList(start, end + 1);
values = new char[secondMostFrequencies.size()];
for (int i = 0; i < secondMostFrequencies.size(); i++) {
values[i] = secondMostFrequencies.get(i).character;
}
} else {
values = new char[0];
}
return values;
}
private class Frequency {
int count;
char character;
public Frequency(int count, char character) {
this.count = count;
this.character = character;
}
}
}
In summary, the puzzle can be solved in many ways as shown in this series of articles. One important point to note is the use of test cases to identify the scenarios before any production code. As you may have already noticed, the same set of test cases were used to test two different implementations. If you have noticed any scenarios that are not covered here, please let me know via comments section so that I can address those.



Finding second highest frequency character in a text is last weeks Thursdays Dzone Code Puzzle. Intention of this post is to try and work out this interview oriented problem in Java with you by explaining the way I am approaching this task. In return, both you and myself can learn through a discussion.
History of Firefox starts in 2002, when a new flavor of Mozilla was released under the name Phoenix. With the release of 0.6 it was renamed as as Mozilla Firebird, but it lasted only for two releases. This most popular name "Firefox" was introduced with the 0.8 release, and it continues as of the time of this post. Initially, Firefox made a major release every two years with minor releases in between.
Monthly

HTTP basic authentication with headers is one of the username & password based methods of securing access to web sites, web applications and web services. Purpose of this article is to analyze the details of this approach by explaining how to encode a pair of username & password as a basic authentication header string as well as to decode the authentication string generated from the web clients like browser or soapIU; and the example is implemented with Java.
Wikipedia, the One-stop website for most of the queries ranging from a tiny cell to the universe has a notice on top of the site claiming the 'Terms of use' (ToU) is changing tomorrow. Even though I am a regular user of Wikipedia, was never worried to read their 'ToU'. However this noticed lead me to compare the
Google has decided to shutdown Buzz in few weeks raising the closed product count to around 20. With the growing popularity of GMail, Google introduced Buzz in February 2010 as an integrated product to GMail which could easily attract users into Google's Social Networking product.
As a proof of above statement, Google Plus considered Privacy as the main concern and came up with a feature named Circle. Google Plus web interface made it simple to understand how this new privacy feature functions. Another good restriction is the age limit; only users over 18+ are allowed to create Plus accounts as Google is still working on proper safety additions.
Subversion 1.7, first feature release after moving to Apache Software Foundation is announced. Starting from this, Subversion will be released under Apache License, version 2 instead of the modified Apache license used by Tigris.
Before reading further; just try and answer the question "Are you leaving the office on-time or late continuously?" and keep the answer to yourself. Most of the employees in an organization have to follow a plan, stick to a schedule. Also there are estimates for the tasks that are pending completion. As an employee in an organization, if you are not leaving the office on time as planned, you must be spoiling the working culture
If you are in the habit of working late continuously, consider changing it by considering the above facts as reasons. Read Seven ways to
Firefox Address bar (or Location bar) is not visible suddenly and browser looks some what similar to the image shown here. Though Navigation bar is visible; there is no space to enter a URL? Sometimes users face this issue though it is not that common. This article shows how to resolve the issue; considering the user is not an expert in configuring Firefox. 
October 5th is going to be a sad day to technology lovers. As you all are aware; Steve Jobs, co-founder of Apple Inc. has passed away at the age of 56 on 5th October 2011. As common to everybody, he also did not have a smooth flow of nicely organized stages in his life; but Steve was praising that as the most important part that created the path to his innovations. One such example is the tragedy of getting fired from the Apple company which he co-founded. You already know this fact, but how would you have responded?