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.
Related
I was wondering if there is a way or a library I can use to do the following:
I have an arraylist of objects where each obj has a name.
The list needs to always be unique with a maximum of 5 elements like [E1,E2,E3]
If for example the list has initial form [E3,E5] and I add an object, its name should be E1 and the list will be [E1,E3,E5] or [E3,E5,E1] it doesn't matter, as long as the name is unique and the item is added to the list starting from 1 to 5.
If add another item, it should be [E3,E5,E1,E2], always a unique name and between 1 and 5
These are my failed attempts,
StartNode node = new StartNode();
node.setName("E1");
for (int i = 0; i < circuit.getNbStartNodes(); i++) {
for (int j = 1; j <= circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (("E"+j).equalsIgnoreCase(test) && ("E"+j).equalsIgnoreCase(node.getName()) ) {
break;
}
else
node.setName("E" + j);
}
}
/*while (t <= circuit.getNbStartNodes()) {
for (int j = 0; j < circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (("E" + t).equalsIgnoreCase(test) || ("E" + t).equalsIgnoreCase(node.getName()))
break;
else {
node.setName("E" + t);
}
}
t++;
}
*/
/* for (int i = 1; i <= circuit.getNbStartNodes(); i++) {
for (int j = 0; j < circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (!("E" + i).equalsIgnoreCase(test)) {
node.setName("E" + i);
t=0;
break;
}
}
if (t==0)
break;
else
continue;
*/
//String test = ((StartNode) circuit.getStartNode(i)).getName();
//for (int j = 1; j <= circuit.getNbStartNodes(); j++) {
// if (!("E" + j).equalsIgnoreCase(test))
// node.setName("E" + j);
//}
What did I do wrong in my code?
Create a small boolean array to track which names are already used and populate it with accordingly
Find the first unused element and use it as id.
boolean[] used = new boolean[circuit.getNbStartNodes()];
for (int i = 0; i < used.length; i++) {
int index = Integer.parseInt(((StartNode) circuit.getStartNode(j)).getName().substring(1)) - 1; // should be in range 0..4
used[index] = true;
}
String name = "E";
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
name += String.valueOf(i + 1); // starting from 1
break;
}
}
System.out.println("free name: " + name);
StartNode node = new StartNode();
node.setName(name);
// add new node to circuit, etc.
With small values, Alex' solution works fine.
However, if you ever come across a use case where the number of elements become potentially large, then you could use a TreeSet to keep track of the unused numbers. Further, the nextCeilValue is the next number to pick when there are no removed numbers.
In the below code, I have created a UniqueNumber class, which is able to get the next number, or remove a given number. Note that this code provides integers starting from 0. Of course, you could easily convert this to your E-numbers using the function i -> "E" + (i + 1).
public class UniqueNumber {
private int nextCeilValue;
private final TreeSet<Integer> removedNumbers = new TreeSet<>(Integer::compare);
public int get() {
if (removedNumbers.isEmpty()) {
return nextCeilValue++;
}
else {
int number = removedNumbers.first();
removedNumbers.remove(number);
return number;
}
}
public boolean remove(int number) {
if (number < 0 || number > nextCeilValue) {
return false;
}
if (number == nextCeilValue) {
nextCeilValue--;
}
else {
removedNumbers.add(number);
}
return true;
}
public int size() {
return nextCeilValue - removedNumbers.size();
}
}
In order to test this, we first need to simulate your initial situation. In our integer-starting-from-zero-world, we need the numbers 2 and 4 (representing E3 and E5). In below code, we need to call get five times, and then remove element 0, 1 and 3. Of course, we could have created a UniqueNumber(int... initialValues) constructor which does this under the hood.
UniqueNumber un = new UniqueNumber();
for (int i = 0; i < 5; i++) {
un.get();
}
un.remove(0); // Remove E1
un.remove(1); // Remove E2
un.remove(3); // Remove E4
In order to get the next value, simply use this:
StartNode node = new StartNode();
node.setName("E" + (un.get() + 1));
I saw this challenge on https://www.topcoder.com/ for Beginners. And I really wanted to complete it. I've got so close after so many failures. But I got stuck and don't know what to do no more. Here is what I mean
Question:
Read the input one line at a time and output the current line if and only if you have already read at least 1000 lines greater than the current line and at least 1000 lines less than the current line. (Again, greater than and less than are with respect to the ordering defined by String.compareTo().)
Link to the Challenge
My Solution:
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
SortedSet<String> linesThatHaveBeenRead = new TreeSet<>();
int lessThan =0;
int greaterThan =0;
Iterator<String> itr;
for (String currentLine = r.readLine(); currentLine != null; currentLine = r.readLine()){
itr = linesThatHaveBeenRead.iterator();
while(itr.hasNext()){
String theCurrentLineInTheSet = itr.next();
if(theCurrentLineInTheSet.compareTo(currentLine) == -1)++lessThan;
else if(theCurrentLineInTheSet.compareTo(currentLine) == 1)++greaterThan;
}
if(lessThan >= 1000 && greaterThan >= 1000){
w.println(currentLine);
lessThan = 0;
greaterThan =0;
}
linesThatHaveBeenRead.add(currentLine);
}
}
PROBLEM
I think the problem with my solution, is because I'm using nested loops which is making it a lot slower, but I've tried other ways and none worked. At this point I'm stuck. The whole point of this challenge is to make use of the most correct data-structure for this problem.
GOAL:
The goal is to use the most efficient data-structure for this problem.
Let me try to present just an accessible refinement of what to do.
public static void
doIt(java.io.BufferedReader r, java.io.PrintWriter w)
throws java.io.IOException {
feedNonExtremes(r, (line) -> { w.println(line);}, 1000, 1000);
}
/** Read <code>r</code> one line at a time and
* output the current line if and only there already were<br/>
* at least <code>nHigh</code> lines greater than the current line <br/>
* and at least <code>nLow</code> lines less than the current line.<br/>
* #param r to read lines from
* #param sink to feed lines to
* #param nLow number of lines comparing too small to process
* #param nHigh number of lines comparing too great to process
*/
static void feedNonExtremes(java.io.BufferedReader r,
Consumer<String> sink, int nLow, int nHigh) {
// collect nLow+nHigh lines into firstLowHigh; instantiate
// - a PriorityQueue(firstLowHigh) highest
// - a PriorityQueue(nLow, (a, b) -> String.compareTo(b, a)) lowest
// remove() nLow elements from highest and insert each into lowest
// for each remaining line
// if greater than the head of highest
// add to highest and remove head
// else if smaller than the head of lowest
// add to lowest and remove head
// else feed to sink
}
Made you a little example with Binary search, now in Java code. It will only use Binary search when newLine is within limits of the sorting.
public static void main(String[] args) {
// Create random lines
ArrayList<String> lines = new ArrayList<String>();
Random rn = new Random();
for (int i = 0; i < 50000; i++) {
int lenght = rn.nextInt(100);
char[] newString = new char[lenght];
for (int j = 0; j < lenght; j++) {
newString[j] = (char) rn.nextInt(255);
}
lines.add(new String(newString));
}
// Here starts logic
ArrayList<String> lowerCompared = new ArrayList<String>();
ArrayList<String> higherCompared = new ArrayList<String>();
int lowBoundry = 1000, highBoundry = 1000;
int k = 0;
int firstLimit = Math.min(lowBoundry, highBoundry);
// first x lines sorter equal
for (; k < firstLimit; k++) {
int index = Collections.binarySearch(lowerCompared, lines.get(k));
if (index < 0)
index = ~index;
lowerCompared.add(index, lines.get(k));
higherCompared.add(index, lines.get(k));
}
for (; k < lines.size(); k++) {
String newLine = lines.get(k);
boolean lowBS = newLine.compareTo(lowerCompared.get(lowBoundry - 1)) < 0;
boolean highBS = newLine.compareTo(higherCompared.get(0)) > 0;
if (lowerCompared.size() == lowBoundry && higherCompared.size() == highBoundry && !lowBS && !highBS) {
System.out.println("Time to print: " + newLine);
continue;
}
if (lowBS) {
int lowerIndex = Collections.binarySearch(lowerCompared, newLine);
if (lowerIndex < 0)
lowerIndex = ~lowerIndex;
lowerCompared.add(lowerIndex, newLine);
if (lowerCompared.size() > lowBoundry)
lowerCompared.remove(lowBoundry);
}
if (highBS) {
int higherIndex = Collections.binarySearch(higherCompared, newLine);
if (higherIndex < 0)
higherIndex = ~higherIndex;
higherCompared.add(higherIndex, newLine);
if (higherCompared.size() > highBoundry)
higherCompared.remove(0);
}
}
}
You need to implement binary search and also need to handle duplicates.
I've done some code sample here which does what you want ( may contains bugs).
public class CheckRead1000 {
public static void main(String[] args) {
// generate strings in revert order to get the worse case
List<String> aaa = new ArrayList<String>();
for (int i = 50000; i > 0; i--) {
aaa.add("some string 123456789" + i);
}
// fast solution
ArrayList<String> sortedLines = new ArrayList<>();
long st1 = System.currentTimeMillis();
for (String a : aaa) {
checkIfRead1000MoreAndLess(sortedLines, a);
}
System.out.println(System.currentTimeMillis() - st1);
// doIt solution
TreeSet<String> linesThatHaveBeenRead = new TreeSet<>();
long st2 = System.currentTimeMillis();
for (String a : aaa) {
doIt(linesThatHaveBeenRead, a);
}
System.out.println(System.currentTimeMillis() - st2);
}
// solution doIt
public static void doIt(SortedSet<String> linesThatHaveBeenRead, String currentLine) {
int lessThan = 0;
int greaterThan = 0;
Iterator<String> itr = linesThatHaveBeenRead.iterator();
while (itr.hasNext()) {
String theCurrentLineInTheSet = itr.next();
if (theCurrentLineInTheSet.compareTo(currentLine) == -1) ++lessThan;
else if (theCurrentLineInTheSet.compareTo(currentLine) == 1) ++greaterThan;
}
if (lessThan >= 1000 && greaterThan >= 1000) {
// System.out.println(currentLine);
lessThan = 0;
greaterThan = 0;
}
linesThatHaveBeenRead.add(currentLine);
}
// will return if we have read more at least 1000 string more and less then our string
private static boolean checkIfRead1000MoreAndLess(List<String> sortedLines, String newLine) {
//adding string to list and calculating its index and the last search range
int indexes[] = addNewString(sortedLines, newLine);
int index = indexes[0]; // index of element
int low = indexes[1];
int high = indexes[2];
//we need to check if this string already was in list for instance
// 1,2,3,4,5,5,5,5,5,6,7 for 5 we need to count 'less' as 4 and 'more' is 2
int highIndex = index;
for (int i = highIndex + 1; i < high; i++) {
if (sortedLines.get(i).equals(newLine)) {
highIndex++;
} else {
//no more duplicates
break;
}
}
int lowIndex = index;
for (int i = lowIndex - 1; i > low; i--) {
if (sortedLines.get(i).equals(newLine)) {
lowIndex--;
} else {
//no more duplicates
break;
}
}
// just calculating how many we did read more and less
if (sortedLines.size() - highIndex - 1 > 1000 && lowIndex > 1000) {
return true;
}
return false;
}
// simple binary search will insert string and return its index and ranges in sorted list
// first int is index,
// second int is start of range - will be used to find duplicates,
// third int is end of range - will be used to find duplicates,
private static int[] addNewString(List<String> sortedLines, String newLine) {
if (sortedLines.isEmpty()) {
sortedLines.add(newLine);
return new int[]{0, 0, 0};
}
// int index = Integer.MAX_VALUE;
int low = 0;
int high = sortedLines.size() - 1;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (sortedLines.get(mid).compareTo(newLine) < 0) {
low = mid + 1;
} else if (sortedLines.get(mid).compareTo(newLine) > 0) {
high = mid - 1;
} else if (sortedLines.get(mid).compareTo(newLine) == 0) {
// index = mid;
break;
}
if (low > high) {
mid = low;
}
}
if (mid == sortedLines.size()) {
sortedLines.add(newLine);
} else {
sortedLines.add(mid, newLine);
}
return new int[]{mid, low, high};
}
}
I'm trying to use this method to sort an integer array in ascending order. But my for loop runs through it only once.
public void sortArray()
{
boolean sorted = false;
while(sorted == false)
{
int temp;
for(int i = 0; i < inArray.length - 1; i++)
{
if(inArray[i] > inArray[i + 1])
{
temp = inArray[i];
inArray[i] = inArray[i + 1];
anArray[i + 1] = temp;
}
}
sorted = true;
}
}
I know it has to do with how I'm handling that boolean flag, but I'm not sure how to go about fixing it. Any suggestions would be appreciated. Thanks in advance.
There are multiple issues here:
while (sorted = false) sets sorted to false and then tests the resulting value false, meaning that you never enter the loop body at all (not once as per your question).
If you fix that, your code will only run the while loop body once (thus leaving the array not sorted yet), because you have sorted = true as an unconditional statement at the end of the loop body.
You need to have a flag that assumes the array is sorted, and then is cleared if you find evidence it wasn't, something like:
public void sortArray()
{
boolean sorted;
do
{
sorted = true; // Assume it's sorted
int temp;
for(int i = 0; i < inArray.length - 1; i++)
{
if(inArray[i] > inArray[i + 1])
{
temp = inArray[i];
inArray[i] = inArray[i + 1];
anArray[i + 1] = temp;
sorted = false; // We changed something, so assume we need to do another pass
}
}
}
while (!sorted);
}
Side note: This is just a style thing, but it's generally best to scope variables as narrowly as possible. There's no need for temp to be outside the for loop or even outside the if block, move it inside the if block
public void sortArray()
{
boolean sorted;
do
{
sorted = true; // Assume it's sorted
for(int i = 0; i < inArray.length - 1; i++)
{
if(inArray[i] > inArray[i + 1])
{
int temp = inArray[i];
inArray[i] = inArray[i + 1];
anArray[i + 1] = temp;
sorted = false; // We changed something, so assume we need to do another pass
}
}
}
while (!sorted);
}
You currently are setting your sorted to true allways at the end of the loop. While of course it should only be true if actually no reshuffling took place.
One way to archieve this would be to set sorted to true at the start of your while loop, and set it to false when you detect that the array is not yet sorted and you do the switching of elements:
public void sortArray()
{
boolean sorted = false;
while(!sorted)
{
sorted = true;
int temp;
for(int i = 0; i < inArray.length - 1; i++)
{
if(inArray[i] > inArray[i + 1])
{
sorted = false; // array is not yet sorted
temp = inArray[i];
inArray[i] = inArray[i + 1];
anArray[i + 1] = temp;
}
}
}
}
My method which contains no java collections
public class Main {
public static void main(String[] args) {
/** By Boris Elkin 21.09.2018 в 22.59 MSK You can input any digits, sorting was made without collections on purpose.
**/
int[] a1=new int[]{1,245623,3,3,3,3454,6,8123,234,123123,797897};
int[] a2=new int[]{234234, 33,4234,5,646456,9,78};
int[] a3;
a3= collide(a1, a2);
a3=sort(a3);
checkArray(a3);
}
public static int[] collide(int[]a, int[]b){
int breakpoint=0;
int size=a.length+b.length;
int[]c=new int[size];
for(int i=0;i<a.length;i++){
c[i]=a[i];
breakpoint=i;
}
for(int i=breakpoint+1,j=0;j<b.length;i++, j++){
c[i]=b[j];
}
return c;
}
public static int[] sort(int a[]){
boolean engine=true;
while(engine) {
for(int i=0;i<a.length;i++){
int temp, temp2;
if ((i + 1 < a.length) && (a[i] > a[i + 1])) {
temp = a[i];
temp2 = a[i + 1];
a[i + 1] = temp;
a[i] = temp2;
}
}
if(checkThreadLogistic(a)){
engine=false;
}
}
return a;
}
private static boolean checkThreadLogistic(int[] a) {
return checkCertainElement(a);
}
private static boolean checkCertainElement(int[] a) {
for(int i=0;i<a.length;i++){
if(i>1){
for(int j=a.length;j>i;j--){
if(j<a.length) if(a[i]>a[j])return false;
}
}
}
return true;
}
public static void checkArray(int[]array){
for (int anArray : array) {
System.out.println(anArray + "");
}
}
}
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..
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));
}
}
}
}