Skip to content

Instantly share code, notes, and snippets.

@sooop
Last active August 29, 2015 14:21
Show Gist options
  • Save sooop/480769d43c34cb008e95 to your computer and use it in GitHub Desktop.
Save sooop/480769d43c34cb008e95 to your computer and use it in GitHub Desktop.
Project Euler #004 (31 ~ 40)
/*
영국의 화폐 단위는 파운드(£)와 펜스(p)이고, 동전의 종류는 아래와 같습니다.
1p, 2p, 5p, 10p, 20p, 50p, £1 (100p), £2 (200p)
이 동전들을 가지고 2파운드를 만드는 방법은 다양할 것입니다. 예를 하나 들면 이렇습니다.
1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
2파운드를 만드는 서로 다른 방법은 모두 몇가지나 있습니까?*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
timeit{
let coins = [1,2,5,10,20,50,100,200]
let limit = 200
var ways = Array<Int>(count:limit+1, repeatedValue:0)
ways[0] = 1
for coin in coins {
for i in coin...limit {
ways[i] += ways[i - coin]
}
}
let result = ways[limit]
print(result)
}
//73682
//time: 1.28203630447388 ms
/*1부터 n까지의 각 숫자를 한번씩만 써서 만들 수 있는 숫자를 팬디지털(pandigital)이라고 합니다.
예를 들면 15234는 1부터 5의 숫자가 한번씩만 쓰였으므로 1 ~ 5 팬디지털입니다.
7254라는 숫자는 그런 면에서 특이한데, 39 × 186 = 7254 라는 곱셈식을 만들 때 이것이 1 ~ 9 팬디지털이 되기 때문입니다.
이런 식으로 a × b = c 가 1 ~ 9 팬디지털이 되는 모든 c의 합은 얼마입니까?
(참고: 어떤 c는 두 개 이상의 (a, b)쌍에 대응될 수도 있는데, 이런 경우는 하나로 칩니다)*/
// 1 * 4 = 4
// 2 * 3 = 4
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func test(a:Int, _ b:Int, _ c:Int) -> Bool {
let x = [a, b, c].map{ String($0) }.reduce("", combine:(+))
if x.characters.sort() == Array("123456789".characters) {
return true
}
return false
}
timeit{
var s = Set<Int>()
for x in 1...9 {
for y in 1234...9876 {
let z = x * y
if test(x, y, z) {
s.insert(z)
}
}
}
for x in 12...98 {
for y in 123...987 {
let z = x * y
if test(x, y, z) {
s.insert(z)
}
}
}
let result = Array(s).reduce(0, combine:(+))
print(s)
print(result)
}
//45228
//time: 4013.89199495316 ms
/*
분수 49/98에는 재미있는 성질이 있습니다. 수학을 잘 모르는 사람이 분모와 분자에서 9를 각각 지워서 간단히 하려고 49/98 = 4/8 처럼 계산해도 올바른 결과가 됩니다.
이에 비해 30/50 = 3/5 같은 경우는 다소 진부한 예라고 볼 수 있습니다.
위와 같은 성질을 가지면서 '진부하지 않은' 분수는, 값이 1보다 작고 분자와 분모가 2자리 정수인 경우 모두 4개가 있습니다.
이 4개의 분수를 곱해서 약분했을 때 분모는 얼마입니까?*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
typealias Frac = (Int, Int)
func ==(l:Frac, r:Frac) -> Bool {
if let dl = deduce(l) {
if let dr = deduce(r) {
return dl.0 == dr.0 && dl.1 == dr.1
}
}
return false
}
func gcd(a:Int, _ b:Int) -> Int? {
let (m, n) = a > b ? (a, b) : (b, a)
if n == 0 {
return nil
}
if m % n == 0 {
return n
}
return gcd(n, m % n)
}
func deduce(n:Frac) -> Frac? {
let (q, d) = n
if let g = gcd(q, d) {
return (q/g, d/g)
}
return nil
}
func weirdDeduce(n:Frac) -> Frac? {
let (q, d) = n
if q % 10 == 0 && d % 10 == 0 {
return nil
}
let convert = { (x:Int) -> Frac in
return (x/10, x%10)
}
let a = convert(q)
let b = convert(d)
switch true {
case a.0 == b.0:
return (a.1, b.1)
case a.0 == b.1:
return (a.1, b.0)
case a.1 == b.0:
return (a.0, b.1)
case a.1 == b.1:
return (a.0, b.0)
default:
return nil
}
}
func test(a:Int, _ b:Int) -> Bool {
if let x = deduce((a, b)) {
if let y = weirdDeduce((a, b)) {
return x == y
}
}
return false
}
timeit{
var t = [(Int, Int)]()
for a in 11...98 {
for b in a+1...99 {
if test(a, b) {
t.append((a,b))
}
}
}
let x = t.reduce((1,1)){ ($0.0 * $1.0, $0.1 * $1.1) }
print(deduce(x)!.1)
}
//100
//time: 1.48701667785645 ms
/*
숫자 145에는 신기한 성질이 있습니다. 각 자릿수의 팩토리얼(계승)을 더하면 1! + 4! + 5! = 1 + 24 + 120 = 145 처럼 자기 자신이 됩니다.
이렇게 각 자릿수의 팩토리얼을 더하면 자기 자신이 되는 모든 수의 합을 구하세요.
단, 1! = 1 과 2! = 2 의 경우는 덧셈이 아니므로 제외합니다.*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func process(var n:Int) -> Int {
let arr:[Int] = [1,1,2,6,24,120,720,5040,40320,362880]
var s = 0
while n > 0 {
s += arr[(n%10)]
n = n / 10
}
return s
}
timeit{
var arr = [Int]()
for i in 3..<999999 {
if process(i) == i {
arr.append(i)
}
}
let result = arr.reduce(0, combine:(+))
print(result)
}
//40730
//time: 774.470031261444 ms
/*소수 중에서 각 자리의 숫자들을 순환시켜도 여전히 소수인 것을 circular prime이라고 합니다. 예를 들어 197은 971, 719가 모두 소수이므로 여기에 해당합니다.
이런 소수는 100 밑으로 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, 97 처럼 13개가 있습니다.
그러면 1,000,000 밑으로는 모두 몇 개나 있을까요?*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func memoize<T:Hashable,U>(f:(T)->U) -> (T)->U {
var cache = [T:U]()
func cached(a:T) -> U {
if let r = cache[a] {
return r
}
let t = f(a)
cache[a] = t
return t
}
return cached
}
func isPrime(n:Int) -> Bool {
switch true {
case n < 2:
return false
case n == 2,
n == 3:
return true
case n % 2 == 0,
n % 3 == 0:
return false
case n < 9:
return true
default:
let l = Int(sqrt(Double(n)))
var k = 5
while k <= l {
if n % k == 0 || n % (k+2) == 0 {
return false
}
k += 6
}
return true
}
}
let cachedIsPrime = memoize(isPrime)
func makeCircular(var n:Int) -> [Int] {
let numberCount = Int(log10(Double(n)))
let maxUnit = Int(pow(Double(10), Double(numberCount)))
var arr:Array<Int> = []
for _ in 0...numberCount {
n = (n % 10) * maxUnit + (n / 10)
arr.append(n)
}
return arr
}
func test(n:Int) -> Bool {
var s = n
while s > 0 {
let i = s % 10
switch i {
case 0, 2, 4, 5, 6, 8:
return false
default:
s = s / 10
}
}
let t = makeCircular(n)
return t.map(cachedIsPrime).reduce(true){return $0 && $1}
}
timeit{
var result:Int = 4
for i in 11..<100_0000 {
if test(i) {
result += 1
}
}
print(result)
}
//55
//time: 134.285986423492 ms
/*대칭수(palindrome)인 585는 2진수로 나타내도 10010010012가 되어 여전히 대칭수입니다.
10진법과 2진법으로 모두 대칭수인 1,000,000 이하 숫자의 합을 구하세요.
(주의: 첫번째 자리가 0이면 대칭수가 아님)*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func destruct(var n:Int) -> [Int] {
var level = Int(pow(10 as Double, floor(log10(Double(n)))))
var s = [Int]()
while level > 0 {
s.append(n / level)
n = n % level
level = level / 10
}
return s
}
func destructBinary(var n:Int) -> [Int] {
var s = [Int]()
while n > 0 {
s.append(n % 2)
n = n / 2
}
return s
}
func isPalindrome(a:[Int]) -> Bool {
let l = a.count
for i in 0..<l/2 {
if a[i] != a[l-i-1] {
return false
}
}
return true
}
func test(n:Int) -> Bool {
return isPalindrome(destruct(n)) && isPalindrome(destructBinary(n))
}
timeit{
var s = 0
var i = 1
while i <= 1000000 {
if test(i) {
s += i
}
i += 2
}
print(s)
}
//872187
//time: 1891.16197824478 ms
/*소수 3797에는 왼쪽부터 자리수를 하나씩 없애거나 (3797, 797, 97, 7) 오른쪽부터 없애도 (3797, 379, 37, 3) 모두 소수가 되는 성질이 있습니다.
이런 성질을 가진 소수는 단 11개만이 존재합니다. 이것을 모두 찾아서 합을 구하세요.
(참고: 2, 3, 5, 7은 제외합니다)*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func memoize<T:Hashable,U>(f:(T)->U) -> (T)->U {
var cache = [T:U]()
func cached(a:T) -> U {
if let r = cache[a] {
return r
}
let t = f(a)
cache[a] = t
return t
}
return cached
}
func isPrime(n:Int) -> Bool {
switch true {
case n < 2:
return false
case n == 2,
n == 3:
return true
case n % 2 == 0,
n % 3 == 0:
return false
case n < 9:
return true
default:
let l = Int(sqrt(Double(n)))
var k = 5
while k <= l {
if n % k == 0 || n % (k+2) == 0 {
return false
}
k += 6
}
return true
}
}
let cachedIsPrime = memoize(isPrime)
// 앞에서부터 한자리씩 없애는 리스트
func rFront(n:Int) -> [Int] {
var level = Int(pow(10 as Double, floor(log10(Double(n)))))
var result = [n]
while level > 1 {
result.append(n % level)
level = level / 10
}
return result
}
// 뒤에서 부터 한자리씩 없앤 리스트
func rRear(var n:Int) -> [Int] {
var result = [Int]()
while n > 0 {
result.append(n)
n = n / 10
}
return result
}
public func all<T>(f:(T) -> Bool, list:[T]) -> Bool {
return list.map(f).reduce(true, combine:{return $0 && $1})
}
func test(n:Int) -> Bool {
return all(cachedIsPrime, list:rFront(n)) && all(cachedIsPrime, list:rRear(n))
}
timeit{
var s = [Int]()
var i = 13
let steps = [4, 6]
var stepIndex = 0
while s.count < 11 {
if test(i) {
s.append(i)
print(i)
}
i += steps[stepIndex]
stepIndex = (stepIndex + 1) % 2
}
let result = s.reduce(0, combine:(+))
print(result)
}
/*
748317
time: 2549.28600788116 ms
*/
/*
숫자 192에 1, 2, 3을 각각 곱합니다.
192 × 1 = 192
192 × 2 = 384
192 × 3 = 576
곱한 결과를 모두 이어보면 192384576 이고, 이것은 1 ~ 9 팬디지털(pandigital)인 숫자입니다. 이런 과정을 편의상 '곱해서 이어붙이기'라고 부르기로 합니다.
같은 식으로 9와 (1, 2, 3, 4, 5)를 곱해서 이어붙이면 918273645 라는 1 ~ 9 팬디지털 숫자를 얻습니다.
어떤 정수와 (1, 2, ... , n)을 곱해서 이어붙였을 때 얻을 수 있는 가장 큰 아홉자리의 1 ~ 9 팬디지털 숫자는 무엇입니까? (단 n > 1)*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func destruct(var n:Int) -> [Int] {
var level = Int(pow(10 as Double, floor(log10(Double(n)))))
var s = [Int]()
while level > 0 {
s.append(n / level)
n = n % level
level = level / 10
}
return s
}
func isPandigital(n:[Int]) -> Bool {
if n.count == 9 {
return n.sort() == [1,2,3,4,5,6,7,8,9]
}
return false
}
func acc(n:[Int]) -> Int {
var s = 0
for i in n {
s = s * 10 + i
}
return s
}
func test(n:Int) -> Int {
var s = [Int]()
for i in 1...9 {
s = s + destruct(n * i)
if s.count >= 9 {
if isPandigital(s) {
return acc(s)
} else {
return 0
}
}
}
return 0
}
timeit{
let result = Array(1...9999).map(test).reduce(0, combine:max)
print(result)
}
//932718654
//time: 202.883958816528 ms
/*
세 변의 길이가 모두 자연수 {a, b, c}인 직각삼각형의 둘레를 p 로 둘 때, p = 120 을 만족하는 직각삼각형은 아래와 같이 세 개가 있습니다.
{20, 48, 52}, {24, 45, 51}, {30, 40, 50}
1000 이하의 둘레 p에 대해서, 직각삼각형이 가장 많이 만들어지는 p의 값은 얼마입니까?
*/
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func test(a:Int, _ b:Int) -> Int {
let c2 = a * a + b * b
let c = Int(sqrt(Double(c2)))
if c * c == c2 {
return a + b + c
}
return 0
}
timeit{
var array = Array<Int>(count:1001, repeatedValue:0)
for a in 1...500 {
for b in 1...500 {
let c = test(a, b)
if c > 1000 {
break
}
if c > 0 {
array[c] += 1
}
}
}
let maxElement = array.reduce(array[0], combine:max)
let result = array.indexOf(maxElement)!
print(result)
}
//840
//time: 8.82399082183838 ms
/*소수점 뒤에 양의 정수를 차례대로 붙여 나가면 아래와 같은 무리수를 만들 수 있습니다.
0.123456789101112131415161718192021...
이 무리수의 소수점 아래 12번째 자리에는 1이 옵니다 (위에서 붉게 표시된 숫자).
소수점 아래 n번째 숫자를 dn이라고 했을 때, 아래 식의 값은 얼마입니까?
d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000*/
// 백만개 숫자를 저장하는 배열을 만들어도 되지만,
// 한 번에 한 자리씩 계산하도록 함.
import Foundation
func timeit(@noescape f:()->()) {
let startTime = NSDate()
f()
let elapsed = NSDate().timeIntervalSinceDate(startTime)
print("time: \(elapsed * 1000) ms")
}
func destruct(var n:Int) -> [Int] {
var level = Int(pow(10 as Double, floor(log10(Double(n)))))
var s = [Int]()
while level > 0 {
s.append(n / level)
n = n % level
level = level / 10
}
return s
}
struct NumberGenerator {
var currentValue = 1
var numberIndex = 0
var numberBasket:[Int]
init() {
numberBasket = destruct(currentValue)
numberIndex = 0
}
mutating func next() -> Int {
let result = numberBasket[numberIndex]
numberIndex += 1
if numberIndex == numberBasket.count {
currentValue += 1
numberBasket = destruct(currentValue)
numberIndex = 0
}
return result
}
}
timeit{
var g = NumberGenerator()
var c = 0
var arr = [Int]()
var a = 0
for i in 0...6 {
while c < Int(pow(10 as Double, Double(i))) {
a = g.next()
c += 1
}
arr.append(a)
}
let result = arr.reduce(1, combine:(*))
print(result)
}
//210
//time: 791.760981082916 ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment