Related
I'd like to print the number of combination and not the actual combination of bits. How can I code that? I'm looking forward for some solution. Thank you!
The Task:
Write a program that accepts a number. This number corresponds to the number of bits to be taken into account. The program should then display on the screen how many binary combinations there are that do not consist of two adjacent 1s. For example, given a 3-bit number, there are 5 out of 8 possible combinations.
import java.util.Scanner;
public class BinaryS {
public static String toString(char[] a) {
String string = new String(a);
return string;
}
static void generate(int k, char[] ch, int n) {
if (n == k) {
for (int i = 0; i < ch.length; i++) {}
System.out.print(toString(ch) + " ");
return;
}
// If the first Character is
//Zero then adding**
if (ch[n - 1] == '0') {
ch[n] = '0';
generate(k, ch, n + 1);
ch[n] = '1';
generate(k, ch, n + 1);
}
// If the Character is One
// then add Zero to next**
if (ch[n - 1] == '1') {
ch[n] = '0';
// Calling Recursively for the
// next value of Array
generate(k, ch, n + 1);
}
}
static void fun(int k) {
if (k <= 0) {
return;
}
char[] ch = new char[k];
// Initializing first character to Zero
ch[0] = '0';
// Generating Strings starting with Zero--
generate(k, ch, 1);
// Initialized first Character to one--
ch[0] = '1';
generate(k, ch, 1);
}
public static void main(String args[]) {
System.out.print("Number: ");
Scanner scanner = new Scanner(System.in);
int k = scanner.nextInt();
//Calling function fun with argument k
fun(k);
}
}
The program actually works fine , my only problem is I would like to print the number of combinations and not the actual combination. For example for the input 3 we get 000 001 010 100 101 which is 5.
Unfortunately, your code has some problems. For one you have an empty forloop in the generate method. However, I can help you get the count by doing it a different way and printing the results. Forgetting about the loop that goes from 2 to 20, here is what is going on. And this may not be most efficient way of finding the matches but for short runs it exposes the counts as a recognizable pattern (which could also be determined by mathematical analysis).
first, create an IntPredicate that checks for adjacent one bits by masking the lower order two bits.
Generate an IntStream from 0 to 2n where n is the number of bits.
then using aforementioned predicate with a filter count every value that does not contain two adjacent 1 bits.
IntPredicate NoAdjacentOneBits = (n)-> {
while (n > 0) {
if ((n & 3) == 3) {
return false;
}
n>>=1;
}
return true;
};
for (int n = 1; n <= 20; n++) {
long count = IntStream.range(0, (int) Math.pow(2, n))
.filter(NoAdjacentOneBits).count();
System.out.println("For n = " + n + " -> " + count);
}
prints (with annotated comments on first three lines)
For n = 1 -> 2 // not printed but would be 0 and 1
For n = 2 -> 3 // 00, 01, 10
For n = 3 -> 5 // 000, 001, 010, 100, 101
For n = 4 -> 8
For n = 5 -> 13
For n = 6 -> 21
For n = 7 -> 34
For n = 8 -> 55
For n = 9 -> 89
For n = 10 -> 144
For n = 11 -> 233
For n = 12 -> 377
For n = 13 -> 610
For n = 14 -> 987
For n = 15 -> 1597
For n = 16 -> 2584
For n = 17 -> 4181
For n = 18 -> 6765
For n = 19 -> 10946
For n = 20 -> 17711
The counts are directly related to the nth term of the Fibonacci Series that starts with 2 3 5 8 . . .
So you really don't even need to inspect the values for adjacent bits. Just compute the related term of the series.
Deepest apologies as I'm sure I'm being dumb but I haven't been able to crack this and I have a school deadline coming up :(
this chunk of code is supposed to approximate the number e, by repeating this process:
e = 1 + 1/1! + 1/2! + 1/3! + 1/4! + 1/5! + ...
the user is supposed to specify the amount of iterations with the int e_stop, so that the output would look like this:
1 -> 2 2 -> 2.5 3 -> 2.666.. 4 -> 2.708333..
and so on, but as of right now the output looks like this:
1 -> 2 2 -> 2 3 -> 2 4 -> 2
import java.util.Scanner;
Scanner Case3Scanner = new Scanner(System. in );
System.out.println("Nivel de exactitud? (iteraciones)?");
//e = 1 + 1/1! + 1/2! + 1/3! + 1/4! + 1/5! + ..
int e_stop = Case3Scanner.nextInt();
System.out.println("--------------");
double e_total = 1; //this is the result we will output
double e_divisor = 1; //this is the number we will get the factorial of of
long e_fact = 1; //this is the factorial of e_divisor
for (int e = 1; e <= e_stop; e++) {
//this for-loop should repeat r_stop times.
//this next for-loop should make e_fact equal the factorial of e_divisor
for (int ef = 2; ef <= e_divisor; ef++) {
e_fact *= ef;
}
e_total += 1 / e_fact;
System.out.println(e_total);
e_divisor += 1;
}
You have 2 mistakes in your code.
One is integer division:
e_total += 1/e_fact
This line does integer division, which means you get a truncated integer result (for example, dividing 5/2 in Java would give a result of 2).
To signal that you do not want to do integer division, you need to do something like
e_total += 1D / e_fact (D for double) or e_total += 1.0 / e_fact
You are also calculating the factorials incorrectly.
e_fact already has the result from the previous iteration, so you don't need to multiply it in a loop.
//e = 1 + 1/1! + 1/2! + 1/3! + 1/4! + 1/5! + ..
int e_stop = 4;
System.out.println("--------------");
double e_total = 1; //this is the result we will output
long e_fact = 1; //this is the factorial of e_divisor
for (int e = 1; e <= e_stop; e++) {
e_fact *= e;
e_total += 1.0 / e_fact;
System.out.printf("e: %d, e_fact: %d, e_total: %f\n", e, e_fact, e_total);
}
Output:
e: 1, e_fact: 1, e_total: 2.000000
e: 2, e_fact: 2, e_total: 2.500000
e: 3, e_fact: 6, e_total: 2.666667
e: 4, e_fact: 24, e_total: 2.708333
I was going through a simple program that takes a number and finds the number of occurrences of consecutive numbers that matches with given number.
For example:
if input is 15, then the consecutive numbers that sum upto 15 are:
1,2,3,4,5
4,5,6
7,8
So the answer is 3 as we have 3 possibilities here.
When I was looking for a solution I found out below answer:
static long process(long input) {
long count = 0;
for (long j = 2; j < input/ 2; j++) {
long temp = (j * (j + 1)) / 2;
if (temp > input) {
break;
}
if ((input- temp) % j == 0) {
count++;
}
}
return count;
}
I am not able to understand how this solves the requirement because this program is using some formula which I am not able to understand properly, below are my doubts:
The for loop starts from 2, what is the reason for this?
long temp = (j * (j + 1)) / 2; What does this logic indicates? How is this helpful to solving the problem?
if ((num - temp) % j == 0) Also what does this indicate?
Please help me in understanding this solution.
I will try to explain this as simple as possible.
If input is 15, then the consecutive numbers that sum upto 15 are:
{1,2,3,4,5} -> 5 numbers
{4,5,6} -> 3 numbers
{7,8} -> 2 numbers
At worst case, this must be less than the Sum of 1st n natural numbers = (n*(n+1) /2.
So for a number 15, there can never be a combination of 6 consecutive numbers summing up to 15 as the sum of 1st 6 numbers =21 which is greater than 15.
Calculate temp: This is (j*(j+1))/2.
Take an example. Let input = 15. Let j =2.
temp = 2*3/2 = 3; #Meaning 1+2 =3
For a 2-number pair, let the 2 terms be 'a+1' and 'a+2'.(Because we know that the numbers are consecutive.)
Now, according to the question, the sum must add up to the number.
This means 2a+3 =15;
And if (15-3) is divisible by 2, 'a' can be found. a=6 -> a+1=7 and a+2=8
Similarly, let a+1 ,a+2 and a+3
a + 1 + a + 2 + a + 3 = 15
3a + 6 = 15
(15-6) must be divisible by 3.
Finally, for 5 consecutive numbers a+1,a+2,a+3,a+4,a+5 , we have
5a + 15 = 15;
(15-15) must be divisible by 5.
So, the count will be changed for j =2,3 and 5 when the input is 15
If the loop were to start from 1, then we would be counting 1 number set too -> {15} which is not needed
To summarize:
1) The for loop starts from 2, what is the reason for this?
We are not worried about 1-number set here.
2) long temp = (j * (j + 1)) / 2; What does this logic indicates? How is this helpful to solving the problem?
This is because of the sum of 1st n natural numbers property as I have
explained the above by taking a+1 and a+2 as 2 consecutive
numbers.
3) if ((num - temp) % j == 0) Also what does this indicate?
This indicates the logic that the input subtracted from the sum of 1st
j natural numbers must be divisible by j.
We need to find all as and ns, that for given b the following is true:
a + (a + 1) + (a + 2) + ... (a + (n - 1)) = b
The left side is an arithmetic progression and can be written as:
(a + (n - 1) / 2) * n = b (*)
To find the limit value of n, we know, that a > 0, so:
(1 + (n - 1) / 2) * n = n(n + 1) / 2 <= b
n(n + 1) <= 2b
n^2 + n + 1/4 <= 2b + 1/4
(n + 1/2)^2 <= 2b + 1/4
n <= sqrt(2b + 1/4) - 1/2
Now we can rewrite (*) to get formula for a:
a = b / n - (n - 1) / 2
Example for b = 15 and n = 3:
15 / 3 - (3 - 1) / 2 = 4 => 4 + 5 + 6 = 15
And now the code:
double b = 15;
for (double n = 2; n <= Math.ceil(Math.sqrt(2 * b + .25) - .5); n++) {
double candidate = b / n - (n - 1) / 2;
if (candidate == (int) candidate) {
System.out.println("" + candidate + IntStream.range(1, (int) n).mapToObj(i -> " + " + (candidate + i)).reduce((s1, s2) -> s1 + s2).get() + " = " + b);
}
}
The result is:
7.0 + 8.0 = 15.0
4.0 + 5.0 + 6.0 = 15.0
1.0 + 2.0 + 3.0 + 4.0 + 5.0 = 15.0
We are looking for consecutive numbers that sum up to the given number.
It's quite obvious that there could be at most one series with a given length, so basically we are looking for those values witch could be the length of such a series.
variable 'j' is the tested length. It starts from 2 because the series must be at least 2 long.
variable 'temp' is the sum of a arithmetic progression from 1 to 'j'.
If there is a proper series then let X the first element. In this case 'input' = j*(X-1) + temp.
(So if temp> input then we finished)
At the last line it checks if there is an integer solution of the equation. If there is, then increase the counter, because there is a series with j element which is a solution.
Actually the solution is wrong, because it won't find solution if input = 3. (It will terminate immediately.) the cycle should be:
for(long j=2;;j++)
The other condition terminates the cycle faster anyway.
NB: loop is starting from 2 because=> (1*(1+1))/2 == 1, which doesn't make sense, i.e, it doesn't effect on the progress;
let, k = 21;
so loop will iterate upto (k/2) => 10 times;
temp = (j*(j+1))/2 => which is, 3 when j =2, 6 when j = 3, and so on (it calculates sum of N natural numbers)
temp > k => will break the loop because, we don't need to iterate the loop when we got 'sum' which is more than 'K'
((k-temp)%j) == 0 => it is basically true when the input subtracted from the sum of first j natural numbers are be divisible by j, if so then increment the count to get total numbers of such equation!
public static long process(long input) {
long count = 0, rest_of_sum;
for (long length = 2; length < input / 2; length++) {
long partial_sum = (length * (length + 1)) / 2;
if (partial_sum > input) {
break;
}
rest_of_sum = input - partial_sum
if (rest_of_sum % length == 0)
count++;
}
return count;
}
input - given input number here it is 15
length - consecutive numbers length this is at-least 2 at max input/2
partial_sum = sum of numbers from 1 to length (which is a*(a+1)/2 for 1 to a numbers) assume this is a partial sequence
rest_of_sum = indicates the balance left in input
if rest of sum is multiple of length meaning is that we can add (rest_of_sum/length) to our partial sequence
lets call (rest_of_sum/length) as k
this only means we can build a sequence here that sums up to our input number
starting with (k+1) , (k+2), ... (k+length)
this can validated now
(k+1) + (k+2) + ... (k+length)
we can reduce this as k+k+k+.. length times + (1+2+3..length)
can be reduced as => k* length + partial_sum
can be reduced as => input (since we verified this now)
So idea here is to increment count every-time we find a length which satisfies this case here
If you put this tweak in it may fix code. I have not extensively tested it. It's an odd one but it puts the code through an extra iteration to fix the early miscalculations. Even 1/20000 would work! Had this been done with floats that got rounded down and 1 added to them I think that would have worked too:
for (long j = 2; j < input+ (1/2); j++) {
In essence you need to only know one formula:
The sum of the numbers m..n (or m to n) (and where n>m in code)
This is ((n-m+1)*(n+m))/2
As I have commented already the code in the original question was bugged.
See here.
Trying feeding it 3. That has 1 occurrence of the consecutive numbers 1,2. It yields 0.
Or 5. That has 2,3 - should yield 1 too - gives 0.
Or 6. This has 1,2,3 - should yield 1 too - gives 0.
In your original code, temp or (j * (j + 1)) / 2 represented the sum of the numbers 1 to j.
1 2 3 4 5
5 4 3 2 1
=======
6 6 6 6 6 => (5 x 6) /2 => 30/2 => 15
As I have shown in the code below - use System.out.println(); to spew out debugging info.
If you want to perfect it make sure m and n's upper limits are half i, and i+1 respectively, rounding down if odd. e.g: (i=15 -> m=7 & n=8)
The code:
class Playground {
private static class CountRes {
String ranges;
long count;
CountRes(String ranges, long count) {
this.ranges = ranges;
this.count = count;
}
String getRanges() {
return this.ranges;
}
long getCount() {
return this.count;
}
}
static long sumMtoN(long m, long n) {
return ((n-m+1)* (n+m))/2;
}
static Playground.CountRes countConsecutiveSums(long i, boolean d) {
long count = 0;
StringBuilder res = new StringBuilder("[");
for (long m = 1; m< 10; m++) {
for (long n = m+1; n<=10; n++) {
long r = Playground.sumMtoN(m,n);
if (d) {
System.out.println(String.format("%d..%d %d",m,n, r));
}
if (i == r) {
count++;
StringBuilder s = new StringBuilder(String.format("[%d..%d], ",m,n));
res.append(s);
}
}
}
if (res.length() > 2) {
res = new StringBuilder(res.substring(0,res.length()-2));
}
res.append("]");
return new CountRes(res.toString(), count);
}
public static void main(String[ ] args) {
Playground.CountRes o = countConsecutiveSums(3, true);
for (long i=3; i<=15; i++) {
o = Playground.countConsecutiveSums(i,false);
System.out.println(String.format("i: %d Count: %d Instances: %s", i, o.getCount(), o.getRanges()));
}
}
}
You can try running it here
The output:
1..2 3
1..3 6
1..4 10
1..5 15
1..6 21
1..7 28
1..8 36
1..9 45
1..10 55
2..3 5
2..4 9
2..5 14
2..6 20
2..7 27
2..8 35
2..9 44
2..10 54
3..4 7
3..5 12
3..6 18
3..7 25
3..8 33
3..9 42
3..10 52
4..5 9
4..6 15
4..7 22
4..8 30
4..9 39
4..10 49
5..6 11
5..7 18
5..8 26
5..9 35
5..10 45
6..7 13
6..8 21
6..9 30
6..10 40
7..8 15
7..9 24
7..10 34
8..9 17
8..10 27
9..10 19
i: 3 Count: 1 Instances: [[1..2]]
i: 4 Count: 0 Instances: []
i: 5 Count: 1 Instances: [[2..3]]
i: 6 Count: 1 Instances: [[1..3]]
i: 7 Count: 1 Instances: [[3..4]]
i: 8 Count: 0 Instances: []
i: 9 Count: 2 Instances: [[2..4], [4..5]]
i: 10 Count: 1 Instances: [[1..4]]
i: 11 Count: 1 Instances: [[5..6]]
i: 12 Count: 1 Instances: [[3..5]]
i: 13 Count: 1 Instances: [[6..7]]
i: 14 Count: 1 Instances: [[2..5]]
i: 15 Count: 3 Instances: [[1..5], [4..6], [7..8]]
Here is the problem I am currently trying to solve.
There is a maximum value called T. There are then two subvalues, A and B, that are 1 <= A,B <= T. In each round, you can pick either A or B to add to your sum. You can also choose to half that sum entirely in only one of the rounds. You can never exceed T in any round. Given an infinite number of rounds, what is the maximum sum you can get.
Here's an example:
T = 8
A = 5, B = 6
Solution: We first take B, then half the sum getting 3. Then we add A and get 8. So the maximum possible is 8.
The iterative idea I have come up with is: it is basically a tree structure where you keep branching of and trying to build of older sums. I am having trouble trying to figure out a maximization formula.
Is there a brute force solution that will run fast or is there some elegant formula?
Limits: 1 <= A, B <= T. T <= 5,000,000.
EDIT: When you divide, you round down the sum (i.e. 5/2 becomes 2).
The problem can be viewed as a directed graph with T + 1 nodes. Imagine we have T + 1 nodes from 0 to T, and we have an edge from node x to node y if:
x + A = y
x + B = y
x/2 = y
So, in order to answer the question, we need to do a search in the graph, with stating point is node 0.
We can do either a breath first search or depth first search to solve the problem.
Update: as we can only do divided once, so we have to add another state to the graph, which is isDivided. However, the way to solve this problem is not changed.
I will demonstrate the solution with a BFS implementation, DFS is very similar.
class State{
int node, isDivided;
}
boolean[][]visited = new boolean[2][T + 1];
Queue<State> q = new LinkedList();
q.add(new State(0, 0));//Start at node 0, and haven't use division
visited[0][0] = true;
int result = 0;
while(!q.isEmpty()){
State state = q.deque();
result = max(state.node, result);
if(state.node + A <= T && !visited[state.isDivided][state.node + A]){
q.add(new State(node + A , state.isDivided));
visited[state.isDivided][node + A] = true;
}
if(node + B <= T && !visited[state.isDivided][node + B]){
q.add(new State(node + B, state.isDivided));
visited[state.isDivided][node + B] = true;
}
if(state.isDivided == 0 && !visited[state.isDivided][node/2]){
q.add(new State(node/2, 1));
visited[state.isDivided][node/2] = true;
}
}
return result;
Time complexity is O(n)
To summarize your problem setting as I understand it (under the constraint that you can divide by two no more than once):
Add A and B as many times as you want (including 0 each)
Divide by 2, rounding down
Add A and B as many times as you want
The goal is to obtain the largest possible sum, subject to the constraint that the sum is no more than T after any step of the algorithm.
This can be captured neatly in a 5-variable integer program. The five variables are:
a1: The number of times we add A before dividing by 2
b1: The number of times we add B before dividing by 2
s1: floor((A*a1+B*b1)/2), the total sum after the second step
a2: The number of times we add A after dividing by 2
b2: The number of times we add B after dividing by 2
The final sum is s1+A*a2+B*b2, which is constrained not to exceed T; this is what we seek to maximize. All five decision variables must be non-negative integers.
This integer program can be easily solved to optimality by an integer programming solver. For instance, here is how you would solve it with the lpSolve package in R:
library(lpSolve)
get.vals <- function(A, B, T) {
sol <- lp(direction = "max",
objective.in = c(0, 0, 1, A, B),
const.mat = rbind(c(A, B, 0, 0, 0), c(0, 0, 1, A, B), c(-A, -B, 2, 0, 0), c(-A, -B, 2, 0, 0)),
const.dir = c("<=", "<=", "<=", ">="),
const.rhs = c(T, T, 0, -1),
all.int = TRUE)$solution
print(paste("Add", A, "a total of", sol[1], "times and add", B, "a total of", sol[2], "times for sum", A*sol[1]+B*sol[2]))
print(paste("Divide by 2, yielding value", sol[3]))
print(paste("Add", A, "a total of", sol[4], "times and add", B, "a total of", sol[5], "times for sum", sol[3]+A*sol[4]+B*sol[5]))
}
Now we can compute how to get as high of a total sum as possible without exceeding T:
get.vals(5, 6, 8)
# [1] "Add 5 a total of 1 times and add 6 a total of 0 times for sum 5"
# [1] "Divide by 2, yielding value 2"
# [1] "Add 5 a total of 0 times and add 6 a total of 1 times for sum 8"
get.vals(17, 46, 5000000)
# [1] "Add 17 a total of 93 times and add 46 a total of 0 times for sum 1581"
# [1] "Divide by 2, yielding value 790"
# [1] "Add 17 a total of 294063 times and add 46 a total of 3 times for sum 4999999"
I'll use some mathematical approach.
Resume:
You should be able to calculate the max with A,B, T, without iterations (only to get A/B HCD), for T, not to small.
If A or B is an odd number, max = T (with a reserve, I'm not sure you never go over T: see below).
If A and B is even numbers, get C as highest common factor. Then max = round (T/C*2) *C/2 = highest multiple of C/2 below or equal to T
Some explanations:
With the rule: Ap+Bq (without dividing by 2)
1 suppose A and B are primes together, then you can get every integer you want, after the little ones. Then max=T
example: A=11, B=17
2 if A=Cx, and B=Cy, x,y primes together (like 10 and 21), you can get every C multiples, then max= biggest multiple of C below T: round(T/C)*C
example: A=33, B=51 (C=3)
With the rule : you can divide by 2
3 - If C is even number (that is A and B can be divided by 2): max= multiple of C/2 below T: round(T/C*2)*C/2
example: A=22, B=34 (C=2)
4 - Otherwise, you have to find the biggest dividor (highest common factor) of A, B, round(A/2), round (B/2), call it D, max= biggest multiple of D below T: round(T/D)*D
As A and round (A/2) are primes together (idem for B and round (B/2)), then you can get max = T as in case 1 - warning: I'm not sure if you never go past T. To check
We can describe the problem in this way aswell:
f(A , B) = (A * n + B * m) / 2 + (A * x + B * y)
= A * (n * 0.5 + x) + B * (m * 0.5 + y) =
= A * p + B * q
find N: N = f(A , B) and N <= T such that no M: M > N satisfying
the condition exists.
The case without any division by two can easily be represented by n = m = 0 and is thus aswell covered by f.
n and y can be any arbitrary values matching p = n * 0.5 + y (same for q and related values). Note that there are multiple valid solutions as shown in f.
T >= A * p + B * q
r = p * 2, s = q * 2
find integral numbers r, s satisfying the condition
T >= A * r / 2 + B * s / 2
simplify:
T * 2 / B >= A / B * r + s
Thus we know:
(T / B * 2) mod 1 - (A / B * r) mod 1 is minimal and >= 0 for the optimal solution
T * 2 / A >= r >= 0 are the upper and lower bounds for r
(A / B * r) mod 1 = 0, if r = B / gcd(A , B) * n, where n is an integral number
Finding r using these constraints now becomes a trivial task, using binary search. There might be more efficient approach to this, but O(log B) should do for this purpose:
Apply a simple binary-search to find the matching value
in the range [0 , min(T * 2 / A , B / gcd(A , B))
Finding s can easily be done for any corresponding r:
s = roundDown(T * 2 / B - A * r / B)
E.g.:
A = 5
B = 6
T = 8
gcd(A , B) = 1
search-range = [0 , 6)
(T / B * 2) mod 1 = 4 / 6
(A / B * r) mod 1 =
r = 3: 3 / 6 => too small --> decrease r
r = 1: 5 / 6 => too great --> increase r
r = 2: 4 / 6 => optimal solution, r is found
r = 2
s = roundDown(T * 2 / B - A * r / B) = roundDown(3.2 - 1.66) = 1
p = r / 2 = 1 = 1 + 0 = 2 * 0.5 --> n = 1 y = 0 or n = 2 y = 0
q = s / 2 = 0.5 --> n = 0.5 y = 0
8 >= 5 * 1 + 5 * 0.5 * 0 + 0 * 6 + 1 * 0.5 * 6 = 5 + 3
= 5 * 0 + 5 * 0.5 * 2 + 0 * 6 + 1 * 0.5 * 6 = 5 + 3
Advantage of this approach: We can find all solutions in O(log B):
If a value for r is found, all other values r' matching the constraints are as follows: r' = r + B / gcd(A , B) * n. A and B are exchangeable in this approach allowing to optimize even further by using the smaller input value as B.
The rounding of values when the variable is divided by two in your algorithm should only cause minor problems, which can easily be fixed.
I am currently looking to find the largest amount of consecutive odd integers added together to equal a target number.
My current code to find 3 consecutive integers looks like
public class consecutiveOdd {
public static void main(String[] args){
int target = 160701;
boolean found = false;
for(int i = 1; i < target; i++){
if(i + (i+2) + (i+4) == target){
System.out.print(i + " + " + (i+2) + " + " + (i+4));
found = true;
}
}
if(!found){
System.out.println("Sorry none");
}
}
}
I am thinking there will need to be a while loop building iterations of (i+2) increments but am having trouble with developing a correct algorithm. Any help or tips will be much appreciated!
Best,
Otterman
Let's say that the answer is equal to k (k > 0). Then for some odd i we can write: i + (i + 2) + (i + 4) + ... + (i + 2k - 2) = target. You can see that this is a sum of arithmetic progression, therefore you can use a well known formula to compute it. Applying the formula we can get:
i = target/k - k + 1.
Basing on this formula I would suggest the following algorithm:
Iterate over the value of k.
If target/k - k + 1 is a positive odd integer, update the answer.
Simple implementation.
int answer = -1;
for (int k = 1;; k++) {
int i = target / k - k + 1;
if (i <= 0) {
break;
}
// Check if calculated i, can be the start of 'odd' sequence.
if (target % k == 0 && i % 2 == 1) {
answer = k;
}
}
The running time of this algorithm is O(sqrt(target)).
Looking at the pattern:
For 1 summand, i = target
For 2 summands, the equation is 2*i + 2 = target, so i = (target - 2) / 2
For 3 summands, the equation is 3*i + 6 = target, so i = (target - 6) / 3
For 4 summands, the equation is 4*i + 12 = target, so i = (target - 12) / 4
etc. Clearly i must be an odd integer in all cases.
You could work out the general expression for n summands, and simplify it to show you an algorithm, but you might be able to see an algorithm already...
Applying #rossum's suggestion:
For 1 summand, 2m + 1 = target
For 2 summands, 2m + 1 = (target - 2) / 2, so m = (target - 4) / 4
For 3 summands, 2m + 1 = (target - 6) / 3, so m = (target - 9) / 6
For 4 summands, 2m + 1 = (target - 12) / 4, so m = (target - 16) / 8
The sum of a sequence of n odd integers, can be calculated as the average value (midpoint m) multiplied by the number of values (n), so:
sum = 5 + 7 + 9 = m * n = 7 * 3 = 21
sum = 5 + 7 + 9 + 11 = m * n = 8 * 4 = 32
If n is odd then m will be odd, and if n is even then m will be even.
The first and last numbers of the sequence can be calculated as:
first = m - n + 1 = 8 - 4 + 1 = 5
last = m + n - 1 = 8 + 4 - 1 = 11
Other interesting formulas:
m = sum / n
m = (first + last) / 2
last = first + (n - 1) * 2 = first + 2 * n - 2
m = (first + first + 2 * n - 2) / 2 = first + n - 1
The longest sequence would have to start with the lowest possible first value, meaning 1, so we get:
sum = m * n = (first + n - 1) * n = n * n
Which means that the longest sequence of any given sum can at most be sqrt(sum) long.
So starting at sqrt(sum), and searching down until we find a valid n:
/**
* Returns length of sequence, or 0 if no sequence can be found
*/
private static int findLongestConsecutiveOddIntegers(int sum) {
for (int n = (int)Math.sqrt(sum); n > 1; n--) {
if (sum % n == 0) { // m must be an integer
int m = sum / n;
if ((n & 1) == (m & 1)) // If n is odd, mid must be odd. If n is even, m must be even.
return n;
}
}
return 0;
}
Result:
n = findLongestConsecutiveOddIntegers(160701) = 391
m = sum / n = 160701 / 391 = 411
first = m - n + 1 = 411 - 391 + 1 = 21
last = m + n - 1 = 411 + 391 - 1 = 801
Since sqrt(160701) = 400.875..., the result was found in 10 iterations (400 to 391, inclusive).
Conclusion:
Largest Amount of Consecutive Odd Integers to Equal 160701: 391
21 + 23 + 25 + ... + 799 + 801 = 160701