I want to use a recursive method but am having trouble making it work correctly.
In this program for example, why when I display my b, the value is 0 and not 10?
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
recursivMethod(a+1);
return a;
}
The issue is, while you are calling the method recursively, you're not returning that value. That is, you call recursivMethod correctly, but then immediately return the initial value of a. Try this instead:
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1); //here, you return the result of your recursive call
return a; //instead of just immediately returning a, which should only be done only after a == 10
}
Two points:
When your method calls itself recursively, it's ignoring the returned value:
if(a != 10)
recursivMethod(a+1); // <--- did you mean to do something with the result?
Since recursivMethod() doesn't change a, and returns a at the end, then calling recursivMethod(0) will return 0. This is exactly what happens when you run your code.
This is because you are ignoring the return value of your recursive invocation:
static int recursivMethod(int a) {
if(a != 10)
return recursivMethod(a+1);
return a;
}
try
return recursiveMethod(a+1);
instead
You did never assign a new value to the method local variable a.
Try:
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
a = recursivMethod(a+1);
return a;
}
You are discarding the result of your recursive call.
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1); // Note the return
return a;
}
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1);
}
missing return:
return recursivMethod(a+1);
Related
Why does return statement is throwing error when used Math function in a method.
public class HCF_1 {
static int hcf(int a, int b)
{
int res = Math.max(a,b);
while(true)
{
if(res%a==0 && res%b==0)
return res;
else res++;
}
return res;
}
public static void main(String[] args) {
System.out.println(hcf(5,25));
}
}
This may or may not be helpful, but IMO while(true) statements are a real code smell. You can rewrite this method as:
public class HCF_1 {
static int hcf(int a, int b)
{
int res = Math.max(a,b);
while(res % a != 0 || res % b != 0)
res++;
return res;
}
public static void main(String[] args) {
System.out.println(hcf(5,25));
}
}
Now there is only a single return statement, and no shortcuts.
Note that the operations !(res % a == 0 && res % b == 0) are the same as res % a != 0 || res % b != 0, due to to the properties of Boolean Logic: ~(A AND B) == ~A OR ~B.
public class HCF_1 {
static int hcf(int a, int b)
{
int res = Math.max(a,b);
while(true)
{
if(res%a==0 && res%b==0)
return res;
else res++;
}
return res; //last line of the method hcf is unreachable
}
public static void main(String[] args) {
System.out.println(hcf(5,25));
}
}
The while loop is a never-ending loop and is escaped only under the condition mentioned inside if block which is a return statement and not a break statement. Therefore the last line of the method hcf return res; is unreachable in any condition.
the segement of your code in if-else the cause to be unreachable for the last line of your return res, you so have to do 2 things:
remove the return inside if and add break instead.
return the last line of method which is return res;
public class HCF_1 {
static int hcf(int a, int b) {
int res = Math.max(a, b);
while (true) {
if (res % a == 0 && res % b == 0)
break;
else
res++;
}
return res;
}
public static void main(String[] args) {
System.out.println(hcf(5, 25));
}
}
I started learning Java, currently I'm playing around with recursion.
I wanted to try and make a substring method which will substring from both sides by 1 character until we get the desired string.
I managed to do the first part but I'm having problem figuring out how to substring from the back.
n and m should be the indexes between which we want to substring (inclusive).
In this example result of method should be "bstri"
Here is my code:
public static void main(String[] args) {
String s = "substringme";
System.out.println(rec(s,2,6));
}
public static String rec(String s, int n, int m) {
if(n == 0 /* && missing 2nd part of condition */){
return s;
} else {
if(n>0){
s = s.substring(1);
n--;
}
if(/* missing condition */){
s= s.substring(0, s.length()-1);
}
return rec(s,n,m);
}
}
I would appreciate any help I can get.
So fixing your recursive method is fairly easy. We just do exactly the same as you did for n:
public static String rec(String s, int n, int m) {
if (n == 0 && m == 0) {
return s;
}
else {
if(n > 0) {
s = s.substring(1);
n--;
}
if(m > 0) {
s = s.substring(0, s.length()-1);
m--;
}
return rec(s,n,m);
}
}
The issue now is that the value of m given as input is measured from the start of the String and it would be way more convenient for us if it were measured from the end of the String.
We can introduce a new method to do this for us which acts as our entry point to the recursive method:
public static String substr(String s, int n, int m) {
final int newM = s.length() - m - 1; //-1 to be inclusive of the char
return rec(s, n, newM);
}
You would then change your main method to call substr() instead:
public static void main(String[] args) {
String s = "substringme";
System.out.println(substr(s,2,6));
}
I often find myself writing these kind of "entry point" methods when I'm using recursive methods. If you were doing this properly, substr would be your public-facing method and rec would be private.
I propose that you do m-- in the first loop because the definition of m as an index changes when you shorten s from the front.
public static String rec(String s, int n, int m) {
if(n == 0 && m == s.length() - 1){
return s;
} else {
if (n > 0) {
s = s.substring(1);
n--;
m--;
}
if (m < s.length() - 1) {
s = s.substring(0, s.length() - 1);
}
return rec(s, n, m);
}
}
What you could do is look for the difference between m and the length of the string, and cut off characters from the end of the string until it is the correct length.
import java.util.*;
public class Test {
public static void main(String[] args) {
String s = "substringme";
System.out.println(rec(s,2,6));
}
public static String rec(String s, int n, int m) {
if(n == 0 && s.length()-m < 1){
return s;
} else {
if(s.length()-m > 1){
s= s.substring(0, s.length()-1);
}
else if(n>0){
s = s.substring(1);
n--;
}
return rec(s,n,m);
}
}
}
Also shouldn't substring from 2 to 6 be "bstr", not "bstri"?
System.out.println(s.substring(2, 6)); //equals bstr
I don't know how to make my code less time consuming. My task was to make brute force password break. I knew how long password is and which characters it contains. So far i have this method.
public boolean moznosti(char [] arr, String pr, int a, int b) {
if (b == 0) {
char [] heslo = pr.toCharArray();
if(tryOpen(heslo)) {
return false;
}
return true;
}
for (int i = 0; i < a; i++) {
String tmp = pr+arr[i];
if (moznosti(arr, tmp, a, b-1) == false) {
return false;
}
moznosti(arr, tmp, a, b-1);
}
return true;
}
}
where heslo is password. any ideas?
Have a look at your code structure.
You have a for loop which recursively calls your moznosti method, and each time it's called it doing the same thing.
I don't know what your variables mean but assuming a and b are 4. Your first cycle will call your moznosti method 4 times with the same b parameter.
Not that this is causing the time issue but where you have:
if (moznosti(arr, tmp, a, b-1) == false)
Because the moznosti method returns a Boolean value, you don't need to check if it's equal to false or true, the if statement brackets only pass when the condition is true. So in your case this might be more applicable:
if (!moznosti(arr, tmp, a, b-1))
I think the part which is taking most of the time is where you are checking your base case
if (moznosti(arr, tmp, a, b-1) == false)
Okay i did it!
public class BruteForceAttacker extends Thief {
private boolean konec;
#Override
public void breakPassword(int sizeOfPassword) {
moznosti(getCharacters(), "", getCharacters().length, sizeOfPassword);
}
public void moznosti(char [] arr, String pr, int a, int b) {
if (konec != true) {
if (b == 0) {
char [] heslo = pr.toCharArray();
if (tryOpen(heslo)) {
konec = true;
}
return;
}
for (int i = 0; i < a; i++) {
String tmp = pr+arr[i];
moznosti(arr, tmp, a, b-1);
}
}
}
}
Consider 4 input fields A, B, C and D on a web surface. The user can fill any of these arbitrary. There are 16 combinations of how to fill these fields. The ones allowed are:
A B C D
-------
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
where 1 means not null and 0 means null.
I am using the MVC pattern with jsf. I don't want the logic to be in the view, but rather in the controller. What is the best way to check this in Java?
I implemented two solutions so far:
Solution 1:
#Override
public boolean isInputInvalid(Integer a, Integer b, Integer c, Integer d) {
if (isNotSet(a) && isNotSet(b) && isNotSet(c) && isNotSet(d) {
return true;
}
return (firstParameterDoesNotExistAndSecondDoesExist(a, b)) || (firstParameterDoesNotExistAndSecondDoesExist(b, c)) || (firstParameterDoesNotExistAndSecondDoesExist(c, d));
}
private boolean firstParameterDoesNotExistAndSecondDoesExist(Integer firstParameter, Integer secondParameter) {
return isNotSet(firstParameter) && !isNotSet(secondParameter);
}
private boolean isNotSet(Integer parameter) {
return parameter == null;
}
Solution 2:
public boolean isInputValid(Integer a, Integer b, Integer c, Integer d) {
if (exists(a) && !exists(b) && !exists(c) && !exists(d) || //
exists(a) && exists(b) && !exists(c) && !exists(d) || //
exists(a) && exists(b) && exists(c) && !exists(d) || //
exists(a) && exists(b) && exists(c) && exists(d)) {
return true;
}
return false;
}
private boolean exists(Integer level) {
return level != null;
}
Note:
The first methods checks if input is invalid, while the second checks if input is valid (note the names of the methods).
I wrote 16 unit test cases, which all run green with both versions.
Do you have any hints/tips/tricks on how to get the code even more readable?
Valid combinations are: 1000, 1100, 1110 and 1111
If you only care about readability:
public static List<String> validOptions = Arrays.asList("1000","1100","1110","1111");
public boolean isValid(Integer a, Integer b, Integer c, Integer d)
{
StringBuilder sb = new StringBuilder();
sb.append(a==null ? 0 : 1);
sb.append(b==null ? 0 : 1),
sb.append(c==null ? 0 : 1);
sb.append(d==null ? 0 : 1);
return validOptions.contains(sb.toString());
}
Note that this is not the fastest or cleanest solution (wastes some CPU and memory)
To solve this for an arbitrary number of parameters, pass in true or false (if not null / null) in this:
static boolean isValid(boolean... params) {
boolean set = true;
for (boolean param : params) {
if (!set && param) return false;
set = param;
}
return params[0];
}
Or much cooler (and IMHO readable), but less performant, use regex on the array's toString():
static boolean isValid(boolean... params) {
return Arrays.toString(params).matches("\\[true(, true)*(, false)*]");
}
which ever implementation you use, you would call it like:
if (isValid(a != null, b != null, c != null, d != null))
Not fancy but fast and simple:
static boolean isValid(boolean a, boolean b, boolean c, boolean d) {
return a && (b || !c) && (c || !d);
}
Call:
isValid(a != null, b != null, c != null, d != null);
I don't really understand why you need this. Rather than a method that tests if input is valid, it would be much better to only allow valid input in the first place.
// This method is private, so you can't call it with arbitrary arguments.
private void privateMethod(Integer a, Integer b, Integer c, Integer d) {
// do something();
}
public void method(int a) {
privateMethod(a, null, null, null);
}
public void method(int a, int b) {
privateMethod(a, b, null, null);
}
public void method(int a, int b, int c) {
privateMethod(a, b, c, null);
}
public void method(int a, int b, int c, int d) {
privateMethod(a, b, c, d);
}
The way to modify this to any number of arguments (not just 4) is to have a method with signature
public void method(int... a)
Then, if the length of the array passed is less than the required length, you can just use null for the remaining inputs.
If this does not address your problem, I think you should consider editing your question to give an example of your use case, because I suspect there is a better way to achieve what you require.
You could create a pattern with a two dimensional array.
The advantage is that it is easy to adjust, and add additional information to it.
Here is a tiny example with your conditions.
In the end all you have to read is the pattern that is initialized in the static block, which is quite easy to read.
// Every boolean array in a dimension represents a valid pattern
private static boolean[][] pattern;
static {
pattern = new boolean[4][4];
pattern[0] = new boolean[]{true, false, false, false};
pattern[1] = new boolean[]{true, true, false, false};
pattern[2] = new boolean[]{true, true, true, false};
pattern[3] = new boolean[]{true, true, true, true};
}
public static void main(String[] args) {
// Testing an invalid combination
System.out.println(test(new Integer[]{1,null,3,null}));
// Testing a valid combination
System.out.println(test(new Integer[]{1,2,3,null}));
}
private static boolean test(Integer[] input) {
// cast the input to a boolean array that can be compared to the pattern.
boolean[] arr = createArr(input);
for(int i = 0;i<pattern.length;++i) {
if(Arrays.equals(pattern[i], arr)) { // Check if the pattern exists in the list of valid pattern. If it exists, then this is a valid combination
return true;
}
}
// the loop never found a valid combination, hence it returns false.
return false;
}
// This is just a helping method to create a boolean array out of an int array. It casts null to true and !null to false.
private static boolean[] createArr(Integer[] input) {
boolean[] output = new boolean[input.length];
for(int i = 0;i<input.length; ++i) {
output[i] = input[i] != null;
}
return output;
}
Yet another solution. Involves more code but for me it's easier to understand:
boolean isInputInvalid(Object ... args) {
int notNullDataIndex = -1;
for (int i = args.length - 1; i >= 0; i--) {
if (args[i] != null) {
notNullDataIndex = i;
break;
}
}
if (notNullDataIndex < 0) return false;
for (int i = notNullDataIndex; i >= 0; i--) {
if (args[i] == null) return false;
}
return true;
}
I wrote this code with the intention of chain being incremented each time recurse() is called. It does this, however (from what I saw with the debugger) each time recurse() reaches a return;, it decrements the value of b. This is project euler #14 if you want background on what I'm trying to do.
http://projecteuler.net/problem=14
private static void euler14()
{
int currentstart=1000000;
int longest = 0;
int current=0;
Integer chain=0;
for(int i = currentstart; i>0; i--)
{
recurse(i,chain);
if(chain > current)
{
current=chain;
longest=i;
}
chain = 0;
}
System.out.print("Euler 14: " + longest + "\n");
}
private static void recurse(int a, Integer b)
{
b++;
if(a==1)
{
return;
}
else if(a%2==0)
{
recurse((a/2), b);
}
else if(a%2==1)
{
recurse(((a*3)+1), b);
}
return;
}
Although the reference to Integer is passed (by value) to recurse, the object itself is immutable. When you do b++, the incremented value is assigned to b which is local to recurse. As soon as you return, the value goes back to the unchanged copy of b in the caller.
You can make b a static int variable, and drop it from the parameter list of recurse to fix the problem:
private static int b = 0;
private static void recurse(int a) {
b++;
if(a==1) {
return;
}
if(a%2==0) {
recurse((a/2), b);
} else if(a%2==1) {
recurse(((a*3)+1), b);
}
}
In order to see updates to b in your main method your need to return them back, when you reach end of recursion:
private static int recurse(int a, int b) {
b++;
if(a==1) return b;
else if(a%2==0) return recurse((a/2), b);
else if(a%2==1) return recurse(((a*3)+1), b);
return b;
}
And in your main method you update your chain with new value:
chain = recurse(i,chain);
Since your method currently doesn't have a return value, you can use a return value for the number of steps. Simply add 1 to each recursive step:
private static int recurse(int a) {
if(a==1) {
return 1;
}
if(a%2==0) {
return 1 + recurse(a/2);
} else if(a%2==1) {
return 1 + recurse((a*3)+1);
}
}