נתון רצף לא ריק ס ומילון dict [] מכיל רשימה של מילים לא ריקות שהמשימה היא להחזיר הכל אפשרי דרכים לפרוץ את המשפט אִישִׁי מילים במילון.
פֶּתֶק: ניתן לעשות שימוש חוזר באותה מילה במילון מְרוּבֶּה פעמים בזמן שבירה.
דוגמאות:
דפוס עיצוב java
קֶלֶט: s = catsanddog dict = [חתולים חתולים וכלב חול]
תְפוּקָה:
חתולים וכלב
כלב חול חתול
הֶסבֵּר: המחרוזת מפוצלת ל-2 דרכים למעלה בכל דרך, כולן מילות מילון חוקיות.
קֶלֶט: s = pineapplepenapple dict = [apple pen applepen pineapple]
תְפוּקָה:
אורן תפוח עט תפוח
עט אננס תפוח
תפוח אורן תפוח
הֶסבֵּר: המחרוזת מפוצלת ל-3 דרכים למעלה בכל דרך, כולן מילות מילון חוקיות.
גִישָׁה:
לגישה הרקורסיבית יש שני מקרים בכל שלב (גודל המחרוזת יורד בכל שלב):
- לִכלוֹל המחרוזת הנוכחית בפתרון אם המחרוזת המשנה קיימת במילון באופן רקורסיבי בדוק את שאר המחרוזת החל מהאינדקס הבא.
- לְדַלֵג את מחרוזת משנה נוכחית ועבור למחרוזת המשנה האפשרית הבאה החל מאותו אינדקס.
wordBreak(sstart) = wordBreak(s end) if s[start:end] ∈ מילון
מקרה בסיסי: wordBreak(s start) = true זה מסמל שנבנה משפט חוקי עבור מחרוזת הקלט הנתונה.
שלבים ליישום הרעיון לעיל:
- המר את ה מילון לתוך א ערכת חשיש לחיפוש מהיר.
- אם ה התחל אינדקס מגיע ל מֶשֶׁך של המחרוזת(ים) זה מסמל א משפט תקף נבנה. לְהוֹסִיף המשפט הנוכחי (curr) לתוצאה.
- לולאה דרך כֹּל מחרוזת משנה החל ב הַתחָלָה ו סִיוּם בְּ- כל התפקידים האפשריים (סוף).
- עבור כל תת מחרוזת בדוק אם זה קיים במילון (dictSet).
- אם תקף :
- לְצַרֵף המילה למשפט הנוכחי (curr).
- התקשר רקורסיבית הפונקציה עבור החלק הנותר של המיתר (מהקצה ואילך).
- לאחר השיחה הרקורסיבית חוזרת לְשַׁחְזֵר המדינה של curr כדי להבטיח שהענף הבא של החקר יתחיל עם משפט נכון.
// C++ implementation to find valid word // break using Recursion #include using namespace std; // Helper function to perform backtracking void wordBreakHelper(string& s unordered_set<string>& dictSet string& curr vector<string>& res int start) { // If start reaches the end of the string // save the result if (start == s.length()) { res.push_back(curr); return; } // Try every possible substring from the current index for (int end = start + 1; end <= s.length(); ++end) { string word = s.substr(start end - start); // Check if the word exists in the dictionary if (dictSet.count(word)) { string prev = curr; // Append the word to the current sentence if (!curr.empty()) { curr += ' '; } curr += word; // Recurse for the remaining string wordBreakHelper(s dictSet curr res end); // Backtrack to restore the current sentence curr = prev; } } } // Main function to generate all possible sentence breaks vector<string> wordBreak(string s vector<string>& dict) { // Convert dictionary vector // to an unordered set unordered_set<string> dictSet(dict.begin() dict.end()); vector<string> res; string curr; wordBreakHelper(s dictSet curr res 0); return res; } int main() { string s = 'ilikesamsungmobile'; vector<string> dict = {'i' 'like' 'sam' 'sung' 'samsung' 'mobile' 'ice' 'and' 'cream' 'icecream' 'man' 'go' 'mango'}; vector<string> result = wordBreak(s dict); for (string sentence : result) { cout << sentence << endl; } return 0; }
Java // Java implementation to find valid // word break using Recursion import java.util.*; class GfG { // Helper function to perform backtracking static void wordBreakHelper(String s HashSet<String> dictSet String curr List<String> res int start) { // If start reaches the end of the string // save the result if (start == s.length()) { res.add(curr); return; } // Try every possible substring from the current index for (int end = start + 1; end <= s.length(); ++end) { String word = s.substring(start end); // Check if the word exists in the dictionary if (dictSet.contains(word)) { String prev = curr; // Append the word to the current sentence if (!curr.isEmpty()) { curr += ' '; } curr += word; // Recurse for the remaining string wordBreakHelper(s dictSet curr res end); // Backtrack to restore the current sentence curr = prev; } } } // Main function to generate all possible sentence breaks static List<String> wordBreak(String s List<String> dict) { // Convert dictionary vector to a HashSet HashSet<String> dictSet = new HashSet<>(dict); List<String> res = new ArrayList<>(); String curr = ''; wordBreakHelper(s dictSet curr res 0); return res; } public static void main(String[] args) { String s = 'ilikesamsungmobile'; List<String> dict = Arrays.asList('i' 'like' 'sam' 'sung' 'samsung' 'mobile' 'ice' 'and' 'cream' 'icecream' 'man' 'go' 'mango'); List<String> result = wordBreak(s dict); for (String sentence : result) { System.out.println(sentence); } } }
Python # Python implementation to find valid # word break using Recursion def wordBreakHelper(s dictSet curr res start): # If start reaches the end of the string # save the result if start == len(s): res.append(curr) return # Try every possible substring from the current index for end in range(start + 1 len(s) + 1): word = s[start:end] # Check if the word exists in the dictionary if word in dictSet: prev = curr # Append the word to the current sentence if curr: curr += ' ' curr += word # Recurse for the remaining string wordBreakHelper(s dictSet curr res end) # Backtrack to restore the current sentence curr = prev def wordBreak(s dict): # Convert dictionary list to a set dictSet = set(dict) res = [] curr = '' wordBreakHelper(s dictSet curr res 0) return res if __name__=='__main__': s = 'ilikesamsungmobile' dict = ['i' 'like' 'sam' 'sung' 'samsung' 'mobile' 'ice' 'and' 'cream' 'icecream' 'man' 'go' 'mango'] result = wordBreak(s dict) for sentence in result: print(sentence)
C# // C# implementation to find valid word // break using Recursion using System; using System.Collections.Generic; class GfG { // Helper function to perform backtracking static void wordBreakHelper(string s HashSet<string> dictSet ref string curr ref List<string> res int start) { // If start reaches the end of the string // save the result if (start == s.Length) { res.Add(curr); return; } // Try every possible substring from the current index for (int end = start + 1; end <= s.Length; ++end) { string word = s.Substring(start end - start); // Check if the word exists in the dictionary if (dictSet.Contains(word)) { string prev = curr; // Append the word to the current sentence if (curr.Length > 0) { curr += ' '; } curr += word; // Recurse for the remaining string wordBreakHelper(s dictSet ref curr ref res end); // Backtrack to restore the current sentence curr = prev; } } } // Main function to generate all possible sentence breaks static List<string> wordBreak(string s List<string> dict) { // Convert dictionary list to a HashSet HashSet<string> dictSet = new HashSet<string>(dict); List<string> res = new List<string>(); string curr = ''; wordBreakHelper(s dictSet ref curr ref res 0); return res; } static void Main() { string s = 'ilikesamsungmobile'; List<string> dict = new List<string> {'i' 'like' 'sam' 'sung' 'samsung' 'mobile' 'ice' 'and' 'cream' 'icecream' 'man' 'go' 'mango'}; List<string> result = wordBreak(s dict); foreach (string sentence in result) { Console.WriteLine(sentence); } } }
JavaScript // JavaScript implementation to find valid // word break using Recursion // Helper function to perform backtracking function wordBreakHelper(s dictSet curr res start) { // If start reaches the end of the string save the result if (start === s.length) { res.push(curr); return; } // Try every possible substring from the current index for (let end = start + 1; end <= s.length; ++end) { let word = s.substring(start end); // Check if the word exists in the dictionary if (dictSet.has(word)) { let prev = curr; // Append the word to the current sentence if (curr.length > 0) { curr += ' '; } curr += word; // Recurse for the remaining string wordBreakHelper(s dictSet curr res end); // Backtrack to restore the current sentence curr = prev; } } } // Main function to generate all possible sentence breaks function wordBreak(s dict) { // Convert dictionary array to a Set let dictSet = new Set(dict); let res = []; let curr = ''; wordBreakHelper(s dictSet curr res 0); return res; } let s = 'ilikesamsungmobile'; let dict = ['i' 'like' 'sam' 'sung' 'samsung' 'mobile' 'ice' 'and' 'cream' 'icecream' 'man' 'go' 'mango']; let result = wordBreak(s dict); result.forEach((sentence) => { console.log(sentence); });
תְפוּקָה
i like sam sung mobile i like samsung mobile
מורכבות זמן: O((2^n) * k) עבור מחרוזת באורך n יש 2^n מחיצות אפשריות וכל בדיקת תת מחרוזת לוקחת זמן O(k) (אורך משנה ממוצע k) המוביל ל-O((2^n) * k).
רווח עזר: O(n) עקב מחסנית הרקורסיה יכולה להגיע לעומק כמו O(n) במקרה הגרוע.