سلسلة حل المشكلات (Problem Sloving) اليوم الستة و عشرين

التحدي رقم 26 لليوم رقم 26 من رمضان

اولا
كل عام و انتم بخير و اعاده الله عليكم بالمن و بالخير و البركه

بالامس كنا نقول رمضان اهلا و اليوم نقول رمضان مهلا فاللهم اغفر لنا ما مضي و اصلح لنا ما بقي واختم لنا رمضان بخير و انت راض عنا

و لا تنسي تجديد نيتك فأن طلب العلم عباده
لا تنسوني و اخي المعتقل سياسيا من جميل دعائكم في هذه الليالي العشر

وصف التحدي :

متنساش تدعي لخواتنا ف غزه لو لسه عندك قلب و شوية دم

**مستوي التحدي : **
متوسط برمجيا ← برمجة ديناميكية

نص ما قبل التحدي :

خلال شهر رمضان، تُقام حملات تبرعات في أوقات مختلفة من اليوم لدعم المشاريع الخيرية. في بعض الأحيان، تتداخل هذه الفترات الزمنية أو تتلاصق، مما يجعل من الصعب معرفة إجمالي الوقت الذي تظل فيه حملات التبرعات نشطة دون احتساب الوقت المكرر.

نص التحدي

قم بكتابة دالة اسمها: calculateActiveDonationMinutes تستقبل مصفوفة من الفترات الزمنية، حيث يتم تمثيل كل فترة على شكل سلسلة نصية بصيغة "start-end" . هنا يمثل start و end الدقائق التي تبدأ وتنتهي فيها الحملة بعد منتصف الليل.
على سبيل المثال، إذا كانت إحدى الفترات هي "60-120" وأخرى "110-180" , فينبغي دمجهما ليصبحا فترة واحدة تمتد من الدقيقة 60 إلى الدقيقة 180، بحيث لا يتم احتساب الدقيقة المشتركة مرتين.

مثال عملي

مثال 1

  • المدخلات:
    مصفوفة الفترات: ["60-120", "110-180"]
  • العملية:
    • الفترة الأولى تغطي الدقائق من 60 إلى 120 (60 دقيقة).
    • الفترة الثانية تغطي الدقائق من 110 إلى 180 (70 دقيقة).
    • عند الدمج، تكون الفترة المشتركة من الدقيقة 110 إلى 120، لذا تصبح الفترتان مدمجتين إلى فترة واحدة تمتد من 60 إلى 180 دقيقة.
  • الناتج:
    إجمالي الدقائق النشطة = 180 - 60 = 120 دقيقة.

مثال 2

  • المدخلات:
    مصفوفة الفترات: ['60-120', '130-150']
  • العملية:
    • الفترة الأولى تغطي الدقائق من 60 إلى 120 (60 دقيقة).
    • الفترة الثانية تغطي الدقائق من 130 إلى 150 (20 دقيقة).
    • هنا لن ندمغ الفترتين لانهما لم يتشاركوا في اي فترة .
  • الناتج:
    إجمالي الدقائق النشطة = 20 + 60 = 80 دقيقة.

ملحوظه : كلمة مصفوفة يعني ليست ← [,]

ملحوظه : تقدر تحل التحدي و تتحقق من صحته من خلال الموقع هنا اهو :
موقع سلسلة حل المشكلات (Problem Sloving)
بس خد بالك لو هتحل ع الموقع لازم اسم الداله يكون زي الاسم اللي موجود في وصف التحدي

أضغط لرؤية المخرجات المتوقعة عشان تتيست الكود بتاعك

الاختبار 1
المدخلات (Inputs)
intervals = [‘60-120’]
المخرجات (Outputs)
60

الاختبار 2
المدخلات (Inputs)
intervals = [‘60-120’, ‘110-180’]
المخرجات (Outputs)
120

الاختبار 3
المدخلات (Inputs)
intervals = [‘60-120’, ‘130-150’]
المخرجات (Outputs)
80

الاختبار 4
المدخلات (Inputs)
intervals = [‘0-30’, ‘25-50’, ‘45-60’]
المخرجات (Outputs)
60

حل التحدي

def calculateActiveDonationMinutes(intervals):
    # بنحول الفترات النصية لأزواج أرقام
    intervals = [list(map(int, interval.split('-'))) for interval in intervals]

    # بنرتب الفترات حسب البداية
    intervals.sort(key=lambda x: x[0])

    # مصفوفة عشان نحفظ الفترات اللي دمجناها
    merged_intervals = []

    for start, end in intervals:
        # لو مفيش تداخل مع اخر فترة مدمجة يبقي هنضيف فترة جديدة
        if not merged_intervals or start > merged_intervals[-1][1]:
            merged_intervals.append([start, end])
        else:
            # لو في تداخل أو الفترات لازقة في بعض يبقي نعمل دمج ليهم
            merged_intervals[-1][1] = max(merged_intervals[-1][1], end)

    #هنا بنحسب إجمالي الوقت النشط
    active_minutes = sum(end - start for start, end in merged_intervals)

    return active_minutes

4 إعجابات

def calculate_active_donation_minutes(intervals):
interval_sets=
total_minutes=0
merged_intervals=
new_interval_sets=
for interval in intervals:
interval_pair=list(map(int,interval.split(“-”)))
interval_sets.append(interval_pair)
interval_sets=sorted(interval_sets,key=lambda interval_pair:interval_pair[0])

for i in range(1,len(interval_sets)):
    if interval_sets[i][0]<=interval_sets[i-1][-1]:
        merged_intervals+=interval_sets[i-1]+interval_sets[i]
        merged_intervals=[merged_intervals[0],merged_intervals[-1]]

new_interval_sets.append(merged_intervals) 
for i in interval_sets:
    if i[0]>merged_intervals[-1]:
        new_interval_sets.append(i)

print(new_interval_sets)

if not interval_sets:
    return "There is no timing"
if len(new_interval_sets)==1:
    return new_interval_sets[0][-1]-new_interval_sets[0][0]
if len(new_interval_sets)>1:
    for j in new_interval_sets:
        total_minutes+=(j[-1]-j[0])
    return total_minutes

print(calculate_active_donation_minutes([“0-30”,“25-50”,“45-60”,“130-180”]))

إعجابَين (2)


إعجابَين (2)

انا كنت فاكره نفسي كويسة لحد التحدي ده و اللي قبله هو في الشغل الحقيقي ده المستوي الطبيعي بتاع المشاكل ولا دي مشاكل advanced

3 إعجابات

ما شاء الله حليت حلو بس كنت متوقع انك تحل افضل خاصتا في المشكله اللي هذكرها رقم 2

اكيد فهمتي كدا ان الكود فيه اخطاء تعالي نمشي عليهم واحده واحده :

المشكله الاولي في الكود :
هنلاقيها في السطر دا :

interval_sets = sorted(interval_sets, key=lambda interval_pair: interval_pair[0])

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

    for interval in intervals:
        interval_pair = list(map(int, interval.split("-")))
        interval_sets.append(interval_pair)

    # اول لما يخلص اللوب يعمل الترتيب 
    interval_sets.sort(key=lambda interval_pair: interval_pair[0])

طبعا انا استخدمت .sort() بدل من sorted() عشان معملش متغير جديد لان الاولي بترتها و تخلي الترتيب في المتغير نفسه انما التانيه بتعمل ناتج جديد

المشكله التانيه :
اولا تعالا نتفق ان انا دماغي لفت احلي لفه بمجرد بدأت احاول افهم المكتوب :sweat_smile:
دا بسبب عوامل اهمهم ان انتي مخليه الكود يضيف كل الفترات بدايه و نهايه في ليست واحده مسطحه و بتالي مش بتبقي فاهم انهو رقم يدل علي بدايه فتره معينه و انهي بيدل علي نهايه نفس الفتره
وبتالي المفروض كنا نستخدم ال 2D lists اللي هي ليستات بداخل ليست
دا طبعا بيظهر في السطر دا :

merged_intervals += interval_sets[i-1] + interval_sets[i]

الي انتي فيه بتحاولي interval_sets[i-1] و interval_sets[i] الي merged_intervals
وبالتالي اللي بيحصل اللي بيحصل فعلًا هو إنك بتضيف كل القيم كعناصر فردية داخل قائمة واحدة مش كقائمة من الفترات

يعني لو عندي الفترتين دول : [60, 120] و [110, 180]
الكود هيخزنهم كدا : merged_intervals = [60, 120, 110, 180]
وده غلط، لأن merged_intervals المفروض يحتوي على قائمة من الفترات بالشكل ده:
[[60, 180]]
ودا لان :
الفترة الأولى: من الدقيقة 60 إلى الدقيقة 120
الفترة الثانية: من الدقيقة 110 إلى الدقيقة 180

الفترة الأولى تنتهي عند الدقيقة 120
الفترة الثانية تبدأ عند الدقيقة 110 (يعني قبل ما تنتهي الأولى!)
إذن، الفترتان متداخلتان، فلازم ندمجهم في فترة واحدة تمتد من 60 إلى 180.

اذا هتكون :

[[60, 180]]

نأخذ أصغر بداية (60)
ونأخذ أكبر نهاية (180)
وبالتالي، تصبح الفترة الجديدة [60, 180] بدل فترتين منفصلتين.

المشكله التانيه في المشكله التانيه :
في بسبب كتابتك للسطر دا بالشكل دا خليت بقا عندي المشكله الاولي اللي قبل دي هتفهم ازاي لما اشرح
السطر :

merged_intervals = [merged_intervals[0], merged_intervals[-1]]

انتي بتحاولي تحتفظي فقط بأول وأخر قيمة في merged_intervals لكن:
الكود ده بيتعامل مع merged_intervals كأنه قائمة مسطحة من الأرقام وليس كقائمة تحتوي على فترات [start, end].
وبالتالي هيخزن بداية أول فترة ونهاية آخر فترة فقط بس بغض النظر عن أي تداخلات إضافية

المشكله التالته في المشكله التانيه ( ودي الاهم يعني كنت مستنيكي تحليها صح ) :
الكود بتاعك هنا بيدمج فترتين 2 بس يعني لو ادناله اكتر من 2 فترات هيدمج اول 2 و التالته لو فيها دمج مش هيدمجها و بالتالي حل المشكله دي اني لازم اعمل لوب علي كل اللي عندي و اقارن بينهم كلهم فا بدل ما نحاول دمج كل زوج لوحده لا احنا نستخدم قائمة merged_intervals لتخزين الفترات بشكل متسلسل ونقارن كل فترة جديدة باخر فترة مدمجة

فا هتبقي كدا :

merged_intervals.append(interval_sets[0])  # نبدأ بأول فترة

for i in range(1, len(interval_sets)):
    start, end = interval_sets[i]
    last_start, last_end = merged_intervals[-1]  # اخر فترة مدمجة

    if start <= last_end:  # في تداخل
        merged_intervals[-1][1] = max(last_end, end)  # ندمج الفترتين
    else:
        merged_intervals.append([start, end])  # مفيش تداخل يبقي نضيف فترة جديدة

المشكله التالته :
هنلاقيها هنا :

new_interval_sets.append(merged_intervals)

for i in interval_sets:
    if i[0] > merged_intervals[-1]:
        new_interval_sets.append(i)

هنا الكود بيحاول يضيف الفترات اللي ماتمش دمجها بالطريقة دي :

for i in interval_sets:
    if i[0] > merged_intervals[-1]:
        new_interval_sets.append(i)

ودا طبعا خطأ فادح لانن ممكن merged_intervals يكون فاضي وهنا يحصل IndexError
بسبب انه مش هيلاقي merged_intervals[-1]

ناجي للمتغير دا : new_interval_sets و اللي لو ضفناعليه ال merged_intervals الفاضي هيعملي ايرور في الحسابات تحت لانك مستخدمه في الحسابات تحت

و اصلا هو غير ضروري ليه :
لاننا بالفعل بنحفظ الفترات المدمجة في merged_intervals
فا مفيش أي داعي لاننا ننشئ new_interval_sets كمتغير إضافي
فا بدل ما نستخدم new_interval_sets ممكن نشتغل مباشرةً على merged_intervals ونحسب مجموع الفترات منه مباشرا

و بعدين عندنا انت بتفحص الحالة الفارغة ل (if not interval_sets:) في المكان الخطأ المفروض تبقي بدري عشان ميعملش الايرورات اللي هتعتمد عليه لو فاضي اصلا من البدايه و برضوا انت مخليه يرجع استرينج و المفروض الداله مش بترجع الا انتجر و بالتالي هنخليه يرجع 0

if not intervals:
    return 0  # لا يوجد فترات

وباالتالي الكود هيبقي كدا :

merged_intervals.append(interval_sets[0])  # نبدأ بالفترة الأولى

for i in range(1, len(interval_sets)):
    start, end = interval_sets[i]
    last_start, last_end = merged_intervals[-1]

    if start <= last_end:  # في تداخل
        merged_intervals[-1][1] = max(last_end, end)  # ندمج الفترتين
    else:
        merged_intervals.append([start, end])  # مفيش تداخل نضيف فترة جديدة

# و بالتالي هنا هنحسب عدد الدقائق النشطه بصوره مباشره 
total_minutes = sum(end - start for start, end in merged_intervals)

اذا الكود بتاعك عشان يبيقي صح كامل اهو :

def calculate_active_donation_minutes(intervals):
    interval_sets = []
    total_minutes = 0
    merged_intervals = []

    # تحويل الفترات النصية إلى أزواج من الأرقام
    for interval in intervals:
        interval_pair = list(map(int, interval.split("-")))
        interval_sets.append(interval_pair)

    # ترتيب الفترات حسب البداية
    interval_sets.sort(key=lambda interval_pair: interval_pair[0])

    if not interval_sets:  # التحقق من الحالة الفارغة مبكرًا
        return 0

    # بدء الدمج بالفترة الأولى
    merged_intervals.append(interval_sets[0])

    for i in range(1, len(interval_sets)):
        start, end = interval_sets[i]
        last_start, last_end = merged_intervals[-1]

        if start <= last_end:  # لو في تداخل، ندمج الفترات
            merged_intervals[-1][1] = max(last_end, end)
        else:
            merged_intervals.append([start, end])  # لا يوجد تداخل، نضيف فترة جديدة

    # حساب إجمالي الدقائق النشطة بعد الدمج
    total_minutes = sum(end - start for start, end in merged_intervals)

    return total_minutes

اتمني تكوني فهمتيي انا عارف ان انا شرحي وحش انا حرفيا اسوء انسان بيشرح حاجه معينه :sweat_smile: ولذلك لو مفهمتيش شوفي الحل الكامل اللي انا كتبته هتفهي منه كويس و انصحك تبص علي حل التحدي اللي انا كاتبه في الحل لانه اكثر منطقيه و اختصار و كدا

إعجابَين (2)

للاسف ايوه دا اللي بياجي في الشركات لان دا اللي بيعتمد علي الخوارزميات و هياكل البيانات و علي البرمجه اللي بجد مش الكودينج

ودا المطلوب اصلا او اللي كان مرتجي من السلسله دي اننا بنيحث بقا عن كورسات للخوارزميان و الداتا استركشر و كدا و نفهم برمجه وحط الف خط تحت نفهم برمجه مش كود

ولكن زي ما اظن انك حسيب بالاحباط بسبب اجابتي الا اني احب ابشرك و اقولك ان برضوا المسائل الصعبه بتبقي اختبارات لشركات كبيره و كويسه

ولكن طول ما الشركات تبقي اقل قيمه طول ما اسئلتها بتيقي اسهل

ولكن كانصيه ليك انت كا مبرمج اسعي انك تشتغل في اكبر منصب تقدر توصله لو انت ناوي تعتمد علي البرمجه كا دخل اساسي

3 إعجابات

اول حاجة شكرا على الشرح تاني حاجه الكود بتاعي لما بيشتغل بتكون ال interval sets عبارة عن nested list و كمان new interval sets بتكون في الاول nested list لحد ما بيتواجد فترة مش متداخلة و وراها فترة متداخلة و دي كانت مشكلة الكود ده.
تاني حاجه خليني اعترف اني مكنش عندي معلومة أنه ممكن نعمل loop علي متغيرين اللي هما ال start و ال end لما عرفتها من حل حضرتك سهلت الدنيا جدا .
اخر حاجه شرح حضرتك فعلا كويس و كتر الف خيرك علي تعبك معانا و ياريت حضرتك تعرفني ازاي اتواصل مع حضرتك علي الخاص

إعجابَين (2)

المهم ان حضرتك تكوني فهمتي المنطق بتاع الحل بصوره صحيحه

3 إعجابات

انا يسطا بقول احنا نجمعلك فلوس علي الحوارات اللي انت بتعملها دي والله

إعجابَين (2)

يعم اقعد ساكت انت حيلتك تاكل
انتو لو معاكم فلوس مكنتش هتتعلموا برمجه اصلا :joy:

3 إعجابات

بس أنا بتعلمها على إنها هواية وحاجة مفيدة

طبعاً مبنكرش إنها ممكن تساعد في الدخل مستقبلا، لاكن أنا مش ناوي أشتغل قريب أساسا.

إعجابَين (2)