Least Common Ancestor algorithm variation - algorithm

root
/ \
A B
/ | \ / \
C D E F G
| |
H I
Given a tree and a list of types {C,D,E,F}. The summary is {A,F}
(as CDE implies A)
If the list of types was {C,D,E,F, I}. The summary is root (as cde implies a, i implies g, and gf implies b, and ab implies root).
At a high level, how would the algorithm for finding the summary work? (pseudo code only)

Pseudo Code, a simple tree traversal
String getSummary(Node node){
if(node contains element in the set)
return node name;
else
String result = "";
for(Node child : node.getChildren){
if(child contains element in the set)
result += getSummary(child);
}
if(result are all the name of its children)
return node name;
return result;

Related

Code for finding redundant edges in a undirected tree partially working

I am solving the question 684. Redundant Connection from from Leetcode with partial success (I am failing one of the testcases). The question is asked as following:
In this problem, a tree is an undirected graph that is connected and
has no cycles.
You are given a graph that started as a tree with n nodes labeled from
1 to n, with one additional edge added. The added edge has two
different vertices chosen from 1 to n, and was not an edge that
already existed. The graph is represented as an array edges of length
n where edges[i] = [ai, bi] indicates that there is an edge between
nodes ai and bi in the graph.
Return an edge that can be removed so that the resulting graph is a
tree of n nodes. If there are multiple answers, return the answer that
occurs last in the input.
I solved this using BFS which gives a time complexity of O(n^2), however I read that using union-find will give a time complexity of O(n). My try with using union-find+path compression is only partially working, and I am stuck figuring out why.
For these following data, my code is working correctly (Meaning my code returns correct edge):
However, for this testcase below, my code don't succeed in finding the correct edge (My union-find runs through all the edges and return false, meaning there was no redundant edges):
Input data: [[7,8],[2,6],[2,8],[1,4],[9,10],[1,7],[3,9],[6,9],[3,5],[3,10]]
From logs i can see that my union-find constructs the graph as following (with no detected redundant edges):
Here is my code:
class Solution {
fun findRedundantConnection(edges: Array<IntArray>): IntArray {
val parents = IntArray(edges.size + 1) // 1 to N, we dont use 0
for(i in 1..parents.size - 1)
parents[i] = i //each node is its own parent, since this is a undirected graph
val rank = IntArray(edges.size + 1){ 1 } //all nodes have rank 1 since they are their own parent
val res = IntArray(2)
for(edge in edges){
val (node1, node2) = edge
if(union(node1,node2, parents, rank, res) == false)
return intArrayOf(node1, node2)
}
return res
}
private fun find(
node: Int,
parents: IntArray
): Int{
var parent = parents[node]
while(parents[node] != parent){
parents[parent] = parents[parents[parent]] //path compression
parent = parents[parent]
}
return parent
}
//modified union which return false on redundant connection
private fun union(
node1: Int,
node2: Int,
parents: IntArray,
rank: IntArray,
res: IntArray
): Boolean{
val parent1 = find(node1, parents)
val parent2 = find(node2, parents)
if(parent1 == parent2){ //redundant connection
res[0] = node1
res[1] = node2
return false
}
if(rank[parent1] > rank[parent2]){
parents[parent2] = parent1
rank[parent1] += rank[parent2]
}else{ // rank[parent1] <= rank[parent2]
parents[parent1] = parent2
rank[parent2] += rank[parent1]
}
return true
}
}
Any suggestions on what the problem might be? I have not been able to figure it out.
var parent = parents[node]
while(parents[node] != parent){
You're never going to get into the while loop.

Morris inorder Traversal

learning morris inorder traversal from here: http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/ and Explain Morris inorder tree traversal without using stacks or recursion
I am confused. 3 questions are in the comments. Help will be welcomed. Thanks
while (current != null) {
if (current.left == null) {
visit(current);
current = current.right;
} else {
pre = current.left;
while (pre.right != null && pre.right != current) {
pre = pre.right;
} // Q1: why "pre.right != current"?
// pre is initialized as current.left and will go right until null,
// why compare pre.right with current?
if (pre.right == null) {
pre.right = current;
current = current.left;
} else { // Q2: In which case, pre.right is not null and program gets here?
pre.right = null;// Q3: why set pre.right to null?
visit(current);
current = current.right;
}
}
}
OK, if I understand correctly, this traversal essentially restructures the tree so that the left most node is at the root of the tree. So something that starts off like this:
D
/ \
B F
/ \ / \
A C E G
Will look like this:
A
\
B
/ \
A' C
\
D
/ \
B' F
/ \
E G
Where A' is A and all its subtrees.
After visiting, it will reconstruct the tree back.
To answer your questions:
Q1
Before the reconstruction, pre.right != current will never be a loop-ending condition, i.e. it will never be true. However, after the reconstruction, imagine if current held B. pre would be set to A', which is the same as A. pre.right == A'.right == A.right == current. Since this means that the A' node was already visited, it breaks the loop and reconstructs it, which leads to your next question.
Q2
Again, this case never happens prior to the reconstruction of the tree, but after the reconstruction, this is the "what to do" when you reach a node that's already been visited. Which again leads to your next question.
Q3
pre.right is set to null because it means prior to the reconstruction, the pre.right was originally null. Looking at the case post-reconstruction, node B, pre is set to A, which was a leaf node, and had no right child. Thus fixing it back:
B
/ \
A C
\
D
/ \
B' F
/ \
E G
As you can see, A' turned into just A since it's right child is no longer B but null.
Essentially, to help you understand it a bit better:
Morris traversal reconstructs the tree to have it's root as it's left most node(Also note that it now has cyclic paths)
Once it's been reconstructed, it will then visit, then fix the reconstruction back to the original form.

Obtain forest out of tree with even number of nodes

I'm stuck on a code challenge, and I want a hint.
PROBLEM: You are given a tree data structure (without cycles) and are asked to remove as many "edges" (connections) as possible, creating smaller trees with even numbers of nodes. This problem is always solvable as there are an even number of nodes and connections.
Your task is to count the removed edges.
Input:
The first line of input contains two integers N and M. N is the number of vertices and M is the number of edges. 2 <= N <= 100.
Next M lines contains two integers ui and vi which specifies an edge of the tree. (1-based index)
Output:
Print the number of edges removed.
Sample Input
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
Sample Output :
2
Explanation : On removing the edges (1, 3) and (1, 6), we can get the desired result.
I used BFS to travel through the nodes.
First, maintain an array separately to store the total number of child nodes + 1.
So, you can initially assign all the leaf nodes with value 1 in this array.
Now start from the last node and count the number of children for each node. This will work in bottom to top manner and the array that stores the number of child nodes will help in runtime to optimize the code.
Once you get the array after getting the number of children nodes for all the nodes, just counting the nodes with even number of nodes gives the answer. Note: I did not include root node in counting in final step.
This is my solution. I didn't use bfs tree, just allocated another array for holding eachnode's and their children nodes total number.
import java.util.Scanner;
import java.util.Arrays;
public class Solution {
public static void main(String[] args) {
int tree[];
int count[];
Scanner scan = new Scanner(System.in);
int N = scan.nextInt(); //points
int M = scan.nextInt();
tree = new int[N];
count = new int[N];
Arrays.fill(count, 1);
for(int i=0;i<M;i++)
{
int u1 = scan.nextInt();
int v1 = scan.nextInt();
tree[u1-1] = v1;
count[v1-1] += count[u1-1];
int root = tree[v1-1];
while(root!=0)
{
count[root-1] += count[u1-1];
root = tree[root-1];
}
}
System.out.println("");
int counter = -1;
for(int i=0;i<count.length;i++)
{
if(count[i]%2==0)
{
counter++;
}
}
System.out.println(counter);
}
}
If you observe the input, you can see that it is quite easy to count the number of nodes under each node. Consider (a b) as the edge input, in every case, a is the child and b is the immediate parent. The input always has edges represented bottom-up.
So its essentially the number of nodes which have an even count(Excluding the root node). I submitted the below code on Hackerrank and all the tests passed. I guess all the cases in the input satisfy the rule.
def find_edges(count):
root = max(count)
count_even = 0
for cnt in count:
if cnt % 2 == 0:
count_even += 1
if root % 2 == 0:
count_even -= 1
return count_even
def count_nodes(edge_list, n, m):
count = [1 for i in range(0, n)]
for i in range(m-1,-1,-1):
count[edge_list[i][1]-1] += count[edge_list[i][0]-1]
return find_edges(count)
I know that this has already been answered here lots and lots of time. I still want to know reviews on my solution here. I tried to construct the child count as the edges were coming through the input and it passed all the test cases.
namespace Hackerrank
{
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var tempArray = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x)).ToList();
int verticeNumber = tempArray[0];
int edgeNumber = tempArray[1];
Dictionary<int, int> childCount = new Dictionary<int, int>();
Dictionary<int, int> parentDict = new Dictionary<int, int>();
for (int count = 0; count < edgeNumber; count++)
{
var nodes = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x)).ToList();
var node1 = nodes[0];
var node2 = nodes[1];
if (childCount.ContainsKey(node2))
childCount[node2]++;
else childCount.Add(node2, 1);
var parent = node2;
while (parentDict.ContainsKey(parent))
{
var par = parentDict[parent];
childCount[par]++;
parent = par;
}
parentDict[node1] = node2;
}
Console.WriteLine(childCount.Count(x => x.Value % 2 == 1) - 1);
}
}
}
My first inclination is to work up from the leaf nodes because you cannot cut their edges as that would leave single-vertex subtrees.
Here's the approach that I used to successfully pass all the test cases.
Mark vertex 1 as the root
Starting at the current root vertex, consider each child. If the sum total of the child and all of its children are even, then you can cut that edge
Descend to the next vertex (child of root vertex) and let that be the new root vertex. Repeat step 2 until you have traversed all of the nodes (depth first search).
Here's the general outline of an alternative approach:
Find all of the articulation points in the graph.
Check each articulation point to see if edges can be removed there.
Remove legal edges and look for more articulation points.
Solution - Traverse all the edges, and count the number of even edges
If we remove an edge from the tree and it results in two tree with even number of vertices, let's call that edge - even edge
If we remove an edge from the tree and it results in two trees with odd
number of vertices, let's call that edge - odd edge
Here is my solution in Ruby
num_vertices, num_edges = gets.chomp.split(' ').map { |e| e.to_i }
graph = Graph.new
(1..num_vertices).to_a.each do |vertex|
graph.add_node_by_val(vertex)
end
num_edges.times do |edge|
first, second = gets.chomp.split(' ').map { |e| e.to_i }
graph.add_edge_by_val(first, second, 0, false)
end
even_edges = 0
graph.edges.each do |edge|
dup = graph.deep_dup
first_tree = nil
second_tree = nil
subject_edge = nil
dup.edges.each do |e|
if e.first.value == edge.first.value && e.second.value == edge.second.value
subject_edge = e
first_tree = e.first
second_tree = e.second
end
end
dup.remove_edge(subject_edge)
if first_tree.size.even? && second_tree.size.even?
even_edges += 1
end
end
puts even_edges
Note - Click Here to check out the code for Graph, Node and Edge classes

Finding palindromes in a linked list

This is an interview question(again).
Given a singly connected linked list, find the largest palindrome
in the list. (You may assume the length of the palindrome is even)
The first approach I made was using a stack - we traverse over the list from the start and keep pushing in the letters. Whenever we find the letter on the top of the stack is same as the next letter on the linked list, start popping(and incrementing the linked list pointer) and set a count on the number of letters that matches. After we find a mismatch, push back all the letters that you popped from the stack, and continue your pushing and popping operations. The worst case complexity of this method would be O(n2) e.g. when the linked list is just a string of the same letters.
To improve on the space and time complexity(by some constant factors), I proposed copying the linked list to an array and finding the largest sized palindrome in the array which again takes O(n2) time complexity and O(n) space complexity.
Any better approach to help me with? :(
One could come up with a O(n²)-algorithm with O(1) space complexity as follows:
Consider f→o→b→a→r→r→a→b:
Walk through the list reversing the links while visiting. Start with x=f and y=f.next:
set x.next = null
f o→b→a→r→r→a→b
^ ^
| \
x y
and check for how many links both lists (x and y) are equal.
Now continue. (tmp=y.next, y.next=x, x=y, y=tmp)
E.g. in the second step, it will yield f←o b→a→r→r→a→b, with x=o and y=b, now you check again if it's a palindrome and continue:
f←o←b a→r→r→a→b
f←o←b←a r→r→a→b
f←o←b←a←r r→a→b yay :)
etc.
If you need to restore the list again, reverse it again in O(n)
This is a well analyzed problem with O(N) time complexity.
You can reverse the original string(let's say str and str_reversed)
Then the problem is transformed to: find the longest common substring in str and str_reversed.
An O(N) approach is building a suffix tree(O(N)) with constant time lowest common ancestor retrieval.
If you copy the lists to an array, the following could be useful: Since we consider only even-length-palindromes, I assume this case. But the technique can be easily extended to work wich odd-length-palindromes.
We store not the actual length of the palindrome, but half the length, so we know how many characters to the left/right we can go.
Consider the word: aabbabbabab. We are looking for the longest palindrome.
a a b b a b b a b a b (spaces for readability)
°^° start at this position and look to the left/right as long as possible,
1 we find a palindrome of length 2 (but we store "1")
we now have a mismatch so we move the pointer one step further
a a b b a b b a b a b
^ we see that there's no palindrome at this position,
1 0 so we store "0", and move the pointer
a a b b a b b a b a b
° °^° ° we have a palindrome of length 4,
1 0 2 so we store "2"
naively, we would move the pointer one step to the right,
but we know that the two letters before pointer were *no*
palindrome. This means, the two letters after pointer are
*no* palindrome as well. Thus, we can skip this position
a a b b a b b a b a b
^ we skipped a position, since we know that there is no palindrome
1 0 2 0 0 we find no palindrome at this position, so we set "0" and move on
a a b b a b b a b a b
° ° °^° ° ° finding a palindrome of length 6,
1 0 2 0 0 3 0 0 we store "3" and "mirror" the palindrome-length-table
a a b b a b b a b a b
^ due to the fact that the previous two positions hold "0",
1 0 2 0 0 3 0 0 0 we can skip 2 pointer-positions and update the table
a a b b a b b a b a b
^ now, we are done
1 0 2 0 0 3 0 0 0 0
This means: As soon as we find a palindrome-position, we can infer some parts of the table.
Another example: aaaaaab
a a a a a a b
°^°
1
a a a a a a b
° °^° °
1 2 1 we can fill in the new "1" since we found a palindrome, thus mirroring the
palindrome-length-table
a a A A a a b (capitals are just for emphasis)
^ at this point, we already know that there *must* be a palindrome of length
1 2 1 at least 1, so we don't compare the two marked A's!, but start at the two
lower-case a's
My point is: As soon as we find palindromes, we may be able to mirror (at least a part of) the palindrome-length table and thus infer information about the new characters.
This way, we can save comparisons.
Here is a O(n^2) algorithm:
Convert the list to a doubly linked list
To have an even length palindrome you need to have two same letters next to each other.
So iterate over each each pair of neighboring letters (n-1 of them) and on each iteration, if the letters are identical, find the largest palindrome whose middle letters are these two.
I did it by using recursion in O(n) time.
I am doing this by,
suppose we have a source linked list, now copy the entire linked
list to other linked list i.e. the target linked list;
now reverse the target linked list;
now check if the data in the source linked list and target linked list are equal, if they are equal they are palindrome,
otherwise they are not palindrome.
now free the target linked list.
Code:
#include<stdio.h>
#include<malloc.h>
struct node {
int data;
struct node *link;
};
int append_source(struct node **source,int num) {
struct node *temp,*r;
temp = *source;
if(temp == NULL) {
temp = (struct node *) malloc(sizeof(struct node));
temp->data = num;
temp->link = NULL;
*source = temp;
return 0;
}
while(temp->link != NULL)
temp = temp->link;
r = (struct node *) malloc(sizeof(struct node));
r->data = num;
temp->link = r;
r->link = NULL;
return 0;
}
int display(struct node *source) {
struct node *temp = source;
while(temp != NULL) {
printf("list data = %d\n",temp->data);
temp = temp->link;
}
return 0;
}
int copy_list(struct node **source, struct node **target) {
struct node *sou = *source,*temp = *target,*r;
while(sou != NULL) {
if(temp == NULL) {
temp = (struct node *) malloc(sizeof(struct node));
temp->data = sou->data;
temp->link = NULL;
*target = temp;
}
else {
while(temp->link != NULL)
temp = temp->link;
r = (struct node *) malloc(sizeof(struct node));
r->data = sou->data;
temp->link = r;
r->link = NULL;
}
sou = sou->link;
}
return 0;
}
int reverse_list(struct node **target) {
struct node *head = *target,*next,*cursor = NULL;
while(head != NULL) {
next = head->link;
head->link = cursor;
cursor = head;
head = next;
}
(*target) = cursor;
return 0;
}
int check_pal(struct node **source, struct node **target) {
struct node *sou = *source,*tar = *target;
while( (sou) && (tar) ) {
if(sou->data != tar->data) {
printf("given linked list not a palindrome\n");
return 0;
}
sou = sou->link;
tar = tar->link;
}
printf("given string is a palindrome\n");
return 0;
}
int remove_list(struct node *target) {
struct node *temp;
while(target != NULL) {
temp = target;
target = target->link;
free(temp);
}
return 0;
}
int main()
{
struct node *source = NULL, *target = NULL;
append_source(&source,1);
append_source(&source,2);
append_source(&source,1);
display(source);
copy_list(&source, &target);
display(target);
reverse_list(&target);
printf("list reversed\n");
display(target);
check_pal(&source,&target);
remove_list(target);
return 0;
}
First find the mid point of the linked list, for this traverse through the linked list and count the number of nodes.
Let's say number of nodes is N, mid point will be N/2.
Now traverse till the mid-point node and start reversing the linked list till the end which can be done in place with O(n) complexity.
Then compare the elements from start to midpoint with elements from mid-point to last if they all are equal, string is a palindrome, break otherwise.
Time Complexity :- O(n)
Space Complexity :- O(1)

Algorithm for converting Binary tree to post-fix mathematical expression?

I have a Binary tree for a mathematical expression(infix), i want to convert directly this TREE to a postfix(Stack)
can any body suggest the algorithm?
What you’re searching for is known as post-order tree traversal:
postorder(node)
if node.left ≠ null then postorder(node.left)
if node.right ≠ null then postorder(node.right)
print node.value
Easy, each node is (Left, Right, Data).
Start with the first node. execute the algorithm for the left subtree if available and then execute the algorithm for the right subtree and then print the data.
TreeNode = ([TreeNode], Data, [TreeNode])
TreeToPostfix: [TreeNode] -> Data*
TreeToPostfix(nil) = []
TreeToPostfix((left, data, right)) ==
TreeToPostfix(left) ++ TreeToPostfix(right) ++ Data
For example:
+
/ \
* -
/ \ / \
2 3 4 5
Produces: 2 3 * 4 5 - +

Resources