Binary Tree Zigzag Level Order Traversal
لديك شجرة ثنائية مخزّنة في المصفوفة root. يقع الجذر عند الفهرس 0، ويقع أبناء الفهرس i عند 2*i+1 (اليسار) و2*i+2 (اليمين)، ويشير -1 إلى موضع فارغ، وقد تنتهي المصفوفة بعناصر -1 إضافية.
أعِد قيم العقد مستوىً تلو الآخر بترتيب متعرّج: مستوى الجذر من اليسار إلى اليمين، والمستوى التالي من اليمين إلى اليسار، وهكذا بالتناوب حتى أعمق مستوى. يُسمّى هذا أيضًا اجتياز ترتيب المستويات الحلزوني.
الدالة
- rootinteger-array
- الشجرة بترتيب الكومة، مع -1 للمكان الفارغ
- تُرجعinteger-2d-array
- قائمة واحدة من القيم لكل مستوى، بدءًا بالمستوى الأعلى، مع التناوب بين اليسار إلى اليمين واليمين إلى اليسار
القيود
1 ≤ root.length ≤ 32767- كل
root[i]إما-1أو قيمة تحقق0 ≤ root[i] ≤ 104. - قيم العقد متميزة.
root[0]لا تكون أبدًا-1، لذا تحتوي الشجرة على عقدة واحدة على الأقل.- قد تنتهي المصفوفة بعناصر
-1إضافية بعد العقدة الأخيرة. - كلا ابني الموضع الفارغ فارغان أيضًا، وعمق الشجرة لا يتجاوز
14مستوى.
أمثلة
- المدخلات
- root = [8, 12, 5, 1, 9, -1, 14, -1, -1, 4, 2, -1, -1, 11]
- المخرجات
- [[8], [5, 12], [1, 9, 14], [11, 2, 4]]
- الشرح
- عند القراءة من اليسار إلى اليمين، تكون المستويات
8؛12, 5؛1, 9, 14؛4, 2, 11. يُقرأ المستويان 1 و3 بالعكس:[5, 12]و[11, 2, 4].
- المدخلات
- root = [1, 2, 3, 4, 5, 6, 7, -1, -1]
- المخرجات
- [[1], [3, 2], [4, 5, 6, 7]]
- الشرح
- شجرة كاملة من ثلاثة مستويات: ينعكس المستوى الأوسط إلى
[3, 2]، ويتجه المستوى الثالث من اليسار إلى اليمين مجددًا. العنصران-1في النهاية يمثلان موضعي الابنين الفارغين للعقدة4.
- المدخلات
- root = [5]
- المخرجات
- [[5]]
- الشرح
- العقدة الواحدة هي مستوى واحد لقيمة واحدة، تُقرأ في أيٍّ من الاتجاهين.
سؤال إضافي
هل يمكنك وضع كل قيمة مباشرةً في موضعها النهائي في صفّها، من دون عكس ومن دون مكدّس ثانٍ؟
تلميحات
افتحها واحدًا تلو الآخر. كل تلميح يكشف أكثر قليلًا.
اجمع المستويات أولًا، كل مستوى من اليسار إلى اليمين، كما في اجتياز عادي حسب ترتيب المستويات. أيّ من هذه القوائم يجب تغييرها، وكيف؟
رقّم المستويات بدءًا من 0 عند الجذر. تُقرأ المستويات الفردية بالعكس. يستغرق عكس قائمة وقتًا يعادل وقت قراءتها، لذا فإن عكس تلك المستويات يُبقي العملية برمّتها خطية.
لتجاوز عملية العكس، احتفظ بالمستوى الحالي في مكدس وادفع الأبناء إلى مكدس ثانٍ أثناء إخراج العناصر: الابن الأيسر أولًا عند القراءة من اليسار إلى اليمين، والابن الأيمن أولًا عند القراءة من اليمين إلى اليسار. عندها يُخرج المكدس الثاني المستوى التالي بالترتيب الذي تحتاجه.
الحل
تأتي المستويات من بحث عادي بعرض الشجرة. والجزء الجديد هو الاتجاه: يخرج كل مستوى آخر معكوسًا. اعكس الصفوف ذات الأرقام الفردية بعد إنشائها، أو ضع كل مستوى في مكدس، فيعيد العناصر بترتيب معاكس لترتيب إدخالها.
ترتيب المستويات، ثم عكس كل مستوى آخر
الفكرة
يعالج الطابور مستوىً واحدًا في كل جولة، فيُنتج كل مستوى من اليسار إلى اليمين. رقّم المستويات بدءًا من 0 عند الجذر: يقرأ النمط المتعرّج المستويات الفردية من اليمين إلى اليسار، لذا فإن عكس تلك الصفوف وحدها يعطي الإجابة.
تزور عملية البحث كل عقدة مرة واحدة، ويلامس كل عكس كل قيمة مرة أخرى، لذا يكون الزمن O(n).
الخوارزمية
- ابدأ طابورًا بالفهرس
0. - في كل جولة، احفظ طول الطابور
s، وأزلsفهارس من الطابور وضعها في صف جديد، ثم أدرج أبناء كل فهرس موجودين في الطابور، الأيسر قبل الأيمن. - إذا كان الجواب يحتوي بالفعل على عدد فردي من الصفوف، فاعكس الصف.
- أضف الصف وتابع حتى يصبح الطابور فارغًا.
from collections import deque
def zigzagLevelOrder(root):
n = len(root)
levels = []
queue = deque([0]) # node indexes; the root is never empty
while queue:
row = []
for _ in range(len(queue)): # exactly the nodes of the current level
i = queue.popleft()
row.append(root[i])
for child in (2 * i + 1, 2 * i + 2):
if child < n and root[child] != -1:
queue.append(child)
if len(levels) % 2 == 1: # levels 1, 3, 5, ... read from right to left
row.reverse()
levels.append(row)
return levelsمكدسان
الفكرة
احتفظ بالمستوى الحالي في مكدس يُخرج العناصر في الاتجاه الذي يُقرأ به المستوى، وأضف أبناء كل عقدة تُخرج إلى مكدس ثانٍ. عندما يفرغ المكدس الحالي، يحتوي المكدس الثاني على المستوى التالي.
ترتيب الإضافة هو ما يجعل ذلك ينجح. عند الإخراج من اليسار إلى اليمين، أضف الابن الأيسر لكل عقدة، ثم ابنها الأيمن: يُضاف الابن الأيمن للعقدة الواقعة أقصى اليمين أخيرًا، لذا يُخرج المستوى التالي من طرفه الأيمن. عند الإخراج من اليمين إلى اليسار، أضف الابن الأيمن ثم الأيسر، ويُضاف الابن الأيسر للعقدة الواقعة أقصى اليسار أخيرًا.
مثال 1: أخرج 8، وأضف 12, 5. أخرج 5, 12، ثم أضف 14 من 5 و9, 1 من 12. أخرج 1, 9, 14، ثم أضف 4, 2 من 9 و11 من 14. أخرج 11, 2, 4.
تُضاف كل عقدة وتُخرج مرة واحدة: زمن O(n)، دون تمريرة لعكس الترتيب.
الخوارزمية
- ضع فهرس الجذر
0في مكدس وابدأ القراءة من اليسار إلى اليمين. - ما دام المكدس غير فارغ، أخرج كل فهرس وضعه في صف جديد، وادفع أبناء كل عقدة مُخرَجة الموجودين إلى مكدس ثانٍ: اليسار ثم اليمين عند القراءة من اليسار إلى اليمين، واليمين ثم اليسار خلاف ذلك.
- أضف الصف إلى الإجابة.
- اجعل المكدس الثاني هو المكدس الحالي، واعكس الاتجاه ثم كرر.
def zigzagLevelOrder(root):
n = len(root)
levels = []
current = [0] # a stack of node indexes; the root is never empty
left_to_right = True
while current:
row = []
upcoming = [] # the next level, pushed while this one pops
while current:
i = current.pop()
row.append(root[i])
# Push so that the next level pops out in its own direction.
if left_to_right:
children = (2 * i + 1, 2 * i + 2)
else:
children = (2 * i + 2, 2 * i + 1)
for child in children:
if child < n and root[child] != -1:
upcoming.append(child)
levels.append(row)
current = upcoming
left_to_right = not left_to_right
return levels
أخطاء شائعة وحالات حدّية
- عكس الترتيب الذي يدخل به الأبناء إلى طابور واحد. يتبادل الأشقاء أماكنهم، لكن الآباء يحافظون على ترتيبهم: يكون المستوى الثالث في المثال 1 بالشكل
[9, 1, 14]. - بدء عدّ المستويات من 1. يؤدي كل عكس إلى انحراف بمستوى واحد، ويعطي المثال 1 الناتج
[[8], [12, 5], [14, 9, 1], [4, 2, 11]]. - استخدام ترتيب دفع واحد في كل مستوى من إصدار المكدسين. عندئذٍ يُخرَج المستوى الثالث في المثال 1 بالشكل
[9, 1, 14]. - دفع الأبناء إلى المكدس الذي ما زلت تسحب منه. سيخرجون قبل بقية عناصر مستوى والدهم.
- ترتيب صف بدلًا من عكسه. يجب أن يكون المستوى الأخير في المثال 1 هو
[11, 2, 4]، وهو ناتج لا ينتجه أي ترتيب.
أسئلة شائعة3
ما الفرق بين اجتياز التعرّج والاجتياز حسب المستوى؟
يزور كلاهما المستويات نفسها بالعقد نفسها. يقرأ اجتياز المستويات كل مستوى من اليسار إلى اليمين؛ أما الاجتياز المتعرج فيقرأ مستوى بعد الآخر من اليمين إلى اليسار، بدءًا من المستوى الذي يلي الجذر. يستغرق كلاهما زمنًا قدره O(n).
هل الاجتياز المتعرج هو نفسه اجتياز الشجرة بالترتيب الحلزوني؟
نعم، يصف الاسمان المسار نفسه. تبدأ بعض النصوص المستوى الثاني من اليسار بدلًا من اليمين، ما يؤدي فقط إلى نقل عمليات القلب مستوىً واحدًا. هنا يمتد مستوى الجذر من اليسار إلى اليمين، والمستوى التالي من اليمين إلى اليسار.
هل يمكن تنفيذ الترتيب حسب المستوى المتعرج باستخدام طابور مزدوج الطرف؟
نعم. أبقِ كل مستوى في الطابور مزدوج النهاية مرتبًا من اليسار إلى اليمين. في المستوى من اليسار إلى اليمين، خذ العقد من المقدمة وأضف أبناءها، اليسار ثم اليمين، إلى المؤخرة. وفي المستوى من اليمين إلى اليسار، خذ العقد من المؤخرة وأضف أبناءها، اليمين ثم اليسار، إلى المقدمة. يظل العدد الذي تأخذه عند بدء الجولة هو ما يحدد المستوى.
مسائل مشابهة
مسائل تعتمد على الأفكار نفسها. حلّ اثنتين أو ثلاث منها يثبّت النمط.
def zigzagLevelOrder(root):
# اكتب الكود هنااختبار #1
اختبار #2
اختبار #3
وسيط
root = [8, 12, 5, 1, 9, -1, 14, -1, -1, 4, 2, -1, -1, 11]
الإخراج المتوقع
[[8], [5, 12], [1, 9, 14], [11, 2, 4]]