Related
I'm trying to solve the following question:
https://leetcode.com/problems/bus-routes/
We have a list of bus routes. Each routes[i] is a bus route that the ith bus repeats forever. For example if routes[0] = [1, 5, 7], this means that the first bus (0th indexed) travels in the sequence 1→5→7→1→5→7→1→... forever.
We start at bus stop S (initially not on a bus), and we want to go to bus stop T. Travelling by buses only, what is the least number of buses we must take to reach our destination? Return -1 if it is not possible.
Example:
Input:
routes = [[1, 2, 7], [3, 6, 7]]
S = 1
T = 6
Output:
2
Explanation:
The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.
Note:
1 <= routes.length <= 500.
1 <= routes[i].length <= 500.
0 <= routes[i][j] < 10 ^ 6.
My idea is to treat each stop as a Node. Each node has a color (the bus number), and has a value (the stop number).
This problem would then be converted to a 0-1 BFS shortest path problem.
Here's my code :
class Node {
int val;
int color;
boolean visited;
int distance;
public Node(int val, int color) {
this.val = val;
this.color = color;
this.visited = false;
this.distance = 0;
}
public String toString() {
return "{ val = " + this.val + ", color = " + this.color + " ,distance = " + this.distance + "}";
}
}
class Solution {
public int numBusesToDestination(int[][] routes, int S, int T) {
if(S == T) return 0;
// create nodes
// map each values node(s)
// distance between nodes of the same bus, have 0 distance
// if you're switching buses, the distance is 1
Map<Integer, List<Node>> adjacency = new HashMap<Integer, List<Node>>();
int color = 0;
Set<Integer> colorsToStartWith = new HashSet<Integer>();
for(int[] route : routes) {
for(int i = 0; i < route.length - 1; i++) {
int source = route[i];
int dest = route[i + 1];
adjacency.putIfAbsent(source, new ArrayList<Node>());
adjacency.putIfAbsent(dest, new ArrayList<Node>());
if(source == S) colorsToStartWith.add(color);
adjacency.get(source).add(new Node(dest, color));
adjacency.get(source).add(new Node(source, color));
}
if(route[route.length - 1] == S) colorsToStartWith.add(color);
adjacency.putIfAbsent(route[route.length - 1], new ArrayList<Node>());
adjacency.get(route[route.length - 1]).add(new Node(route[0], color));
adjacency.get(route[route.length - 1]).add(new Node(route[route.length - 1], color));
color++;
}
// run bfs
int minDistance = Integer.MAX_VALUE;
Deque<Node> q = new LinkedList<Node>();
Node start = new Node(S, 0);
start.distance = 1;
q.add(start);
boolean first = true;
boolean found = false;
while(!q.isEmpty()) {
Node current = q.remove();
current.visited = true;
System.out.println(current);
for(Node neighbor : adjacency.get(current.val)) {
if(!neighbor.visited) {
neighbor.visited = true;
if(neighbor.color == current.color || current.val == neighbor.val || first) {
q.addFirst(neighbor);
neighbor.distance = current.distance;
} else {
q.addLast(neighbor);
neighbor.distance = current.distance + 1;
}
if(neighbor.val == T) {
minDistance = Math.min(minDistance, neighbor.distance);
}
}
}
first = false;
}
return minDistance == Integer.MAX_VALUE ? -1 : minDistance;
}
}
I'm not sure why this is wrong.
The following test case fails :
Routes = [
[12,16,33,40,44,47,68,69,77,78,82,86,97],
[5,8,25,28,45,46,50,52,63,66,80,81,95,97],
[4,5,6,14,30,31,34,36,37,47,48,55,56,58,73,74,76,80,88,98],
[58,59],
[54,56,78,96,98],
[7,30,35,44,60,87,97],
[3,5,57,88],
[3,9,13,15,23,24,28,38,49,51,54,59,63,65,78,81,86,92,95],
[2,7,16,20,23,46,55,57,93],
[10,11,15,31,32,48,53,54,57,66,69,75,85,98],
[24,26,30,32,51,54,58,77,81],
[7,21,39,40,49,58,84,89],
[38,50,57],
[10,57],
[11,27,28,37,55,56,58,59,81,87,97],
[0,1,8,17,19,24,25,27,36,37,39,51,68,72,76,82,84,87,89],
[10,11,14,22,26,30,48,49,62,66,79,80,81,85,89,93,96,98],
[16,18,24,32,35,37,46,63,66,69,78,80,87,96],
[3,6,13,14,16,17,29,30,42,46,58,73,77,78,81],
[15,19,32,37,52,57,58,61,69,71,73,92,93]
]
S = 6
T = 30
What is the error in my code that makes this test fail?
The example input you give should return 1, since the one-but-last route contains both the source and target bus stop (6 and 30):
[3,6,13,14,16,17,29,30,42,46,58,73,77,78,81]
I ran your code with that input, and it returns 1, so your solution is rejected for another reason, which then must be a time out.
I see several causes for why your code is not optimal:
While ideally a BFS should stop when it has found the target node, your version must continue to visit all unvisited nodes that are reachable, before it can decide what the solution is. So even if it finds the target on the same route as the source, it will continue to switch routes and so do a lot of unnecessary work, as there is no hope to find a shorter path.
This is not how it is supposed to be. You should take care to perform your search in a way that gives priority to the edges that do not increase the distance, and only when there are no more of those, pick an edge that adds 1 to the distance. If you do it like that you can stop the search as soon as you have found the target.
A Node object is created repeatedly for the same combination of bus stop and "color" (i.e. route). As a consequence, when you later set visited to true, the duplicate Node objects will still have visited equal to false and so that bus stop will be visited several times with no gain.
You should make sure to only create new Node objects when there is no existing object with such combination yet.
Edges exist between two consecutive bus stops on the same route, meaning you may need to traverse several edges on the same route before finding the one that is either the target or the right place to switch to another route.
It would be more efficient to consider a whole route a Node: routes would be considered connected (with an edge) when they share at least one bus stop. Converting routes to Sets of bus stops would make it fast and easy to identify these edges.
The reflexive edges, from and to the same bus stop, but specifying a color (route), also do not add to efficiency. The main issue you tried to solve with this set up, is to make sure that the first choice of a route is free of charge (is not considered a switch). But that concern is no longer an issue if you apply the previous bullet point.
Implementation
I chose JavaScript as implementation, but I guess it wont be hard to rewrite this in Java:
function numBusesToDestination (routes, S, T) {
if (S === T) return 0;
// Create nodes of the graph
const nodes = routes;
// Map bus stops to routes: a map keyed by stops, with each an empty Set as value
const nodesAtBusStop = new Map([].concat(...routes.map(route => route.map(stop => [stop, new Set]))));
// ... and populate those empty Sets:
for (let node of nodes) {
for (let stop of node) {
nodesAtBusStop.get(stop).add(node);
}
}
// Build adjacency list of the graph
const adjList = new Map(nodes.map(node => [node, new Set]));
for (let [stop, nodes] of nodesAtBusStop.entries()) {
for (let a of nodes) {
for (let b of nodes) {
if (a !== b) adjList.get(a).add(b);
}
}
}
const startNodes = nodesAtBusStop.get(S);
const targetNodes = nodesAtBusStop.get(T);
if (!startNodes || !targetNodes) return -1;
// BFS
let queue = [...startNodes];
let distance = 1;
let visited = new Set;
while (queue.length) {
// Create a new queue for each distance increment
let nextLevel = [];
for (let node of queue) {
if (visited.has(node)) continue;
visited.add(node);
if (targetNodes.has(node)) return distance;
nextLevel.push(...adjList.get(node));
}
queue = nextLevel;
distance++;
}
return -1;
};
// I/O handling
(document.oninput = function () {
let result = "invalid JSON";
try {
let routes = JSON.parse(document.querySelector("#inputRoutes").value);
let S = +document.querySelector("#inputStart").value;
let T = +document.querySelector("#inputTarget").value;
result = numBusesToDestination(routes, S, T);
}
catch (e) {}
document.querySelector("#output").textContent = result;
})();
#inputRoutes { width: 100% }
Routes in JSON format:
<textarea id="inputRoutes">[[1,2,7],[3,6,7]]</textarea><br>
Start: <input id="inputStart" value="1"><br>
Target: <input id="inputTarget" value="6"><br>
Distance: <span id="output"></span>
i'm trying to solve a problem from the UVA online judge site, specifically 539 where i need to use a DFS to find the longest path, i can solve it imperatively but i'd like to do it in a more functional idiomatic way using scala, the problem is that when the algorithm return from a branch the data structure is not updated for use in others branches, don't want to use vars, nor side effects, heres my code:
type Vertex=Int
type Graph = Map[Vertex,Set[Vertex]]
def DFS(start: Vertex, g: Graph): Int = {
def loop(v: Vertex, visited: List[Vertex], size: Int = 0): Int = {
val neighbours: List[Vertex] = ( g(v) filterNot visited.contains ).toList
if (neighbours == Nil) size
else {
( for (elem <- neighbours) yield loop(elem, v :: visited, size + 1) ).max }
}
loop(start, List())
}
You need to store the paths, not the Vertex in the visited Set (better performance than List in contains operation). Also you should try this starting in all the Vertex. Check this:
type Vertex = Int
type Graph = Map[Vertex, Set[Vertex]]
def DFS(g: Graph): Int = {
def loop(current: Vertex, visited: Set[(Vertex, Vertex)]): Int = {
val neighbours = g(current).filterNot(contains(visited, current, _))
if (neighbours.isEmpty)
visited.size
else {
(for {
elem <- g(current).filterNot(contains(visited, current, _))
} yield (loop(elem, add(visited, current, elem)))).max
}
}
(for {
elem <- g.keys
} yield (loop(elem, Set()))).max
}
def add(set:Set[(Vertex,Vertex)], v1:Vertex, v2:Vertex): Set[(Vertex,Vertex)] =
if(v1 < v2) add(set, v2,v1) else set.+((v1,v2))
def contains(set:Set[(Vertex,Vertex)], v1:Vertex, v2:Vertex):Boolean =
if(v1 < v2) contains(set, v2,v1) else set.contains((v1,v2))
I want to model the following puzzle with a graph.
The barman gives you three
glasses whose sizes are 1000ml, 700ml, and 400ml, respectively. The 700ml and 400ml glasses start
out full of beer, but the 1000ml glass is initially empty. You can get unlimited free beer if you win
the following game:
Game rule: You can keep pouring beer from one glass into another, stopping only when the source
glass is empty or the destination glass is full. You win if there is a sequence of pourings that leaves
exactly 200ml in the 700ml or 400 ml glass.
I was a little unsure of how to translate this problem in a graph. My thought was that the glasses would be represented by nodes in a weighted, undirected graph where edges indicate that a glass u can be poured into a glass v and the other way is the same, therefore a walk would be a sequence of pourings that would lead to the correct solution.
However, this approach of having three single nodes and undirected edges doesn't quite work for Dijkstra's algorithm or other greedy algorithms which was what I was going to use to solve the problem. Would modeling the permutations of the pourings as a graph be more suitable?
You should store whole state as vertex. I mean, value in each glass is a component of state, hence state is array of glassesCount numbers. For example, initial state is (700,400,0).
After that you should add initial state to queue and run BFS. BFS is appliable because each edge has equal weight =1. Weight is equal because weight is a number of pourings between each state which is obviously = 1 as we generate only reachable states from each state in queue.
You may also use DFS, but BFS returns the shortest sequence of pourings because BFS gives shortest path for 1-weighted graphs. If you are not interested in shortest sequence of pourings but any solution, DFS is ok. I will describe BFS because it has the same complexity with DFS and returns better (shorter) solution.
In each state of BFS you have to generate all possible new states by pouring from all pairwise combinations. Also, you should check possibility of pouring.
For 3 glasses there are 3*(3-1)=6 possible branches from each state but I implemented more generic solution allowing you to use my code for N glasses.
public class Solution{
static HashSet<State> usedStates = new HashSet<State>();
static HashMap<State,State> prev = new HashMap<State, State>();
static ArrayDeque<State> queue = new ArrayDeque<State>();
static short[] limits = new short[]{700,400,1000};
public static void main(String[] args){
State initialState = new State(new Short[]{700,400,0});
usedStates.add(initialState);
queue.add(initialState);
prev.put(initialState,null);
boolean solutionFound = false;
while(!queue.isEmpty()){
State curState = queue.poll();
if(curState.isWinning()){
printSolution(curState);
solutionFound = true;
break; //stop BFS even if queue is not empty because solution already found
}
// go to all possible states
for(int i=0;i<curState.getGlasses().length;i++)
for(int j=0;j<curState.getGlasses().length;j++) {
if (i != j) { //pouring from i-th glass to j-th glass, can't pour to itself
short glassI = curState.getGlasses()[i];
short glassJ = curState.getGlasses()[j];
short possibleToPour = (short)(limits[j]-glassJ);
short amountToPour;
if(glassI<possibleToPour) amountToPour = glassI; //pour total i-th glass
else amountToPour = possibleToPour; //pour i-th glass partially
if(glassI!=0){ //prepare new state
Short[] newGlasses = Arrays.copyOf(curState.getGlasses(), curState.getGlasses().length);
newGlasses[i] = (short)(glassI-amountToPour);
newGlasses[j] = (short)(newGlasses[j]+amountToPour);
State newState = new State(newGlasses);
if(!usedStates.contains(newState)){ // if new state not handled before mark it as used and add to queue for future handling
usedStates.add(newState);
prev.put(newState, curState);
queue.add(newState);
}
}
}
}
}
if(!solutionFound) System.out.println("Solution does not exist");
}
private static void printSolution(State curState) {
System.out.println("below is 'reversed' solution. In order to get solution from initial state read states from the end");
while(curState!=null){
System.out.println("("+curState.getGlasses()[0]+","+curState.getGlasses()[1]+","+curState.getGlasses()[2]+")");
curState = prev.get(curState);
}
}
static class State{
private Short[] glasses;
public State(Short[] glasses){
this.glasses = glasses;
}
public boolean isWinning() {
return glasses[0]==200 || glasses[1]==200;
}
public Short[] getGlasses(){
return glasses;
}
#Override
public boolean equals(Object other){
return Arrays.equals(glasses,((State)other).getGlasses());
}
#Override
public int hashCode(){
return Arrays.hashCode(glasses);
}
}
}
Output:
below is 'reversed' solution. In order to get solution from initial
state read states from the end
(700,200,200)
(500,400,200)
(500,0,600)
(100,400,600)
(100,0,1000)
(700,0,400)
(700,400,0)
Interesting fact - this problem has no solution if replace
200ml in g1 OR g2
to
200ml in g1 AND g2
.
I mean, state (200,200,700) is unreachable from (700,400,0)
If we want to model this problem with a graph, each node should represent a possible assignment of beer volume to glasses. Suppose we represent each glass with an object like this:
{ volume: <current volume>, max: <maximum volume> }
Then the starting node is a list of three such objects:
[ { volume: 0, max: 1000 }, { volume: 700, max: 700 }, { volume: 400, max: 400 } ]
An edge represents the action of pouring one glass into another. To perform such an action, we pick a source glass and a target glass, then calculate how much we can pour from the source to the target:
function pour(indexA, indexB, glasses) { // Pour from A to B.
var a = glasses[indexA],
b = glasses[indexB],
delta = Math.min(a.volume, b.max - b.volume);
a.volume -= delta;
b.volume += delta;
}
From the starting node we try pouring from each glass to every other glass. Each of these actions results in a new assignment of beer volumes. We check each one to see if we have achieved the target volume of 200. If not, we push the assignment into a queue.
To find the shortest path from the starting node to a target node, we push newly discovered nodes onto the head of the queue and pop nodes off the end of the queue. This ensures that when we reach a target node, it is no farther from the starting node than any other node in the queue.
To make it possible to reconstruct the shortest path, we store the predecessor of each node in a dictionary. We can use the same dictionary to make sure that we don't explore a node more than once.
The following is a JavaScript implementation of this approach. Click on the blue button below to run it.
function pour(indexA, indexB, glasses) { // Pour from A to B.
var a = glasses[indexA],
b = glasses[indexB],
delta = Math.min(a.volume, b.max - b.volume);
a.volume -= delta;
b.volume += delta;
}
function glassesToKey(glasses) {
return JSON.stringify(glasses);
}
function keyToGlasses(key) {
return JSON.parse(key);
}
function print(s) {
s = s || '';
document.write(s + '<br />');
}
function displayKey(key) {
var glasses = keyToGlasses(key);
parts = glasses.map(function (glass) {
return glass.volume + '/' + glass.max;
});
print('volumes: ' + parts.join(', '));
}
var startGlasses = [ { volume: 0, max: 1000 },
{ volume: 700, max: 700 },
{ volume: 400, max: 400 } ];
var startKey = glassesToKey(startGlasses);
function solve(targetVolume) {
var actions = {},
queue = [ startKey ],
tail = 0;
while (tail < queue.length) {
var key = queue[tail++]; // Pop from tail.
for (var i = 0; i < startGlasses.length; ++i) { // Pick source.
for (var j = 0; j < startGlasses.length; ++j) { // Pick target.
if (i != j) {
var glasses = keyToGlasses(key);
pour(i, j, glasses);
var nextKey = glassesToKey(glasses);
if (actions[nextKey] !== undefined) {
continue;
}
actions[nextKey] = { key: key, source: i, target: j };
for (var k = 1; k < glasses.length; ++k) {
if (glasses[k].volume === targetVolume) { // Are we done?
var path = [ actions[nextKey] ];
while (key != startKey) { // Backtrack.
var action = actions[key];
path.push(action);
key = action.key;
}
path.reverse();
path.forEach(function (action) { // Display path.
displayKey(action.key);
print('pour from glass ' + (action.source + 1) +
' to glass ' + (action.target + 1));
print();
});
displayKey(nextKey);
return;
}
queue.push(nextKey);
}
}
}
}
}
}
solve(200);
body {
font-family: monospace;
}
I had the idea of demonstrating the elegance of constraint programming after the two independent brute force solutions above were given. It doesn't actually answer the OP's question, just solves the puzzle. Admittedly, I expected it to be shorter.
par int:N = 7; % only an alcoholic would try more than 7 moves
var 1..N: n; % the sequence of states is clearly at least length 1. ie the start state
int:X = 10; % capacities
int:Y = 7;
int:Z = 4;
int:T = Y + Z;
array[0..N] of var 0..X: x; % the amount of liquid in glass X the biggest
array[0..N] of var 0..Y: y;
array[0..N] of var 0..Z: z;
constraint x[0] = 0; % initial contents
constraint y[0] = 7;
constraint z[0] = 4;
% the total amount of liquid is the same as the initial amount at all times
constraint forall(i in 0..n)(x[i] + y[i] + z[i] = T);
% we get free unlimited beer if any of these glasses contains 2dl
constraint y[n] = 2 \/ z[n] = 2;
constraint forall(i in 0..n-1)(
% d is the amount we can pour from one glass to another: 6 ways to do it
let {var int: d = min(y[i], X-x[i])} in (x[i+1] = x[i] + d /\ y[i+1] = y[i] - d) \/ % y to x
let {var int: d = min(z[i], X-x[i])} in (x[i+1] = x[i] + d /\ z[i+1] = z[i] - d) \/ % z to x
let {var int: d = min(x[i], Y-y[i])} in (y[i+1] = y[i] + d /\ x[i+1] = x[i] - d) \/ % x to y
let {var int: d = min(z[i], Y-y[i])} in (y[i+1] = y[i] + d /\ z[i+1] = z[i] - d) \/ % z to y
let {var int: d = min(y[i], Z-z[i])} in (z[i+1] = z[i] + d /\ y[i+1] = y[i] - d) \/ % y to z
let {var int: d = min(x[i], Z-z[i])} in (z[i+1] = z[i] + d /\ x[i+1] = x[i] - d) % x to z
);
solve minimize n;
output[show(n), "\n\n", show(x), "\n", show(y), "\n", show(z)];
and the output is
[0, 4, 10, 6, 6, 2, 2]
[7, 7, 1, 1, 5, 5, 7]
[4, 0, 0, 4, 0, 4, 2]
which luckily coincides with the other solutions. Feed it to the MiniZinc solver and wait...and wait. No loops, no BFS and DFS.
What is the basic algorithm for testing if a tree is symmetrical? Because it is a binary tree, I would assume that it would be a recursive definition of sorts
The formal question is below:
A binary tree is a mirror image of itself if its left and right subtrees are identical mirror images i.e., the binary tree is symmetrical.
This is best explained with a few examples.
1
/ \
2 2
TRUE
1
/ \
2 2
\
3
FALSE
1
/ \
2 2
/ \ / \
4 3 3 4
TRUE
1
/ \
2 2
/ \ / \
3 4 3 4
FALSE
1
/ \
2 2
/ \
3 3
TRUE
In a programming language of choice, define a BTree class/C struct and an associated method to check if the tree is a mirror image. For statically typed languages, you can assume that node values are all integers.
Class/structure definition
BTree {
BTree left;
BTree right;
int value;
}
Assume that the root of the tree is tracked by caller and function isMirror() is invoked on it.
Also, if defining a class, make sure to provide a no-argument constructor and getter/setter methods if data elements are not publicly accessible.
How about calling mirrorEquals(root.left, root.right) on the following function :-
boolean mirrorEquals(BTree left, BTree right) {
if (left == null || right == null) return left == null && right == null;
return left.value == right.value
&& mirrorEquals(left.left, right.right)
&& mirrorEquals(left.right, right.left);
}
Basically compare the left subtree and inverted right subtree, drawing an imaginary line of inversion across root.
Solution 1 - Recursively:
bool isMirror(BinaryTreeNode *a, BinaryTreeNode *b)
{
return (a && b) ?
(a->m_nValue==b->m_nValue
&& isMirror(a->m_pLeft,b->m_pRight)
&& isMirror(a->m_pRight,b->m_pLeft)) :
(a == b);
}
bool isMirrorItselfRecursively(BinaryTreeNode *root)
{
if (!root)
return true;
return isMirror(root->m_pLeft, root->m_pRight);
}
Solution 2 - Iteratively:
bool isMirrorItselfIteratively(BinaryTreeNode *root)
{
/// use single queue
if(!root) return true;
queue<BinaryTreeNode *> q;
q.push(root->m_pLeft);
q.push(root->m_pRight);
BinaryTreeNode *l, *r;
while(!q.empty()) {
l = q.front();
q.pop();
r = q.front();
q.pop();
if(l==NULL && r==NULL) continue;
if(l==NULL || r==NULL || l->m_nValue!=r->m_nValue) return false;
q.push(l->m_pLeft);
q.push(r->m_pRight);
q.push(l->m_pRight);
q.push(r->m_pLeft);
}
return true;
}
Recursive and Iterative solutions in Java using approaches discussed above
Recursive
public Boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return isSymmetricInternal(root.left, root.right);
}
private Boolean isSymmetricInternal(TreeNode leftNode,
TreeNode rightNode) {
boolean result = false;
// If both null then true
if (leftNode == null && rightNode == null) {
result = true;
}
if (leftNode != null && rightNode != null) {
result = (leftNode.data == rightNode.data)
&& isSymmetricInternal(leftNode.left, rightNode.right)
&& isSymmetricInternal(leftNode.right, rightNode.left);
}
return result;
}
Iterative using LinkedList as a Queue
private Boolean isSymmetricRecursive(TreeNode root) {
boolean result = false;
if (root == null) {
return= true;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root.left);
queue.offer(root.right);
while (!queue.isEmpty()) {
TreeNode left = queue.poll();
TreeNode right = queue.poll();
if (left == null && right == null) {
result = true;
}
else if (left == null ||
right == null ||
left.data != right.data) {
// It is required to set result = false here
result = false;
break;
}
else if (left != null && right != null) {
queue.offer(left.left);
queue.offer(right.right);
queue.offer(left.right);
queue.offer(right.left);
}
}
return result;
}
Test Case
#Test
public void testTree() {
TreeNode root0 = new TreeNode(1);
assertTrue(isSymmetric(root0));
assertTrue(isSymmetricRecursive(root0));
TreeNode root1 = new TreeNode(1, new TreeNode(2), new TreeNode(2));
assertTrue(isSymmetric(root1));
assertTrue(isSymmetricRecursive(root1));
TreeNode root2 = new TreeNode(1,
new TreeNode(2, null, new TreeNode(3)), new TreeNode(2));
assertFalse(isSymmetric(root2));
assertFalse(isSymmetricRecursive(root2));
TreeNode root3 = new TreeNode(1, new TreeNode(2, new TreeNode(4),
new TreeNode(3)), new TreeNode(2, new TreeNode(3),
new TreeNode(4)));
assertTrue(isTreeSymmetric(root3));
assertTrue(isSymmetricRecursive(root3));
TreeNode root4 = new TreeNode(1, new TreeNode(2, new TreeNode(3),
new TreeNode(4)), new TreeNode(2, new TreeNode(3),
new TreeNode(4)));
assertFalse(isSymmetric(root4));
assertFalse(isSymmetricRecursive(root4));
}
Tree Node class
public class TreeNode {
int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data){
this(data, null, null);
}
public TreeNode(int data, TreeNode left, TreeNode right)
{
this.data = data;
this.left = left;
this.right = right;
}
}
The recursive solution from #gvijay is very clear, and here's an iterative solution.
Inspect each row of the tree from top to bottom and see if the values are a palindrome. If they all are then, yes, it's a mirror. You'll need to implement an algorithm to visit each row and include null values for sparse trees. In pseudocode:
boolean isMirror(BTree tree) {
foreach (List<Integer> row : tree.rows() {
if (row != row.reverse()) return false;
}
return true;
}
The trick is to design the algorithm to iterate the rows of a tree with consideration that sparse trees should have null values as place holders. This Java implementation seems ok:
public static boolean isMirror(BTree root) {
List<BTree> thisRow, nextRow;
thisRow = Arrays.asList(root);
while (true) {
// Return false if this row is not a palindrome.
for (int i=0; i<thisRow.size()/2; i++) {
BTree x = thisRow.get(i);
BTree y = thisRow.get(thisRow.size()-i-1);
if ((x!=null) && (y!=null)
&& (x.value != y.value))
return false;
if (((x==null) && (y!=null))
|| (x!=null) && (y==null))
return false;
}
// Move on to the next row.
nextRow = new ArrayList<BTree>();
for (BTree tree : thisRow) {
nextRow.add((tree==null) ? null : tree.lt);
nextRow.add((tree==null) ? null : tree.rt);
}
boolean allNull = true;
for (BTree tree : nextRow) {
if (tree != null) allNull = false;
}
// If the row is all empty then we're done.
if (allNull) return true;
thisRow = nextRow;
}
}
EDIT
As was pointed out in the comments, my first version of the algorithm failed for certain inputs. I'm not going to reinvent the wheel, I'll just provide a Python answer using #gvijay correct algorithm. First, a representation for the binary tree:
class BTree(object):
def __init__(self, l, r, v):
self.left = l
self.right = r
self.value = v
def is_mirror(self):
return self._mirror_equals(self.left, self.right)
def _mirror_equals(self, left, right):
if left is None or right is None:
return left is None and right is None
return (left.value == right.value
and self._mirror_equals(left.left, right.right)
and self._mirror_equals(left.right, right.left))
I tested the above code using all the sample trees in the question and the trees which were returning incorrect results, as mentioned in the comments. Now the results are correct for all cases:
root1 = BTree(
BTree(None, None, 2),
BTree(None, None, 2),
1)
root1.is_mirror() # True
root2 = BTree(
BTree(None, BTree(None, None, 3), 2),
BTree(None, None, 2),
1)
root2.is_mirror() # False
root3 = BTree(
BTree(
BTree(None, None, 4),
BTree(None, None, 3),
2),
BTree(
BTree(None, None, 3),
BTree(None, None, 4),
2),
1)
root3.is_mirror() # True
root4 = BTree(
BTree(
BTree(None, None, 3),
BTree(None, None, 4),
2),
BTree(
BTree(None, None, 3),
BTree(None, None, 4),
2),
1)
root4.is_mirror() # False
root5 = BTree(
BTree(BTree(None, None, 3), None, 2),
BTree(None, BTree(None, None, 3), 2),
1)
root5.is_mirror() # True
root6 = BTree(BTree(None, None, 1), None, 1)
root6.is_mirror() # False
root7 = BTree(BTree(BTree(None, None, 1), None, 2), None, 1)
root7.is_mirror() # False
Here is a C++ solution per gvijay
bool isMirrorTree(BTnode* LP, BTnode* RP)
{
if (LP == NULL || RP == NULL) // if either is null check that both are NULL
{
return ( LP == NULL && RP == NULL );
}
// check that data is equal and then recurse
return LP->data == RP->data &&
isMirrorTree( LP->left, RP->right ) &&
isMirrorTree( LP->right, RP->left );
}
Below is the solution with respect to C- COde
isMirror(root)
{
Symmetric(root->left, root->right);
}
Symmetric(root1,root2)
{
if( (root1->left EX-NOR root2->right) && (root1->right EX-NOR root2->left) && (root1->value==root2->value) )
//exnor operation will return true if either both present or both not present
// a EX-NOR b =(!a && !b) || (a && b))
{
Symmetric(root1->left, root2->right);
Symmetric(root1->right, root2->left);
}
else return false;
}
If someone needs a Swift version, here's one.
Another approach would be to just invert one of the subtrees, and compare the two resulting subtrees in a straightforward manner.
func compareTrees(left: TreeNode?, right: TreeNode?) -> Bool {
var res = false
if left == nil && right == nil {return true}
if left != nil && right != nil {
res = left!.val == right!.val &&
compareTrees(left!.left, right: right!.left) &&
compareTrees(left!.right, right: right!.right)
}
return res
}
func invertTree(node: TreeNode?) {
if node == nil {return}
var tmp = node!.left
node!.left = node!.right
node!.right = tmp
invertTree(node!.left)
invertTree(node!.right)
}
// and run it as:
if root == nil {print("Y")}
invertTree(root!.right)
compareTrees(root!.left, right: root!.right) ? print("Y") : print("N")
Slightly different approach.
How about do an inorder traversal of the binary tree storing all the contents in some data structure like a string/ array.
Once traversal is complete, check if the elements in your array form a palindrome.
Not as efficient space wise (recursion takes O(log(n)), this method tales O(n)) but this will work as well.
Iterative solution using slightly different approach in python. Use queue1 to store left children in order of left to right and queue2 to store right children in order of right to left and compare for equality.
def isSymmetric(root):
if not root:
return True
if not (root.left or root.right):
return True
q1 = collections.deque([root.left])
q2 = collections.deque([root.right])
while q1 and q2:
n1 = q1.popleft()
n2 = q2.popleft()
if n1 is None and n2 is None:
continue
if (n1 is None) ^ (n2 is None):
return False
if n1.val != n2.val:
return False
q1.append(n1.left)
q1.append(n1.right)
q2.append(n2.right)
q2.append(n2.left)
if not (q1 and q2):
return True
return False
using python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def helper(root1, root2):
if not root1 and not root2: return True
if not root1 or not root2: return False
if root1.val != root2.val: return False
if helper(root1.left, root2.right): return helper(root1.right, root2.left)
return False
return helper(root, root)
Thought I'd add a solution in Python that some people might find easier to understand than other approaches. The idea is:
add +1 to value returned by left child.
add -1 to value returned by right child.
return l+r to parent
So if l+r == 0 for any node in the tree, then the sub-tree anchored at that node is symmetric. Therefore the entire tree is symmetric only if l+r == 0 at root.
def check(root):
l = check(root.left)+1 if root.left else 0
r = check(root.right)-1 if root.right else 0
return l+r
def is_symmetric(root):
return root is not None and check(root) == 0
public class SymmetricTree {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//int[] array = {1,2,2,3,4,4,3};
/*
* 1
* / \
* / \
* / \
* 2 2
* / \ / \
* / \ / \
* 3 4 4 3
*
* */
//int[] array = {1,2};
BinaryTree bt=new BinaryTree();
bt.data=1;
bt.left = new BinaryTree(2);
bt.right = new BinaryTree(2);
bt.left.right = new BinaryTree(3);
bt.right.right = new BinaryTree(3);
//bt=BinaryTree.buildATree(bt, array);
System.out.print(isSymmetric(bt));
BinaryTree.inOrderTraversal(bt);
}
public static boolean isSymmetric(BinaryTree root){
if(root==null)
return true;
return isSymmetricLR(root.left,root.right);
}
public static boolean isSymmetricLR(BinaryTree left, BinaryTree right){
if(left == null && right == null)
return true;
if(left!=null && right!=null)
return (left.data == right.data) &&
(isSymmetricLR(left.left, right.right)) &&
(isSymmetricLR(left.right, right.left));
return false;
}
}
Using Queue , Because i find Recursion a bit hard.
bool isSymmetric(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
q.push(root);
while(q.empty()==false){
TreeNode* a = q.front();
q.pop();
TreeNode* b = q.front();
q.pop();
if(a->val != b->val){
return false;
}
if(a->left == nullptr and b->right != nullptr)
return false;
if(a->left != nullptr and b->right == nullptr)
return false;
if(a->right != nullptr and b->left == nullptr)
return false;
if(a->right == nullptr and b->left != nullptr)
return false;
if(a->left != nullptr and b->right != nullptr){
q.push(a->left);
q.push(b->right);
}
if(a->right != nullptr and b->left != nullptr){
q.push(a->right);
q.push(b->left);
}`enter code here`
}
return true;
}
how about a java script solution
algorithm used
araay = ["10" , "2", "2", "#", "1", "1", "#"]
lets break this into each step
step 1 = ["10"]
step 2 = [ "2", "2" ]
step 3 = ["#", "1", "1", "#"]
check mirror for each step other than first step
lets take step 3 .
step 3 = ["#", "1", "1", "#"]
break this into 2 array from middle
step 3 1 = ["#", "1" ]
step 3 2 = ["1", "#"]
Now reverse step 3 2
step 3 2 = ["1", "#"]
now check if step 3 2 is equal to step 3 1
Do the above thing for each step
if all are mirror then binary tree is mirror
const Input = ["10" , "2", "2", "#", "1", "1", "#"];
function isEqual(a,b)
{
// if length is not equal
if(a.length!=b.length)
return false;
else
{
// comapring each element of array
for(var i=0;i<a.length;i++)
if(a[i] !== b[i]){
return false;
}
return true;
}
}
// Response
let symetric = true ;
let stepSymetric = true ;
let mirror = true ;
// length of input
const length = Input.length ;
// const length = 31 ;
// lets create binary tree from it
const totalSteps =
Math.log(length + 1)/Math.log(2) ;
// check for symetric binary tree
function checkInt(n) { return parseInt(n) === n };
symetric = checkInt(totalSteps);
//now check for mirror
let goneArrayLength = 0 ;
for (let i = 0; i < totalSteps; i++) {
const cStep = Math.pow(2,i);
const stepArray = [];
// console.log(goneArrayLength);
// now update the step array
const start = goneArrayLength ;
const end = goneArrayLength + cStep ;
for (let j = start; j < end; j++) {
stepArray.push(Input[j])
}
console.log(stepArray);
// Now we have each step lets find they are mirror image or not
// check for even length
if(stepArray.length%2 !== 0 && i !== 0){
stepSymetric = false ;
}
const partitation = stepArray.length / 2 ;
const leftArray = stepArray.slice(0,partitation);
const rightArray = stepArray.slice(partitation , partitation * 2);
// console.log("leftArray");
// console.log(leftArray);
// console.log("rightArray");
// console.log(rightArray);
function mirrorCheck (){
let check = false;
if(cStep === 1){
return true ;
}
let array1 = leftArray;
let array2 = rightArray.reverse();
// console.log("first");
// console.log(array1);
// console.log("second");
// console.log(array2);
let equal = isEqual(array1 , array2)
// console.log(equal);
check = true ;
if(!equal){
// console.log("Noooooooooooooooo")
check = false ;
}
return check;
}
let mirrorC = mirrorCheck();
if(!mirrorC){
mirror = false;
}
goneArrayLength = goneArrayLength + cStep ;
}
console.log(mirror + " " + symetric + " " + stepSymetric )
if(mirror && symetric && stepSymetric ){
console.log("Mirror Image");
}
else{
console.log("Not mirror image")
}
// console.log(isSymetric);
// console.log(totalSteps);
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def is_mirror(t1,t2):
# this is when I hit the leaf nodes
if t1 is None and t2 is None:
return True
# if node has only one child
if t1 is None or t2 is None:
return False
return t1.val==t2.val and is_mirror(t1.left,t2.right) and is_mirror(t1.right,t2.left)
return is_mirror(root.left,root.right)
I'm not very experienced (just a year at corporate), but in my opinion, this can be solved by using S=recursion
For example:
MYTREECLASS B1= new MYTREECLASS();
MYTREECLASS B2= new MYTREECLASS();
B1= OriginalTree;
B2=OriginalTRee;
Boolean CHECK(MYTREECLASS, MYTREECLASS)
{
if (B1.Node = B2.Node)
then (
CHECK(B1.Left, B2.Right);
CHECK(B1.Right,B2.Left)
)
elseIf(b1.Left==null or b2.right...blah blah ,,)
return False)
else return False,
Return true if it matches.
This is an interview question
I think of a solution.
It uses queue.
public Void BFS()
{
Queue q = new Queue();
q.Enqueue(root);
Console.WriteLine(root.Value);
while (q.count > 0)
{
Node n = q.DeQueue();
if (n.left !=null)
{
Console.Writeln(n.left);
q.EnQueue(n.left);
}
if (n.right !=null)
{
Console.Writeln(n.right);
q.EnQueue(n.right);
}
}
}
Can anything think of better solution than this, which doesn't use Queue?
Level by level traversal is known as Breadth-first traversal. Using a Queue is the proper way to do this. If you wanted to do a depth first traversal you would use a stack.
The way you have it is not quite standard though.
Here's how it should be.
public Void BFS()
{
Queue q = new Queue();
q.Enqueue(root);//You don't need to write the root here, it will be written in the loop
while (q.count > 0)
{
Node n = q.DeQueue();
Console.Writeln(n.Value); //Only write the value when you dequeue it
if (n.left !=null)
{
q.EnQueue(n.left);//enqueue the left child
}
if (n.right !=null)
{
q.EnQueue(n.right);//enque the right child
}
}
}
Edit
Here's the algorithm at work.
Say you had a tree like so:
1
/ \
2 3
/ / \
4 5 6
First, the root (1) would be enqueued. The loop is then entered.
first item in queue (1) is dequeued and printed.
1's children are enqueued from left to right, the queue now contains {2, 3}
back to start of loop
first item in queue (2) is dequeued and printed
2's children are enqueued form left to right, the queue now contains {3, 4}
back to start of loop
...
The queue will contain these values over each loop
1: {1}
2: {2, 3}
3: {3, 4}
4: {4, 5, 6}
5: {5, 6}
6: {6}
7: {}//empty, loop terminates
Output:
1
2
3
4
5
6
Since the question requires printing the tree level by level, there should be a way to determine when to print the new line character on the console. Here's my code which tries to do the same by appending NewLine node to the queue,
void PrintByLevel(Node *root)
{
Queue q;
Node *newline = new Node("\n");
Node *v;
q->enque(root);
q->enque(newline);
while(!q->empty()) {
v = q->deque();
if(v == newline) {
printf("\n");
if(!q->empty())
q->enque(newline);
}
else {
printf("%s", v->val);
if(v->Left)
q-enque(v->left);
if(v->right)
q->enque(v->right);
}
}
delete newline;
}
Let's see some Scala solutions. First, I'll define a very basic binary tree:
case class Tree[+T](value: T, left: Option[Tree[T]], right: Option[Tree[T]])
We'll use the following tree:
1
/ \
2 3
/ / \
4 5 6
You define the tree like this:
val myTree = Tree(1,
Some(Tree(2,
Some(Tree(4, None, None)),
None
)
),
Some(Tree(3,
Some(Tree(5, None, None)),
Some(Tree(6, None, None))
)
)
)
We'll define a breadthFirst function which will traverse the tree applying the desired function to each element. With this, we'll define a print function and use it like this:
def printTree(tree: Tree[Any]) =
breadthFirst(tree, (t: Tree[Any]) => println(t.value))
printTree(myTree)
Now, Scala solution, recursive, lists but no queues:
def breadthFirst[T](t: Tree[T], f: Tree[T] => Unit): Unit = {
def traverse(trees: List[Tree[T]]): Unit = trees match {
case Nil => // do nothing
case _ =>
val children = for{tree <- trees
Some(child) <- List(tree.left, tree.right)}
yield child
trees map f
traverse(children)
}
traverse(List(t))
}
Next, Scala solution, queue, no recursion:
def breadthFirst[T](t: Tree[T], f: Tree[T] => Unit): Unit = {
import scala.collection.mutable.Queue
val queue = new Queue[Option[Tree[T]]]
import queue._
enqueue(Some(t))
while(!isEmpty)
dequeue match {
case Some(tree) =>
f(tree)
enqueue(tree.left)
enqueue(tree.right)
case None =>
}
}
That recursive solution is fully functional, though I have an uneasy feeling that it can be further simplified.
The queue version is not functional, but it is highly effective. The bit about importing an object is unusual in Scala, but put to good use here.
C++:
struct node{
string key;
struct node *left, *right;
};
void printBFS(struct node *root){
std::queue<struct node *> q;
q.push(root);
while(q.size() > 0){
int levelNodes = q.size();
while(levelNodes > 0){
struct node *p = q.front();
q.pop();
cout << " " << p->key ;
if(p->left != NULL) q.push(p->left);
if(p->right != NULL) q.push(p->right);
levelNodes--;
}
cout << endl;
}
}
Input :
Balanced tree created from:
string a[] = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n"};
Output:
g
c k
a e i m
b d f h j l n
Algorithm:
Create an ArrayList of Linked List Nodes.
Do the level order traversal using queue(Breadth First Search).
For getting all the nodes at each level, before you take out a node from queue, store the size of the queue in a variable, say you call it as levelNodes.
Now while levelNodes > 0, take out the nodes and print it and add their children into the queue.
After this while loop put a line break.
P.S: I know the OP said, no queue. My answer is just to show if someone is looking for a C++ solution using queue.
public class LevelOrderTraversalQueue {
Queue<Nodes> qe = new LinkedList<Nodes>();
public void printLevelOrder(Nodes root)
{
if(root == null) return;
qe.add(root);
int count = qe.size();
while(count!=0)
{
System.out.print(qe.peek().getValue());
System.out.print(" ");
if(qe.peek().getLeft()!=null) qe.add(qe.peek().getLeft());
if(qe.peek().getRight()!=null) qe.add(qe.peek().getRight());
qe.remove(); count = count -1;
if(count == 0 )
{
System.out.println(" ");
count = qe.size();
}
}
}
}
In order to print out by level, you can store the level information with the node as a tuple to add to the queue. Then you can print a new line whenever the level is changed. Here is a Python code to do so.
from collections import deque
class BTreeNode:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def printLevel(self):
""" Breadth-first traversal, print out the data by level """
level = 0
lastPrintedLevel = 0
visit = deque([])
visit.append((self, level))
while len(visit) != 0:
item = visit.popleft()
if item[1] != lastPrintedLevel: #New line for a new level
lastPrintedLevel +=1
print
print item[0].data,
if item[0].left != None:
visit.append((item[0].left, item[1] + 1))
if item[0].right != None:
visit.append((item[0].right, item[1] + 1))
Try this one (Complete code) :
class HisTree
{
public static class HisNode
{
private int data;
private HisNode left;
private HisNode right;
public HisNode() {}
public HisNode(int _data , HisNode _left , HisNode _right)
{
data = _data;
right = _right;
left = _left;
}
public HisNode(int _data)
{
data = _data;
}
}
public static int height(HisNode root)
{
if (root == null)
{
return 0;
}
else
{
return 1 + Math.max(height(root.left), height(root.right));
}
}
public static void main(String[] args)
{
// 1
// / \
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 21
HisNode root1 = new HisNode(3 , new HisNode(6) , new HisNode(7));
HisNode root3 = new HisNode(4 , new HisNode(21) , null);
HisNode root2 = new HisNode(2 , root3 , new HisNode(5));
HisNode root = new HisNode(1 , root2 , root1);
printByLevels(root);
}
private static void printByLevels(HisNode root) {
List<HisNode> nodes = Arrays.asList(root);
printByLevels(nodes);
}
private static void printByLevels(List<HisNode> nodes)
{
if (nodes == null || (nodes != null && nodes.size() <= 0))
{
return;
}
List <HisNode> nodeList = new LinkedList<HisNode>();
for (HisNode node : nodes)
{
if (node != null)
{
System.out.print(node.data);
System.out.print(" , ");
nodeList.add(node.left);
nodeList.add(node.right);
}
}
System.out.println();
if (nodeList != null && !CheckIfNull(nodeList))
{
printByLevels(nodeList);
}
else
{
return;
}
}
private static boolean CheckIfNull(List<HisNode> list)
{
for(HisNode elem : list)
{
if (elem != null)
{
return false;
}
}
return true;
}
}
I think what you expecting is to print the nodes at each level either separated by a space or a comma and the levels be separated by a new line. This is how I would code up the algorithm. We know that when we do a breadth-first search on a graph or tree and insert the nodes in a queue, all nodes in the queue coming out will be either at the same level as the one previous or a new level which is parent level + 1 and nothing else.
So when you are at a level keep printing out the node values and as soon as you find that the level of the node increases by 1, then you insert a new line before starting to print all the nodes at that level.
This is my code which does not use much memory and only the queue is needed for everything.
Assuming the tree starts from the root.
queue = [(root, 0)] # Store the node along with its level.
prev = 0
while queue:
node, level = queue.pop(0)
if level == prev:
print(node.val, end = "")
else:
print()
print(node.val, end = "")
if node.left:
queue.append((node.left, level + 1))
if node.right:
queue.append((node.right, level + 1))
prev = level
At the end all you need is the queue for all the processing.
I tweaked the answer so that it shows the null nodes and prints it by height.
Was actually fairly decent for testing the balance of a red black tree. can
also add the color into the print line to check black height.
Queue<node> q = new Queue<node>();
int[] arr = new int[]{1,2,4,8,16,32,64,128,256};
int i =0;
int b = 0;
int keeper = 0;
public void BFS()
{
q.Enqueue(root);
while (q.Count > 0)
{
node n = q.Dequeue();
if (i == arr[b])
{
System.Diagnostics.Debug.Write("\r\n"+"("+n.id+")");
b++;
i =0 ;
}
else {
System.Diagnostics.Debug.Write("(" + n.id + ")");
}
i++;
if (n.id != -1)
{
if (n.left != null)
{
q.Enqueue(n.left);
}
else
{
node c = new node();
c.id = -1;
c.color = 'b';
q.Enqueue(c);
}
if (n.right != null)
{
q.Enqueue(n.right);
}
else
{
node c = new node();
c.id = -1;
c.color = 'b';
q.Enqueue(c);
}
}
}
i = 0;
b = 0;
System.Diagnostics.Debug.Write("\r\n");
}
Of course you don't need to use queue. This is in python.
# Function to print level order traversal of tree
def printLevelOrder(root):
h = height(root)
for i in range(1, h+1):
printGivenLevel(root, i)
# Print nodes at a given level
def printGivenLevel(root , level):
if root is None:
return
if level == 1:
print "%d" %(root.data),
elif level > 1 :
printGivenLevel(root.left , level-1)
printGivenLevel(root.right , level-1)
""" Compute the height of a tree--the number of nodes
along the longest path from the root node down to
the farthest leaf node
"""
def height(node):
if node is None:
return 0
else :
# Compute the height of each subtree
lheight = height(node.left)
rheight = height(node.right)
return max(lheight, reight)
Try with below code.
public void printLevelOrder(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> nodesToVisit = new LinkedList<>();
nodesToVisit.add(root);
int count = nodesToVisit.size();
while (count != 0) {
TreeNode node = nodesToVisit.remove();
System.out.print(" " + node.data);
if (node.left != null) {
nodesToVisit.add(node.left);
}
if (node.right != null) {
nodesToVisit.add(node.right);
}
count--;
if (count == 0) {
System.out.println("");
count = nodesToVisit.size();
}
}
}
here is my answer.
//for level order traversal
func forEachLevelOrder(_ visit : (TreeNode) -> Void) {
visit(self)
var queue = Queue<TreeNode>()
children.forEach {
queue.Enqueue($0)
}
while let node = queue.Dequeue() {
visit(node)
node.children.forEach { queue.Enqueue($0)}
}
}
children is an array here that stores the children of a node.