Method that determines if a number is 'insipid' - java

So I have been tasked with writing a program that determines if a number is insipid or not. Meaning, if you take a number:
57 for example, and you add the square of each digit, 5*5 + 7*7, that is now the new number:74. And you keep doing that until you either get 58 which means the number is NOT insipid, or you get 1, meaning the number is. 58 will just repeat a sequence that always ends back on 58.
So I wanted to attempt it with some basic recursion but perhaps I misunderstand the use of recursion here.
Here are the two relevant methods I wrote:
public static boolean insipid(int num){
int dig1 = 0, dig2 = 0, dig3 = 0; // num = 159 for example, dig1 would be 1. Default is 0 in case of a 2 digit number, dig1*dig1 = 0
if(num == 58){ //The number is not insipid
return false;
}
if(num == 1){ // the number is insipid
return true;
}
if (num < 10){
insipid(num * num);
}
if(num>99){
dig1 = (int)(num / 100);
dig2 = (int)((num - 100)/10);
dig3 = num - (((int)(num / 10))*10);
insipid(squaresum(dig1,dig2,dig3));
}
else{
dig2 = (int)(num/10); //the 10s place
dig3 = num - (((int)(num/10)) * 10); // the 1's place
insipid(squaresum(dig1, dig2,dig3)); //dig1 = 0 so I just pass it along with it.
}
}
public static int squaresum(int dig1, int dig2, int dig3){
//Returns the sum of three digits squared.
return (dig1 * dig1) + (dig2 * dig2) + (dig3 + dig3);
}
It gives me an error saying that Insipid() must return a boolean whenever I supply it a number. But I know for any number given it will always either eventually resolve to 58 or 1. So shouldn't true or false always eventually be returned so a boolean is returned and the error is invalid? Obviously this is not the case, but how I see it. Is it the use of the recursion here that is invalid?
Also, if you have any suggestions on how I might clean this up I wouldn't mind harsh criticism, my java is not very good.

If you went with your solution, the only thing missing is the return statements from the recursive calls to incipid.

Update you insipid as below. A method declared with return must return values in all cases. Your method doesn't return any value if it reach second else i.e. if number is anything other than 1 & 58.
public static boolean insipid(int num){
boolean returnValue = false;
if(num == 58){ //The number is not insipid
//do nothing
} if(num == 1){ // the number is insipid
returnValue = true;
}else{
int dig1 = 0, dig2 = 0, dig3 = 0; // num = 159 for example, dig1 would be 1. Default is 0 in case of a 2 digit number, dig1*dig1 = 0
if (num < 10){
returnValue = insipid(num * num);
}
else if(num>99){
dig1 = (int)(num / 100);
dig2 = (int)((num - 100)/10);
dig3 = num - (((int)(num / 10))*10);
returnValue = insipid(squaresum(dig1,dig2,dig3));
}
else{
dig2 = (int)(num/10); //The 10s place
dig3 = num - (((int)(num/10)) * 10); //the 1s place
returnValue = insipid(squaresum(dig1, dig2,dig3)); //dig1 = 0 so I just pass it along with it.
}
}
return returnValue ;
}
Please Note: I just tried to answer your issue regarding return issue ONLY.

In addition to Yogendra Singh's answer, you're calculating digits incorrectly: e.g. with
dig2 = (int)((num -100)/10);
you're assuming that the hundreds digit is 1. Try
dig2 = (int)((num - dig1 * 100)/10);
and similarly for dig3.

Related

Java recursive calls

I want to build a code to go over any sequence of 0 and 1 and calculate how many different ways it can pass through the number just "jumping" between the '1's. Also it can jump no more than 3 digits per time.
For example, number 100110101 it could be like:
1xx1xx1x1 or 1xx11x1x1 (passing through all the '1').
Another example could be 1011011101:
1x11x111x1 (passing through all '1') or 1xx1x111x1 or 1x1xx1x1x1 and so on...
The important is not to jump more than 3 digits.
And the number will always start and finish with 1 as well.
I've got the following code and I think it is working.
public int calculate(String number){
if(number.length()<3){ //left fill with 0
if(number.length()==2) number = "0" + number;
else number = "00" + number;
}
if(number.length() == 3){ //for 001, 101, 011, 111
if (number.equalsIgnoreCase("111")) return 2; //2 possible ways
else return 1; //any other combination will have just one way
}
String aux = number.substring(1,4);//take the 3 next digits
//recursive calls to calculate it
if (aux.equalsIgnoreCase("001")) return calculate(number.substring(3, number.length()));
else if (aux.equalsIgnoreCase("010")) return calculate(number.substring(2, number.length()));
else if (aux.equalsIgnoreCase("011")) return calculate(number.substring(2, number.length())) + calculate(number.substring(3, number.length()));
else if (aux.equalsIgnoreCase("100")) return calculate(number.substring(1, number.length()));
else if (aux.equalsIgnoreCase("101")) return calculate(number.substring(1, number.length())) + calculate(number.substring(3, number.length()));
else if (aux.equalsIgnoreCase("110")) return calculate(number.substring(1, number.length())) + calculate(number.substring(2, number.length()));
else if (aux.equalsIgnoreCase("111")) return calculate(number.substring(1, number.length())) + calculate(number.substring(2, number.length())) + calculate(number.substring(3, number.length()));
return 0;
}
The question is: I also wanna make sure that it is not allowed to jump 3 digits twice in a row. Something like 1xx1xx1 is not allowed. However since I'm using recursive calls I don't know if that's possible.
One way to prevent jumping 3 digits twice in a row is to pass extra state information to calculate(); the extra data you pass would be a boolean indicating whether or not the last jump was of length 3. Then in your initial call to calculate(), just make sure to indicate that the last jump was not of length 3 (so the first jump is allowed to be of length 3).
private static int countPossibilities(String inputString) {
final char validChar = '1';
final char maxDistance = 3; // max consecutive jumps. eg: maxDistance for '1xxx1' is 3.
if (inputString.length() == 1) {
return 1;
}
var indexForMaxPossibleJump = Math.min(maxDistance + 1, inputString.length() - 1);
if (inputString.charAt(indexForMaxPossibleJump) != validChar) {
indexForMaxPossibleJump = inputString.substring(0, indexForMaxPossibleJump).lastIndexOf(validChar);
}
// No jumps possible.
if (indexForMaxPossibleJump == 0) {
return 0;
}
int finalCount = 0;
var remainingString = inputString.substring(indexForMaxPossibleJump);
var maxJumpingString = inputString.substring(1, indexForMaxPossibleJump);
// calculate count if we are not jumping to max distance. i.e., taking intermediate step on 1.
for (var i = 0; i < maxJumpingString.length(); i++) {
if (maxJumpingString.charAt(i) != validChar) {
continue;
}
var countOfString = countPossibilities(maxJumpingString.substring(i) + remainingString);
finalCount += countOfString;
}
// calculate count if we are jumping to max distance.
var countOfRemainingString = countPossibilities(remainingString);
finalCount += countOfRemainingString;
return finalCount;
}

Converting a Binary Integer to a Decimal Integer using Recursion

I am having trouble getting this method, which converts an integer from binary to decimal, to work properly. The main problem I have found is that with binary numbers that end in 0, the last 0 is ignored by the program. For example, if I input 1010, the program would return 5 instead of 10. Below is my method for this conversion.
public int toDecimal(int inBase2){
int num = 0;
if(inBase2 < 0){
num = -1;
return num;
}
if(inBase2 == 0 && num == 0){
return num;
}else{
num = inBase2 % 10 * (int)(Math.pow(2, Math.log10(inBase2)));
return num + toDecimal(inBase2 / 10);
}
}
How would I go about fixing the program in a way that allows it to read the final 0 in the binary integer correctly?
You're doing the calculation the wrong way round. The least significant digit in the binary number is treated as though it's the most significant. So effectively, 1010 returns the result for 0101. Right now, the first digit you process, in the ones place, is multiplied by Math.pow(2, Math.log10(inBase2)), and given the most weight. Instead, you should multiply the results of the recursive function, so later calls (which represent higher value digits) are multiplied more. Example
public int toDecimal(int inBase2){
int num = 0;
if(inBase2 < 0){
num = -1;
return num;
}
if(inBase2 == 0 && num == 0){
return num;
}else{
num = inBase2 % 10;
return num + 2 * toDecimal(inBase2 / 10);
}
}

Largest number of times square root can be calculated on numbers between 2 intervals

I wrote a simple program to calculate the maximum number of times square root can be calculated on a number , input is an interval from num1 to num2
eg:
if the input is (1,20), answer is 2, since square root of 16 is 4 , and square root of 4 is 2 .
int max = 0;
for (int i = num1; i <= num2; i++) {
boolean loop = true;
int count = 0;
int current = i;
if (i == 1) {
count++;
} else {
while (loop) {
double squareRoot = Math.sqrt(current);
if (isCurrentNumberPerfectSquare(squareRoot)) {
count++;
current = (int) squareRoot;
} else {
loop = false;
}
}
}
if (count > max) {
max = count;
}
}
return max;
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - floor(number)) == 0);
}
I get the answer, but was wondering wether this can be improved using some mathematical way ?
Any suggestions ?
To avoid more confusion here my final answer to this topic.
A combination of both previously mentioned approaches.
What 'Parameswar' is looking for is the largest perfect square formed by the lowest base.
Step 1 -
To get that calculate the largest possible perfect square based on your num2 value.
If it is outside your range, you have no perfect square within.
Step 2 -
If it is within your range, you have to check all perfect square formed by a lower base value with a higher number of times.
Step 3 -
If you find one that is within your range, replace your result with the new result and proceed to check lower values. (go back to Step 2)
Step 4 -
Once the value you check is <= 2 you have already found the answer.
Here some sample implementation:
static class Result {
int base;
int times;
}
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - Math.floor(number)) == 0);
}
private static int perfectSquare(int base, int times) {
int value = base;
for (int i = times; i > 0; i--) {
value = (int) Math.pow(base, 2);
}
return value;
}
private static Result calculatePerfectSquare(int perfectSquare) {
Result result = new Result();
result.base = (int) Math.sqrt(perfectSquare);
result.times = 1;
while (result.base > 2 && isCurrentNumberPerfectSquare(Math.sqrt(result.base))) {
result.base = (int) Math.sqrt(result.base);
result.times += 1;
}
System.out.println(perfectSquare + " -> " + result.base + " ^ " + result.times);
return result;
}
static int maxPerfectSquares(int num1, int num2) {
int largestPerfectSqr = (int) Math.pow(Math.floor(Math.sqrt(num2)), 2);
if (largestPerfectSqr < num1) {
return 0;
}
Result result = calculatePerfectSquare(largestPerfectSqr);
int currentValue = result.base;
while (currentValue > 2) {
// check lower based values
currentValue--;
int newValue = perfectSquare(currentValue, result.times + 1);
if (newValue >= num1 && newValue < num2) {
result = calculatePerfectSquare(newValue);
currentValue = result.base;
}
}
return result.times;
}
Edit - My assumption is incorrect. Refer to the answer provided by "second".
You can remove the outer loop, num2 can be directly used to determine the number with the maximum number of recursive square roots.
requiredNumber = square(floor(sqrt(num2)));
You just need to check to see if the requiredNumber exists in the range [num1, num2] after finding it.
So the refactoring code would look something like this,
int requiredNumber = Math.pow(floor(Math.sqrt(num2)),2);
int numberOfTimes=0;
if(requiredNumber>=num1) {
if (requiredNumber == 1) {
numberOfTimes=1;
} else{
while (isCurrentNumberPerfectSquare(requiredNumber)) {
numberOfTimes++;
}
}
}
Edit 4: for a more optimal approach check my other answer.
I just leave this here if anybody wants to try to follow my thought process ;)
Edit 3:
Using prime numbers is wrong, use lowest non perfect square instead
Example [35,37]
Edit 2:
Now that I think about it there is a even better approach, especially if you assume that num1 and num2 cover a larger range.
Start with the lowest prime number 'non perfect square' and
calculate the maximum perfect square that fits into your range.
If you have found one, you are done.
If not continue with the next prime number 'non perfect square'.
As a example that works well enough for smaller ranges:
I think you can improve the outerloop. There is no need to test every number.
If you know the smallest perfect square, you can just proceed to the next perfect square in the sequence.
For example:
[16, 26]
16 -> 4 -> 2 ==> 2 perfect squares
No neeed to test 17 to 24
25 -> 5 ==> 1 perfect square
and so on ...
#Chrisvin Jem
Your assumption is not correct, see example above
Edit:
Added some code
static int countPerfectSquares(int current) {
int count = 0;
while (true) {
double squareRoot = Math.sqrt(current);
if (isCurrentNumberPerfectSquare(squareRoot)) {
count++;
current = (int) squareRoot;
} else {
return count;
}
}
}
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - Math.floor(number)) == 0);
}
static int numPerfectSquares(int num1, int num2) {
int max = 0;
if (num1 == 1) {
max = 1;
}
int sqr = Math.max(2, (int) Math.floor(Math.sqrt(num1)));
int current = (int) Math.pow(sqr, 2);
if (current < num1) {
current = (int) Math.pow(++sqr, 2);
}
while (current <= num2) {
max = Math.max(countPerfectSquares(current), max);
current = (int) Math.pow(++sqr, 2);
}
return max;
}

Find max rating(number) in an array where we cannot skip over 1 or more consecutive number in array

we have an array of ratings, we have to find the max rating in such a away that we cannot skip 1 or more consecutive rating in an arrray
Example-1: {9,-1,-3,-4,-5} output = 9 + -1 + -4 = 4
Explanation: I took 9 the we have to took -1 or -3 we cannot jump to -4 directly as we cannot skip 1 or more consecutive number.
Example-2: {-1,-2,-3,-4,-5} output = -2 + -4 = -6
Example-3: {-3,2,-4,-1,-2,5} output = 2 + -1 + 5 = 6
Example-4: {9,-1,-3,4,5} output = 9 + -1 + 4 + 5 = 17
I tried below code but it is working in case of example: 2,3,4 but not for example 1 similarly failing for other scenario.
static int maximizeRatings(int[] ratings) {
int current = 0;
boolean result = false;
for(int j=0; j<ratings.length;j++){
if(ratings[j]<0){
result = true;
}else{
result = false;
}
}
if(result){
return allnegatine(ratings);
}
for(int i=0; i<ratings.length;i++){
if(i == ratings.length-1){
if(ratings[i] > 0)
current += ratings[i];
}else{
if(ratings[i] >0 && ratings[i+1]>0){
current = ratings[i]+ratings[i+1];
i++;
}
if(ratings[i] > ratings[i+1]){
current += ratings[i];
}else{
current += ratings[i+1];
i++;
}
}
}
return current;
}
private static int allnegatine(int[] ratings) {
int current =0;
for(int i=0; i<ratings.length;i++){
if(ratings.length%2==0){
if(i%2 == 0)
current += ratings[i];
}else{
if(i%2!=0)
current += ratings[i];
}
}
return current;
}
not getting excepted out for some scenarios like example 1 I am getting -6 instead of 4, I am trying to get proper code which will pass all scenarios. Thank you
This is a dynamic programming problem.
Let dp[i] be the max ratings which can be achieved considering only the part of the array that starts at zero, ends at i, and includes ratings[i].
dp[0]=ratings[0]
dp[1]=max(ratings[1],ratings[0]+ratings[1])
dp[i]=max(dp[i-1],dp[i-2])+ratings[i]
Answer: max(dp[n-1],dp[n-2]) where n is the size of the ratings array.
Also you can chose to do away with dp array and maintain 2 variables for dp[i-1] and dp[i-2].
this is typical recursion problem (as long as the input array is reasonably long). You should go thru items and try all possible combinations and then pick the best one.
Because it looks like typical school work I am not sure if I should paste my solution. You should figure it out yourself or at least understand what's going on to be able to implement it yourself next time.
public class RatingService {
public int calculate(List<Integer> input) {
return recursion(input, true, 0);
}
private int recursion(List<Integer> sublist, boolean canSkip, int sum) {
if (sublist.isEmpty()) {
return sum;
}
int skippedSum = Integer.MIN_VALUE;
int notSkippedSum;
Integer integer = sublist.get(0);
if (canSkip) {
skippedSum = recursion(sublist.subList(1, sublist.size()), false, sum);
}
notSkippedSum = recursion(sublist.subList(1, sublist.size()), true, integer + sum);
return skippedSum > notSkippedSum ? skippedSum : notSkippedSum;
}
}
I think you are doing the mistake while checking for all negative numbers in for loop. If the last element in the array is negative then the 'result' variable will be true means that all array is negative but actually its not.
You have to replace the for loop by :
for(int j=0;j<ratings.length;j++){
if(ratings[j]<0){
result=true;
}
else{
result = false;
break;
}
}
It will break the for loop at the index where it founds any positive number i-e: all elements of array are not negative.

Reverse the digits of an integer [duplicate]

This question already has answers here:
Java reverse an int value without using array
(33 answers)
Closed 3 years ago.
I'm a Java beginner so please pardon me if the question seems silly but I already searched the forums but it seems like no one has my problem.
I need to reverse the digits of an integer, and my class hasn't covered while or if loops yet, so I can't use those. All answers I can find on stackoverflow use those, so I can't use those.
the input I am given is below 10000 and above 0 and the code I have written has no problem reversing the integer if the input is 4 digits (e.g. 1000 - 9999) but once the input is between 1 - 999 it creates zeroes on the right hand side but according to the answer sheets its wrong.
For example: 1534 gets turned into 4351, but
403 becomes 3040 instead of the 304 it should be, and 4 becomes 4000 instead of 4.
I've tried different things in the code but it seems to just keep giving the same answer. Or maybe I'm just missing some key mathematics, I'm not sure.
Scanner scan = new Scanner(System.in);
System.out.println ("Enter an integer:");
int value = scan.nextInt();
int digit = (value % 10);
value = (value / 10);
int digit2 = (value % 10);
value = (value / 10);
int digit3 = (value % 10);
value = (value / 10);
int digit4 = (value % 10);
String reversednum = ("" + digit + digit2 + digit3 + digit4);
System.out.println ( reversednum);
and
Scanner scan = new Scanner(System.in);
System.out.println ("Enter an integer:");
int value = scan.nextInt();
int digit = (value % 10);
int reversednum = (digit);
value = (value /10);
digit = (value % 10);
reversednum = (reversednum * 10 + digit);
value = (value / 10);
digit = (value % 10);
reversednum = (reversednum * 10 + digit);
value = (value / 10);
digit = (value);
reversednum = (reversednum * 10 + digit);
System.out.println (reversednum);
What am I doing wrong?
You can convert from int to String -> reverse String -> convert again in int.
This is a code example.
public int getReverseInt(int value) {
String revertedStr = new StringBuilder(value).reverse().toString();
return Integer.parseInt(revertedStr);
}
Your code assumes that the number can be divided by 1000, which is clearly not the case for numbers below 1000. So add some if statements:
public int reverseNumber(int n) {
// step one: we find the factors using integer maths
int s = n;
int thousands = s / 1000; // this will be 0 if the number is <1000
s = s - thousands*1000;
int hundreds = s / 100; // this will be 0 if the number is <100
s = s - hundreds*100;
int tens = s / 10; // etc.
s = s - tens*10;
int ones = s;
// then: let's start reversing. single digit?
if (n<10) return n;
// two digits?
if (n<100) {
return ones*10 + tens;
}
// etc.
if (n<1000) {
return ones*100 + tens*10 + hundreds;
}
if (n<10000) {
return ones*1000 + tens*100 + hundreds*10 + thousands;
}
// if we get here, we have no idea what to do with this number.
return n;
}
Without spoon-feeding you code (leaving the value of writing your own homework code intact)...
Although you've said you can't use a loop, I don't think there's a sane approach that doesn't use one. Your basic problem is you have hard-coded a solution that works when the number happens to have 4 digits, rather than using code that adapts to a variable length. ie, are not using a loop.
All is not lost with your code however. You have figured out the essence of the solution. You just need to convert it to work processing one digit at a time. Consider using recursion, that divides the number by 10 each time and continues until the number is zero. Of course, you’ll have to capture the end digit before it’s lost by division.
Pseudo code may look like:
pass in the number and the current result
if the number is 0 return result
multiply result by 10 and add remainder of number divided by 10
return the result of calling self with number divided by 10 and result
then call this passing number and zero
Using modulus and division:
int nbr = 123; // reverse to 321 or 3*10*10 + 2*10 + 1
int rev = 0;
while(nbr > 0) {
rev *= 10; // shift left 1 digit
int temp = nbr % 10; // get LO digit
rev += temp; // add in next digit
nbr /= 10; // move to next digit
}
Or a recursive method:
public static int reverseInt(int number, int value) {
switch(number) { // is this conditional statement allowed???
case 0:
return value;
}
value *= 10;
int lod = number % 10;
value += lod;
number /= 10;
return reverseInt(number, value);
}

Categories