1. Introduction

In this tutorial, we’re going to explore several ways to print a triangle in Java.

There are, naturally, many types of triangles. Here, we’re going to explore only a couple of them: right and isosceles triangles.

2. Building a Right Triangle

The right triangle is the simplest type of triangle we’re going to study. Let’s have a quick look at the output we want to obtain:

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

Here, we notice that the triangle is made of 5 rows, each having a number of stars equal to the current row number. Of course, this observation can be generalized: for each row from 1 to N, we have to print r stars, where r is the current row and N is the total number of rows.

So, let’s build the triangle using two for loops:

public static String printARightTriangle(int N) {
    StringBuilder result = new StringBuilder();
    for (int r = 1; r <= N; r++) {
        for (int j = 1; j <= r; j++) {
            result.append("*");
        }
        result.append(System.lineSeparator());
    }
    return result.toString();
}

3. Building an Isosceles Triangle

Now, let’s take a look at the form of an isosceles triangle:

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

What do we see in this case? We notice that, in addition to the stars, we also need to print some spaces for each row. So, we have to figure it out how many spaces and stars we have to print for each row. Of course, the number of spaces and stars depends on the current row.

First, we see that we need to print 4 spaces for the first row and, as we get down the triangle, we need 3 spaces, 2 spaces, 1 space, and no spaces at all for the last row. Generalizing, we need to print N – r spaces for each row.

Second, comparing with the first example, we realize that here we need an odd number of stars: 1, 3, 5, 7…

So, we need to print r x 2 – 1 stars for each row.

3.1. Using Nested for Loops

Based on the above observations, let’s create our second example:

public static String printAnIsoscelesTriangle(int N) {
    StringBuilder result = new StringBuilder();
    for (int r = 1; r <= N; r++) {
        for (int sp = 1; sp <= N - r; sp++) {
            result.append(" ");
        }
        for (int c = 1; c <= (r * 2) - 1; c++) {
            result.append("*");
        }
        result.append(System.lineSeparator());
    }
    return result.toString();
}

3.2. Using a Single for Loop

Actually, we have another way that consists only of a single for loop – it uses the Apache Commons Lang 3 library.

We’re going to use the for loop to iterate over the rows of the triangle as we did in the previous examples. Then, we’ll use the StringUtils.repeat() method in order to generate the necessary characters for each row:

public static String printAnIsoscelesTriangleUsingStringUtils(int N) {
    StringBuilder result = new StringBuilder();

    for (int r = 1; r <= N; r++) {
        result.append(StringUtils.repeat(' ', N - r));
        result.append(StringUtils.repeat('*', 2 * r - 1));
        result.append(System.lineSeparator());
    }
    return result.toString();
}

Or, we can do a neat trick with the substring() method.

We can extract the StringUtils.repeat() methods above to build a helper string and then apply the String.substring() method on it. The helper string is a concatenation of the maximum number of spaces and the maximum number of stars that we need to print the rows of the triangle.

Looking at the previous examples, we notice that we need a maximum number of N – 1 spaces for the first row and a maximum number of N x 2 – 1 stars for the last row:

String helperString = StringUtils.repeat(' ', N - 1) + StringUtils.repeat('*', N * 2 - 1);
// for N = 10, helperString = "    *********"

For instance, when N = 5 and r = 3, we need to print ”  *****”, which is included in the helperString variable. All we need to do is to find the right formula for the substring() method.

Now, let’s see the complete example:

public static String printAnIsoscelesTriangleUsingSubstring(int N) {
    StringBuilder result = new StringBuilder();
    String helperString = StringUtils.repeat(' ', N - 1) + StringUtils.repeat('*', N * 2 - 1);

    for (int r = 0; r < N; r++) {
        result.append(helperString.substring(r, N + 2 * r));
        result.append(System.lineSeparator());
    }
    return result.toString();
}

Similarly, with just a bit more work, we could make the triangle print upside down.

4. Complexity

If we take a look again at the first example, we notice an outer loop and an inner loop each having a maximum of N steps. Therefore, we have O(N^2) time complexity, where N is the number of rows of the triangle.

The second example is similar — the only difference is that we have two inner loops, which are sequential and do not increase the time complexity.

The third example, however, uses only a for loop with N steps. But, at every step, we’re calling either the StringUtils.repeat() method or the substring() method on the helper string, each having O(N) complexity. So, the overall time complexity remains the same.

Finally, if we’re talking about the auxiliary space, we can quickly realize that, for all examples, the complexity stays in the StringBuilder variable. By adding the entire triangle to the result variable, we cannot have less than O(N^2) complexity.

Of course, if we directly printed the characters, we’d have constant space complexity for the first two examples. But, the third example uses the helper string and the space complexity would be O(N).

5. Conclusion

In this tutorial, we’ve learned how to print two common types of triangles in Java.

First, we’ve studied the right triangle, which is the simplest type of triangle we can print in Java. Then, we’ve explored two ways of building an isosceles triangle. The first one uses only for loops and the other one takes advantage of the StringUtils.repeat() and the String.substring() method and helps us write less code.

Finally, we’ve analyzed the time and space complexity for each example.

As always, all the examples can be found over on GitHub.