Why is this program running so slowly? - java

This is for project euler problem 14.
When a number is even, you're supposed to divide the number by two, but when it is odd you multiply it by three and add one. Eventually it should reach one.
My task is to find the number that takes the largest amount of steps to get to 1.
Here's my code:
int currentNum = 0;
int iterator = 0;
int[] largestChain = new int[]{0,0};
for(int i = 10;i<=1000000;i++)
{
currentNum = i;
iterator = 0;
while(currentNum!=1)
{
iterator++;
if(currentNum%2==0)
{
currentNum/=2;
}
else
{
currentNum = (currentNum*3)+1;
}
}
if(iterator>largestChain[1])
{
largestChain[0] = i;
largestChain[1] = iterator;
}
}
System.out.println("largest iterator:"+largestChain[1]+"for num:"+largestChain[0]);
Can you please help me out by telling me what's slowing it down? (It's taking >30 minutes right now and it still hasn't come up with the answer).

Use long variables instead of int. currentNum goes so high the values wrap around into the negatives!
Once you do that change, your algorithm works just fine. (I tested it)

The reason it take so long is that you are performing this while loop operation on 1 million numbers. The solution to this is to create an algorithm which saves the number of steps dynamically.
int[] steps = new int[1000000];
steps[0] = 0;
steps[1] = 1;
Iterate through the rest of your numbers, adding back to this base case. By the end, many of your paths will be computed, and you will not need a nested loop.
However, if you want to stick to your way:
I'd recommend putting some debug print statements in there to see where it is getting caught up. My guess is that the 1 Million looped while statements are the culprit, but the easiest way to find out is progress check.
try adding System.out.println(i+":"); before the while and System.out.println(" current number: "+currentnum); inside the while.
Should print out something like:
1:
1
2:
2
1
etc.

I modified the code to print the interesting info and how its looping. The loop is crazy.
I would suggest converting currentNum to 'long' and re-run it as that number goes negative (beyond int capacity).
public class TestLoop{
public static void main(String[] args){
int currentNum = 0;
int iterator = 0;
int[] largestChain = new int[]{0,0};
for(int i = 10;i<=1000000;i++)
{
currentNum = i;
iterator = 0;
System.out.println("\nCurrently Running :" + i);
while(currentNum!=1)
{
iterator++;
if(currentNum%2==0)
{
currentNum/=2;
}
else
{
currentNum = (currentNum*3)+1;
}
System.out.print(currentNum + " ");
}
if(iterator>largestChain[1])
{
largestChain[0] = i;
largestChain[1] = iterator;
}
}
System.out.println("\nLargest iterator: "+largestChain[1]+" for num:"+largestChain[0]);
}
}
I ran it on linux and got below answer in 10 mins after I changed the currentNum to 'long'.
Largest iterator: 524 for num:837799
Still there is a flaw in your logic: you are NOT checking if any other number taking the same iterations. E.g. below loop gives two such numbers :
import java.util.ArrayList;
public class TestLoop {
public static void main(String[] args) {
long currentNum;
int iterator;
int[] largestChain = new int[]{0, 0};
ArrayList Nums = new ArrayList();
for (int i = 10; i <= 300; i++) {
currentNum = i;
iterator = 0;
System.out.println("\nCurrently Running :" + i);
while (currentNum != 1) {
iterator++;
if (currentNum % 2 == 0) {
currentNum /= 2;
} else {
currentNum = (currentNum * 3) + 1;
}
System.out.print(currentNum + " ");
}
if (iterator > largestChain[1]) {
largestChain[0] = i;
largestChain[1] = iterator;
Nums.clear();
Nums.add(i);
} else if (iterator == largestChain[1]) {
Nums.add(i);
}
}
System.out.println("\nLargest iterator: " + largestChain[1]);
//+ " for num:" + largestChain[0]);
if (Nums.size() == 1) {
System.out.println("There is only one number with " + largestChain[1] + " iterations:" + largestChain[0]);
} else {
System.out.print("Below numbers took " + largestChain[1] + " iterations:");
for (int i = 0; i < Nums.size(); i++) {
System.out.print(" " + Nums.get(i));
}
}
}
}

Related

Coding Bubble Sort using Java

I don't know if I did this coding correctly, but can someone confirm if my doBubbleSort method and its implementation in the main method are programmed correctly? My coding requires me to create an array of size 20 and populate it with random integers between 1 and 1000 without hard coding them. The result should display the original, unsorted list of integers; and then display each pass of the bubble sorting algorithm on a separate line. I have to repeat the program until the user chooses to quit. **I have made edits to make sure that whatever variables I use, it is declared according to ArrayLists.
An example of how I want my output to come out as is shown below (although it only shows 5 integers when I'm trying to do 20):
Unsorted list: 68 3 298 290 1
Pass 1: 3 68 290 1 298
Pass 2: 3 68 1 290 298
Pass 3: 3 1 68 290 298
Pass 4: 1 3 68 290 298
// Used to capture keyboard input
import java.util.*;
// Our class called BubbleSort
public class BubbleSort {
// Create doBubbleSort method
public static void doBubbleSort(ArrayList<Integer> arr) {
boolean needNextPass = true;
while (needNextPass) {
// Array may be sorted and next pass not needed
needNextPass = false;
// Swap list
for (int i = 0; i < arr.size()-1; i++) {
if (arr.get(i) > arr.get(i+1)) {
int temp = arr.get(i);
arr.set(i, arr.get(i+1));
arr.set(i+1, temp);
printOut(i+1, arr); // using printOut method
needNextPass = true; // Next pass still needed
}
}
}
}
private static void printOut(int pass, ArrayList<Integer> list) {
System.out.print("PASS " + pass + ": ");
for (int i = 0; i < list.size()-1; i++) {
System.out.print(list.get(i) + ", ");
}
// Shows very last integer with a period
System.out.print(list.get(list.size()-1) + ".");
System.out.println();
}
// Main method
public static void main(String[] args) {
ArrayList<Integer> array = new ArrayList<Integer>(); // Declare and instantiate a new ArrayList object
Scanner userChoice = new Scanner(System.in); // User input for quitting program
String choice = ""; // Will hold user choice to quit program
boolean inputFlag = false; // True if input is valid, false otherwise
// Repeat program until user chooses to quit
while (inputFlag = true) {
System.out.print("\nWould you like to continue the program? (Y/N): ");
choice = userChoice.nextLine();
if (choice.equalsIgnoreCase("Y")) {
try {
/* Create an array of size 20 and populate it with random integers between 1 and 1000.
Do not ask user for the numbers and do not hard code them */
for (int i = 0; i < 20; i++) {
int integer = (int)(1000.0 * Math.random());
array.add(integer);
}
System.out.print("\nUNSORTED LIST: ");
//Display the 20 size of the unsorted ArrayList
for (int i = 0; i < array.size() - 1; i++) {
System.out.print(array.get(i) + ", ");
}
// Shows very last integer with a period
System.out.print(array.get(array.size() - 1) + ".");
System.out.println();
doBubbleSort(array);
}
catch (IndexOutOfBoundsException e) {
System.out.println("\nThere is an out of bounds error in the ArrayList.");
}
}
else if (choice.equalsIgnoreCase("N")) {
break;
}
// Error message when inputting anything other than Y/N
else {
System.out.println("\nERROR. Only Y, y, N, or n may be inputted.");
System.out.println("Please try again.");
}
}
}
}
Going with your implementation, since you seem to be newly learning this, there are a few things you should change. First of all, since you're using an int array for the doBubbleSort method, use an int array in the main method as well.
The implementation of bubblesort needs to be changed too. You should first look into its logic carefully. Going through the whole array every time is not necessary.
// Create doBubbleSort method
public static void doBubbleSort(int[] arr) {
boolean needNextPass = true;
// Array may be sorted and next pass not needed
// Swap list
for (int i = 0; i < arr.length - 1; i++) {
if (needNextPass) {
needNextPass = false;
for (int j = arr.length - 1; j > i; j--) {
int temp;
if (arr[j] < arr[j - 1]) {
temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
needNextPass = true; // Next pass still needed
}
}
printOut(i + 1, arr); // using printOut method
}
}
}
And then, printing the array.
private static void printOut(int pass, int[] list) {
System.out.print("PASS " + pass + ": ");
for (int i = 0; i < list.length - 1; i++) {
System.out.print(list[i] + ", ");
}
// Shows very last integer with a period
System.out.print(list[list.length - 1] + ".");
System.out.println();
}
Now the main method. I've changed the input handling part for re-running the program, and used an int array as you had originally posted.
// Main method
public static void main(String[] args) {
int[] array = new int[20]; // Declare and instantiate a new ArrayList object
Scanner userChoice = new Scanner(System.in); // User input for quitting program
boolean inputFlag = true; // True if input is valid, false otherwise
String choice;
// Repeat program until user chooses to quit
while (inputFlag == true) {
try {
/* Create an array of size 20 and populate it with random integers between 1 and 1000.
Do not ask user for the numbers and do not hard code them */
for (int i = 0; i < 20; i++) {
int integer = (int) (1000.0 * Math.random());
array[i] = integer;
}
System.out.print("\nUNSORTED LIST: ");
//Display the 20 size of the unsorted ArrayList
for (int i = 0; i < array.length - 1; i++) {
System.out.print(array[i] + ", ");
}
// Shows very last integer with a period
System.out.print(array[array.length - 1] + ".");
System.out.println();
doBubbleSort(array);
} catch (IndexOutOfBoundsException e) {
System.out.println("\nThere is an out of bounds error in the ArrayList.");
}
System.out.print("\nWould you like to continue the program? (Y/N): ");
choice = userChoice.nextLine();
while (!(choice.equalsIgnoreCase("Y")) && !(choice.equalsIgnoreCase("N"))) {
// Error message when inputting anything other than Y/N
System.out.println("\nERROR. Only Y, y, N, or n may be inputted.");
System.out.println("Please try again.");
choice = userChoice.nextLine();
}
if (choice.equalsIgnoreCase("N")) {
inputFlag = false;
}
}
}
}
You wrote too much boiler plate code for bubble sort. For bubble sort, use recursive method. I wrote for you simple bubble method, do what you want with output
private int[] bubbleSort(int[] arr){
int c;
boolean isArranged = false;
for (int i = 0; i < arr.length; i++) {
if (i < (arr.length - 1) && arr[i] > arr[i+1]){
c = arr[i];
arr[i] = arr[i+1];
arr[i+1] = c;
isArranged = true;
}
}
if (isArranged){
return bubbleSort(arr);
}else{
return arr;
}
}
Call this like:
Scanner in = new Scanner(System.in);
int length = in.nextInt();
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = in.nextInt();
}
Main main = new Main();
int[] newArr = main.bubbleSort(arr);
for (int i = 0; i < newArr.length; i++) {
System.out.print(newArr[i] + " ");
}
You can write ArrayList instead int array.

Blue J shows it is running, but will not open result window

I have been running a program that simulates the number of steps it will take to get across a 7-step bridge. A random number is generated to determine if the person takes a step forwards or backwards. This simulation is run 1000 times. After this the average number of steps it takes to get across is out printed, as well as the maximum number of steps it took.
This, in turn is run 1000 times. It compiles fine. My issue is that when I go to run it, (on BlueJ) the bar shows that it is running but the output window fails to appear. What is happening? (Most likely is something stupidly obvious that I am oblivious to.)
import java.util.Random;
public class Prog214a
{
public static void main (String[] args)
{
Random rn = new Random();
for (int m = 1; m <= 20; m++)
{
int max = 0;
for (int c = 1; c <= 1000; c++)
{
int s = 0;
int sn = 0;
int sum = 0;
while (s < 7)
{
int ans = rn.nextInt(1) + 0;
if (ans == 1) {
s = s + 1
}
else {
s = s - 1;
}
sn++;
}
sum = sum + sn;
if (sn > max) {
max = sn;
}
if (c == 1000) {
double avg = sum / c;
System.out.print(avg);
System.out.print(" " + max);
}
}
}
}
}
There is at least one problem. Here:
int ans = rn.nextInt(1) + 0;
if (ans == 1){
s = s + 1;
}
else {
s = s -1;
}
rn.nextInt(1) can only return 0, so ans will be 0. You have no guard to ensure that s does not go negative, so it does - and it remains less than 7, meaning that the while loop (with condition s < 7) goes on for a long time (specifically, until s wraps back to a positive number again).

Merge Sort isn't working

I have written a program in which you can sort an ArrayList using 3 different sort methods: bubble, merge and bogo (or stupid sort). Here's the code:
import java.util.*;
import java.io.*;
import java.lang.*;
import java.lang.IndexOutOfBoundsException;
public class Sorting {
public static void bubbleSort(ArrayList<Integer> bubble) {
int temp;
if (bubble.size() > 1) {
for (int i = 0; i < bubble.size(); i++) {
for (int j = 0; j < bubble.size() - i - 1; j++) {
if (bubble.get(i).compareTo(bubble.get(i + 1)) > 0) {
temp = bubble.get(i);
bubble.set(i, bubble.get(i + 1));
bubble.set(i + 1, temp);
}
}
}
}
}
public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
if (merge.size() == 1) {
return merge;
} else {
int halfway = merge.size() / 2;
ArrayList<Integer> left = new ArrayList<Integer>(halfway);
ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);
for (int i = 0; i < halfway; i++) {
left.add(merge.get(i));
}
for (int i = halfway; i < merge.size(); i++) {
right.add(merge.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
ArrayList<Integer> newMerge = new ArrayList<Integer>(merge.size());
int index1 = 0;
int index2 = 0;
for (int i = 0; i < merge.size(); i++) {
if (index1 == left.size()) {
merge.set(i, right.get(index2));
index2++;
} else if (index2 == right.size()) {
merge.set(i, left.get(index1));
index1++;
} else {
if (left.get(index1) <= right.get(index2)) {
newMerge.set(i, left.get(index1));
index1++;
} else if (left.get(index1) >= right.get(index2)) {
newMerge.set(i, right.get(index2));
index2++;
}
}
}
return newMerge;
}
}
public static void bogoSort(ArrayList<Integer> bogo) {
while (!isOrdered(bogo)) {
Collections.shuffle(bogo);
}
}
public static boolean isOrdered(ArrayList<Integer> order) {
for (int i = 0; i < order.size(); i++) {
if (order.get(i) > order.get(i + 1)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
try {
Scanner input = new Scanner(new File("random1.txt"));
ArrayList<Integer> random = new ArrayList<Integer>();
while (input.hasNextInt()) {
random.add(input.nextInt());
}
input.close();
System.out.println("Unsorted: " + random);
long startTime = System.nanoTime();
bubbleSort(random);
long endTime = System.nanoTime();
long duration = ((endTime - startTime) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Bubble sort took: " + duration + " milliseconds to sort.");
System.out.println();
long startTime2 = System.nanoTime();
mergeSort(random);
long endTime2 = System.nanoTime();
long duration2 = ((endTime2 - startTime2) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Merge sort took: " + duration2 + " milliseconds to sort.");
System.out.println();
long startTime3 = System.nanoTime();
bogoSort(random);
long endTime3 = System.nanoTime();
long duration3 = ((endTime3 - startTime3) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Bogo sort took: " + duration3 + " milliseconds to sort.");
System.out.println();
} catch (FileNotFoundException e) {
System.out.println("File is not found.");
System.exit(1);
}
}
}
When I ran the program, the unsorted ArrayList and the bubble sort method showed up but I received an error with my Merge Sort method, which stated that I have an IndexOutOfBoundsException at lines 38, 57 & 102. I did the algorithm correctly but I don't know why I'm receiving an error. Any reasoning behind this?
To List, you can not add or set element, at specific index, if the index is greater than the size. Check the documentation here. You can add null values to your List(newMerge) to fix this or simply add elements to your newMerge list. I prefer later. The other IndexOutOfBoundsException exceptions are related to this.
Corrected Code
public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
if (merge.size() == 1) {
return merge;
} else {
int halfway = merge.size() / 2;
ArrayList<Integer> left = new ArrayList<Integer>(halfway);
ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);
for (int i = 0; i < halfway; i++) {
left.add(merge.get(i));
}
for (int i = halfway; i < merge.size(); i++) {
right.add(merge.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
int index1 = 0;
int index2 = 0;
// Merge left and right sub-lists into original list
// See how the newMerge list is no longer needed
for (int i = 0; i < merge.size(); i++) {
if (index1 == left.size()) {
merge.set(i, right.get(index2));
index2++;
} else if (index2 == right.size()) {
merge.set(i, left.get(index1));
index1++;
} else {
if (left.get(index1) <= right.get(index2)) {
merge.set(i, left.get(index1)); // We now set the values into merge
index1++;
} else if (left.get(index1) >= right.get(index2)) {
merge.set(i, right.get(index2)); // We now set the values into merge
index2++;
}
}
}
return merge; // We now return a reference to merge, not newMerge
}
}
public static boolean isOrdered(ArrayList<Integer> order) {
for (int i = 0; i < order.size() - 1; i++) { // order.size() - 1 prevents going out of bounds
if (order.get(i) > order.get(i + 1)) {
return false;
}
}
return true;
}
Elaboration
Issues with mergeSort()
The issue arises when you begin merging your left and right sub-lists. Note that during the merging process you invoke the set() method on both the newMerge and merge lists. This isn't what you want. Within the "merge"-loop you may attempt to set a value into the newMerge list when it is empty, or when i is greater than its size. This is the reason for the error you're getting. Since your other sorts seem to sort the original list that was passed in (versus creating a copy, sorting, and returning the copy instead) I can assume your merge sort was intended to do the same. If that's the case, there isn't actually a need for a newMerge list at all, since we can just write into the original merge list. This change can be seen in the code above.
Issues with isOrdered()
Minor issue here. You should have terminated your loop when i == order.size() - 1, not when i == order.size(). Otherwise, when i == order.size() - 1, order.get(i + 1) will attempt to retrieve an element that does not exist within the list (i.e. out of bounds).
I did the algorithm correctly but I don't know why I'm receiving an error.
Clearly, you haven't done the algorithm correctly, or you wouldn't be getting the exception. ;-)
You are calling:
merge.set(i, right.get(index2));
and
merge.set(i, left.get(index1));
which is modifying the original list, not your newly created newMerge list which is returned from mergeSort. The caller expects the returned list to have as many elements as it was passed, but (since it is never modified) it actually has zero, which results in the exception in the caller.
Use newMerge as the target of your set calls, and use add instead of trying to set at a particular index.

Lychrel Number Program Error

I am trying to make the lychrel number program. but i cannot make it. Criteria is that, list the Lychrel Number which is below in 10000,Lychrel number checking iteration in limited. I have been set it as 30.But i didnt got the solution yet.
number should be listed if the checking completed upto 30 iteration. i didnt get the solutions.help me.
public class LychrelNumber {
static final int MAX_NUMBER = 10000;
static final int MAX_ITERATION = 30;
int iterationCount = 0;
void listTheLychrelNymber() throws Exception {
long i = 0;
long temp;
for (int j = 0; j < MAX_NUMBER; j++) {
iterationCount = 0;
temp = j;
for (i = 0; i < MAX_ITERATION; i++) {
long first = temp;
long second = reverseTheNumber(temp);
long third = first + second;
long fourth = reverseTheNumber(third);
if (third == fourth) {
break;
} else {
temp = third;
if (i == MAX_ITERATION) {
System.out.println("Lychrel Numbers are :" + j);
}
}
}
}
}
long reverseTheNumber(long n) {
long reverse = 0;
while (n != 0) {
reverse = reverse * 10;
reverse = reverse + n % 10;
n = n / 10;
}
return reverse;
}
public static void main(String[] args) {
try {
LychrelNumber lychrelNumber = new LychrelNumber();
lychrelNumber.listTheLychrelNymber();
} catch (Exception e) {
}
}
}
it is build successfull. but i didnt get the output.
Look at your loop of i (I shortened the code a bit)
for (i = 0; i < MAX_ITERATION; i++) {
if (i == MAX_ITERATION) {
System.out.println("Lychrel Numbers are :" + j);
}
}
As you see, you stop looping when i reaches MAX_ITERATION but only print the Lychrel number in the loop if i == MAX_ITERATION (which will of course never happen).
I got the solution.
if (i == (MAX_ITERATION-1)) {
System.out.println("Lychrel Numbers are:" + j);
}
here i made the mistake in Condition Checking..

Codeforces Round #322 (Div. 2) - B O(n) but still overtime

The problem: http://codeforces.com/contest/581/problem/B
My code is O(n), and I compared my code with others, cannot understand why my code exceeds the time limit in test case 6 (with n = 100,000)? Any idea?
private void solve() throws IOException {
//String s = nextToken();
int n = nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = nextInt();
}
int max = -1;
String ans = "";
for (int i = array.length-1; i >=0; i--) {
if (array[i] >= max) {
max = array[i];
ans = 0 + " " + ans;
}
else {
ans = ( max - array[i] +1) + " " + ans ;
}
}
writer.println(ans.substring(0,ans.length()-1));
}
Your code is not O(n); + on a String is O(n) and your code is O(n^2). You'd need to use StringBuilder instead.
Additionally, inserting at the beginning instead of the end is also generally bad, so even StringBuilder won't let you do that efficiently.
You'll need to figure out how to build the answer the other way around.

Categories

Resources