AlgoVerse

بیشینه‌ی زیرآرایه (کادان)

بازه‌ی پیوسته‌ای با بیشترین مجموع را در یک گذر پیدا می‌کند: هر وقت مجموع جاری منفی شد، آن را کنار می‌گذارد و از نو شروع می‌کند.

در آرایه‌ای از عددهای مثبت و منفی (مثلاً تغییرات روزانه‌ی قیمت)، بازه‌ی پیوسته‌ای پیدا کن که مجموعش بیشترین باشد.

ادامه‌ی توضیح ↓
ورودی:
n=16خروجی PDF

شانزده تغییر روزانه‌ی قیمت؛ بهترین بازه a[7..10] با مجموع ۴۳ است.

  1. def max_subarray(a):
  2. best = a[0]
  3. best_lo = 0
  4. best_hi = 0
  5. cur = a[0]
  6. cur_lo = 0
  7. for i in range(1, len(a)):
  8. if cur < 0:
  9. cur = a[i]
  10. cur_lo = i
  11. else:
  12. cur = cur + a[i]
  13. if cur > best:
  14. best = cur
  15. best_lo = cur_lo
  16. best_hi = i
  17. return best, best_lo, best_hi

ناوردا: cur بیشترین مجموع زیرآرایه‌ای است که دقیقاً در خانه‌ی i تمام می‌شود، و best بیشترین مجموع کل تا i.

شروع اجرا

130-31-252203-34-165-236187208-791210-511-22121513-414715

متغیرهای محلی

نارنجی = در همین گام عوض شد

a list

13-3-2520-3-16-231820-712-5-2215-47

Call stack

  1. max_subarray()خط 1
گام ۱ از ۷۹
خط سیاه = restart, extend · خط نارنجی = گام کلیدیcompare: 0/30 · extend: 0/13 · restart: 0/2 · new_best: 0/3

    رشد تعداد عملیات با اندازه‌ی ورودی

    میانگین ۱۲ گراف تصادفی برای هر n (با seed ثابت). نشانگر توخالی = ورودی فعلی.

    • comparisons
    • ورودی فعلی (n=16)
    010203046810121416n = تعداد عضوهای آرایهcomparisons
    نمایش به شکل جدول
    ncomparisons
    46
    610
    814
    1018
    1222
    1426
    1630
    توضیح

    مسئله

    در آرایه‌ای از عددهای مثبت و منفی (مثلاً تغییرات روزانه‌ی قیمت)، بازه‌ی پیوسته‌ای پیدا کن که مجموعش بیشترین باشد.

    ایده‌ی کادان

    برای هر خانه‌ی i، cur بیشترین مجموع زیرآرایه‌ای است که دقیقاً در i تمام می‌شود. این مقدار دو انتخاب دارد: یا زیرآرایه‌ی قبلی را با a[i] ادامه بده، یا از a[i] از نو شروع کن. اگر cur منفی است، ادامه دادنش فقط ضرر دارد، پس از نو شروع می‌کنیم. best بزرگ‌ترین cur دیده‌شده است.

    هزینه

    یک گذر: O(n) زمان و O(1) حافظه. CLRS همین مسئله را با تقسیم و حل در O(n log n) حل می‌کند؛ کادان نشان می‌دهد که با یک ایده‌ی برنامه‌ریزی پویا می‌شود خطی حلش کرد.

    در trace به چه چیزی نگاه کنی

    • نوار آبی بهترین بازه تا اینجاست؛ فلش cur_lo شروع اجرای جاری و i خانه‌ی جاری است.
    • در ورودی «شروع دوباره» ببین بعد از افت بزرگ، cur_lo جلو می‌پرد.