宽度优先搜索
1、二叉树的序列化和反序列化
在序列化过程中使用数据存储后然后从前往后依次访问子节点,避免使用栈,相当于是利用数据模仿栈的功能,同时空节点也进入数组,但是在访问时需要跳过节点为空的,这样就完成了二叉树的序列化。在反序列化时,使用一个栈存储已经生成的二叉树结构,每次生成新的节点时加到队列的第一个元素上,同时记录左子节点标记,当时右子节点插入时节点从队列中弹出。
1 class Solution { 2 public: 3 string serialize(TreeNode *root) { 4 vector<TreeNode *> Q; 5 Q.push_back(root); 6 7 for (int i = 0; i < Q.size(); i++) { 8 TreeNode *node = Q[i]; 9 if (node == NULL) { 10 continue; 11 } 12 Q.push_back(node->left); 13 Q.push_back(node->right); 14 } 15 16 while (Q.size() > 0 && Q[Q.size() - 1] == NULL) { 17 Q.pop_back(); 18 } 19 20 if (Q.size() == 0) { 21 return "{}"; 22 } 23 24 stringstream ss; 25 ss << "{" << Q[0]->val; 26 for (int i = 1; i < Q.size(); i++) { 27 if (Q[i] == NULL) { 28 ss << ",#"; 29 } else { 30 ss << "," << Q[i]->val; 31 } 32 } 33 ss << "}"; 34 35 return ss.str(); 36 } 37 38 TreeNode *deserialize(string data) { 39 if (data == "{}") { 40 return NULL; 41 } 42 43 vector<string> vals = split(data.substr(1, data.size() - 2), ","); 44 TreeNode *root = new TreeNode(atoi(vals[0].c_str())); 45 queue<TreeNode *> Q; 46 Q.push(root); 47 48 bool isLeftChild= true; 49 for (int i = 1; i < vals.size(); i++) { 50 if (vals[i] != "#") { 51 TreeNode *node = new TreeNode(atoi(vals[i].c_str())); 52 if (isLeftChild) { 53 Q.front()->left = node; 54 } else { 55 Q.front()->right = node; 56 } 57 Q.push(node); 58 } 59 if (!isLeftChild) { 60 Q.pop(); 61 } 62 63 isLeftChild = !isLeftChild; 64 } 65 return root; 66 } 67 68 vector<string> split(const string &str, string delim) { 69 vector<string> results; 70 int lastIndex = 0, index; 71 while ((index = str.find(delim, lastIndex)) != string::npos) { 72 results.push_back(str.substr(lastIndex, index - lastIndex)); 73 lastIndex = index + delim.length(); 74 } 75 76 if (lastIndex != str.length()) { 77 results.push_back(str.substr(lastIndex, str.length() - lastIndex)); 78 } 79 80 return results; 81 } 82 };
2、判断图是否是树
可以先建立一个邻接矩阵然后使用邻接矩阵然后宽度优先搜索看是否可以找到同一个元素。
//bfs版本2:首先使用边的情况构建一个邻接矩阵,然后在使用临街矩阵做bfs //隐藏条件就是如果是一个树那么边的数量必然是节点数量减1 class Solution2 { public: bool validTree(int n, vector<vector<int>>& edges) { int pairs = edges.size(); if(pairs == 0 && n <= 1){ return true; } if(pairs == 0 && n > 1){ return false; } if(pairs != n-1){ return false; } int col = edges[0].size(); if(col == 0){ return true; } map<int, set<int>> graph = initGraph(n, edges); //cout << "graph init complete" << endl; int visited = 0; set<int> nodeS; queue<int> nodeQ; nodeS.insert(0); nodeQ.push(0); while(nodeQ.empty() != true){ int tmp = nodeQ.front(); nodeQ.pop(); visited++; for(auto value : graph[tmp]){ if(nodeS.find(value) != nodeS.end()){ continue; } nodeS.insert(value); nodeQ.push(value); } } return visited == n; } map<int, set<int>> initGraph(int n, vector<vector<int>>& edges){ map<int, set<int>> graphVector; for(int i = 0; i < n; i++){ graphVector[i] = set<int>(); } //cout << "run here" << graphVector.size() << endl; for(int i = 0; i < edges.size(); i++){ int u = edges[i][0]; int v = edges[i][1]; graphVector[u].insert(v); graphVector[v].insert(u); } return graphVector; } };
深度优先搜索
1.数组组合
给出一组候选数字(C)和目标数字(T),找出C中所有的组合,使组合中数字的和为T。C中每个数字在每个组合中只能使用一次。
class Solution { public: /** * @param num: Given the candidate numbers * @param target: Given the target number * @return: All the combinations that sum to target */ vector<vector<int> > combinationSum2(vector<int> &num, int target) { // write your code here int size = num.size(); if(size == 0){ return vector<vector<int> >(); } vector<vector<int> > res; vector<int> permution; sort(num.begin(), num.end()); dfsHelper(num, 0, permution, res, target); return res; } void dfsHelper(vector<int> &num, int index, vector<int> & permution, vector<vector<int> >& res, int target){ if(target == 0){ //sort(permution.begin(), permution.end()); res.push_back(permution); return; } if(target < 0){ return; } int size = num.size(); set<int> numS; for(int i = index; i < size; i++){ if(numS.find(num[i]) != numS.end()){ continue; } if(num[i] > target){ continue; } numS.insert(num[i]); permution.push_back(num[i]); dfsHelper(num, i+1, permution, res, target - num[i]); permution.pop_back(); } } };
2、数字组合||
给出一组候选数字(C)和目标数字(T),找到C中所有的组合,使找出的数字和为T。C中的数字可以无限制重复被选取。
//时间复杂度怎么计算? //计算方法:原有所有解的情况下翻倍,但是这样是穷举的方法,试探回溯的时间复杂度是 //优于穷举的,这个地推公式应该是什么公式怎么建立O(n)与O(n-1)之间的关系? //隶属于试探回溯法,深度优先搜索的一种,具体做法: //1、首先判断递归条件的出口 //2、排除不符合题目要求的情况 //3、递归查找如果当前元素存在的情况下的解,递归语句后把改元素删掉,继续进行没有该元素的情况下的解; class Solution { public: /** * @param candidates: A list of integers * @param target:An integer * @return: A list of lists of integers */ vector<vector<int> > combinationSum(vector<int> &candidates, int target) { // write your code here int size = candidates.size(); vector<vector<int> > res; if(size == 0){ return res; } vector<int> path; sort(candidates.begin(), candidates.end()); //cout << "run into here" << endl; helper(candidates, target, 0, path, res); return res; } void helper(vector<int>& candidates, int target, int index, vector<int>& path,vector<vector<int>> &res){ if(target == 0){ res.push_back(path); return; } int pre = -1; for(int i = index; i < candidates.size(); i++){ if(candidates[i] > target){ break; } if(pre != -1 && pre == candidates[i]){ continue; } path.push_back(candidates[i]); helper(candidates, target - candidates[i], i, path, res); path.pop_back(); //cout << "candidates[i]" << candidates[i] << endl; pre = candidates[i]; } } };