I have a quick question. When transversing backwards up a tree using DFS how does timestamp work?
eg.
if a graph has node 1 as the starting node. 1 goes to 2 and 2 goes to 3.
I have implemented some of the code below. It should return a 2d array for start and end times of each vertex.
boolean[] visited = new boolean[g.getNumberOfVertices()-1]
LinkedList<Integer> stack = new LinkedList<integer>();
int[][] times = new int[g.getNumberOfVertices()][2]; //[i][0] == start, [i][1] == end
int timer = 0;
stack.push(startingVertex);
while(!stack.isEmpty())
{
int v = stack.pop();
timer++;
times[v][0] = timer; //start time
int children = 0;
for (int i = 0; i < g.getEdgeMatrix()[v].length; i++)
{
if(g.getEdgeMatrix()[v][i] == 1)
{
children++;
if(visited[i] == false)
{
stack.push(i)
visited[i] = true;
}
}
}
if(children == 0)
{
times[v][1] == timer + 1; // end time
}
}
This could be coded wrong but im a bit lost here.
This how this works is below:
node 1 popped and starts at time 1. node 2 added to the stack, then popped starts at time 1. node 3 added to the stack, then popped starts at time 3. No children so time ends at 4 for node 3. stack empty! exits while loop.
How can I transverse back to node 1 to end the time?
Related
I've been grinding leetcode recently and am perplexed on why my solution is timing out when I submit it to Leetcode.
Here is the question:
https://leetcode.com/explore/learn/card/data-structure-tree/133/conclusion/942/
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
Here is my solution that times out in one of the test cases:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder == null || inorder.length == 0) {
return null; // input error
}
if (postorder == null || postorder.length == 0) {
return null; // input error
}
if (postorder.length != inorder.length) {
return null; // input error
}
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
return buildBinaryTree(inOrder, postOrder);
}
public TreeNode buildBinaryTree(List<Integer> inOrder, List<Integer> postOrder) {
boolean found = false;
int root = 0;
int rootIndex = 0;
// for given in-order scan the post-order right to left to find the root
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
root = inOrder.get(rootIndex);
found = true;
break;
}
}
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
if (rootIndex > 0) {
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
}
if ((rootIndex + 1) < inOrder.size()) {
rightOfRoot.addAll(inOrder.subList(rootIndex + 1, inOrder.size()));
}
TreeNode node = new TreeNode(root);
node.left = buildBinaryTree(leftOfRoot, postOrder);
node.right = buildBinaryTree(rightOfRoot, postOrder);
return node;
}
return null;
}
}
Can anyone help determine why this is happening? I'm thinking it is the Leetcode judge at fault here and my code is fine.
Leetcode's judge is probably OK. This code is too casual about nested linear array operations and heap allocations. Creating ArrayLists and calling contains, addAll, subList and indexOf may appear innocuous, but they should all be thought of as extremely expensive operations when inside a recursive function that spawns two child calls in every frame.
Let's unpack the code a bit:
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
This is a minor up-front cost but it's an omen of things to come. We've done 2 heap allocations that weren't necessary and walked n. I'd stick to primitive arrays here--no need to allocate objects other than the result nodes. A lookup map for inOrder with value -> index pairs might be useful to allocate if you feel compelled to create a supporting data structure here.
Next, we step into buildBinaryTree. Its structure is basically:
function buildBinaryTree(root) {
// do some stuff
if (not base case reached) {
buildBinaryTree(root.left)
buildBinaryTree(root.right)
}
}
This is linear on the number of nodes in the tree, so it's important that // do some stuff is efficient, hopefully constant time. Walking n in this function would give us quadratic complexity.
Next there's
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
This looks bad, but by definition the root is always the last element in a postorder traversal array, so if we keep a pointer to it, we can remove this outer loop. You can use indexOf directly and avoid the contains call since indexOf returns -1 to indicate a failed search.
The code:
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
does more unnecessary heap allocations for every call frame.
Here,
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
Walks the list twice, once to create the sublist and again to add the entire sublist to the ArrayList. Repeat for the right subtree for two full walks on n per frame. Using start and end indices per call frame means you never need to allocate heap memory or copy anything to prepare the next call. Adjust the indices and pass a reference to the same two arrays along the entire time.
I recommend running your code with a profiler to see exactly how much time is spent copying and scanning your ArrayLists. The correct implementation should do at most one walk through one of the lists per call frame to locate root in inOrder. No array copying should be done at all.
With these modifications, you should be able to pass, although wrangling the pointers for this problem is not obvious. A hint that may help is this: recursively process the right subtree before the left.
Yes, it would be much faster with arrays. Try this:
public static TreeNode buildTree(int[] inorder, int[] postorder, int start,
int end) {
for (int i = postorder.length-1; i >= 0; --i) {
int root = postorder[i];
int index = indexOf(inorder, start, end, root);
if (index >= 0) {
TreeNode left = index == start
? null
: buildTree(inorder, postorder, start, index);
TreeNode right = index+1 == end
? null
: buildTree(inorder, postorder, index+1, end);
return new TreeNode(root, left, right);
}
}
return null;
}
private static int indexOf(int[] array, int start, int end, int value) {
for (int i = start; i < end; ++i) {
if (array[i] == value) {
return i;
}
}
return -1;
}
I've made a simple 15puzzle game using A-star algorithm with Manhattan Distance.
For easy problems it works, but the solution isn't the optimal one.
For example, if a movement is:
Right->Up
my solution would be:
Right->Up->Left->Down->Right->Up
If i have a hard game to solve, it takes infinite time and get no solution to problem, I think because of this problem.
To implement my game I have followed wikipedia pseudocode of A* algorithm.
Here is my AStar function:
public ArrayList<String> solution(Vector<Integer> start){
ArrayList<String> movePath = new ArrayList<String>(); //Path to solution
PriorityQueue<Node> closedQueue = new PriorityQueue<Node>(500,new Comparator<Node>() {
#Override public int compare(Node a,Node b) {
return a.get_fScore() - b.get_fScore();
}
});
Node node = new Node(start,movePath,heuristic);
int cnt =0;
openQueue.add(node);
while(!openQueue.isEmpty() ) {
//Alt if it takes too much time (ToRemove)
if(cnt == (150)*1000) {
ArrayList<String> noResult = new ArrayList<String>();
noResult.add("Timeout");
return noResult;
}
Node bestNode = openQueue.remove(); //Remove best node from openQueue
closedQueue.add(bestNode); //Insert its to closedQueue
cnt++;
if( cnt % 10000 == 0) {
System.out.printf("Analizzo %,d posizioni. Queue Size = %,d\n", cnt, openQueue.size());
}
//Get first step from bestNode and add to movePath
if(!bestNode.isEmptyMoves()) {
String step = bestNode.get_moves().get(0);
movePath.add(step);
}
//Exit Condition
if(bestNode.get_hScore() == 0) {
return bestNode.get_moves();
}
//Looking for childs
Vector<Node> childs = get_nextMoves(bestNode);
for(int i=0; i<childs.size(); i++) {
if(closedQueue.contains(childs.elementAt(i)))
continue;
childs.elementAt(i).set_gScore(bestNode.get_gScore()+1); //Increment level in tree
if(!openQueue.contains(childs.elementAt(i)))
openQueue.add(childs.elementAt(i));
else {
//!Never reached this level!
System.out.println("Here!");
//TODO Copy child from openQueue to closedQueue
}
}
}
return null;
That is my function to find neighbours:
public Vector<Node> get_nextMoves(Node act){
Vector<Node> steps = new Vector<Node>();
int position = act.get_valuePos(0);
String lastMove = act.get_lastMove();
//System.out.println(lastMove);
//Right Child
if(position + 1 < 16 && position + 1!=3 && position + 1!=7 && position+1 !=11 && lastMove !="Left") {
int temp_pos[] = copyToArray(act.get_posVect());//Copy array of positions of ACT to a temp_pos array
temp_pos[position] = temp_pos[position+1]; //Switch 0 position with Right position
temp_pos[position+1] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i)); //Save old steps
}
temp_moves.add("Right");//And add new one
Node child = new Node(temp_pos,temp_moves,act.get_heuristic()); //New Node
steps.addElement(child);//Added to vector
}
//Left Child
if(position - 1 >= 0 && position - 1 != 4 && position - 1 != 8 && position - 1 != 12 && lastMove !="Right") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position-1];
temp_pos[position-1] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Left");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
//Up Child
if(position - 4 >= 0 && lastMove !="Down") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position-4];
temp_pos[position-4] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Up");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
//Down Child
if(position + 4 < 16 && lastMove !="Up") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position+4];
temp_pos[position+4] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Down");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
return steps;
And that is my ManhattanDistance function:
public int calcolaDist(Vector<Integer> A) {
int result = 0;
Vector<Integer> goal_Mat = initialize_Mat();
for(int i=0; i<16; i++) {
int x_goal = (goal_Mat.indexOf(i))/4;
int y_goal = (goal_Mat.indexOf(i))%4;
int x_def = (A.indexOf(i))/4;
int y_def = (A.indexOf(i))%4;
if(A.elementAt(i) > 0) {
result += Math.abs(x_def - x_goal);
result += Math.abs(y_def - y_goal);
}
}
return result;
If my puzzle is:
start = {1,3,0,4,5,2,7,8,9,6,10,11,13,14,15,12}
My solution will be:
[Left, Down, Down, Right, Down, Right, Up, Left, Down, Right, Up, Left, Down, Right]
I know that using Vectors isn't a good choice and my code is "a little" dirty, but I'm going to clean its as soon as I get out of that problem!
Thank you all!
First, I see a bit of confusion in your code with the OPEN and CLOSED queues. The OPEN queue should be the one that manages the priority of the nodes (PriorityQueue). This is not needed for CLOSED, which only stores the visited nodes and their cost (maybe your algorithm will be more efficient changing CLOSED by a HashSet or HashMap to avoid ordering the nodes in CLOSED as well). I can't see in your code how you initialized the OPEN queue, but maybe that is one issue with your implementation of A*.
The other issue I see with your code is that with A*-based algorithms, you need to manage the situation in which you reach a node that is already in OPEN/CLOSED, but with a different cost. This can happen if you visit a node from different parents, or you enter in a loop. The algorithm will not work properly if you are not taking that into account.
If you visit a node that is already in the OPEN queue, and the new node has a lower f-score, you should remove the old node from OPEN and insert the one with the lower cost.
If the node has a higher cost (in OPEN or CLOSED) then you should simply discard that node to avoid loops.
The problem is though, but the state space is finite and the algorithm should finish at some point. I see that your implementation is in Java. Maybe it would be helpful for you if you take a look to the library Hipster4j, which has an implementation of A*, and an example solving the 8-puzzle.
I hope my answer helps. Good luck!
Implement a data type that supports insert an item, delete the item added least recently, and delete a random item. Each operation should take constant expected amortized time per operation and should use space (at most) proportional to the number of items in the data structure.
eg. 1 2 3 4 5 6 -> 1 2 4 5 6
I have already implemented the queue as below, but now I do not know how the delete a random item with amortized time, should I rearrange the array every time when there is a random remove like moving number after the random removed number one slot forward in array? is it a really bad practice? or should I implement the Queue using linked list? but my gut feeling tells me linked list also need average O(n) to reach the random node from the head of the linked list.
public class RandomQueue<Item> implements Iterable<Item> {
Item[] items;
int N;
int first;
int last;
public RandomQueue() {
items = (Item[]) new Object[2];
N = 0;
first = last = 0;
}
public static void main(String[] args) {
RandomQueue<Integer> rd = new RandomQueue<>();
}
public boolean isEmpty() {
return N == 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < N; i++) {
sb.append(items[(first + i) % items.length]).append(" ");
}
return sb.toString();
}
private void resize(int length) {
Item[] temp = (Item[]) new Object[length];
for (int i = 0; i < N; i++) {
temp[i] = items[(first + i) % items.length];
}
items = temp;
first = 0;
last = N;
}
public void enqueue(Item item) {
if (N == items.length)
resize(items.length * 2);
items[last++] = item;
if (last == items.length)
last = 0;
N++;
}
public Item dequeue() {
if (isEmpty())
throw new NoSuchElementException("Queue is empty");
Item first = items[first];
items[first] = null;
N--;
if (first == items.length)
first = 0;
else
first++;
if (N > 0 && N == items.length / 4)
resize(items.length / 2);
return first;
}
}
The key to this problem is that you are not removing a random item from the queue you are creating a queue that excludes a random item. You should have a function in your program that accepts a queue as input and does the following:
Create a second queue that will exclude the random deleted item.
Generate a random number less than or equal to the total length of the first queue.
Create a loop that will remove items from the first queue and add them to the second queue.
If the counter in your loop equals the random number, do not add it to the second queue.
Delete the first queue and return the second queue.
public int bfs(int maxDepth){ //maxDepth = 3 works.. maxDepth = 4 gives me an error
int src = 0;
int dest = 2;
int nodes = arr[src].length - 1;
boolean[] visited = new boolean[nodes + 1];
int i;
int countDepth = 0;
int countPaths = 0;
int element;
queue.add(src);
while(!queue.isEmpty() || countDepth != maxDepth)
{
element = queue.remove();
i = element;
while(i <= nodes)
{
if(arr[element][i] > 0 && visited[i] == false)
{
queue.add(i);
visited[i] = true;
if(arr[i][element] > 0) //if it has two directions
visited[i] = false;
if(element == dest || i == dest)
countPaths++;
}
i++;
}
countDepth++;
}
return countPaths;
}
I'm trying to go 'x' amount of levels deep while counting the # of paths to the destination.
For some reason I keep getting an error:
Exception in thread "main" java.util.NoSuchElementException
at java.util.LinkedList.removeFirst(Unknown Source)
at java.util.LinkedList.remove(Unknown Source)
at Graph.bfs(Graph.java:48)
I don't understand what's going on. It seems to work when I go 3 levels deep but when I change it to 4, it doesn't work.
Change
while(!queue.isEmpty() || countDepth != maxDepth)
to
while(!queue.isEmpty() && countDepth != maxDepth)
Each graph has some maximal depth. It seems, you set maxDepth larger than it's really possible for given graph and your loop tries to continue bfsing even after handling all possible nodes (i.e when queue is empty)
UPDATE
I will try to provide answer to your second question you posted in comments even if given information actually is not enough, so, I will try to be extrasens=)
I guess, you are going to calculate all paths of length=1, of length=2.. length=givenMaxDepth|maxPossibleDepth. I saw queue data structure but I didn't see declaration - are you using the same queue for all function calls? If yes, you should clear queue after each call (best place to call queue.clear() is before return statement).
Also, I see you are using new visited array in each call and it's correct but if you actually using some global visited you also should "clear" visited after each call - in other words fill it with false.
I am learning to use heaps and as an exercise I am trying to write a program using a heap class I have created to sort words. I have read in words from a file and added them to the heap successfully. I am having some trouble figuring out how I can print out a sorted list of the words. From my understanding of how a min-heap works, if I remove from the min/root node they will always be removed in sorted order. So far I have tried out to do a simple for loop but, only half of the heap is being removed.
My Main Attempt
public static void main(String[] args) {
Heap heap = new Heap();
heap = read( heap );
for( int i = 0; i < heap.getSize(); i++){
heap.removeMin();
}
heap.printHeap();
}
This is the remove function in my Heap Class
public Node removeMin(){
Node min = heap.get(0);
int index = heap.size() - 1;
Node last = heap.remove(index);
if( index > 0 ){
heap.set( 0, last );
Node root = heap.get(0);
int end = heap.size() - 1;
index = 0;
boolean done = false;
while(!done){
if(getLCLoc(index) <= end ){
//left exists
Node child = getNodeAt( getLCLoc(index) );
int childLoc = getLCLoc(index);
if( getRCLoc(index) <= end ){
//right exists
if( getNodeAt( getRCLoc(index) ).getData().compareToIgnoreCase( child.getData() ) < 0 ){
child = getNodeAt( getRCLoc(index) );
childLoc = getRCLoc(index);
}
}
if(child.getData().compareToIgnoreCase( root.getData() ) < 0 ){
heap.set( index, child );
index = childLoc;
}else{
done = true;
}
}else{
//no children
done = true;
}
}
heap.set( index, root );
}
return min;
}
I would guess that remove() decreases heap size by 1. So, for each iteration of your loop, you are incrementing i by 1 and decrementing heap size by 1. I would change to a while loop that runs while heapsize >0.