Arithmetic Operations -Java - java

class Example {
public static void main(String args[]){
System.out.println(12+8/5%4*(5-4/5)+4*5);
}
}
Why the output is 37? Can anyone explain? I'm a beginner in java

Check the precedence of the operators in java:
12+8/5%4*(5-4/5)+4*5
12+8/5%4*(5-0)+4*5
12+8/5%4*5+4*5
12+1%4*5+4*5
12+1*5+4*5
12+5+20
37

You have: 12+8/5%4*(5-4/5)+4*5
In the post of user3134614
12+8/5%4*(5-4/5)+4*5
12+8/5%4*(5-0)
12+8/5%4*5+4*5
12+1%4*5+4*5
12+1*5+4*5
12+5+20
37
You have the basic operators
+ add two numbers
- subtract two numbers
* Multiply two numbers
/ divide two numbers
And these, a little more advanced
% gets the remainder of two numbers, that is, that divides them and obtains the remainder, if the number is even, then the rest is zero, and if it is odd, it is another number
For example 4%4 would be 4 divided by 4 results in 2 and 2 + 2 = 4, there is no remainder, on the other hand 5%4 = 1, because 2 + 2 = 4 and over 1 of 5
The parentheses () separate a mathematical expression and return it as a single quantity, example
5 - (3-2) * 2 is equivalent to 5 - (1) * 2 = 5 - 2 = 3
Then
12+8/5%4*(5-4/5)+4*5
12+8/5%4*(5-0) is 12+8/5%4*(5 - (4/5) = 0.8, but converted to integer is 0, then 5 - 0 = 5)
12+8/5%4*5+4*5 is 12+ (8/5 = 1.6, but to integer is 1) %4*5+4*5
12+1%4*5+4*5 is 12+ (1%4 = 1 (1 is different of 4 then result is 1)) *5+4*5
12+1*5+4*5 is 12 + (1*5 = 5) + (4*5 = 20)
12+5+20 and 12 + 5 + 20 = 37
37

Related

Trying to find the number of x's that satisfies n + x = n ^ x fails with timeout

I'm trying to solve the following problem from the section Bit Manipulation at the Hacker Rank site using new features of Java 8 such as Streams.
The problem description:
Given an integer, n, find each x such that:
0 <= x <= n
n + x = n ^ x
where ^ denotes the bitwise XOR operator. Then print an integer denoting the total number of x's satisfying the criteria above.
Constraints
0 <= n <= 1015
Sample Input: 5
Sample Output: 2
Explanation:
For n = 5, the x values 0 and 2 satisfy the conditions:
5 + 0 = 5 ^ 0 = 5
5 + 2 = 5 ^ 2 = 7
Thus, we print 2 as our answer.
Sample Input: 10
Sample Output: 4
Explanation:
For n = 10, the x values 0, 1, 4, and 5 satisfy the conditions:
10 + 0 = 10 ^ 0 = 10
10 + 1 = 10 ^ 1 = 11
10 + 4 = 10 ^ 4 = 14
10 + 5 = 10 ^ 5 = 15
Thus, we print 4 as our answer.
My code is as follows:
public class SumVsXor
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
long n = in.nextLong();
long count = LongStream.rangeClosed(0, n)
.filter(k -> k + n == (k ^ n))
.count();
System.out.println(count);
}
}
The problem is this code doesn't pass all the test cases.
It works for small values of n, but for large values such as 1000000000000000 it fails due to timeout.
I wonder whether LongStream can't handle Streams with that many elements.
The problem with your code is that it is very inefficient. For the case of n==1000000000000000, your Stream pipeline is performing 1,000,000,000,000,000 addition and XOR operations, which takes a long time. Testing for each number between 0 and n whether n + x == n ^ x would take a long time even if you use a for loop instead of Streams.
Instead of checking all the numbers between 0 and n, you should try to figure out a better way to calculate the required total number of x's. That fact that this problem appears under a "Bit Manipulation" section should give you a hint
to look into the bits of numbers that satisfy n + x == n ^ x.
Let's consider the case of n==1000000000000000. The binary representation of that large number is
0000000000000011100011010111111010100100110001101000000000000000
=== == = ====== = = = == == =
--- - - - - -- -- --- - ---------------
~~~~~~~~~~~~~~
In order for n + x to be equal to n ^ x, x must have a 0 value in all the bits corresponding with the 1 bits of n (marked with = above), and either 0 or 1 value in the bits corresponding with the 0 bits of n (marked with - above). This doesn't include the leading 0s (marked with ~ above), since x must be <= n, so any leading 0s in n must also have a 0 value in x.
This means that the total number of x's for which n + x == n ^ x is 2the number of 0s in n, not including leading 0s.
In the case of n = 1000000000000000, there are 30 such 0 bits, so the total number of x's that satisfy the requirement is 230.
Here's one way to compute the total number of x's :
long n = 1000000000000000L;
int zeroBitsCount = 0;
while (n > 0) {
if (n % 2 == 0) {
zeroBitsCount++; // counts the number of non-leading 0 bits
}
n = n >> 1; // divide n by 2 in order to examine the next bit in the next iteration
}
long total = 1L << zeroBitsCount; // the total is 2^(the 0 bits count)
I came to the same result, but via a different explanation, so thought I might post it here.
Eran's answer got to the same conclusion that I did : to modify the zeroes in the binary representation of the initial number - that is pretty straightforward.
Let's suppose our number is
101010100
so it has 5 zeroes.
you need all the possible combinations of:
a single zero
two zeroes
three zeroes
four zeroes
five zeroes
that is actually :
comb(1,5) + comb(2,5) + comb(3,5) + comb(4,5) + comb (5,5)
that is a well known formula being equal to:
pow(2,n) // where n is five in our case
from there the solution is obvious...
This is a simple question if you know little bit about XOR. I don't know much about java. But I can explain in python.
1.First convert the number to binary.
2.Count the number of zeros in that binary number.
3.print 2 ^ (number of zeros) and that's it.
Here is my python code.
n = int(input())
sum = 0
if n!=0:
n=str(bin(n))
for i in range(len(n)):
if n[i]=='0':
sum = sum + 1
print(2**(sum-1))
else: print(1)
The reason to decrement the sum by 1 is, in python it convert the number to the binary as this format. e.g: 0b'10101.
public static void main (String[] args) {
Scanner in = new Scanner (System.in);
long n = in.nextLong();
long count = 1L << (64-Long.bitCount(n)-Long.numberOfLeadingZeros(n));
System.out.println(count);
}

Store all odd numbers between -6 and 38 into an array

I'm doing some Java exercises, and this was one of them. I did this:
int odds[] = new int[22];
int storedNo = -5;
for (int i = 0; i < odds.length; i++) {
odds[i] = storedNo;
storedNo += 2;
}
Which works. But, I looked at the answer and it said to do this:
int[] odds = new int[22];
for (int i = 0; i < 22; i++) {
odds[i] = i * 2 - 5;
}
My question is, how did they arrive at that answer?, specifically the i * 2 - 5 part? I don't get how to think of the math to get that answer.
A simple way to think about it is that it evaluates the equation y = 2x - 5 for integer values x in [0, 21].
How did they arrive at this solution? One way is to look at the first and last points. We know the first odd number is at x = 0, y = -5 and the last is at x = 21, y = 37. Two points is sufficient to solve for a linear equation y = mx + b:
From the first point we have
(-5) = m(0) + b
=> b = -5
From the second point we have
(37) = m(21) + b
=> 37 = 21m - 5
=> 21m = 42
=> m = 2
Thus our solution is y = 2x - 5. This also follows the intuitive observation that successive odd numbers have a difference of 2, and the y-intercept of the line should be the smallest number.
Just follow the math to see how it works. The first odd number you have is -5, so doing i*2 - 5 gives you -5 to start out when your loop variable is 0. When i increases by 1 on each loop iteration, you're going to have a result that's 2 greater than the previous.
0 * 2 - 5 = -5
1 * 2 - 5 = -3
2 * 2 - 5 = -1
...
21 * 2 -5 = 37

How to stack fruit in a neat pile

I've chosen Java for this case because the language is simple enough for anyone to translate.
What would be the mathematical algorithm to determine the number of fruit required on the bottom line to stack X number of fruits in a pattern like this? (ignoring power of 2's, which I stack in a square)
* 1
* 2 3 = 2
*
* 1 2
* 3 4 5 = 3
*
* 1
* 2 3
* 4 5 6 = 3
*
* 1 2 3
* 4 5 6 7 = 4
*
* 1 2
* 3 4 5
* 6 7 8 9 = 4
*
* 1
* 2 3
* 4 5 6
* 7 8 9 X = 4
*
* 1 2 3
* 3 4 5 6
* 7 8 9 X 1 = 5
Initially I thought it'd be easy, but as the numbers got higher I'm starting to think it's more of a factorial.
Edit: Adding in the code translated from answer provided below by #templatetypedef
private int _getBottomLineCount() {
double insideSquareRoot = (8 * numberOfApples) +1;
double squareRoot = Math.sqrt(insideSquareRoot);
double val = (squareRoot -1) /2;
return (int) Math.ceil(val); // Round it up to nearest whole number
}
The number of fruit in a pyramid of height n is given by the nth triangular number, given by the equation
Tn = n(n + 1) / 2
For example, a pyramid of height 2 holds 2(2 + 1) / 2 = 3 fruit. A pyramid of height 4 holds 4(4 + 1) / 2 = 10 fruit.
If you have k fruit to put into a stack, you're looking for the smallest number n such that Tn ≥ k. You can solve for this directly:
Tn = k
n(n + 1) / 2 = k
n2 + n = 2k
n2 + n - 2k = 0
Using the quadratic formula gives
n = (-1 ±√(1 + 8k)) / 2
The negative root here can be ignored, so your number n should be given by
n = (√(8k + 1) - 1) / 2
This number might be not be an integer, in which case you want to round up.
Let's try some examples. Suppose that you have 9 fruit to stack. We can evaluate the formula above to get
n = (√(72 + 1) - 1) / 2 = (√(73) - 1) / 2 = 3.772001873
Rounding up gives k = 4, so you'd need a stack of height 4.
Suppose you have 137 fruit to stack. The same formula gives back n = 16.060495162, so you'd need a stack of height 17 to store the fruit.
Hope this helps!

How can I optimize this class that solves this math sequence

Given an infinite sequence like so (commas inserted to make pattern more apparent):
1, 1 2, 1 2 3, 1 2 3 4, 1 2 3 4 5, 1 2 3 4 5 6 ,1 2 3 4 5 6 7, 1 2 3 4 5 6 7 8, 1 2 3 4 5 6 7 8 9, 1 2 3 4 5 6 7 8 9 1 0, 1 2 3 4 5 6 7 8 9 1 0 1 1, 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2, 1 2 3 . . . . . . . . . .
I am given an index (1 <= index <= 10^10) and I need to find what digit is in that index.
I have wrote this working code but it is too slow. I have optimized it as much as I can but it's still not enough. Is there any other way I can make this run faster?
public class Foo {
private static Scanner sc = new Scanner(System.in);
private static long input;
private static long inputCounter = 0;
private static int numberOfInputs;
public static void main(String[] args) {
numberOfInputs = Integer.parseInt(sc.nextLine().trim());
while (inputCounter != numberOfInputs) {
input = Long.parseLong(sc.nextLine().trim());
System.out.println(step());
inputCounter++;
}
}
public static char step() {
int incrementor = 1;
long _counter = 1L;
while (true) {
for (int i = 1; i <= incrementor; i++) {
_counter += getNumberOfDigits(i);
if (_counter > input) {
return ((i + "").charAt((int)(input - _counter
+ getNumberOfDigits(i))));
}
}
incrementor++;
}
}
private static long getNumberOfDigits(int n) {
// 5 or less
if (n < 100) {
// 1 or 2
if (n < 10)
return 1;
else
return 2;
} else {
// 3 or 4 or 5
if (n < 1000)
return 3;
else {
// 4 or 5
if (n < 10000)
return 4;
else
return 5;
}
}
}
}
EDIT: Credit to Marian's method of getting the number of digits in a number. His divide and conquer method which I've named getNumberOfDigits(int n) sped up my program execution a lot. Initially I was converting the number to a String then calling length() and that was taking a lot longer than I expected
EDIT2: Some sample I/O:
1 : 1
2 : 1
3 : 2
4 : 1
5 : 2
6 : 3
7 : 1
8 : 2
9 : 3
10 : 4
11 : 1
12 : 2
13 : 3
14 : 4
15 : 5
16 : 1
17 : 2
18 : 3
19 : 4
20 : 5
21 : 6
22 : 1
23 : 2
24 : 3
25 : 4
26 : 5
27 : 6
28 : 7
29 : 1
30 : 2
31 : 3
32 : 4
33 : 5
34 : 6
35 : 7
36 : 8
37 : 1
38 : 2
39 : 3
40 : 4
41 : 5
42 : 6
43 : 7
44 : 8
45 : 9
46 : 1
47 : 2
48 : 3
49 : 4
50 : 5
51 : 6
52 : 7
53 : 8
54 : 9
55 : 1
56 : 0
57 : 1
58 : 2
59 : 3
60 : 4
61 : 5
62 : 6
63 : 7
64 : 8
65 : 9
66 : 1
67 : 0
68 : 1
69 : 1
70 : 1
71 : 2
72 : 3
73 : 4
74 : 5
75 : 6
76 : 7
77 : 8
78 : 9
79 : 1
80 : 0
81 : 1
82 : 1
83 : 1
84 : 2
85 : 1
86 : 2
87 : 3
88 : 4
89 : 5
90 : 6
91 : 7
92 : 8
93 : 9
94 : 1
95 : 0
96 : 1
97 : 1
98 : 1
99 : 2
I think the triangular numbers come into play here if we look at the positions of the digits:
Position: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15, 16 17 18 19 20 21, 22 23 24 25 26 27 28
Number: 1, 1 2, 1 2 3, 1 2 3 4, 1 2 3 4 5, 1 2 3 4 5 6, 1 2 3 4 5 6 7,
Call this sequence N(p).
Now look at the triangular numbers which have formula k(k+1)/2
k : 1 2 3 4 5 6
k(k+1)/2 : 1 3 6 10 15 21 triangle numbers
k(k+1)/2+1 : 2 4 7 11 16 22 plus one
N(k(k+1)/2+1): 1 1 1 1 1 1 item at this position
so the item just after the n'th triangular number is always 1.
Give a position p we can find nearest k so that k(k+1)/2 +1 <= p. We can solve the quadratic x(x+1)/2+1=p by rearranging
0.5 x^2 + 0.5 x + 1 - p = 0.
So a=0.5, b=0.5 and c=1-p. Solving for x gives
x = -0.5 +/- sqrt( 0.25 - 2 * (1-p) )
take the positive sign this gives these values
1 0
2 1
3 1.5615528128
4 2
5 2.3722813233
6 2.7015621187
7 3
8 3.2749172176
9 3.5311288741
10 3.7720018727
11 4
12 4.216990566
13 4.4244289009
14 4.623475383
15 4.8150729064
16 5
So if we take k=floor(-0.5 +/- sqrt( 2 p - 1.75 ) ) we find the number k. Next find l = p-k(k+1)/2 which gives the digit in the p-th place.
As pointed out this fails as soon as we get two digit numbers. But we could make an adjustment. We can get a formula "triangular-digit-number" TD(k). Which behaves like triangular numbers, T(k), for k < 10, but adds the extra digits.
k : 1 ... 9 10 11 12
T(k) : 1 45 55 66 78
change 1 3 6
TD(k) : 2 45 56 69 84
We see that for 10 <= k <= 99 we just need to add T(k)+T(k-9). This should give us another quadratic we could be solved. Similar happens for 100<=k<=999 with T(k)+T(k-9)+T(k-99).
Now T(k)+T(k-9) + 1 = k(k+1)/2 +(k-9)(k-8)/2 + 1
= 0.5 k^2 + 0.5 k + 0.5 k^2 - 17/2 k + 72/2 + 1
= k^2 -8 k + 37
Solve x^2 -8 k + 37 - p =0 gives
x = ( 8 +/- sqrt(64 - 4 *(37-p) ) ) /2
= ( 8 +/- sqrt(4 p - 64) )/2
= 4 +/- sqrt(p - 21)
taking the floor of this gives us the k value.
We want to find the sum of triangles T(k) + T(k-9) + T(k-99) + ....
To a first approximation T(k-n) = T(n) for any n. So the sum is simply
d * T(k) where d in the number of digits of k. T(k) is approximately k^2/2 so the sum is approx d * k^2/2. This is easy to solve let d be the number of digits of the position p then k = sqrt(2*p/d). You could use this to get a rough guess for k.
The following code is a nearly direct calculation. It produces the exact same results as that of #maaartinus (see results below) but does it in < 1ms as opposed to 30ms.
See the code comments for details on how it works. Let me know if I need to explain a bit more.
package com.test.www;
import java.util.ArrayList;
import java.util.List;
public final class Test {
/** <p>
* Finds digit at {#code digitAt} position. Runs in O(n) where n is the max
* digits of the 'full' number (see below), e.g. for {#code digitAt} = 10^10,
* n ~ 5, for 10^20, n ~ 10.
* <p>
* The algorithm is thus basically a direct 'closed form' calculation.
* It finds the quadratic equation to calculate triangular numbers (x(x+1)/2) but also
* takes into a account the transitions from 9 to 10, from 99 to 100, etc. and
* adjusts the quadratic equation accordingly. This finds the last 'full' number
* on each 'line' (see below). The rest follows from there.
*
*/
public static char findDigitAt(long digitAt) {
/* The line number where digitAt points to, where:
* 1, 1 2, 1 2 3, 1 2 3 4, etc. ->
* 1 <- line 1
* 1 2 <- line 2
* 1 2 3 <- line 3
* 1 2 3 4 <- line 4
*/
long line;
// ---- Get number of digits of 'full' numbers where digitAt at points, e.g.
// if digitAt = 55 or 56 then digits = the number of digits in 10 which is 2.
long nines = 0L; // = 9 on first iteration, 99 on second, etc.
long digits = 0;
long cutoff = 0; // Cutoff of digitAt where number of digits change
while (digitAt > cutoff) {
digits++;
nines = nines + Math.round(Math.pow(10L, digits-1L)) * 9L;
long nines2 = 0L;
cutoff = 0L;
for (long i = 1L; i <= digits; i++) {
cutoff = cutoff + ((nines-nines2)*(nines-nines2+1)/2);
nines2 = nines2 + Math.round(Math.pow(10L, i-1L)) * 9L;
}
}
/* We build a quadratic equation to take us from digitAt to line */
double r = 0; // Result of solved quadratic equation
// Must be double since we're using Sqrt()
// even though result is always an integer.
// ---- Define the coefficients of the quadratic equation
long xSquared = digits;
long x = 0L;
long c = 0L;
nines = 0L; // = 9 on first iteration, 99 on second, etc.
for (long i = 1L; i <= digits; i++) {
x = x + (-2L*nines + 1L);
c = c + (nines * (nines - 1L));
nines = nines + Math.round(Math.pow(10L, i-1L)) * 9L;
}
// ---- Solve quadratic equation, i.e. y - ax^2 + bx + c => x = [ -b +/- sqrt(b^2 - 4ac) ] / 2
r = (-x + Math.sqrt(x*x - 4L*xSquared*(c-2L*digitAt))) / (2L*xSquared);
// Make r an integer
line = ((long) r) + 1L;
if (r - Math.floor(r) == 0.0) { // Simply takes care of special case
line = line - 1L;
}
/* Now we have the line number ! */
// ---- Calculate the last number on the line
long lastNum = 0;
nines = 0;
for (int i = 1; i <= digits; i++) {
long pline = line - nines;
lastNum = lastNum + (pline * (pline+1))/2;
nines = nines + Math.round(Math.pow(10, i-1)) * 9;
}
/* The hard work is done now. The piece of cryptic code below simply counts
* back from LastNum to digitAt to find first the 'full' number at that point
* and then finally counts back in the string representation of 'full' number
* to find the actual digit.
*/
long fullNumber = 0L;
long line_decs = 1 + (int) Math.log10(line);
boolean done = false;
long nb;
long a1 = Math.round(Math.pow(10, line_decs-1));
long count_back = 0;
while (!done) {
nb = lastNum - (line - a1) * line_decs;
if (nb-(line_decs-1) <= digitAt) {
fullNumber = line - (lastNum - digitAt) / line_decs;
count_back = (lastNum - digitAt) % line_decs;
done = true;
} else {
lastNum = nb-(line_decs);
line = a1-1;
line_decs--;
a1 = a1 / 10;
}
}
String numStr = String.valueOf(fullNumber);
char digit = numStr.charAt(numStr.length() - (int) count_back - 1);
//System.out.println("digitAt = " + digitAt + " - fullNumber = " + fullNumber + " - digit = " + digit);
System.out.println("Found " + digit + " at position " + digitAt);
return digit;
}
public static void main(String... args) {
long t = System.currentTimeMillis();
List<Long> testList = new ArrayList<Long>();
testList.add(1L); testList.add(2L); testList.add(3L); testList.add(9L);
testList.add(2147483647L);
for (int i = 1; i <= 18; i++) {
testList.add( Math.round(Math.pow(10, i-1)) * 10);
}
//testList.add(4611686018427387903L); // OVERFLOW OCCURS
for (Long testValue : testList) {
char digit = findDigitAt(testValue);
}
long took = t = System.currentTimeMillis() - t;
System.out.println("Calculation of all above took: " + t + "ms");
}
}
Results
Found 1 at position 1
Found 1 at position 2
Found 2 at position 3
Found 3 at position 9
Found 2 at position 2147483647
Found 4 at position 10
Found 1 at position 100
Found 4 at position 1000
Found 9 at position 10000
Found 2 at position 100000
Found 6 at position 1000000
Found 2 at position 10000000
Found 6 at position 100000000
Found 8 at position 1000000000
Found 1 at position 10000000000
Found 1 at position 100000000000
Found 9 at position 1000000000000
Found 8 at position 10000000000000
Found 3 at position 100000000000000
Found 7 at position 1000000000000000
Found 6 at position 10000000000000000
Found 1 at position 100000000000000000
Found 1 at position 1000000000000000000
Calculation of all above took: 0ms
I've added some code that vastly improves the running time - skip to the bottom to see the examples.
A key insight I found is that you can skip sub-sequences if the input doesn't lie anywhere in it. For example, if you are looking for the 1,000,000,000th number, you know it isn't in the 5th subsequence {1,2,3,4,5}. So why iterate over it? This version seems to be much faster (try running it with an input of 1000000000 and see the time difference), and as far as I can tell it returns the same result in all cases.
Thus, my algorithm keeps track of the length of the subsequence (Add the number of digits on each iteration), and the subsequence we're on. If the input is larger than the subsequence's length, just subtract that length and iterate again. If it is smaller (or equal, since the problem is 1-indexed), start breaking down that sub-sequence.
A minor note: I also updated the getNumberOfDigits so that it can handle any number by doing it recursively, but both the new and old versions rely on this new method so it doesn't get credit for the time improvement.
public class Foo {
private static Scanner sc = new Scanner(System.in);
private static long input;
private static long inputCounter = 0;
private static int numberOfInputs;
/** Updated main method that calls both the new and old step() methods
* to compare their outputs and their respective calculation times.
* #param args
*/
public static void main(String[] args) {
numberOfInputs = Integer.parseInt(sc.nextLine().trim());
while (inputCounter != numberOfInputs) {
long i = Long.parseLong(sc.nextLine().trim());
input = i;
System.out.println("Processing " + input);
long t = System.currentTimeMillis();
System.out.println("New Step result - " + newStep() + " in " + (System.currentTimeMillis() - t)+"ms");
input = i;
t = System.currentTimeMillis();
System.out.println("Old Step result - " + step() + " in " + (System.currentTimeMillis() - t)+"ms");
inputCounter++;
}
}
/** Old version of step() method given in question. Used for time comparison */
public static char step() {
int incrementor = 1;
long _counter = 1L;
while (true) {
for (int i = 1; i <= incrementor; i++) {
_counter += getNumberOfDigits(i);
if (_counter > input) {
return ((i + "").charAt((int)(input - _counter
+ getNumberOfDigits(i))));
}
}
incrementor++;
}
}
/** New version of step() method.
* Instead of iterating one index at a time, determines if the result lies within this
* sub-sequence. If not, skips ahead the length of the subsequence.
* If it does, iterate through this subsequence and return the correct digit
*/
public static int newStep() {
long subSequenceLength = 0L;
long subSequenceIndex = 1L;
while(true){
//Update to the next subsequence length
subSequenceLength += getNumberOfDigits(subSequenceIndex);
if(input <= subSequenceLength){
//Input lies within this subsequence
long element = 0L;
do{
element++;
long numbDigits = getNumberOfDigits(element);
if(input > numbDigits)
input -= numbDigits;
else
break;
}while(true);
//Correct answer is one of the digits in element, 1-indexed.
//Speed isn't that important on this step because it's only done on return
return Integer.parseInt(("" + element).substring((int)input-1, (int)input));
} else{
//Input does not lie within this subsequence - move to next sequence
input -= subSequenceLength;
subSequenceIndex++;
}
}
}
/** Updated to handle any number - hopefully won't slow down too much.
* Won't handle negative numbers correctly, but that's out of the scope of the problem */
private static long getNumberOfDigits(long n){
return getNumberOfDigits(n, 1);
}
/** Helper to allow for tail recursion.
* #param n - the number of check the number of digits for
* #param i - the number of digits thus far. Accumulator. */
private static long getNumberOfDigits(long n, int i) {
if(n < 10) return i;
return getNumberOfDigits(n/10, i+1);
}
}
Sample output showing time improvement:
> 8
> 10000
Processing 10000
New Step result - 9 in 0ms
Old Step result - 9 in 2ms
> 100000
Processing 100000
New Step result - 2 in 0ms
Old Step result - 2 in 4ms
> 1000000
Processing 1000000
New Step result - 6 in 0ms
Old Step result - 6 in 3ms
> 10000000
Processing 10000000
New Step result - 2 in 1ms
Old Step result - 2 in 22ms
> 100000000
Processing 100000000
New Step result - 6 in 1ms
Old Step result - 6 in 178ms
> 1000000000
Processing 1000000000
New Step result - 8 in 4ms
Old Step result - 8 in 1765ms
> 10000000000
Processing 10000000000
New Step result - 1 in 11ms
Old Step result - 1 in 18109ms
> 100000000000
Processing 100000000000
New Step result - 1 in 5ms
Old Step result - 1 in 180704ms
I wrote a program without much thinking...
length(n) computes the number of digits of the decimal representation of n
cummulativLength(n) computes the total number of digits for a sequence ending with n
doublyCummulativLength(n) computes the total number of digits for all sequence ending with at most n
fullSequenceBefore(pos) computes the longest full sequence before the position pos using binary search
digitAt(n) computes the digit at position n by first computing fullSequenceBefore and subtracting its length; it then uses another binary search for the last sequence
I used long everywhere as it's damn fast. There's a rudimentary test and a demo producing the following results
Found 1 at position 1
Found 1 at position 2
Found 2 at position 3
Found 3 at position 9
Found 2 at position 2147483647
Found 4 at position 10
Found 1 at position 100
Found 4 at position 1000
Found 9 at position 10000
Found 2 at position 100000
Found 6 at position 1000000
Found 2 at position 10000000
Found 6 at position 100000000
Found 8 at position 1000000000
Found 1 at position 10000000000
Found 1 at position 100000000000
Found 9 at position 1000000000000
Found 8 at position 10000000000000
Found 3 at position 100000000000000
Found 7 at position 1000000000000000
Found 6 at position 10000000000000000
Found 1 at position 100000000000000000
Found 1 at position 1000000000000000000
Found 7 at position 4611686018427387903
Computed in 0.030 seconds.
The biggest number I tried it for is Long.MAX_VALUE/2. In theory it could work for Long.MAX_VALUE as well, but I'm getting overflow there.

Is my understanding of this While Loop correct?

The example in the book asks the user to enter any positive number. Then the program will add the individual digits separately and print the total. For example if the user enters the number 7512 the program is designed to add 7 + 5 + 1 + 2 and then print the total.
I've written out the way I understand how the code works. Is this correct? Is my understanding of this loop correct with each step, or am I missing any calculations? What happens during the 4th loop when there is no remainder in 7 % 10?
1st run of loop ... sum = sum + 7512 % 10 which is equal to 2
n = 7512 / 10 which which equals to 751
2nd run of loop ... sum = 2 + 751 % 10 which is equal to 1
n = 751 / 10 which is equal to 75
3rd run of loop ... sum = 3 + 75 % 10 which is equal to 5
n = 75 / 10 which is equal to 7
4th run of loop ... sum = 8 + 7 % 10 <------?
import acm.program.*;
public class DigitSum extends ConsoleProgram{
public void run() {
println("This program will add the integers in the number you enter.");
int n = readInt("Enter a positive integer: ");
int sum = 0;
while (n > 0) {
sum += n % 10;
n /= 10;
}
println("The sum of the digits is" + sum + ".");
}
}
The result of the operation 7 % 10 is 7, the remainder when you divide 7 by 10. The last iteration of the loop is to add 7 to the prior value. The next division step inside the loop (n /= 10;) takes n to 0, which is what ends the loop.
% is not the same as /
The % operator is for the modulus, not division... This means that the result of the operations is not dividing, but obtaining the remainder of the division, like:
7512 % 10 => 2
751 % 10 => 1
75 % 10 => 5
7 % 10 => 7
This kind of logic is fairly frequently used when dealing with numeric operations.
before run, sum = 0, n = 7512
1st run of loop ... sum = 0 + 2 => sum = 2, n = 751
2nd run of loop ... sum = 2 + 1 => sum = 3, n = 75
3rd run of loop ... sum = 3 + 5 => sum = 8, n = 7
4th run of loop ... sum = 8 + 7 => sum = 15, n = 0
After 7%10 you get 7 and that is added to your result.
And 7/10 will result in 0 and hence your loop ends and your sum now has addition that you want.

Categories

Resources