1. 程式人生 > >[Haskell] 一些簡單題

[Haskell] 一些簡單題

  1. 二分查詢,找出列表裡是否存在給定的x
    顯然,列表必須是有序的(這就包括了元素是可比較的,也就是都屬於Ord型別類)。
binarySearch :: (Ord a) => a -> [a] -> Bool
binarySearch x list | x < mid = binarySearch x front
                    | x > mid = binarySearch x behind
                    | x == mid = True
                    | otherwise = False
where (front, mid : behind) = (splitAt (div (length list) 2) list)
  1. 二分查詢,找出列表裡所有的x
binarySearch :: (Ord a) => a -> [a] -> [a]
binarySearch x list | x < mid = binarySearch x front
                    | x > mid = binarySearch x behind
                    | x == mid = concat [[x], binarySearch x front, binarySearch x behind]
                    | otherwise = []
                    where
(front, mid : behind) = splitAt (div (length list) 2) list

感覺寫的有點醜。。。

  1. Hanoi塔
hanoi :: (Int, Int, Int, Int) -> [(Int, Int)]
-- hanoi (num, from, to, via) -> [(from, to)]

hanoi (num, from, to, via) = hanoi (num - 1, from, via, to) + [(from, to)] + hanoi (num - 1, via, to, from)
-- hanoi num = 2 * hanoi (num - 1) + 1

hanoi塔很簡單,hanoi函式表示最小的num個金片,從from柱子順序不變地移動到to柱子,via柱子用來中轉的移動情況。由於是最小的num個金片,所以3個柱子的已有金片並不會導致金片無法放置的情況,所以可以忽略三個柱子原有的其他金片。然後如果要移動n個金片,就要先把n-1個金片先移開(即移動到via柱上),再移動第n個金片到to柱子上,再將之前的n-1個金片再移動到to柱子上,為了滿足小的金片一定在上的條件。

那麼對於n-1個金片,第一次移動,從from柱子移動到目前的via柱子,經過to柱子。第二次移動,從via柱子移動到to柱子,經過from柱子,這就是引數的由來。

  1. 歸併排序
    其實我覺得歸併排序是最簡單的O(nlogn)排序演算法了。。。
merge x [] = x
merge [] x = x
merge (a:la) (b:lb) | a < b = a : merge la (b:lb)
                    | otherwise = b : merge (a:la) lb

mergeSort list | length list <= 1 = list
               | otherwise = merge (mergeSort l1) (mergeSort l2)
               where (l1, l2) = splitAt (div (length list) 2) list
-- squareRoot iteration root
squareRoot 0 c = c
squareRoot n c = x0 - (x0 ^ 2 - c) / (2 * x0) where x0 = squareRoot (n - 1) c

令函式

f(x)=x2c
則該函式的零點為我們要的答案,利用牛頓迭代法找函式零點:
f(x0)+f(x0)(xx0)=0
每一次求出x,x將越來越逼近方程的根。
變形上述方程:
x=x0x20c2x0
  1. 漢明數列
    對於漢明數集合X,有
    1) 1X
    2) xX,2x,3x,5xX
    寫一個函式,返回這個集合所有元素組成的有序序列。
divide x y
 | mod x y == 0 = divide (div x y) y
 | otherwise = x
ham = filter (\x -> divide (divide (divide x 2) 3) 5 == 1) [1..]
  1. π
    我們有計算公式:
    π=4(1213(12)3+15(12)5+)+4(1313(13)3+15(13)5+)
    那麼兩個無限項數列可以用下面的函式表示
series base = [(1 / (fromIntegral x)) * (base ^ fromIntegral x) * (-1) ^ div (fromIntegral x) 2 | x <- [1,3..]]

其中base為被乘方的數,在這裡取1213
然後就知道了:

num = 2000000 -- compute times.
mypi = (sum $ take num $ series (1/2)) * 4 + 4 * (sum $ take num $ series (1/3))
  1. 求素數因子
primeFactors n =
  case factors of
    [] -> [n]
    _  -> factors ++ primeFactors (n `div` head factors)
  where factors = take 1 $ filter (\x -> (n `mod` x) == 0) [2 .. floor $ sqrt $ fromIntegral n]
  1. 矩陣轉置
    這是我的寫法
transpose :: [[a]] -> [[a]]
transpose [xs] = [[x]|x<-xs]
transpose (xs:xss) = zipWith (++) (transpose [xs]) (transpose xss)

下面是書上的寫法

transpose :: [[a]] -> [[a]]
transpose [] = []
transpose ([]:xss) = transpose xss
transpose ((x:xs) : xss) = (x : [h | (h:_) <- xss]) : transpose (xs : [t | (_:t) <- xss])
  1. 快速冪
-- quickPower (*) 2 8 = 256
quickPower f a n
 | n == 1 = a
 | odd n = let m = quickPower f a (div n 2) in f (f m m) a
 | otherwise = let m = quickPower f a (div n 2) in f m m