6
\$\begingroup\$

A student has a book containing 411 pages. She read a certain number of pages on the first day and created a rule to work out how many pages she had to read on each succeeding day. She decided that the number of pages to be read on the next day should be equal to the square of the sum of the digits of the page she ended at. For example, if she ended on page 36, then she should read 81 pages on the next day as this is the square of 6 + 3. She found that on the sixth day, the number of pages she had set herself to read took her exactly to the final page of the book. How many pages did she read each day?

Here's what I did:

import java.util.*;
import java.lang.*;
import java.io.*;

class ADG {
  public static void main(String[] args) throws java.lang.Exception {
    for (int firstpage = 1; firstpage <= 411; firstpage++) {
      int sum = firstpage;
      int day = 1;
      do {
        sum += squareofroot(sum);
        day++;
        if (sum == 411) {
          System.out.println(firstpage + "&" + day + "\\\\");
          break;
        }
      } while (sum <= 411);
    }
  }
  public static int squareofroot(int pnum) {
    int root = 0;
    int j = 0;
    do {
      root += pnum % 10;
      pnum = pnum / 10;
      j = j + 1;
    } while (pnum != 0);
    return (root * root);
  }

}

Any reviews?

Numbers that end up with 411 pages, not necessarily in 6 days:

$$\begin{array}{c|c} \text{pages read $\\$on first day}&\text{days required to$\\$ read exactly 411 pages}\\\hline 13&5\\ 16&4\\ 29&4\\ \huge \color{red}{61}&\huge \color{red}{6}\\ 65&3\\ 110&5\\ 114&4\\ 150&3\\ 186&2\\ 190&3\\ 241&3\\ 290&2\\ \end{array}$$

\$\endgroup\$
  • \$\begingroup\$ @Legato day x vs. pages read would be more relevant to the problem, but the table presented here is fine in its own right. And it isn't in the inverse order. The independent variable is on the left and the dependent variable is on the right (you'll note that the right side has duplicate values). \$\endgroup\$ – JLRishe Feb 7 '15 at 21:37
6
\$\begingroup\$

A few clear problems in your code that Legato did not mention:

  • There is a j variable in your squareofroot method that serves no purpose. It is never used.
  • The squareofroot method is misleadingly named. There is no root involved. I think squareOfDigitSum would be more accurate.
    • The root variable in that method is also misleading for the same reason.
  • There's no real reason to use do..while in either of the places where you are using it. A while loop is more consise and can help avoid unnecessary looping.

That method can be simplified like this:

  public static int squareOfDigitSum(int pNum) {
    int total = 0;
    while (pNum > 0) {
      total += pNum % 10;
      pNum /= 10;
    }
    return (total * total);
  }

I also think that your main method is doing too much. It is both looping through the set of possible starting values and checking if each one is a solution. I suggest separating the solution check out into a separate method to clearly convey intent and avoid excessive nesting.

public static void main(String[] args) throws java.lang.Exception {
    int totalPages = 411;
    for (int firstDay = 1; firstDay <= totalPages; firstDay++) {
        checkSolution(firstDay, totalPages);
    }
}

private static void checkSolution(int firstDay, int totalPages) {
    int sum = firstDay;
    int day = 1;
    while (sum <= totalPages) {
        sum += squareOfDigitSum(sum);
        day++;
        if (sum == totalPages) {
            System.out.println(firstDay + "&" + day + "\\\\");
        }
    }
}

As far as the point of finding the number of pages on each day in order to get six, the following deviates a bit from your solution, but it is a clean way to get the answer without computing it twice:

import java.util.*;
import java.lang.*;
import java.io.*;

class ADG {
    public static void main(String[] args) throws java.lang.Exception {
        int totalPages = 411;
        int expectedDays = 6;
        for (int firstDay = 1; firstDay <= totalPages; firstDay++) {
            Stack<Integer> solution = checkSolution(0, firstDay, totalPages);
            if (solution != null && solution.size() == expectedDays) {
                printSolution(solution);
            }
        }
    }

    private static void printSolution(Stack<Integer> solution) {
        int i = 1;
        while (!solution.empty()) {
            int pages = solution.pop();
            System.out.println("Day " + i + " " + pages + " pages");
            i++;
        }
    }

    // returns a stack of the pages read each day if the values 
    // provided lead to a solution, and null if not
    private static Stack<Integer> checkSolution(int soFar, int current, int total) {
        int totalRead = soFar + current;

        if (totalRead == total) {
            // reached the total
            Stack<Integer> solution = new Stack<Integer>();
            solution.push(current);
            return solution;
        }
        if (totalRead > total) {
            // already passed total
            return null;
        } 

        // see if this leads to a solution
        Stack<Integer> solution = checkSolution(totalRead, squareOfDigitSum(totalRead), total);

        if (solution == null) {
            // doesn't lead to a solution
            return solution;
        }

        solution.push(current);
        return solution;
    }

    public static int squareOfDigitSum(int pNum) {
        int total = 0;
        while (pNum > 0) {
            total += pNum % 10;
            pNum /= 10;
        }
        return (total * total);
    }

}

Output:

Day 1 61 pages
Day 2 49 pages
Day 3 4 pages
Day 4 36 pages
Day 5 36 pages
Day 6 225 pages

https://ideone.com/ILBJle

\$\endgroup\$
7
\$\begingroup\$

You don't usually need to import java.lang, as it is built in, but maybe this is a special case. Either way, It's best to only import the classes you need. Regardless, java.io, and java.util are unused.

Did you import java.io for exceptions? In general's, it's preferable to throw a specific Exception, this alone doesn't really say much. As it is I think it's entirely unnecessary, and wonder why you're throwing any exception in the first place.

You don't need to break when you reach the sum, your while loops condition is already checking if sum reaches 411.

411 is a magic number. Looking at the code alone in the future it would serve you to instantiate the value in a final field.

In java it's conventional for variables and methods to be camelCase, so as an example, in your code firstpage should be firstPage and squareofroot should be squareOfRoot. Additionally, class names are PascalCase, so your class ADG would be Adg (Though I'd pick a better class name), doesn't hurt to be as descriptive as possible. I'd wager if you stepped back for a few months and just saw a file named ADG you'd wonder what it is. Try to keep these standards in mind going forward, they will help keep your code readable not only to yourself but anyone else you present it to.

Lastly, you don't really answer the question. The challenge asks

How many pages did she read on each day?`

Answering that would be trivial with your code, you actually went one further and found out different ways she could have finished the book using her method.

Suggested Implementation:

import java.util.Map;
import java.util.LinkedHashMap;

public class Test {
    public static void main(String[] args) {
        final int pageTotal = 411;
        final int daysRequired = 6;
        Map<Integer, Integer> pagesReadPerDay = new LinkedHashMap<>();

        for (int firstPage = 1; firstPage <= pageTotal; firstPage++) {
            int sum = firstPage;
            int day = 1;

            while (sum <= pageTotal) {
                sum += squareSumDigit(sum);
                day++;

                if (sum == pageTotal && day == daysRequired) {
                    int pagesRead = firstPage;
                    int currentPage = pagesRead;

                    for (int onDay = 1; onDay <= daysRequired; onDay++) {
                        pagesReadPerDay.put(onDay, pagesRead);
                        pagesRead = squareSumDigit(currentPage);
                        currentPage += pagesRead;
                    }
                }
            }
        }

        for (Map.Entry<Integer, Integer> entry : pagesReadPerDay.entrySet()){
            System.out.println(
                "Day: " + entry.getKey() + 
                ", Pages Read: " + entry.getValue() + "."
            );
        }
    }

    public static int squareSumDigit(int num) {
        int sum = 0;

        while (num > 0) {
            sum += num % 10;
            num /= 10;
        }

        return sum * sum;
    }
}

Output:

Day: 1, Pages Read: 61.
Day: 2, Pages Read: 49.
Day: 3, Pages Read: 4.
Day: 4, Pages Read: 36.
Day: 5, Pages Read: 36.
Day: 6, Pages Read: 225.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.