कोडिंग साक्षात्कार की तैयारी · पाठ

स्टैक और क्यू का पारस्परिक अनुकरण

दो स्टैक से क्यू और दो क्यू से स्टैक लागू कीजिए तथा दोनों तरीकों की परिशोधित लागत समझाइए।

पाठ 4, कुल 4 में से13 चरण

स्टैक और क्यू का पारस्परिक अनुकरण, CoddyKit पर कोडिंग साक्षात्कार की तैयारी का एक निःशुल्क पाठ है। यह 4 में से 4वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह कोडिंग साक्षात्कार की तैयारी सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। कोडिंग साक्षात्कार की तैयारी पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

एक संरचना को दूसरी से क्यों अनुकरण करें

दो स्टैक से कतार और दो कतारों से स्टैक लागू करना अभिकल्पना-साक्षात्कार के पारंपरिक प्रश्न हैं। ये दोनों डेटा संरचनाओं के क्रम-नियमों की आपकी समझ और दूसरी संरचना की मूल क्रियाओं का उपयोग करते हुए एक संरचना की गारंटी बनाए रखने की आपकी क्षमता जाँचते हैं। साक्षात्कारकर्ता इनका उपयोग परिशोधित जटिलता पर चर्चा शुरू करने के लिए भी करते हैं।

मुख्य बात यह है: स्टैक LIFO होते हैं और कतारें FIFO। इनके बीच बदलने के लिए क्रम उलटना पड़ता है—और एक स्टैक को दूसरे स्टैक में उलटने पर मूल प्रविष्टि क्रम वापस मिल जाता है, जो FIFO होता है।

दो स्टैक से कतार (विलंबित तरीका)

विलंबित तरीके में जोड़ने के लिए inbox स्टैक और निकालने के लिए outbox स्टैक का उपयोग कीजिए। जब कतार से निकालने की क्रिया की जाए, यदि outbox खाली हो, तो inbox के सभी तत्व outbox में स्थानांतरित कीजिए—यह उलटाव FIFO क्रम वापस लाता है। यदि outbox खाली न हो, तो सीधे उसी से तत्व निकालिए। स्थानांतरण विलंब से होते हैं, इसलिए O(n) स्थानांतरण लागत कई क्रियाओं में परिशोधित हो जाती है।

class MyQueue:
    def __init__(self):
        self.inbox  = []
        self.outbox = []

    def push(self, x):
        self.inbox.append(x)

    def _transfer(self):
        if not self.outbox:
            while self.inbox:
                self.outbox.append(self.inbox.pop())

    def pop(self):
        self._transfer()
        return self.outbox.pop()

    def peek(self):
        self._transfer()
        return self.outbox[-1]

    def empty(self):
        return not self.inbox and not self.outbox

q = MyQueue()
q.push(1); q.push(2); q.push(3)
print(q.peek())  # 1
print(q.pop())   # 1
print(q.pop())   # 2
q.push(4)
print(q.pop())   # 3

स्टैक से कतार के लिए परिशोधित O(1) विश्लेषण

प्रत्येक तत्व को inbox से outbox में अधिकतम एक बार स्थानांतरित किया जाता है। जब outbox से तत्व निकालना O(1) हो और स्थानांतरण केवल outbox के खाली होने पर हों, तो n बार जोड़ने और n बार निकालने में अधिकतम 2n स्टैक क्रियाएँ होती हैं—कुल O(n), अर्थात प्रति क्रिया परिशोधित O(1)। इसका अर्थ है कि सबसे खराब स्थिति में कोई एक क्रिया O(n) की हो सकती है, लेकिन औसत लागत O(1) होती है।

# Trace transfer costs for 10 push/pop interleaved
class TrackedQueue:
    def __init__(self):
        self.inbox = []; self.outbox = []; self.transfers = 0

    def push(self, x): self.inbox.append(x)

    def pop(self):
        if not self.outbox:
            while self.inbox:
                self.outbox.append(self.inbox.pop())
                self.transfers += 1
        return self.outbox.pop()

q = TrackedQueue()
for i in range(5):
    q.push(i)
for _ in range(5):
    q.pop()
q.push(10); q.push(20)
q.pop()
print('Total transfer operations:', q.transfers)  # at most n

दो कतारों से स्टैक (विलंबित निष्कासन)

दो कतारों से स्टैक लागू करना कम स्वाभाविक है, क्योंकि कतारें FIFO होती हैं। विलंबित निष्कासन वाले तरीके में एक मुख्य कतार और एक अस्थायी कतार रखिए। push पर मुख्य कतार में तत्व जोड़िए (O(1))। pop या peek पर अंतिम तत्व को छोड़कर सभी तत्वों को अस्थायी कतार में निकालिए, अंतिम तत्व को सुरक्षित रखिए, फिर दोनों कतारों की अदला-बदली कीजिए। यह प्रत्येक pop के लिए O(n), लेकिन प्रत्येक push के लिए O(1) है।

from collections import deque

class MyStack:
    def __init__(self):
        self.main = deque()
        self.temp = deque()

    def push(self, x):
        self.main.append(x)   # O(1)

    def pop(self):
        # Move all but last element to temp
        while len(self.main) > 1:
            self.temp.append(self.main.popleft())
        val = self.main.popleft()   # the 'top'
        self.main, self.temp = self.temp, self.main  # swap
        return val

    def top(self):
        while len(self.main) > 1:
            self.temp.append(self.main.popleft())
        val = self.main[0]
        self.temp.append(self.main.popleft())
        self.main, self.temp = self.temp, self.main
        return val

    def empty(self):
        return len(self.main) == 0

s = MyStack()
s.push(1); s.push(2); s.push(3)
print(s.top())  # 3
print(s.pop())  # 3
print(s.pop())  # 2

एक कतार से स्टैक (जोड़ते समय घुमाना)

एक कतार का सुंदर कार्यान्वयन यह है: push पर नया तत्व कतार में जोड़िए, फिर कतार को इस तरह घुमाइए कि नया तत्व आगे आ जाए। घुमाने का अर्थ है push से पहले मौजूद सभी तत्वों को कतार से निकालकर फिर उसी में जोड़ना। इसके बाद pop और peek O(1) हो जाते हैं (केवल आगे से निकालना/peek करना पड़ता है)। push O(n) है—दो कतारों वाले संस्करण के उलट समझौता।

from collections import deque

class MyStackOneQueue:
    def __init__(self):
        self.q = deque()

    def push(self, x):
        self.q.append(x)
        # Rotate: move all preceding elements behind x
        for _ in range(len(self.q) - 1):
            self.q.append(self.q.popleft())

    def pop(self):
        return self.q.popleft()

    def top(self):
        return self.q[0]

    def empty(self):
        return len(self.q) == 0

s = MyStackOneQueue()
s.push(1); s.push(2); s.push(3)
print(s.top())  # 3
print(s.pop())  # 3
print(s.top())  # 2

समझौते का सारांश: कौन-सा रूप चुनें

दो स्टैक से कतार के लिए: push O(1), pop/peek परिशोधित O(1)—जब pop क्रियाएँ अधिक हों तब इसे चुनिए। दो कतारों से स्टैक के लिए: push O(1), pop O(n)—जब push क्रियाएँ pop की तुलना में बहुत अधिक हों तब इसे चुनिए। एक कतार से स्टैक के लिए: push O(n), pop O(1)—जब pop क्रियाएँ प्रमुख हों तब इसे चुनिए। साक्षात्कार में इन समझौतों को स्पष्ट रूप से बताइए, ताकि यह दिखे कि आप केवल “यह काम करता है” से आगे भी सोचते हैं।

print('Queue from 2 stacks: push O(1), pop O(1) amortised')
print('Stack from 2 queues: push O(1), pop O(n)')
print('Stack from 1 queue:  push O(n), pop O(1)')

उलटने से FIFO क्यों बहाल होता है

जब 1, 2, 3 तत्वों को स्टैक (inbox) में डाला जाता है, तो वे नीचे से ऊपर के क्रम में 1, 2, 3 रहते हैं। सभी तत्वों को दूसरे स्टैक (outbox) में निकालने पर क्रम उलट जाता है: outbox में नीचे 3 और ऊपर 1 होता है। outbox से तत्व निकालने पर क्रम 1, फिर 2, फिर 3 मिलता है—बिल्कुल FIFO प्रविष्टि क्रम। यही कारण है कि ठीक दो उलटाव (दो स्टैक) FIFO को बहाल करते हैं, जबकि एक स्टैक LIFO देता है।

# Demonstrate double-reversal = FIFO
inbox  = [1, 2, 3]   # pushed in this order
outbox = []
while inbox:
    outbox.append(inbox.pop())
print('outbox (one reversal):', outbox)  # [3, 2, 1] top-to-bottom

# Pop from outbox gives FIFO
result = []
while outbox:
    result.append(outbox.pop())
print('dequeued:', result)  # [1, 2, 3] — FIFO!

LeetCode 232: स्टैक से कतार लागू करना

LeetCode 232 सीधे “दो स्टैक से कतार” वाली समस्या है। अपेक्षित समाधान विलंबित outbox स्थानांतरण है। साक्षात्कार में बताइए कि प्रत्येक तत्व अधिकतम एक बार inbox से outbox में जाता है, इसलिए सभी क्रियाओं की परिशोधित लागत O(1) होती है। यह भी बताइए कि किसी एक pop क्रिया की सबसे खराब स्थिति में लागत O(n) हो सकती है (जब outbox खाली हो), लेकिन n क्रियाओं पर औसत लागत O(1) रहती है।

class MyQueue:
    def __init__(self):
        self.inbox  = []
        self.outbox = []

    def push(self, x):
        self.inbox.append(x)

    def pop(self):
        self.peek()             # ensure outbox is populated
        return self.outbox.pop()

    def peek(self):
        if not self.outbox:
            while self.inbox:   # transfer lazily
                self.outbox.append(self.inbox.pop())
        return self.outbox[-1]

    def empty(self):
        return not self.inbox and not self.outbox

# Simulation
q = MyQueue()
q.push(1); q.push(2)
print(q.peek())  # 1
print(q.pop())   # 1
print(q.empty()) # False

LeetCode 225: कतारों से स्टैक लागू करना

LeetCode 225 “कतारों से स्टैक” वाली समस्या है। एक कतार को जोड़ते समय घुमाने वाला समाधान सबसे साफ़ है। तत्व x को जोड़ने के बाद, पहले से मौजूद सभी तत्वों को x के पीछे ले जाकर कतार घुमाइए। इसमें प्रत्येक push के लिए O(n) लागत आती है, लेकिन top और pop O(1) हो जाते हैं। इस समझौते को बताइए और पुष्टि कीजिए कि यह शर्तों के अनुरूप है (जैसे, कम push या अधिक pop वाला कार्यभार)।

from collections import deque

class MyStack:
    def __init__(self):
        self.q = deque()

    def push(self, x):       # O(n)
        self.q.append(x)
        for _ in range(len(self.q) - 1):
            self.q.append(self.q.popleft())

    def pop(self):           # O(1)
        return self.q.popleft()

    def top(self):           # O(1)
        return self.q[0]

    def empty(self):
        return len(self.q) == 0

s = MyStack()
s.push(1); s.push(2); s.push(3)
print(s.top())  # 3
print(s.pop())  # 3
print(s.top())  # 2
print(s.empty()) # False

एक ऐरे में तीन स्टैक तक विस्तार

एक संबंधित रूप-रचना चुनौती है: एक ही ऐरे का उपयोग करके तीन स्टैक लागू कीजिए। एक तरीका ऐरे को तीन बराबर, स्थिर खंडों में बाँटता है। अधिक लचीला तरीका पॉइंटरों के साथ आंतरित भंडारण का उपयोग करता है, प्रत्येक स्टैक को उसके क्षेत्र से बढ़ाता है और सीमाएँ टकराने पर प्रतिलिपि बनाता है। यह गतिशील ऐरे प्रबंधन की जाँच करता है और वरिष्ठ-स्तरीय साक्षात्कारों में पूछा जाता है। स्थिर-खंड वाला तरीका सरल है, लेकिन यदि स्टैक असमान रूप से बढ़ें तो स्थान व्यर्थ करता है।

class ThreeStacks:
    def __init__(self, size):
        self.data = [0] * (3 * size)
        self.tops = [-1, -1, -1]  # relative top of each stack
        self.size = size

    def push(self, stack_num, val):
        self.tops[stack_num] += 1
        if self.tops[stack_num] >= self.size:
            raise OverflowError('stack full')
        self.data[stack_num * self.size + self.tops[stack_num]] = val

    def pop(self, stack_num):
        if self.tops[stack_num] < 0:
            raise IndexError('stack empty')
        val = self.data[stack_num * self.size + self.tops[stack_num]]
        self.tops[stack_num] -= 1
        return val

ts = ThreeStacks(5)
ts.push(0, 10); ts.push(1, 20); ts.push(2, 30)
print(ts.pop(0), ts.pop(1), ts.pop(2))  # 10 20 30

मुख्य बातें: अनुकरण के प्रतिरूप

पारस्परिक अनुकरण वाली समस्याएँ एक व्यापक सिद्धांत सिखाती हैं: पर्याप्त मध्यवर्ती बफ़रिंग और उलटाव उपलब्ध होने पर किसी भी डेटा संरचना को दूसरी डेटा संरचना से बनाया जा सकता है। अनुकरण की लागत इस बात पर निर्भर करती है कि आप किन संक्रियाओं को अनुकूलित करते हैं — आप हमेशा push को O(1) या pop को O(1) बना सकते हैं, लेकिन दोनों को O(1) बनाने के लिए अमॉर्टाइज़ेशन या कई सहायक संरचनाओं की आवश्यकता होती है।

साक्षात्कार में हमेशा पूछिए: 'कौन-सी संक्रियाएँ अधिक बार होती हैं?' इससे कार्यान्वयन के प्रकार का चुनाव तय होता है और संचालन संबंधी आवश्यकताओं पर वरिष्ठ-स्तरीय सोच का संकेत मिलता है।

त्वरित जाँच

इस पाठ में डेटा संरचनाएँ और एल्गोरिद्म — कोडिंग साक्षात्कार की तैयारी से संबंधित अवधारणाओं की अपनी समझ जाँचिए।

पाठ का पुनरावलोकन

इस पाठ में आपने सीखा: दो स्टैक से बना क्यू इनबॉक्स से आउटबॉक्स में तत्वों को आवश्यकता पड़ने पर स्थानांतरित करके O(1) का अमॉर्टाइज़्ड pop प्राप्त करता है, एक क्यू से बना स्टैक प्रत्येक push पर क्यू को घुमाकर O(1) का pop प्राप्त करता है (push की लागत O(n) होती है), और किस संक्रिया को O(1) बनाना है, इसका चुनाव उपयोग के प्रतिरूप पर निर्भर करता है। आगे हम हैश मैप की आंतरिक कार्यप्रणाली और टकराव प्रबंधन का अध्ययन करेंगे।

शुरुआत निःशुल्क

एआई शिक्षक के साथ कोडिंग साक्षात्कार की तैयारी सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
90
पाठ
360

अक्सर पूछे जाने वाले प्रश्न

क्या “स्टैक और क्यू का पारस्परिक अनुकरण” पाठ निःशुल्क है?

हाँ—“स्टैक और क्यू का पारस्परिक अनुकरण” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और कोडिंग साक्षात्कार की तैयारी पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। कोडिंग साक्षात्कार की तैयारी पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“स्टैक और क्यू का पारस्परिक अनुकरण” में मैं क्या सीखूँगा?

दो स्टैक से क्यू और दो क्यू से स्टैक लागू कीजिए तथा दोनों तरीकों की परिशोधित लागत समझाइए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ कोडिंग साक्षात्कार की तैयारी का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या कोडिंग साक्षात्कार की तैयारी शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर कोडिंग साक्षात्कार की तैयारी शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 4वाँ पाठ है।

“स्टैक और क्यू का पारस्परिक अनुकरण” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस कोडिंग साक्षात्कार की तैयारी पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर कोडिंग साक्षात्कार की तैयारी पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. स्टैक का कार्यान्वयन और उपयोग
  2. क्यू का कार्यान्वयन और Deque
  3. Monotonic Stack पैटर्न
  4. स्टैक और क्यू का पारस्परिक अनुकरण
← कोडिंग साक्षात्कार की तैयारी पर वापस जाएँ