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!
Related
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?
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 recently got interviewed and was asked the following question.
Given an n-ary tree, find the maximum path from root to leaf such that maximum path does not contain values from any two adjacent nodes.
(Another edit: The nodes would only have positive values.)
(Edit from comments: An adjacent node means node that share a direct edge. Because its a tree, it means parent-child. So if I include parent, I can not include child and vice versa.)
For example:
5
/ \
8 10
/ \ / \
1 3 7 9
In the above example, the maximum path without two adjacent would be 14 along the path 5->10->9. I include 5 and 9 in the final sum but not 10 because it would violate the no two adjacent nodes condition.
I suggested the following algorithm. While I was fairly sure about it, my interviewer did not seem confident about it. Hence, I wanted to double check if my algorithm was correct or not. It seemed to work on various test cases I could think of:
For each node X, let F(X) be the maximum sum from root to X without two adjacent values in the maximum sum.
The formula for calculating F(X) = Max(F(parent(X)), val(X) + F(grandParent(X)));
Solution would have been
Solution = Max(F(Leaf Nodes))
This was roughly the code I came up with:
class Node
{
int coins;
List<Node> edges;
public Node(int coins, List<Node> edges)
{
this.coins = coins;
this.edges = edges;
}
}
class Tree
{
int maxPath = Integer.MIN_VALUE;
private boolean isLeafNode(Node node)
{
int size = node.edges.size();
for(int i = 0; i < size; i++)
{
if(node.edges.get(i) != null)
return false;
}
return true;
}
// previous[0] = max value obtained from parent
// previous[1] = max value obtained from grandparent
private void helper(Node node, int[] previous)
{
int max = Math.max(previous[0], max.val + previous[1]);
//leaf node
if(isLeafNode(node))
{
maxPath = Math.max(maxPath, max);
return;
}
int[] temp= new int[2];
temp[0] = max;
temp[1] = prev[0];
for(int i = 0; i < node.edges.size(); i++)
{
if(node.edges.get(i) != null)
{
helper(node.edges.get(i), temp);
}
}
}
public int findMax(Node node)
{
int[] prev = new int[2];
prev[0] = 0;
prev[1] = 0;
if(node == null) return 0;
helper(node, prev);
return maxPath;
}
}
Edit: Forgot to mention that my primary purpose in asking this question is to know if my algorithm was correct rather than ask for a new algorithm.
Edit: I have a reason to believe that my algorithm should also have worked.
I was scouring the internet for similar questions and came across this question:
https://leetcode.com/problems/house-robber/?tab=Description
It is pretty similar to the problem above except that it is now an array instead of the tree.
The formal F(X) = Max(F(X-1), a[x] + F(X-2)) works in this case.
Here is my accepted code:
public class Solution {
public int rob(int[] nums) {
int[] dp = new int[nums.length];
if(nums.length < 1) return 0;
dp[0] = nums[0];
if(nums.length < 2) return nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < nums.length; i++)
{
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
}
return dp[nums.length-1];
}
}
The natural solution would be to compute for each node X two values: max path from X to leaf including X and max path from X to leaf, excluding X, let's call them MaxPath(X) and MaxExcluded(X).
For leaf L MaxPath(L) is Value(L) and MaxExcluded(L) is 0.
For internal node X:
MaxPath(X) = Value(X) + Max over child Y of: MaxExcluded(Y)
MaxExcluded(X) = Max over child Y of : Max(MaxExcluded(Y), MaxPath(Y))
The first line means that if you include X, you have to exclude its children. The second means that if you exclude X, you are free to either include or exclude its children.
It's a simple recursive function on nodes which can be computed going leaves-to-parents in O(size of the tree).
Edit: The recursive relation does also work top-down, and in this case you can indeed eliminate storing two values by the observation that MaxExcluded(Y) is actually MaxPath(Parent(Y)), which gives the solution given in the question.
Implementation of what #RafaĆDowgird explained.
/* 5
* 8 10
* 1 3 7 9
* 4 5 6 11 13 14 3 4
*
*
*/
public class app1 {
public static void main(String[] args) {
Node root = new Node(5);
root.left = new Node(8);root.right = new Node(10);
root.left.left = new Node(1);root.left.right = new Node(3);
root.right.left = new Node(7);root.right.right = new Node(9);
root.left.left.left = new Node(4);root.left.left.right = new Node(5);
root.left.right.left = new Node(6);root.left.right.right = new Node(11);
root.right.left.left = new Node(13);root.right.left.right = new Node(14);
root.right.right.right = new Node(4);
System.out.println(findMaxPath(root));
}
private static int findMaxPath(Node root) {
if (root == null) return 0;
int maxInclude = root.data + findMaxPathExcluded(root);
int maxExcludeLeft = Math.max(findMaxPath(root.left), findMaxPathExcluded(root.left));
int maxExcludeRight = Math.max(findMaxPath(root.right), findMaxPathExcluded(root.right));
return Math.max(maxInclude, Math.max(maxExcludeLeft, maxExcludeRight));
}
private static int findMaxPathExcluded(Node root) {
if(root == null) return 0;
int left1 = root.left!=null ? findMaxPath(root.left.left) : 0;
int right1 = root.left!=null ? findMaxPath(root.left.right) : 0;
int left2 = root.right!=null ? findMaxPath(root.right.left) : 0;
int right2 = root.right!=null ? findMaxPath(root.right.right) : 0;
return Math.max(left1, Math.max(right1, Math.max(left2, right2)));
}
}
class Node{
int data;
Node left;
Node right;
Node(int data){
this.data=data;
}
}
I need to write a metod that goes over a sorted singly linked list and returns
the number that appears the most times but goes over the list only one time.
Can someone point me in the right direction?
Can't find an elegent solution yet, should I use recursion?
I want the code to be as efficient as possible.
Thanks in advance.
You may use HashMap<index,count>
traverse linked list
if you find same number then incr count
at last check which count is great and return its index.
public int findMoreRecurrentValue(List<Integer> sortedList) {
if(sortedList.size() == 0) return -1;
int mostRecurrent = -1;
int nReccurrences = 0;
int n = 1;
int current = sortedList.get(0);
for(int i = 1; i < sortedList.size(); ++i) {
if(sortedList.get(i) == current)
++n;
else {
if(n > nReccurrences) {
mostRecurrent = current;
nReccurrences = n;
}
current = sortedList.get(i);
n = 1;
}
}
// Check again at the end, the most reccurrent value could be the last one.
if(n > nReccurrences) {
mostRecurrent = current;
nReccurrences = n;
}
return mostRecurrent;
}
I am working on the project with handling a singleton class that is a list of boat. I am working on an activity that will show the longest boat. I want to try using bubble sort to sort the list by its longest boat. The app runs, but then it stop working when I press the button for showing the longest boat. Could anyone help me?
public void showLongBoat(View view)
{
//Declare references
BoatList boat_list;
TextView tv;
int i;
int x = 0;
boolean found;
int num_items;
int visit = 0;
boolean exchange_value;
int last_item;
int temp;
int a = 0;
int b;
//Set references. Access the list.
boat_list = BoatList.getInstance();
tv = (TextView) findViewById(R.id.text_main);
//Get the number of items in the list
num_items = boat_list.size();
//Find the longest boat
i = 0;
found = false;
while(!found && (i < boat_list.size()))
{
//If num_item is 0 or 1, then do not sort. Otherwise, do sorting
if(num_items > 1)
{
//Set the number of values to visit on the first pass
visit = num_items - 1;
}
do
{
//No exchange or swapping of item was made, so set the exchange to false
exchange_value = false;
//Set the index for the last item to visit
last_item = visit - 1;
for(x = 0; x <= last_item; x++)
{
if(boat_list.get(x).getLength() > boat_list.get(x).getLength() + 1)
{
//Swap the item
temp = a;
a = boat_list.get(x).getLength() + 1;
b = temp;
exchange_value = true;
}
}
visit--;
}while(exchange_value && (visit > 0)); //end sort
}
if(found)
{
boat_list.get(x).getLength();
tv.append("Longest Boat is: ");
}
else
{
Toast.makeText(ShowLongBoatActivity.this, "Error: Cannot find the longest boat successfully!",
Toast.LENGTH_SHORT).show();
}
} //end of showLongBoat
This is a infinite loop, as you don't modify found,i or the list size inside the loop:
while(!found && (i < boat_list.size()))
You don't need 3 loops in your code. If you only want the longest boat, iterate over the boats one time and take the maximum it's enough. If you want to make the sort, using a bubble sort algorithm, the biggest element will be at the end after sorting.