Archive for the ‘Programming’ Category

Triangle Identification – C++ solution and test code

Tuesday, September 23rd, 2008

Here is another interview coding question that I have heard of.

You have to write a function to identify the triangle type. You have to return a number between 1 or 4 to identify either a valid triangle type or an error.

The solution is very simple requiring only one condensed line of code to identify each triangle type. Two lines of code identify error cases. One of the error cases identifies input with 0 or negative lengths. The other error case identifies line lengths that don’t make a triangle or which make a segment (thanks to Yabba for pointing out these error cases).

As an exercise you could try to extend the solution to identify right-angled triangles as well.

const int SCALENE = 1;
const int ISOSCELES = 2;
const int EQUILATERAL = 3;
const int ERROR = 4;

int TriangleType(int x, int y, int z)
{
	if ((x + y <= z) || (x + z <= y) || (z + y <= x)) return ERROR;
	if (x<=0 || y<=0 || z<=0) return ERROR;
	if (x == y && y == z) return EQUILATERAL;
	if (x == y || y == z || z == x) return ISOSCELES;
	return SCALENE;
}

The more interesting code comes from testing the function. To test the function I pass in a series of triangle side lengths. I also pass in the expected result. If the actual result matches the expected result then the test passes.

The test data is written in a way that allows each test to be defined in a single line of code which makes it very easy to extend.

This easy extendibility was fortunate as my original version of this solution missed out the cases where the line lengths don’t make a triangle (e.g. 1, 1, 5), and where the line lengths make a segment (e.g. 2, 2, 4).

void TriangleTest()
{
const int testDataSize = 14;

int testData[testDataSize][4] = {
	{9, 9, 9, EQUILATERAL},
	{4, 5, 5, ISOSCELES},
	{5, 4, 5, ISOSCELES},
	{5, 3, 3, ISOSCELES},
	{0, 0, 0, ERROR}, // 0 number checks
	{0, 1, 2, ERROR},
	{1, 0, 2, ERROR},
	{1, 2, 0, ERROR},
	{-1, -1, -1, ERROR}, // negative number checks
	{-1, 1, 2, ERROR},
	{1, -1, 2, ERROR},
	{1, 2, -1, ERROR},
	{2, 2, 4, ERROR}, // line segment not a triangle
	{1, 1, 5, ERROR} // not a triangle
};

for (int i=0; i<testDataSize; ++i)
{
	int result = TriangleType(
		testData[i][0], testData[i][1], testData[i][2]);
	if (result == testData[i][3])
	{
		cout << " Pass: triangleType("
			<< testData[i][0] << ", "
			<< testData[i][1] << ", "
			<< testData[i][2] << ")==" << result << endl;
	}
	else
	{
		cout << "!Fail: triangleType("
			<< testData[i][0] << ", "
			<< testData[i][1] << ", "
			<< testData[i][2] << ")==" << result
			<< " Expected: " << testData[i][3] << endl;
	}
}
}

Reverse the words in a sentence – C++ solution and test code

Tuesday, September 16th, 2008

Here is a solution to the standard interview questions of reversing the letters in the words of a sentence. It is a more complex version of the even more common “reverse a string” question. I also include my test code.

There are two main parts to this. The first identifies where the word boundaries are. The second reverses the letters between two positions in the array.

The wordStart and wordEnd variables keep track of the word boundaries. We first look for the start of the word and then the end and store the positions. These values are then passed to ReverseWord along with the character array. ReverseWord does some simple character swapping to reverse the word.

void ReverseWords(char string[])
{
	int length = StringLength(string);
	int wordStart = -1;
	int wordEnd = -1;
	for (int i=0; i<length; ++i)
	{
		if (string[i] == ' ' && wordStart == -1)
		{
			continue;
		}
		else if (wordStart == -1)
		{
			wordStart = i;
		}
		if (wordStart != -1 && string[i] == ' ')
		{
			wordEnd = i-1;
			ReverseWord(string, wordStart, wordEnd);
			wordStart = -1;
			wordEnd = -1;
		}
	}
	if (wordStart != -1)
	{
		wordEnd = length-1;
		ReverseWord(string, wordStart, wordEnd);
	}
}

void ReverseWord(char string[], int wordStart, int wordEnd)
{
	int midPoint = (wordStart+wordEnd)/2;
	for (int l=wordStart, r=wordEnd; l<=midPoint; ++l, --r)
	{
		char tmp = string[l];
		string[l] = string[r];
		string[r] = tmp;
	}
}

Here is the test code. For each test a character array is passed to the word reversing function. The result is then compared against the expected result. If they match the test passes. If they don’t match then the test fails. I’ve tried to test the obvious cases. You could easily find flaws in the word reversal function but it is probably good enough to get you onto the next question.

void ReverseWordsTest()
{
	char test1[] = "cat and dog";
	char expected1[] = "tac dna god";
	ReverseAndCheck(test1, expected1);

	char test2[] = "cat and dog ";
	char expected2[] = "tac dna god ";
	ReverseAndCheck(test2, expected2);

	char test3[] = " cat and dog";
	char expected3[] = " tac dna god";
	ReverseAndCheck(test3, expected3);

	char test4[] = " cat and dog ";
	char expected4[] = " tac dna god ";
	ReverseAndCheck(test4, expected4);

	char test5[] = "cat  and dog";
	char expected5[] = "tac  dna god";
	ReverseAndCheck(test5, expected5);

	char test6[] = "catanddog";
	char expected6[] = "goddnatac";
	ReverseAndCheck(test6, expected6);

	char test7[] = "";
	char expected7[] = "";
	ReverseAndCheck(test7, expected7);
}

void ReverseAndCheck(char string[], char expected[])
{
	ReverseWords(string);
	if (MatchingStrings(string, expected))
	{
	cout << " Pass: " << string << endl;
	}
	else
	{
	cout << "!Fail: " << string << " != " << expected << endl;
	}
}

bool MatchingStrings(char string1[], char string2[])
{
	int length = StringLength(string1);
	if (length != StringLength(string2))
	{
		return false;
	}

	for (int i=0; i<length; ++i)
	{
		if (string1[i] != string2[i])
		{
			return false;
		}
	}

	return true;
}

int StringLength(char string[])
{
	int index = 0;
	char s = string[index];
	while (s)
	{
		++index;
		s = string[index];
	}
	return index;
}

Picking the 5th from last element in a singly linked list

Monday, August 18th, 2008

Here’s another of those fun coding interview puzzles. The kind that companies like Microsoft or Google might ask you. Given a singly linked list, select the 5th from last element. I’m writing the solution in C++ but the solution in Java would be almost identical. I’m also putting up my test code.

The restrictions are – you can only make one pass of the list, and you don’t know the length of the list.

First we need to define our linked list element. All it needs is to store a value, and a pointer to the next element in the list.

class Element
{
public:
	Element(int valueArg) : value(valueArg), next(NULL) {}
public:
	int value;
	Element* next;
};

Here is the actual solution. As we are only allowed one pass of the list we use two pointers. The second pointer trails 5 places behind the first pointer. When the first pointer reaches the end of the list we simply return whichever element the second pointer is pointing to.

We need to take care of the special case where the list has less than 5 elements – including the case where the list has 0 elements!

Element* FifthFromLast(Element* root)
{
	Element* current = root;
	int fromLast = 5;
	while (fromLast > 0 && current)
	{
		current = current->next;
		--fromLast;
	}

	if (fromLast != 0)
	{
		return NULL; // less than 5 items in list
	}

	Element* fifthFromLast = root;
	while (current)
	{
		current = current->next;
		fifthFromLast = fifthFromLast->next;
	}

	return fifthFromLast;
}

Here is the test code which tests the most common cases for this problem. As the parameter to FifthFromLast is the root element we can simulate a shorter list by passing in one of the middle elements.

void LinkedListTest()
{
	Element* one = new Element(1);
	Element* two = new Element(2);
	Element* three = new Element(3);
	Element* four = new Element(4);
	Element* five = new Element(5);
	Element* six = new Element(6);
	Element* seven = new Element(7);
	Element* eight = new Element(8);
	Element* nine = new Element(9);
	Element* ten = new Element(10);

	one->next = two;
	two->next = three;
	three->next = four;
	four->next = five;
	five->next = six;
	six->next = seven;
	seven->next = eight;
	eight->next = nine;
	nine->next = ten;

	cout << "Test: find 5th from last in 10 item list" << endl;
	Element* fifthFromLast = FifthFromLast(one);
	if (fifthFromLast == six)
	{
		cout << " Pass" << endl;
	}
	else
	{
		cout << "!Fail" << endl;
	}

	cout << "Test: with 4 item list - expect NULL" << endl;
	Element* nullReturnCheck = FifthFromLast(seven);
	if (nullReturnCheck == NULL)
	{
		cout << " Pass" << endl;
	}
	else
	{
		cout << "!Fail" << endl;
	}

	cout << "Test: FifthFromLast(NULL) - expect NULL" << endl;
	nullReturnCheck = FifthFromLast(NULL);
	if (nullReturnCheck == NULL)
	{
		cout << " Pass" << endl;
	}
	else
	{
		cout << "!Fail" << endl;
	}

	// clean up
	Element* current = one;
	while (current)
	{
		Element* next = current->next;
		delete current;
		current = next;
	}
}

This is the output from running the tests.

Test: find 5th from last in 10 item list
 Pass
Test: with 4 item list - expect NULL
 Pass
Test: FifthFromLast(NULL) - expect NULL
 Pass