Use PriorityQueue as a minHeap - java

When trying to solve this problem https://www.hackerrank.com/challenges/cut-the-tree
I was trying to always pick and cut a leaf and then combine its weight to the node that it connects.
I was using a PriorityQueue to store all the nodes, and using the size of their adjacent nodes as the priority. But when I'm trying some test case, it seems that the priority queue property is violated, which means that non-leaf nodes may appear before leaf nodes. Will PriorityQueue automatically update itself or should I call some function to update it. My temporary solution is to use a list to store all the leaves.
The following is my code:
public class Solution {
private static class Node implements Comparable<Node> {
int index;
int value;
Map<Integer, Node> adj;
public Node(int index, int value) {
this.index = index;
this.value = value;
this.adj = new HashMap<Integer, Node>();
}
#Override
public int compareTo(Node n) {
return adj.size() - n.adj.size();
}
}
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
int total = 0;
int N = Integer.parseInt(br.readLine());
String[] strs = br.readLine().split(" ");
HashMap<Integer, Node> nodes = new HashMap<Integer, Node>();
for (int i = 0; i < N; i++) {
int value = Integer.parseInt(strs[i]);
nodes.put(i, new Node(i, value));
total += value;
}
for (int i = 0; i < N - 1; i++) {
strs = br.readLine().split(" ");
int n1 = Integer.parseInt(strs[0]) - 1;
int n2 = Integer.parseInt(strs[1]) - 1;
nodes.get(n1).adj.put(n2, nodes.get(n2));
nodes.get(n2).adj.put(n1, nodes.get(n1));
}
// PriorityQueue<Node> pq = new PriorityQueue<Node>(nodes.values());
// while (!pq.isEmpty()) {
// Node n = pq.poll();
// System.out.println(n.index + " " + n.adj.size());
// }
// NOTE: java's PriorityQueue doesn't support update, cannot use it
// LAME DESIGN. use a LinkedList instead
List<Node> leaves = new LinkedList<Node>();
for (Node node : nodes.values()) {
if (node.adj.size() == 1) {
leaves.add(node);
}
}
int minDiff = Integer.MAX_VALUE;
while (!leaves.isEmpty()) {
// get a leaf node
// Node leaf = pq.poll();
Node leaf = leaves.get(0);
leaves.remove(0);
if (leaf.adj.size() <= 0)// last node
break;
int diff = Math.abs((total - leaf.value) - leaf.value);
if (diff < minDiff)
minDiff = diff;
// combind leaf to it's connection
Node conn = null;
for (Node node : leaf.adj.values()) {
conn = node;
}
conn.value += leaf.value;
conn.adj.remove(leaf.index);
if (conn.adj.size() == 1)
leaves.add(conn);
nodes.remove(leaf.index);
}
System.out.println(minDiff);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Thanks.

The standard Java PriorityQueue does not support update. If you need to remove items, then you have to implement your own minHeap. Call heapify when you removed some items in the heap.
The implementation and explanation can be found here!

PrioirtyQueue does not have an implementation but LinkedHashMap does, they are removeEldestEntry.
According to documentation:
The removeEldestEntry(Map.Entry) method may be overridden to impose a policy for removing stale mappings automatically when new mappings are added to the map.

Related

Traversing through a Array-Binary tree

I have troubles with traversing through a array binary tree without recursion.
I hope someone can tell me what iam doing wrong. For simplicity the code is kept simple.
Please note: Its not allowed to add other methods like Iterator to check if there is a hasNext() and so on.
For now i just want to print all keys out (incl. child keys) in the hope that i can do the rest of the learning!
Thank you very much for helping.
public class BTree {
private Node root;
public BTree(Node root) {
this.root = root;
}
public int getMaxKey() {
Node copy = root;
for (int i = 0; copy.child != null && i < copy.child.length; i++) {
System.out.println("key: " + copy.key); // output: 15, 80
if (copy.child != null) {
copy = copy.child[i];
}
}
return 0;
}
}
public class Node {
public int key;
public Node[] child;
public Node(int key, Node[] child) {
this.key = key;
this.child = child;
}
}
public class NodeMain {
public static void main(String[] args) {
Node[] lv1Nodes = new Node[2];
lv1Nodes[0] = new Node(25, null);
lv1Nodes[1] = new Node(99, null);
Node[] lv0Nodes = new Node[2];
lv0Nodes[0] = new Node(80, lv1Nodes);
lv0Nodes[1] = new Node(5, null);
Node root = new Node(15, lv0Nodes);
BTree bTree = new BTree(root);
int maxKey = bTree.getMaxKey(); // output should be 99
System.out.println(maxKey);
}
}
So, here you are following only one branch till null for the Binary tree traversal. But, you need to keep track of all nodes in traversal order of child array so that you can get the max element from it.
please refer to below code, here i've used stack to keep all of the value array nodes, which we can pop and check for maxValue.
public class BTree {
private final Node root;
public BTree(Node root) {
this.root = root;
}
public int getMaxKey() {
int maxKey = root.key;
Stack<Node> stack = new Stack<>();
stack.addAll(Arrays.asList(root.child));
while(!stack.isEmpty()){
Node node = stack.pop();
System.out.println(node.key);
if(node.key > maxKey)
maxKey = node.key;
if(node.child != null)
stack.addAll(Arrays.asList(node.child));
}
return maxKey;
}
}
Edit: I've created a image which can help us to understand the tree little bit more clearly, and i've used for my reference for this code.
My solution without Stack object:
public int getMaxKey() {
Node copy = root;
int max = -1;
while (copy.child != null) {
if (max < copy.key)
max = copy.key; //root
if (copy.child.length == 1) { // max key between parent and child node, only one path available
if (max < copy.child[0].key) {
max = copy.child[0].key;
copy = copy.child[0];
}
} else if (copy.child.length == 2) { // max between two nodes, decide between one path
int maxBetweenChild = Math.max(copy.child[0].key, copy.child[1].key);
Node node = Arrays.stream(copy.child).filter(n -> n.key == maxBetweenChild).findFirst().get();
copy = node;
if (max < maxBetweenChild)
max = maxBetweenChild;
}
}
return max;
}

Represent a graph containing directed and undirected edges using List<Integer>

I was asked this question in one of my google interviews. I couldn't figure it out. If someone can help that would be great :)
The class provided was
class Node{
int data,
List<Node> outEdges;
}
if you're provided a Node stream containing both directed and undirected edges you have to encode it in such a way that it return List and and decode again to original graph
List<Integer> encode(Node root){
}
Node decode(List<Integer> graph){
}
The hint provided was you can add your own integers if you want
You could just put the data and all the edges in the list and using null as delimiter:
private class IndexAndEdge {
public Set<Integer> edges = new HashSet<>();
public int index;
public int data;
}
List<Integer> encode(Node root) {
List<Integer> result = new ArrayList<>();
Map<Node, IndexAndEdge> lookup = new HashMap<>();
parse(root, lookup);
result.add(lookup.size());
lookup.values().stream()
.sorted((a, b) -> Integer.compare(a.index, b.index))
.forEach(iae -> {
result.add(iae.data);
result.addAll(iae.edges);
result.add(null);
});
result.remove(result.size() - 1);
return result;
}
private int parse(Node node, Map<Node, IndexAndEdge> lookup) {
if (lookup.containsKey(node))
return lookup.get(node).index;
IndexAndEdge iae = new IndexAndEdge();
iae.index = lookup.size();
iae.data = node.data;
lookup.put(node, iae);
for (Node n : node.outEdges)
iae.edges.add(parse(n, lookup));
return iae.index;
}
Node decode(List<Integer> graph) {
Node[] nodes = new Node[graph.get(0)];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new Node();
nodes[i].outEdges = new ArrayList<>();
}
int index = 0;
for (int i = 1; i < graph.size(); i++) {
Integer n = graph.get(i);
if (n == null)
index++;
else if (nodes[index].outEdges.isEmpty())
nodes[index].data = n;
else
nodes[index].outEdges.add(nodes[n]);
}
return nodes[0];
}

Counting nodes for each index + toString

So I was wondering if there is a way to print out which index of the list has the most collisions? As well as this, I wanted to know, what is the best way to produce a toString() for my LinkedList? I've tried a few times with the default implementation for a LinkedList toString but I can't quite figure out how to do it.
Thanks in advance!
Code:
static LinkedList<Node> hashTable[] = new LinkedList[100];
static class Node {
int value;
int key;
#Override
public String toString() {
return "Value: " + value + " " + "Key: " + key;
}
}
public static void main(String[] args) throws FileNotFoundException {
File f = new File("Ex5.txt");
Scanner scan = new Scanner(f);
if (f.exists() == false) {
System.out.println("File doesn't exist or could not be found.");
System.exit(0);
}
for (int i = 0; i < 100; i++) {
hashTable[i] = null;
}
while (scan.hasNextInt()) {
int n = scan.nextInt();
insert(n, hashFunction(n));
}
for (int i = 0; i < 100; i++) {
System.out.println(hashTable[i]);
}
int emptyEntries = 0;
for (int i = 0; i < 100; i++) {
if (hashTable[i] == null) {
emptyEntries += 1;
}
}
System.out.println("Number of empty entries: " + emptyEntries);
}
public static void insert(int key, int value) {
int index = hashFunction(value);
LinkedList<Node> items = hashTable[index];
if (items == null) {
items = new LinkedList<>();
Node item = new Node();
item.key = key;
item.value = value;
items.add(item);
hashTable[index] = items;
} else {
for (Node item : items) {
if (item.key == key) {
item.value = value;
return;
}
}
Node item = new Node();
item.key = key;
item.value = value;
items.add(item);
}
}
public static int hashFunction(int value) {
int hashKey = value % 100;
return hashKey;
}
Classes are objects. LinkedList is a class. All objects extend java.lang.Object and you can always call Object.toString() on them, but what you are likely looking for is a way to print out all the values. In this case, it is best to use a for loop:
for(int i=0; i<items.size(); i++){
System.out.println(items.get(i));
}
You are printing multiple lines, each containing various amounts of Node objects. You want to find which line has the most amounts of Node objects.
The way to do this is simple. You need nested for loops to print that, and thus you can do this, with your for loops
int maxNodes = Integer.MIN_VALUE;
int index = -1;
for(int i=0; i<LinkedList.size(); i++){
int nodes = 0;
for(int j=0; j<nestedLinkedList.size(); j++){
System.out.print(NodeInformation);
nodes++;
}
if(nodes>maxNodes){
index = i;
maxNodes = nodes;
}
System.out.println();
}
This sample code would find which line would contain the most Node objects.

BFS: Shortest Reach in a Graph

I am working to get the shortest reach in a graph problem in hackercode. I have designed a code and some testcases are fine whereas some testcases are terminated due to timeout.
Could you say where I need to optimize and please also comment about code style. I am looking for the ways to improve it.
Following is my code,
public class BFS {
public static class Graph {
public Node[] nodes;
Stack<Node> stack = new Stack<Node>();
public Graph(int size) {
nodes = new Node[size];
}
public void addEdge(int first, int second) {
Node nodeF = getNode(first);
if (nodeF == null) {
nodeF = new Node();
nodeF.nodeVal = first;
}
Node nodeS = getNode(second);
if (nodeS == null) {
nodeS = new Node();
nodeS.nodeVal = second;
}
nodeF.neighbours.add(nodeS);
nodes[first] = nodeF;
nodes[second] = nodeS;
}
public int[] shortestReach(int startId) { // 0 indexed
stack.push(getNode(startId));
int[] distance = new int[nodes.length];
Arrays.fill(distance, -1);
distance[startId] = 0;
while (!stack.isEmpty()) {
Node currentNode = stack.pop();
Set<Node> children = getChildren(currentNode);
for (Node node : children) {
distance[node.nodeVal] = distance[currentNode.nodeVal] + 6;
stack.add(node);
}
}
return distance;
}
public Set<Node> getChildren(Node givenNode) {
for (Node node : nodes) {
if (node == givenNode) {
return node.neighbours;
}
}
return null;
}
public Node getNode(int index) {
return nodes[index];
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int queries = scanner.nextInt();
for (int t = 0; t < queries; t++) {
// Create a graph of size n where each edge weight is 6:
Graph graph = new Graph(scanner.nextInt());
int m = scanner.nextInt();
// read and set edges
for (int i = 0; i < m; i++) {
int u = scanner.nextInt() - 1;
int v = scanner.nextInt() - 1;
// add each edge to the graph
graph.addEdge(u, v);
}
// Find shortest reach from node s
int startId = scanner.nextInt() - 1;
int[] distances = graph.shortestReach(startId);
for (int i = 0; i < distances.length; i++) {
if (i != startId) {
if (distances[i] == 0)
continue;
System.out.print(distances[i]);
System.out.print(" ");
}
}
System.out.println();
}
scanner.close();
}
}
class Node {
public int nodeVal;
public Set<Node> neighbours = new HashSet<Node>();
}

DFS java pathfinding problems

I'm developing a search algorithm for finding paths in a graph. In this algorithm i need to find all the paths in an undirected, not weighted graph that go trough each graph connection only once.
Currently, what my prgoram is doing, is finding all the paths that go trough each node only once. I need connections and not nodes.
Here is my code:
import java.util.*;
public class dfs {
private static Map<Integer, LinkedHashSet<Integer>> map = new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
private int numLinks;
public dfs(int startNode, int numLinks) {
super();
this.startNode = startNode;
this.numLinks = numLinks;
}
public int getNumLinks(){
return numLinks;
}
public void addEdge(int source, int destiny) {
LinkedHashSet<Integer> adjacente = map.get(source);
if(adjacente==null) {
adjacente = new LinkedHashSet<Integer>();
map.put(source, adjacente);
}
adjacente.add(destiny);
}
public void addLink(int source, int destiny) {
addEdge(source, destiny);
addEdge(destiny, source);
}
public LinkedList<Integer> adjacentNodes(int adj) {
LinkedHashSet<Integer> adjacente = map.get(adj);
System.out.println("adjacentes:" + adjacente);
if(adjacente==null) {
return new LinkedList<Integer>();
}
return new LinkedList<Integer>(adjacente);
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numVertices = input.nextInt();
int numLinks = input.nextInt();
int startNode = input.nextInt();
int endNode = startNode;
dfs mapa = new dfs(startNode, numLinks);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
Integer currentNode = 0;
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
currentNode = (Integer) pairs.getKey();
mapa.findAllPaths(mapa, visited, paths, currentNode);
}
}
private void findAllPaths(dfs mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
for (Integer node : nodes) {
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
System.out.println("temp:" + temp);
findAllPaths(mapa, temp, paths, node);
}
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
System.out.println("currentNode:" + currentNode);
List<Integer> inseridos = new ArrayList<Integer>();
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
inseridos.add(currentNode);
temp.addAll(visited);
System.out.println("visited:" + visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
Right now, i think the following code:
if (visited.contains(node)) {
continue;
}
is making that the program not going through each node more than once.
I need helping transforming my program to go trough each connection only once, and not through each node only once.
(I'm sorry about my english, i'm not a native)
If you're willing to do some rewriting, I think this kind of problem is more cleanly expressed in an OO fashion.
You could build a linked graph out of Node and Edge instances, allowing you to mark visited edges as you traverse the graph.
class Node
{
List<Edge> adjacentEdges;
boolean isVisited;
}
class Edge
{
Node node1;
Node node2;
boolean isVisited;
}

Categories