Update
by changing
unordered_set<unordered_set<int>, hash_X> t1 = mt(A); unordered_set<unordered_set<int>, hash_X> t2 = mt(B); unordered_set<unordered_set<int>, hash_X> i(t1.begin(), t1.end()); int res = count_if(t2.begin(), t2.end(), [&](unordered_set<int> k) {return i.find(k) != i.end();}); cout << res;
to
unordered_set<unordered_set<int>, hash_X> setsA = mt(A); unordered_set<unordered_set<int>, hash_X> setsB = mt(B); int res = count_if(setsB.begin(), setsB.end(), [&](unordered_set<int> subsetofB) {return setsA.find(subsetofB) != setsA.end();}); cout << res;
the code gets faster, because it does not need to create the set "i" anymore. This works on more test cases now, but is still too slow.
Update 2
Consider the tree:
/\ /\ /\ ...
the parsing and splitting part of my algorithm would parse the complete right subtree everytime, which leads to "O(N**2)" complexity. So there seems to be the problem!
Update 3
Using a stack one can parse the treestructure from the input string in O(N)( as mentioned here : https://stackoverflow.com/questions/7814209/parsing-text-to-make-a-tree-data-structure ). I think this will work afterwards. For reference this is my current code, and the problem resides in the else block of the function "get_sets" ( i hope )
#include <iostream> #include <list> #include <algorithm> #include <string> #include <unordered_set> #include <deque> using namespace std; struct hashX{ size_t operator()(const unordered_set<int> &x) const{ int sum = 0; for(int element: x){sum = sum+element;} return sum*sum%10007; } }; unordered_set<int> get_sets(list<string> &L, unordered_set<unordered_set<int>, hashX> &subsets){ if(L.size() == 1){ unordered_set<int> subset; int i = stoi(*L.begin()); subset.insert(i); subsets.insert(subset); return subset; } else{ L.pop_front(); L.pop_back(); list<string>::iterator it = L.begin(); if(*it == "("){ int i = 1; while(i != 0){ it++; if(*it == ")"){i = i-1;} else if(*it == "("){i=i+1;} } } it++; list<string> right; list<string>::iterator it_right = right.begin(); right.splice(it_right, L, it, L.end()); unordered_set<int> X = get_sets(right, subsets); unordered_set<int> Y = get_sets(L, subsets); for(int i: X){ Y.insert(i); } subsets.insert(Y); return Y; } } int main(){ int n; cin >> n; //input stuff string inputA, inputB; cin >> inputA; cin >> inputB; // parse "((3,(1,(5,2))),4)" into ((3(1(52)))4) list<string> A, B; for(int i = 0; i < inputA.size(); i++){ string c = ""; c += inputA[i]; if( c == "(" or c == ")" ){A.push_back(c);} else if( isdigit(inputA[i]) ){ string tmp = ""; while( isdigit(inputA[i]) ){ tmp += inputA[i]; i++; } i--; A.push_back(tmp); } } for(int i = 0; i < inputB.size(); i++){ string c = ""; c += inputB[i]; if( c == "(" or c == ")" ){B.push_back(c);} else if( isdigit(inputB[i]) ){ string tmp = ""; while( isdigit(inputB[i]) ){ tmp += inputB[i]; i++; } i--; B.push_back(tmp); } } //get the subsets. unordered_set<unordered_set<int>, hashX> setsA; unordered_set<unordered_set<int>, hashX> setsB; get_sets(A, setsA); get_sets(B, setsB); int result = count_if(setsB.begin(), setsB.end(), [&](unordered_set<int> subsetofB) {return setsA.find(subsetofB) != setsA.end();}); cout << result; }
Update 4:
Changed the parsing method to get the tree in one pass over the input string, and i like it very much. After that i recursively traverse down the tree and write down the sets of the subtrees. For some reason this is still to slow. I tried to comment enough and choose descriptive names at key places. If someone is still interested here is the code:
#include <iostream> #include <list> #include <algorithm> #include <string> #include <unordered_set> using namespace std; struct hashX{ size_t operator()(const unordered_set<int> &x) const{ int sum = 0; for(int element: x){sum = sum+element;} return hash<int>()(sum); } }; class node{ public: struct node *left,*right; int data; bool isleaf; }; void make_tree(string s, struct node **root){ //the stack will hold the node hierarchy, the last element will be the current parent node. list<node*> stack; struct node *newnode,*current,*previous, *previousprevious; int i = 0; while(i < s.size()){ // if we see ( we create a new node and push it back as the current parent onto the stack if(s[i] == '('){ newnode = new node(); newnode->data = -1; newnode->left = NULL; newnode->right= NULL; newnode->isleaf= false; stack.push_back(newnode); } // if we see a digit we parse it, create a leaf and push it onto the stack else if(isdigit(s[i])){ //parse the whole number string tmp = ""; while( isdigit(s[i]) ){ tmp += s[i]; i++; } int int_tmp = stoi(tmp); i--; //create a leaf node and push it onto the stack newnode = new node(); newnode->data = int_tmp; newnode->left = NULL; newnode->right= NULL; newnode->isleaf= true; stack.push_back(newnode); } // if we see ) the current node is finished and the right child of the previous previous node, the previous node is the left child .. see (a, (b, c)) root = ( ..... ) .. left child = a, right child = (b, c) else if(s[i] == ')'){ current = new node(); current = stack.back(); stack.pop_back(); previous = new node(); previous = stack.back(); stack.pop_back(); previousprevious = new node(); previousprevious = stack.back(); stack.pop_back(); previousprevious->right = previous; previousprevious->left = current; stack.push_back(previousprevious); } i++; } *root = stack.front(); } unordered_set<int> get_sets(node *T, unordered_set<unordered_set<int>, hashX> &subsets){ //if we encounter a leaf node we add the singleton set of its data to the subsets if(T->isleaf){ unordered_set<int> subset; subset.insert(T->data); subsets.insert(subset); return subset; } //else we join the subsets of its children, and add it to the subsets else{ node *left = T->left; node *right = T->right; unordered_set<int> x = get_sets(left, subsets); unordered_set<int> y = get_sets(right, subsets); for(int i: x){ y.insert(i); } subsets.insert(y); return y; } } int main(){ int n; cin >> n; //input stuff string inputA, inputB; cin >> inputA; cin >> inputB; //construct the trees struct node *TreeA, *TreeB; make_tree(inputA, &TreeA); make_tree(inputB, &TreeB); //get the subsets unordered_set<unordered_set<int>, hashX> setsA; unordered_set<unordered_set<int>, hashX> setsB; get_sets(TreeA, setsA); get_sets(TreeB, setsB); //compute the size of the intersection int result = count_if(setsB.begin(), setsB.end(), [&](unordered_set<int> subsetofB) {return setsA.find(subsetofB) != setsA.end();}); cout << result; }