challenge 急勾配の判定

有限の長さの数列で,各要素の値が,その要素の後ろにある残りの列に含まれるすべての要素の和よりも大きい列を「急勾配の列」ということにします(空列の和は0とします).

任意の長さ(ただし有限の長さの)数列を与えられたとき,それが「急勾配の列」であるかどうかを判定する述語関数を定義してください.

必須ではありませんが,効率についてコメントがあれば面白いかもしれませんね.

Posted feedbacks - Haskell

$ が多くてうっとうしいけど。

1
2
3
import List

steep xs = and $ zipWith (>) xs $ map sum $ tail $ tails xs

1
isSteelyList xs = and $ zipWith (>) xs $ tail $ scanl (-) (sum xs) xs

mapAccumの遅延評価が良くわかりませんが...

1
2
3
import Data.List (mapAccumR)

isSteep = and . snd . mapAccumR (\acc x -> (acc+x, x > acc)) 0

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import Maybe

isKyukoubai xs = isJust $ foldr f (Just 0) xs  where
  f x b = do
    s <- b
    if (x > s) then Just (s+x) else Nothing
{-
> isKyukoubai [4,2,1]
True
> isKyukoubai [2,2,1]
False
> isKyukoubai [undefined,2,2,1]
False
-}

末尾再帰になってる?
1
2
3
4
5
6
7
isKyukoubai xs = f [] xs  where
  f ys (x:xs) = f (x:ys) xs
  f ys [] = g 0 ys
  g s (y:ys)
    | y > s     = g (s+y) ys
    | otherwise = False
  g _ [] = True

効率や末尾再帰や遅延評価や見易さやら考えてたら
#8896 の reverse版になりました。
1
2
isKyukoubai xs = and $ zipWith (>) ys $ scanl (+) 0 ys  where
  ys = reverse xs

Index

Feed

Other

Link

Pathtraq

loading...