Java: Recursive sudoku solutions counting algorithm - java

I made Sudoku checker/solver with ease, but I need one that can tell wheter there is more than one solution, and couldn't wrap my head around it. I found a working algorithm, but I'm trying to understand why it's working. It's the answer from this question, provided by #fabian
Copied below:
// returns 0, 1 or more than 1 depending on whether 0, 1 or more than 1 solutions are found
static byte solve(int i, int j, int[][] cells, byte count /*initailly called with 0*/) {
if (i == 9) {
i = 0;
if (++j == 9)
return 1+count;
}
if (cells[i][j] != 0) // skip filled cells
return solve(i+1,j,cells, count);
// search for 2 solutions instead of 1
// break, if 2 solutions are found
for (int val = 1; val <= 9 && count < 2; ++val) {
if (legal(i,j,val,cells)) {
cells[i][j] = val;
// add additional solutions
count = solve(i+1,j,cells, count));
}
}
cells[i][j] = 0; // reset on backtrack
return count;
}
I tried implementing it, and as it should, it works. However though I think I understand what each part of the code does, I cannot get why it works.
First: The first if statement stops the method once the final number in the 2d array is reached. I get this in finding a single solution, but why does it work in finding more than one solution? Shouldn't the method just return 0+1=1 after solution is found?
Second: after if (cells[i][j] != 0) why does the recursive solve(...) call need return statement in front of it? I have made several recursive algorithms, but always by just calling the method again.
Third: If none suitable numbers are found the for loop stops and 0 is inputted to the cell place. Since it should already have 0, shouldn't the backtracking put 0 to the last place instead of current? At least that is how I made the solver that I made myself.
Fourth: After the backtrack set, there is just return count. Why is the program still working? Shouldn't it just return count = 0 and stop after facing first place that doesn't allow any numbers? Howcome there isn't a recursive call at the end?
If you made it this far on this rampling question, it is clear that I'm understanding some things completely wrong. I'd highly appreciate assistance/explanation, since using code one doesn't understand is a complete failure as far as learning to code goes.

Ok, so Google gracefully provided an Powerpoint lecture from Harvard:
http://www.fas.harvard.edu/~cscie119/lectures/recursion.pdf
If someone else is having problems getting recursive backtracking, I recommend checking it out. Very short but informative.
My problem seemed to be only that I stupidly (at least on hindsight) assumed for the method to stop after it calls itself recursively. I forgot that after it gets results from the recursive call it makes, it executes itself to the end. Funny how you can use umphteen hours solving something just because your initial thought process was flawed. Well, live and learn I guess.

Related

What is the best way of detecting whether two strings differ by one one character?

I have this code, but it seems pretty unwieldy. Is there a more canonical way of doing so in Java?
public boolean oneDiff(String from, String s) {
if (from.length()!=s.length()) return false;
int differences = 0;
for (int charIndex = 0;charIndex<from.length();charIndex++) {
if (from.charAt(charIndex)!=s.charAt(charIndex)) differences++;
}
return (differences==1);
}
I agree with #mk. However to minimize the loop execution you should not run the loop till the string ends. Instead you can break the loop as soon as the difference becomes greater than 1. Like this:
for (int charIndex = 0;charIndex<from.length();charIndex++) {
if (from.charAt(charIndex)!=s.charAt(charIndex)) differences++;
if(differences > 1) break;
}
return (differences==1);
This will help in faster execution by loop optimization if this is what you want.
Nope, that really is the best way!
There's nothing built-in because this isn't something you need to do often. The closest trick is doing an xor on two integers, and then getting the Hamming Weight using bitCount, in order to check for how many flipped bits they have in common:
Integer.bitCount(int1 ^ int2)
But there's nothing like that for Strings - it's not a common case, so you have to code your own. And the way you've coded it seems fine - you really do have to loop over every character. I guess you could shorten the variable names and remove the parens around your return, but that's just cosmetic.

fizzbuzz - can it be shorter?

WARNING:I'm not asking for a better code, I'm asking for a shorter code for HackerRank just to learn what can be done to shorten it.
I'm newbie to Java and was trying out this FizzBuzz problem:
Write a program that prints the numbers from 1 to 100. But for multiples of three print >“Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which >are multiples of both three and five print “FizzBuzz”.
I wrote my solution as short as possible.
class Solution{
public static void main(String[]b){
for(int i=1;i<101;i++){
String a=(i%3==0)?(i%5==0)?"FizzBuzz":"Fizz":(i%5==0)?"Buzz":i+"";
System.out.println(a);}}}
and I got a 3.6 score. But obviously there's room to improve because some people wrote it with 27 characters less. How is that possible ? Any suggestions? I don't really care about the ranks, I just wanna know what I'm missing.
EDIT: So with your help, I made it like this:
class Solution{public static void main(String[]b){for(int i=1;i<101;i++){System.out.println((i%3==0)?(i%5==0)?"FizzBuzz":"Fizz":(i%5==0)?"Buzz":i);}}}
and it seems I got rid of 14 characters. God knows what the other people did to lose 13 more characters. Anyway, thanks.
What about something like:
for(int i=0;i++<100;System.out.println((i%3>0?"":"Fizz")+(i%5>0?i%3>0?i:"":"Buzz")))
Warning: this code is just an exercise of trying to make the code shorter. It is neither good or readable as normal code should try to be!
Yes, it is possible to make it even shorter. Proof: According to the leaderboard, the highest score for java is 7.00.
How? Spoiler: identifier(s), parentheses, line breaks, pre/post increment. The conditions may be written as i%3>0 or the opposite like i%3<1.
class S{public static void main(String[]a){for(int i=0;++i<101;)System.out.println(i%3>0?i%5>0?i:"Buzz":"Fizz"+(i%5>0?"":"Buzz"));}}
It may not be getting significantly shorter yet, most likely due to the boilerplate code for main and print method. Based on everything suggested on this QA so far, it is possible to achieve at least 6.90 in Java if not the current max which is 7.00.
For example,
class S{public static void main(String[]a){for(int i=0;++i<101;)System.out.println(i%3>0?i%5>0?i:"Buzz":i%5>0?"Fizz":"FizzBuzz");}}
If we are open to try out other languages, we may wish to try JS with caution/advisory.
Many more approaches have been discussed here and here.
Java, C, C++, C#, Python, Ruby, R, none of the submissions in these languages reached the top score yet which is 16.0. It leads us to the question, which submission led to the top score? The answer is bash scripting. Proof: leaderboard for bash
How? The hint has been kindly provided by the author of the top submission, Byron Formwalt at here.
If we are new to bash scripting, we may wish to get started with few resources mentioned here, here, and here.
Disclaimer: Even though this may be suitable for the purpose of the getting higher score in hackerrank or just for exercise, it may not be a good practice for Best_coding_practices. There are many scopes for improvement in this post. Suggestions are welcome. Acknowledgements/Thanks.
It just becomes an argument to migrate to Kotlin!
fun fizzBuzz(number: Int) = when {
number.divisibleBy(3) and number.divisibleBy(5) -> "Fizz-Buzz"
number.divisibleBy(3) -> "Fizz"
number.divisibleBy(5) -> "Buzz"
else -> number.toString()
}
fun Int.divisibleBy(number: Int) = this % number == 0
fun main() {
(1..100).forEach {
println(fizzBuzz(it))
}
}
function fizzBuzz(n) {
for (i = 1; i <= n; i++) {
let result = "";
if (i % 3 === 0) result += "Fizz";
if (i % 5 === 0) result += "Buzz";
if (i % 7 === 0) result += "Foo";
console.log(result || i);
}
}
fizzBuzz(105);
It will check every condition, if all are true then all will be added together as well as it works with the single true condition as well as two true conditions.

In a Logic When to use For loop and When to use while loop [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I am beginner for the programming language , I am bit confused in the basic of looping concept can any one please tell me clearly when to use the concept of For loop and when to use the while loop so that it would be very grace full for me to my future programming,
Thanks in advance
Generally, you use a for loop if you know (Or the program can know at the time of the loop) how many times you want to run a piece of code, and while loops if you do not.
However, it is possible to use them interchangably, so while it may be a bit less elegant to use one than the other, it doesn't matter too much.
Ex:
for(int i = 0; i < 100; i++){
do stuff
}
is the same as
int i = 0;
while(i < 100){
do stuff
i++;
}
, but the former looks more elegant.
Similarly,
bool condition = false;
while(condition){
do stuff
}
and
for(bool condition = false; condition;){
do stuff
}
are the same, but generally, the while loop is considered more elegant here.
In almost all cases you could use either for or while loops. You are provided with two ways of looping to help reduce the complexity of your code across different use cases.
When to use for loops
For loops are best when you know how many iterations you want to loop before you begin. For example, if you knew you wanted to print the numbers 1 through 10 in order you know you want to loop 10 times.
for(int i = 1; i <= 10; i++)
{
System.out.println(i);
}
When to use while loops
While loops are best when you want to continue looping until a specific event occurs or a condition is met. For example, let's say you wanted to print random numbers between 1 and 10 until you came across the number 5. This may take one iteration or hundreds depending on your luck.
Random rand = new Random();
int value = 0;
while(value != 5)
{
value = rand.nextInt(10);
System.out.println(value);
}
Basically you should use a for loop if you know the number of iterations this loop has to do. Even if that number is a variable (like the length of a list) it is know at runtime.
A while loop is used when you don't know the number of iteration. You mostly check a condition that can evaluate to false after any number.
You also have the do-while and the for-each loops at your disposal. The do-while is used when you know that you have at least one iteration but the number is otherwise unkown. The for-each is used to iterate over arrays and collections. It can do something for each element contained.
A for loop will give you the option to perform any or all of these three things:
Instantiate a starting iteration value (int i = 0)
Define a boolean condition on which iteration may continue (i < 10)
Provide an incrementation step (i += 2)
A valid for loop can look like this:
for(; ;) {
System.out.println("This will run forever!!!");
}
A while loop only gives you the boolean condition, which is mandatory.
You typically use the for loop when:
You know the size of the elements you must iterate over
You typically use the while loop when:
You don't know the size of the elements you must iterate over
You want to busy-wait on some value or variable
For loops are used when you know how many times you need to loop. While loops are used to loop until an event occurs.
Also, note that whatever you can do with a for loop, you can do it with a while loop (just add a variable that increments in the while loop and uses it to break out of the loop when the variable reaches a certain value).
This is one of those things that folks typically pick up by experience. First thing to realise is that any for loop can be decomposed into a while loop
for ( initialise; test ; go on to next )
can be expressed as
initialise;
while(test) {
go on to next
}
I'd suggest trying for a little while to use only while loops. What you will then find is that some of your while loops start to feel a little clumsy.
initialise;
while(test) {
my really interesting code here
go on to next
}
and you find that
for ( initialise ; test; go on to next ) {
my really interesting code here
}
reads more clearly. One common example being working your way through an array.
for ( int i; i < array.length; i++ ){
something with array[i];
}

Stack Overflow Error java

I'm trying to solve a problem that calls for recursive backtracking and my solution produces a stackoverflow error. I understand that this error often indicates a bad termination condition, but my ternimation condition appears correct. Is there anything other than a bad termination condition that would be likely to cause a stackoverflow error? How can I figure out what the problem is?
EDIT: sorry tried to post the code but its too ugly..
As #irreputable says, even if your code has a correct termination condition, it could be that the problem is simply too big for the stack (so that the stack is exhausted before the condition is reached). There is also a third possibility: that your recursion has entered into a loop. For example, in a depth-first search through a graph, if you forget to mark nodes as visited, you'll end up going in circles, revisiting nodes that you have already seen.
How can you determine which of these three situations you are in? Try to make a way to describe the "location" of each recursive call (this will typically involve the function parameters). For instance, if you are writing a graph algorithm where a function calls itself on neighbouring nodes, then the node name or node index is a good description of where the recursive function is. In the top of the recursive function, you can print the description, and then you'll see what the function does, and perhaps you can tell whether it does the right thing or not, or whether it goes in circles. You can also store the descriptions in a HashMap in order to detect whether you have entered a circle.
Instead of using recursion, you could always have a loop which uses a stack. E.g. instead of (pseudo-code):
function sum(n){
if n == 0, return 0
return n + sum(n-1)
}
Use:
function sum(n){
Stack stack
while(n > 0){
stack.push(n)
n--
}
localSum = 0
while(stack not empty){
localSum += stack.pop()
}
return localSum
}
In a nutshell, simulate recursion by saving the state in a local stack.
You can use the -Xss option to give your stack more memory if your problem is too large to fix in the default stack limit size.
As the other fellas already mentioned, there might be few reasons for that:
Your code has problem by nature or in the logic of the recursion. It has to be a stoping condition, base case or termination point for any recursive function.
Your memory is too small to keep the number of recursive calls into the stack. Big Fibonacci numbers might be good example here. Just FYI Fibonacci is as follows (sometimes starts at zero):
1,1,2,3,5,8,13,...
Fn = Fn-1 + Fn-2
F0 = 1, F1 = 1, n>=2
If your code is correct, then the stack is simply too small for your problem. We don't have real Turing machines.
There are two common coding errors that could cause your program to get into an infinite loop (and therefore cause a stack overflow):
Bad termination condition
Bad recursion call
Example:
public static int factorial( int n ){
if( n < n ) // Bad termination condition
return 1;
else
return n*factorial(n+1); // Bad recursion call
}
Otherwise, your program could just be functioning properly and the stack is too small.

Java Binary search

Trying to perform a binary search on a sorted array of Book objects.
Its not working well, it returns the correct results for some of the objects, but not all.
I went through the loop on paper and it seems that a number can get missed out due to rounding #.5 upwards.
Any ideas how to make this work?
Book found = null;
/*
* Search at the center of the collection. If the reference is less than that,
* search in the upper half of the collection, else, search in the lower half.
* Loop until found else return null.
*/
int top = numberOfBooks()-1;
int bottom = 0;
int middle;
while (bottom <= top && found == null){
middle = (bottom + top)/2;
if (givenRef.compareTo(bookCollection.get(middle).getReference()) == 0) {
found = bookCollection.get(middle);
} else if (givenRef.compareTo(bookCollection.get(middle).getReference()) < 0){
bottom = middle + 1;
} else if (givenRef.compareTo(bookCollection.get(middle).getReference()) > 0){
top = middle - 1;
}
}
return found;
A couple suggestions for you:
there's no need to keep a Book variable. In your loop, just return the book when it's found, and at the end return null. And you can also remove the boolean check for the variable in the while condition.
the middle variable can be scoped inside the loop, no need to have it live longer.
you're doing bookCollection.get(middle).getReference() three times. Consider creating a variable and then using it.
the middle = (bottom + top)/2 is a classic mistake in binary search implementation algorithms. Even Joshua Bloch, who wrote the Java Collection classes, made that error (see this interesting blog post about it). Instead, use (bottom+top) >>> 1, to avoid integer overflow for very large values (you probably wouldn't encounter this error, but it's for the principle).
As for your actual problem statement, rounding would be downwards (integer division), not upwards. To troubleshoot the problem:
are you sure the numberOfBooks() method corresponds to the length of your collection?
are you sure the compareTo() method works as expected for the types you are using (in your code example we do not know what the getReference() return type is)
are you sure your collection is properly sorted according to getReference()?
and finally, are you sure that using givenRef.compareTo(bookCollection.get(middle).getReference()) < 0 is correct? In standard binary search implementations it would be reversed, e.g. bookCollection.get(middle).getReference().compareTo(givenRef) < 0. This might be what donroby mentions, not sure.
In any case, the way to find the error would be to try out different values and see for which the output is correct and for which it isn't, and thus infer what the problem is. You can also use your debugger to help you step through the algorithm, rather than using pencil and paper if you have to run many tests. Even better, as donroby said, write a unit test.
What about Collections.binarySearch()?
All of JRL's suggestions are right, but the actual fail is that your compares are reversed.
I didn't see this immediately myself, but replicating your code into a function (using strings instead of Books), writing a some simple Junit tests and then running them in the debugger made it really obvious.
Write unit tests!
I found the problem.
It turns out i was binary searching my bookCollection arrayList, and NOT the new sroted array i had created - sortedLib.
Silly mistake at my end, but thanks for the input and suggestions!

Categories