ปัญหา Sub-Array สูงสุดใน C++

Payha Sub Array Sungsud Ni C



ปัญหาอาเรย์ย่อยสูงสุดจะเหมือนกับปัญหาสไลซ์สูงสุด บทช่วยสอนนี้กล่าวถึงปัญหาของการเข้ารหัสใน C++ คำถามคือ ผลรวมสูงสุดของลำดับตัวเลขที่ต่อเนื่องกันภายในอาร์เรย์คือเท่าใด นี่อาจหมายถึงอาร์เรย์ทั้งหมด ปัญหานี้และวิธีแก้ไขในภาษาใดๆ เรียกว่า ปัญหาอาร์เรย์ย่อยสูงสุด อาร์เรย์สามารถมีตัวเลขติดลบได้

การแก้ปัญหาจะต้องมีประสิทธิภาพ จำเป็นต้องมีความซับซ้อนของเวลาที่เร็วที่สุด ณ ตอนนี้ อัลกอริธึมที่เร็วที่สุดสำหรับการแก้ปัญหาเป็นที่รู้จักในชุมชนวิทยาศาสตร์ว่าอัลกอริทึมของ Kadane บทความนี้อธิบายอัลกอริทึมของ Kadane ด้วย C++







ตัวอย่างข้อมูล

พิจารณาเวกเตอร์ (อาร์เรย์):



เวกเตอร์ < int > เอ = { 5 , - 7 , 3 , 5 , - สอง , 4 , - 1 } ;


สไลซ์ (อาร์เรย์ย่อย) ที่มีผลรวมสูงสุดคือลำดับ {3, 5, -2, 4} ซึ่งให้ผลรวมเป็น 10 ไม่มีลำดับอื่นใดที่เป็นไปได้ แม้แต่อาร์เรย์ทั้งหมด จะให้ผลรวมสูงถึง ค่า 10 ทั้งอาร์เรย์ให้ผลรวมเป็น 7 ซึ่งไม่ใช่ผลรวมสูงสุด



พิจารณาเวกเตอร์ต่อไปนี้:





เวกเตอร์ < int > ข = { - สอง , 1 , - 3 , 4 , - 1 , สอง , 1 , - 5 , 4 } ;


สไลซ์ (อาร์เรย์ย่อย) ที่มีผลรวมสูงสุดคือลำดับ {4, -1, 2, 1} ซึ่งให้ผลรวมเป็น 6 โปรดทราบว่าอาจมีตัวเลขติดลบภายในอาร์เรย์ย่อยสำหรับผลรวมสูงสุด

พิจารณาเวกเตอร์ต่อไปนี้:



เวกเตอร์ < int > ค = { 3 , สอง , - 6 , 4 , 0 } ;


สไลซ์ (อาร์เรย์ย่อย) ที่มีผลรวมสูงสุดคือลำดับ {3, 2} ซึ่งให้ผลรวมเป็น 5

พิจารณาเวกเตอร์ต่อไปนี้:

เวกเตอร์ < int > ด = { 3 , สอง , 6 , - 1 , 4 , 5 , - 1 , สอง } ;


อาร์เรย์ย่อยที่มีผลรวมสูงสุดคือลำดับ {3, 2, 6, -1, 4, 5, -1, 2} ซึ่งให้ผลรวมเป็น 20 เป็นอาร์เรย์ทั้งหมด

พิจารณาเวกเตอร์ต่อไปนี้:

เวกเตอร์ < int > อี = { 5 , 7 , - 4 , - 10 , - 6 , 6 , 5 , 10 , - 5 , สิบห้า , 4 , - 8 , - สิบห้า , - 22 } ;


มีอาร์เรย์ย่อยสองอาร์เรย์ที่มีผลรวมสูงสุดที่นี่ ผลรวมที่สูงกว่าคือสิ่งที่ถือเป็นวิธีแก้ปัญหา (คำตอบ) สำหรับปัญหาอาร์เรย์ย่อยสูงสุด อาร์เรย์ย่อยคือ: {5, 7} มีผลรวม 12 และ {6, 5, 10, -5, 15, 4} ที่มีผลรวม 35 แน่นอนว่าสไลซ์ที่มีผลรวม 35 คือ คำตอบ.

พิจารณาเวกเตอร์ต่อไปนี้:

เวกเตอร์ < int > ฉ = { - 4 , 10 , สิบห้า , 9 , - 5 , - ยี่สิบ , - 3 , - 12 , - 3 , 4 , 6 , 3 , สอง , 8 , 3 , - 5 , - สอง } ;


มีสองอาร์เรย์ย่อยที่มีผลรวมสูงสุด ผลรวมที่สูงกว่าคือสิ่งที่ถือเป็นวิธีแก้ปัญหาสำหรับปัญหาอาร์เรย์ย่อยสูงสุด อาร์เรย์ย่อยคือ: {10, 15, 9} ที่มีผลรวม 34 และ {4, 6, 3, 2, 8, 3} ที่มีผลรวม 26 แน่นอนว่าสไลซ์ที่มีผลรวม 34 คือ คำตอบเพราะปัญหาคือการมองหาอาร์เรย์ย่อยที่มีผลรวมสูงสุดไม่ใช่อาร์เรย์ย่อยที่มีผลรวมสูงกว่า

การพัฒนาอัลกอริทึมของ Kadane

ข้อมูลในบทช่วยสอนนี้ไม่ใช่งานต้นฉบับจาก Kadane เป็นวิธีการสอนอัลกอริทึมของ Kadane ของผู้เขียนเอง หนึ่งในเวกเตอร์ด้านบนที่มียอดรวมวิ่งอยู่ในตารางนี้:

ข้อมูล 5 7 -4 -10 -6 6 5 10 -5 สิบห้า 4 -8 -สิบห้า -22
วิ่งทั้งหมด 5 12 8 -สอง -8 -สอง 3 13 8 23 27 ยี่สิบเอ็ด 16 -6
ดัชนี 0 1 สอง 3 4 5 6 7 8 9 10 สิบเอ็ด 12 13

การรัน Total สำหรับดัชนีคือผลรวมของค่าก่อนหน้าทั้งหมดรวมทั้งค่าสำหรับดัชนี มีสองลำดับที่มีผลรวมสูงสุดที่นี่ คือ {5, 7} ซึ่งให้ผลรวม 12 และ {6, 5, 10, -5, 15, 4} ซึ่งให้ผลรวมเป็น 35 ลำดับที่ให้ผลรวม 35 คือสิ่งที่ต้องการ .

สังเกตว่าสำหรับยอดรวมที่กำลังรัน มีพีคสองค่าคือค่า 12 และ 27 พีคเหล่านี้สอดคล้องกับดัชนีสุดท้ายของสองลำดับ

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

เวกเตอร์อื่นจากด้านบนพร้อมผลรวมที่วิ่งอยู่ในตารางนี้:


มีสองลำดับที่มีผลรวมสูงสุด พวกมันคือ {10, 15, 9} ซึ่งให้ผลรวม 34; และ {4, 6, 3, 2, 8, 3} ซึ่งให้ผลรวมเป็น 26 ลำดับที่ให้ผลรวม 34 คือสิ่งที่ต้องการ

สังเกตว่าสำหรับยอดรวมที่รันอยู่ มีพีคสองค่าคือค่า 30 และ 13 พีคเหล่านี้สอดคล้องกับดัชนีสุดท้ายของสองลำดับ

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

รหัสโดยอัลกอริทึมของ Kadane ใน C++

รหัสที่ให้ไว้ในส่วนนี้ของบทความไม่จำเป็นต้องเป็นรหัสที่ Kadane ใช้ อย่างไรก็ตามมันเป็นโดยอัลกอริทึมของเขา โปรแกรมเช่นเดียวกับโปรแกรม C++ อื่นๆ จะเริ่มต้นด้วย:

#include
#include<เวกเตอร์>


ใช้เนมสเปซ std;

มีการรวมไลบรารี iostream ซึ่งรับผิดชอบอินพุตและเอาต์พุต ใช้เนมสเปซมาตรฐาน

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

int maxSunArray ( เวกเตอร์ < int > & อา ) {
int N = A.size ( ) ;

int maxSum = A [ 0 ] ;
int runTotal = A [ 0 ] ;

สำหรับ ( int ผม = 1 ; ผม < ยังไม่มีข้อความ; ฉัน++ ) {
int tempRunTotal = runTotal + A [ ผม ] ; // อาจเล็กกว่า A [ ผม ]
ถ้า ( อา [ ผม ] > tempRunTotal )
runTotal = A [ ผม ] ; // ใน กรณี อา [ ผม ] มากกว่าการวิ่งทั้งหมด
อื่น
runTotal = tempRunTotal;

ถ้า ( runTotal > maxAmount ) // เปรียบเทียบผลรวมสูงสุดทั้งหมด
maxSum = runTotal;
}

กลับ จำนวนเงินสูงสุด;
}


ขนาด N ของอาร์เรย์ที่กำหนด (เวกเตอร์) ถูกกำหนด ตัวแปร maxSum เป็นหนึ่งในผลรวมสูงสุดที่เป็นไปได้ อาร์เรย์มีผลรวมสูงสุดอย่างน้อยหนึ่งรายการ ตัวแปร runTotal แสดงถึงยอดรวมที่รันในแต่ละดัชนี ทั้งคู่เริ่มต้นด้วยค่าแรกของอาร์เรย์ ในอัลกอริธึมนี้ ถ้าค่าถัดไปในอาร์เรย์มากกว่าผลรวมการทำงาน ค่าถัดไปนั้นจะกลายเป็นผลรวมการทำงานใหม่

มีหนึ่งวงหลักสำหรับวง การสแกนเริ่มต้นจาก 1 และไม่ใช่ศูนย์เนื่องจากการเริ่มต้นของตัวแปร maxSum และ runTotal ถึง A[0] ซึ่งเป็นองค์ประกอบแรกของอาร์เรย์ที่กำหนด

ใน for-loop คำสั่งแรกจะกำหนดยอดรวมชั่วคราวโดยการเพิ่มมูลค่าปัจจุบันเข้ากับผลรวมสะสมของค่าก่อนหน้าทั้งหมด

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

ส่วนโค้ดสุดท้ายใน for-loop จะเลือกระหว่างผลรวมสูงสุดก่อนหน้าสำหรับลำดับก่อนหน้า (อาร์เรย์ย่อย) และผลรวมสูงสุดในปัจจุบันสำหรับลำดับปัจจุบัน ค่าที่สูงกว่าจึงถูกเลือก สามารถมีผลรวมอาร์เรย์ย่อยสูงสุดได้มากกว่าหนึ่งรายการ โปรดทราบว่ายอดรวมจะเพิ่มขึ้นและลดลง เนื่องจากอาร์เรย์ถูกสแกนจากซ้ายไปขวา มันตกลงมาตามค่าลบ

ผลรวมของอาร์เรย์ย่อยสูงสุดที่เลือกสุดท้ายจะถูกส่งคืนหลัง for-loop

เนื้อหาสำหรับฟังก์ชันหลัก C++ ที่เหมาะสม สำหรับฟังก์ชันอัลกอริทึมของ Kadane คือ:

เวกเตอร์ < int > เอ = { 5 , - 7 , 3 , 5 , - สอง , 4 , - 1 } ; // { 3 , 5 , - สอง , 4 } - > 10
int ret1 = maxSunArray ( อา ) ;
ศาล << ret1 << ปลาย;

เวกเตอร์ < int > ข = { - สอง , 1 , - 3 , 4 , - 1 , สอง , 1 , - 5 , 4 } ; // { 4 , − 1 , สอง , 1 } - > 6
int ret2 = maxSunArray ( บี ) ;
ศาล << ret2 << ปลาย;

เวกเตอร์ < int > ค = { 3 , สอง , - 6 , 4 , 0 } ; // { 3 , สอง } - > 5
int ret3 = maxSunArray ( ) ;
ศาล << ret3 << ปลาย;

เวกเตอร์ < int > ด = { 3 , สอง , 6 , - 1 , 4 , 5 , - 1 , สอง } ; // { 3 , สอง , 6 , - 1 , 4 , 5 , - 1 , สอง } - > 5
int ret4 = maxSunArray ( ดี ) ;
ศาล << net4 << ปลาย;

เวกเตอร์ < int > อี = { 5 , 7 , - 4 , - 10 , - 6 , 6 , 5 , 10 , - 5 , สิบห้า , 4 , - 8 , - สิบห้า , - 22 } ; // { 6 , 5 , 10 , - 5 , สิบห้า , 4 } - > 35
int ret5 = maxSunArray ( และ ) ;
ศาล << ret5 << ปลาย;

เวกเตอร์ < int > ฉ = { - 4 , 10 , สิบห้า , 9 , - 5 , - ยี่สิบ , - 3 , - 12 , - 3 , 4 , 6 , 3 , สอง , 8 , 3 , - 5 , - สอง } ; // { 10 , สิบห้า , 9 } - > 3. 4
int ret6 = maxSunArray ( F ) ;
ศาล << ขวา 6 << ปลาย;


ด้วยเหตุนี้ผลลัพธ์จะเป็น:

10

6

5

ยี่สิบ

35

3. 4

แต่ละบรรทัดตอบที่นี่ สอดคล้องกับอาร์เรย์ที่กำหนดตามลำดับ

บทสรุป

ความซับซ้อนของเวลาสำหรับอัลกอริทึมของ Kadane คือ O(n) โดยที่ n คือจำนวนองค์ประกอบในอาร์เรย์ที่กำหนด ความซับซ้อนในเวลานี้เป็นวิธีที่เร็วที่สุดสำหรับปัญหา sub-array สูงสุด มีอัลกอริธึมอื่นที่ช้ากว่า แนวคิดของอัลกอริธึมของ Kadane คือการทำยอดรวมในขณะที่เปรียบเทียบผลรวมสูงสุดตามที่พบ โดยย้ายจากซ้ายไปขวาในอาร์เรย์ที่กำหนด หากค่าปัจจุบันเพียงอย่างเดียวมากกว่าผลรวมที่รันอยู่ ค่าเดียวนั้นจะกลายเป็นผลรวมรันใหม่ มิฉะนั้น ยอดรวมรันใหม่คือยอดรวมการรันก่อนหน้าบวกอิลิเมนต์ปัจจุบัน ตามที่คาดไว้ เมื่อสแกนอาร์เรย์ที่ระบุ

สามารถมีผลรวมสูงสุดได้มากกว่าหนึ่งรายการ สำหรับอาร์เรย์ย่อยที่แตกต่างกัน เลือกผลรวมสูงสุดสูงสุดสำหรับอาร์เรย์ย่อยที่เป็นไปได้ทั้งหมด

ดัชนีจำกัดสำหรับช่วงของผลรวมสูงสุดที่เลือกคืออะไร – นั่นคือการสนทนาในบางครั้ง!

คริส