MEX from root node to every other node in a tree - java

Given a rooted tree having N nodes. Root node is node 1. Each ith node has some value , val[i] associated with it.
For each node i (1<=i<=N) we want to know MEX of the path values from root node to node i.
MEX of an array is smallest positive integer not present in the array, for instance MEX of {1,2,4} is 3
Example : Say we are given tree with 4 nodes. Value of nodes are [1,3,2,8] and we also have parent of each node i (other than node 1 as it is the root node). Parent array is defined as [1,2,2] for this example. It means parent of node 2 is node 1, parent of node 3 is node 2 and parent of node 4 is also node 2.
Node 1 : MEX(1) = 2
Node 2 : MEX(1,3) = 2
Node 3 : MEX(1,3,2) = 4
Node 4 : MEX(1,3,8) = 2
Hence answer is [2,2,4,2]
In worst case total number of Nodes can be upto 10^6 and value of each node can go upto 10^9.
Attempt :
Approach 1 : As we know MEX of N elements will be always be between 1 to N+1. I was trying to use this understanding with this tree problem, but then in this case N will keep on changing dynamically as one proceed towards leaf nodes.
Approach 2 : Another thought was to create an array with N+1 empty values and then try to fill them as we go along from root node. But then challenge I faced was on to keep track of first non filled value in this array.

public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int T = Integer.parseInt(br.readLine().trim());
for(int t_i = 0; t_i < T; t_i++)
{
int N = Integer.parseInt(br.readLine().trim());
String[] arr_val = br.readLine().split(" ");
int[] val = new int[N];
for(int i_val = 0; i_val < arr_val.length; i_val++)
{
val[i_val] = Integer.parseInt(arr_val[i_val]);
}
String[] arr_parent = br.readLine().split(" ");
int[] parent = new int[N-1];
for(int i_parent = 0; i_parent < arr_parent.length; i_parent++)
{
parent[i_parent] = Integer.parseInt(arr_parent[i_parent]);
}
int[] out_ = solve(N, val, parent);
System.out.print(out_[0]);
for(int i_out_ = 1; i_out_ < out_.length; i_out_++)
{
System.out.print(" " + out_[i_out_]);
}
System.out.println();
}
wr.close();
br.close();
}
static int[] solve(int N, int[] val, int[] parent){
// Write your code here
int[] result = new int[val.length];
ArrayList<ArrayList<Integer>> temp = new ArrayList<>();
ArrayList<Integer> curr = new ArrayList<>();
if(val[0]==1)
curr.add(2);
else{
curr.add(1);
curr.add(val[0]);
}
result[0]=curr.get(0);
temp.add(new ArrayList<>(curr));
for(int i=1;i<val.length;i++){
int parentIndex = parent[i-1]-1;
curr = new ArrayList<>(temp.get(parentIndex));
int nodeValue = val[i];
boolean enter = false;
while(curr.size()>0 && nodeValue == curr.get(0)){
curr.remove(0);
nodeValue++;
enter=true;
}
if(curr.isEmpty())
curr.add(nodeValue);
else if(!curr.isEmpty() && curr.contains(nodeValue) ==false && (enter|| curr.get(0)<nodeValue))
curr.add(nodeValue);
Collections.sort(curr);
temp.add(new ArrayList<>(curr));
result[i]=curr.get(0);
}
return result;
}
}

This can be done in time O(n log n) using augmented BSTs.
Imagine you have a data structure that supports the following operations:
insert(x), which adds a copy of the number x.
remove(x), which removes a copy of the number x.
mex(), which returns the MEX of the collection.
With something like this available, you can easily solve the problem by doing a recursive tree walk, inserting items when you start visiting a node and removing those items when you leave a node. That will make n calls to each of these functions, so the goal will be to minimize their costs.
We can do this using augmented BSTs. For now, imagine that all the numbers in the original tree are distinct; we’ll address the case when there are duplicates later. Start off with Your BST of Choice and augment it by having each node store the number of nodes in its left subtree. This can be done without changing the asymptotic cost of an insertion or deletion (if you haven’t seen this before, check out the order statistic tree data structure). You can then find the MEX as follows. Starting at the root, look at its value and the number of nodes in its left subtree. One of the following will happen:
The node’s value k is exactly one plus the number of nodes in the left subtree. That means that all the values 1, 2, 3, …, k are in the tree, so the MEX will be the smallest value missing from the right subtree. Recursively find the MEX of the right subtree. As you do, remember that you’ve already seen the values from 1 to k by subtracting k off of all the values you find there as you encounter them.
The node’s value k is at least two more than the number of nodes in the left subtree. That means that the there’s a gap somewhere in the node’s in the left subtree plus the root. Recursively find the MEX of the left subtree.
Once you step off the tree, you can look at the last node where you went right and add one to it to get the MEX. (If you never went right, the MEX is 1).
This is a top-down pass on a balanced tree that does O(1) work per node, so it takes a total of O(log n) work.
The only complication is what happens if a value in the original tree (not the augmented BST) is duplicated on a path. But that’s easy to fix: just add a count field to each BST node tracking how many times it’s there, incrementing it when an insert happens and decrementing it when a remove happens. Then, only remove the node from the BST in the case where the frequency drops to zero.
Overall, each operation on such a tree takes time O(log n), so this gives an O(n log n)-time algorithm for your original problem.

public class PathMex {
static void dfs(int node, int mexVal, int[] res, int[] values, ArrayList<ArrayList<Integer>> adj, HashMap<Integer, Integer> map) {
if (!map.containsKey(values[node])) {
map.put(values[node], 1);
}
else {
map.put(values[node], map.get(values[node]) + 1);
}
while(map.containsKey(mexVal)) mexVal++;
res[node] = mexVal;
ArrayList<Integer> children = adj.get(node);
for (Integer child : children) {
dfs(child, mexVal, res, values, adj, map);
}
if (map.containsKey(values[node])) {
if (map.get(values[node]) == 1) {
map.remove(values[node]);
}
else {
map.put(values[node], map.get(values[node]) - 1);
}
}
}
static int[] findPathMex(int nodes, int[] values, int[] parent) {
ArrayList<ArrayList<Integer>> adj = new ArrayList<>(nodes);
HashMap<Integer, Integer> map = new HashMap<>();
int[] res = new int[nodes];
for (int i = 0; i < nodes; i++) {
adj.add(new ArrayList<Integer>());
}
for (int i = 0; i < nodes - 1; i++) {
adj.get(parent[i] - 1).add(i + 1);
}
dfs(0, 1, res, values, adj, map);
return res;
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int nodes = sc.nextInt();
int[] values = new int[nodes];
int[] parent = new int[nodes - 1];
for (int i = 0; i < nodes; i++) {
values[i] = sc.nextInt();
}
for (int i = 0; i < nodes - 1; i++) {
parent[i] = sc.nextInt();
}
int[] res = findPathMex(nodes, values, parent);
for (int i = 0; i < nodes; i++) {
System.out.print(res[i] + " ");
}
}
}

Related

Get the longest route traveled in a graph

I have an array of nodes that are connected to each other
I have below network of nodes. Here 0 is the starting point, I want to travel as many nodes as possible with a node traveled only once.
Also during a trip from 0 to destination node, I want to have only a single odd numbered node (like 1, 3, 5, 7).
Now I need to find out the longest route I can travel from my beginning position 0.
Example :
int[] array = { 0, 9, 0, 2, 6, 8, 0, 8, 3, 0 };
In above graph, below are possibilities:
0 -> 6 -> 4 (valid path, length = 3 nodes)
0 -> 9 -> 1 (Not valid path, length as we have 2 odd numbers here 1 & 9)
0 -> 2 -> 3 -> 8 (valid path, length = 4 nodes)
0 -> 2 -> 3 -> 8 -> 5 (Not valid path as we have 2 odd numbers here 3 & 5)
0 -> 2 -> 3 -> 8 -> 7 (Not valid path as we have 2 odd numbers here 3 & 7)
So the answer is 4 for this input.
Below is the program I am trying.
public int process(int[] array) {
int count = array.length;
ArrayList<Integer>[] branches = new ArrayList[count];
for (int i = 0; i < count; i++) {
branches[i] = new ArrayList<>();
}
int begin = 0;
for (int i = 0; i < count; i++) {
if (array[i] != i) {
branches[i].add(array[i]);
branches[array[i]].add(i);
}
}
Arrays.stream(branches).forEach(System.out::println);
Queue<Network> networkQueue = new LinkedList<Network>();
ArrayList<Integer> networkList = branches[begin];
networkList.forEach(value -> {
Network net = new Network(0, value);
networkQueue.add(net);
});
System.out.println("printing starting nodes.......");
List<Network> nodes = new ArrayList<>();
for (Network n : networkQueue) {
nodes.add(n);
System.out.println(n.value + " : " + n.road);
}
int result = 0;
return result;
}
class Network {
int road, value;
public Network(int road, int value) {
this.road = road;
this.value= value;
}
}
The program prints the branches and the nodes for the starting point i.e 0 :
[2, 6, 9]
[9]
[0, 3]
[2, 8]
[6]
[8]
[4, 0]
[8]
[5, 7, 3]
[1, 0]
printing starting nodes.......
2 : 0
6 : 0
9 : 0
I got stuck on finding the longest route, how to proceed next with this program, please help me here.
This is a classic Depth First Search with backtracking problem.
The gist of this algorithm is as follow.
Starting from the start node, visit all its neighbors that have not been visited and do not break the max odd number node of 1 restriction. Add the current node to the current path and increment odd number node counter if the current node number is odd. Do this recursively until you've exhausted all valid paths for one neighbor, then backtrack for the remaining neighbors.
The following is the implementation with your provided input as the test case. I also added another list of list variable that is called res. This will give you all the valid longest path. I used a map to represent a graph, but you can modify this as you like.
import java.util.*;
public class LongestRoute {
private static int maxLen = 0;
private static List<List<Integer>> res = new ArrayList<>();
public static int longestRouteWithRestrictions(Map<Integer, List<Integer>> graph, int startNode) {
Set<Integer> visited = new HashSet<>();
visited.add(startNode);
List<Integer> path = new ArrayList<>();
path.add(startNode);
dfs(graph, startNode, visited, startNode % 2 == 1 ? 1 : 0, path);
return maxLen;
}
private static void dfs(Map<Integer, List<Integer>> graph, int currentNode, Set<Integer> visited, int oddNumNodeCnt, List<Integer> path) {
if(path.size() > maxLen) {
maxLen = path.size();
res.clear();
res.add(new ArrayList<>(path));
}
else if(path.size() == maxLen) {
res.add(new ArrayList<>(path));
}
for(int neighbor : graph.get(currentNode)) {
if(visited.contains(neighbor) || oddNumNodeCnt == 1 && neighbor % 2 != 0) {
continue;
}
path.add(neighbor);
visited.add(neighbor);
dfs(graph, neighbor, visited, oddNumNodeCnt + (neighbor % 2 != 0 ? 1 : 0), path);
path.remove(path.size() - 1);
visited.remove(neighbor);
}
}
public static void main(String[] args) {
//Init a test graph
Map<Integer, List<Integer>> graph = new HashMap<>();
Integer[] neighbors_0 = {2,6,9};
List<Integer> list0 = Arrays.asList(neighbors_0);
graph.put(0, list0);
Integer[] neighbors_1 = {9};
List<Integer> list1 = Arrays.asList(neighbors_1);
graph.put(1, list1);
Integer[] neighbors_2 = {0,3};
List<Integer> list2 = Arrays.asList(neighbors_2);
graph.put(2, list2);
Integer[] neighbors_3 = {2,8};
List<Integer> list3 = Arrays.asList(neighbors_3);
graph.put(3, list3);
Integer[] neighbors_4 = {6};
List<Integer> list4 = Arrays.asList(neighbors_4);
graph.put(4, list4);
Integer[] neighbors_5 = {8};
List<Integer> list5 = Arrays.asList(neighbors_5);
graph.put(5, list5);
Integer[] neighbors_6 = {0,4};
List<Integer> list6 = Arrays.asList(neighbors_6);
graph.put(6, list6);
Integer[] neighbors_7 = {8};
List<Integer> list7 = Arrays.asList(neighbors_7);
graph.put(7, list7);
Integer[] neighbors_8 = {5,7};
List<Integer> list8 = Arrays.asList(neighbors_8);
graph.put(8, list8);
Integer[] neighbors_9 = {0,1};
List<Integer> list9 = Arrays.asList(neighbors_9);
graph.put(9, list9);
System.out.println(longestRouteWithRestrictions(graph, 0));
for(List<Integer> route : res) {
System.out.println(route.toString());
}
}
}
I'm sorry I don't have time to code it, but here is the logic i would apply.
starting from 0 the program generate linked lists of neighbors. In our case:
[0->2]
[0->9]
[0->6]
checking neighbors (last elements in lists): if they are odd then increment a counter that refer to that path list.
If the odd counter ==2 then erase that list from further analsys
for each list start again from 1. using last element as input. When no more VALID lists can be generated find the one with longest path, counting elements.
Just pay attention that a valid neighbor cannot be the same as the previous element in the list to avoid infinite loops: The only valid list generable by [0->2] it's [0->2->3], and not [0->2->0]
You can try below approach, which should be relatively simple to implement as well as track. Firstly, you need to form a Node class which would have information about 3 things:
Max length of the path traveled so far while visiting all the nodes until this node from node 0, visiting each node just once.
A variable called oddCounter that counts the number of odd nodes encountered so far in this path.
A boolean variable isVisited to know if this node is already visited or not.
Now just implement BFS with nodes being as instance of this type of class defined above and while doing BFS, you just need to update each node variables accordingly.
Please note that you need to do BFS to all nodes starting from node 0, each time resetting the values of above 3 variables so you can keep track of the further paths in that route through this node. You can terminate the loop beyond certain nodes if you have already found one odd node. This way it would be more flexible in future as well where you might want to include maybe 2 or 3 odd numbered nodes in your path as compared to just one node currently.
Also, you would need to create a resultList and currList where you create a new currList everytime you traverse to a new node and update resultList with currList if length of currList is greater than the length of resultList as per the constraints we have.
I am sure that this approach can be optimized further using Dynamic Programming. As you know the route length and number of odd nodes until a given node say i, you can just do a BFS now from ith node and using memoization to keep track of previous route length and odd numbered nodes, which we are already tracking using above class we created.
this is in c++, but i think it works the same:
#include <vector>
using namespace std;
void dfs(vector<vector<int>> &graphs, int nextidx, int& ticket, int& cities);
int solution(vector<int>& T)
{
if (T.empty()) return 0;
vector<vector<int>> graphs(T.size());
int ticket = 1;
int citiesmax = 0;
for (int i = 1; i < T.size(); ++i) {
graphs[T[i]].emplace_back(i);
}
// 0-> 2, 6, 9
// 1-> _
// 2-> 3
// 3-> 8
// 4-> _
// 5-> _
// 6-> 4
// 7-> _
// 8-> 5, 7
// 9-> 1
for (int i = 0; i < graphs[0].size(); ++i)
{
int nextidx = graphs[0][i];
int cities = 1;
dfs(graphs, nextidx, ticket, cities);
if(cities > citiesmax)
{
citiesmax = cities;
}
}
return citiesmax;
}
void dfs(vector<vector<int>> &graphs, int nextidx, int &ticket, int& cities)
{
if (graphs[nextidx].empty()) return;
for (int i = 0; i < graphs[nextidx].size(); ++i)
{
if (graphs[nextidx][i] % 2 > 0)
{
if (ticket == 0) return;
ticket--;
}
int idx = graphs[nextidx][i];
cities++;
dfs(graphs, idx, ticket, cities);
}
return;
}
int main()
{
vector<int> test1 = {0,9,0,2,6,8,0,8,3,0};
int res = solution(test1);
}

Need help to find the least amount of semesters

My homework problem presents some courses and how many depend on each other. For an instance, the first test (courses,depedent on): (1,3) (2,3) (4,1) (4,2) and we identify that there are 5 courses and 4 dependent on each other (Thats why 5 is not on the list, its just 0)
I know from a topological search, that the following is a valid solution:
1 3 2 4 0
I then need to print the number of semesters it takes to take these courses and I know it is 3 semester, due to the relations between them. We first have to take course 1 and 2 to take 3 and since we already have 1 2, we can take course 4.
So I need help figuring some code out that does this. That's where I need you guys help
I've tried to simply count the courses that are connected, but failed. I've tried to think of something that I can do but literally nothing pops up as a solution.
The graph class:
public class Graph {
int V;
LinkedList<Integer> adjList[];
public Graph(int vertex) {
this.V = vertex;
//We then define the num of vertexes in the adjlist
adjList = new LinkedList[vertex];
//Then create a new list for each vertex so we can create a link between the vertexes
for (int i = 0; i < vertex; i++) {
adjList[i] = new LinkedList<>();
}
}
//Directed graph
public void addEdge(int source, int destination) {
//Add the edge from the source node to the destination node
adjList[source].add(destination);
adjList[destination].add(source);
}
//Method to print the graph if necessary
public void printGraph(Graph graph) {
for (int i = 0; i < graph.V; i++) {
System.out.println("Adjacency list over vertex: " + i);
System.out.print("head");
for (Integer treeCrawler : graph.adjList[i]) {
System.out.print("-> " + treeCrawler);
}
System.out.println("\n");
}
}
public LinkedList<Integer>[] getAdjList() {
return adjList;
}
}
and the topological sort class, the algorithm we are using for the problem
public class TopologicalSort {
int vertex;
//This function helps the topological function recursively by marking the vertices and pushing them onto the stack
public void topologicalHelper(int vertex, boolean marked[], Stack nodes, Graph graph) {
List<Integer>[] list = graph.getAdjList();
marked[vertex] = true;
Iterator<Integer> iterator = list[vertex].iterator();
while (iterator.hasNext()) {
int temp = iterator.next();
if (!marked[temp] && list[temp].size() != 0) {
topologicalHelper(temp, marked, nodes, graph);
}
}
nodes.add(vertex);
}
public TopologicalSort(Graph graph, int vertecies) {
vertex = vertecies;
Stack nodes = new Stack();
boolean[] marked = new boolean[vertex];
for (int i = 0; i < vertex; i++) {
if (marked[i] == false) {
topologicalHelper(i, marked, nodes, graph);
}
}
while(!nodes.empty()) {
System.out.print(nodes.pop() + " ");
}
}
}
The result should be 3, but I haven't produced that number in all my solution ideas, I need some help or hints.
Oh and the following is the console output
Adjacency list over vertex: 0
head
Adjacency list over vertex: 1
head-> 3-> 4
Adjacency list over vertex: 2
head-> 3-> 4
Adjacency list over vertex: 3
head-> 1-> 2
Adjacency list over vertex: 4
head-> 1-> 2
1 3 2 4 0
Dependency is a directed property so you should be using a directed graph. After populating the graph u will end up with a disconnected graph which has one or more trees in it. Find out which nodes are roots of each tree and use DFS to get the max depth of each tree. Assuming there is no limit on no of courses for each semester the max depth of all trees is the solution.
public class Graph {
int V;
ArrayList<Integer> adjList[];
boolean[] notRoot;
public Graph(int vertex) {
this.V = vertex;
adjList = new ArrayList[vertex];
notRoot = new boolean[vertex];
for (int i = 0; i < vertex; i++) {
adjList[i] = new ArrayList<Integer>();
}
}
public void addEdge(int a, int b) {
//asuming b is dependent on a
adjList[b].add(a);
notRoot[a]=true;
}
int maxDepthDfs(int root){
int depth=1;
for(int i=0;i<adjList[root].size();i++){
int child=adjList[root].get(i);
depth=Math.max(maxDepthDfs(child)+1,depth);
}
return depth;
}
public int getSolution(){
int ans=0;
for(int i=0;i<V;i++){
if(!notRoot[i])
ans=Math.max(ans,maxDepthDfs(i));
}
return ans;
}
}
A topological sort is simply DFS with adding nodes into a stack,(all children of a node are added first and then root is added). In Kahn's algorithm first the root elements(nodes without parent) are found and the method is called only or those nodes.
int maxDepthDfs(int root){
//since we are only calling this function for root nodes we need not check if nodes were previously visited
int depth=1;
for(int i=0;i<adjList[root].size();i++){
int child=adjList[root].get(i);
depth=Math.max(maxDepthDfs(child)+1,depth);
}
s.push(root);
return depth;
}
public int getSolution(){
s=new Stack<Integer>();
int ans=0;
for(int i=0;i<V;i++){
if(!notRoot[i])
ans=Math.max(ans,maxDepthDfs(i));
}
//stack s contains result of topological sort;
return ans;
}

Average of each level in a Binary Tree

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
}

How to calculate the shortest path between two vertices in Graph with given parameters?

We need to compute the minCost(), which has follwing parameters:
gNodes - no of Nodes in graph g.
an array of int's, gFrom, where each gfrom[i] denotes a node connected by ith edge in graph g.
an array of int's, gTo, where each gTo[i] denotes a node connected by ith edge in graph g.
an array of int's, gWeight, denoting the respective weights of each edge in graph g.
an int, start, denoting the start node index.
an int, end, denoting the end node index.
an integer, wExtra, denoting the weight of optional extra edge.
We need to find the path from start to end having minimum possible weight. We can add at most one extra edge(ie. zero or one) having wExtra weight between any two distinct nodes that are not already connected by an edge. The function must return an int denoting the minimum path weight from start to end.
I was able to come up with following code (Dijkstra algorithm) but it doesn't give the expected output.
public static int minCost(int gNodes, int[] gFrom, int[] gTo, int[] gWeights, int start, int end) {
//making a array to store shortest length and filling it with infinity except the first one
int[] shortest = new int[gNodes];
for (int i = 0; i < gNodes; i++) {
shortest[i] = Integer.MAX_VALUE;
}
shortest[start]=0;
//filling the Queue with all vertices
Queue<Integer> theQ = new PriorityQueue<>();
for (int i = 0; i < gNodes; i++) {
theQ.add(i + 1);
}
//following the algorithm
while (!theQ.isEmpty()) {
int u = theQ.poll();
//making a list of adjacent vertices
List<Integer> adjacent = new ArrayList<>();
for (int i = 0; i < gFrom.length; i++) {
if (gFrom[i] == u) {
adjacent.add(gTo[i]);
} else if (gTo[i] == u) {
adjacent.add(gFrom[i]);
}
}
for (int v: adjacent) {
int weight=0;
for (int i = 0; i < gFrom.length; i++) {
if ((gFrom[i] == u && gTo[i] == v) || (gFrom[i] == v && gTo[i] == u)) {
weight = gWeights[i];
}
}
//relaxing the verices
if (shortest[v] > shortest[u] + weight) {
shortest[v] = shortest[u] + weight;
}
if (v == end) {
return shortest[v];
}
theQ.add(v);
}
}
return -1;
}
public static void main(String[] args) {
int gNodes = 4;
int[] gFrom = {1, 2, 2, 3};
int[] gTo = {2, 3, 4, 4};
int[] gWeights = {2, 1, 2, 3};
int start =1;
int end = 4;
System.out.println(shortestDistance(gNodes, gFrom, gTo, gWeights, start, end));
}
}
It's not giving the expected output which I think is because I can't think of how to use that wExtra. Also, the code is quite messy. Please let me know what's wrong or feel free to provide any robust code that does it well. Thanks.
A possible idea to integrate wExtra is the following:
Duplicate the graph, such that you have two nodes for every input node. The original graph represents the state before introducing the new edge. The copy represents the state after the introduction. For every node n in the original graph, you should then introduce directed edges with weight wExtra to all nodes m in the copy, where the original of m is not adjacent to n. This basically represents the fact that you can introduce a new edge between any two non-adjacent edges. But once you have done this, you cannot go back. Then, run usual Dijkstra on the modified graph between start and either the original end or the copy of end and you should get the correct result.
The best way to visualize this is probably to interpret the two sub graphs as layers. You start at the original layer and want to get to one of the two end nodes (whichever is closer). But you may switch layers only once.

Reduced time complexity of inner loop: Find count of elements greater than current element in the first loop and store that in solved array

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;
}
}
}

Categories

Resources