Rohan Shah
Rohan Shah

Reputation: 489

In depth explanation of algorithm for Designer Door Mat?

I am looking at the Designer Door Mat problem on HackerRank, however the solution is very difficult for me to comprehend.

What I am looking for:

I am looking for a simpler explanation that is more "my level" which I will be able to understand. I already understand all the core concepts of python (loops, different data structures, commonly used functions like enumerate(), etc), but please assume I know nothing more than that in your explanation.

I would especially like explanations regarding any math (however simple) needed for this, and the reasoning behind it.

The solution can be found online with a simple google search, but I can't seem to understand the explanation provided.

Problem copied from above link:

Mr. Vincent works in a door mat manufacturing company. One day, he designed a new door mat with the following specifications:

  • Mat size must be N X M. (N is an odd natural number, and M is 3 times N.)
  • The design should have 'WELCOME' written in the center.
  • The design pattern should only use |, . and - characters.

Sample Designs

Size: 7 x 21 
---------.|.---------
------.|..|..|.------
---.|..|..|..|..|.---
-------WELCOME-------
---.|..|..|..|..|.---
------.|..|..|.------
---------.|.---------

Size: 11 x 33
---------------.|.---------------
------------.|..|..|.------------
---------.|..|..|..|..|.---------
------.|..|..|..|..|..|..|.------
---.|..|..|..|..|..|..|..|..|.---
-------------WELCOME-------------
---.|..|..|..|..|..|..|..|..|.---
------.|..|..|..|..|..|..|.------
---------.|..|..|..|..|.---------
------------.|..|..|.------------
---------------.|.--------------- 

Input Format:

A single line containing the space separated values of N and M

Constraints

  • 5 < N < 101
  • 15 < M < 303

Output Format:

Output the design pattern.

Sample Input:

9 27

Sample Output

------------.|.------------
---------.|..|..|.---------
------.|..|..|..|..|.------
---.|..|..|..|..|..|..|.---
----------WELCOME----------
---.|..|..|..|..|..|..|.---
------.|..|..|..|..|.------
---------.|..|..|.---------
------------.|.------------ 

Upvotes: 0

Views: 162

Answers (1)

trincot
trincot

Reputation: 350167

Looking at the desired output, we can make the following observations:

  • All lines have the same width 𝑚

  • The middle line has "WELCOME" and is padded with "-" characters at both sides to reach that width 𝑚. Looking up whether Python has some method that does this kind of padding, leads us to center

  • The upper half of the output pattern has (𝑛 - 1) / 2 lines, and the same is true for the lower half of the output. This way we get 𝑛 lines in total:

    • (𝑛 - 1) / 2
    • 1 for "WELCOME"
    • (𝑛 - 1) / 2

    As 𝑛 is given to be odd, we can also calculate (𝑛 - 1) / 2 using integer division, which in Python is n // 2

  • These other lines have repetitions of ".|.": the line with index 0 has 1 such pattern, the next one has 3, the next one has 5... So in the top half of the output we see a pattern: if 𝑖 is the line's index, then we need 2𝑖+1 times that ".|." pattern. The rest consists of padding with "-" like above, so we should be able to use center for that.

  • The bottom half is the same but in reverse order. So if we define 𝑖 as the index of the line but counting backwards, then we have the same formula 2𝑖+1 for the number of ".|." patterns to generate.

And that is really it.

Getting the input

First, we need to get the input. There are two words to read from the input which can be expected to represent numbers (but they will be strings at first):

input().split()

To turn those two words into two numbers, we should call int in them. We can use map to perform this action on all words, and we can capture the result into two variables (since we expect two):

n, m = map(int, input().split())

Implementing the "algorithm"

Starting with the top half: to produce the line index, we just need a range. And we can repeat the ".|." pattern using the * operator:

for i in range(n // 2):
    pattern = ".|." * (2 * i + 1)

If you would print(pattern) inside the loop, you'd get something like this:

.|.
.|..|..|.
.|..|..|..|..|.

This pattern needs to be padded with "-" to get a length of 𝑚:

for i in range(n // 2):
    pattern = ".|." * (2 * i + 1)
    line = pattern.center(m, "-")
    print(line)

This will output the top half perfectly:

---------.|.---------
------.|..|..|.------
---.|..|..|..|..|.---

Then we get to the center line. This one is simple:

line = "WELCOME".center(m, "-")
print(line)

And to generate the bottom half, we make sure we have i iterate in descending order this time:

for i in range(n // 2 - 1, -1, -1):
    pattern = ".|." * (2 * i + 1)
    line = pattern.center(m, "-")
    print(line)

Clean up

As we have some code repetition here, we might want to create a separate function for the padding and printing:

def out(line, m):
    print(line.center(m, "-"))

Also, the formula 2𝑖+1 can also be embedded in the range function: with range(1, n, 2) we get the same sequence: 1, 3, 5, ... And the reverse becomes: range(n - 2, 0, -2)

Putting it all together, and eliminating the need of some variables, we get this:

def out(s, m):
    print(s.center(m, "-"))

n, m = map(int, input().split())

for i in range(1, n, 2):
    out(".|." * i, m)

out("WELCOME", m)

for i in range(n - 2, 0, -2):
    out(".|." * i, m)

We can even move the loop logic inside the out function, but it becomes a bit obscure then:

def out(s, m, starttimes, endtimes, step=2):
    for times in range(starttimes, endtimes, step):
        print((s  * times).center(m, "-"))

n, m = map(int, input().split())

out(".|.", m, 1, n)
out("WELCOME", m, 1, 2)
out(".|.", m, n - 2, 0, -2)

Upvotes: 1

Related Questions