I'm learning Java, and I'm stuck on a recursion problem.
I need to use a recursive method to check if a number is an Armstrong number or not.
My code:
public class ArmstrongChecker {
public boolean isArmstrong(int number) {
// check if the number is a negative number
if (number < 0) {
return false;
}
ArmstrongChecker armstrongChecker = new ArmstrongChecker();
// find the length of the number
int length = armstrongChecker.lengthChecker(number);
// create a variable to store the sum of the digits of the number
int sum = 0;
// find the individual digits and raise to the power of the numbers of digits
if (number != 0) {
int digit = Math.floorMod(number, 10);
int powerRaised = (int) Math.pow(digit, length);
sum = sum powerRaised;
isArmstrong(number / 10);
}
return sum == number;
}
// method to check the length of the number
public int lengthChecker(int number) {
int length = String.valueOf(number).length();
return length;
}
}
How do I prevent int length in isArmstrong()
method from changing its value.
CodePudding user response:
While you are not changing it's value in the posted code, you could mark that variable to be a constant. This way the compiler can error out if you tried to assign a new value.
final int length = armstrongChecker.lengthChecker(number);
CodePudding user response:
As I've already said in the comments, your solution has the following issues:
- The result of the recursive call
isArmstrong()
is being ignored; - There's no need for spawning new instances of
ArmstrongChecker
. And this method doesn't require object creation at all, it can be implemented asstatic
. - Checking if the number is an Armstrong number boils down to calculating its Armstrong sum, the solution will be cleaner if you implement only this part using recursion.
It might look like this:
public static boolean isArmstrong(int number) {
if (number < 0) return false;
if (number < 10) return true;
return number == getArmstrongSum(number, String.valueOf(number).length());
}
public static int getArmstrongSum(int number, int power) {
if (number == 0) {
return 0;
}
return (int) Math.pow(number % 10, power) getArmstrongSum(number / 10, power);
}
main()
public static void main(String[] args) {
System.out.println(isArmstrong(370)); // true
System.out.println(isArmstrong(12)); // false
System.out.println(isArmstrong(54)); // false
System.out.println(isArmstrong(153)); // true
}
Output:
true
false
false
true
CodePudding user response:
You need to get the length once for whole recursion, so the cleanest approach would be to pass down both the number and the length into the recursion. An easy way to do this is to have one method that is the public face of the API, and another that does the recursion.
public class ArmstrongChecker {
public boolean isArmstrong(int number) {
if (number < 0) {
return false;
}
int length = lengthChecker(number);
int sum = armstrongSum(number, length);
return sum == number;
}
private int armstrongSum(int number, int length) {
int sum = 0;
if (number != 0) {
int digit = Math.floorMod(number, 10);
int powerRaised = (int) Math.pow(digit, length);
sum = powerRaised;
sum = armstrongSum(number / 10, length);
}
return sum;
}
public int lengthChecker(int number) {
int length = String.valueOf(number).length();
return length;
}
}
This is pretty common in recursion, where the parameters to the recursive part of the algorithm are a little different (usually there are more of them) than what you want a client of the API to have to pass in. The number changes in each recursive call, where number / 10
is passed down, but the same length
is passed all the way through.
Notice that the recursive armstrongSum
uses the return value from the recursive call, and that there is no need to create another instance of ArmstrongChecker
when you are already in an instance method of the class.
CodePudding user response:
This is pretty difficult to do with just taking in number
as a parameter, so I edited the method a bit:
class Main {
public static void main(String[] args) {
System.out.println(isArmstrong(555,555,0));
System.out.println(isArmstrong(153,153,0));
}
public static boolean isArmstrong(int number, int copy, int curr){
if(copy == 0 && curr == number){
return true;
}
else if(copy == 0){
return false;
}
curr = (int)(Math.pow(copy % 10, String.valueOf(number).length()));
copy /= 10;
return isArmstrong(number, copy, curr);
}
}
We use 3 parameters instead: number
, copy
, and curr
: copy
will initially store the same value as number
, though we will change the value as we go through each recursion to access each digit. curr
will store the current value of the sum of cubes of the digits.
While the value of copy
is not 0
, we will update the value of curr
by adding the power of the last digit of curr
, and then removing that digit from curr
by dividing it by 10.
We repeat this process until copy
is 0
. If curr
matches the value of number
, we return true
, and otherwise false
.
You could also create a helper method so that when you call the function, you still only input one parameter:
class Main {
public static void main(String[] args) {
System.out.println(isArmstrong(555));
System.out.println(isArmstrong(153));
}
public static boolean isArmstrong(int number){
return isArmstrong(number, number, 0);
}
public static boolean isArmstrong(int number, int copy, int curr){
if(copy == 0 && curr == number){
return true;
}
else if(copy == 0){
return false;
}
curr = (int)(Math.pow(copy % 10, String.valueOf(number).length()));
copy /= 10;
return isArmstrong(number, copy, curr);
}
}
Output of both:
false
true
I hope this helped! Please let me know if you need any further help/clarification.