كيفية حل مسائل LeetCode في بايثون باستخدام أوامر من سطر واحد

دقائق القراءة: 5

مقدمة: لماذا يفضّل كثير من المطورين بايثون في حل مسائل LeetCode؟

تُعد Python من أكثر لغات البرمجة مرونة وسهولة في كتابة الحلول السريعة، خصوصاً في منصات التحديات البرمجية مثل LeetCode. ويعود ذلك إلى ما توفره اللغة من أدوات تعبيرية قوية تساعد على كتابة كود مختصر، واضح، وسهل الفهم. ومن أبرز هذه الأدوات ميزة List Comprehension التي تتيح إنشاء القوائم ومعالجتها بأسلوب أنيق ومباشر.

في هذا المقال، سنستعرض مفهوم List Comprehension بصورة عملية، ثم نطبّقه على مجموعة من مسائل المصفوفات الشائعة في LeetCode، مع الحفاظ على الطابع التعليمي والفهم العميق للحلول، بدلاً من الاكتفاء بالاختصار فقط.

استخدام بايثون لحل مسائل ليت كود بأسلوب مختصر عبر List Comprehension

ما هي ميزة List Comprehension في بايثون؟

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

تكمن أهميتها في أنها:

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

مثال توضيحي على الفرق بين الحلقة التقليدية وList Comprehension

لنفترض أن لدينا مصفوفة أرقام، والمطلوب هو إضافة 1 إلى العناصر ذات الفهرس الفردي، وإضافة 2 إلى العناصر ذات الفهرس الزوجي.

الحل باستخدام حلقة for

def addOneAndTwo(nums, n):
    for i in range(n):
        if i % 2 == 1:
            nums[i] += 1
        else:
            nums[i] += 2
    return nums

الحل باستخدام List Comprehension

def addOneAndTwo(nums, n):
    return [nums[i] + 1 if i % 2 == 1 else nums[i] + 2 for i in range(n)]

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

كيف تساعدك List Comprehension في حل مسائل LeetCode؟

في مسائل الخوارزميات، كثيراً ما تحتاج إلى:

  • المرور على العناصر.
  • تطبيق شرط على كل عنصر.
  • إنشاء قائمة جديدة مشتقة من قائمة أصلية.
  • دمج النتائج مع دوال مثل sum() وmax() وzip() وreduce().

ولهذا السبب، تظهر List Comprehension كخيار قوي في عدد كبير من المسائل، خصوصاً مسائل المصفوفات والقوائم.

حل مسائل LeetCode في سطر واحد باستخدام List Comprehension

1) مسألة Shuffle the Array

في هذه المسألة، نحصل على مصفوفة nums مكوّنة من 2n عنصراً بالشكل التالي:

[x1, x2, ..., xn, y1, y2, ..., yn]

والمطلوب إعادة ترتيبها لتصبح:

[x1, y1, x2, y2, ..., xn, yn]

مثال

  • المدخلات: nums = [2,5,1,3,4,7]، n = 3
  • المخرجات: [2,3,5,4,1,7]

الفكرة هنا تعتمد على دمج النصف الأول مع النصف الثاني زوجاً بعد زوج باستخدام zip()، ثم تحويل الأزواج إلى قائمة واحدة متتابعة.

def shuffle(self, nums, n):
    return reduce(lambda a, b: a + b, [[nums[i], nums[j]] for i, j in zip(range(0, n), range(n, 2 * n))])

شرح مختصر

  • يتم إنشاء أزواج من الفهارس عبر zip().
  • لكل زوج فهارس، ننشئ قائمة بالشكل [nums[i], nums[j]].
  • تُدمج القوائم الصغيرة معاً باستخدام reduce().

2) مسألة Number of Good Pairs

المطلوب هو حساب عدد الأزواج (i, j) التي تحقق الشرطين التاليين:

  • nums[i] == nums[j]
  • i < j

مثال

  • المدخلات: nums = [1,2,3,1,1,3]
  • المخرجات: 4

الحل التالي يجرب كل زوج ممكن بطريقة منظمة، ثم يحسب عدد الأزواج الصحيحة.

def numIdenticalPairs(self, nums):
    return sum([int(i != j and nums[i] == nums[j]) for i in range(0, len(nums)) for j in range(i + 1, len(nums))])

كيف يعمل هذا الحل؟

  • يدور المتغير i على جميع العناصر.
  • يبدأ المتغير j من العنصر التالي مباشرة لضمان تحقق الشرط i < j.
  • إذا كانت القيمتان متساويتين، يتم تحويل النتيجة إلى 1 عبر int()، ثم جمع كل النتائج باستخدام sum().

3) مسألة Kids With the Greatest Number of Candies

لدينا مصفوفة candies تمثل عدد الحلوى لدى كل طفل، ولدينا أيضاً قيمة extraCandies. المطلوب هو تحديد ما إذا كان كل طفل يمكنه الوصول إلى أكبر عدد من الحلوى أو تجاوزه إذا حصل على كل الحلوى الإضافية.

مثال

  • المدخلات: candies = [2,3,5,1,3]، extraCandies = 3
  • المخرجات: [True, True, True, False, True]

الحل هنا من أكثر الأمثلة وضوحاً على قوة List Comprehension.

def kidsWithCandies(self, candies, extraCandies):
    return [candy + extraCandies >= max(candies) for candy in candies]

فهم الحل

  • نحسب أكبر قيمة في القائمة عبر max(candies).
  • نفحص لكل عنصر candy ما إذا كانت إضافته إلى extraCandies ستجعله ضمن الأعلى.
  • النتيجة النهائية قائمة من القيم المنطقية.

4) مسألة Decompress Run-Length Encoded List

في هذه المسألة، تمثل القائمة nums بيانات مضغوطة بأسلوب Run-Length Encoding. كل زوج متجاور في المصفوفة يكون على الصورة:

[freq, val]

وهذا يعني تكرار القيمة val بعدد مرات يساوي freq.

مثال

  • المدخلات: nums = [1,2,3,4]
  • المخرجات: [2,4,4,4]

المنطق هنا يقوم بإنشاء قائمة فرعية لكل زوج، ثم دمج جميع القوائم الناتجة في قائمة واحدة.

def decompressRLElist(self, nums):
    return reduce(lambda a, b: a + b, [[nums[i + 1]] * nums[i] for i in range(0, len(nums), 2)])

لماذا هذا الحل فعّال؟

  • المرور يتم بخطوة 2 لالتقاط كل زوج.
  • التعبير [nums[i + 1]] * nums[i] ينشئ قائمة متكررة مباشرة.
  • بعد ذلك تتولى reduce() دمج كل القوائم الفرعية.

5) مسألة Richest Customer's Wealth

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

مثال

  • المدخلات: accounts = [[1,2,3],[3,2,1]]
  • المخرجات: 6

الحل هنا بسيط وواضح: نحسب مجموع كل صف، ثم نأخذ أكبر مجموع.

def maximumWealth(self, accounts):
    return max([sum(row) for row in accounts])

التحليل

  • sum(row) يحسب ثروة كل عميل.
  • List Comprehension تبني قائمة الثروات.
  • max() تختار أعلى قيمة بينها.

متى يكون استخدام الحل في سطر واحد فكرة جيدة؟

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

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

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

أفضل الممارسات عند استخدام List Comprehension في بايثون

  • استخدمها في التحويلات الواضحة والبسيطة.
  • تجنب تداخل الشروط المعقدة داخل التعبير نفسه.
  • ادمجها بحذر مع دوال مثل map() وfilter() وreduce().
  • احرص على أن يبقى الكود مفهوماً لمن يراجعه بعدك.
  • لا تجعل هدفك هو الاختصار فقط، بل الوضوح والكفاءة معاً.

الخلاصة التقنية

تُظهر الأمثلة السابقة أن List Comprehension ليست مجرد اختصار شكلي في Python، بل أداة عملية تساعد على كتابة حلول سريعة وأنيقة في مسائل LeetCode، خاصة في التعامل مع المصفوفات والقوائم. ومع ذلك، فإن الاستخدام الذكي لهذه الميزة هو ما يصنع الفارق الحقيقي؛ فكلما حافظت على التوازن بين الاختصار والوضوح، أصبحت حلولك أكثر احترافية وأسهل في الفهم والمراجعة.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *