leecode 解题总结:140. Word Break II
2017-02-18 16:38
393 查看
#include <iostream> #include <stdio.h> #include <vector> #include <string> #include <unordered_map> #include <sstream> using namespace std; /* 问题: Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words. Return all such possible sentences. For example, given s = "catsanddog", dict = ["cat", "cats", "and", "sand", "dog"]. A solution is ["cats and dog", "cat sand dog"]. 分析:给定一个非空字符串,确定是否可以将字符串分割为多个字符串之后,且每个字符串都在字典中。 字符串的切分应该是一个回溯的分割,一种暴力破解就是:采用回溯,得到分割结果,遍历结果中 每一个字符串,看其是否在字典中。时间复杂度应该是O(2^n)。 关键就是回溯的过程是怎么样的,大致应该是: if(pos == len) { //遍历分割后的每个字符串是否在字典中,如果都符合,就返回true;否则返回false } for(int i = beg ; i <= len ; i++) { //判断左边是否在里面 sub = s.substr(i , i - beg + 1); if(sub 在字典中) { result.push_back(sub); backTrace(i+1 , s) //弹出之前压入的 result.pop_back(); } } 输入: 2(字符串个数) leetcode leet code 2 leecode leet code 3 abc a b c 5 catsanddog cat cats and sand dog 输出: leet code 空 a b c cats and dog, cat sand dog 又超时了,难道还是用之前的dp来做。因为dp标记了dp[i]表示s[0...i]可以被划分 那么所有的结果应该是 找到所有dp[i] = true的地方,然后 但是之前dp[i]即使为true并没有说明s[0...i]具体应该是怎么划分,即没有存储 使得dp[j] = dp[i-1] && s[i...j] in dict中的dp[i-1]应当需要保存下来,而且如果有多个,每一个都需要记录 也就是要记录dp[i-1]中的位置i-1,作为上一个字符串的结尾位置 如何存储?建立一个映射map<int , vector<int>>表明dp[j]可以通过dp[i-1]获得,如果dp[j]还可以由其他dp[k] 获得,那么就把i-1,k等这样的全部存入到j对应的数组中 那么该map中最后一个元素应该是n-1(假设字符串长度为n) n-1推得能够到达dp[n-1]的其他元素,从其他元素再得到更前面的元素,逆推,即可 存储在路径数组中,遍历每个路径数组做切分即可 关键: 1 回溯超时,回溯其实是对每个位置尝试进行分割,时间复杂度为O(2^n)。 用dp,设置一个双重循环,时间复杂度为O(n^2) 2 还是用dp来做,dp[i]表示s[0..i]是可以被划分成功的, dp[j] = dp[i-1] && s[i...j] in dict, 建立一个映射map<int , vector<int>>存储能够使得j划分成功的所有位置 对map遍历,传入当前位置index,看能否找到使得该位置分割成功的之前所有位置, 对每个位置递归查找,直到找到位置-1,存储一个完整路径,将所有路径存储后,然后切分 */ class Solution { public: //逆推获得路径数组,这个应该是要遍历的。这是递归还是迭代的?好像是递归。最后一个元素指向的位置是-1,递归截止,表明 void getPaths(unordered_map<int , vector<int> >& currentToPrevious , int index, vector< vector<int> >& paths ,vector<int>& path) { if(currentToPrevious.empty()) { return ; } //找到的最后一个位置下标是-1,表明上一个字符串的是直接从字符串的前面部分截取而来的,这里停止递归,将路径放入结果集 if(-1 == index) { paths.push_back(path); return; } //如果找不到最后一个元素,说明不能切分 if(currentToPrevious.find( index ) == currentToPrevious.end()) { return ; } vector<int> previousArr = currentToPrevious[ index ]; if(previousArr.empty()) { return ; } int size = previousArr.size(); int previousPos = -1; for(int i = 0 ; i < size ; i++) { previousPos = previousArr.at(i); //对每个位置递归查找 //将当前位置插入到位置数组中 //-1不要插入,终止,直接输出结果并检查下一个元素 if(-1 == previousPos) { paths.push_back(path); continue; } path.push_back(previousPos); getPaths(currentToPrevious , previousPos , paths , path); path.pop_back();//回溯 } } vector<string> wordBreak(string s, vector<string>& wordDict) { vector<string> result; vector<vector <string> > results; if(s.empty() || wordDict.empty()) { return result; } unordered_map<string ,bool> dict; int size = wordDict.size(); for(int i = 0 ; i < size ; i++) { dict[ wordDict.at(i) ] = true; } int len = s.length(); vector<bool> dp(len , false); string str; //dp[j]=dp[i-1] && s[i...j] in dict,其中0 <= i <=j, 0<= j < n unordered_map<int , vector<int> > currentToPrevious;//当前位置到上一个位置 for(int j = 0 ; j < len ; j++) { for(int i = 0 ; i <= j ; i++) { str = s.substr(i , j - i + 1); if(i) { if(dp.at(i-1) && dict.find(str) != dict.end()) { dp.at(j) = true; //如果已经存储了位置,则压入新的结果i-1 if( currentToPrevious.find(j) != currentToPrevious.end() ) { currentToPrevious[j].push_back(i-1); } else { vector<int> poss; poss.push_back(i-1); currentToPrevious[j] = poss; } } } else { //如果从0到当前位置可以直接获得,存储位置为-1 if(dict.find(str) != dict.end()) { dp.at(j) = true; if( currentToPrevious.find(-1) != currentToPrevious.end() ) { currentToPrevious[j].push_back(i-1); } else { vector<int> poss; poss.push_back(-1); currentToPrevious[j] = poss; } } } } } bool isOk = dp.at(len - 1); if(!isOk) { return vector<string>(); } //逆推获得路径数组 vector<vector<int> > paths; vector<int> path; path.push_back(len - 1); //插入最后一个位置 getPaths(currentToPrevious , len - 1 , paths , path); //切分字符串 result.clear(); if(paths.empty()) { return result; } size = paths.size(); for(int i = 0 ; i < size ; i++) { len = paths.at(i).size(); stringstream stream; //获得的路径是逆序的,必须逆置一下 reverse(paths.at(i).begin() , paths.at(i).end()); for(int j = 0 ; j < len ; j++) { if(j) { str = s.substr( paths.at(i).at(j-1) + 1 , paths.at(i).at(j) - paths.at(i).at(j-1) ); stream << " " << str; } else { str = s.substr(0, paths.at(i).at(j) + 1); stream << str; } } result.push_back(stream.str()); } return result; } }; void print(vector<string>& result) { if(result.empty()) { cout << "no result" << endl; return; } int size = result.size(); for(int i = 0 ; i < size; i++) { cout << result.at(i) << ","; } cout << endl; } void process() { vector<string> nums; string str; string value; int num; Solution solution; vector<string> result; while(cin >> num >> str ) { nums.clear(); for(int i = 0 ; i < num ; i++) { cin >> value; nums.push_back(value); } result = solution.wordBreak(str , nums); print(result); } } int main(int argc , char* argv[]) { process(); getchar(); return 0; } /* void backTrace(string& s , int beg , vector<string>& result, unordered_map<string , bool>& dict, vector<vector <string> >& results) { if(s.empty() || beg < 0) { return; } int len = s.length(); //如果到达末尾,说明得到结果,返回true if(beg == s.length()) { results.push_back(result); return; } string str; for(int i = beg ; i < len; i++) { str = s.substr(beg , i - beg + 1); //左半部分在字典中,才继续递归处理 if(dict.find(str) != dict.end()) { result.push_back(str); //如果回溯成功,直接返回 backTrace(s , i + 1 , result , dict ,results); result.pop_back(); } } } vector<string> wordBreak2(string s, vector<string>& wordDict) { vector<string> result; vector<vector <string> > results; if(s.empty() || wordDict.empty()) { return result; } unordered_map<string ,bool> dict; int size = wordDict.size(); for(int i = 0 ; i < size ; i++) { dict[ wordDict.at(i) ] = true; } backTrace(s , 0 , result , dict , results); //拼接结果 result.clear(); if(results.empty()) { return result; } size = results.size(); int len; for(int i = 0 ; i < size ; i++) { len = results.at(i).size(); stringstream stream; for(int j = 0 ; j < len ; j++) { if(j) { stream << " " << results.at(i).at(j); } else { stream << results.at(i).at(j); } } result.push_back(stream.str()); } return result; } */
相关文章推荐
- leecode 解题总结:126. Word Ladder II
- leecode 解题总结:117. Populating Next Right Pointers in Each Node II
- leecode 解题总结:264. Ugly Number II
- leecode 解题总结:122. Best Time to Buy and Sell Stock II
- leecode 解题总结:45. Jump Game II
- leecode 解题总结:40 Combination Sum II
- leecode 解题总结:92. Reverse Linked List II
- leecode 解题总结:142. Linked List Cycle II
- [Leetcode] 140. Word Break II 解题报告
- leecode 解题总结:132. Palindrome Partitioning II
- leecode 解题总结:113. Path Sum II
- leecode 解题总结:80. Remove Duplicates from Sorted Array II
- [leetcode] 140. Word Break II 解题报告
- leecode 解题总结:81. Search in Rotated Sorted Array II
- LeetCode — Word Break II 解题报告
- leetcode 140. Word Break II
- CODE 137: Word Break II
- Algorithms—140.Word Break II
- leetcode 140: Word Break II
- Java for LeetCode 140 Word Break II