Tìm cực trị địa phương


14

Viết một hàm hoặc chương trình có trong một danh sách và tạo một danh sách các cực trị cục bộ.

Trong danh sách [x_0, x_1, x_2...]một cực đoan địa phương là một x_iví dụ mà x_(i-1) < x_ix_(i+1) < x_ihay x_(i-1) > x_ix_(i+1) > x_i. Lưu ý rằng các yếu tố đầu tiên và cuối cùng của danh sách không bao giờ có thể là cực trị cục bộ.

Vì vậy, đối với một số ví dụ

local_extremes([1, 2, 1]) = [2]
local_extremes([0, 1, 0, 1, 0]) = [1, 0, 1]
local_extremems([]) = []

Đây là mã golf nên mã ngắn nhất sẽ thắng!


Để chắc chắn tôi hiểu chính xác: Số lớn hơn số ở hai bên?
undergroundmonorail

@undergroundmonorail Lớn hơn hoặc ít hơn. Vì vậy, nó phải là một mức tối thiểu cục bộ, trong đó các nước láng giềng đều lớn hơn hoặc tối đa khi cả hai đều nhỏ hơn
Daniel Gratzer

Ồ, tôi hiểu rồi. Tôi hiểu lắm nó
undergroundmonorail

2
và những gì về trình tự 1 2 2 1không nên 2được coi là cực đoan quá? - Tôi biết, điều này sẽ làm cho giải pháp khó khăn hơn nhiều ...
VX

Câu trả lời:


5

Toán học 66 58 51

Giải pháp tạm thời

Rút ngắn nhờ đóng góp của Calle.

Cases[Partition[#,3,1],{a_,b_,c_}/;(a-b) (b-c)<0⧴b]&

Partition[#,3,1] tìm thấy bộ ba.

(a-b) (b-c)<0là đúng nếu và chỉ nếu blà bên dưới a, choặc ở trên a, c. và nhìn vào có dấu hiệu của sự khác biệt. Một cực địa phương sẽ trở lại {-1,1}hoặc {1,-1}.


Ví dụ

Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{1, 2, 1}]
Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{0, 1, 0, 1, 0}]
Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{}]
Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{9, 10, 7, 6, 9, 0, 3, 3, 1, 10}]

{2}
{1, 0, 1}
{}
{10, 6, 9, 0, 1}


Giải pháp trước đó

Điều này có vẻ như tất cả các bộ ba (được tạo bởi Partition) và xác định xem phần tử ở giữa có nhỏ hơn cả hai cực trị hay lớn hơn các cực trị hay không.

Cases[Partition[#,3,1],{a_,b_,c_}/;(b<ab<c)∨(b>ab>c)⧴b]& ;

Giải pháp đầu tiên

Điều này tìm thấy bộ ba, và nhìn vào có dấu hiệu của sự khác biệt. Một cực địa phương sẽ trở lại {-1,1}hoặc {1,-1}.

Cases[Partition[#,3,1],x_/;Sort@Sign@Differences@x=={-1,1}⧴x[[2]]]&

Thí dụ

Cases[Partition[#,3,1],x_/;Sort@Sign@Differences@x=={-1,1}:>x[[2]]]&[{9, 10, 7, 6, 9, 0, 3, 3, 1, 10}]

{10, 6, 9, 0, 1}


Phân tích :

Partition[{9, 10, 7, 6, 9, 0, 3, 3, 1, 10}]

{{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, { 3, 3, 1}, {3, 1, 10}}

% đề cập đến kết quả từ dòng trước tương ứng.

Differences/@ %

{{1, -3}, {-3, -1}, {-1, 3}, {3, -9}, {-9, 3}, {3, 0}, {0, -2}, {-2, 9}}

Sort@Sign@Differences@x=={-1,1}xác định các bộ ba từ {{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, {3, 3, 1}, {3, 1, 10}} sao cho dấu (-, 0, +) của sự khác biệt bao gồm a -1và a 1. Trong trường hợp hiện tại đó là:

{{9, 10, 7}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {3, 1, 10}}

Đối với mỗi trường hợp này, x, x[[2]]đề cập đến thuật ngữ thứ hai. Đó sẽ là tất cả các cực đại và cực tiểu địa phương.

{10, 6, 9, 0, 1}


Phong cách Mathicala của bạn ngắn gọn hơn nhiều so với của tôi. Khi nào chúng ta bắt đầu gọi nó là "Ngôn ngữ Wolfram"?
Michael Stern

Tôi thấy điều này ! Đồ họa toán học
Tiến sĩ belisarius

Michael Stern, tôi nghi ngờ Wolfram Language sẽ chỉ trở thành chính thức tại phiên bản 10, một số hình thức đã có sẵn trên Raspberry Pi.
DavidC

BTW, ai đó đã chèn một dòng mã chuyển đổi Math ML thành đồ họa. Tôi cung không chăc tại sao.
DavidC

Tôi không chắc tại sao anh ta làm điều đó. Tôi không thể thấy bất kỳ sự khác biệt nào trong mã "đã sửa đổi"
Tiến sĩ belisarius

6

J - 19 char

Không thể giúp nó;)

(}:#~0,0>2*/\2-/\])

Giải thích sau:

  • 2-/\] - Trên mỗi cặp phần tử trong đối số (mỗi phần tử dài 2 mục), hãy lấy sự khác biệt.
  • 2*/\ - Bây giờ qua từng cặp của danh sách mới, lấy sản phẩm.
  • 0> - Kiểm tra xem mỗi kết quả có nhỏ hơn 0. Điều này chỉ xảy ra nếu các bội số có dấu hiệu xen kẽ, nghĩa là nó không xảy ra nếu chúng có cùng dấu hoặc bằng không.
  • 0, - Tuyên bố rằng phần tử đầu tiên không phải là phần tử cực đoan.
  • }: - Cắt bỏ phần tử cuối cùng, bởi vì đó cũng không thể là một thái cực.
  • #~ - Sử dụng các giá trị thực ở phía bên phải để chọn các mục từ danh sách ở phía bên trái.

Sử dụng:

   (}:#~0,0>2*/\2-/\]) 1 2 1
2
   (}:#~0,0>2*/\2-/\]) 0 1 0 1 0
1 0 1
   (}:#~0,0>2*/\2-/\]) i.0   NB. i.0 is the empty list (empty result also)

   (}:#~0,0>2*/\2-/\]) 3 4 4 4 2 5
2

Umm, điều này có thể không hoạt động nếu đầu vào là 3, 4, 4, 4, 4, 5, tức là bạn có thể nhận được số 0 trong bước "0 =" nếu 0 được thêm vào 0.
Lord Soth

Ngoài ra, tôi không biết về ngôn ngữ này, nhưng, thay vì lấy dấu hiệu trong bước đầu tiên, bạn có thể để lại sự khác biệt như hiện tại. Sau đó, trong bước thứ hai, nhân các phần tử thay vào đó, và trong phần thứ ba, bạn có thể kiểm tra xem sản phẩm có âm hay không (điều này cũng tránh được 0 vấn đề đó). Có lẽ điều này có thể dẫn đến một mã ngắn hơn.
Lord Soth

Bắt tốt, và vâng, điều này tiết kiệm hai nhân vật. Đang cập nhật.
thuật toán

5

Javascript - 62 45 ký tự

f=a=>a.filter((x,i)=>i&&i<a.length-1&&(a[i-1]-x)*(a[i+1]-x)>0)

Biên tập

f=a=>a.filter((x,i)=>(a[i-1]-x)*(a[i+1]-x)>0)

4

Ruby, 83 70 60 55 49 ký tự

f=->a{a.each_cons(3){|x,y,z|p y if(x-y)*(z-y)>0}}

In tất cả các cực trị cục bộ sang STDOUT.

Sử dụng <=>toán tử "tàu vũ trụ" mà tôi thực sự thích. (Nó trả về 1 nếu thứ nhất lớn hơn thứ hai, -1 nếu nó nhỏ hơn và 0 nếu bằng nhau. Do đó, nếu chúng thêm vào -2 hoặc 2, điều đó có nghĩa là giữa là cực trị.)

Không còn nữa, như @daniero đã chỉ ra rằng cách "rõ ràng" thực sự ngắn hơn!

Thay đổi một lần nữa! Bây giờ, nó sử dụng thuật toán tuyệt vời được tìm thấy trong câu trả lời của MT0 (+1 cho anh ta!).

Ngoài ra, tôi thích each_conschọn từng nnhóm phần tử liên tiếp trong một mảng. Và trailing ifcũng thú vị.

Nhìn chung, tôi chỉ thích vẻ thanh lịch của nó.

Một số mẫu chạy:

irb(main):044:0> f[[1,2,1]]
2
=> nil
irb(main):045:0> f[[1,0,1,0,1]]
0
1
0
=> nil
irb(main):046:0> f[[]]
=> nil
irb(main):047:0> f[[1,2,3,4,5,4,3,2,1]]
5
=> nil
irb(main):048:0> f[[1,1,1,1,1]]
=> nil
irb(main):049:0> f[[10,0,999,-45,3,4]]
0
999
-45
=> nil

Nó ngắn hơn để giải nén x thành 3 biến:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero

@daniero Cảm ơn; Tôi thậm chí không biết bạn có thể làm điều đó! Đã chỉnh sửa
Doorknob

thật không : D Btw, hiện tại mỗi thuật ngữ ngắn hơn 3 ký tự, tổng thể sẽ rẻ hơn x>y&&y<z||x<y&&y>z(ngay cả khi người vận hành tàu vũ trụ rất đẹp);)
daniero

cũng ... !((x..z)===y)thậm chí còn ngắn hơn mặc dù không thông minh
Không phải Charles

@Charles Thất bại khi x < z.
Doorknob

3

C ++ - 208 ký tự

Giải pháp dài nhất một lần nữa:

#include<iostream>
#include<deque>
using namespace std;
int main(){deque<int>v;int i;while(cin){cin>>i;v.push_back(i);}for(i=0;i<v.size()-2;)if(v[++i]>v[i-1]&v[i]>v[i+1]|v[i]<v[i-1]&v[i]<v[i+1])cout<<v[i]<<' ';}

Để sử dụng, hãy nhập số nguyên của bạn, sau đó bất kỳ ký tự nào sẽ làm hỏng luồng đầu vào - mọi ký tự không có số sẽ hoạt động.

Đầu vào: 0 1 0 x

Đầu ra: 1


Bạn có thể sử dụng dequethay vì a vectorđể có được 2 ký tự.
Morwenn

Ngoài ra, thay vì sử dụng ij, bạn có thể khai báo int i;ngay sau khi thu thập và sử dụng là hai vòng thay vì khai báo hai biến.
Morwenn

Cuối cùng, bạn có thể thoát khỏi gia số i++trong vòng lặp for và bắt đầu điều kiện của mình bằng cách if(v[++i]>[i-1]...lấy lại một ký tự.
Morwenn


2

Python 2.7 - 73 byte

e=lambda l:[l[i]for i in range(1,len(l)-1)if(l[i]-l[i-1])*(l[i]-l[i+1])]

Không quá ấn tượng (Nhìn vào mọi yếu tố của danh sách ngoại trừ đầu tiên và cuối cùng, xem nó lớn hơn hoặc nhỏ hơn so với hàng xóm của nó). Tôi hầu như chỉ đăng nó vì không phải ai cũng biết bạn có thể làm x<y>zvà để nó hoạt động. Tôi nghĩ đó là loại gọn gàng.

Vâng, x<y>zlà một tính năng thú vị của python, nhưng nó không thực sự tối ưu trong trường hợp này. Cảm ơn VX về thủ thuật nhân, điều đó hoàn toàn không xảy ra với tôi. Wrzlprmft nhắc nhở tôi rằng khai báo một hàm ẩn danh là ít tổ hợp phím hơn def x(y):.


if(l[i]-l[i-1])*(l[i]-l[i+1])>0sẽ giảm mã xuống 11 ký tự ...
VX

@wrz À, bạn nói đúng. Tôi đã bị loại bỏ bởi thực tế def e(l):\n là cùng số lượng ký tự e=lambda l:, nhưng tôi quên rằng bạn không cần phải sử dụng returntừ khóa. Cảm ơn!
undergroundmonorail

@vx ơi, mình thích thế lắm. Cảm ơn bạn :) chỉnh sửa: Thật ra bạn có thể tiết kiệm nhiều hơn thế! Kể từ khi (l[i]-l[i-1])*(l[i]-l[i+1])1nếu l[i]là một cực đoan địa phương và 0nếu không, tôi không cần phải sử dụng >0. Tôi chỉ có thể để python giải thích nó như là một bool. :)
undergroundmonorail

@wrz Tôi không thể tìm ra cách chỉnh sửa nhận xét đã được chỉnh sửa (biểu tượng bút chì dường như thay thế nút chỉnh sửa. Đây có phải là do thiết kế không?). Tôi chỉ muốn nói thêm rằng, nếu tôi thông minh, tôi đã nhận ra rằng chức năng một dòng của tôi hoàn toàn không cần \n khai báo! Điều đó sẽ cứu hai nhân vật, nhưng việc đưa vào returnvẫn khiến nó không xứng đáng.
undergroundmonorail

2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]

1
Điều này chỉ kiểm tra tối đa cục bộ, cho minumum cần thêm | | x <min pn
karakfa

x>p&&x>ncó ít ký tự hơn x>max p n:-)
yatima2975

không gian sau ,cũng không cần thiết.
karakfa

1
thay đổi x>p&&x>nđể (x>p)==(x>n)tối thiểu địa phương quá, thêm 4 ký tự.
karakfa

2

Thạch , 8 byte

IṠIỊ¬T‘ị

Hãy thử trực tuyến!

Giải trình

IṠIỊ¬T‘ị
I          Differences between adjacent elements {of the input}
 Ṡ         Take the sign of each difference
  I        Differences between adjacent difference signs
   Ị       Mark the elements that are     in the range -1..1 inclusive
    ¬                                 not
     T     Take the indexes of the marked elements
      ‘      with an offset of 1
       ị   Index back into the original list

Một phần tử chỉ là một cực trị cục bộ nếu sự khác biệt của nó với hàng xóm bên trái của nó có dấu hiệu trái ngược với sự khác biệt của nó với hàng xóm bên phải của nó, tức là các dấu hiệu của sự khác biệt khác nhau 2 hoặc -2. Jelly có một số nguyên thủy hữu ích để xử lý "tìm phần tử với các thuộc tính nhất định" (đặc biệt, chúng ta có thể tìm các phần tử có thuộc tính nhất định trong một danh sách và sử dụng phần tử đó để trích xuất các phần tử từ danh sách khác), nghĩa là chúng ta có thể dịch lại danh sách ban đầu trực tiếp ít nhiều (chúng ta chỉ cần bù 1 bởi vì các yếu tố đầu tiên và cuối cùng của danh sách gốc đã bị mất trong phần chênh lệch).


1

Python có Numpy - 81 74 67 byte ( 61 54 không có importdòng)

import numpy
e=lambda a:a[1:-1][(a[2:]-a[1:-1])*(a[1:-1]-a[:-2])<0]

Đầu vào cần phải là một mảng Numpy.


1

C, 83

x,y,z;main(){y=z=0;while(scanf("%d",&x)){(y-z)*(y-x)>0?printf("%d ",y):1;z=y,y=x;}}

1

awk - 32 ký tự

{c=b;b=a;a=$0;$0=b}(b-c)*(a-b)<0

Không có hy vọng đánh bại một ngôn ngữ như J hay APL vì sự ngắn gọn, nhưng tôi nghĩ dù sao tôi cũng sẽ ném mũ vào vòng. Giải trình:

  • Tại bất kỳ thời điểm nào, a, b, và cgiữ x_i, x_(i-1)x_(i-2)
  • b-ca-bgần đúng đạo hàm trước và saux_(i-1)
  • Nếu sản phẩm của họ âm tính, thì một sản phẩm âm tính và sản phẩm khác là tích cực, do đó x_(i-1)là một cực trị cục bộ, vì vậy hãy in

1

Brachylog , 17 byte

s₃{b≠h.&k≠&{⌉|⌋}}

Hãy thử trực tuyến!

Đưa đầu vào qua biến đầu vào và tạo đầu ra thông qua biến đầu ra.

s₃{             }    For a length-3 substring of the input:
  {b                 its last two elements
    ≠                are distinct,
     h               and the first of those elements is
      .              the output variable;
       &k            its first two elements
         ≠           are also distinct;
          &{⌉| }     either its largest element
          &{ |⌋}     or its smallest element
                }    is also the output variable.

Nếu chạy các giá trị có thể được đảm bảo vắng mặt, s₃{{⌉|⌋}.&bh}sẽ tiết kiệm bốn byte.



1

Ngôn ngữ Wolfram (Mathicala) , 43 42 byte

#~Pick~ArrayFilter[#[[2]]!=Median@#&,#,1]&

Hãy thử trực tuyến!

Tôi đoán Nothinglà quá dài ...

#~Pick~                                  &  (* select elements of the input where, *)
       ArrayFilter[                 ,#,1]   (*  when considering the block of length 1 *)
                                            (*    on either side of that element, *)
                   #[[2]]!=Median@#&        (*  its median is not that element *)

1

05AB1E , 11 10 byte

¥.±¥Ä2Q0šÏ

Hãy thử trực tuyến hoặc xác minh một vài trường hợp thử nghiệm .

Giải trình:

¥           # Get the forward differences (deltas) of the (implicit) input-list
            #  i.e. [9,10,7,6,9,0,3,3,1,10] → [1,-3,-1,3,-9,3,0,-2,9]
          # Get the signum of each delta (-1 if neg.; 0 if 0; 1 if pos.)
            #  → [1,-1,-1,1,-1,1,0,-1,1]
   ¥        # Get the forward differences of that list again
            #  → [-2,0,2,-2,2,-1,-1,2]
    Ä       # Convert each integer to its absolute value
            #  → [2,0,2,2,2,1,1,2]
     2Q     # And now check which ones are equal to 2 (1 if truthy; 0 if falsey)
            #  → [1,0,1,1,1,0,0,1]
       0š   # Prepend a 0
            #  → [0,1,0,1,1,1,0,0,1]
         Ï  # And only leave the values in the (implicit) input-list at the truthy indices
            #  → [10,6,9,0,1]
            # (after which the result is output implicitly)

0

PHP, 116 114 113

function _($a){for(;$a[++$i+1];)if(($b=$a[$i])<($c=$a[$i-1])&$b<($d=$a[$i+1])or$b>$c&$b>$d)$r[]=$a[$i];return$r;}

Ví dụ sử dụng:

print_r(_(array(2, 1, 2, 3, 4, 3, 2, 3, 4)));

Array
(
    [0] => 1
    [1] => 4
    [2] => 2
)

0

Haskell, 70C

Phiên bản chơi gôn

e(a:b:c:r)
 |a<b&&b>c||a>b&&b<c=b:s
 |True=s
 where s=e(b:c:r)
e _=[]

Phiên bản ung dung

-- if it's possible to get three elements from the list, take this one
extrema (a:b:c:rest)
    | a<b && b>c = b:rec
    | a>b && b<c = b:rec
    | otherwise = rec
    where rec = extrema (b:c:rest)
-- if there are fewer than three elements in the list, there are no extrema
extrema _ = []

0

Javascript: 102 ký tự

function h(a){for(u=i=[];++i<a.length-1;)if(x=a[i-1],y=a[i],z=a[i+1],(x-y)*(y-z)<0)u.push(y);return u}

0

APL, 19 byte

{⍵/⍨0,⍨0,0>2×/2-/⍵}

Tôi đã chuyển đổi phiên bản 20 char J sang APL. Nhưng tôi thêm số 0 vào đầu và cuối thay vì xóa chữ số đầu tiên và chữ số cuối. Nếu không, nó hoạt động giống như phiên bản J.

- Thông số chính thức omega. Đây là đầu vào của chức năng.


Trong khi chúng tôi ở đó, tôi cũng có phiên bản K, gồm 22 ký tự: {x@1+&0>2_*':-':0 0,x} . 6 trong số các ký tự này ( 2_0 0,) được dành để bảo vệ chống lại lỗi độ dài nếu đối số ngắn hơn hai mục, vì vậy nếu không có vấn đề đó thì sẽ là 16 ... Hành động cũng hơi khác một chút - chúng ta phải chuyển boolean liệt kê vào một danh sách các chỉ mục với 1+&và sử dụng nó để lập chỉ mục xlại - nhưng nó ngắn hơn và cũng là một việc rất K-ish phải làm.
thuật toán

Phiên bản K của bạn sẽ đánh bại phiên bản APL của tôi sau đó. Mã của tôi cần ít nhất hai số.
dùng10639

0

Python 2 , 59 byte

f=lambda l=0,c=0,*r:r and(c,)*(l<c>r[0]or l>c<r[0])+f(c,*r)

Hãy thử trực tuyến!

Hàm này chủ yếu tránh việc lập chỉ mục tốn kém, bằng cách lấy các yếu tố của danh sách làm đối số, thay vì chính danh sách. Mặc dù có nhiều hơn một yếu tố còn lại trong danh sách, chúng tôi đệ quy xây dựng danh sách, kiểm tra tối đa ở mỗi bước.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.