خوارزمية كادينس: أكبر مجموعة فرعية متجاورة

⚡ ملخص ذكي

تجد خوارزمية كادان أكبر مجموع لمصفوفة فرعية متجاورة في وقت خطي بواسطة tracاستخدم القيمة القصوى المتغيرة بدلاً من فحص كل مصفوفة فرعية ممكنة. هذه الحيلة الكلاسيكية في البرمجة الديناميكية تُستخدم في مسائل الأسهم والتمويل والإشارات.

  • 🎯 تعريف المشكلة: المصفوفة الفرعية المتجاورة هي سلسلة من العناصر المتتالية؛ والهدف هو المصفوفة الفرعية ذات أعلى مجموع حسابي داخل مصفوفة مختلطة من العناصر الموجبة والسالبة.
  • 🐢 القوة الغاشمة: تقوم حلقتان متداخلتان بتقييم كل فهرس بداية ونهاية في وقت O(N²) وطباعة النافذة الفائزة باستخدام علامات البداية والنهاية.
  • ⚡ رؤية كادان: أعد ضبط المجموع التراكمي كلما تجاوز العنصر الحالي المجموع التراكمي، واحتفظ به.ping أفضل بادئة فقط التي لا يزال من الممكن أن تتطور إلى الإجابة.
  • 🧭 مثال عملي: يُظهر استعراض سريع لمصفوفة تحتوي على قيم سالبة كيف يتطور كل من max_sum و current_sum خطوة بخطوة حتى يتم التقاط القيمة القصوى الحقيقية.
  • ؟؟؟؟ التغطية اللغوية: يبلغ قطر كلاً من C++ و Python تُظهر تطبيقات النهج البسيط وخوارزمية كادان الانتقال من زمن O(N²) إلى زمن O(N).
  • 📊 تعقيد: تعمل خوارزمية كادان في وقت O(N) مع مساحة إضافية O(1)، مما يتفوق بشكل كبير على خط الأساس القائم على القوة الغاشمة على مصفوفات الإدخال الكبيرة.

خوارزمية كادان: أكبر مجموع للمصفوفات الفرعية المتجاورة

ما هو أكبر مجموع للمصفوفة الفرعية المتجاورة؟

المصفوفة الفرعية هي جزء مستمر من المصفوفة. يمكن أن يكون عنصرًا واحدًا من المصفوفة أو جزءًا من المصفوفة. أكبر صفيف فرعي متجاور يعني صفيفًا فرعيًا له الحد الأقصى لقيمة المجموع.

على سبيل المثال، لنأخذ المصفوفة {-10، 5، 1، 6، -9، 2، -7، 3، -5}. يمكن أن تكون مصفوفاتها الفرعية {-10، 5، 1، 6}، أو {5، 1، 6}، أو {2، -7، 3، -5}، وهكذا. مع ذلك، لا يمكن أن تكون {5، 1، 6، 3} مصفوفة فرعية لأن عناصرها ليست متسلسلة.

أكبر مجموع سوباري متجاورة

إذا لاحظت، من بين جميع المصفوفات الفرعية، فإن المصفوفة الفرعية المميزة {5، 1، 6} لها أعلى قيمة مجموع:

تم تمييز أكبر مجموع للمصفوفة الفرعية المتجاورة

مجموع المصفوفة الفرعية {5، 1، 6} هو 12، وهو أكبر مجموع ممكن بين جميع المصفوفات الفرعية الممكنة للمصفوفة المذكورة أعلاه. لذا، بالنسبة لهذه المصفوفة، فإن أكبر مجموع للمصفوفة الفرعية المتجاورة هو {5، 1، 6}.

طريقة بسيطة لحل مصفوفة فرعية متجاورة ذات أكبر مجموع

الطريقة البسيطة لحل هذه المشكلة هي استخدام حلقتين للعثور على جميع المصفوفات الفرعية، وحساب المجموع، ثم العثور على القيمة القصوى لها.

إليكم مخطط انسيابي للطريقة البسيطة لإيجاد أكبر مجموع لمصفوفة فرعية متجاورة. هذه طريقة تعتمد على التجربة والخطأ، حيث نمر على كل مصفوفة فرعية ممكنة.

طريقة بسيطة لحل المبلغ الأكبر

فيما يلي الخطوات البسيطة للقيام بذلك.

الخطوة 1) تهيئة المجموع الأقصى بأقل قيمة عددية صحيحة، ثم حدد بدأ و النهاية إلى الصفر.

الخطوة 2) اسمحوا i و j تكون مؤشرات المصفوفة حيث j أكبر من أو يساوي i; i يُشير إلى بداية المصفوفة الفرعية و j نهايتها.

الخطوة 3) المجموع الحالي يحتوي على المجموع التراكمي. بعد كل تحديث، تحقق مما إذا كان المجموع الحالي أكبر من المجموع الأقصى.

الخطوة 4) If المجموع الحالي إذا كان أكبر، استبدل المجموع الأقصى معها.

الخطوة 5) متى j عند الوصول إلى نهاية المصفوفة، قم بزيادة العداد i وإعادة تعيين المجموع الحالي ل0.

الخطوة 6) كرر حتى i يصل إلى نهاية المصفوفة. المجموع الأقصى ثم يحتوي على أكبر مجموع للمصفوفة الفرعية.

كنية Code لنهج بسيط

function maximumSubarraySum():
    input: array
    for all possible subArray from array:
        calculate sum of each subarray
        store the maximum subArray
    return the maximum sum

C++ تنفيذ النهج البسيط

#include <stdio.h>
#include <iostream>
using namespace std;
void maximumSubarraySum(int array[], int n) {
    int max_sum = -1e9;
    int begin = 0;
    int end = 0;
    for (int i = 0; i < n; i++) {
        int current_sum = 0;
        for (int j = i; j < n; j++) {
            current_sum += array[j];
            if (max_sum < current_sum) {
                max_sum = current_sum;
                begin = i;
                end = j;
            }
        }
    }
    cout << "largest sum is " << max_sum << endl;
    cout << "largest sum contiguous subarray: ";
    for (int i = begin; i <= end; i++) {
        cout << array[i] << "\t";
    }
}
int main() {
    int array[] = {-10, 5, 1, 6, -9, 2, -7, 3, -5};
    maximumSubarraySum(array, sizeof(array) / sizeof(array[0]));
}

الإخراج:

largest sum is 12
largest sum contiguous subarray: 5      1       6

Python تنفيذ النهج البسيط

def maximumSubarraySum(numbers):
    max_sum, begin, end = -1e9, 0, 0
    for i in range(len(numbers)):
        current_sum = 0
        for j in range(i, len(numbers)):
            current_sum += numbers[j]
            if max_sum < current_sum:
                max_sum = current_sum
                begin, end = i, j
    print("largest sum is ", max_sum)
    print("largest sum contiguous subarray: ", end='')
    for i in range(begin, end + 1):
        print(numbers[i], end='\t')

numbers = [-10, 5, 1, 6, -9, 2, -7, 3, -5]
maximumSubarraySum(numbers)

الإخراج:

largest sum is 12
largest sum contiguous subarray: 5      1       6

خوارزمية كادان لإيجاد أكبر مجموع للمصفوفة الفرعية المتجاورة

خوارزمية كادان هي طريقة برمجة ديناميكية تستخدم حلقة واحدة بدلاً من حلقتين. وهي تتعامل مع المصفوفات التي تحتوي على أعداد موجبة وسالبة مختلطة، طالما أن قيمة واحدة على الأقل غير سالبة.

نحتاج فقط إلى متغيرين لإيجاد أكبر مجموع لمصفوفة فرعية متجاورة. إليك مخطط التدفق:

خوارزمية كادان لإيجاد أكبر مجموع

فيما يلي خطوات خوارزمية كادان:

الخطوة 1) أنشئ متغيرين، المجموع الحالي و المجموع الأقصى.

المجموع الحالي يحتفظ بأقصى مجموع ينتهي عند فهرس محدد في المصفوفة، بينما المجموع الأقصى يخزن أكبر قيمة إجمالية تم رصدها حتى الآن.

الخطوة 2) أضف كل عنصر من عناصر المصفوفة إلى المجموع الحاليثم تحقق من الشرطين التاليين:

  • If المجموع الحالي إذا كان أقل من العنصر الحالي، المجموع الحالي يصبح العنصر الحالي.
  • If المجموع الأقصى أقل من المجموع الحالي، ثم المجموع الأقصى يصبح المجموع الحالي.

الخطوة 3) بعد تكرار الخطوة السابقة للمصفوفة بأكملها، المجموع الأقصى يحتوي على أكبر مجموع للمصفوفة الفرعية المتجاورة.

مثال على خوارزمية كادان

نوضح خوارزمية كادان على مصفوفة صغيرة ونستعرض كل خطوة من خطوات إيجاد أكبر مجموع للمصفوفة الفرعية المتجاورة.

لنفترض أن المصفوفة المعطاة تشبه ما يلي:

مثال على خوارزمية كادان

فيما يلي خطوات خوارزمية كادان:

الخطوة 1) أنشئ متغيرين، المجموع الحالي و المجموع الأقصىقم بتعيين INT_MIN إلى المجموع الأقصى ومن صفر إلى المجموع الحاليهنا، يمثل INT_MIN أصغر قيمة عددية صحيحة.

الخطوة 2) عند الفهرس 0، تكون القيمة 4. لذا، المجموع الحالي = 0 + 4 = 4. بما أن المجموع الحالي أكبر من المجموع الأقصى, المجموع الأقصى يصبح 4.

مثال على الخطوة الثانية من خوارزمية كادان

الخطوة 3) عند الفهرس 1، تكون القيمة -2. لذا، المجموع الحالي = 4 + (-2) = 2.

هذا الوقت المجموع الحالي أقل من المجموع الأقصىونتيجة لذلك، فإن قيمة المجموع الأقصى لم يتم تحديثه.

مثال على الخطوة الثانية من خوارزمية كادان

الخطوة 4) القيمة التالية هي 1. بإضافتها إلى المجموع الحالي يعطي 3. بما أن المجموع الأقصى (4) لا يزال أكبر من المجموع الحالي, المجموع الأقصى لم يتم تحديثه.

مثال على الخطوة الثانية من خوارزمية كادان

الخطوة 5) عند الفهرس 3، تكون القيمة 3. زيادة المجموع الحالي بضربها في 3 تعطي المجموع الحالي = 6.

مثال على الخطوة الثانية من خوارزمية كادان

في هذه الحالة، المجموع الأقصى أصغر من المجموع الحالي، وبالتالي المجموع الأقصى يتم تحديثها بقيمة المجموع الحالي.

الخطوة 6) بالنسبة للعنصر الأخير في المصفوفة، لدينا -1. بإضافته إلى المجموع الحالي يعطي 5، وهو أصغر من المجموع الأقصى. وبالتالي، المجموع الأقصى يتبقى 6.

مثال على الخطوة الثانية من خوارزمية كادان

عندما وصلنا إلى نهاية المصفوفة، تنتهي الخوارزمية هنا. الآن، المجموع الأقصى تحتوي على أكبر مجموع، وهو 6. المصفوفة الفرعية هي {4، -2، 1، 3}.

كنية Code لخوارزمية كادان

function KadaneAlgorithm():
    input: array
    maximum_sum, current_sum = 0
    for each element in array:
        add the element with current_sum
        if current_sum is greater than the maximum_sum
            then maximum_sum = current_sum
        if current_sum is less than the element
            then current_sum = element
    return the value of maximum_sum

C++ تنفيذ خوارزمية كادان

#include <iostream>
using namespace std;
void kadane(int array[], int n) {
    int current_sum = 0;
    int max_sum = -1e9;
    // -1e9 means -1,000,000,000
    for (int i = 0; i < n; i++) {
        current_sum += array[i];
        if (max_sum < current_sum) {
            max_sum = current_sum;
        }
        if (current_sum < array[i]) {
            current_sum = array[i];
        }
    }
    cout << "largest sum is " << max_sum << endl;
}
int main() {
    int array[] = {-10, 5, 1, 6, -9, 2, -7, 3, -5};
    kadane(array, sizeof(array) / sizeof(array[0]));
}

الإخراج:

largest sum is 12

Python تنفيذ خوارزمية كادان

def kadane(numbers):
    current_sum = 0
    max_sum = -1e9
    for i in range(len(numbers)):
        current_sum += numbers[i]
        if max_sum < current_sum:
            max_sum = current_sum
        if current_sum < numbers[i]:
            current_sum = numbers[i]
    print("largest sum is ", max_sum)

kadane([-10, 5, 1, 6, -9, 2, -7, 3, -5])

الإخراج:

largest sum is 12

تحليل التعقيد لمجموع أكبر مجموعة فرعية متجاورة

تعتمد الطريقة البسيطة على استخدام حلقتين لحساب كل مجموع ممكن للمصفوفة الفرعية وتحديد أكبر مجموع. وهي طريقة تعتمد على البحث الشامل؛ حيث تستمر كل حلقة حتى نهاية المصفوفة. مجموعة، إعطاء O(N²) مرة.

تستخدم خوارزمية كادان حلقة واحدة فقط، مما يوفر زمنًا قدره O(N) ومساحة إضافية قدرها O(1). على مصفوفة مكونة من 100 عنصر، تُجري الطريقة البسيطة 100 × 100 = 10,000 عملية، بينما تُجري خوارزمية كادان 100 عملية فقط - وهو تسارع هائل للمدخلات الكبيرة.

الأسئلة الشائعة

تُشكّل خوارزمية كادان أساس هندسة ميزات الذكاء الاصطناعي لبيانات السلاسل الزمنية، واكتشاف النوافذ الشاذة، وتجزئة المكافآتping في التعلم المعزز، هيلping تحدد النماذج أقوى فاصل زمني إيجابي في الإشارات المشوشة.

نعم. يُخرج كل من GitHub Copilot وGPT خوارزمية كادان بشكل موثوق في Python, C++و Java، بما في ذلك المتغيرات التي تُرجع مؤشرات البداية والنهاية للمصفوفة الفرعية الفائزة.

تعمل خوارزمية كادان في زمن O(N) ومساحة إضافية O(1) لأنها تقوم بمرور واحد. tracالملك مجرد مجموع تراكمي وأفضل قيمة حتى الآن.

قم بتهيئة المتغير max_sum إلى العنصر الأول أو إلى سالب ما لا نهاية بدلاً من الصفر. عندها تُعيد الخوارزمية العنصر الأقل سالبية، وهو الإجابة الصحيحة.

تشمل الاستخدامات الشائعة نوافذ الربح لشراء وبيع الأسهم، ومجاميع حواف الصور، وفترات تسجيل الجينوم، وتحليل المخاطر المالية حيث تكون أفضل نافذة عائد متجاورة هي الأهم.

Tracيتم تعيين فهرس بداية مؤقت عند إعادة تعيين قيمة current_sum إلى العنصر الحالي. عند تحديث قيمة max_sum، يتم تسجيل فهرسي البداية والنهاية حتى يمكن تقسيم مصفوفة الإجابة الفرعية في النهاية.

تُحلّل خوارزمية فرق تسد مصفوفة فرعية قصوى في زمن O(N log N) من خلال دمج المجاميع اليسرى واليمنى ومجاميع التقاطع. أما خوارزمية كادان فهي أسرع بزمن O(N) وأسهل في البرمجة.

نعم. مثال كادان هو مثال نموذجي للبرمجة الديناميكية مع حالة O(1)، حيث يعتمد كل حد أقصى جديد ينتهي عند الفهرس i على الحد الأقصى الذي ينتهي عند الفهرس i ناقص واحد زائد العنصر الحالي.

تلخيص هذه التدوينة بـ: