[topic] リストの並び

数値のリストがあります。リストのサイズは N です。
ls[0]がリストの先頭要素、ls[N-1]が最後の要素です。

問題: 入力として与えられたリストが次の条件を満たすかどうかを求めてください。

for (int i = 0; i < N-1; i++) {
  ls[i] != ls[i+1] である
  ls[i] < ls[i+1] なら、ls[i] < ls[k] である(for all k = i+1 to N-1)
  ls[i] > ls[i+1] なら、ls[i] > ls[k] である(for all k = i+1 to N-1)
}

N の範囲は 3 <= N <= 50000 です。実行例を示します。

> check([1, 5, 4, 2])
True
> check([1, 2, 3])
True
> check([825, 102, 811, 140, 812, 125, 263])
False
> check([824, 102, 811, 140, 810, 155, 263])
True
> check([5, 4, 3, 2, 1])
True
> check([4, 2, 5, 3, 1])
False

Posted feedbacks - Flatten

Nested Hidden

日本語でお願いします。


Console.WriteLine(check(new[] { 825, 102, 811, 140, 812, 125, 263 })); False

Console.WriteLine(check(new[] { 824, 102, 811, 140, 810, 155, 263 })); True

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Linq;

class Program
{
    static void Main()
    {
        Console.WriteLine(check(new[] { 825, 102, 811, 140, 812, 125, 263 }));
        Console.WriteLine(check(new[] { 824, 102, 811, 140, 810, 155, 263 }));
    }

    static bool check(int[] ls)
    {
        if (ls.Count() <= 1)
        {
            return true;
        }
        else if (ls.First() < ls.Skip(1).First())
        {
            return ls.Skip(1).All(n => ls.First() < n) && check(ls.Skip(1).ToArray());
        }
        else if (ls.First() > ls.Skip(1).First())
        {
            return ls.Skip(1).All(n => ls.First() > n) && check(ls.Skip(1).ToArray());
        }
        else
        {
            return false;
        }
    }
}

Squeak Smalltalk で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
| check |

check := [:list |
    (1 to: list size - 1) allSatisfy: [:idx |
        | first second |
        (first := list at: idx) = (second := list at: idx + 1) ifTrue: [false] ifFalse: [
            | sym |
            sym := first < second ifTrue: [#positive] ifFalse: [#negative].
            (list allButFirst: idx) - first allSatisfy: [:each | each perform: sym]]]].


check value: #(1 5 4 2).                       "=> true "
check value: #(1 2 3).                         "=> true "
check value: #(825 102 811 140 812 125 263).   "=> false "
check value: #(824 102 811 140 810 155 263).   "=> true "
check value: #(5 4 3 2 1).                     "=> true "
check value: #(4 2 5 3 1).                     "=> false "

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import Data.List

check :: [Int] -> Bool
check xs = all foo $ tails xs
 where
  foo []     = True
  foo (x:xs) = all (EQ /=) &&& ((1 >=) . length . group) $ map (compare x) xs

(&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(p &&& q) x = if p x then q x else False

JavaScript@Firebugコンソールで。少し意訳しました。

>>> new Array(1,5,4,2).check();
true
>>> new Array(1,2,3).check();
true
>>> new Array(825,102,811,140,812,125,263).check();
false
>>> new Array(824,102,811,140,810,155,263).check();
true
>>> new Array(5,4,3,2,1).check();
true
>>> new Array(4,2,5,3,1).check();
false
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Array.prototype.check = function() {
  var upper = Number.MAX_VALUE;
  var lower = Number.MIN_VALUE;
  for (var i = 0; i < this.length; i++) {
    if ( (upper <= this[i]) || (this[i] <= lower) )
      return false;
    if (this[i] < this[i+1])
      lower = this[i];
    else
      upper = this[i];
  }
  return true;
};

書いてみたら意外とすっきり。

1
2
3
(defun check (list)
  (loop for (x . xs) on list always
    (or (every (lambda (y) (< x y)) xs) (every (lambda (y) (> x y)) xs))))

Haskell の方がきれいに書けますね。

1
2
3
4
import Data.List

check (x:xs) = (all (< x) xs || all (> x) xs) && check xs
check []     = True

N = 50000 のときの速度を考えて実装。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
object Doukaku183 extends Application {
  
  def least   [A <% Ordered[A]](a: A, b: A) = if (a < b) a else b
  def greatest[A <% Ordered[A]](a: A, b: A) = if (a > b) a else b
  
  def check[A <% Ordered[A]](ls: List[A]) = {
    
    def loop(ls: List[A], min: A, max: A): boolean = ls match {
      case Nil => true
      case h :: t => {
        if (min <= h && h <= max) false
        else loop(t, least(min, h), greatest(max, h))
      }
    }
    
    ls.reverse match {
      case Nil => true
      case h :: t => {
        loop(t, h, h)
      }
    }
  }
  
  
  {
    println(check(List(1, 5, 4, 2)))                        // => true
    println(check(List(1, 2, 3)))                           // => true
    println(check(List(825, 102, 811, 140, 812, 125, 263))) // => false
    println(check(List(824, 102, 811, 140, 810, 155, 263))) // => true
    println(check(List(5, 4, 3, 2, 1)))                     // => true
    println(check(List(4, 2, 5, 3, 1)))                     // => false
    
    println(check((1 to 50000).toList))                     // => true
    println(check(100 :: (1 to 49999).toList))              // => false
  }
}

Number.MIN_VALUE = 5e-324
なので、0以下の数値を含んでいると失敗しませんか。

>>> new Array(0, 1, 2).check();
false

1
2
3
4
5
6
7
8
import Maybe

check [] = True
check xs = isJust $ check' $ reverse xs  where
  check' (x:xs) = foldl (\b x -> b >>= f x) (Just(x,x)) xs
  f x (l,h) | x < l = Just (x,h)
            | x > h = Just (l,x)
            | otherwise = Nothing

-∞ と ∞ と foldr を使って書き直し。
1
2
3
4
5
6
7
import Maybe

data Z = NegInf | Finite Integer | PosInf deriving (Eq,Ord)
 
check xs = isJust $ foldr ((=<<).f.Finite) (Just(PosInf,NegInf)) xs  where 
  f x (l,h) | l <= x && x <= h = Nothing
            | otherwise        = Just (min x l, max x h)

ナイスツッコミ!
語感にやられました。(それをMIN_VALUEと言うか・・・。)
無限大に直してみました。

>>> new Array(0, 1, 2).check();
true
1
2
3
4
5
<  var upper = Number.MAX_VALUE;
<  var lower = Number.MIN_VALUE;
---
>  var upper = Number.POSITIVE_INFINITY;
>  var lower = Number.NEGATIVE_INFINITY;

整数しかこないつもりでいました。一般の型に修正。
1
2
3
> data Z = NegInf | Finite Integer | PosInf deriving (Eq,Ord)
---
> data N a = NegInf | Finite a | PosInf deriving (Eq,Ord)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
let rec check = function
  | [] -> true
  | hd::[] -> true
  | x::y::tl ->
      if (x!=y) && 
        ((x<y && List.for_all ((<) x) tl) || 
         (x>y && List.for_all ((>) x) tl))
      then check (y::tl) else false;;
(*
  Array.map check [|
    [1; 5; 4; 2];
    [1; 2; 3];
    [825; 102; 811; 140; 812; 125; 263];
    [824; 102; 811; 140; 810; 155; 263];
    [5; 4; 3; 2; 1];
    [4; 2; 5; 3; 1];
  |];;
*)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(use srfi-1)

(define (main args)
  (print
   (let loop ((xs (map string->number (cdr args))))
     (or (null? xs)
         (null? (cdr xs))
         (let ((a (car xs))
               (b (cadr xs)))
           (and (not (= a b))
                (every (cute (if (< a b) < >) a <>) (cddr xs))
                (loop (cdr xs)))))))
  0)

Index

Feed

Other

Link

Pathtraq

loading...