Problem 17 : Number letter counts
If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.
If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?
NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of “and” when writing out numbers is in compliance with British usage.
1. 数的字母计数
如果从1到5的数是用单词写出来:one, two, three, four, five,那么总共使用的字母为 3 + 3 + 5 + 4 + 4 = 19。
如果从1到1000的所有数(含1000)用单词写出来,用到多少个字母呢?
注意:不要计算空格或连字符。例如,342 (three hundred and forty-two) 包含23个字母,115 (one hundred and fifteen) 包含20个字母。在写出数时,要使用“and”以符合英国用法。
2. 求解分析
首先,我们要知道1到1000个数用英语单词写出来的所有类型:
“one”, “two”, “three”, “four”, “five”, “six”, “seven”,“eight”, “nine”, “ten”, “eleven”, “twelve”, “thirteen”, “fourteen”,“fifteen”,“sixteen”, “seventeen”, “eighteen”, “nineteen”, “twenty”,“thirty”, “forty”, “fifty”, “sixty”, “seventy”, “eighty”, “ninety”,“hundred”, “thousand”, “and”
另外,要搞清楚每个数用单词写出的方法,主要是使用"and"。
然后,每种单词的字母个数可以在先算出来,保存在一个数组里,最后组合以下就算出最后的字母的个数。
3. C++ 代码实现
类PE0017的类图如下:
-
全局变量numberString 是字符串数组,保存所有32种关键字字符串。
-
成员变量m_digits[]用于保存每个数的数字,最多四个。 成员变量m_lettersArray[]用来保存32种类型的字符数。
-
成员函数 getDigitsOfNumber(int number) 把数number的取每一位,结果保存在成员变量数组m_digits里。
-
成员函数 getUnitValue() 返回个位数的数字。
-
成员函数 getDecadeValue() 返回十位数的数字。
-
成员函数 getHundredValue() 返回百位数的数字。
-
构造函数PE0017() 遍历所有全局字符串数组 numberString, 给成员变量m_lettersArray赋初值。
-
成员函数 getLettersSumOfNumber(int number) 计算一个数number的字符个数。
-
成员函数 getSumOfLetters(int max_number) 统计从1到max_number的所有数的字母个数。
C++ 代码
#include <iostream>
#include <vector>
#include <string>
#include <cassert>
using namespace std;
const int max_types = 32;
string numberString[max_types]={"", "one", "two", "three", "four", "five",
"six", "seven","eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen","fifteen","sixteen", "seventeen", "eighteen", "nineteen",
"twenty","thirty", "forty", "fifty", "sixty", "seventy", "eighty",
"ninety","hundred", "thousand", "and"};
/*
#define C_blank 0 // blank
#define C_1 1 // one
#define C_2 2 // two
#define C_3 3 // three
#define C_4 4 // four
#define C_5 5 // five
#define C_6 6 // six
#define C_7 7 // seven
#define C_8 8 // eight
#define C_9 9 // nine
#define C_10 10 // ten
#define C_11 11 // eleven
#define C_12 12 // twelve
#define C_13 13 // thirteen
#define C_14 14 // fourteen
#define C_15 15 // fifteen
#define C_16 16 // sixteen
#define C_17 17 // seventeen
#define C_18 18 // eighteen
#define C_19 19 // nineteen
#define C_20 20 // twenty
#define C_30 21 // thirty
#define C_40 22 // forty
#define C_50 23 // fifty
#define C_60 24 // sixty
#define C_70 25 // seventy
#define C_80 26 // eighty
#define C_90 27 // ninety
#define C_100 28 // hundred
#define C_1000 29 // thousand
#define C_and 30 // and
#define C_MAX C_and
*/
class PE0017
{
private:
static const int max_digits = 4;
static const int C_1 = 1;
static const int C_19 = 19;
static const int C_100 = 28;
static const int C_1000 = 29;
static const int C_and = 30;
int m_digits[max_digits];
int m_lettersArray[max_types];
void getDigitsOfNumber(int number);
int getUnitValue() { return m_digits[0]; }
int getDecadeValue() { return m_digits[1]; }
int getHundredValue() { return m_digits[2]; }
public:
PE0017();
int getLettersSumOfNumber(int number);
int getSumOfLetters(int max_number);
};
PE0017::PE0017()
{
for (int i=0; i<max_types; i++)
{
m_lettersArray[i] = numberString[i].size();
}
}
void PE0017::getDigitsOfNumber(int number)
{
memset(m_digits, 0, sizeof(m_digits));
int i = 0;
while(number > 0)
{
m_digits[i++] = number%10;
number /= 10;
}
}
int PE0017::getLettersSumOfNumber(int number)
{
getDigitsOfNumber(number);
int unitDigit = getUnitValue();
int decadeDigit = getDecadeValue();
int hundredDigit = getHundredValue();
int sumOfLetters = 0;
if (1000 == number)
{
sumOfLetters += m_lettersArray[C_1000] + m_lettersArray[C_1];
}
else
{
if (hundredDigit > 0)
{
sumOfLetters += m_lettersArray[hundredDigit]+m_lettersArray[C_100];
if (decadeDigit+unitDigit > 0)
{
sumOfLetters += m_lettersArray[C_and];
}
}
if (decadeDigit > 1)
{
sumOfLetters += m_lettersArray[decadeDigit+C_19-1];
}
else if (decadeDigit == 1)
{
sumOfLetters += m_lettersArray[10+unitDigit];
}
if (unitDigit > 0 && decadeDigit != 1)
{
sumOfLetters += m_lettersArray[unitDigit];
}
}
return sumOfLetters;
}
int PE0017::getSumOfLetters(int max_number)
{
int sumOfLetters = 0;
for(int i=1; i<=max_number; i++)
{
sumOfLetters += getLettersSumOfNumber(i);
}
return sumOfLetters;
}
int main()
{
PE0017 pe0017;
assert(20 == pe0017.getLettersSumOfNumber(115));
int sumOfLetters = pe0017.getSumOfLetters(1000);
cout << "The letters "<<sumOfLetters<<" are used for all the numbers "<<endl;
cout << "from 1 to 1000 (one thousand) inclusive in words." << endl;
return 0;
}
4. Python 代码实现
Python和C++采用一样的实现方法。虽然方法没有什么巧妙,但还是很实用和易懂的。
Python 代码
def getDigits(number):
digits = [0]*4
numOfDigits = 0
while number >= 1:
digits[numOfDigits] = number%10
number /= 10
numOfDigits += 1
return digits
def getLettersSumOfNumber(number):
"""
C_blank = 0 # blank
C_1 = 1 # one
C_2 = 2 # two
C_3 = 3 # three
C_4 = 4 # four
C_5 = 5 # five
C_6 = 6 # six
C_7 = 7 # seven
C_8 = 8 # eight
C_9 = 9 # nine
C_10 = 10 # ten
C_11 = 11 # eleven
C_12 = 12 # twelve
C_13 = 13 # thirteen
C_14 = 14 # fourteen
C_15 = 15 # fifteen
C_16 = 16 # sixteen
C_17 = 17 # seventeen
C_18 = 18 # eighteen
C_19 = 19 # nineteen
C_20 = 20 # twenty
C_30 = 21 # thirty
C_40 = 22 # forty
C_50 = 23 # fifty
C_60 = 24 # sixty
C_70 = 25 # seventy
C_80 = 26 # eighty
C_90 = 27 # ninety
C_100 = 28 # hundred
C_1000 = 29 # thousand
C_and = 30 # and
"""
numberString = ["", "one", "two", "three", "four", "five",
"six", "seven","eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen","fifteen","sixteen", "seventeen", "eighteen", "nineteen",
"twenty","thirty", "forty", "fifty", "sixty", "seventy", "eighty",
"ninety","hundred", "thousand", "and"]
letters_list = [ len(item) for item in numberString ]
digits = getDigits(number)
unitDigit = int(digits[0])
decadeDigit = int(digits[1])
hundredDigit = int(digits[2])
sumOfLetters = 0
C_1, C_19, C_100, C_1000, C_and = 1, 19, 28, 29, 30
if 1000 == number:
sumOfLetters += letters_list[C_1000] + letters_list[C_1]
else:
if hundredDigit > 0:
sumOfLetters += letters_list[hundredDigit]+letters_list[C_100]
if decadeDigit+unitDigit > 0:
sumOfLetters += letters_list[C_and]
if decadeDigit > 1:
sumOfLetters += letters_list[decadeDigit+C_19-1]
elif decadeDigit == 1:
sumOfLetters += letters_list[10+unitDigit]
if unitDigit > 0 and decadeDigit != 1:
sumOfLetters += letters_list[unitDigit]
return sumOfLetters
def getSumOfLetters(max_number):
sumOfLetters = 0;
for i in range (1, max_number+1):
sumOfLetters += getLettersSumOfNumber(i)
return sumOfLetters
def main():
assert 20 == getLettersSumOfNumber(115)
assert 23 == getLettersSumOfNumber(342)
print("The letters", getSumOfLetters(1000), "are used for all the numbers ")
print("from 1 to 1000 (one thousand) inclusive in words.")
if __name__ == '__main__':
main()