Skip to main content

Control Flow Practice

Number Patterns 2

Hello coders : )

I hope you went through previous articles (I am optimistic, I'll take it as a yes 🤭). Till now we solved many questions on star patterns and numeric patterns with 0s and 1s. These were the problems that utilised only 1 or 2 variables in the entire pattern. But now we'll use different mathematical numbers for creating number patterns.

💡
Suggestion: These patterns and logics might be confusing initially. But the only key to understand them is dry run. Dry running the given examples alongwith the code and the logic is very essential to understand what's happening there. So always dry run the code side by side, as you write down the code to grasp the concepts : )

Excited already? Let's go🚀

Numeric Square Patterns

In the last article, we practiced square patterns only by using 0s and 1s but now let's play with more numbers. Patterns would be same, user would input the no. of of rows and columns but now the pattern would be using a range of numbers and you would be writing the codes for the same.

So get ready coders! Here comes the problems..

Pattern 1

Input

rows = 5
cols = 5

Output

11111
22222
33333
44444
55555

Intuition

If you have read our previous articles, the you must have been familiar with the concept of using nested loops, outer one for printing rows and inner one for printing columns. But the question arises for what to print exactlty?

Here if you observe carefully, we print 1 in 1st row, 2 in 2nd row etc. So doesn't it make it obvious that we have to print our current row's value in that row. In coding terms, we'll print current row's value inside our inner loop.

Logic

  1. Run a loop on i from 1 to rows for iterating through rows.
  2. Run a loop on j from 1 to cols for iterating through columns.
  3. For each row the current row number is printed. Hence, in the inner loop, print the value of i to print current row number.
Solution
#include <iostream>
using namespace std;

int main() {
    int rows, cols;

    /* Input rows and columns from user */
    cout << "Enter number of rows: "<<endl;
    cin >> rows;
    cout << "Enter number of columns: "<<endl;
    cin >> cols;

    for(int i = 1; i <= rows; i++) {
        for(int j = 1; j <= cols; j++) {
            // Print the current row number
            cout << i;
        }

        cout << endl;
    }

    return 0;
}

Pattern 2

Input

rows = 5
cols = 5

Output

12345
12345
12345
12345
12345

Intuition

If we relate this to our previous problem, then it's exactly the same with just a minor change. Here rather than printing the current row, we print current column. Now, can you guess the change that we would have to do in our previous problem's code??

Rather than printing current_row's value, we'll print current_column's value. Simple, isn't it?

Logic

  1. Run a loop on i from 1 to rows for iterating through rows.
  2. Run a loop on j from 1 to cols for iterating through columns.
  3. For each column the current column number is printed. Hence, in the inner loop, print the value of j to print current column number.
Solution
#include <iostream>
using namespace std;

int main() {
    int rows, cols;

    /* Input rows and columns from user */
    cout << "Enter number of rows: "<<endl;
    cin >> rows;
    cout << "Enter number of columns: "<<endl;
    cin >> cols;

    for(int i = 1; i <= rows; i++) {
        for(int j = 1; j <= cols; j++) {
            // Print the current row number
            cout << j;
        }

        cout << endl;
    }

    return 0;
}

Pattern 3

Input

rows = 5
cols = 5

Output

12345
23456
34567
45678
56789

Intuition

Let's think once that we have to write this pattern manually. Then what I'll do is, write the first no. and then keep incrementing it as per the no. of columns. Example I'll write 2 for 2nd row and then increment it till 5 columns aren't filled.

Now let's focus on what would be our first value?
For 1st row, first value is 1
For 2nd row, first value is 2
For 3rd row, first value is 3
and so on.

Decoding this, we get that the first value of any row is equal to the current row number. But till what value do we need to increment it in following columns. Since, we know that we have to increment it till 5th column(total column value) starting from first column, means we have to go from current_row value to current_row+cols.

Understand it with observation:
If our current_row=1, then we go till 1+5=6
If our current_row=2, then we go till 2+5=7
If our current_row=2, then we go till 3+5=8
and so on.

These observations imply that our inner loop would run from current_row till current_row+cols. Note that the last value would be excluded and the inner loop would be constructed in the same way.

Logic

  1. Run a loop on i from 1 to rows for iterating through rows.
  2. Run a loop on j from row count i and go till i+cols like 'for(int j=i; j<i+cols; j++)'.
  3. Inside this loop we'll simply print j's value to achieve the desired output.
Solution
#include <iostream>
using namespace std;

int main() {
    int rows, cols;

    /* Input rows and columns from user */
    cout << "Enter number of rows: "<<endl;
    cin >> rows;
    cout << "Enter number of columns: "<<endl;
    cin >> cols;

    for(int i = 1; i <= rows; i++) {
        for(int j = i; j < i + cols; j++) {
            cout << j;
        }

        cout << endl;
    }

    return 0;
}

Tired? Don't worry we are already midway💪 Think of the sense of achievement that you are going to have after ending this article! If not, then keep going 😄


Pattern 4

Input

rows = 5
cols = 5

Output

1  2  3  4  5
6  7  8  9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25

Intuition

Let's think this pattern from a lazy person's perspective (yup that's me). This pattern seems like a single sequence of no. where I just add an enter when my desired columns (here 5) are filled. The sequence of numbers is a simple one: 1,2,3,4,5,6.........

According to the pattern, I'll simply start writing from 1 and keep incrementing the value till 5 columns are filled. As soon as I write the value for 5th column, I'll move to the next row and continue the sequence of no.s

This gives me 2 hints:
1. I need an external value to keep a track of the number in the sequence.
2. Keep printing this external value with adding appropriate breaks when a column ends

To manage the rows and columns, we'll simply run a nested loop with outer loop from 1 to rows and inner loop from 1 to cols to iterate over rows and columns. We'll define a variable k=1 outside these loops and keep incrementing it with the inner loop (every changing column).

Logic

  1. Run a loop on i from 1 to rows for iterating through rows.
  2. Run a loop on j from 1 to cols for iterating through columns.
  3. To print this pattern we will use another variable outside the loop: k=1 which will keep track of the number to be printed. Each time the number gets printed we will increment the value of k to get the next number.
Solution
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int rows, cols, k = 1;

    /* Input rows and columns from user */
    cout << "Enter number of rows: "<<endl;
    cin >> rows;
    cout << "Enter number of columns: "<<endl;
    cin >> cols;

    for(int i = 1; i <= rows; i++) {
        for(int j = 1; j <= cols; j++, k++) {
        // setw function is a C++ manipulator which stands for set width
        // Here width's set for value 3 to give proper spacing between the values
            cout << setw(3) << k;
        }

        cout << endl;
    }

    return 0;
}

Now let's see some pattern division problems. These problems are solved by dividing the given patterns into 2 or more different patterns. Sounding scary enough? Don't forget the initial suggestion: dry run is the key and you are good to go : )

Pattern 5

Input

rows = 5
cols = 5

Output

55555
54444
54333
54322
54321

Intuition

This pattern if observed carefully can be divided into two parts:

5----
54---
543--
5432-
54321

-5555
--444
---33
----2
-----

This indicates that there need to be 2 inner loops for each pattern inside one outer loop. The results of both the inner loops when combined will give us the desired final output.

To iterate through rows, we'll use a similar loop from 1 to rows as we used in our previous problems but need to break the columns.

Pattern 1: To print first part of pattern, we are printing the columns value in a decreasing fashion.
For row 1: We start from 5 and print all values that are greater than 4.
For row 2: We start from 5 and print all values that are greater than 3.
For row 3: We start from 5 and print all values that are greater than 2.
and so on.

What we observe here is that we are starting from the total columns value (5) and goes till 5-current_row. This indicates that we need to run a loop from 5 to 5-current_row or in generic terms: from cols to cols-current_row.

Pattern 2: Carefully observe the value that's printed and its frequency.
Row 1: Value = 5 Frequency = 4
Row 2: Value = 4 Frequency = 3
Row 3: Value = 3 Frequency = 2
and so on.

Decoding the pattern, value to be printed is equal to current row from the opposite end ( last row value for first row, 2nd last row value for 2nd row etc.)
This value is nothing but, total rows - current row +1.
For the frequency, it's equal to total columns - current row.

Hence we need to run the loop from (1 to total columns - current_row) and print (total rows - current row +1).

Logic

  1. To iterate through rows, run an outer loop from 1 to rows (where rows is total rows to be printed).
  2. Pattern 1: Run an inner loop on j starting from total columns going till total columns – current_row. In this example, total columns value is 5. Inside this loop keep printing the value of j.
  3. Pattern 2: Run another inner loop from 1 to total columns – current_row. Inside this loop print the value of rows – current row + 1.
Solution
#include <iostream>
using namespace std;

int main() {
    int rows, cols, i, j;

    // Input rows and columns from user
    cout << "Enter number of rows: "<<endl;
    cin >> rows;
    cout << "Enter number of columns: "<<endl;
    cin >> cols;

    // i refers to current row
    for (i = 1; i <= rows; i++) {
    
    //Loop 1 runs j from cols to cols - current_row and print this j value
        for (j = cols; j > cols - i; j--) {
            cout << j;
        }
        
    //Loop 2 runs j from 1 to cols - current_row and print row-i+1 value
        for (j = 1; j <= cols - i; j++) {
            cout << rows - i + 1;
        }

        cout << endl;
    }

    return 0;
}

Pattern 6

Input

rows = 5
cols = 5

Output

55555
44445
33345
22345
12345

Pattern Division

This pattern if observed carefully can be divided into two parts:

5555-
444--
33---
2----
-----

----5
---45
--345
-2345
12345

Relating to the last problem, we need 2 inner loops for each pattern inside one outer loop. The results of both the inner loops when combined will give us the desired final output.

Outer loop

For the outer loop, we need to observe that the pattern seems decreasing in our first pattern, and so we need to compare the current rows to the opposite ones (print 5 for first, 4 for second, 3 for third etc.)
There's a trick that I use to escape from this first-last analogy but promise me you'll keep it secret🤫

An active person like you would suggest run a loop from 1 to rows and print total rows - current row + 1. But a lazy person like me would simply run a loop from rows to 1 and print the current_row value. (It would be automatically reversed🤭)

Same thing we are going to do in this and in many upcoming articles. We would run our loop from 5 to 1 (rows to 1) so that we can simply print the current row rather than total rows - current row + 1. Remember that the other way is also right but this one will will simplify our variables.

Note: In this question, current_row reference means the opposite row only (i.e like 5, 4, 3, 2, 1) and not the actual current_row (1,2,3,4,5) due to the decreasing loop

Inner loop 1

Focusing on the value's frequency in first question, it's decreasing (4->3->2->1: i decreases with increasing row). This pattern when generalised is nothing but current_row - 1. Hence, we would run a loop from 1 to current_row - 1. Also, the printed value in first pattern is 5,4,3,2,1 i.e. the current_row's value. Hence, we would print current_row's value and 'current_row - 1' times.

Inner loop 2

In the 2nd pattern, we are directly printing the column's value. The range of this value clearly ends at the last row. But where does it start?

We print from 5th column in 1st row
from 4th column in 2nd row
from 3rd column in 3rd row
and so on.

The starting column is nothing but the 'current_row' of this pattern. Hence, the loop will run from current_row to cols and prints the column value.

NOTE: Notice that how much the change in our outer loop (from rows to 1) has simplified our code in both the patterns. In other words, emphasise on the direct usage of current_row variable: we have directly used it multiple times without needing to change it as in the case of increasing outer loop (from 1 to rows).

Logic

  1. To iterate through rows, run an outer loop on i from rows to 1 (where rows is total rows to be printed).
  2. Pattern 1: Run an inner loop on j from 1 to i-1 printing the i value.
    Note: Value to be printed is i as i's value is decreasing with every row as required by the pattern. This is the reason that we made our outer loop from rows to 1 rather than 1 to rows.
  3. Pattern 2: Run an inner loop on j starting from i to the total no. of columns and keep printing the jth value.
Solution
#include <iostream>
using namespace std;

int main() {
    int rows, cols;

    /* Input rows and columns from user */
    cout << "Enter number of rows: " << endl;
    cin >> rows;
    cout << "Enter number of columns: " << endl;
    cin >> cols;

    for (int i = rows; i >= 1; i--) {
        for (int j = 1; j <= i - 1; j++) {
            cout << i;
        }

        for (int j = i; j <= cols; j++) {
            cout << j;
        }

        cout << endl;
    }

    return 0;
}

Tired or confident? Former might be the case but it's temporary and the latter one is permanent! These patterns can be mind-boggling but as suggested before - dry run the codes! Dry running examples while solving problems is a habit that you should always follow while solving any type of problem because if you do that, you'll retain and understand it more as your brain will always relate it to an example.

"Remember Practice leads to Perfection".

Now let's end this article and be ready for what's coming next : )