การนับที่มีประสิทธิภาพ


35

เมื่อฉันยังเป็นเด็กและต้องการนับเงินดอลลาร์ในการออมชีวิตของฉันฉันจะนับดัง ๆ :

หนึ่งสองสามสี่ห้าหกเจ็ดแปดเก้าสิบ;
สิบเอ็ด, สิบสาม, สิบสาม, สิบสี่, สิบห้า, สิบหก, สิบเจ็ด, สิบแปด, สิบแปด, สิบเก้า, ยี่สิบ;
ยี่สิบเอ็ด, ยี่สิบสอง, ยี่สิบสาม, ยี่สิบสี่, ยี่สิบห้า ...

ในที่สุดฉันก็เบื่อที่จะออกเสียงแต่ละพยางค์เหล่านี้ ด้วยความคิดทางคณิตศาสตร์ฉันได้สร้างวิธีการนับที่มีประสิทธิภาพมากขึ้น:

หนึ่งสองสามสี่ห้าหกเจ็ดแปดเก้าสิบ;
หนึ่ง, สอง, สาม, สี่, ห้า, หก, เจ็ด, แปด, เก้า, ยี่สิบ;
หนึ่ง, สอง, สาม, สี่, ห้า, หก, เจ็ด, แปด, เก้า, สามสิบ ...

อย่างที่คุณเห็นฉันจะออกเสียงเฉพาะตัวเลขที่เปลี่ยนไปจากตัวเลขก่อนหน้า นี่เป็นข้อได้เปรียบที่เพิ่มเติมว่ามีความซ้ำซ้อนมากกว่าชื่อภาษาอังกฤษสำหรับตัวเลขดังนั้นจึงต้องใช้พลังสมองน้อยในการคำนวณ

ท้าทาย

เขียนโปรแกรม / ฟังก์ชั่นซึ่งใช้จำนวนเต็มบวกและเอาท์พุท / คืนค่าวิธีที่ฉันจะนับ: นั่นคือหลักที่ไม่เป็นศูนย์ที่เหมาะสมที่สุดและเลขศูนย์ทั้งหมดต่อท้าย

ตัวอย่าง

   1    1
   2    2
  10   10
  11    1
  29    9
  30   30
  99    9
 100  100
 119    9
 120   20
 200  200
 409    9
1020   20

รายชื่อกรณีทดสอบทั้งหมดไม่จำเป็น นี่คือA274206บน OEIS

กฎระเบียบ

  • รายการของคุณจะต้องทำงานในเชิงบวกสำหรับจำนวนเต็มบวกทั้งหมดโดยไม่สนใจปัญหาความแม่นยำและหน่วยความจำ
  • อินพุตและเอาต์พุตต้องเป็นทศนิยม
  • คุณอาจเลือกที่จะรับอินพุตและ / หรือเอาท์พุทเป็นตัวเลขสตริงหรืออาร์เรย์ของตัวเลข
  • อินพุตรับประกันว่าจะเป็นจำนวนเต็มบวก รายการของคุณสามารถทำอะไรก็ได้เพื่อการป้อนข้อมูลที่ไม่ถูกต้อง

นี่คือดังนั้นโค้ดที่สั้นที่สุดในหน่วยไบต์ชนะ


ดังนั้น "เป็นทศนิยม" จึงรวมรายการเลขทศนิยมเช่น[1,0,2,0]-> [2,0]สำหรับกรณีทดสอบครั้งสุดท้าย (ฉันไม่ชัดเจนในวลี "อาร์เรย์รายการเดียว")
Jonathan Allan

1
@JonathanAllan โดย "single-item array" ฉันหมายถึงอาร์เรย์ที่มีตัวเลขหรือสตริงเดียวซึ่งแสดงถึงจำนวนเต็ม ฉันไม่คิดว่าการอนุญาตให้ใช้อาร์เรย์ของตัวเลขเป็นความคิดที่ดี แต่ตอนนี้มันดูเหมือนว่าเป็นข้อ จำกัด โดยพลการเนื่องจากอนุญาตให้ใช้สตริงได้ (และสตริงมีความคล้ายคลึงกับอาร์เรย์ในหลายภาษามาก) ดังนั้นฉันจะอนุญาตให้มีอาร์เรย์ของตัวเลขหากไม่มีเหตุผลที่ดีที่จะไม่
ETHproductions

5
คุณขโมยความลับของฉัน: P
LegionMammal978

1
ฉันคิดว่าเกือบทุกคนนับว่าเป็นเด็ก ;) อย่างน้อยฉันก็ทำได้เช่นกัน :)
Kevin Cruijssen

7
@KevinCruijssen "เป็นเด็ก" หรือไม่?
Martin Ender

คำตอบ:


19

Python 2 , 28 ไบต์

f=lambda n:n%10or 10*f(n/10)

ลองออนไลน์!

สูตรเรียกซ้ำทำงานได้อย่างหมดจด หากตัวเลขหลักสุดท้ายไม่ใช่ศูนย์ให้ส่งออก มิฉะนั้นลบศูนย์สุดท้ายคำนวณผลลัพธ์สำหรับสิ่งนั้นและคูณด้วย 10


11

เยลลี่ , 6 3 ไบต์

-3 ไบต์โดยมี I / O เป็นรายการทศนิยมของตัวเลข

ṫTṪ

ชุดทดสอบที่ลองใช้ออนไลน์!

อย่างไร?

ṫTṪ - Main link: listOfDigits  e.g.  [1,    0,    2,    0]  or [1,      1,    9  ]
 T  - truthy indexes                 [1,          3      ]     [1,      2,    3  ]
ṫ   - tail (vectorises)              [[1,0,2,0],  [2,0]  ]     [[1,1,9],[1,9],[9]]
  Ṫ - tail pop                                    [2,0]                       [9]

หากเราไม่สามารถรับค่าทศนิยมรายการ 6 byter คือ:

DµṫTṪḌ

ซึ่งคุณสามารถดูที่นี่

สิ่งนี้ทำสิ่งเดียวกัน แต่แปลงจำนวนเต็มเป็นรายการทศนิยมล่วงหน้าและแปลงกลับเป็นจำนวนเต็มหลังจากนั้น


ขณะที่ฉันเลื่อนดูคำตอบแรก ๆ ฉันพูดกับตัวเองว่า "ฉันพนันได้เลยว่าจะมีวิธีแก้ปัญหาวุ้นขนาด 3 ไบต์ ... "
DLosc

9

C, 30 29 27 ไบต์

ภูมิใจในสิ่งนี้เนื่องจากฉันใช้การละเมิดสองวิธีในการเล่นกอล์ฟนี้ (อธิบายที่ท้ายโพสต์); นี่คือเฉพาะสำหรับ C (GCC)


3) b=10;f(a){a=a%b?:b*f(a/b);}// 27 ไบต์

2) b;f(a){b=a=a%10?:10*f(a/10);}// 29 ไบต์

1) f(i){return i%10?:10*f(i/10);}// 30 ไบต์

ลองออนไลน์ (รุ่น 27 ไบต์)


ความพยายามครั้งแรก (30 ไบต์): การละเมิดความจริงที่ว่าใน GCC หากไม่มีการประกาศค่าในแบบไตรภาคจะส่งคืนค่าเงื่อนไข ดังนั้นผู้ประกอบการที่สามของฉันจึงว่างเปล่าสำหรับค่าส่งคืนความจริง

ความพยายามครั้งที่สอง (29 ไบต์): ละเมิดข้อผิดพลาดของหน่วยความจำใน GCC ซึ่งเท่าที่ฉันเข้าใจหากฟังก์ชั่นไม่มีค่าตอบแทนเมื่อตัวแปรมากกว่าสองตัวถูกใช้อย่างมีความหมายในฟังก์ชันค่าชุดสุดท้ายของตัวแปรอาร์กิวเมนต์แรก จะถูกส่งกลับ
   (แก้ไข: แต่ "set value" นี้ต้องตั้งค่าในบางวิธีตัวอย่างเช่นการตั้งค่าตัวแปรด้วย=หรือใช้+=งานได้ แต่การตั้งค่าด้วย%=ไม่ทำงาน; แปลก)

ความพยายามครั้งที่สาม (27 ไบต์): เนื่องจากฉันต้องใช้ตัวแปรที่สอง (b) อย่างมีความหมายเพื่อใช้หน่วยความจำที่ผิดพลาดดังกล่าวข้างต้นฉันจึงอาจใช้มันเป็นตัวแปรจริงสำหรับ "10" เพื่อทดแทน
   (หมายเหตุ: ฉันควรจะสามารถสลับa=a%bกับa%=bบันทึกไบต์อื่นได้ แต่น่าเสียดายที่นี่ทำให้หน่วยความจำบั๊กใช้ประโยชน์จากด้านบนเพื่อหยุด "ทำงาน" ดังนั้นฉันจึงไม่สามารถ)


คุณอาจต้องการเพิ่ม "GCC" ในชื่อคำตอบของคุณเนื่องจากเป็นคำเฉพาะของ GCC (ไม่สามารถใช้เสียงดังกราว) นอกจากนี้ "ข้อผิดพลาดหน่วยความจำ" อาจเป็นพฤติกรรมที่ไม่ได้กำหนดซึ่งเกิดขึ้นเนื่องจากโครงร่างสแต็กเฟรมเฉพาะที่ GCC ใช้ มันอาจไม่ทำงานบนแพลตฟอร์มอื่น ๆ แม้แต่กับ GCC
simon

@gurka เสร็จแล้วขอบคุณ
Albert Renshaw

7

เรติน่า7 7ไบต์

!`.0*$

ลองออนไลน์ (กรณีทดสอบทั้งหมด)

จับคู่เอาต์พุตของตัวเลขตามด้วยศูนย์ใด ๆ ที่ท้ายสตริงอินพุต แม้ว่าจะไม่จำเป็น แต่สิ่งนี้ก็เกิดขึ้นได้เช่น0กัน


อืมมมผมได้คิด[1-9](หรือ[^0]) \dจำเป็นจะต้องแทน ฉันเดาว่าความโลภของการ*รับประกันผลลัพธ์ที่ถูกต้องทุกครั้ง
ETHproductions

@ETHproductions สิ่งนี้ไม่มีส่วนเกี่ยวข้องกับความโลภ*แต่ด้วยความจริงที่ว่าการค้นหานั้นตรงกันจากซ้ายไปขวา \d0*?$ก็จะทำงานเช่นกัน
Martin Ender

ใช้ regex .0*$ควรทำงาน
12Me21

หากมีวิธี (สั้นพอ) ในการแสดงผลเฉพาะนัดที่แล้วคุณสามารถใช้.0*
12Me21

@ 12Me21 วิธีเดียวที่จะทำคือจับคู่เหตุการณ์ที่เกิดขึ้นครั้งสุดท้ายเท่านั้นหรือใช้การแทนที่หรืออะไรบางอย่าง มันจะไม่สั้นลง
mbomb007

7

Cubix , 18 32ไบต์

ฉันคิดว่าฉันจะต้องใช้เวลาในภายหลังและดูว่าฉันสามารถบีบอัดได้ไหม แต่สำหรับช่วงเวลาที่นี่มันเป็น
ปรากฎว่าฉันกำลังคิดเกี่ยวกับวิธีที่ผิดทั้งหมดนี้ ตอนนี้กระบวนการจะใช้ mod (1,10,100,1000, ... ) แบบเพิ่มหน่วยกับอินพุตจำนวนเต็มและพิมพ์ค่าแรกซึ่งไม่เป็นศูนย์ บิตน่าเบื่อมากขึ้น แต่สั้นกว่า

!N%*I1^\.u;u@O\;;r

ลองที่นี่

    ! N
    % *
I 1 ^ \ . u ; u
@ O \ ; ; r . .
    . .
    . .

มีความสุขเสมอที่จะเห็นคำตอบ Cubix :)
โอลิเวอร์

@obarakon ได้รับการปรับปรุงที่จะวางในไม่ช้า ทำสิ่งนี้ผิดจริง ๆ
MickyT

5

JavaScript ขนาด 21 ไบต์

f=n=>n%10||10*f(n/10)

กรณีทดสอบ


5

Javascript 19 18 ไบต์

ขอบคุณ ETHproductions สำหรับการเล่นกอล์ฟหนึ่งไบต์และ Patrick Roberts สำหรับการเล่นกอล์ฟสองไบต์

x=>x.match`.0*$`

ส่งคืนอาร์เรย์ของสตริงที่ตรงกับ regex ของการเป็นที่ส่วนท้ายของสายป้อนที่มีตัวละครใด ๆ ตามด้วยจำนวนศูนย์ที่เป็นไปได้ที่ใหญ่ที่สุด

ลองออนไลน์


5
ฉันไม่คิดว่าคุณต้องการgเพราะมีเพียงหนึ่งการแข่งขันที่จะหา
ETHproductions

ประหยัด 2 ไบต์โดยใช้x=>x.match`.0*$`
Patrick Roberts



3

Brachylogขนาด 2 ไบต์

a₁

ลองออนไลน์!

builtin คำต่อท้ายa₁สำหรับจำนวนเต็มจะดำเนินการตาม:

brachylog_adfix('integer':1, 'integer':0, 'integer':0).
brachylog_adfix('integer':1, 'integer':I, 'integer':P) :-
    H #\= 0,
    H2 #\= 0,
    abs(P) #=< abs(I),
    integer_value('integer':Sign:[H|T], I),
    integer_value('integer':Sign:[H2|T2], P),
    brachylog_adfix('integer':1, [H|T], [H2|T2]).

Brachylog integer_value/2ชอบที่จะสามารถที่จะรักษาจำนวนเต็มเป็นรายการของตัวเลขและการที่จะใช้กริยายูทิลิตี้ที่กำหนดเอง สิ่งที่น่าสนใจเกี่ยวกับinteger_value/2ที่นี่คือเนื่องจากต้องสามารถแปลรายการหลักด้วยศูนย์นำได้อย่างถูกต้องมันยังสามารถแปลจำนวนเต็มเป็นรายการหลักด้วยศูนย์นำหน้าดังนั้นเพรดิเคตที่ไม่ต้องการให้ เกิดขึ้น (ส่วนใหญ่ของพวกเขาโดยเฉพาะอย่างยิ่งคนที่ไม่ชอบa) ห้ามมิให้หัวของรายการหลักของพวกเขาจากการเป็น 0 ดังนั้นในขณะที่a₁สร้างคำต่อท้ายที่สั้นที่สุดก่อนสำหรับรายการและสตริงมันข้ามเหนือต่อท้ายของจำนวนเต็ม นอกเหนือจากการลบข้อมูลที่ซ้ำกันออกไปยังหมายความว่าคำต่อท้ายแรกที่สร้างขึ้นนั้นเป็นตัวเลขที่ไม่เป็นศูนย์ทางด้านขวาสุดด้วยเลขศูนย์ทั้งหมด


2

Brain-Flak , 74 ไบต์

{({}<>)<>}(()){{}<>(({}<>)[((((()()()){}){}){}){}]<(())>){((<{}{}>))}{}}{}

ลองออนไลน์!

พิมพ์ non-0 ล่าสุดและ 0 ต่อท้ายทั้งหมดเท่านั้น

คำอธิบาย:

{({}<>)<>}                    # Move everything to the other stack (reverse the input)
(())                          # Push a 1 to get started
{                             # do...
  {}<>                        #   pop the result of the equals check (or initial 1)
  (                           #   push...
    ({}<>)                    #     the top value from the other stack (also put this on the stack)
    [((((()()()){}){}){}){}]  #     minus the ASCII value of 0
    <(())>                    #     on top of a 1
  )                           #   close the push   
  {                           #   if not zero (ie. if not equal)
    ((<{}{}>))                #     replace the 1 from 3 lines back with a 0
  }{}                         #   end if and pop the extra 0
}                             # while the copied value != "0"
{}                            # pop the result of the equals check

2

เป็นกลุ่ม, 19 ไบต์

สองรุ่นทั้ง 19 ไบต์:

:s/\v.*([^0]0*)/\1
:s/.*\([^0]0*\)/\1

รวมทั้งการขึ้นบรรทัดใหม่ของการขึ้นลงแต่ละครั้ง

ตรวจสอบกรณีทดสอบออนไลน์ทั้งหมด! (เพิ่มหนึ่งไบต์เพื่อทดสอบในหลายบรรทัด)



2

R, 33 ไบต์

นำมาใช้เป็นฟังก์ชั่นที่ไม่มีชื่อ

function(x)rle(x%%10^(0:99))$v[2]

สิ่งนี้ใช้ mod 10 ^ 0 ถึง 10 ^ 99 rleใช้เพื่อลดผลลัพธ์ลงเพื่อให้รายการที่สองเป็นผลลัพธ์ที่เราต้องการเสมอ
ลองออนไลน์!


2

Zsh , 18 16 ไบต์

<<<${(M)1%[^0]*}

ลองออนไลน์! ลองออนไลน์!

Bashขนาด 25 ไบต์

r=${1%[^0]*}
echo ${1#$r}

ลองออนไลน์!


Shells ต้องเรียกโปรแกรมภายนอกเพื่อใช้ regex ดังนั้นเราต้องทำด้วยการวนรอบ

ส่วน${1%[^0]*}ขยายตรงกับส่วนต่อท้ายที่สั้นที่สุดที่เริ่มต้นด้วยอักขระที่ไม่ใช่ศูนย์และลบออก

  • ใน Zsh การเพิ่มการ(M)ตั้งค่าสถานะทำให้คำต่อท้ายที่ตรงกันจะถูกเก็บไว้แทนการเอาออก
  • ใน Bash การ${1% }ขยายจะลบคำนำหน้าอะไรก็ตามที่เหลืออยู่

1

GNU sed , 17 14 + 1 (แฟล็ก r) = 15 ไบต์

แก้ไข:น้อยกว่า 2 ไบต์ขอบคุณRiley

s:.*([^0]):\1:

มันทำงานได้โดยการลบทุกอย่างจนกว่าตัวเลขที่ไม่ใช่ศูนย์จะถูกพิมพ์ออกมาพร้อมกับศูนย์ต่อท้ายที่มีอยู่ สคริปต์สามารถจัดการทดสอบหลายรายการในการทดสอบครั้งเดียวโดยแต่ละครั้งจะแยกกัน

ลองออนไลน์! (ตัวอย่างการทดสอบทั้งหมด)


1

Mathematica ขนาด 26 ไบต์

ฟังก์ชั่นเพียวซึ่งใช้รายการของตัวเลขและแสดงรายการของตัวเลข:

#/.{___,x_,y:0...}:>{x,y}&

คำอธิบาย

#                           First argument
 /.                           Replace
   {                              start of list followed by
    ___,                          zero or more elements followed by
        x_,                       an element (referred to later as x) followed by
           y:0...                 a sequence of zero or more 0s (referred to later as y) followed by
                 }                end of list
                  :>            with
                    {x,y}         {x,y}
                         &   End of function.

วิธีนี้ใช้งานได้เนื่องจากพบการจับคู่ซ้ายสุดสำหรับxซึ่งต้องเป็นองค์ประกอบที่ไม่ใช่ศูนย์ขวาสุดของรายการเนื่องจากตามด้วยลำดับศูนย์มากกว่า0s แล้วจึงสิ้นสุดรายการ


1

Java 8, 47 ไบต์

นี่คือการแสดงออกแลมบ์ดาที่กำหนดให้กับIntUnaryOperator:

x->{int m=1;for(;x%m<1;m*=10);return x%m*m/10;}

คำอธิบาย: คูณ m ด้วย 10 จนกระทั่งx%mไม่ใช่ 0 return x%m*m/10ต้องใช้การหารเนื่องจาก m เป็นลำดับความสำคัญมากกว่าผลลัพธ์ที่ต้องการ



1

MATL , 10 7 ไบต์

บันทึกได้ 3 ไบต์ด้วย@B เมธา!

tfX>Jh)

อินพุตและเอาต์พุตเป็นอาร์เรย์ของตัวเลข

ลองออนไลน์!

หรือตรวจสอบกรณีทดสอบทั้งหมด

คำอธิบาย

t     % Input string implicitly. Duplicate
f     % Push indices of non-zero digits
X>    % Keep maximum, say k
Jh    % Attach 1j to give [k, 1j]. This is interpreted as an index "k:end"
)     % Index into original string. Display implcitly

เนื่องจากเราได้รับอนุญาตให้นำเข้าและส่งออกเป็นเวกเตอร์ของจำนวนเต็มคุณสามารถลบ48-ทั้งหมดได้โดยประหยัด 3 ไบต์: ลองออนไลน์!
B. Mehta

1

C #, 30 28 ไบต์

ตามคำตอบ JavaScript นี้ดังนั้นฉันคิดว่าเครดิตทั้งหมดจะไปหาเขา

แข็งแรงเล่นกอล์ฟ

i=a=>a%10<1?10*i(a/10):a%10;
  • -2 bytes โดยลบ()ไปรอบ ๆaขอบคุณEmigna

1
ฉันคิดว่าคุณต้องตั้งชื่อฟังก์ชั่นiนี้ให้ชัดเจนเพื่อให้ทำงานได้ในขณะที่คุณใช้การสอบถามซ้ำ
Emigna

@Emigna คุณพูดถูก! ฉันพลาดไปโดยสิ้นเชิง :(
Metoniem

อัปเดตแล้ว แต่ฉันไม่แน่ใจ 100% ว่าแก้ไขด้วยวิธีนี้หรือไม่
Metoniem

1
ฉันไม่ทราบฉันทามติเกี่ยวกับเรื่องนี้ใน C # ไวยากรณ์นั้นถูกต้อง แต่จะใช้ได้เฉพาะเมื่อผู้รับมอบสิทธิ์ได้รับการประกาศแล้ว (ไม่เช่นiนั้นจะไม่ได้ประกาศสำหรับการโทรซ้ำ)
Emigna

1
วงเล็บaไม่จำเป็นต้องใช้ทั้งสองวิธี
Emigna

1

J, 27 ไบต์

10&|`(10*(p%&10))@.(0=10&|)

มันขึ้นอยู่กับสูตรของ xnor ดังนั้นให้เครดิตกับเขา


1

Kotlin, 49 ไบต์

แลมบ์ดาสามารถมอบหมายให้ (List<Int>) -> List<Int>

{a->a.slice(a.indexOfLast{it in 1..9}..a.size-1)}
  • ชื่อพารามิเตอร์โดยนัยitในindexOfLast
  • .. สำหรับช่วงอาคาร


1

05AB1E , 9 ไบต์

RD0Ê1k>£R

ลองออนไลน์! หรือเป็น ชุดทดสอบ

คำอธิบาย

R          # reverse input
 D         # duplicate
  0Ê       # check each for inequality with 0
    1k     # get the index of the first 1
      >    # increment
       £   # take that many digits from the input
        R  # reverse



@MagicOctopusUrn: นั่นเป็นเพียงการตรวจสอบหลักสุดท้าย ควรเป็นตัวเลขที่ไม่ใช่ศูนย์สุดท้ายและหลังทั้งหมด
Emigna


1

Stax , 5 ไบต์

æΩ$3╚

เรียกใช้และแก้ไขข้อบกพร่อง

ขั้นตอน:

  1. คำนวณ "multiplicity" 10 (นั่นคือจำนวนครั้งที่ 10 แบ่งเท่า ๆ กันอินพุท)
  2. เพิ่ม 1
  3. เก็บอักขระจำนวนมากนั้นไว้ทางด้านขวาของ (อินพุตเป็นสตริง)

1

05AB1E , 4 ไบต์

ĀÅ¡θ

I / O เป็นรายการตัวเลข

ลองออนไลน์หรือตรวจสอบกรณีทดสอบทั้งหมด (ชุดทดสอบมีการเข้าร่วมเพื่อให้อ่านง่ายขึ้น)

คำอธิบาย:

Ā     # Python-style truthify each digit in the (implicit) input-list (0 if 0; 1 if [1-9])
      #  i.e. [9,0,4,0,3,0,0] → [1,0,1,0,1,0,0]
 Å¡   # Split the (implicit) input-list on truthy values (1s)
      #  i.e. [9,0,4,0,3,0,0] and [1,0,1,0,1,0,0] → [[],[9,0],[4,0],[3,0,0]]
   θ  # And only leave the last inner list
      #  i.e. [[],[9,0],[4,0],[3,0,0]] → [3,0,0]
      # (after which it is output implicitly as result)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.