I have written a code for finding level in Binary Tree having max sum of elements. I have a few Questions.
Is it a good design ? - I have used 2 queues but the total num of elements both queues store will be less than n. SO I think it should be Ok.
Can there be a better design?
public class MaxSumLevel {
public static int findLevel(BinaryTreeNode root) {
Queue mainQ = new Queue();
Queue tempQ = new Queue();
int maxlevel = 0;
int maxVal = 0;
int tempSum = 0;
int tempLevel = 0;
if (root != null) {
mainQ.enqueue(root);
maxlevel = 1;
tempLevel = 1;
maxVal = root.getData();
}
while ( !mainQ.isEmpty()) {
BinaryTreeNode head = (BinaryTreeNode) mainQ.dequeue();
BinaryTreeNode left = head.getLeft();
BinaryTreeNode right = head.getRight();
if (left != null) {
tempQ.enqueue(left);
tempSum = tempSum + left.getData();
}
if (right != null) {
tempQ.enqueue(right);
tempSum = tempSum + right.getData();
}
if (mainQ.isEmpty()) {
mainQ = tempQ;
tempQ = new Queue();
tempLevel ++;
if (tempSum > maxVal) {
maxVal = tempSum;
maxlevel = tempLevel;
tempSum = 0;
}
}
}
return maxlevel;
}
}
I like recursion (note, untested code):
public static int maxLevel(BinaryTreeNode tree) {
ArrayList<Integer> levels = new ArrayList<Integer>();
findLevels(tree, 0, levels);
// now just return the index in levels with the maximal value.
// bearing in mind that levels could be empty.
}
private static void findLevels(BinaryTreeNode tree, int level,
ArrayList<Integer> levels) {
if (tree == null) {
return;
}
if (levels.length <= level) {
levels.add(0);
}
levels.set(level, levels.get(level) + tree.getData());
findLevels(tree.getLeft(), level+1, levels);
findLevels(tree.getRight(), level+1, levels);
}
If I was feeling really mean to the garbage collector, I'd make findLevels return a list of (level, value) pairs and sum over those. That makes a lot more sense in co-routiney sort of languages, though, it'd be weird in java.
Obviously you can take the strategy in the recursive function and do it with an explicit stack of nodes to be processed. The key difference between my way and yours is that mine takes memory proportional to the height of the tree; yours takes memory proportional to its width.
Looking at your code, it seems pretty reasonable for the approach. I'd rename tempLevel to currentLevel, and I'd be inclined to pull the inner loop out into a function sumLevel that takes a queue and returns an int and a queue (except actually the queue would be an argument, because you can only return one value, grrr). But it seems okay as is.
It depends on how many nodes your trees have and how deep they are. Since you're performing breadth first search, your queues will take O(n) memory space, which is OK for most applications.
The following solution has O(l) space complexity and and O(n) time complexity (l is the depth of a tree and n number of its vertices):
public List<Integer> levelsSum(BinaryTreeNode tree) {
List<Integer> sums = new ArrayList<Integer>()
levelsSum(tree, sums, 0);
return sums;
}
protected void levelsSum(BinaryTreeNode tree, List<Integer> levelSums, int level) {
if (tree == null)
return;
// add new element into the list if needed
if (level.size() <= level)
levelSums.add(Integer.valueOf(0));
// add this node's value to the appropriate level
levelSums.set(level, levelSums.get(level) + tree.getData());
// process subtrees
levelSum(tree.getLeft(), levelSums, level + 1);
levelSum(tree.getRight(), levelSums, level + 1);
}
Now just call levelsSum on a tree and scan the returned list to find the maximum value.
Are You sure that elements will all be non-negative?
I would make it callable like new MaxSumLevel(root).getLevel(). Otherwise, what will You when You have to sometimes return maxSum ?
I would structure this as 2 nested loops:
while(!mainQ.isEmpty()){
while(!mainQ.isEmpty()){
BinaryTreeNode head = (BinaryTreeNode) mainQ.dequeue();
BinaryTreeNode left = head.getLeft();
BinaryTreeNode right = head.getRight();
if (left != null) {
tempQ.enqueue(left);
tempSum = tempSum + left.getData();
}
if (right != null) {
tempQ.enqueue(right);
tempSum = tempSum + right.getData();
}
}
mainQ = tempQ;
tempQ = new Queue();
tempLevel ++;
if (tempSum > maxVal) {
maxVal = tempSum;
maxlevel = tempLevel;
tempSum = 0;
}
}
This recursive approach works for me:
public int findMaxSumRootLeaf(TreeNode node,int currSum) {
if(node == null)
return 0;
return Math.max(findMaxSumRootLeaf(node.leftChild,currSum)+node.data, findMaxSumRootLeaf(node.rightChild,currSum)+node.data);
}
You can represent end of a level using null in the queue and calculating the maximum sum for each level.
public int maxLevelSum(BinaryTreeNode root) {
if (root == null) //if empty tree
return 0;
else {
int current_sum = 0;
int max_sum = 0;
Queue<BinaryTreeNode> queue = new LinkedList<BinaryTreeNode>(); //initialize a queue
queue.offer(root); //add root in queue
queue.offer(null); // null in queue represent end of a level
while (!queue.isEmpty()) {
BinaryTreeNode temp = queue.poll();
if (temp != null) {
if (temp.getLeft() != null) //if left is not null
queue.offer(temp.getLeft());
if (temp.getRight() != null)
queue.offer(temp.getRight()); //if right is not null
current_sum = current_sum + temp.getData(); //add to level current level sum
} else { // we reached end of a level
if (current_sum > max_sum) //check if cuurent level sum is greater than max
max_sum = current_sum;
current_sum = 0; //make current_sum=0 for new level
if (!queue.isEmpty())
queue.offer(null); //completion of a level
}
}
return max_sum; //return the max sum
}
}
Related
My end goal is to do a findKthElement function and the only way I can think of is to perform iterative inorder traversal so that I can keep a counter, which obviously doesn't work if its recursive. I have tried my best at an implementation similar to a BST but its not working, just printing the same thing infinately. Here is my attempt:
public void findKth() {
Stack<BTreeNode> s = new Stack<>();
BTreeNode current = this.root;
while(current != null || !s.isEmpty()) {
int i;
for(i = 0; i < current.numNodes; i++) {
if(!current.isLeaf) {
s.push(current);
current = current.children[i];
}
}
current = s.pop();
for(int j = 0; j < current.numNodes; j++) {
System.out.println(current.keys[j].getName());
}
}
}
keep a counter, which obviously doesn't work if its recursive
There is no problem keeping a counter in a recursive solution. You just need to make sure it's a mutable reference. For example:
public class Counter {
private int count;
public boolean complete() { return count == 0; }
public void decrement() { count--; }
}
Optional<Node> findKthChild(Node node, Counter counter) {
if (counter.isLeaf()) {
if (counter.complete())
return Optional.of(node);
counter.decrement();
} else {
for (Node child: getChildren()) {
Optional<Node> kthChild = findKthChild(child, counter);
if (kthChild.isPresent())
return kthChild;
}
}
return Optional.empty();
}
If you're familiar with streams the internal for loop could be:
return getChildren().stream()
.map(ch -> findKthChild(ch, counter))
.filter(Optional::isPresent)
.findFirst().orElse(Optional.empty());
This reeks of home work. One should try to solve it by tracing the needed steps manually, with pen and paper.
I am not claiming that the code below is correct, or good.
It is to indicate that an in-order traversal, depth first, needs to come back a some nodes ith sub-branch to continue with the next child.
For that I use the new record class as stack element, a class consisting of just BTreeNode node and int index.
public String findKth(int k) {
record NodePos(BTreeNode node, int index) {};
Stack<NodePos> stack = new Stack<>();
stack.push(new NodePos(this.root, -1);
while (!stack.isEmpty()) {
NodePos pos = stack.pop();
pos = new NodePos(pos.node, pos.index + 1);
if (pos.index >= pos.node.numNodes) { // Past end of child nodes.
continue;
}
// Sub-branch:
if (!pos.node.isLeaf) {
stack.push(new NodePos(pos.node.children[pos.index], -1);
continue;
}
// Key:
if (pos.index + 1 >= pos.node.numNodes) { // Past end of child keys.
continue;
}
System.console().printf("%d. %s%n", k, pos.node.keys[pos.index]);
if (k <= 0) {
return pos.node.keys[pos.index];
}
--k;
stack.push(pos);
}
}
There are numNodes sub-branches (node.children)and numNodes - 1 keys in a node (node.keys).
When you are at the i th sub-branch, you may first continue with the subtree, and when not sufficient (decreasing k still greater 0), then continue with the i-1 th key.
As you see, when not manually executing the code, it is hard to read it. For that it invaluable advice to work out these things yourself.
A recursive solution is easier by the way.
Okay, a working solution
My answer above was intended to think about, certainly not correct,
as the OP did not show having seriously thought about the algorithm,
given the OPs code. But there is effort evidently.
Hence a readable recursive solution. Still in a form which cannot
be given back as ones own home work.
static class BTreeNode {
int numNodes;
boolean isLeaf;
BTreeNode[] children;
int[] keys;
BTreeNode(int... keys) {
numNodes = keys.length + 1;
this.keys = keys.clone();
isLeaf = true;
}
public void addChildren(BTreeNode... children) {
assert children.length == numNodes;
this.children = children.clone();
isLeaf = false;
}
}
public static OptionalInt findKth(BTreeNode node, AtomicInteger k) {
if (node == null || k.get() < 0) {
return OptionalInt.empty();
}
for (int i = 0; i < node.numNodes; ++i) {
if (!node.isLeaf) {
OptionalInt result = findKth(node.children[i], k);
if (result.isPresent()) {
return result;
}
}
if (i + 1 < node.numNodes) {
int j = k.getAndDecrement();
System.out.printf("%d. %s%n", j, node.keys[i]);
if (j <= 0) {
return OptionalInt.of(node.keys[i]);
}
}
}
return OptionalInt.empty();
}
public static void main(String[] args) {
//
// (4 8 12)
// (1 2 3) (5 6 7) (9 10 11) (13 14 15)
BTreeNode n1to3 = new BTreeNode(1, 2, 3);
BTreeNode n5to7 = new BTreeNode(5, 6, 7);
BTreeNode n9to11 = new BTreeNode(9, 10, 11);
BTreeNode n13to15 = new BTreeNode(13, 14, 15);
BTreeNode root = new BTreeNode(4, 8, 12);
root.addChildren(n1to3, n5to7, n9to11, n13to15);
OptionalInt key5 = findKth(root, new AtomicInteger(5));
System.out.println("The result is " + key5.orElse(-1));
}
One walks in-order through the B-tree decrementing the asked k till it reaches 0. The in-order walk with numNodes subtree branches and numNodes - 1 keys requires a for+if.
The AtomicInteger is used to have a counter, a result from findKth otherwise one would need an input parameter k, and a new value for k on return. That can be done.
Optimisation: One could skip visiting a subtree, if one knew the number of elements in an entire subtree. For leaf nodes that would be numNodes.
I am trying to find the average of each level in a binary tree. I am doing BFS. I am trying to do it using a null node. Whenever I find a dummy node, that means I am at the last node at that level. The problem I am facing is that I am not able to add average of the last level in a tree using this. Can Someone Help me?
Consider example [3,9,20,15,7]
I am getting the output as [3.00000,14.50000]. Not getting the average of the last level that is 15 and 7
Here's my code
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> list = new ArrayList<Double>();
double sum = 0.0;
Queue<TreeNode> q = new LinkedList<TreeNode>();
TreeNode temp = new TreeNode(0);
q.offer(root);
q.offer(temp);
int count = 0;
while(!q.isEmpty()){
root = q.poll();
sum += root.val;
if(root != temp)
{
count++;
if(root.left != null){
q.offer(root.left);
}
if(root.right != null){
q.offer(root.right);
}
}
else
{
if(!q.isEmpty()){
list.add(sum / count);
sum = 0;
count = 0;
q.add(temp);
}
}
}
return list;
}
}
Take a look at this code, which executes whenever you find the marker for the end of the current level:
if(!q.isEmpty()){
list.add(sum / count);
sum = 0;
count = 0;
q.add(temp);
}
This if statement seems to be designed to check whether you've finished the last row in the tree, which you could detect by noting that there are no more entries in the queue that would correspond to the next level. In that case, you're correct that you don't want to add the dummy node back into the queue (that would cause an infinite loop), but notice that you're also not computing the average in the row you just finished.
To fix this, you'll want to compute the average of the last row independently of reseeding the queue, like this:
if(!q.isEmpty()){
q.add(temp);
}
list.add(sum / count);
sum = 0;
count = 0;
There's a new edge case to watch out for, and that's what happens if the tree is totally empty. I'll let you figure out how to proceed from here. Good luck!
I would use recursive deep scan of the tree. On each node I would push the value into a map with a pair .
I DID NOT test that code but it should be along the lines.
void scan(int level, TreeNode n, Map<Integer, List<Integer> m) {
List l = m.get(level); if (l==null) {
l = new ArrayList();
m.put(level, l);
}
l.add(n.val);
int nextLevel = level + 1;
if (n.left != null) scan(nextLevel, n.left, m);
if (n.right != null) scan(nextLevel, n.right, m);
}
Once the scan is done I can calculate the average for each level.
for (int lvl in m.keyset()) {
List l = m.get(lvl);
// MathUtils.avg() - it is obvious what it should be
double avg = MathUtils.avg(l);
// you code here
}
I want to reduce the complexity of this program and find count of elements greater than current/picked element in first loop (array[])and store the count in solved array(solved[]) and loop through the end of the array[]. I have approached the problem using a general array based approach which turned out to have greater time complexity when 2nd loop is huge.
But If someone can suggest a better collection here in java that can reduce the complexity of this code that would also be highly appreciated.
for (int i = 0; i < input; i++) {
if (i < input - 1) {
count=0;
for (int j = i+1; j < input; j++) {
System.out.print((array[i])+" ");
System.out.print("> ");
System.out.print((array[j]) +""+(array[i] > array[j])+" ");
if (array[i] > array[j]) {
count++;
}
}
solved[i] = count;
}
}
for (int i = 0; i < input; i++) {
System.out.print(solved[i] + " ");
}
What I want to achieve in simpler terms
Input
Say I have 4 elements in my
array[] -->86,77,15,93
output
solved[]-->2 1 0 0
2 because after 86 there are only two elements 77,15 lesser than 86
1 because after 77 there is only 15 lesser than 77
rest 15 <93 hence 0,0
So making the code simpler and making the code faster aren't necessarily the same thing. If you want the code to be simple and readable, you could try a sort. That is, you could try something like
int[] solved = new int[array.length];
for (int i = 0; i < array.length; i++){
int[] afterward = Arrays.copyOfRange(array, i, array.length);
Arrays.sort(afterward);
solved[i] = Arrays.binarySearch(afterward, array[i]);
}
What this does it it takes a copy of the all the elements after the current index (and also including it), and then sorts that copy. Any element less than the desired element will be beforehand, and any element greater will be afterward. By finding the index of the element, you're finding the number of indices before it.
A disclaimer: There's no guarantee that this will work if duplicates are present. You have to manually check to see if there are any duplicate values, or otherwise somehow be sure you won't have any.
Edit: This algorithm runs in O(n2 log n) time, where n is the size of the original list. The sort takes O(n log n), and you do it n times. The binary search is much faster than the sort (O(log n)) so it gets absorbed into the O(n log n) from the sort. It's not perfectly optimized, but the code itself is very simple, which was the goal here.
With Java 8 streams you could reimplement it like this:
int[] array = new int[] { 86,77,15,93 };
int[] solved =
IntStream.range(0, array.length)
.mapToLong((i) -> Arrays.stream(array, i + 1, array.length)
.filter((x) -> x < array[i])
.count())
.mapToInt((l) -> (int) l)
.toArray();
There is actually a O(n*logn) solution, but you should use a self balancing binary search tree such as red-black tree.
Main idea of the algorithm:
You will iterate through your array from right to left and insert in the tree triples (value, sizeOfSubtree, countOfSmaller). Variable sizeOfSubtree will indicate the size of the subtree rooted at that element, while countOfSmaller counts the number of elements that are smaller than this element and appear at the right side of it in the original array.
Why binary search tree? An important property of BST is that all nodes in the left subtree are smaller than the current node, and all in the right subtree are greater.
Why self-balancing tree? Because this will guarantee you O(logn) time complexity while inserting a new element, so for n elements in array that will give O(n*logn) in total.
When you insert a new element you will also calculate the value of countOfSmaller by counting elements that are currently in the tree and are smaller than this element - exactly what are we looking for. Upon inserting in the tree compare the new element with the existing nodes, starting with the root. Important: if the value of the new element is greater than the value of the root, it means that is also greater than all the nodes in the left subtree of root. Therefore, set countOfSmaller to the sizeOfSubtree of root's left child + 1 (because the new element is also greater than root) and proceed recursively in the right subtree. If it is smaller than root, it goes to the left subtree of root. In both cases increment sizeOfSubtree of root and proceed recursively. While rebalancing the tree, just update the sizeOfSubtree for nodes that are included in left/right rotation and that's it.
Sample code:
public class Test
{
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count) {
value = val;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
System.out.println("For element " + val + " the number of smaller elements to the right is " + count);
}
}
static Node insert(Node node, int value, int countOfSmaller)
{
if (node == null)
return new Node(value, countOfSmaller);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1);
else
node.left = insert(node.left, value, countOfSmaller);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
/** Here goes the rebalancing part. In case that you plan to use AVL, you will need an additional variable that will keep the height of the subtree.
In case of red-black tree, you will need an additional variable that will indicate whether the node is red or black */
return node;
}
static int size(Node n)
{
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args)
{
int[] array = {13, 8, 4, 7, 1, 11};
Node root = insert(null, array[array.length - 1], 0);
for(int i = array.length - 2; i >= 0; i--)
insert(root, array[i], 0); /** When you introduce rebalancing, this should be root = insert(root, array[i], 0); */
}
}
As Miljen Mikic pointed out, the correct approach is using RB/AVL tree. Here is the code that can read and N testcase do the job as quickly as possible. Accepting Miljen code as the best approach to the given problem statement.
class QuickReader {
static BufferedReader quickreader;
static StringTokenizer quicktoken;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
quickreader = new BufferedReader(new InputStreamReader(input));
quicktoken = new StringTokenizer("");
}
static String next() throws IOException {
while (!quicktoken.hasMoreTokens()) {
quicktoken = new StringTokenizer(quickreader.readLine());
}
return quicktoken.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static long nextLong() throws IOException {
return Long.parseLong(next());
}
static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
public class ExecuteClass{
static int countInstance = 0;
static int solved[];
static int size;
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count, int len, int... arraytoBeused) {
countInstance++;
value = val;
size = len;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
solved = arraytoBeused;
solved[size - countInstance] = count;
}
}
static Node insert(Node node, int value, int countOfSmaller, int len, int solved[]) {
if (node == null)
return new Node(value, countOfSmaller, len, solved);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1, len, solved);
else
node.left = insert(node.left, value, countOfSmaller, len, solved);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
return node;
}
static int size(Node n) {
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args) throws IOException {
QuickReader.init(System.in);
int testCase = QuickReader.nextInt();
for (int i = 1; i <= testCase; i++) {
int input = QuickReader.nextInt();
int array[] = new int[input];
int solved[] = new int[input];
for (int j = 0; j < input; j++) {
array[j] = QuickReader.nextInt();
}
Node root = insert(null, array[array.length - 1], 0, array.length, solved);
for (int ii = array.length - 2; ii >= 0; ii--)
insert(root, array[ii], 0, array.length, solved);
for (int jj = 0; jj < solved.length; jj++) {
System.out.print(solved[jj] + " ");
}
System.out.println();
countInstance = 0;
solved = null;
size = 0;
root = null;
}
}
}
So someone posted their solution to this, but I found that it didn't seem to work, I posted this there but I wanted to make it more accessible to others.
The question is in "Cracking the Code Interview" and it is the first tree question, feel free to make other suggestions (or prove me wrong!)
The key here is that it is difficult to keep track of the eventual paths and their heights with one stack.
What I ended up doing is pushing both the left and right child's height on a stack, checking if they are within one of one another, adding one to the max and then pushing that onto the stack after popping the left and right off.
I have commented so I hope it's clear enough
/* Returns true if binary tree with root as root is height-balanced */
boolean isBalanced(Node root) {
if(root == null) return false;
Deque<Integer> heights = new LinkedList<>();
Deque<Node> trail = new LinkedList<>();
trail.push(root);
Node prev = root; //set to root not null to not confuse when root is misisng children
while(!trail.isEmpty()) {
Node curr = trail.peek(); //get the next node to process, peek because we need to maintain trail until we return
//if we just returned from left child
if (curr.left == prev) {
if(curr.right != null) trail.push(curr.right); //if we can go right go
else {
heights.push(-1); //otherwise right height is -1 does not exist and combine heights
if(!combineHeights(heights)) return false;
trail.pop(); //back to parent
}
}
//if we just returned from right child
else if (curr.right == prev) {
if(!combineHeights(heights)) return false;
trail.pop(); //up to parent
}
//this came from a parent, first thing is to visit the left child, or right if no left
else {
if(curr.left != null) trail.push(curr.left);
else {
if (curr.right != null) {
heights.push(-1); //no left so when we combine this node left is 0
trail.push(curr.right); //since we never go left above logic does not go right, so we must here
}
else { //no children set height to 1
heights.push(0);
trail.pop(); //back to parent
}
}
}
prev = curr;
}
return true;
}
//pop both previous heights and make sure they are balanced, if not return false, if so return true and push the greater plus 1
private boolean combineHeights(Deque<Integer> heights) {
int rightHeight = heights.pop();
int leftHeight = heights.pop();
if(Math.abs(leftHeight - rightHeight) > 1) return false;
else heights.push(Math.max(leftHeight, rightHeight) + 1);
return true;
}
So in the end I managed to create an iterative solution which works for all test cases on Leetcode
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public static boolean isBalanced(TreeNode root) {
if (root == null) return true;
Deque<Pair> queue = new LinkedList<>();
queue.offer(new Pair(root, 0));
while (!queue.isEmpty()) {
var curr = queue.poll();
System.out.printf(">>Curr node is %s and curr.lvl is %s", curr.node.val, curr.lvl);
int left = getSubTreeHeight(new Pair(curr.node.left, curr.lvl + 1));
int right = getSubTreeHeight(new Pair(curr.node.right, curr.lvl + 1));
if (Math.abs(left - right) > 1) return false;
if (curr.node.left != null) queue.offer(new Pair(curr.node.left, curr.lvl + 1));
if (curr.node.right != null) queue.offer(new Pair(curr.node.right, curr.lvl + 1));
}
return true;
}
static int getSubTreeHeight(Pair pair) {
if (pair.node == null) {
return pair.lvl -1;
}
Deque<Pair> queue = new LinkedList<>();
queue.offer(pair);
int height = 0;
while (!queue.isEmpty()) {
Pair curr = queue.poll();
System.out.printf("Curr node is %s and curr.lvl is %s", curr.node.val, curr.lvl);
height = curr.lvl;
if (curr.node.left != null) queue.offer(new Pair(curr.node.left, curr.lvl + 1));
if (curr.node.right != null) queue.offer(new Pair(curr.node.right, curr.lvl + 1));
}
return height;
}
public static class Pair {
TreeNode node;
int lvl;
public Pair(TreeNode node, int lvl) {
this.node = node;
this.lvl = lvl;
}
}
}
The original question in the book does not mention the tree being binary. I happen to solve the same question, but coded in Python. So, here is my iterative solution for the problem, for general trees (where the children of a node is stored in a list), in python.
def is_balanced_nonrecursive(self):
stack = [self.root]
levels = [0]
current_min = sys.maxint
current_max = 0
current_level = 0
while len(stack) > 0:
n = stack.pop()
current_level = levels.pop()
for c in n.children:
stack.append(c)
levels.append(current_level + 1)
if len(n.children) == 0:
if current_level < current_min:
current_min = current_level
if current_level > current_max:
current_max = current_level
return current_max - current_min < 2
This is basically a depth first traversal of the tree. We keep a separate stack for the levels (the list levels). If we see any leaf node, we update the current min and current max levels accordingly. The algorithm traverses the whole tree and at the end if max and min levels differ by more than one, then the tree is not balanced.
There are many optimizations possible, like for instance checking whether the difference of min and max is more than one inside the loop, and if that is the case return False immediately.
Some code repetition on this one, but at least it doesn't give me a headache as the recursive ones do:
public boolean isBalanced() {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
int leftLevel = 0;
int rightLevel = 0;
if(this == null) return false;
if(this.left != null)queue.offer(this.left);
while(!queue.isEmpty()) {
int size = queue.size();
for(int i=0; i < size; i++) {
if(queue.peek().left != null) queue.offer(queue.peek().left);
if(queue.peek().right != null) queue.offer(queue.peek().right);
queue.poll();
}
leftLevel++;
}
if(this.right != null) queue.offer(this.right);
while(!queue.isEmpty()) {
int size = queue.size();
for(int i=0; i < size; i++) {
if(queue.peek().left != null) queue.offer(queue.peek().left);
if(queue.peek().right != null) queue.offer(queue.peek().right);
queue.poll();
}
rightLevel++;
}
return Math.abs(leftLevel - rightLevel) < 2;
}
Write the method removeRightmostHalf member of the class LinkedList. Do not call any methods of the class and do not use any auxiliary data structures.
If l contains A! B! C! D! E, then after calling l.removeRightmostHalf(), l becomes A! B! C.
int size = 0 ;
int halfSize = 0;
current = head;
while (current.next != null) {
++size;
current=current.next;
}
++size;
if (size % 2 == 0) {
halfSize = (size / 2);
for (int i = halfSize + 1; i < size; i++) {
}
}
I do not know how I will remove inside for loop.
Any help!
I would suggest you to use two pointers, slow and fast pointer. Initially both will be pointing to the start of the linked list.
The slow pointer will move one node at a time.
The fast will move two node a time.
The moment you see that fast pointer has reached the end of the list, just mark the slow pointer node as end of the list, by setting next=null;
Important note that, the discovery of the end of the list will be depend on the even/odd size of the list. So design and test with both cases.
This will work , when you reach the half of the list just cut the link with the rest of it.
public void removeRightMost() {
int size = 0;
int halfSize = 0;
current = head;
while (current!= null) {
size++;
current = current.next;
}
if (size % 2 == 0) {
halfSize = (size / 2);
int count = 0;
current = head;
/* if the number of elements is even you need to decrease the halfSize 1 because
you want the current to reach the exactly half if you have 4 elements the current
should stop on the element number 2 then get out of the loop */
while (count < halfSize-1) {
current = current.next;
count++;
}
current.next=null; //here the process of the deletion when you cut the rest of the list , now nothing after the current (null)
}
else {
halfSize = (size / 2);
int count = 0;
current = head;
while (count < halfSize) {
current = current.next;
count++;
}
current.next=null;
}
current=head; // return the current to the first element (head)
}
good luck