Related
I am trying to implement a 2 dimensional matrix as a maze. There is a starting point, an ending point (randomly chosen). And to make it little complicated, there are obstacles and agents. If the rat runs into an obstacle, it should backtrack and find the correct path. If it runs into an agent, it gets destroyed.
Here's a sample 4x4 matrix
1 7 1 1
2 1 1 0
1 0 1 0
1 1 1 9
Key: 0 is an obstacle, 2 is an agent, 7 is the starting point, 9 is the goal/ending point. 1 means that is is safe to move there.
The correct solution for this matrix would be:
0 1 1 0
0 0 1 0
0 0 1 0
0 0 1 1
But the rat is not intelligent (at least for this program) , so I am implementing a brute force algorithm, with random moves.
I have tried to implement this using a recursive function called mazeUtil().
Below is the function:
maze[][] is the randomized initial matrix that the rat moves through.
solution[][] is the solution matrix that will keep track of the moves.
(x, y) is the current position in the grid
n is the size of the matrix (it is a square matrix).
public static void mazeUtil(int maze[][], int solution[][], int x, int y, int n)
{
if(x == goal[0] && y == goal[1])
{
solution[x][y] = 1;
return;
}
int check = moveCheck(maze, x, y, n);
//moveCheck() return 0 for Obstacle, 1 for safe path, 2 for agent, 7 for starting point (also safe path), 9 for goal (safe path)
if (check == 2){
solution[x][y] = 1;
out.println("Oops! Ran into an agent!");
return;
}
else if(check == 0)
{
//What should I put here?
}
else if(check == 1 || check == 7 || check == 9)
{
solution[x][y] = 1;
Random newRandom = new Random();
int temp = newRandom.nextInt(3);
if(temp == 0){ //move up if possible? x--
if(x > 0)
mazeUtil(maze, solution, x-1, y, n);
else
mazeUtil(maze, solution, x+1, y, n);
}
else if (temp == 1){
if (x < n-1)
mazeUtil(maze, solution, x+1, y, n);
else
mazeUtil(maze, solution, x-1, y, n);
}
else if(temp == 2){
if (y < n-1)
mazeUtil(maze, solution, x, y+1, n);
else
mazeUtil(maze, solution, x,y-1, n);
}
else if (temp == 3){
if (y > 0)
mazeUtil(maze, solution, x, y-1, n);
else
mazeUtil(maze, solution, x, y+1, n);
}
}
}
I have to randomize the moves and that's why i have used random function. My function works quite well if it runs into an agent (2). I have also prevented the rat from going out of boundary. And it doesn't have any problem going through the safe path (1). But the problem is when it hits an obstacle. I'm thinking about backtracking. How do I add that into my function? Like save the last step, and do the reverse? And it is quite possible that there is no solution in the maze like this one
7 0 0 9
2 0 1 1
0 1 0 0
1 2 0 1
It would hit an obstacle if it goes right, and hit an agent if it goes down. It cannot move diagonally.
That brings me to my second question, how would I terminate my recursive function in that case.
At this point the only time it terminates is when it reaches the goal or hits an agent.
Any help would be appreciated. Thanks in advance
Well, let's imagine I need to solve the same problem by the same way you are solving it.
(I think the best solution for it is Path finding, as already mentioned in comments).
I will create
class Point{
public int x;
public int y;
}
and store coordinates in it.
I will store all points the rat visited in List<Point> path
In this solution you do not have problems with previous point (it is the last point in list)
As for algorithm termination -- you use algorithm with randoms. So you can't be sure that your rat will solve the simplest maze like
7 1 1
1 1 1
1 1 1
it is possible that rat will move from (0,0) to (1,0) and from (1,0) to (0,0) forever.
So, let's again imagine that I need to improve your algorithm instead of using good one.
I will store number of times the rat returned back from obstacle or visited the point in path list.
If this number > 4 I will command to my rat return back to the original point (point 7). And start the journey again.
If the rat need to return back, for example 10 times, the algorithm terminates.
Again, your algorithm is funny, and it should be interesting to see how the rat moves but it does not solve the problem. It will not work on big mazes.
Try to implement path finding. If you will have problems -- ask questions.
Good luck!
A quick point on style, to save some typing later: maze[][], solution[][] and n are all effectively global, and do not change between recursive calls (maze and solution are just passed as references to the same arrays, and n never changes). This is purely style, but you can write this as:
private static int[][] maze;
private static int[][] solution;
private static int n;
public static void mazeUtil(int x, int y) {
...
}
So on to your solution: the first point is I don't see how you know when you've reached the goal; your mazeUtil function does not return anything. For this kind of recursion, a general approach is for your solver function to return a boolean: true if the goal has been reached and false if not. Once you get a true, you just pass it back all the way up the call stack. Each time you get a false, you backtrack to the next solution.
So I'd suggest:
public static boolean mazeUtil(int x, int y) {
// return true if goal found, false otherwise
...
}
Next, I'm not sure what the practical difference between an agent and an obstacle is: running in to either causes you to backtrack. So I'd think that bit of code would be:
if (check == 2) {
out.println("Oops! Ran into an agent!");
return false;
}
if (check == 0)
out.println("Oops! Ran into an obstacle!");
return false;
}
Then the recursive bit: one point here is you do not ever reset the solution to 0 for failed attempts (actually, as the final algorithm will never backtrack more than a single step this is not actually that important, but it's good to illustrate the general approach). Given what we have so far, this should now be something like:
if (check == 9) {
out.println("Found the goal!");
return true;
}
if (check == 1 || check == 7) {
// add current position to solution
solution[x][y] = 1;
// generate random move within bounds
int nextX = ...
int nextY = ...
if (mazeUtil(nextX, nextY)) {
// we've found the solution, so just return up the call stack
return true;
}
// this attempt failed, so reset the solution array before returning
solution[x][y] = 0;
return false;
}
// shouldn't ever get here...
throw new IllegalStateException("moveCheck returned unexpected value: " + check);
Right, so far so good, but there's still a problem. As soon as one of the mazeUtil calls returns a value (either true or false) it will return that all the way up the calls stack. So if you happen to find the exit before an agent or an obstacle, all good, but that's quite unlikely. So instead of trying a single move when recursing, you need to try all possible moves.
WIth a supporting class Point, containing a simple x and y pair:
if (check == 1 || check == 7) {
// add current position to solution
solution[x][y] = 1;
// generate an array of all up/down/left/right points that are within bounds
// - for a random path need to randomise the order of the points
Point[] points = ...
for (Point next : points) {
if (mazeUtil(next.x, next.y)) {
// we've found the solution, so just return up the call stack
return true;
}
}
// this attempt failed, so reset the solution array before returning
solution[x][y] = 0;
return false;
}
And I think that's about as far as you can go with a totally ignorant rat! To see how this works, consider the following maze:
7 1
0 9
Starting at "7", possible moves are Down and Right.
If you try Down first, it returns false, so the only option left is
Right, so you end up on the "1".
If you try Right first, you still end up on the "1".
From the "1", possible moves are Down and Left:
If you try Down first, it returns true, which bubbles up the call stack - success!
If you try Left first, you end up on the "7", so recurse to the previous step.
And that's all that can ever happen. So using * for a return-false-backtrack, and ! for a success, any of the following are possible:
R-D!
R-L-D*-R-D!
R-L-R-L-R-L-R-L (keep going for a long, long time....) R-L-R-D!
So for a solvable maze, and a truly random generator, this will eventually solve the maze, although it could take a very long time. Something to note with this though, is it does not really backtrack that much: only ever a single step from a 2 or 0 node.
However, there's still the problem of the unsolveable maze, and I don't think that is possible given a totally ignorant rat. The reason for this is that for a brute force recursion like this, there are only two possible termination conditions:
The goal has been found.
All possible paths have been tried.
And with a totally ignorant rat, there is no way to detect the second!
Consider the following maze:
7 1 1 1
0 0 0 0
0 0 0 0
1 1 1 9
The totally ignorant rat will just wander left and right across the top row forever, and so the program will never terminate!
The solution to this is that the rat must be at least a bit intelligent, and remember where it has been (which will also make the solveable maze run quicker in most cases and backtrack along entire paths instead of only for single nodes). However, this answer is getting a bit too long already, so if you're interested in that I'll refer you to my other maze-solving answer here: Java Recursive Maze Solver problems
Oh, just two final points on Random:
You don't need to create a new Random each time - just create a
global one and call nextInt each time.
nextInt(n) returns between 0 (inclusive) and n (exclusive), so you
need nextInt(4) not nextInt(3).
Hope this all helps!
if you want to move in random, u need to know the states you've been already in them, so u will need a tree, otherwise u can keep the most left path when the rat is in multi way place.
now lets think of recursive + random. it can not be that hard. you can have a function that returns the list of points it has been in them, and get correct position as input, there is a bit of problem and the idiot rat can got back the way he already came from, so lets solve it with adding previous point as another input for our function.
every thing in place. now we wana know if the idiot rat runs into a dead path or an agent. how about making 2 exceptions for this situations and handling them in recursive function??
well, i don't think there will be any more problems on way. actually i'm temped to try it myselft. that would be fun :D
good luck with the idiot rat
I'd like to do some analysis of your algorithm design before proposing a solution.
You mention that you want to use a random walk algorithm. No problem with that it's a perfectly acceptable (though not necessarily efficient) way to look for a path. However you need to be aware that it has some implications.
In general random walk will not tell you when there is no solution. If you just keep trying paths at random you will never exhaust the search tree.
If this is unacceptable (i.e. it needs to be able to halt when there is no soltuion) then you need to keep a record of paths already attempted and randomise only those not yet attempted.
Random walk won't necessarily find the optimal solution unless there is only one solution. In other words if there are loops / multiple paths in your maze then there's no guarantee you are finding the fastest.
I can't actually see the difference between agents and obstacles in your problem. In both cases you need to backtrack and find another path. If there is a difference then you'll need to point it out.
So assuming your maze could have zero or more successful paths and you are not looking for the optimal path (in which case you really should use A* or similar), the structure of a solution should look something like:
public List<Position> findPath(Set<Position> closedSet, Position from, Position to) {
if (from.equals(to))
return List.of(to);
while (from.hasNeighboursNotIn(closedSet)) {
Position pos = from.getRandomNeighbourNotIn(closedSet);
closedSet.add(pos);
List<Position> path = findPath(closedSet, pos, to);
if (!path.isEmpty())
return List.of(pos, path);
}
closedSet.add(from);
return Collection.EMPTY_LIST;
}
This uses lots of pseudo-code (e.g. there is no List.of(item, list)) but you get the idea.
I have to code a recursive method that iterates through a linked list and returns the number of integers that are positive. Here is the question:
The method countPos below must be a recursive method that takes a Node head
as its argument, goes down the list headed by head, and counts the number of nodes which have a positive data field.
The code I have works however, I don't understand how it works.
public int countPos(Node head) {
int count = 0;
if (head == null) { return count; }
if (head.data > 0) {
count++;
return count + countPos(head.next);
} else {
return count + countPos(head.next);
}
}
The problem I'm having is I don't understand how count doesn't get set back to 0 every time the method is called. For some reason the statement int count = 0; is ignored the next time the method gets called. Is this because I'm returning count also? Any explanation would be greatly appreciated.
Thanks.
DON'T begin by tracing execution or debugging. The power of recursion is that it lets you reason about complicated programs with simple logic.
Your code works by chance. It reflects that whoever wrote it (you?) doesn't understand how recursion solves problems. It's more complex than necessary.
To exploit recursion, take the problem at hand and:
Define the function interface.
Split the problem into parts, at least one of which is a smaller version of the same problem.
Solve that (or those) smaller version(s) by calling the function interface itself.
Find the "base case" or cases that are solutions to very small instances of the same problem.
With all this done, the pseudocode for most recursive algorithms is:
function foo(args)
if args describe a base case
return the base case answer.
solve the smaller problem or problems by calling foo with
args that describe the smaller problem!
use the smaller problem solution(s) to get the answer for this set of args
return that answer
end
Let's apply this to your case:
PROBLEM: Count the number of positive items in a list.
Define the function interface: int countPos(Node head).
Split the problem up into parts: Get the number of positives in the list remaining after the head, then add one if the head is positive and nothing if the head is zero or negative.
The smaller version of the problem is finding the number of positives in the list with head removed: countPos(head.next).
Find the base case: The empty list has zero positives.
Put this all together:
int countPos(Node head) {
// Take care of the base case first.
if (head == null) return 0;
// Solve the smaller problem.
int positiveCountWithoutHead = countPos(head.next);
// Now the logic in step 2. Return either the positive count or 1+ the positive count:
return head.data > 0 ? positiveCountWithoutHead + 1 : positiveCountWithoutHead;
}
You might learn a little bit by tracing execution of something like this one time. But trying to write recursive code by reasoning about what's going on with the stack is a dead end. To be successful, you must think at a higher level.
Let's try one that doesn't quite follow the standard template: Recursive binary search. We have an array a of integers and are trying to find the index of x if it exists in the array and return -1 if not.
PROBLEM: Search the array between positions i0 and i1-1.
(The above is an example of how you must sometimes "specialize" the problem by adding parameters so that smaller subproblems can be described in the recursive call or calls. Here we are adding the new parameters i0 and i1 so that we can specify a subarray of a. Knowing how and when to do this is a matter of practice. The parameters needed can vary with language features.)
Function interface: int search(int [] a, int x, int i0, int i1)
Split the problem in parts: We'll pick a "middle" element index: mid = (i0 + i1) / 2. Then the subproblem is either searching the first half of the array up to but excluding mid or the second half of the array starting after mid and continuing to the end.
The calls are search(a, x, i0, mid) and search(a, x, mid + 1, i1).
The base cases are that 1) if i0 >= i1, there are no elements to search, so return -1 and 2) if we have a[mid] == x, then we've found x and can return mid.
Putting this all together
int search(int [] a, int x, int i0, int i1) {
// Take care of one base case.
if (i0 >= i1) return -1;
// Set up mid and take care of the other base case.
int mid = (i0 + i1) / 2;
if (a[mid] == x) return mid;
// Solve one or the other subproblems. They're both smaller!
return x < a[mid] ? search(a, x, i0, mid) : search(a, x, mid + 1, i1);
}
And to start the search:
int search(int [] a, int x) { return search(a, x, 0, a.length); }
Each time you call countPos(), a new version of that function starts. This function starts from a clean slate meaning all of the local variables (count) are its own, and no other "copy" of countPos can see or modify its local variables.
The only state that is passed between these "copies" or of countPos is the variables that are passed in as parameters (Node head).
So here's a rough workflow assuming the list [1, -2, 3]
countPos starts, and says number of positive nodes is equal to 1, since "1" is positive. The total number of positive nodes is equal to 1 + whatever the next function returns.
The next function says the number of positive nodes is equal to 0 + whatever the next function returns.
The next function says the number of positive nodes is equal to 1 + whatever the next function returns
The next function sees that head == null and so returns 0.
Now each recursive function returns one after another to the original function that called it, with the total number of positive nodes "snowballing" as we return.
The total number returned in the end will be 2.
I have just started my long path to becoming a better coder on CodeChef. People begin with the problems marked 'Easy' and I have done the same.
The Problem
The problem statement defines the following -:
n, where 1 <= n <= 10^9. This is the integer which Johnny is keeping secret.
k, where 1 <= k <= 10^5. For each test case or instance of the game, Johnny provides exactly k hints to Alice.
A hint is of the form op num Yes/No, where -
op is an operator from <, >, =.
num is an integer, again satisfying 1 <= num <= 10^9.
Yes or No are answers to the question: Does the relation n op num hold?
If the answer to the question is correct, Johnny has uttered a truth. Otherwise, he is lying.
Each hint is fed to the program and the program determines whether it is the truth or possibly a lie. My job is to find the minimum possible number of lies.
Now CodeChef's Editorial answer uses the concept of segment trees, which I cannot wrap my head around at all. I was wondering if there is an alternative data structure or method to solve this question, maybe a simpler one, considering it is in the 'Easy' category.
This is what I tried -:
class Solution //Represents a test case.
{
HashSet<SolutionObj> set = new HashSet<SolutionObj>(); //To prevent duplicates.
BigInteger max = new BigInteger("100000000"); //Max range.
BigInteger min = new BigInteger("1"); //Min range.
int lies = 0; //Lies counter.
void addHint(String s)
{
String[] vals = s.split(" ");
set.add(new SolutionObj(vals[0], vals[1], vals[2]));
}
void testHints()
{
for(SolutionObj obj : set)
{
//Given number is not in range. Lie.
if(obj.bg.compareTo(min) == -1 || obj.bg.compareTo(max) == 1)
{
lies++;
continue;
}
if(obj.yesno)
{
if(obj.operator.equals("<"))
{
max = new BigInteger(obj.bg.toString()); //Change max value
}
else if(obj.operator.equals(">"))
{
min = new BigInteger(obj.bg.toString()); //Change min value
}
}
else
{
//Still to think of this portion.
}
}
}
}
class SolutionObj //Represents a single hint.
{
String operator;
BigInteger bg;
boolean yesno;
SolutionObj(String op, String integer, String yesno)
{
operator = op;
bg = new BigInteger(integer);
if(yesno.toLowerCase().equals("yes"))
this.yesno = true;
else
this.yesno = false;
}
#Override
public boolean equals(Object o)
{
if(o instanceof SolutionObj)
{
SolutionObj s = (SolutionObj) o; //Make the cast
if(this.yesno == s.yesno && this.bg.equals(s.bg)
&& this.operator.equals(s.operator))
return true;
}
return false;
}
#Override
public int hashCode()
{
return this.bg.intValue();
}
}
Obviously this partial solution is incorrect, save for the range check that I have done before entering the if(obj.yesno) portion. I was thinking of updating the range according to the hints provided, but that approach has not borne fruit. How should I be approaching this problem, apart from using segment trees?
Consider the following approach, which may be easier to understand. Picture the 1d axis of integers, and place on it the k hints. Every hint can be regarded as '(' or ')' or '=' (greater than, less than or equal, respectively).
Example:
-----(---)-------(--=-----)-----------)
Now, the true value is somewhere on one of the 40 values of this axis, but actually only 8 segments are interesting to check, since anywhere inside a segment the number of true/false hints remains the same.
That means you can scan the hints according to their ordering on the axis, and maintain a counter of the true hints at that point.
In the example above it goes like this:
segment counter
-----------------------
-----( 3
--- 4
)-------( 3
-- 4
= 5 <---maximum
----- 4
)----------- 3
) 2
This algorithm only requires to sort the k hints and then scan them. It's near linear in k (O(k*log k), with no dependance on n), therefore it should have a reasonable running time.
Notes:
1) In practice the hints may have non-distinct positions, so you'll have to handle all hints of the same type on the same position together.
2) If you need to return the minimum set of lies, then you should maintain a set rather than a counter. That shouldn't have an effect on the time complexity if you use a hash set.
Calculate the number of lies if the target number = 1 (store this in a variable lies).
Let target = 1.
Sort and group the statements by their respective values.
Iterate through the statements.
Update target to the current statement group's value. Update lies according to how many of those statements would become either true or false.
Then update target to that value + 1 (Why do this? Consider when you have > 5 and < 7 - 6 may be the best value) and update lies appropriately (skip this step if the next statement group's value is this value).
Return the minimum value for lies.
Running time:
O(k) for the initial calculation.
O(k log k) for the sort.
O(k) for the iteration.
O(k log k) total.
My idea for this problem is similar to how Eyal Schneider view it. Denoting '>' as greater, '<' as less than and '=' as equals, we can sort all the 'hints' by their num and scan through all the interesting points one by one.
For each point, we keep in all the number of '<' and '=' from 0 to that point (in one array called int[]lessAndEqual), number of '>' and '=' from that point onward (in one array called int[]greaterAndEqual). We can easily see that the number of lies in a particular point i is equal to
lessAndEqual[i] + greaterAndEqual[i + 1]
We can easily fill the lessAndEqual and greaterAndEqual arrays by two scan in O(n) and sort all the hints in O(nlogn), which result the time complexity is O(nlogn)
Note: special treatment should be taken for the case when the num in hint is equals. Also notice that the range for num is 10^9, which require us to have some forms of point compression to fit the array into the memory
This question is quite a long shot. It could take quite long, so if you haven't the time I understand.
Let me start by explaining what I want to achieve:
Me and some friends play this math game where we get 6 random numbers out of a pool of possible numbers: 1 to 10, 25, 50, 75 and 100. 6 numbers are chosen out of these and no duplicates are allowed. Then a goal number will be chosen in the range of [100, 999]. With the 6 aforementioned numbers, we can use only basic operations (addition, subtraction, multiplication and division) to reach the goal. Only integers are allowed and not all 6 integers are required to reach the solution.
An example: We start with the numbers 4,8,6,9,25,100 and need to find 328.
A possible solution would be: ((4 x 100) - (9 x 8)) = 400 - 72 = 328. With this, I have only used 4 out of the 6 initial numbers and none of the numbers have been used twice. This is a valid solution.
We don't always find a solution on our own, that's why I figured a program would be useful. I have written a program (in Java) which has been tested a few times throughout and it had worked. It did not always give all the possible solutions, but it worked within its own limitations. Now I've tried to expand it so all the solutions would show.
On to the main problem:
The program that I am trying to execute is running incredibly long. As in, I would let it run for 15 minutes and it doesn't look like it's anywhere near completion. So I thought about it and the options are indeed quite endless. I start with 6 numbers, I compare the first with the other 5, then the second with the other 5 and so on until I've done this 6 times (and each comparison I compare with every operator, so 4 times again). Out of the original one single state of 6 numbers, I now have 5 times 6 times 4 = 120 states (with 5 numbers each). All of these have to undergo the same ritual, so it's no wonder it's taking so long.
The program is actually too big to list here, so I will upload it for those interested:
http://www.speedyshare.com/ksT43/MathGame3.jar
(Click on the MathGame3.jar title right next to download)
Here's the general rundown on what happens:
-6 integers + goal number are initialized
-I use the class StateNumbers that are acting as game states
-> in this class the remaining numbers (initially the 6 starting numbers)
are kept as well as the evaluated expressions, for printing purposes
This method is where the main operations happen:
StateNumbers stateInProcess = getStates().remove(0);
ArrayList<Integer> remainingNumbers = stateInProcess.getRemainingNumbers();
for(int j = 0; j < remainingNumbers.size(); j++){
for(int i = 0; i < remainingNumbers.size(); i++){
for(Operator op : Operator.values()){ // Looping over different operators
if(i == j) continue;
...
}
}
}
I evaluate for the first element all the possible operations with all the remaining numbers for that state. I then check with a self written equals to see if it's already in the arraylist of states (which acts as a queue, but the order is not of importance). If it's not there, then the state will be added to the list and then I do the same for the other elements. After that I discard the state and pick another out of the growing list.
The list grows in size to 80k states in 10 minutes and grows slower and slower. That's because there is an increasing amount of states to compare to when I want to add a new state. It's making me wonder if comparing with other states to prevent duplicates is such a good idea.
The completion of this program is not really that important, but I'd like to see it as a learning experience. I'm not asking anyone to write the code for me, but a friendly suggestion on what I could have handled better would be very much appreciated. This means if you have something you'd like to mention about another aspect of the program, please do. I'm unsure if this is too much to ask for on this forum as most topics handle a specific part of a program. While my question is specific as well, the causes could be many.
EDIT: I'm not trying to find the fastest single solution, but every solution. So if I find a solution, my program will not stop. It will however try to ignore doubles like:
((4+5)7) and (7(5+4)). Only one of the two is accepted because the equals method in addition and multiplication do not care about the positioning of the operands.
It would probably be easier to write this using recursion, i.e. a depth-first search, as this would simplify the bookkeeping for intermediary states.
If you want to keep a breath-first approach, make sure that the list of states supports efficient removal of the first element, i.e. use a java.util.Queue such as java.util.ArrayDeque. I mention this because the most frequently used List implementation (i.e. java.util.ArrayList) needs to copy its entire contents to remove the first element, which makes removing the first element very expensive if the list is large.
120 states (with 5 numbers each). All of these have to undergo the same ritual, so it's no wonder it's taking so long.
Actually, it is quite surprising that it would. After all, a 2GHz CPU performs 2 billion clock cycles per second. Even if checking a state were to take as many as 100 clock cycles, that would still mean 20 million states per second!
On the other hand, if I understand the rules of the game correctly, the set of candidate solutions is given by all orderings of the 6 numbers (of which there are 6! = 720), with one of 4 operators in the 5 spaces in between, and a defined evaluation order of the operators. That is, we have a total of 6! * 4^5 * 5! = 88 473 600 candidate solutions, so processing should complete in a couple of seconds.
PS: A full solution would probably not be very time-consuming to write, so if you wish, I can also postcode - I just didn't want to spoil your learning experience.
Update: I have written the code. It was harder than I thought, as the requirement to find all solutions implies that we need to print a solution without unwinding the stack. I, therefore, kept the history for each state on the heap. After testing, I wasn't quite happy with the performance (about 10 seconds), so I added memoization, i.e. each set of numbers is only processed once. With that, the runtime dropped to about 3 seconds.
As Stackoverflow doesn't have a spoiler tag, I increased the indentation so you have to scroll right to see anything :-)
package katas.countdown;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
enum Operator {
plus("+", true),
minus("-", false),
multiply("*", true),
divide("/", false);
final String sign;
final boolean commutes;
Operator(String sign, boolean commutes) {
this.sign = sign;
this.commutes = commutes;
}
int apply(int left, int right) {
switch (this) {
case plus:
return left + right;
case minus:
return left - right;
case multiply:
return left * right;
case divide:
int mod = left % right;
if (mod == 0) {
return left / right;
} else {
throw new ArithmeticException();
}
}
throw new AssertionError(this);
}
#Override
public String toString() {
return sign;
}
}
class Expression implements Comparable<Expression> {
final int value;
Expression(int value) {
this.value = value;
}
#Override
public int compareTo(Expression o) {
return value - o.value;
}
#Override
public int hashCode() {
return value;
}
#Override
public boolean equals(Object obj) {
return value == ((Expression) obj).value;
}
#Override
public String toString() {
return Integer.toString(value);
}
}
class OperationExpression extends Expression {
final Expression left;
final Operator operator;
final Expression right;
OperationExpression(Expression left, Operator operator, Expression right) {
super(operator.apply(left.value, right.value));
this.left = left;
this.operator = operator;
this.right = right;
}
#Override
public String toString() {
return "(" + left + " " + operator + " " + right + ")";
}
}
class State {
final Expression[] expressions;
State(int... numbers) {
expressions = new Expression[numbers.length];
for (int i = 0; i < numbers.length; i++) {
expressions[i] = new Expression(numbers[i]);
}
}
private State(Expression[] expressions) {
this.expressions = expressions;
}
/**
* #return a new state constructed by removing indices i and j, and adding expr instead
*/
State replace(int i, int j, Expression expr) {
Expression[] exprs = Arrays.copyOf(expressions, expressions.length - 1);
if (i < exprs.length) {
exprs[i] = expr;
if (j < exprs.length) {
exprs[j] = expressions[exprs.length];
}
} else {
exprs[j] = expr;
}
Arrays.sort(exprs);
return new State(exprs);
}
#Override
public boolean equals(Object obj) {
return Arrays.equals(expressions, ((State) obj).expressions);
}
public int hashCode() {
return Arrays.hashCode(expressions);
}
}
public class Solver {
final int goal;
Set<State> visited = new HashSet<>();
public Solver(int goal) {
this.goal = goal;
}
public void solve(State s) {
if (s.expressions.length > 1 && !visited.contains(s)) {
visited.add(s);
for (int i = 0; i < s.expressions.length; i++) {
for (int j = 0; j < s.expressions.length; j++) {
if (i != j) {
Expression left = s.expressions[i];
Expression right = s.expressions[j];
for (Operator op : Operator.values()) {
if (op.commutes && i > j) {
// no need to evaluate the same branch twice
continue;
}
try {
Expression expr = new OperationExpression(left, op, right);
if (expr.value == goal) {
System.out.println(expr);
} else {
solve(s.replace(i, j, expr));
}
} catch (ArithmeticException e) {
continue;
}
}
}
}
}
}
}
public static void main(String[] args) {
new Solver(812).solve(new State(75, 50, 2, 3, 8, 7));
}
}
}
As requested, each solution is reported only once (where two solutions are considered equal if their set of intermediary results is). Per Wikipedia description, not all numbers need to be used. However, there is a small bug left in that such solutions may be reported more than once.
What you're doing is basically a breadth-first search for a solution. This was also my initial idea when I saw the problem, but I would add a few things.
First, the main thing you're doing with your ArrayList is to remove elements from it and test if elements are already present. Since your range is small, I would use a separate HashSet, or BitSet for the second operation.
Second, and more to the point of your question, you could also add the final state to your initial points, and search backward as well. Since all your operations have inverses (addition and subtraction, multiplication and division), you can do this. With the Set idea above, you would effectively halve the number of states you need to visit (this trick is known as meet-in-the-middle).
Other small things would be:
Don't divide unless your resulting number is an integer
Don't add a number outside the range (so >999) into your set/queue
The total number of states is 999 (the number of integers between 1 and 999 inclusive), so you shouldn't really run into performance issues here. I'm thinking your biggest drain is that you're testing inclusion in an ArrayList which is O(n).
Hope this helps!
EDIT: Just noticed this. You say you check whether a number is already in the list, but then remove it. If you remove it, there's a good chance you're going to add it back again. Use a separate data structure (a Set works perfectly here) to store your visited states, and you should be fine.
EDIT 2: As per other answers and comments (thanks #kutschkem and #meriton), a proper Queue is better for popping elements (constant versus linear for ArrayList). In this case, you have too few states for it to be noticeable, but use either a LinkedList or ArrayDeque when you do a BFS.
Updated answer to solve Countdown
Sorry for my misunderstandings before. To solve countdown, you can do something like this:
Suppose your 6 initial numbers are a1, a2, ..., a6, and your target number is T. You want to check whether there is a way to assign operators o1, o2, ..., o5 such that
a1 o1 a2 ... o5 a6 = T
There are 5 operators, each can take one of 4 values, so there are 4 ^ 5 = 2 ^ 10 possibilities. You can use less than the entire 6, but if you build your solution recursively, you will have checked all of them at the end (more on this later). The 6 initial numbers can also be permuted in 6! = 720 ways, which leads to a total number of solutions of 2 ^ 10 * 6! which is roughly 720,000.
Since this is small, what I would do is loop through every permutation of the initial 6 numbers, and try to assign the operators recursively. For that, define a function
void solve(int result, int index, List<Integer> permutation)
where result is the value of the computation so far, and index is the index in the permutation list. You then loop over every operator and call
solve(result op permutation.get(index), index + 1, permutation)
If at any point you find a solution, check to see if you haven't found it before, and add it if not.
Apologies for being so dense before. I hope this is more to the point.
Your problem is analogous to a Coin Change Problem. First do all of the combinations of subtractions so that you can have your 'unit denomination coins' which should be all of the subtractions and additions, as well as the normal numbers you are given. Then use a change making algorithm to get to the number you want. Since we did subtractions beforehand, the result may not be exactly what you want but it should be close and a lot faster than what you are doing.
Say we are given the 6 numbers as the set S = {1, 5, 10, 25, 50, 75, 100}. We then do all the combinations of subtractions and additions and add them to S i.e. {-99, -95, -90,..., 1, 5, 10,..., 101, 105,...}. Now we use a coin change algorithm with the elements of S as the denominations. If we do not get a solution then it is not solvable.
There are many ways to solve the coin change problem, a few are discussed here:
AlgorithmBasics-examples.pdf
I'm taking an online class so there isn't any help from the teachers or other classmates. Our assignment is that we need to find the max value and index of an array of random numbers. We need to do it in two ways. A regualr loop(brute force) and divide and conquer. In the divide and conquer we need to split the array into two smaller arrays and find the max of both and then merge.
I got the brute force to work and I got the divide and conqure to find the max also. But I can't seem to get the max of the two smaller arrays and merge the two. We also need to check for how many comparison is made by both methods and print the output.
Here's what I have so far:
public class MinMaxValues{
// Find maxiumum (largest) value in array using Divide and Conquer
public static int findMax( int[]numbers, int left, int right )
{
int middle;
int max_l, max_r, max_m;
if ( left == right ) // Only one element...
{
// Base case: solved easily...
return numbers[left];
}
else
{
// Solve smaller problems
middle = (left+right)/2; // Divide into 2 halves
max_l = findMax( numbers, left, middle);
// Find max in first half
max_r = findMax( numbers, middle+1, right);
// Find max in second half
//System.out.println("Maximum Value = " + max_r);
max_m = max_l+ max_r;
// Use the solutions to solve original problem
if ( max_l > max_r )
return(max_l);
else
return(max_r);
//return(max_m);
}
}
}
You are never returning an array.
Also you don't make any changes to the array.
You must change the array in some way once you find the max.
Try wrapping it with a method.
public static int[] maxSort(int[] array,int length){
int[] sorted = new int[array.length];
sorted[arrayLength]=findmax(array,0,sorted,arrayLength);//assumes find max returns maximum value of entire array.
while(length>0){
sorted=maxsort(array,length--);
}
return sorted;
}
I am not 100% sure it's working by i think it's a step in the right direction.
You need to more carefully address points in your program where you are comparing the index or the value at that index. For example, instead of checking whether max_l > max_r, I believe you mean to be checking whether numbers[max_l] > numbers[max_r].