The Collatz Sequence problem - java

I'm trying to solve this problem, its not a homework question, its just code I'm submitting to uva.onlinejudge.org so I can learn better java trough examples. Here is the problem sample input :
3 100
34 100
75 250
27 2147483647
101 304
101 303
-1 -1
Here is simple output :
Case 1: A = 3, limit = 100, number of terms = 8
Case 2: A = 34, limit = 100, number of terms = 14
Case 3: A = 75, limit = 250, number of terms = 3
Case 4: A = 27, limit = 2147483647, number of terms = 112
Case 5: A = 101, limit = 304, number of terms = 26
Case 6: A = 101, limit = 303, number of terms = 1
The thing is this has to execute within 3sec time interval otherwise your question won't be accepted as solution, here is with what I've come up so far, its working as it should just the execution time is not within 3 seconds, here is code :
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner stdin = new Scanner(System.in);
int start;
int limit;
int terms;
int a = 0;
while (stdin.hasNext()) {
start = stdin.nextInt();
limit = stdin.nextInt();
if (start > 0) {
terms = getLength(start, limit);
a++;
} else {
break;
}
System.out.println("Case "+a+": A = "+start+", limit = "+limit+", number of terms = "+terms);
}
}
public static int getLength(int x, int y) {
int length = 1;
while (x != 1) {
if (x <= y) {
if ( x % 2 == 0) {
x = x / 2;
length++;
}else{
x = x * 3 + 1;
length++;
}
} else {
length--;
break;
}
}
return length;
}
}
And yes here is how its meant to be solved :
An algorithm given by Lothar Collatz produces sequences of integers, and is described as follows:
Step 1:
Choose an arbitrary positive integer A as the first item in the sequence.
Step 2:
If A = 1 then stop.
Step 3:
If A is even, then replace A by A / 2 and go to step 2.
Step 4:
If A is odd, then replace A by 3 * A + 1 and go to step 2.
And yes my question is how can I make it work inside 3 seconds time interval?

From Googling I found this thread where a couple of other people have had the same problem and the solution is to use 64-bit arithmetic instead of 32-bit arithmetic.
Try changing int to long and see if that helps.

Related

what is the best algorithm to solve this programming challenge ? Given a positive integer number consisting only of digits 6 and 9 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Given a positive integer num consisting only of digits 6 and 9.
Return the maximum number you can get by changing at most one digit (6 becomes 9, and 9 becomes 6).
Example 1:
Input: num = 9669
Output: 9969
Explanation:
Changing the first digit results in 6669.
Changing the second digit results in 9969.
Changing the third digit results in 9699.
Changing the fourth digit results in 9666.
The maximum number is 9969.
Example 2:
Input: num = 9996
Output: 9999
Explanation: Changing the last digit 6 to 9 results in the maximum number.
Example 3:
Input: num = 9999
Output: 9999
Explanation: It is better not to apply any change.
Traverse from left to right and change the first occurrence of 6 to 9. If there is not any 6 while traversal then does not change any digit.
Following code may help:-
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class testing {
public static void main(String[] args) throws FileNotFoundException {
Scanner sc=new Scanner(System.in);
System.out.print("Enter a number : ");
int a=sc.nextInt();
String numberString = Integer.toString(a);
for (int i = 0; i < numberString.length(); i++){
char c = numberString.charAt(i);
if(c=='6') { // check if the digit is 6 or not, if 6 is present then change it to 9
numberString = numberString.substring(0, i) + '9' + numberString.substring(i + 1);
break; // break the loop if 6 is changed to 9
}
}
System.out.println("Largest Number is : "+numberString);
}
}
public class Maximum69 {
public static void main(String[] args) {
int num=6669;
int added = 0;
int cur = 1;
int curNum = num;
while(curNum > 0) {
if(curNum % 10 == 6)
added = cur;
cur *= 10;
curNum = curNum / 10;
}
System.out.println(num + added * 3);
}
}
I found out how to slove, This takes less time to run:
I have found a formule, it could have been a single line solution but for clarity I have divided in two lines
First , get the highest number based on input number of digits , for example if input is 6, topNumber will be 9, for 69 top will be 99 , for 696 top is 999, so topNumber can be 9 or 99 or 999 or 9999 or 99999,etc up to java limit, the formula to get number of digits in an integer is :
floor(log10(input)) + 1
Then you can notice that the top number minus the input, it gives you a number that starts with 3, for example 9-6 = 3 , 99 - 69 = 30 , 999 - 696 = 303, except when the input is equal to the top number, in that case the result is 0,
knowing that fact, we can conclude that for switching the first 6 in the number can be achieved by summing up 3 * (((the position of the 6) -1) * 10) , eg. 3 or 30 or 300 or 3000 or 30000, etc.
resulting in the last part of the function : input + (10^(NumberOfDigits(top - input)) -1) * 3
private static int largest69(int number) {
int topNumber = (int) (Math.pow(10,(int)(Math.log10(number)) + 1) -1);
return number + (int) Math.pow(10,(( (int)(Math.log10(topNumber - number)) + 1 ) -1) ) * 3;
}
If you're not as good as nitinsridar at intuitively implementing math into your algorithm, and if you don't want to mess around with strings like backdoor did, then you can utilize data structures to help you come to a solution without much thought
public static void main(String[] args) {
System.out.println(maxNumber(9669));
}
public static int maxNumber(int number) {
Stack<Integer> numbers = new Stack<Integer>();
int numberLength = 0;
while(number > 0) {
numbers.push(number % 10);
number /= 10;
numberLength++;
}
boolean changedFirstOccurrence = false;
int maxNumber = 0;
for(int i = numberLength; i > 0; i--) {
int numberToAdd = numbers.pop();
if (numberToAdd == 6 && !changedFirstOccurrence) {
numberToAdd = 9;
changedFirstOccurrence = true;
}
maxNumber += numberToAdd * (int) Math.pow(10, i);
}
return maxNumber / 10;
}
Is this the best solution? Nope, I would go with nitinsridar's answer (I also believe that his/her answer should get the green checkmark).
Backdoor's answer is definitely how I would've solved this problem before I took my data structures and algorithms class. I'm not saying it's a bad answer. In fact, his algorithm is more concise than mine. It's just my opinion that you don't want to get in the habit of relying on string manipulation to solve these sort of "numerical" problems, because one day it's not going to work; in this case, it did. I'm just providing another way of doing it

Random - nextInt(int y) isn't able to give me 18 even integers in a row when 'int y' % 2 == 0 && 'int y' != a power of 2

sorry for that title but I wanted to pack as much information about my problem in as little space as possible without being too confusing.
So, I have a loop which runs n times and each time it uses a = r.nextInt(int y); to generate an int and if all n integers generated are even numbers, then the program "returns true".
The weird thing is: if I chose n to be 18 or higher while y is and even number which is not a power of 2, then the programm will not "termintate successfully".
I love to help you help me, and can take a heavy dose of criticism.
(I know I'm asking about the Random/nextInt(int) topic but I will also take tips for better coding)
EDIT: I looked into the Documentation for Java8 befor I posted here and for powers of two the method uses a different way of producing the random number.
What I don't understand is why is 18 the breakpoint for consecutive even numbers and why does it work with odd numbers for nextInt(int)?
So the following code will work with howManyInts = 16 or 17 but not 18 (or higher) when nextIntValue is an even number which is not a power of two (6,10,12...)
It works with howManyInts = 25 and nextIntValue = 8 in less than 20 seconds
import java.util.*;
class test{
public static void main(String[] args) {
boolean win = false;
int areEven = 0;
long loopCounter = 0; // The loopCounter is used to control the maximum number of loops should be run incase the loop is endless
int howManyInts = 18;
int nextIntValue = 6; // nextIntValue = 6 or 10 won't work while all powers of 2 work fine
// also, I don't want an odd value as that would change to odds towards odd values...
while(win == false){
loopCounter += 1;
areEven = 0;
Random r = new Random();
int[] num = new int[howManyInts];
for(int a = 0; a < num.length; a++){
num[a] = r.nextInt(nextIntValue);
if(num[a] % 2 == 0){
areEven += 1;
}
}
if(areEven == num.length || loopCounter >= 10000000){
win = true;
System.out.println("It took " + loopCounter + " loops to get " + num.length + " random values which are all even.");
}
}
}
}
If you use SecureRandom instead of Random, your program will finish fairly quickly.
Another way would be to use nextDouble instead
num[a] = (int) (r.nextDouble() * nextIntValue);
The problem with Random.nextInt(int n) is I believe hidden within its implementation and you can read about it in its javadoc.
The algorithm is slightly tricky. It rejects values that would result
in an uneven distribution (due to the fact that 2^31 is not divisible
by n). The probability of a value being rejected depends on n. The
worst case is n=2^30+1, for which the probability of a reject is 1/2,
and the expected number of iterations before the loop terminates is 2.
The algorithm treats the case where n is a power of two specially: it
returns the correct number of high-order bits from the underlying
pseudo-random number generator. In the absence of special treatment,
the correct number of low-order bits would be returned. Linear
congruential pseudo-random number generators such as the one
implemented by this class are known to have short periods in the
sequence of values of their low-order bits. Thus, this special case
greatly increases the length of the sequence of values returned by
successive calls to this method if n is a small power of two.
The implementation looks like this:
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
While the next method looks like this (I've replaced the constants with literals)
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
(I suppose that 48-31 == 17 is purely coincidental)
Interesting question!
I have added some statistic-gathering to the code:
import java.util.*;
public class J {
static Random r = new Random();
private static class Stats {
long s[];
public Stats(int n) { this.s = new long[n]; }
public String toString() {
return Arrays.toString(s);
}
}
public static void test(int target, int options) {
boolean win = false;
Stats s = new Stats(target);
for (long iterations = 0; !win; iterations ++) {
int even = 0;
for (int i = 0; i < target; i++) {
if ((r.nextInt(options) % 2) != 0) {
s.s[i] ++;
break;
} else {
even ++;
}
}
if (even == target) {
win = true;
System.out.println(
"It took " + iterations + " loops to get " + target
+ " random values which are all even. Stats: " + s);
} else if (iterations >= 1E8) {
win = true;
System.out.println(iterations + ": " + s);
}
}
}
public static void main(String args[]) {
test(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
}
The code now ends if no sequence is found after 100M tries; and always stores how far it managed to get before failing (= drawing an odd number).
These are some runs:
18 9: It took 57235 loops to get 18 random values which are all even. Stats: [25401, 14081, 7864, 4328, 2508, 1366, 747, 390, 263, 126, 76, 38, 28, 4, 8, 4, 2, 1]
18 8: It took 48612 loops to get 18 random values which are all even. Stats: [24285, 12336, 6066, 2981, 1436, 738, 385, 197, 95, 43, 23, 10, 8, 7, 1, 0, 0, 1]
18 7: It took 23302 loops to get 18 random values which are all even. Stats: [10062, 5712, 3174, 1877, 1101, 590, 331, 190, 98, 59, 44, 31, 18, 8, 5, 2, 0, 0]
18 6: Aborted after 100000000 tries: [49997688, 24993911, 12503043, 6272129, 3113557, 1544194, 788879, 393680, 205236, 89264, 45016, 35858, 5340, 9155, 763, 1525, 0, 763]
So, for those particular values (100M attempts at runs of 18 even numbers, throwing 6-sided dice), there were 0 cases where the run bailed out because of the 17th number, but 763(!) where it bailed out because of the last number!
It definitely looks like a higher-quality PRNG is needed, such as the one mentioned by #radoh.
Probabilistically speaking, you would expect to find runs of N even throws of a fair coin with probability 1/(2^N); and you would expect to collect stats where each entry would be 1/2 the previous one. Encountering 0, 763 indicates a strong bias.
The issue is almost certainly with r.nextInt(nextIntValue);. Here you are requesting a random integer between 0 and 5. I cannot understand specifically why 18 is the break point but the chances a sequence of random positive integers less than a small number to be all even must reduce as the limit reduces.
I note that increasing that value from 6 to 100 still does not find length-18 even sequences. Perhaps the algorithm behind the scenes somehow influences the statistics.
Seems like the random generator doesn't allow 18 consecutive even numbers, when your maxRandom is even, starting at 6.
I changed the code a bit to demonstrate how the 18th random is always odd:
class NextIntWeirdness {
public static void main(String[] args) {
int maxRandom = 6;
Random r = new Random();
for (int i = 0; i < 100; i++) {
int evenNumbers = 17;
int evenResults;
do {
evenResults = 0;
for (int j = 0; j < evenNumbers; j++) {
int num = r.nextInt(maxRandom);
if (num % 2 != 0) {
break;
} else {
evenResults++;
}
}
} while (evenResults < evenNumbers);
System.out.println(r.nextInt(maxRandom));
}
}
}

Euler Challenge 1 in Java - I'm doing something wrong?

http://projecteuler.net/problem=1
Hey. I'm a high schooler trying to get a good grasp on programming problems, so I visited Project Euler. For Problem 1, I wrote up some code in Java that would of solved it, but something is evidently going wrong. Can I get some insight as to what?
Explanation:
I stop everything at the index value of 332 because Java counts from 0, and 333 * 3 is 999 which is below 1,000. Apples is a seperate class with pretty much the same code, although it counts for 5. At the end, I manually add together the two answers, but it wasn't right. What am I doing wrong?
The two final sums are:
Three: 164838
Five: 97515
public class Learning {
public static void main(String[] args){
int three[] = new int[333];
int counter = 0;
three[332] = 0;
int totalthree = 0;
int threeincrementer = 1;
int grandtotal;
boolean run = true;
boolean runagain = true;
for (counter = 1; counter<=332; counter++){
three[counter] = 3 * counter;
if (!(three[332] == 0)){
System.out.println("Finished three.");
while (run == true){
totalthree = totalthree + three[threeincrementer];
threeincrementer++;
if (threeincrementer >= 332){
run = false;
System.out.println("Three final is: " + totalthree);
}
}
}
if (runagain == true){
apples ApplesObject = new apples();
ApplesObject.rerun(0);
runagain = false;
}
}
}
}
Some numbers are at the same time multiplication of 3 AND 5 like 15 so you shouldn't separately calculate sum of all multiplications of 3 and multiplications of 5 and than add them because you will end up doing something like
sum3 = 3,6,9,12,15,...
sum5 = 5,10,15,...
so first sum3 will include 15, and sum5 will also include it which means you will add 15 two times. Now to balance your calculations you will need to subtract from your sum3+sum5 sum which will add all multiplications of 15
sum15 = 15,30,45,...
So using your approach your final formula should look like sum3+sum5-sum15.
But simpler solution for this problem can look like
sum = 0
for each X in 1...999
if (X is multiplication of 3) OR (X is multiplication of 5)
add X to sum
To check if some number X is multiplication of number Y you can use modulo operator % (example reminder = X % Y) which finds the remainder of division of one number by another.
You can find more Java operators here

How to write a program that reverses a number a user inputs

The homework problem is the user enters a number. Then you have to write a program that reverses that order. So if the user enters 7364 you have to write a program that presents 4637 on the next line. I think I've figured out the solution but I'm not sure how to write it.
Since the last number is the first number in reverse order that means that if someone enters 7364 that means i want to get 4637. I have to write a program that multiplies 4 by 1000, 6 by 100, 3 by 10 and 7 by 1 then add those up to get 4637. I'm not not 100% sure how to do it. What's messing me up is how to multiply one number by 1000, the next by 100, the next by 10 and the next by 1 then add those up.
import acm.program.*;
public class ReverseNumber extends ConsoleProgram{
public void run(){
int n = readInt("please enter any positive number: ");
int total = 0;
while ( n > 0){
total = total + n % 10; <----?
n = n * 1000; <----?
}
println("the reverse order is" + total);
}
}
The easiest way to do it using library.
System.out.println(new StringBuilder(String.valueOf(i)).reverse());
Try this:
while( n != 0 )
{
reverse = reverse * 10;
reverse = reverse + n%10;
n = n/10;
}
Logic is to get a single digit in each iteration starting from unit place, until all digits are encountered.
n is the input no.
reverse is the variable where reverse of n is stored after while is finished.
% operator when used with 10, gives you the digit at unit place.
/ operator when used with 10, goves you all the digits except the digit at unit place.
When n = 7364 and reverse = 0
in 1st iteration, loop will look like:
while(7364 != 0) // true
{
reverse = 0 * 10; // reverse = 0
reverse = 0 + 7364%10 // reverse = 4
n = 7364/10 // n = 736
}
in 2nd iteration:
while(736 != 0) // true
{
reverse = 4 * 10; // reverse = 40
reverse = 40 + 736%10 // reverse = 46
n = 736/10 // n = 73
}
in 3rd iteration:
while(73 != 0) // true
{
reverse = 46 * 10; // reverse = 460
reverse = 460 + 73%10 // reverse = 463
n = 73/10 // n = 7
}
in 4th iteration:
while(7 != 0) // true
{
reverse = 463 * 10; // reverse = 4630
reverse = 4630 + 7%10 // reverse = 4637
n = 7/10 // n = 0
}
in 5th iteration:
while(0 != 0) // false and loop ends
{
...
}
and we have reverse = 4637.
Well, to reverse the number the simplest solution would be to convert it to a string get the first letter and append it at the end until you reach the last letter or number in this case. Also, you can do pretty much the same with the multiplication part. Get the numbers one by one as a string convert it back to int then multiply and add.
EDIT: if you cant do it using strings. here is a somewhat mathematical solution.
int num = 123456; // any number than you want to reverse
string revnum = ''; // the reversed number
int temp = 0;
do {
temp= (temp*10)+(num%10);
num = (int)(num/10);
}while(num>0){
revnum = revnum + temp;
}
This should work:
total = 0;
while (n > 0) {
total = total * 10 + n % 10;
n = n / 10;
}
println("the reverse order is " + total);
You don't have to know how many digits there are in the original number, you're iterating through all of them anyway. Here's what happens:
When you get a new digit (n % 10), you multiply the result by 10 and add it to it. This way, you offset the digits in the result.
Then you eliminate the last digit (the one you added in the step before) from the original number by doing n / 10.
Do you have to represent it with an int? A String seems more natural?
If you stick with the int, you need to keep track of the factor to multiply with: which means another variable that you multiply by 10 each iteration.
Convert the Int to String, then put it in a StringBuffer
then use .reverse()
I wouldn't want to add the codes because there are many samples for this.
Like this one.
After that, you could convert it again to String.
public class value{
public static void main(String[] args){
int n=Integer.parseInt(args[0]);
int t=0;
do{
t=n%10;
System.out.print(t);
n=n/10;
}while(n>0);
}
}

Happy numbers checker not working correctly

int Cnt(){
return Count (10);
}
int Count (int init){
int u = init % 10;
int t = (init % 100) - u;
int u2 = u * u;
int t2 = t * t;
int m = u2 + t2;
if(m <= 1)
System.out.println("Happy!");
else {
return Count (m);
}
This code should (in theory) check if number is Happy, and if it's not sets initial value to be same as the result and whole process repeats.
Infinite loop should occur if number is not happy.
However none of this happens, does anyone know how to make this work?
According to the Wiki article that you linked, you have to repeat the process of summing the digits of the digits in each number. For the example of 7:
7^2 = 49
49 = 4^2 + 9^2 = 16 + 81 = 97
97 = 9^2 + 7^2 = 81 + 49 = 130
130 = 1^2 + 3^2 = 10
10 = 1^2 = 1
I see a few problems with your code. First, you haven't divided your tens digit by 10, which means for the number 52, you will get u = 2, and t = 50, rather than 5. This part, I'm sure you can easily fix.
Second, it looks like you will never reach a conclusion if your number is unhappy. For example with the number 4, you will reach 16, 37, 72, 53, 34, 25, 29, 85, 89, 145, 42, 20, 4. But your program, since you have no way of checking that you've entered a loop, will run until you run out of memory.
Try using the approach as outlined in the article you referenced:
private static boolean isHappy(int number)
{
List<Integer> set = new ArrayList<Integer>();
while (number > 1 && !set.contains(number))
{
set.add(number);
number = sumSquaresOfDigits(number);
}
return number == 1;
}
private static int sumSquaresOfDigits(int number)
{
String numberString = Integer.toString(number);
int result = 0;
for (char character : numberString.toCharArray())
{
int digit = Character.digit(character, 10);
result += digit * digit;
}
return result;
}
This can be done more efficiently by computing the squares of all 10 digits (0-9) and storing the results in an integer array.
Since this is homework I am not putting in the answer... but here is the clue..
You are not handling 3 digit numbers well.
t=init%100-u computes to 10%100-0 = 10
and once m=u2+t2 i.e. m=0+100 reaches to 100 and your program doesn't handle 3 digit numbers. Hope this helps.
add following...
int h = init/100;
int h2 = h * h;
int m = u2+t2+h2;
and it should keep you going... :)
import java.io.*;
class happy_no
{
void happy(double n)
{
int c=0;
double s=0;
double d,p,i,_sa;
for(i=1;i<=n;i++)
{
while(n!=0)
{
d=n%10;
p=d*d;
s=s+p;
n=n/10;
}
if(s==1)
{
System.out.println("HAPPY NO.");
break;
}
else
{
n=s;
}
}
}
public static void main()throws IOException
{
InputStreamReader read=new InputStreamReader(System.in);
BufferedReader in=new BufferedReader(read);
double a;
System.out.println("ENTER A NO.");
a=Double.parseDouble(in.readLine());
happy_no obj=new happy_no();
obj.happy(a);
}

Categories

Resources