تعقيد المساحة والمفاضلات
قِس المساحة المساعدة لمكدسات الاستدعاء وهياكل البيانات المساعدة، وتعرّف إلى مفاضلات الزمن والمساحة في التخزين المؤقت والخوارزميات التي تعمل في مكانها
تعقيد المساحة والمفاضلات درس مجاني في DSA Interview Prep على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في DSA Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة DSA Interview Prep 4 دروس في المجموع.
ماذا يقيس التعقيد المكاني؟
يقيس التعقيد المكاني الذاكرة الإضافية التي تتجاوز الإدخال، وتُسمى المساحة المساعدة. يكون استخدام بضعة متغيرات بتعقيد O(1)، بينما تكون مصفوفة النتائج أو خريطة التجزئة بتعقيد O(n). اطّلع على الشيفرة.
# O(1) auxiliary space
def sum_array(nums):
total = 0 # one integer variable
for n in nums:
total += n # constant extra space
return total
# O(n) auxiliary space
def copy_array(nums):
return list(nums) # allocates n slots
print(sum_array([1, 2, 3, 4])) # 10
print(copy_array([1, 2, 3, 4])) # [1, 2, 3, 4]مساحة مكدس الاستدعاءات في الاستدعاء الذاتي
يضيف كل استدعاء ذاتي إطارًا إلى المكدس، ولذلك يحدد العمق المساحة المطلوبة. يكون الاستدعاء الذاتي الخطي O(n)، بينما يكون بحث DFS في شجرة متوازنة O(log n). يمكن لنسخة تكرارية أن تتحكم في ذلك بصورة أفضل.
import sys
def recursive_sum(n):
if n == 0: return 0
return n + recursive_sum(n - 1)
# Space: O(n) stack frames
def iterative_sum(n):
total = 0
while n > 0:
total += n
n -= 1
return total
# Space: O(1)
print(recursive_sum(100)) # 5050
print(iterative_sum(100)) # 5050مساحة فرز الدمج: O(n)
يحتاج فرز الدمج إلى مساحة إضافية بتعقيد O(n) لمصفوفاته المؤقتة. هذه هي تكلفة فرز مستقر بتعقيد O(n log n) — إذ يوفر فرز الكومة مساحة أقل، لكنه غير مستقر. اطّلع على الشيفرة.
import tracemalloc
tracemalloc.start()
def merge_sort(arr):
if len(arr) <= 1: return arr
m = len(arr) // 2
l = merge_sort(arr[:m]) # new list
r = merge_sort(arr[m:]) # new list
out, i, j = [], 0, 0
while i < len(l) and j < len(r):
if l[i] <= r[j]: out.append(l[i]); i+=1
else: out.append(r[j]); j+=1
return out + l[i:] + r[j:]
data = list(range(1000, 0, -1))
merge_sort(data)
_, peak = tracemalloc.get_traced_memory()
print(f'Peak memory: {peak} bytes') # proportional to nالخوارزميات داخل المكان: مساحة O(1)
تغيّر خوارزمية داخل المكان الإدخال مباشرةً دون تخزين إضافي يتناسب مع حجمه — مثل عكس مصفوفة باستخدام مؤشرين. ويحافظ ذلك على المساحة عند O(1). اطّلع على الشيفرة.
def reverse_inplace(arr):
l, r = 0, len(arr) - 1
while l < r:
arr[l], arr[r] = arr[r], arr[l] # swap
l += 1
r -= 1
# Space: O(1) -- only two pointer variables
def rotate_right(arr, k):
'''Rotate array right by k positions in-place.'''
n = len(arr)
k %= n
arr.reverse() # O(1) space
arr[:k] = arr[:k][::-1]
arr[k:] = arr[k:][::-1]
a = [1, 2, 3, 4, 5]
rotate_right(a, 2)
print(a) # [4, 5, 1, 2, 3]الموازنة بين الزمن والمساحة: Two-Sum
تظهر الموازنة بين الزمن والمساحة في كل مكان. تبلغ كلفة Two-Sum الزمنية O(n^2) مع مساحة O(1)، أو O(n) زمنيًا مع مساحة O(n) باستخدام خريطة تجزئة. اذكر الخيارين واسأل أيهما أهم.
# O(n^2) time, O(1) space
def two_sum_slow(nums, target):
for i in range(len(nums)): # O(n)
for j in range(i+1, len(nums)): # O(n)
if nums[i] + nums[j] == target:
return [i, j]
return []
# O(n) time, O(n) space
def two_sum_fast(nums, target):
seen = {} # O(n) space
for i, n in enumerate(nums):
comp = target - n
if comp in seen: # O(1) lookup
return [seen[comp], i]
seen[n] = i
return []
print(two_sum_fast([2, 7, 11, 15], 9)) # [0, 1]مساحة الحفظ مقابل الجدولة
يستهلك الحفظ من أعلى إلى أسفل مساحة O(n) للنتائج المحفوظة، إضافةً إلى O(n) للمكدس؛ أما الجدولة من أسفل إلى أعلى فتتجاوز المكدس. ويؤدي الاحتفاظ بالصفوف القليلة الأخيرة فقط إلى تقليصها إلى O(1) — أي البرمجة الديناميكية المحسّنة مكانيًا.
# Fibonacci: O(n) space with full table
def fib_table(n):
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
# O(1) space: keep only last two values
def fib_optimal(n):
if n <= 1: return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
print(fib_table(10)) # 55
print(fib_optimal(10)) # 55مساحة خريطة التجزئة: O(n)
تكون خريطة التجزئة عادةً سبب تكلفة المساحة O(n) في الحلول: مجموعة للعناصر التي تمت زيارتها، أو خريطة للتكرارات بغرض العد. اذكرها دائمًا — «الزمن O(n)، والمساحة O(n)» هي الإجابة الكاملة.
def contains_duplicate(nums):
# O(n) time, O(n) space
seen = set()
for n in nums:
if n in seen: return True
seen.add(n)
return False
def group_anagrams(words):
# O(n*m) time, O(n) space (m = avg word length)
from collections import defaultdict
groups = defaultdict(list)
for w in words:
groups[tuple(sorted(w))].append(w)
return list(groups.values())
print(contains_duplicate([1,2,3,1])) # True
print(group_anagrams(['eat','tea','tan','ate','nat','bat']))تحليل المساحة لخوارزميات الرسوم البيانية
تستهلك الرسوم البيانية مساحة فعلية: فقائمة التجاور بتعقيد O(V + E)، ومجموعة العناصر التي زارها BFS وطابوره بتعقيد O(V)، كما أن الاستدعاء الذاتي لـ DFS يتعمق بمقدار O(V). اذكر مساحة الرسم البياني بدلالة V وE.
from collections import deque
def bfs(graph, start):
# Space: O(V) for visited set + O(V) for queue
visited = set() # O(V)
queue = deque([start]) # O(V) max
order = []
while queue:
node = queue.popleft()
if node in visited: continue
visited.add(node)
order.append(node)
for nb in graph.get(node, []):
queue.append(nb)
return order
g = {0:[1,2], 1:[3], 2:[3], 3:[]}
print(bfs(g, 0)) # [0, 1, 2, 3]مشكلات تخصيص السلاسل والمصفوفات
قد تؤدي التخصيصات الخفية إلى استهلاك مساحة O(n): إذ ينشئ التقطيع قائمة جديدة، كما أن استخدام + مع السلاسل داخل حلقة بتعقيد O(n^2). تنشئ sorted() نسخة، بينما يبقى lst.sort() داخل المكان. اطّلع على الشيفرة.
# Hidden allocations:
nums = [1, 2, 3, 4, 5]
# Creates a NEW list -- O(n) space
slice_copy = nums[1:4] # [2, 3, 4]
# Creates a NEW sorted list -- O(n) space
sorted_copy = sorted(nums) # nums unchanged
# Sorts IN PLACE -- O(1) extra space
nums.sort()
print(slice_copy) # [2, 3, 4]
print(sorted_copy) # [1, 2, 3, 4, 5]
print(nums) # [1, 2, 3, 4, 5]التعرّف على موازنات المساحة في المقابلات
اذكر التعقيد المكاني في البداية. إذا أراد المحاوِر مساحة أقل، فمن الخيارات الشائعة استخدام البرمجة الديناميكية من أسفل إلى أعلى بدلًا من الحفظ، أو استخدام فرز داخل المكان بدلًا من خريطة تجزئة. اطّلع على الشيفرة.
# Problem: find if array has duplicates
# Option 1: O(1) time-per-check, O(n) space
def has_dup_hash(nums):
return len(nums) != len(set(nums))
# Option 2: O(n log n) time, O(1) extra space
def has_dup_sort(nums):
nums_copy = sorted(nums) # O(n) space -- still!
for i in range(1, len(nums_copy)):
if nums_copy[i] == nums_copy[i-1]:
return True
return False
# Option 3: truly O(1) extra -- sort in-place
def has_dup_inplace(nums):
nums.sort() # modifies original
for i in range(1, len(nums)):
if nums[i] == nums[i-1]: return True
return Falseقالب العبارة الكاملة للتعقيد
اذكر دائمًا العبارة الكاملة — الزمن والمساحة: «الزمن O(n)، والمساحة الإضافية O(1)». اذكر الموازنات عند وجودها. فهذا ما يميز المرشحين ذوي الخبرة.
# Complete complexity example: Merge Intervals
def merge_intervals(intervals):
# Time: O(n log n) for sort + O(n) for merge = O(n log n)
# Space: O(n) for output (could be n/2 to n intervals)
intervals.sort(key=lambda x: x[0]) # O(n log n)
merged = [intervals[0]]
for start, end in intervals[1:]:
if start <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
return merged
print(merge_intervals([[1,3],[2,6],[8,10],[15,18]]))
# [[1,6],[8,10],[15,18]]اختبار سريع
اختبار سريع — لنرَ مدى استيعابك لأفكار التعقيد المكاني. أنت مستعد لذلك. ✅
مراجعة الدرس
مراجعة: تُحسب المساحة المساعدة باستثناء مساحة الإدخال، ويستخدم الاستدعاء الذاتي مساحة مكدس بتعقيد O(العمق)، كما أن الموازنة بين الزمن والمساحة توجه معظم خيارات تصميم الخوارزميات.
الأسئلة الشائعة
هل درس «تعقيد المساحة والمفاضلات» مجاني؟
نعم — نص درس «تعقيد المساحة والمفاضلات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة DSA Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة DSA Interview Prep 4 دروس في المجموع.
ماذا ستتعلم في «تعقيد المساحة والمفاضلات»؟
قِس المساحة المساعدة لمكدسات الاستدعاء وهياكل البيانات المساعدة، وتعرّف إلى مفاضلات الزمن والمساحة في التخزين المؤقت والخوارزميات التي تعمل في مكانها تتمرن على DSA Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ DSA Interview Prep؟
لا تُشترط خبرة سابقة. DSA Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «تعقيد المساحة والمفاضلات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس DSA Interview Prep هذا؟
نعم. كل درس في DSA Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- ترميز Big-O من الصفر
- تحليل الحلقات والحلقات المتداخلة
- الاستدعاء الذاتي وطريقة شجرة الاستدعاء الذاتي
- تعقيد المساحة والمفاضلات