0Pricing
Coding Interview Prep · درس

السلسلة النشطة الحالية حتى اليوم

حساب سلسلة متواصلة وإعادة ضبطها عند انقطاعها

السلسلة النشطة الحالية حتى اليوم درس مجاني في Coding Interview Prep على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Coding Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.

سؤال المنتج

تحتاج ميزات السلاسل المتتالية (مثل Duolingo أو Snapchat) إلى السلسلة الحالية، لا إلى أطول سلسلة تاريخية. وصيغة السؤال في المقابلة هي: «لكل مستخدم، كم يومًا متتاليًا، ينتهي باليوم الحالي، ظل نشطًا؟ أعد القيمة إلى 0 إذا لم ينشط اليوم.»

يضيف هذا الأمر تفصيلًا مهمًا: يجب أن تكون السلسلة مرتبطة باليوم الحالي (أو بالأمس وفق قاعدة السماح). لننشئها اعتمادًا على أساس الفجوات والجزر الذي تعرفه بالفعل.

تعريف النشاط

وضّح القواعد أولًا مع المحاور — فهذه القرارات تغيّر الاستعلام:

  • هل تتطلب السلسلة نشاطًا اليوم، أم يُقبل الأمس (فترة سماح)؟
  • هل تُختزل الأحداث المتعددة في اليوم نفسه إلى يوم واحد؟
  • ما المنطقة الزمنية التي تحدد «اليوم»؟

سنفترض وجود صف واحد لكل يوم نشط، وأن السلسلة الحالية إذا تضمنت اليوم أو الأمس.

إنشاء الجزر مجددًا

أعد استخدام المرساة: رقّم أيام كل مستخدم حسب التاريخ، ثم اطرح الرقم. ستشترك كل سلسلة متتالية في مرساة واحدة. السلسلة الحالية هي ببساطة الجزيرة التي يكون آخر يوم فيها هو اليوم أو الأمس.

WITH numbered AS (
  SELECT user_id, login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY login_date
    ) AS rn
  FROM logins
),
islands AS (
  SELECT user_id,
    MIN(login_date) AS streak_start,
    MAX(login_date) AS streak_end,
    COUNT(*)        AS streak_len
  FROM numbered
  GROUP BY user_id, login_date - rn
)
SELECT * FROM islands;

تحديد أحدث جزيرة

أحدث جزيرة لكل مستخدم هي التي تملك أكبر قيمة في streak_end. نختبر ما إذا كانت نهايتها حديثة بما يكفي لاعتبار السلسلة مستمرة.

تعطي CURRENT_DATE تاريخ اليوم. أما CURRENT_DATE - 1 فهو تاريخ الأمس. إذا ساوت streak_end أيًا منهما، تكون السلسلة نشطة.

WITH /* ...numbered, islands... */
latest AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY streak_end DESC
    ) AS rn2
  FROM islands
)
SELECT * FROM latest WHERE rn2 = 1;

تطبيق اختبار الحداثة

حدّد الآن ما إذا كانت أحدث جزيرة نشطة. إذا كان تاريخ نهايتها هو اليوم أو الأمس، تساوي السلسلة الحالية طولها؛ وإلا فقد انقطعت سلسلة المستخدم وتكون القيمة الحالية 0.

SELECT user_id,
  CASE
    WHEN streak_end >= CURRENT_DATE - 1
    THEN streak_len
    ELSE 0
  END AS current_streak
FROM latest
WHERE rn2 = 1;

استعلام السلسلة الحالية الكامل

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

WITH numbered AS (
  SELECT user_id, login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY login_date
    ) AS rn
  FROM logins
),
islands AS (
  SELECT user_id,
    MAX(login_date) AS streak_end,
    COUNT(*)        AS streak_len
  FROM numbered
  GROUP BY user_id, login_date - rn
),
latest AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY streak_end DESC
    ) AS rn2
  FROM islands
)
SELECT user_id,
  CASE WHEN streak_end >= CURRENT_DATE - 1
       THEN streak_len ELSE 0 END AS current_streak
FROM latest
WHERE rn2 = 1
ORDER BY user_id;

التقيّد بالنشاط اليوم فقط

إذا كانت قاعدة العمل صارمة — أي إن السلسلة تظل نشطة فقط إذا كان المستخدم قد نشط اليوم — فغيّر المقارنة لتتطلب streak_end = CURRENT_DATE.

أما إصدار فترة السماح (>= CURRENT_DATE - 1) فهو أكثر مرونة وشائع في التطبيقات الفعلية، إذ إن اليوم لم ينتهِ بعد. تأكّد دائمًا من الإصدار الذي يريده المحاور.

CASE WHEN streak_end = CURRENT_DATE
     THEN streak_len ELSE 0 END AS current_streak

بديل: الرجوع إلى الخلف

هناك نموذج ذهني مختلف يفضّله بعض المحاورين: احسب الفجوة بين كل يوم واليوم الحالي. لا يكون اليوم جزءًا من السلسلة الحالية إلا إذا كان كل يوم من ذلك اليوم حتى اليوم الحالي موجودًا. وبعبارة مكافئة، قارن login_date مع CURRENT_DATE - (offset from the latest).

تكون طريقة الجزر عادةً أوضح، لكن معرفة بديل تُظهر عمق فهمك. الفكرة الأساسية واحدة: سلسلة غير منقطعة مرتبطة باليوم الحالي.

تضمين المستخدمين غير النشطين

لا يملك المستخدمون غير الموجودين في logins أي جزيرة، ولذلك يختفون. إذا كان يجب عرض سلسلة لكل مستخدم (ويرجّح أن تكون 0)، فاستخدم LEFT JOIN مع قائمة المستخدمين، ثم استخدم COALESCE لتحويل النتيجة إلى 0.

SELECT u.user_id,
  COALESCE(s.current_streak, 0) AS current_streak
FROM users u
LEFT JOIN current_streaks s ON s.user_id = u.user_id;

مخاطر المناطق الزمنية

إذا خُزّن النشاط على هيئة طوابع زمنية، فإن معنى «اليوم» يعتمد على المنطقة الزمنية. حوّل الطابع الزمني قبل اقتطاعه إلى تاريخ.

  • خزّن البيانات وقارنها بتوقيت UTC، أو حوّلها أولًا إلى المنطقة المحلية للمستخدم.
  • استخدم event_ts AT TIME ZONE 'UTC' AT TIME ZONE user_tz في Postgres، ثم حوّل الناتج إلى تاريخ.
  • قد يضع استخدام ::date مباشرةً على طابع زمني بتوقيت UTC حدثًا مسائيًا في يوم تقويمي خاطئ.

إن ذكر هذه النقطة يسبق سؤال متابعة شائعًا حول هذا الخطأ.

SELECT user_id,
  (event_ts AT TIME ZONE 'UTC'
             AT TIME ZONE 'America/New_York')::date AS local_day
FROM events;

الأداء والخلاصة

بالنسبة إلى لوحات المعلومات التي تُحدّث كثيرًا، يُنفّذ هذا الاستعلام لكل مستخدم في مرور واحد. وللحفاظ على سرعته:

  • أنشئ فهرسًا على (user_id, login_date).
  • يمكنك تقييد الإدخال اختياريًا بالتواريخ الحديثة — فلا يمكن أن تتضمن السلسلة الحالية بيانات أقدم من طولها نفسه، لذا تكفي نافذة متحركة، مثل آخر 400 يوم.
  • أنشئ جدولًا للسلاسل اليومية بصورة مادية إذا كانت قراءته متكررة جدًا.

تحقّق سريع

تأكّد من فهمك للمرساة المرتبطة بـ «الآن».

مراجعة

لحساب سلسلة النشاط الحالية حتى تاريخ اليوم:

  • أنشئ الجزر باستخدام مرساة login_date - ROW_NUMBER().
  • اختر أحدث جزيرة لكل مستخدم باستخدام أكبر قيمة لـ streak_end.
  • أعد طولها فقط إذا كان streak_end هو اليوم (أو الأمس في حالة السماح)، وإلا فأعد 0.
  • استخدم LEFT JOIN مع users لتضمين الحسابات غير النشطة، وتعامل مع المناطق الزمنية قبل الاقتطاع إلى تاريخ.

أصبحت الآن متمكّنًا من مجموعة أدوات تحليل السلاسل المتتالية كاملةً: اكتشاف السلاسل، وأطول سلسلة، والشروط التي تتطلب N من العناصر المتتالية، والسلسلة النشطة.

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

هل درس «السلسلة النشطة الحالية حتى اليوم» مجاني؟

نعم — نص درس «السلسلة النشطة الحالية حتى اليوم» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Coding Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.

ماذا ستتعلم في «السلسلة النشطة الحالية حتى اليوم»؟

حساب سلسلة متواصلة وإعادة ضبطها عند انقطاعها تتمرن على Coding Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Coding Interview Prep؟

لا تُشترط خبرة سابقة. Coding Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «السلسلة النشطة الحالية حتى اليوم»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Coding Interview Prep هذا؟

نعم. كل درس في Coding Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. اكتشاف الأيام التقويمية المتتالية
  2. أطول سلسلة متتالية لكل مستخدم
  3. عدد N من الصفوف المتتالية التي تستوفي شرطًا
  4. السلسلة النشطة الحالية حتى اليوم
← العودة إلى Coding Interview Prep