10
\$\begingroup\$

I just got back from my interview where I had to solve the following problem:

Write a C++ program that prints the following pattern using nested for loops.

*
***
*****
***
*

Here is my solution:

int inc = 2;
for (int i = 1; i >= 1; i += inc){
    for (int j = 0; j < i; j++ )
        std::cout<<'*';
    std::cout<<endl;
    if ( i == 5 )
        inc = -2;
}

I'm just curious to know if there are better solutions (any criteria for better) or just different approaches.

\$\endgroup\$

6 Answers 6

8
\$\begingroup\$

This answer is simpler and shorter:

for(;0;)
    for(;0;)
        ;
std::cout << "*\n***\n*****\n***\n*\n";

Perhaps you'd do better to consider how you could generalise your answer by parametrising it e.g. by the depth and the angle of the tree it outputs.

\$\endgroup\$
6
  • 8
    \$\begingroup\$ If this is an interview question and you came to me with this answer I would not give you the position -- because you are obviously too clever for your own good. And therefore for our team. \$\endgroup\$
    – towi
    Jun 12, 2012 at 7:10
  • 3
    \$\begingroup\$ Why? It's important to recognise when a simple, hard-coded solution is sufficient and not waste resources parametrising code in dimensions that are never used (YAGNI). Instead, one should explore the problem space with the customer to determine where parametrisation is required. \$\endgroup\$
    – ecatmur
    Jun 12, 2012 at 7:40
  • \$\begingroup\$ I see that this would start a long discussion.. smile. Well, the customer said he wanted a nested-loop. This is of course nothing a real customer in a real project would say, but here it is a requirement. Often one has to interpret a vague specification and come up with the solution the customer really wanted, despite of what he said. And I'd say he asked for useful loops, even when he did not say that. \$\endgroup\$
    – towi
    Jun 12, 2012 at 8:03
  • 4
    \$\begingroup\$ What’s “too clever for your own good” actually supposed to mean? It’s just an empty adage that’s begging the question, and not applicable in this context. Yes, the answer is clever. Too clever? No – why? And in particular, it answers the crucial question: which parts of this answer are supposed to be the movable parts? If we don’t have this information, we can’t design a good, general-purpose answer without over-engineering. \$\endgroup\$ Jun 12, 2012 at 12:03
  • 1
    \$\begingroup\$ @KonradRudolph, Ecatmur's solution follows the letter of the requirement, but only barely. The question is a thought puzzle, intended to test the candidate's problem-solving abilities. ecatmur's answer is a "smart-a**" answer that refuses to play by the rules of the problem. \$\endgroup\$
    – Duncan C
    Mar 12, 2014 at 12:30
8
\$\begingroup\$

Edit Oh well, not using nested for... Sorry about that

int inc = 2;
for (int i = 1; i >= 1; i += inc){
    std::cout<<std::string(i,'*')<<endl;
    if ( i == 5 )
        inc = -2;
}
\$\endgroup\$
5
\$\begingroup\$

This allows for reusability - any number of lines, whatever increment, to get the sideways triangle format:

int NUMBER_LINES = 5;
int INC = 2;
int stars = 1;
for( int i = 1; i <= NUMBER_LINES; i++ )
{
   for( int j = 0; j < stars; j++ )
      std::cout<<'*';
   std::cout<<std::endl;
   if( i < (NUMBER_LINES / 2 + NUMBER_LINES % 2) )
      stars += INC;
   else if( NUMBER_LINES % 2 == 0 && i == NUMBER_LINES / 2 )
      ;
   else
      stars -= INC;
}
\$\endgroup\$
1
  • \$\begingroup\$ Even better if you change NUMBER_LINES and INC to const int. \$\endgroup\$ Jun 20, 2012 at 8:58
5
\$\begingroup\$

@ecatmur hit the nail on the head: unless we know which are the moving parts, the hard-coded answer is the best. Otherwise, we can only guess what’s supposed to be variable:

  1. Does the number of lines change?
  2. Does the step increment change?
  3. Does the printed symbol change? E.g. + instead of *, or maybe even [], necessitating a new data type (string instead of char).

Every solution will necessarily make some assumptions about these questions so it’s good to clear them up beforehand, or at least to be aware of them. As an interviewer, this is what I’d expect as the answer to this question.

\$\endgroup\$
3
\$\begingroup\$

I'm not sure about better, but this qualifies as a "different" solution.

int count;
for (int i = -2; i <= 2; i++){
    count = 1 + 2 * (2 - abs(i));
    for (int j = 0; j < count; j++ )
        std::cout<<'*';
    std::cout<<std::endl;
}
std::cin >> count;
return 0;
\$\endgroup\$
3
\$\begingroup\$

A friend of mine missed the part about the for loops and came up with the following recursive version:

const int MAX_STARS = 5;
const int INC = 2; 
const int STARTING_STARS = 1;

void printRowOfStars(int length){
         while( length-- > 0){
             std::cout<<'*';                
         }
         std::cout<<'\n';
     }

void printTriangle(int i = STARTING_STARS){
     assert (MAX_STARS - STARTING_STARS) % INC == 0;
     printRowOfStars(i);
     if (i == MAX_STARS)
        return;
     printTriangle(i+INC);
     printRowOfStars(i);
     }

int main()
{
    printTriangle();
    system("pause");
    return 0;
}

I liked it so I thought why not post it

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.