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

सबसे लंबा लगातार अनुक्रम और LRU Cache

set का उपयोग करके longest-consecutive-sequence को O(n) में हल कीजिए, फिर OrderedDict से LRU cache की रूपरेखा बनाइए।

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

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

सबसे लंबा क्रमागत अनुक्रम

LeetCode 128 'सबसे लंबा क्रमागत अनुक्रम': बिना क्रमबद्ध की गई सरणी दी गई हो, तो क्रमागत पूर्णांकों के सबसे लंबे अनुक्रम की लंबाई खोजिए। उदाहरण: [100,4,200,1,3,2] में लंबाई 4 वाला क्रमागत अनुक्रम [1,2,3,4] मौजूद है। चुनौती यह है कि इसे O(n log n) के बजाय O(n) में हल किया जाए (क्रमबद्ध करके स्कैन करने पर O(n log n) मिलता है)।

मुख्य विचार यह है: O(1) सदस्यता-जाँच के लिए एक सेट का उपयोग कीजिए और किसी अनुक्रम की गिनती केवल उसके सबसे छोटे तत्व से शुरू कीजिए (यह जाँचकर पहचाना जाता है कि उसका पूर्ववर्ती सेट में मौजूद नहीं है)।

def longestConsecutive(nums):
    num_set = set(nums)
    best    = 0
    for n in num_set:
        if n - 1 not in num_set:   # n is the start of a sequence
            curr_n = n
            length = 1
            while curr_n + 1 in num_set:
                curr_n += 1
                length += 1
            best = max(best, length)
    return best

print(longestConsecutive([100,4,200,1,3,2]))   # 4
print(longestConsecutive([0,3,7,2,5,8,4,6,0,1]))  # 9

O(n) का प्रमाण क्यों सही है

बाहरी लूप की सभी पुनरावृत्तियों में प्रत्येक संख्या while लूप में अधिकतम एक बार देखी जाती है। यद्यपि for लूप के भीतर while लूप है, फिर भी सभी बाहरी पुनरावृत्तियों में while लूप की कुल पुनरावृत्तियों की संख्या अधिकतम n होती है, क्योंकि प्रत्येक संख्या अधिकतम एक अनुक्रम के 'वर्तमान संख्या + 1' के रूप में आ सकती है। यह परिशोधित तर्क कुल मिलाकर O(n) देता है, जो एकदिश स्टैक के विश्लेषण के समान है।

# Demonstrate O(n) total inner iterations
nums    = list(range(1000))  # worst case: one long sequence
num_set = set(nums)
inner_iters = 0
for n in num_set:
    if n - 1 not in num_set:
        curr = n
        while curr + 1 in num_set:
            curr += 1
            inner_iters += 1
print('n =', len(nums), '  total inner iterations =', inner_iters)
# inner_iters = n-1 <= n => O(n)

वैकल्पिक तरीका: क्रमबद्धीकरण-आधारित समाधान

तुलना के लिए, क्रमबद्ध-और-स्कैन तरीका O(n log n) समय लेता है: सरणी को क्रमबद्ध कीजिए, लगातार आने वाले डुप्लिकेट हटाइए, फिर क्रमागत अनुक्रमों की गिनती कीजिए। यह धीमा है, लेकिन अतिरिक्त O(1) स्थान का उपयोग करता है (यदि क्रमबद्धीकरण उसी स्थान पर किया जाए)। सेट वाला तरीका O(n) अतिरिक्त स्थान लेता है। साक्षात्कार में दोनों तरीके बताइए और स्पष्ट कीजिए कि स्थान की सीमाओं को देखते हुए O(n log n) वाला समाधान स्वीकार्य है या नहीं।

def longestConsecutive_sort(nums):
    if not nums:
        return 0
    nums.sort()
    best = length = 1
    for i in range(1, len(nums)):
        if nums[i] == nums[i-1]:
            continue              # skip duplicates
        if nums[i] == nums[i-1] + 1:
            length += 1
            best = max(best, length)
        else:
            length = 1
    return best

print(longestConsecutive_sort([100,4,200,1,3,2]))  # 4

LRU कैश क्या है

LRU (सबसे कम हाल में उपयोग किया गया) कैश निश्चित क्षमता वाली डेटा संरचना है, जो भर जाने पर और नई वस्तु डालने की आवश्यकता होने पर सबसे कम हाल में उपयोग की गई वस्तु को बाहर निकाल देती है। क्रियाएँ: get(key) कुंजी मौजूद होने पर उसका मान लौटाता है (और उसे हाल में उपयोग की गई वस्तु के रूप में चिह्नित करता है), या कुंजी न होने पर -1 लौटाता है; put(key, value) युग्म डालता है (क्षमता पूरी होने पर LRU वस्तु को बाहर निकालता है)।

LRU कैश का उपयोग ऑपरेटिंग सिस्टम्स (पृष्ठ प्रतिस्थापन), ब्राउज़र कैश और डेटाबेस प्रश्न-कैश में किया जाता है। LeetCode 146 में आपसे O(1) get और put वाली कैश बनाने को कहा जाता है।

OrderedDict से LRU कैश

पाइथन का collections.OrderedDict डालने का क्रम बनाए रखता है और किसी वस्तु को सबसे हाल में उपयोग की गई वस्तु के रूप में चिह्नित करने के लिए move_to_end(key) (O(1)) का समर्थन करता है। put पर कुंजी को अंत में ले जाइए; सीमा पार होने पर पहली वस्तु निकालिए (LRU)। इससे आंतरिक रूप से द्वि-संबद्ध सूची और हैश मैप पर आधारित अंतर्निहित संरचना का उपयोग करके O(1) get और put मिलते हैं।

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache    = OrderedDict()

    def get(self, key):
        if key not in self.cache:
            return -1
        self.cache.move_to_end(key)  # mark as recently used
        return self.cache[key]

    def put(self, key, value):
        if key in self.cache:
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            self.cache.popitem(last=False)  # evict LRU (first item)

cache = LRUCache(2)
cache.put(1, 1); cache.put(2, 2)
print(cache.get(1))  # 1 (and 1 becomes most recently used)
cache.put(3, 3)      # evict key 2 (LRU)
print(cache.get(2))  # -1
cache.put(4, 4)      # evict key 1 (LRU)
print(cache.get(1))  # -1
print(cache.get(3))  # 3
print(cache.get(4))  # 4

शुरू से LRU कैश: द्वि-संबद्ध सूची + HashMap

शुरू से किया गया कार्यान्वयन द्वि-संबद्ध सूची (O(1) नोड हटाने के लिए) और हैश मैप (कुंजी के आधार पर O(1) नोड खोजने के लिए) का उपयोग करता है। सूची LRU (head.next) से MRU (tail.prev) तक क्रम बनाए रखती है। डमी head और tail प्रहरी, सीमाओं पर डालने और हटाने से जुड़े विशेष मामलों को समाप्त करते हैं।

class DNode:
    def __init__(self, key=0, val=0):
        self.key  = key
        self.val  = val
        self.prev = None
        self.next = None

class LRUCacheDLL:
    def __init__(self, capacity):
        self.cap  = capacity
        self.map  = {}   # key -> DNode
        self.head = DNode()   # dummy LRU end
        self.tail = DNode()   # dummy MRU end
        self.head.next = self.tail
        self.tail.prev = self.head

    def _remove(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev

    def _add_to_tail(self, node):
        node.prev = self.tail.prev
        node.next = self.tail
        self.tail.prev.next = node
        self.tail.prev = node

    def get(self, key):
        if key not in self.map:
            return -1
        node = self.map[key]
        self._remove(node)
        self._add_to_tail(node)
        return node.val

    def put(self, key, val):
        if key in self.map:
            self._remove(self.map[key])
        node = DNode(key, val)
        self._add_to_tail(node)
        self.map[key] = node
        if len(self.map) > self.cap:
            lru = self.head.next
            self._remove(lru)
            del self.map[lru.key]

cache = LRUCacheDLL(2)
cache.put(1,1); cache.put(2,2)
print(cache.get(1))  # 1
cache.put(3,3)
print(cache.get(2))  # -1 (evicted)

LRU के लिए द्वि-संबद्ध सूची क्यों

एकल-संबद्ध सूची किसी मनमाने नोड को O(1) में नहीं हटा सकती, जब तक कि उसके पूर्ववर्ती का पता न हो। द्वि-संबद्ध सूची prev और next दोनों पॉइंटर रखती है, इसलिए नोड का संदर्भ मिलने पर हटाना O(1) में संभव होता है। हैश मैप कुंजी के आधार पर नोड तक O(1) अभिगम प्रदान करता है। साथ में: get(key) में नोड खोजने के लिए O(1) और उसे tail तक ले जाने के लिए O(1) समय लगता है; put(key) में नोड जोड़ने के लिए O(1) और head से LRU नोड हटाने के लिए O(1) समय लगता है।

# Why not a singly linked list?
# To remove a node you need its predecessor
# With SLL: must traverse from head to find predecessor => O(n)
# With DLL: node.prev IS the predecessor => O(1) removal

print('SLL removal: O(n) — must find predecessor by traversal')
print('DLL removal: O(1) — node.prev is immediately available')
print('Hash map lookup: O(1) — get DNode reference by key')
print('Combined LRU get/put: O(1) average')

LFU कैश (सबसे कम बार उपयोग किया गया)

एक कठिन रूप LFU कैश (LeetCode 460) है, जिसमें सबसे कम अभिगम-गिनती वाली वस्तु को बाहर निकाला जाता है। बराबरी की स्थिति में हालिया उपयोग के आधार पर निर्णय होता है (समान रूप से कम आवृत्ति वाली वस्तुओं में सबसे कम हाल में उपयोग की गई वस्तु)। कार्यान्वयन के लिए तीन डेटा संरचनाएँ चाहिए: कुंजी-से-मान मैप, कुंजी-से-आवृत्ति मैप और आवृत्ति-से-OrderedDict मैप (प्रत्येक आवृत्ति समूह के भीतर डालने का क्रम बनाए रखने के लिए)। LFU get और put परिशोधित रूप से O(1) होते हैं।

from collections import defaultdict, OrderedDict

class LFUCache:
    def __init__(self, capacity):
        self.cap   = capacity
        self.min_f = 0
        self.kv    = {}   # key -> val
        self.kf    = {}   # key -> freq
        self.fk    = defaultdict(OrderedDict)  # freq -> {key: None}

    def _touch(self, key):
        f = self.kf[key]
        self.kf[key] = f + 1
        del self.fk[f][key]
        if not self.fk[f] and f == self.min_f:
            self.min_f += 1
        self.fk[f+1][key] = None

    def get(self, key):
        if key not in self.kv:
            return -1
        self._touch(key)
        return self.kv[key]

    def put(self, key, val):
        if self.cap == 0: return
        if key in self.kv:
            self.kv[key] = val
            self._touch(key)
        else:
            if len(self.kv) == self.cap:
                lfu_key, _ = self.fk[self.min_f].popitem(last=False)
                del self.kv[lfu_key]; del self.kf[lfu_key]
            self.kv[key] = val; self.kf[key] = 1
            self.fk[1][key] = None; self.min_f = 1

रूप-पद्धतियाँ: हैश मैप + लिंक्ड सूची

LRU कैश एक शक्तिशाली रूप-पद्धति दिखाता है: O(1) कुंजी-अभिगम के लिए हैश मैप को O(1) क्रमबद्ध क्रियाओं के लिए लिंक्ड सूची के साथ जोड़ना। यह रूप-पद्धति साक्षात्कार की कई अभिकल्पना समस्याओं में दिखाई देती है: LRU कैश, LFU कैश, स्किप सूचियाँ और कुछ कतार रूप। जब भी किसी समस्या में O(1) अभिगम और O(1) क्रम-आधारित क्रियाएँ दोनों चाहिए हों, इस संयोजन पर विचार कीजिए।

साक्षात्कार में इस रूप-पद्धति को स्पष्ट रूप से बताना प्रणाली-स्तरीय सोच और क्लासिक डेटा संरचना-संयोजनों से परिचय दिखाता है।

मैट्रिक्स में क्रमागत अनुक्रम

क्रमागत अनुक्रम के विचार का 2D विस्तार: पूर्णांकों का एक मैट्रिक्स दिया गया हो, तो उस सबसे लंबे क्रमागत अनुक्रम की लंबाई खोजिए जिसे खोजा जा सके (हर चरण में किसी सन्निकट सेल पर जाना होता है)। इसमें BFS/DFS को क्रमागत-अनुक्रम सेट वाले तरीके के साथ जोड़ा जाता है। प्रत्येक मान का स्थान संग्रहीत कीजिए, फिर प्रत्येक प्रारंभिक मान के लिए जाँचिए कि मान+1 पड़ोसी के रूप में मौजूद है या नहीं।

# Simpler: find longest consecutive values in a 2D matrix (no adjacency)
def longestConsecutiveMatrix(matrix):
    all_vals = set()
    for row in matrix:
        for v in row:
            all_vals.add(v)
    best = 0
    for v in all_vals:
        if v - 1 not in all_vals:  # start of sequence
            length = 0
            while v in all_vals:
                v += 1
                length += 1
            best = max(best, length)
    return best

m = [[1, 5, 3], [4, 6, 2], [8, 7, 9]]
print(longestConsecutiveMatrix(m))  # 9 (1..9 all present)

साक्षात्कार सारांश: सेट + HashMap की शक्ति

इन दोनों समस्याओं में एक समान विचार है: उचित हैश संरचना का उपयोग करके O(n log n) या O(n²) वाली समस्याओं को O(n) में बदलना। सबसे लंबा क्रमागत अनुक्रम O(1) में 'क्या पूर्ववर्ती मौजूद है?' का उत्तर देने के लिए सेट का उपयोग करता है। LRU कैश नोड को तुरंत खोजने के लिए हैश मैप और क्रम को O(1) में अद्यतन करने के लिए द्वि-संबद्ध सूची का उपयोग करता है। दोनों धीमे traversal को O(1) सदस्यता-जाँच या अभिगम से बदल देते हैं।

जब साक्षात्कारकर्ता पूछता है, 'क्या आप O(n log n) से बेहतर कर सकते हैं?', तो उत्तर लगभग हमेशा होता है: 'क्रमबद्धीकरण से बचने के लिए हैश मैप या हैश सेट का उपयोग कीजिए।'

त्वरित जाँच

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

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

इस पाठ में आपने सीखा: सबसे लंबा क्रमागत अनुक्रम O(1) सदस्यता-जाँच के लिए सेट का उपयोग करके और गिनती केवल अनुक्रमों के आरंभ से शुरू करके O(n) में चलता है, LRU कैश OrderedDict (या शुरू से बनाए गए हैश मैप + द्वि-संबद्ध सूची) का उपयोग करके O(1) get और put प्राप्त करता है, और हैश मैप + लिंक्ड सूची रूप-पद्धति क्रम-संवेदी O(1) डेटा संरचनाओं के लिए पुनः उपयोग योग्य आधार-घटक है। अब हम आधार-स्थिति, भरोसे और निर्माण वाले ढाँचे के साथ पुनरावर्तन पर लौटेंगे।

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

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

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

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

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

क्या “सबसे लंबा लगातार अनुक्रम और LRU Cache” पाठ निःशुल्क है?

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

“सबसे लंबा लगातार अनुक्रम और LRU Cache” में मैं क्या सीखूँगा?

set का उपयोग करके longest-consecutive-sequence को O(n) में हल कीजिए, फिर OrderedDict से LRU cache की रूपरेखा बनाइए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ कोडिंग साक्षात्कार की तैयारी का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

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

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

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

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

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

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

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

  1. हैश फ़ंक्शन की आंतरिक कार्यप्रणाली और टकराव प्रबंधन
  2. Two-Sum और इसके अनेक रूप
  3. आवृत्ति गिनना और समूह बनाना
  4. सबसे लंबा लगातार अनुक्रम और LRU Cache
← कोडिंग साक्षात्कार की तैयारी पर वापस जाएँ