Skip to content

Commit 5a6b1d0

Browse files
authored
feat: Project Euler Problem 17 (TheAlgorithms#1168)
1 parent 564ee85 commit 5a6b1d0

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

Project-Euler/Problem017.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* Problem 17 - Number letter counts
3+
*
4+
* @see {@link https://projecteuler.net/problem=17}
5+
*
6+
* 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.
7+
* If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?
8+
*
9+
* @author Chetan07j
10+
*/
11+
12+
// Array of number word length from 0 -> 19
13+
const ones = [4, 3, 3, 5, 4, 4, 3, 5, 5, 4, 3, 6, 6, 8, 8, 7, 7, 9, 8, 8]
14+
15+
// Array for tens from 20, 30, 40, 50, 60, 70, 80, 90 in words length
16+
const tens = [6, 6, 5, 5, 5, 7, 6, 6]
17+
18+
// Word length for words thousand, hundred, and
19+
const thousandLength = 8
20+
const hundredLength = 7
21+
const andLength = 3
22+
23+
/**
24+
* Function to convert number to word
25+
*
26+
* This function is called recursively to handle thousand and its sub part
27+
*/
28+
const numberToWordLength = (n) => {
29+
let count = 0
30+
31+
// If number is < 20 then return its corresponding value from ones
32+
if (n < 20) {
33+
return ones[n]
34+
}
35+
36+
/**
37+
* To calculate tens value "n / 10 - 2" is performed, which might return decimal value
38+
* to extract proper integer value Math.floor is added
39+
* Here "-2" is performed as our tens array start with index 0
40+
* To get appropriate value from that for our number it is required
41+
* e.g.,
42+
* -> 34 -> 34/10= 3.4 -> Math.floor(3.4) = 3
43+
* -> ones[3] = 5 // this is wrong
44+
* -> 3 - 2 = 1 -> ones[1] = 6
45+
*
46+
* To find ones part, unit is identified by n % 10
47+
* If > 0 then ones word is appended to tens word otherwise nothing
48+
* e.g.,
49+
* 1. 34 -> 10
50+
* 2. 30 -> 6
51+
*/
52+
if (n >= 20 && n < 100) {
53+
const unit = n % 10
54+
return tens[Math.floor(n / 10 - 2)] + ((unit !== 0) ? ones[unit] : 0)
55+
}
56+
57+
// Find thousand, hundred and sub part
58+
const hundred = Math.floor(n / 100) % 10
59+
const thousand = Math.floor(n / 1000)
60+
const sub = n % 100
61+
62+
// Find ones for thousand part number
63+
// e.g., thousand = 2 => inWord = twothousand
64+
if (n > 999) {
65+
count += numberToWordLength(thousand) + thousandLength
66+
}
67+
68+
// Find ones for hundred part number
69+
// e.g., hundred = 1 => inWord = onehundred
70+
if (hundred !== 0) {
71+
count += ones[hundred] + hundredLength
72+
}
73+
74+
// Find and part of number
75+
// e.g., 922 => ninehundred"andtwentytwo"
76+
if (sub !== 0) {
77+
count += andLength + numberToWordLength(sub)
78+
}
79+
80+
// return number in word format
81+
return count
82+
}
83+
84+
/**
85+
* Function responsible for calculating total number word length
86+
* for provided input number
87+
* Validation is performed for input
88+
* Loop is executed to find total word length for given number range
89+
* starting from 1
90+
*
91+
*
92+
* @param {number} number
93+
* @returns {number}
94+
*/
95+
const countNumberWordLength = (number) => {
96+
let count = 0
97+
98+
// Not a number check
99+
if (Number.isNaN(parseInt(number))) {
100+
throw new Error('Invalid input, please provide valid number')
101+
}
102+
103+
// Number should be greater than 1
104+
if (number < 1) {
105+
throw new Error('Please provide number greater that 1')
106+
}
107+
108+
// Loop to calculate word length by calling {@link numberToWord}
109+
for (let i = 1; i <= number; i++) {
110+
count += numberToWordLength(i)
111+
}
112+
113+
// return final count for number word length
114+
return count
115+
}
116+
117+
export { countNumberWordLength }

Project-Euler/test/Problem017.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { countNumberWordLength } from '../Problem017.js'
2+
3+
describe('Number letter count', () => {
4+
test.each([[5, 19], [100, 864], [1000, 21124]])('Number letter count from 1 to %i', (n, expected) => {
5+
expect(countNumberWordLength(n)).toBe(expected)
6+
})
7+
8+
test.each([
9+
['test', 'Invalid input, please provide valid number'],
10+
[0, 'Please provide number greater that 1']
11+
])('Should throw an error for input %i', (n, expected) => {
12+
expect(() => countNumberWordLength(n)).toThrowError(expected)
13+
})
14+
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy