Engaged Employer
Give these two API’s, plus an enum and struct: enum Alignment { Left, Right, Center } class Size { int width; int height; } // returns the dimensions for a character Size getCharSize(char c); // Draws a character at the specified location, with // (0,0) being the top left. This method does NOT // understand the newline character. Once rendered, // there is no way to delete a character. void drawCharAt(char c, int x, int y); Show how you would implement code for this function: void renderText(String text, int screenWidth, Alignment alignment);
Anonymous
My original idea (and what I implemented during the interview) was to split the incoming text into an array of lines. Each line containing what words could fit on a single line within the screen width. Then iterate through the array of lines and render each line (making sure to take into account the specified alignment). void renderText(String text, int screenWidth, Alignment alignment) { NSArray *arrayOfWordsFromText = [text componentsSeparatedByCharacter:@" "]; NSMutableArray *wordBreaks = [[NSMutableArray alloc] init]; CGFloat totalWidth = 0.0; // float might be overkill since char sizes are ints… int wordIndex = 0; int lineNumber = 0; [wordBreaks addObject: @0]; // first line starts at character index 0 for(eachWord in arrayOfWordsFromText) { totalWidth += getWordSize(eachWord); // if totalWidth is greater than screenWidth, go to the next line if totalWidth > screenWidth { totalWidth = 0.0; // I forgot this line in my interview… [wordBreaks addObject: @wordIndex]; lineNumber++; } else { // take into account spaces between words until end of the line totalWidth += getCharSize(" "); } wordIndex++; } // get last word index also into the wordBreaks array [wordBreaks addObject: @wordIndex]; // now iterate through the array and render each line CGFloat maxYForThisLine = 0.0; // again, maybe I should have used an int instead of float int lineNumber = 0; for(;;) { // join words from the arrayOfWords together between point A (or 0) // and point B (or the end of the arrayOfWords) int indexA = [wordBreaks objectAtIndex: lineNumber]; int indexB = [wordBreaks objectAtIndex: lineNumber+1]; NSArray *arrayOfWordsForThisLine = [arrayOfWordsFromText subarrayWithRange: NSMakeRange(indexA, indexB)]; NSString *lineToRender = [arrayOfWordsForThisLine componentsJoinedByString: @" "]; maxYForThisLine = renderEachLine( lineToRender, y, alignment ); // break out at the very last line if lineNumber >= ([wordBreaks count] - 1) break; } } - (CGFloat) getWordSize(String *word) { CGFloat totalWidth = 0.0; for(char eachCharacter in word) { totalWidth+=getCharSize(eachCharacter); } return totalWidth; } - (CGFloat) renderEachLine(String line, int yPosition, Alignment alignment) { if (alignment != Left) { // calculate width again // ^^ which is a performance bug, which I realized as I was coding this up for(eachCharacter in line) { totalWidth += getCharSizeWordSize(eachWord); // if totalWidth is greater than screenWidth, go to the next line if totalWidth > screenWidth { totalWidth = 0.0; // I forgot this line in my interview… [wordBreaks addObject: @wordIndex]; } else { // take into account spaces between words until end of the line totalWidth += getCharSize(" "); } } } Immediately after implementing all that in front of the interviewer, I realized and pointed out to him that a better approach would have been to also save the character index representing where one line goes to the next and also the calculated pixel width (and height) of each line. These things could have been saved in custom objects or structures kept track of in an array. And that would have 1) saved CPU time (and big O time) having to rescan each line to find the width in renderEachLine and 2) probably simplified the code.
Check out your Company Bowl for anonymous work chats.