पहले खोज में बैकट्रैकिंग और डेप्थ के बीच क्या अंतर है?
पहले खोज में बैकट्रैकिंग और डेप्थ के बीच क्या अंतर है?
जवाबों:
Backtracking एक अधिक सामान्य प्रयोजन एल्गोरिथ्म है।
गहराई-पहली खोज , पेड़ की संरचनाओं को खोजने से संबंधित बैकट्रैकिंग का एक विशिष्ट रूप है। विकिपीडिया से:
एक रूट पर शुरू होता है (ग्राफ मामले में रूट के रूप में कुछ नोड का चयन करते हुए) और पीछे जाने से पहले प्रत्येक शाखा के साथ जहां तक संभव हो, की खोज करता है।
यह एक पेड़ के साथ काम करने के अपने साधन के रूप में बैकट्रैकिंग का उपयोग करता है, लेकिन एक पेड़ की संरचना तक सीमित है।
बैकट्रैकिंग, हालांकि, किसी भी प्रकार की संरचना पर उपयोग किया जा सकता है जहां डोमेन के कुछ हिस्सों को समाप्त किया जा सकता है - चाहे वह तार्किक पेड़ हो या न हो। विकी उदाहरण एक शतरंज की बिसात और एक विशिष्ट समस्या का उपयोग करता है - आप एक विशिष्ट चाल को देख सकते हैं, और इसे समाप्त कर सकते हैं, फिर अगले संभव कदम पर वापस ले जा सकते हैं, इसे समाप्त कर सकते हैं, आदि।
मुझे लगता है कि दूसरे संबंधित प्रश्न का यह उत्तर अधिक अंतर्दृष्टि प्रदान करता है।
मेरे लिए, बैकट्रैकिंग और डीएफएस के बीच का अंतर यह है कि बैकट्रैकिंग एक निहित पेड़ को संभालता है और डीएफएस स्पष्ट रूप से व्यवहार करता है। यह तुच्छ लगता है, लेकिन इसका मतलब बहुत है। जब किसी समस्या के खोज स्थान का बैकट्रैकिंग द्वारा दौरा किया जाता है, तो निहित पेड़ उसके बीच में फंस जाता है और छंट जाता है। फिर भी डीएफएस के लिए, जिस पेड़ / ग्राफ से संबंधित है, वह स्पष्ट रूप से निर्मित है और अस्वीकार्य मामलों को पहले ही फेंक दिया गया है, अर्थात किसी भी खोज से पहले दूर फेंक दिया गया है।
इसलिए, बैकट्रैकिंग निहित पेड़ के लिए डीएफएस है, जबकि डीएफएस छंटाई के बिना बैकट्रैकिंग है।
बैकट्रैकिंग को आमतौर पर डीएफएस प्लस सर्च प्रुनिंग के रूप में लागू किया जाता है। आप रास्ते में आंशिक समाधानों का निर्माण करते हुए खोज अंतरिक्ष वृक्ष की गहराई का पता लगाते हैं। जानवर बल डीएफएस सभी खोज परिणामों का निर्माण कर सकते हैं, यहां तक कि वे भी, जो व्यावहारिक रूप से समझ में नहीं आते हैं। सभी समाधानों का निर्माण करने के लिए यह बहुत अक्षम हो सकता है (n! या 2 ^ n)। इसलिए वास्तव में जब आप डीएफएस करते हैं, तो आपको आंशिक समाधानों को भी प्राथमिकता देने की आवश्यकता होती है, जो वास्तविक कार्य के संदर्भ में समझ में नहीं आते हैं, और आंशिक समाधानों पर ध्यान केंद्रित करते हैं, जिससे वैध इष्टतम समाधान हो सकते हैं। यह वास्तविक बैकट्रैकिंग तकनीक है - आप आंशिक समाधानों को जल्द से जल्द छोड़ देते हैं, एक कदम पीछे करते हैं और फिर से स्थानीय इष्टतम खोजने की कोशिश करते हैं।
बीएफएस का उपयोग करके खोज अंतरिक्ष के पेड़ को पीछे करने के लिए कुछ भी नहीं रुकता है और रास्ते में पीछे की रणनीति को निष्पादित करता है, लेकिन यह अभ्यास में समझ में नहीं आता है क्योंकि आपको कतार में परत द्वारा खोज राज्य परत को संग्रहीत करने की आवश्यकता होगी, और पेड़ की चौड़ाई ऊंचाई तक तेजी से बढ़ती है। इसलिए हम बहुत जल्दी जगह बर्बाद कर देंगे। यही कारण है कि पेड़ों को आमतौर पर डीएफएस का उपयोग करके निकाला जाता है। इस स्थिति में खोज स्थिति स्टैक (कॉल स्टैक या स्पष्ट संरचना) में संग्रहीत होती है और यह पेड़ की ऊंचाई से अधिक नहीं हो सकती।
डोनाल्ड नथ के अनुसार, यह समान है। डांसिंग लिंक एल्गोरिथ्म के बारे में उनके पेपर पर यहां लिंक दिया गया है, जिसका उपयोग "गैर-पेड़" समस्याओं को एन-क्वेंस और सुडोकू सॉल्वर के रूप में हल करने के लिए किया जाता है।
आमतौर पर, एक गहराई-पहली-खोज एक वास्तविक ग्राफ / ट्री संरचना के माध्यम से पुनरावृत्ति करने का एक तरीका है, जो मूल्य की तलाश में है, जबकि बैकट्रैकिंग एक समस्या अंतरिक्ष के माध्यम से एक समाधान की तलाश में है। Backtracking एक अधिक सामान्य एल्गोरिथ्म है जो जरूरी नहीं कि पेड़ों से भी संबंधित हो।
मैं कहूंगा, DFS बैकट्रैकिंग का विशेष रूप है; बैकट्रैकिंग डीएफएस का सामान्य रूप है।
यदि हम DFS को सामान्य समस्याओं के लिए विस्तारित करते हैं, तो हम इसे बैकट्रैकिंग कह सकते हैं। यदि हम ट्री / ग्राफ संबंधित समस्याओं के लिए बैकट्रैकिंग का उपयोग करते हैं, तो हम इसे डीएफएस कह सकते हैं।
वे एल्गोरिथम पहलू में समान विचार रखते हैं।
IMHO, अधिकांश उत्तर या तो बड़े पैमाने पर अभेद्य हैं और / या किसी भी संदर्भ को सत्यापित किए बिना। तो मुझे एक संदर्भ के साथ एक बहुत स्पष्ट स्पष्टीकरण साझा करने दें ।
सबसे पहले, डीएफएस एक सामान्य ग्राफ ट्रैवर्सल (और खोज) एल्गोरिदम है। तो यह किसी भी ग्राफ (या यहां तक कि जंगल) पर लागू किया जा सकता है। ट्री एक खास तरह का ग्राफ है, इसलिए डीएफएस पेड़ के लिए भी काम करता है। संक्षेप में, यह कहना बंद कर दें कि यह केवल एक पेड़, या पसंद के लिए काम करता है।
[1] के आधार पर, बैकट्रैकिंग एक विशेष प्रकार का डीएफएस है जो मुख्य रूप से अंतरिक्ष (मेमोरी) की बचत के लिए उपयोग किया जाता है। जिस अंतर का मैं उल्लेख करने वाला हूं, वह इस तरह के ग्राफ़ एल्गोरिदम के बाद से भ्रामक लग सकता है, इसलिए हम आसन्न सूची अभ्यावेदन का उपयोग करने के लिए उपयोग किए जाते हैं और सभी तत्काल पड़ोसियों ( पेड़ के लिए यह तत्काल बच्चों के लिए ) के लिए पुनरावृत्ति पैटर्न का उपयोग करते हैं। , हम अक्सर अनदेखा करते हैं कि get_all_immediate_neighbors के खराब कार्यान्वयन से अंतर्निहित एल्गोरिथ्म के मेमोरी उपयोगों में अंतर हो सकता है।
इसके अलावा, यदि एक ग्राफ नोड में ब्रांचिंग कारक बी है, और व्यास एच ( एक पेड़ के लिए यह पेड़ की ऊंचाई है ), अगर हम एक नोड पर जाने के प्रत्येक चरण में सभी तत्काल पड़ोसियों को संग्रहीत करते हैं, तो मेमोरी आवश्यकताएं बड़ी-ओ (बीएच) होंगी । हालांकि, अगर हम एक समय में केवल एक (तत्काल) पड़ोसी लेते हैं और इसका विस्तार करते हैं, तो मेमोरी जटिलता बड़े-ओ (एच) में कम हो जाती है । जबकि पूर्व प्रकार के कार्यान्वयन को डीएफएस कहा जाता है , बाद के प्रकार को बैकट्रैकिंग कहा जाता है ।
अब आप देखते हैं, यदि आप उच्च स्तरीय भाषाओं के साथ काम कर रहे हैं, तो सबसे अधिक संभावना है कि आप वास्तव में डीएफएस की आड़ में बैकट्रैकिंग का उपयोग कर रहे हैं। इसके अलावा, एक बहुत बड़ी समस्या सेट के लिए विज़िट किए गए नोड्स का ट्रैक रखना वास्तव में स्मृति गहन हो सकता है; get_all_immediate_neighbors (या एल्गोरिदम जो अनंत लूप में शामिल हुए बिना नोड को फिर से शुरू करने में सक्षम कर सकते हैं) को सावधानीपूर्वक डिजाइन करने के लिए बुला रहे हैं ।
[१] स्टुअर्ट रसेल और पीटर नोरविग, आर्टिफिशियल इंटेलिजेंस: ए मॉडर्न एप्रोच, ३ थ एड
गहराई पहले एक पेड़ को हटाने या खोजने के लिए एक एल्गोरिथ्म है। देखें यहाँ । Backtracking एक बहुत अधिक व्यापक शब्द है जिसका उपयोग जहां भी एक समाधान उम्मीदवार का गठन किया जाता है और बाद में पूर्व राज्य को वापस करने के लिए छोड़ दिया जाता है। देखें यहाँ । गहराई पहली खोज एक शाखा को खोजने के लिए बैकट्रैकिंग का उपयोग करती है पहला (समाधान उम्मीदवार) और यदि दूसरी शाखा (तों) की सफल खोज नहीं है।
IMO, बैकट्रैकिंग के किसी भी विशिष्ट नोड पर, आप सबसे पहले उसके प्रत्येक बच्चे में शाखाओं में बँधने की कोशिश करते हैं, लेकिन इससे पहले कि आप बच्चे के किसी भी नोड में शाखा करें, आपको पिछले बच्चे की स्थिति को "समाप्त" करने की आवश्यकता है (यह कदम पीछे के बराबर है। मूल नोड तक चलना)। दूसरे शब्दों में, प्रत्येक भाई-बहन राज्य को एक-दूसरे को प्रभावित नहीं करना चाहिए।
इसके विपरीत, सामान्य डीएफएस एल्गोरिथ्म के दौरान, आपके पास आमतौर पर यह बाधा नहीं होती है, आपको अगले भाई-बहन के नोड का निर्माण करने के लिए पिछले भाई-बहन राज्य को मिटा देने की आवश्यकता नहीं है।
डीएफएस उस तरीके का वर्णन करता है जिसमें आप एक ग्राफ का पता लगाना या उसे पार करना चाहते हैं। यह चुनाव को देखते हुए यथासंभव गहरे जाने की अवधारणा पर केंद्रित है।
बैकफ़ुटिंग, जबकि आमतौर पर डीएफएस के माध्यम से कार्यान्वित किया जाता है, संभव के रूप में जल्दी से अप्रकाशित खोज उप-प्रूनिंग की अवधारणा पर अधिक ध्यान केंद्रित करता है।
एक गहराई से पहली खोज में , आप पेड़ की जड़ से शुरू करते हैं और फिर प्रत्येक शाखा के साथ दूर तक तलाश करते हैं, फिर आप प्रत्येक बाद के मूल नोड में वापस आ जाते हैं और बच्चों को पीछे छोड़ते हैं
बैकट्रैकिंग एक लक्ष्य के अंत में शुरू करने के लिए एक सामान्यीकृत शब्द है, और धीरे-धीरे पीछे की ओर बढ़ते हुए, धीरे-धीरे एक समाधान का निर्माण होता है।
आइडिया - किसी भी बिंदु से शुरू करें, जांचें कि क्या इसका वांछित समापन बिंदु है, यदि हां, तो हमने पाया कि कोई और समाधान अगले सभी संभावित पदों पर जाता है और अगर हम आगे नहीं जा सकते हैं, तो पिछली स्थिति पर वापस जाएं और उस वर्तमान को चिह्नित करने वाले अन्य विकल्पों की तलाश करें रास्ता हमें समाधान के लिए नेतृत्व नहीं करेगा।
अब बैकट्रैकिंग और डीएफएस 2 अलग-अलग नाम हैं जो 2 अलग-अलग सार डेटा प्रकारों पर एक ही विचार के लिए दिए गए हैं।
यदि विचार मैट्रिक्स डेटा संरचना पर लागू होता है, तो हम इसे बैकट्रैकिंग कहते हैं।
अगर यही विचार पेड़ या ग्राफ पर लागू होता है तो हम इसे डीएफएस कहते हैं।
यहां क्लिच यह है कि मैट्रिक्स को ग्राफ में बदला जा सकता है और ग्राफ को मैट्रिक्स में बदला जा सकता है। इसलिए, हम वास्तव में इस विचार को लागू करते हैं। यदि एक ग्राफ पर है तो हम इसे डीएफएस कहते हैं और यदि मैट्रिक्स पर है तो हम इसे बैकट्रैकिंग कहते हैं।
दोनों एल्गोरिथ्म में विचार समान है।
बैकट्रैकिंग केवल विशिष्ट समाप्ति स्थितियों के साथ पहली खोज है।
एक भूलभुलैया से गुजरने पर विचार करें जहां प्रत्येक चरण के लिए आप निर्णय लेते हैं, वह निर्णय कॉल स्टैक के लिए एक कॉल है (जो आपकी गहराई को पहले खोज का संचालन करता है) ... यदि आप अंत तक पहुंचते हैं, तो आप अपना रास्ता वापस कर सकते हैं। हालांकि, यदि आप एक समय सीमा पर पहुंचते हैं, तो आप अपने कॉल स्टैक पर एक फ़ंक्शन से बाहर लौटने पर, एक निश्चित निर्णय से बाहर लौटना चाहते हैं।
इसलिए जब मैं पीछे हटने के बारे में सोचता हूं तो मुझे चिंता होती है
मैं उलटे पांव लौटने पर अपने वीडियो में यह समझाने यहाँ ।
Backtracking कोड का विश्लेषण नीचे है। इस backtracking कोड में मैं उन सभी संयोजनों को प्राप्त करना चाहता हूं जिनके परिणामस्वरूप एक निश्चित राशि या लक्ष्य होगा। इसलिए, मेरे 3 निर्णय हैं जो मेरे कॉल स्टैक पर कॉल करते हैं, प्रत्येक निर्णय पर मैं लक्ष्य संख्या तक पहुंचने के लिए अपने पथ के हिस्से के रूप में एक संख्या चुन सकता हूं, उस नंबर को छोड़ सकता हूं, या इसे चुन सकता हूं और फिर से चुन सकता हूं। और फिर अगर मैं एक समाप्ति की स्थिति में पहुंचता हूं, तो मेरा पीछे हटने वाला कदम सिर्फ वापस लौटने के लिए है । रिटर्निंग बैकग्राउंडिंग स्टेप है क्योंकि यह कॉल स्टैक पर उस कॉल से बाहर निकल जाता है।
class Solution:
"""
Approach: Backtracking
State
-candidates
-index
-target
Decisions
-pick one --> call func changing state: index + 1, target - candidates[index], path + [candidates[index]]
-pick one again --> call func changing state: index, target - candidates[index], path + [candidates[index]]
-skip one --> call func changing state: index + 1, target, path
Base Cases (Termination Conditions)
-if target == 0 and path not in ret
append path to ret
-if target < 0:
return # backtrack
"""
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
"""
@desc find all unique combos summing to target
@args
@arg1 candidates, list of ints
@arg2 target, an int
@ret ret, list of lists
"""
if not candidates or min(candidates) > target: return []
ret = []
self.dfs(candidates, 0, target, [], ret)
return ret
def dfs(self, nums, index, target, path, ret):
if target == 0 and path not in ret:
ret.append(path)
return #backtracking
elif target < 0 or index >= len(nums):
return #backtracking
# for i in range(index, len(nums)):
# self.dfs(nums, i, target-nums[i], path+[nums[i]], ret)
pick_one = self.dfs(nums, index + 1, target - nums[index], path + [nums[index]], ret)
pick_one_again = self.dfs(nums, index, target - nums[index], path + [nums[index]], ret)
skip_one = self.dfs(nums, index + 1, target, path, ret)