package com.rmd.personal.projecteuler;

public class Problem14 implements Problem {

    private static final long DEFAULT_START_VALUE = 1;
    private static final long DEFAULT_END_VALUE = 1000000;

    private long startVal;
    private long endVal;

    public Problem14() {
        this.setStartVal(DEFAULT_START_VALUE);
        this.setEndVal(DEFAULT_END_VALUE);
    }

    public long getStartVal() {
        return startVal;
    }

    public void setStartVal(long startVal) {
        this.startVal = startVal;
    }

    public long getEndVal() {
        return endVal;
    }

    public void setEndVal(long endVal) {
        this.endVal = endVal;
    }

    @Override
    public String getDescription() {
        return "The following iterative sequence is defined for the set of positive integers:\n\n"
                + "n → n/2 (n is even)\n"
                + "n → 3n + 1 (n is odd)\n\n"
                + "Using the rule above and starting with 13, we generate the following sequence:\n\n"
                + "13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1\n"
                + "It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it"
                + " has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.\n\n"
                + "Which starting number, under one million, produces the longest chain?\n\n"
                + "NOTE: Once the chain starts the terms are allowed to go above one million.";
    }

    @Override
    public String run() {
        int maxChainLength = 0;
        long maxChainLengthStartingVal = 1;
        for (long start = this.getStartVal(); start <= this.getEndVal(); start++) {
            int chainLength = 1;
            long currentVal = start;
            while (currentVal != 1) {
                currentVal = this.nextValue(currentVal);
                chainLength++;
            }
            if (chainLength > maxChainLength) {
                maxChainLength = chainLength;
                maxChainLengthStartingVal = start;
            }
        }
        return String.valueOf(maxChainLengthStartingVal);
    }

    private long nextValue(long n) {
        if (n % 2 == 0) {
            return n / 2;
        } else {
            return 3 * n + 1; // SUPPRESS CHECKSTYLE magicNumber
        }
    }
}

@@ -252,24 +252,59 @@
  endVal;%0D%0A%0D%0A
+    private int%5B%5D chainLengths;%0D%0A%0D%0A
     public P
@@ -714,32 +714,115 @@
 dVal;%0D%0A    %7D%0D%0A%0D%0A
+    private int%5B%5D getChainLengths() %7B%0D%0A        return this.chainLengths;%0D%0A    %7D%0D%0A%0D%0A
     @Override%0D%0A 
@@ -1701,24 +1701,180 @@
 ng run() %7B%0D%0A
+        this.chainLengths = new int%5B(int) this.getEndVal() + 1%5D;%0D%0A        this.getChainLengths()%5B1%5D = 1; // 0 index is never used - we're 1-index based.%0D%0A%0D%0A
         int 
@@ -1890,17 +1890,17 @@
 ength = 
-0
+1
 ;%0D%0A     
@@ -1935,24 +1935,26 @@
 ngVal = 1;%0D%0A
+%0D%0A
         for 
@@ -2060,144 +2060,235 @@
 h = 
-1;%0D%0A            long currentVal = start;%0D%0A            while (currentVal != 1) %7B%0D%0A                currentVal = this.nextValue(currentVal)
+this.getOrPopulateChainLength(start);%0D%0A            if (chainLength %3E maxChainLength) %7B%0D%0A//                System.out.println(%22New maximum found: %22 + chainLength + %22 at: %22 + start); %0D%0A                maxChainLength = chainLength
 ;%0D%0A 
@@ -2302,17 +2302,20 @@
         
-c
+maxC
 hainLeng
@@ -2316,18 +2316,35 @@
 inLength
-++
+StartingVal = start
 ;%0D%0A     
@@ -2364,146 +2364,288 @@
     
+ %7D%0D%0A
      
-if (chainLength %3E maxChainLength) %7B%0D%0A                maxChainLength = chainLength;%0D%0A                maxChainLengthStartingVal = start
+   return String.valueOf(maxChainLengthStartingVal);%0D%0A    %7D%0D%0A%0D%0A    private int getOrPopulateChainLength(long value) %7B%0D%0A        if (value %3C this.getChainLengths().length && this.getChainLengths()%5B(int) value%5D != 0) %7B%0D%0A            return this.getChainLengths()%5B(int) value%5D
 ;%0D%0A 
@@ -2643,37 +2643,40 @@
 alue%5D;%0D%0A        
-    %7D
+%7D else %7B
 %0D%0A        %7D%0D%0A   
@@ -2673,68 +2673,254 @@
     
-%7D%0D%0A
     
-    return String.valueOf(maxChainLengthStartingVal);
+int count = this.getOrPopulateChainLength(this.nextValue(value)) + 1;%0D%0A            if (value %3C this.getChainLengths().length) %7B%0D%0A                this.getChainLengths()%5B(int) value%5D = count;%0D%0A            %7D%0D%0A            return count;%0D%0A        %7D
 %0D%0A  

Increase performance of Problem14.