เขียนโปรแกรม (หรือฟังก์ชั่น) ที่แสดงความซับซ้อนของเวลาO ขนาดใหญ่ สี่ทั่วไปขึ้นอยู่กับวิธีการทำงาน ในรูปแบบใดก็จะใช้เวลาในจำนวนเต็มบวก N ที่คุณอาจคิดน้อยกว่า 2 วันที่ 31
เมื่อโปรแกรมทำงานในรูปแบบดั้งเดิมควรมีความซับซ้อนคงที่ นั่นคือความซับซ้อนควรจะΘ (1)หรือเท่ากันΘ (1 ^ N)
เมื่อโปรแกรมกลับด้านและรันควรมีความซับซ้อนเชิงเส้น นั่นคือความซับซ้อนควรจะΘ (N)หรือเท่ากันΘ (N ^ 1)
(สิ่งนี้สมเหตุสมผลเนื่องจากN^1
มีการ1^N
ย้อนกลับ)เมื่อโปรแกรมสองเท่า , ตัดแบ่งเช่นกับตัวเองและเรียกมันควรจะมีการชี้แจงความซับซ้อนโดยเฉพาะ2 N นั่นคือความซับซ้อนควรจะΘ (2 ^ N)
(นี้ทำให้รู้สึกตั้งแต่2
ใน2^N
เป็นสองเท่า1
ใน1^N
.)เมื่อโปรแกรมสองเท่าและย้อนกลับและเรียกมันควรจะมีพหุนามความซับซ้อนโดยเฉพาะN 2 นั่นคือความซับซ้อนควรจะΘ (N ^ 2)
(สิ่งนี้สมเหตุสมผลเนื่องจากN^2
มีการ2^N
ย้อนกลับ)
สี่กรณีนี้เป็นกรณีเดียวที่คุณต้องจัดการ
โปรดทราบว่าเพื่อความแม่นยำฉันใช้สัญลักษณ์ขนาดใหญ่ที (Θ)แทนO ใหญ่เพราะรันไทม์ของโปรแกรมของคุณจะต้องล้อมรอบทั้งด้านบนและด้านล่างด้วยความซับซ้อนที่จำเป็น มิฉะนั้นเพียงแค่เขียนฟังก์ชั่นใน O (1) จะตอบสนองทั้งสี่จุด มันไม่สำคัญเกินไปที่จะเข้าใจความแตกต่างที่นี่ ส่วนใหญ่หากโปรแกรมของคุณกำลังดำเนินการ k * f (N) สำหรับค่าคงที่ k บางค่าอาจเป็นΘ (f (N))
ตัวอย่าง
ถ้าโปรแกรมเดิมถูก
ABCDE
จากนั้นเรียกใช้มันควรจะใช้เวลาคงที่ นั่นคือไม่ว่าอินพุต N เป็น 1 หรือ 2147483647 (2 31 -1) หรือค่าใด ๆ ที่อยู่ระหว่างนั้นควรจะสิ้นสุดลงในเวลาเท่ากัน
เวอร์ชันที่ตรงกันข้ามของโปรแกรม
EDCBA
ควรใช้เวลาเชิงเส้นในแง่ของ N นั่นคือเวลาที่ใช้ในการยุติควรเป็นสัดส่วนประมาณ N ดังนั้น N = 1 ใช้เวลาน้อยที่สุดและ N = 2147483647 ใช้เวลามากที่สุด
โปรแกรมเวอร์ชันสองเท่า
ABCDEABCDE
ควรใช้เวลาสอง-to--N ในแง่ของเอ็นนั่นคือเวลาที่ใช้ในการยุติควรจะเป็นสัดส่วนถึง 2 N ดังนั้นหาก N = 1 ยุติลงในเวลาประมาณหนึ่งวินาที N = 60 จะใช้เวลานานกว่าอายุของเอกภพที่จะยุติ (ไม่คุณไม่ต้องทดสอบ)
เวอร์ชันของโปรแกรมสองเท่าและกลับด้าน
EDCBAEDCBA
ควรใช้เวลายกกำลังสองในแง่ของ N นั่นคือเวลาที่ใช้ในการยุติควรเป็นสัดส่วนประมาณ N * N ดังนั้นหาก N = 1 ยุติลงในเวลาประมาณหนึ่งวินาที N = 60 จะใช้เวลาประมาณหนึ่งชั่วโมงในการยกเลิก
รายละเอียด
คุณต้องแสดงหรือยืนยันว่าโปรแกรมของคุณกำลังทำงานอยู่ในความซับซ้อนที่คุณบอกว่าเป็น การให้ข้อมูลเวลาเป็นความคิดที่ดี แต่พยายามอธิบายว่าทำไมความซับซ้อนในเชิงทฤษฎีจึงถูกต้อง
มันก็โอเคถ้าในทางปฏิบัติเวลาที่โปรแกรมของคุณไม่ได้แสดงถึงความซับซ้อนของมันอย่างสมบูรณ์ (หรือแม้แต่กำหนดขึ้น) เช่นอินพุต N + 1 บางครั้งอาจทำงานเร็วกว่า N
สภาพแวดล้อมที่คุณใช้งานโปรแกรมของคุณนั้นสำคัญ คุณสามารถตั้งสมมติฐานพื้นฐานว่าภาษายอดนิยมไม่เคยเสียเวลาในขั้นตอนวิธีอย่างไรตัวอย่างเช่นถ้าคุณรู้ว่า Java เวอร์ชันเฉพาะของคุณใช้การจัดเรียงฟองแทนที่จะเป็นอัลกอริทึมการเรียงลำดับที่เร็วขึ้นคุณควรคำนึงถึงเรื่องนั้นด้วย .
สำหรับความซับซ้อนทั้งหมดที่นี่สมมติว่าเรากำลังพูดถึงสถานการณ์กรณีที่เลวร้ายที่สุดไม่ใช่กรณีที่ดีที่สุดหรือกรณีเฉลี่ย
ความซับซ้อนของพื้นที่ของโปรแกรมไม่สำคัญเพียงความซับซ้อนของเวลาเท่านั้น
โปรแกรมอาจแสดงผลอะไรก็ได้ มันสำคัญแค่ว่าพวกมันใช้จำนวนเต็มบวก N และมีความซับซ้อนของเวลาที่ถูกต้อง
อนุญาตให้แสดงความคิดเห็นและโปรแกรมหลายบรรทัดได้ (คุณอาจสันนิษฐานว่า
\r\n
ตรงกันข้าม\r\n
สำหรับความเข้ากันได้กับ Windows)
การแจ้งเตือน Big O
ตั้งแต่เร็วที่สุดไปจนถึงช้าที่สุดO(1), O(N), O(N^2), O(2^N)
(สั่งซื้อ 1, 2, 4, 3 ด้านบน)
O(2^N + N^2 + N) = O(2^N)
แง่ช้าเสมอครองเช่น
O(k*f(N)) = O(f(N))
สำหรับค่าคงที่ k ดังนั้นและO(2) = O(30) = O(1)
O(2*N) = O(0.1*N) = O(N)
โปรดจำไว้และO(N^2) != O(N^3)
O(2^N) != O(3^N)
เกณฑ์การให้คะแนน
นี่คือรหัสกอล์ฟปกติ โปรแกรมดั้งเดิมที่สั้นที่สุด (เวลาหนึ่งคงที่) เป็นไบต์ชนะ
n = input(); for i in xrange(n): pass
จึงมีความซับซ้อนแบบเอกซ์โพเนนเชียลเพราะมัน2 ** k
ทำตามขั้นตอนซึ่งk = log_2(n)
เป็นขนาดอินพุต คุณควรชี้แจงว่าเป็นกรณีนี้หรือไม่เนื่องจากมีการเปลี่ยนแปลงข้อกำหนดอย่างมาก