How to check if a number is a concatenation of 1, 14 or 144

Viewed 533

I've managed to get the code to check whether or not it's a concatenation of 1, 14, or 144 but the main problem here is that when I print numbers like 144441 it returns "YES" when it should give a "NO."

This problem occurs as long as there are at least 3 fours sandwiched between 2 ones (i.e. 14441, 14444444444441, 1444441)

def magic_num(N):
    magic = N

    while magic in range(1,1000000001):
        if (magic % 1000 == 144):
            magic /= 1000
        elif (magic % 100 == 14):
            magic /= 100
        elif (magic % 10 == 1):
            magic /= 10
        else:
            return"NO"

    return "YES"

N = int(input("Enter an integer between 1 and 10^9: "))
print(magic_num(N));
5 Answers

I think for your case you just need to check that your number only contains 1s and 4s, that it starts with a 1 and that you don't have three or more 4's in a row:

def is_concatenation(n):
    """Returns True if n is a concatenation of 1, 14 and 144"""
    n = str(n)
    return set(n) <= {"1", "4"} and n.startswith("1") and "444" not in n

I really suggest using RegEx (Regular Expression) to handle this issue. You can do that simply like so:

import re

regex = r"^(1+4{,2})+$"
def is_concatenation(N):
    return re.match(regex, str(N)) is not None

Let's test this function over some test-cases:

>>> is_concatentaion(1)
True
>>> is_concatentaion(14)
True
>>> is_concatentaion(144)
True
>>> is_concatentaion(1444)
False
>>> is_concatentaion(14414)
True
>>> is_concatentaion(14414111)
True
>>> is_concatentaion(144414111)
False
>>> is_concatentaion(144441)
False
>>> is_concatentaion(14444444444441)
False
>>> is_concatentaion(1444441)
False

I like the pattern match answer from @Anwarvic. However if you want make your approach work instead of converting it to a string, try this:

def magic_num(magic):

    while magic:
        if (magic % 1000 == 144):
            magic //= 1000
        elif (magic % 100 == 14):
            magic //= 100
        elif (magic % 10 == 1):
            magic //= 10
        else:
            return"NO"

    return "YES"

N = int(input("Enter an integer "))
print(magic_num(N))

You should be doing integer division. Also you just need to check that the result is not 0 as the loop terminator. As a result of that change you do not have to limit the size of the number input either.

You can directly operate on the number parameter passed in. In this context it is only changing the value passed and NOT changing the callers copy of the number passed in, so this is safe to do.

Try this instead

from re import findall, search

def magic_num(n):
    n = str(n)
    
    if search("[^14]", n) or any(len(s) > 2 for s in findall("4+", n)):
        return "NO"
    return "YES"

Here's my way:

n = [1, 14, 144]

def magic_num(N):
    n.sort(reverse=True) # Sort the list from greatest to least
    for number in n:
        if str(number) in N:
            while N != N.replace(str(number),'_',1):
                N = N.replace(str(number),'_',1)
    if N.replace('_','') == '':
        return 'YES'
    return 'NO'

N = input("Enter an integer: ")
print(magic_num(N))

This program will not work if the list isn't sorted from greatest to least.

The reason: Lets say our integer is 14414.

When the program iterates through the list,

if it sees a 1 first, it will replace the first 1 in 14414,

before the program notices the 144 that's supposed to be replaced,

leaving the program with 4414, and obviously, it will return 'NO'.

Related