Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ min-public-methods=0
# Maximum number of public methods for a class (see R0904).
max-public-methods=20

# Minimum line length for functions/classes that require docstrings, shorter ones are exempt.
docstring-min-length=10


# checks for
# * external modules dependencies
Expand Down Expand Up @@ -263,7 +266,7 @@ notes=FIXME,XXX,TODO
[FORMAT]

# Maximum number of characters on a single line.
max-line-length=90
max-line-length=120

# Maximum number of lines in a module
max-module-lines=1000
Expand Down
Empty file added leetcode/math/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions leetcode/math/lc263_ugly_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Write a program to check whether a given number is an ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not
ugly since it includes another prime factor 7.

Note that 1 is typically treated as an ugly number.
"""


def is_ugly_number(number):
"""
Returns True if the number is an ugly number.
:param number: the number
:return: True or False
"""
if number <= 0:
return False
if number == 1:
return True

primes = {2, 3, 5}
# keep dividing until it reaches 1 or some other number

while dividable_by_primes(number, primes):
for prime in primes:
if number % prime == 0:
number /= prime
return number == 1


def dividable_by_primes(number, primes):
"""
Returns True if number is dividable by at least one of numbers in the list of `primes`
"""
return any(number % prime == 0 for prime in primes)
117 changes: 117 additions & 0 deletions leetcode/math/lc273_integer_to_english_words.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""
Convert a non-negative integer to its english words representation.
Given input is guaranteed to be less than 2^31 - 1.

For example,
123 -> "One Hundred Twenty Three"
12345 -> "Twelve Thousand Three Hundred Forty Five"
1234567 -> "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"

"""


class Solution(object):
""" The mighty solution - silly pylint requires a docstring """

THOUSAND = 1000
HUNDRED = 100

DIVISION_TO_SUFFIX = {
0: '',
1: 'Thousand',
2: 'Million',
3: 'Billion'
}

INT_TO_ENGLISH = {
1: 'One',
2: 'Two',
3: 'Three',
4: 'Four',
5: 'Five',
6: 'Six',
7: 'Seven',
8: 'Eight',
9: 'Nine',
10: 'Ten',
11: 'Eleven',
12: 'Twelve',
13: 'Thirteen',
14: 'Fourteen',
15: 'Fifteen',
16: 'Sixteen',
17: 'Seventeen',
18: 'Eighteen',
19: 'Nineteen',
20: 'Twenty',
30: 'Thirty',
40: 'Forty',
50: 'Fifty',
60: 'Sixty',
70: 'Seventy',
80: 'Eighty',
90: 'Ninety'
}

def number_to_words(self, num):
"""
:type num: int
:rtype: str
"""

if num < 0 or num > 2**31 - 1:
raise ValueError('Invalid input: num must be non-negative and less than 2^31 - 1')

if num == 0:
return 'Zero'

# fast track
try:
return self.INT_TO_ENGLISH[num]
except KeyError:
pass

# keep dividing...
division_count = 0
words = []

while num > 0:
# change / to //
num, residual = num // self.THOUSAND, num % self.THOUSAND
if residual:
words.insert(0, self._helper(residual, suffix=self.DIVISION_TO_SUFFIX[division_count]))
division_count += 1
return ' '.join(words)

def _helper(self, num, suffix=''):
"""num is less than 1000"""

if num == 0:
return ''

words = []

# get hundreds
hundreds = num // self.HUNDRED
if hundreds:
words.append(self.INT_TO_ENGLISH[hundreds])
words.append('Hundred')

# get last two digits
last_two = num % self.HUNDRED
if last_two:
# fast track if possible
try:
words.append(self.INT_TO_ENGLISH[last_two])
except KeyError:
ones = num % 10
tens = (num % self.HUNDRED) - ones
if tens:
words.append(self.INT_TO_ENGLISH[tens])
if ones:
words.append(self.INT_TO_ENGLISH[ones])

# apply suffix
if suffix:
words.append(suffix)
return ' '.join(words)
File renamed without changes.
45 changes: 45 additions & 0 deletions leetcode/math/test_lc263_ugly_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Test file `lc263_ugly_number.py`
"""
# pylint: disable=no-self-use

import random

import pytest

from leetcode.math.lc263_ugly_number import is_ugly_number


class TestIsUglyNumber(object):
""" The mighty test suite to the mighty solution. """

PRIMES = [2, 3, 5]

@pytest.mark.parametrize('test_input', [
0,
-1234
])
def test_non_positive(self, test_input):
assert not is_ugly_number(test_input)

def test_one(self):
assert is_ugly_number(1)

@pytest.mark.parametrize("test_input", PRIMES)
def test_primes(self, test_input):
assert is_ugly_number(test_input)

def test_multiple_of_primes(self):
turns = random.randint(0, 20)
number = 1
for _ in range(turns):
number *= random.choice(self.PRIMES)
assert is_ugly_number(number)

def test_ugly_factor(self):
the_uglies = [7, 11, 13, 17, 29]
turns = random.randint(0, 20)
number = random.choice(the_uglies)
for _ in range(turns):
number *= random.choice(self.PRIMES)
assert not is_ugly_number(number)
44 changes: 44 additions & 0 deletions leetcode/math/test_lc273_integer_to_english_words.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
Test file `lc273_integer_to_english_words.py`
"""

import pytest

from leetcode.math import lc273_integer_to_english_words


class TestNumberToWords(object):
""" Test the number to words function. """

SOLUTION = lc273_integer_to_english_words.Solution()

def test_zero(self):
number = 0
assert self.SOLUTION.number_to_words(number) == 'Zero'

def test_negative(self):
number = -1
with pytest.raises(ValueError):
self.SOLUTION.number_to_words(number)

def test_large_number(self):
number = 2**32
with pytest.raises(ValueError):
self.SOLUTION.number_to_words(number)

def test_trailing_zero(self):
number = 10000000
assert self.SOLUTION.number_to_words(number) == 'Ten Million'

def test_full_of_numbers(self):
number = 2134435666
assert self.SOLUTION.number_to_words(number) == 'Two Billion One Hundred Thirty Four Million Four Hundred ' \
'Thirty Five Thousand Six Hundred Sixty Six'

def test_below_one_thousand(self):
number = 434
assert self.SOLUTION.number_to_words(number) == 'Four Hundred Thirty Four'

def test_zeros(self):
number = 101010101
assert self.SOLUTION.number_to_words(number) == 'One Hundred One Million Ten Thousand One Hundred One'