Problem statement: https://www.hackerrank.com/contests/ncr-codesprint/challenges/spiral-message
You've intercepted an encoded spy message! The message originated as a single line of one or more space-separated words, but it was encoded into an matrix as a clockwise spiral starting in the lower left-hand corner. For example, the diagram below shows the decoding process for an encoded message:
The message is decoded spirally starting from the lower left-hand corner of the matrix and moving in the clockwise direction (i.e., up, right, down, left, up, right, etc.). From the starting position, you must clockwise-traverse the matrix, scanning characters and switching to the next clockwise direction each time you reach a boundary (i.e., an already-scanned character or the end of the matrix). Continue scanning characters in this manner until you've scanned all the matrix's characters into a single decoded string. The word separator for the decoded string is the hash mark (#).
Given n, m, and an encoded message, decode the message and print the number of words in the decoded message.
Input Format
The first line contains two space-separated positive integers describing the respective values of n and m. Each line i of the n subsequent lines contains a string of m characters describing row i of the encoded message.
Constraints
Each word consists of lowercase English alphabetic characters (a to z). The encoded message consists of words and hash marks (#). Each hash mark denotes a single space. 0
Print an integer denoting the number of decoded words.
Sample Input
3 5
a##ar
a#aa#
xxwsr
Sample Output
4
Explanation
The diagram at the top of the challenge demonstrates the decoding process for the given Sample Input. The decoded message is xaa##ar#rswx#aa. Because hash marks denote spaces, we can break the message into four words: xaa, ar, rswx, and aa. Thus, we print 4 as our answer.
My introduction of the algorithm: The algorithm is an easy one of NCR codesprint on HackerRank in Nov. 2016, but I like to ask help for code review. Since in the contest, I made a few mistakes, instead of starting from lower-left corner, the algorithm I did is from upper-left corner; Secondly, base cases: one node, one row, one column I did not test my algorithm.
After the contest, the submission of other players are not available, so I like to ask help here.
I made a few changes, for example, name function to include requirements: 1. start point: lowerLeft 2. spiral message: clockwise Instead of returning the count of decoded message, the function returns the spiral message, I added several test cases to test the spiral message's order is correct.
But, I like to get advice, make the C# solution better. Here is the code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpiralMessage
{
class Program
{
/*
* https://www.hackerrank.com/contests/ncr-codesprint/challenges/spiral-message
*
*
*/
static void Main(string[] args)
{
//RunSampleTestCase();
SpiralMessage();
}
private static void RunTestcases()
{
TestOneChar();
TestOneRow();
TestingOneColumn();
RunSampleTestCase();
}
private static void RunSampleTestCase()
{
IList<string> input = new List<string>();
input.Add("a##ar");
input.Add("a#aa#");
input.Add("xxwsr");
string spiralMessage = SpiralMessageFromLowerLeftClockWise(input);
Debug.Assert(spiralMessage.CompareTo("xaa##ar#rswx#aa") == 0);
var result = spiralMessage.Split('#').ToList();
result.RemoveAll(str => string.IsNullOrEmpty(str));
Debug.Assert(result.Count == 4);
}
/*
* One column test
*/
private static void TestingOneColumn()
{
IList<string> input = new List<string>();
input.Add("a");
input.Add("#");
input.Add("#");
input.Add("a");
input.Add("#");
Debug.Assert(SpiralMessageFromLowerLeftClockWise(input).CompareTo("#a##a") == 0);
}
private static void TestOneRow()
{
IList<string> input = new List<string>();
input.Add("a##a#");
Debug.Assert(SpiralMessageFromLowerLeftClockWise(input).CompareTo("a##a#") == 0);
}
private static void TestOneChar()
{
IList<string> input = new List<string>();
input.Add("a");
Debug.Assert(SpiralMessageFromLowerLeftClockWise(input).CompareTo("a") == 0);
}
private static void SpiralMessage()
{
int[] arr = ToInt(Console.ReadLine().Split(' '));
int rows = arr[0], cols = arr[1];
IList<string> input = new List<string>();
for (int i = 0; i < rows; i++)
{
input.Add(Console.ReadLine().Trim());
}
var result = SpiralMessageFromLowerLeftClockWise(input).Split('#').ToList();
result.RemoveAll(str => string.IsNullOrEmpty(str));
Console.WriteLine(result.Count());
}
/*
* Dec. 8, 2016
* Function spec:
* 1. Clockwise direction
* 2. Start from lower left corner
* 3. String can be counted using the hash mark (#)
* Return:
* Spiral message instead of count of words
*/
private static string SpiralMessageFromLowerLeftClockWise(IList<string> data)
{
int rows = data.Count;
int cols = data[0].Length;
int startX = 0, endX = rows - 1;
int startY = 0, endY = cols - 1;
StringBuilder sb = new StringBuilder();
while (startX <= endX &&
startY <= endY
)
{
int nRows = endX - startX + 1;
int mCols = endY - startY + 1;
bool isOneNode = nRows == 1 && mCols == 1;
bool isOneRow = nRows == 1;
bool isOneCol = mCols == 1;
bool downToUp = false;
bool leftToRight = false;
bool upToDown = false;
bool rightToLeft = false;
// special case handling - one node, one row, one column
if (isOneNode)
downToUp = true;
else if (isOneRow)
{
downToUp = true;
leftToRight = true;
}
else if (isOneCol)
{
downToUp = true;
}
else
{
downToUp = true;
leftToRight = true;
upToDown = true;
rightToLeft = true;
}
// 1. to upward
if (downToUp)
for (int i = endX; i >= startX; i--)
{
char runner = data[i][startY];
sb.Append(runner);
}
// 2. to right
if (leftToRight)
for (int j = startY + 1; j <= endY; j++)
{
char runner = data[startX][j];
sb.Append(runner);
}
// 3. downward
if (upToDown)
for (int i = startX + 1; i <= endX; i++)
{
char runner = data[i][endY];
sb.Append(runner);
}
// 4. to left
if (rightToLeft)
for (int j = endY - 1; j > startY; j--)
{
char runner = data[endX][j];
sb.Append(runner);
}
startX++;
endX--;
startY++;
endY--;
}
return sb.ToString();
}
private static int[] ToInt(string[] arr)
{
int len = arr.Length;
int[] result = new int[len];
for (int i = 0; i < len; i++)
{
result[i] = Convert.ToInt32(arr[i]);
}
return result;
}
}
}
Because in the contest, test cases are kept private, I think that it is a good idea to design some test cases in the design process, special base cases. Best performer spends only less than 10% time I spent in the contest.
"Don't practice 'til you get it right. Practice 'til you can't get it wrong." I like to practice until I cannot get it wrong, specially on easy algorithm. Detail see my coding blog: http://juliachencoding.blogspot.ca/2016/12/hackerrank-ncr-codesprint-spiral-message.html