Solution of hackerrank Binary Tree Nodes question - sql

You are given a table, BST, containing two columns: N and P, where N represents the value of a node in Binary Tree, and P is the parent of N.
Write a query to find the node type of Binary Tree ordered by the value of the node. Output one of the following for each node:
Root: If node is root node.
Leaf: If node is leaf node.
Inner: If node is neither root nor leaf node.
Sample Input
Sample Output
1 Leaf
2 Inner
3 Leaf
5 Root
6 Leaf
8 Inner
9 Leaf
Explanation
The Binary Tree below illustrates the sample:
why below solution is not working :
select n,
CASE when P is null then 'Root'
when (select count(*) from BST where n = p)>0 then 'Inner'
else 'Leaf'
end as nodetype from BST
order by n
and below solution is working:
select n,
CASE when P is null then 'Root'
when (select count(*) from BST where b.n = p)>0 then 'Inner'
else 'Leaf'
end as nodetype from BST b
order by n

In your fist query you are comparing n with p column within the subquery which should never be true.
In second query you are comparing n column of outer query with p column of subquery which will return more than 0 if there is at least one leaf under the b.n node otherwise it will return 0.

Using a case statement is a way to go. However, to determine if a node is 'Inner' one needs to see if it is a parent to another node i.e. is its value N in the set of all P values.
SELECT N, CASE
WHEN P IS NULL THEN 'Root'
WHEN N IN (SELECT P FROM BST) THEN 'Inner'
ELSE 'Leaf' END as node_type FROM BST ORDER BY N

By using below code, you can easily solve the binary tree nodes question.In foreach statement we can check the max value and print in console
int n = Convert.ToInt32(Console.ReadLine().Trim());
string[] groupings = Convert.ToString(n, 2).Split("0");
int max = 0;
foreach(string s in groupings){
if(max < s.Length){
max = s.Length;
}
}
Console.WriteLine(max);

Related

WITH RECURSIVE Not Working Correctly - Postgres

I have two tables representing a graph. Nodes consists of an id, type and properties. Edges consist of an id, properties, type and an origin node id and destination node id. I've been working on a query that will basically take a single node and return the graph to a given depth - heavily based (basically copied) on an article here - https://www.alibabacloud.com/blog/postgresql-graph-search-practices---10-billion-scale-graph-with-millisecond-response_595039
However, whenever I run the query my results are always returned with many duplicates of the first query, as if it's not running running the recursive part - I'm not sure what I'm doing wrong here.
Here is my query.
WITH RECURSIVE search_graph(
id,
origin_id,-- point 1
origin_metatype_id,
origin_properties,
destination_id, -- point 2
destination_metatype_id,
destination_properties,
relationship_pair_id,
properties, -- edge property
depth, -- depth, starting from 1
path -- path, stored using an array
) AS (
SELECT -- ROOT node query
g.id,
g.origin_id,-- point 1
n1.metatype_id AS origin_metatype_id,
n1.properties AS origin_properties,
g.destination_id, -- point 2
n2.metatype_id AS destination_metatype_id,
n2.properties AS destination_properties,
g.relationship_pair_id,
g.properties, -- edge property
1 as depth, -- initial depth =1
ARRAY[g.id] as path -- initial path
FROM current_edges AS g
LEFT JOIN nodes n1 ON n1.id = g.origin_id
LEFT JOIN nodes n2 ON n2.id = g.destination_id
WHERE
origin_id = ? -- ROOT node =?
UNION ALL
SELECT
g.id,-- recursive clause
g.origin_id,-- point 1
n1.metatype_id AS origin_metatype_id,
n1.properties AS origin_properties,
g.destination_id, -- point 2
n2.metatype_id AS destination_metatype_id,
n2.properties AS destination_properties,
g.relationship_pair_id,
g.properties, -- edge property
sg.depth + 1 as depth, -- depth + 1
sg.path || g.id as path -- add a new point to the path
FROM current_edges AS g
LEFT JOIN nodes n1 ON n1.id = g.origin_id
LEFT JOIN nodes n2 ON n2.id = g.destination_id,
search_graph AS sg -- circular INNER JOIN
WHERE
g.origin_id = sg.destination_id -- recursive JOIN condition
AND (g.id != ALL(sg.path)) -- prevent from cycling
AND sg.depth <= 10 -- search depth =?
)
SELECT * FROM search_graph;

"NOT IN" not working as expected

I was writing a query to find the node type from the table BST ordered by the value of the node.
table, BST, had two columns N and P, where N represents the value of a node in BST, and P is the parent of N.
say, BST has following records:
BST Table
I successfully executed the query as follows:
SELECT n,CASE
WHEN p IS NULL THEN 'Root'
WHEN n IN (SELECT DISTINCT p FROM BST) THEN 'Inner'
ELSE 'Leaf'
END
FROM BST
ORDER BY n;
Result: Result as expected
But instead of using "IN", when I tried the same query using "NOT IN" as given below:
SELECT n,CASE
WHEN p IS NULL THEN 'Root'
WHEN n NOT IN (SELECT DISTINCT p FROM BST) THEN 'Leaf'
ELSE 'Inner'
END
FROM BST
ORDER BY n;
it didn't work as expected. Why so?
As #jarlh suggested, use NOT EXISTS, or when using NOT IN, be sure to exclude NULLs from your subquery like:
SELECT n,CASE
WHEN p IS NULL THEN 'Root'
WHEN n NOT IN (SELECT DISTINCT p FROM BST WHERE p IS NOT NULL) THEN 'Leaf'
ELSE 'Inner'
END
FROM BST
ORDER BY n;
If I were you, I'd just a NOT EXISTS. I used to always use NOT IN as a beginner. Later on I realized that you need to consider quite a bit of different factors that you never thought of at first. Use WHERE NOT EXISTS and you'll be happy fellow.
Cheers!

Recursive CTE...dealing with nested parent/children records

I have the following records:
My goal is to check the SUM of the children for each parent and make sure it is 1 (or 100%).
In the example above, you have a first parent:
12043
It has 2 children:
12484 & 12485
Child (now parent) 12484 has child 12486. The child here (12486) has a percentage of 0.6 (which is NOT 100%). This is NOT OK.
Child (now parent) 12485 has child 12487. The child here (12487) has a percentage of 1 (or 100%). This is OK.
I need to sum the percentages of each nested children and get that value because it doesn't sum up to 100%, then I have to display a message. I'm having a hard time coming up with a query for this. Can someone give me a hand?
This is what I tried and I'm getting the "The statement terminated. The maximum recursion 100 has been exhausted before statement completion." error message.
with cte
as (select cp.parent_payee_id,
cp.payee_id,
cp.payee_pct,
0 as level
from dbo.tp_contract_payee cp
where cp.participant_id = 12067
and cp.payee_id = cp.parent_payee_id
union all
select cp.parent_payee_id,
cp.payee_id,
cp.payee_pct,
c.level + 1 as level
from dbo.tp_contract_payee cp
inner join cte c
on cp.parent_payee_id = c.payee_id
where cp.participant_id = 12067
)
select *
from cte
I believe something like the following should work:
WITH RECURSIVE recCTE AS
(
SELECT
parent_payee_id as parent,
payee_id as child,
payee_pct
1 as depth,
parent_payee_id + '>' + payee_id as path
FROM
table
WHERE
--top most node
parent_payee_id = 12043
AND payee_id <> parent_payee_id --prevent endless recursion
UNION ALL
SELECT
table.parent_payee_id as parent,
table.payee_id as child,
table.payee_pct,
recCTE.depth + 1 as Depth,
recCTE.path + '>' + table.payee_id as path
FROM
recCTE
INNER JOIN table ON
recCTE.child = table.parent_payee_id AND
recCTE.child <> table.payee_id --again prevent records where parent is child
Where depth < 15 --prevent endless cycles
)
SELECT DISTINCT parent
FROM recCTE
GROUP BY parent
HAVING sum(payee_pct) <> 1;
This differs from yours mostly in the WHERE statements on both the Recursive Seed (query before UNION) and the recursive term (query after UNION). I believe yours is too restrictive, especially in the recursive term since you want to allow records that are children of 12067 through, but then you only allow 12067 as the parent id to pull in.
Here, though, we pull every descendant of 12043 (from your example table) and it's payee_pct. Then we analyze each parent in the final SELECT and the sum of all it's payee_pcts, which are essentially that parent's first childrens sum(payee_pct). If any of them are not a total of 1, then we display the parent in the output.
At any rate, between your query and mine, I would imagine this is pretty close to the requirements, so it should be tweaks to get you exactly where you need to be if this doesn't do the trick.

T-SQL Count child node in Binary Tree?

I made a table to store a Binary Tree like below:
- NodeID
- NodeLeft
- NodeRight
NodeLeft store the ID of the left node. And Node right store the ID of the right node.
I need to write a Procedure that if i pass a NodeID, it'll count how many child node on the left and how many child node on the right. Can separate to 2 Procedure.
Try this:
WITH CTE_Node(
NodeID,
NodeRigth,
NodeLeft,
Level,
RigthOrLeft
)
AS
(
SELECT
NodeID,
NodeRigth,
NodeLeft,
0 AS Level,
'P'
FROM Node
WHERE NodeID = 1
UNION ALL
SELECT
Node.NodeID,
Node.NodeRigth,
Node.NodeLeft,
Level + 1,
CASE WHEN CTE_Node.NodeLeft = Node.NodeID THEN 'R' ELSE 'L' END
FROM Node
INNER JOIN CTE_Node ON CTE_Node.NodeLeft = Node.NodeID
OR CTE_Node.NodeRigth = Node.NodeID
)
SELECT DISTINCT RigthOrLeft,
COUNT(NodeID) OVER(PARTITION BY RigthOrLeft)
FROM CTE_Node
Here is an SQL Fiddle.
The Level is just there to see how is it working. May you can use it later.
I found this topic.
http://www.sqlservercentral.com/Forums/Topic1152543-392-1.aspx
The table structure is different from my designed table. But it is an Binary Tree so i can use it.
And the SQL Fiddle is very helpful.

Recursive query rows to single column?

1) What are recursive queries ?
2) Are they dangerous ?
3) How can I make a recursive query to give me results from
ID Date
1 10/10/2010
1 20/10/2010
1 20/10/2010
2 11/10/2010
2 22/10/2010
to
ID Dates
1 10/10/2010,20/10/2010,20/10/2010
2 11/10/2010,22/10/2010
4) Can you explain how recursion operates inside the query? I googled but can't get how the recursion works actually. My database is DB2 ISeries V5R4.
Recursive query is a SQL query that can do a recursive computation. In other words, it can use the results of itself to continue query. Here is an abstract description:
1/ ancestor (x, y) = parent (x, y)
2/ ancestor (x, y) = parent (x, z) && ancestor (Z, Y).
It can be understood in a brief way that you to list all ancestor of Z, you list all of its parents and then all parents of those parents...
For example, if you have a table of Family with 2 columns Parent and Child like this:
pkey char 1 not null primary key
ckey char 1 not null primary key
('A','B')
('A','C')
('A','D')
('C','E')
('D','A')
('D','E')
('D','F')
('F','G')
The left handside is parent and the right hand side is children. Now you want to find all descedants of A then here is some code:
with parent_ctl (ckey) as
(
select ckey
from parents
where pkey='A'
UNION ALL
select c.ckey
from parents C, parent_ctl P
where P.ckey = C.Pkey
)
select ckey from parent_ctl;