Extract & Delete patterns not functioning entirely with Arraylists - java

this is my first time asking a question on here so I apologize for any mistakes in terms of form.
I am working on an assignment for AP Computer Science which involves generating a listarray filled with random ints (within a certain range) and then processing them with methods that remove objects which either exceed or are less than a threshold determined earlier in the program. Here is an example of the code I wrote along with the preconditions provided by my teacher.
/**
* #param orig is a List of Integer
* #param mid is an int > 2
* #return a new List of Integer that contains, in order, all the numbers in
* orig that are >= mid / 2
*/public static ArrayList<Integer> extractUpper(ArrayList<Integer> orig, int mid) {
ArrayList<Integer> myArray = new ArrayList<Integer>();
for(Integer a: orig) {
if (a >= mid/2)
myArray.add(a);
}
return myArray;
}
/**
* #param orig is a List of Integer
* #param mid is an int > 2
* #return none PostCondition: all numbers less than mid / 2 have been
* removed from orig
*/
public static void deleteUpper(ArrayList<Integer> orig, int mid) {
for(int j = 0; j < orig.size(); j++) {
if (orig.get(j) >= (mid/2))
orig.remove(j);
}
}
To me, this seems like it should work fine, but when I run this:
ic static void main(String[] args) {
//a.
int listLen = 10;
int listMax = 20;
System.out.println("listLen equals " + listLen + " and listMax equals " + listMax);
System.out.println();
//b.
System.out.println("Generating a fixed-length ArrayList of length " + listLen + " with all values >= 0 and < " + listMax);
ArrayList<Integer> Array1 = Main.buildFixedList(listLen, listMax);
System.out.println(Array1);
//c.
System.out.print("The numbers in this ArrayList >= " + listMax/2 + " are: ");
ArrayList<Integer> Array2 = Main.extractUpper(Array1, listMax);
System.out.println(Array2);
//d.
System.out.print("After deleting numbers > " + listMax/2 + " the modified list is: ");
Main.deleteUpper(Array1, listMax);
System.out.println(Array1);
//e.
System.out.print("After deletion, the numbers in the List >= " + listMax/2 + " are: ");
ArrayList<Integer> Array3 = Main.extractUpper(Array1, listMax);
System.out.println(Array3);
//f.
System.out.println();
My output seems to ignore certain numbers, some more frequently than others.
listLen equals 10 and listMax equals 20
Generating a fixed-length ArrayList of length 10 with all values >= 0 and < 20
[14, 16, 12, 9, 8, 11, 14, 16, 1]
The numbers in this ArrayList >= 10 are: [14, 16, 12, 11, 14, 16]
After deleting numbers > 10 the modified list is: [16, 9, 8, 14, 1]
After deletion, the numbers in the List >= 10 are: [16, 14]
The >=10 and <10 methods work occasionally, but I figure it's more of a crap-shoot right now. In this particular example the >=10 method worked but the <10 did not. I am at a loss as to what is wrong with my code.
EDIT:
Thank you for all the replies, I appreciate the help. I have edited both the extractUpper and deleteUpper methods and am getting an even higher rate of success, but the code just seems to ignore some numbers. Here's the code:
/**
* #param orig is a List of Integer
* #param mid is an int > 2
* #return a new List of Integer that contains, in order, all the numbers in
* orig that are >= mid / 2
*/public static ArrayList<Integer> extractUpper(ArrayList<Integer> orig, int mid) {
ArrayList<Integer> myArray = new ArrayList<Integer>();
for (int i = 0; i < orig.size(); i++){
if(orig.get(i) >= mid/2) {
myArray.add(orig.get(i));
}
}
return myArray;
}
/**
* #param orig is a List of Integer
* #param mid is an int > 2
* #return none PostCondition: all numbers less than mid / 2 have been
* removed from orig
*/
public static void deleteUpper(ArrayList<Integer> orig, int mid) {
for ( int i = orig.size()-1; i >= 0; i--){
if (i < orig.size()) {
if(orig.get(i) >= mid/2) {
orig.remove(i);
i++;
}
}
else
i--;
}
}
Here are a few outputs directly from the program:
listLen equals 10 and listMax equals 20
Generating a fixed-length ArrayList of length 10 with all values >= 0 and < 20
[4, 15, 8, 11, 18, 16, 7, 3, 6]
The numbers in this ArrayList >= 10 are: [15, 11, 18, 16]
After deleting numbers > 10 the modified list is: [4, 8, 7, 3, 6]
After deletion, the numbers in the List >= 10 are: []
Generating a fixed-length ArrayList of length 10 with all values >= 0 and < 20
[6, 3, 9, 16, 4, 4, 17, 8, 4]
The numbers in this ArrayList >= 10 are: []
After deleting numbers > 10 the modified list is: [6, 3, 9, 4, 4, 8, 4]
After deletion, the numbers in the List >= 10 are: []
listLen equals 10 and listMax equals 20
Generating a fixed-length ArrayList of length 10 with all values >= 0 and < 20
[4, 5, 0, 4, 12, 12, 1, 12, 10]
The numbers in this ArrayList >= 10 are: [12, 12, 12, 10]
After deleting numbers > 10 the modified list is: [4, 5, 0, 4, 1, 12]
After deletion, the numbers in the List >= 10 are: [12]
Generating a fixed-length ArrayList of length 10 with all values >= 0 and < 20
[15, 16, 2, 8, 1, 7, 3, 0, 15]
The numbers in this ArrayList >= 10 are: [12]
After deleting numbers > 10 the modified list is: [2, 8, 1, 7, 3, 0]
After deletion, the numbers in the List >= 10 are: [12]

Your problem is in the function deleteUpper
You should iterate in reverse order the collection to be able to remove item without impacting the original index of the collection

The problem is in the deleteUpper method.
When you delete an item from an List, the indexes in that List change - if you remove item 3, the item that was previously accesible at index 4 now becomes number 3.
In your implementation you always increase the index pointer, regardless if the deletion happened or not. This means that if two consecutive items meet the deletion criterion, only the first one will be removed.
Use an Iterator instead:
Iterator<Integer> i = orig.iterator();
while (i.hasNext()) {
if (i.next() >= mid) {
i.remove();
}
}
If you don't want to use an Iterator:
for (int i=0; i<orig.size(); ) {
if (orig.get(i) >= mid) {
orig.remove(i);
}
else {
i++;
}
}

Related

How can I efficiently compute the sum of parts of an array of sizes in an arithmetic sequence?

I am trying to find the sum of parts of a given array with a length that is the sum of the first N positive integers for some whole number N. The size of each part for which I am to find the sum are the numbers in said arithmetic sequence. For instance, for an array of length 10, I need to find the sum of the first number, the next two numbers, and so on, until the next N numbers.
Example Input:
[1,4,5,2,6,7,9,8,7,10]
Example Output:
[1,9,15,34]//1, 4+5, 2+6+7, 9+8+7+10
Explanation:
The first sum is 1, the first element (index 0). The sum of the next two numbers is 4 + 5 = 9 (index 1 and 2). The sum of the next three numbers is 2 + 6 + 7 = 15 (index 3, 4, and 5). The sum of the last four numbers is 9 + 8 + 7 + 10 = 34 (index 6, 7, 8, 9).
You can compute the size of the result array using the formula for the sum of an arithmetic sequence, i.e. n(n + 1) / 2.
A prefix sum array can be applied here so so that any range sum can be computed in O(1) time with O(n) precomputation time and space (which is also the overall complexity of this algorithm).
final int[] input = { 1, 4, 5, 2, 6, 7, 9, 8, 7, 10 };
// size * (size + 1) / 2 = input.length
final int size = (-1 + (int) Math.sqrt(1 + 8 * input.length)) / 2;
// derived by quadratic formula
final int[] result = new int[size];
final int[] sum = new int[input.length + 1];
for (int i = 1; i <= input.length; i++) {
sum[i] = sum[i - 1] + input[i - 1];
}
for (int i = 1, j = 0; i <= input.length; i += ++j) {
result[j] = sum[i + j] - sum[i - 1];
}
System.out.println(Arrays.toString(result));
Ideone Demo
The following algorithm is very efficient and does not rely on the summation formula to work (as you had asked about) other than to compute the length of the result array. This should not be a problem since it is basic algebra. If you use a List implementation you would not have to do that.
It also only sums only to the max allowed by the given array. So if you provide an array like
1 2 3 4 5 6 7 8 9 10 11 12 13
It will silently ignore 11 12 and 13 since they don't comprise enough values to continue.
Here is the algorithm with your original data set and the output.
int[] arr = { 1, 4, 5, 2, 6, 7, 9, 8, 7, 10 };
int start = 0; // start of group
int end = 0; // end of group
int[] sol = new int[(int)(-.5 + Math.sqrt(2*arr.length + .25))];
for (int i = 1; i <= sol.length; i++) {
// initialize the sum
int sum = 0;
// compute next end
end += i;
// and sum from start to end
for (int k = start; k < end; k++) {
sum += arr[k];
}
// old end becomes next start
start = end;
sol[i-1] = sum;
}
Prints
[1, 9, 15, 34]

How can I get the greatest product in an array of integers?

This is not for a homework. It's just a part of a monthly algorithm exam for engineers in our company. The exam is done. I failed and this was the part of the problem that stumped me. Though it is not required to pass, it has an effect on your yearly bonus on how well you do in these algorithm exams.
So, given an array of integers, find the greatest product you can get using its elements. This is not the actual problem, just a tiny part of it.
The constraints are:
3 <= size_of_array <= 8
1 <= integer_in_array <= 9
Libraries are not allowed (e.g. Integer.max, Arrays.sort, etc...)
The initial solution I've thought of was to sort the array in descending order. Take the greatest value in the array then multiply it to the remaining integers.
Suppose, we have an array:
int[] arr = {3, 6, 5, 4};
sort(arr); // array becomes {6, 5, 4, 3}
int product = getProduct(arr);
In the getProduct method, I have:
int getProduct(int[] arr) {
int maxVal = arr[0];
int multiplier = 0;
for(int i = 0; i < arr.length; i++) {
if(multiplier == 0) {
multiplier = arr[i];
} else {
multiplier *= 10;
multiplier += arr[i];
}
}
return maxVal * multiplier; // 6 * 543 = 3258
}
It turns out the my implementation is not correct because the highest product you can get out of this array would be:
63 * 54 = 3402
I think this part of the problem boils down to some sort of permutation problem where you try all possible combinations. Please note that libraries are not allowed. So in case you need some type of sorting, you have to implement it yourself. I would appreciate if the answer is in Java since it is my language of choice for this problem.
EDIT:
The value of each element in the array is always a positive single digit integer except for zero. Hence the constraint,
1 <= integer_in_array <= 9
Each integer could vary from 1 to 9 only. And the number of elements in the array varies from 3 to 8 only. The smallest array you could get would have 3 elements and the biggest would have 8 elements in it.
The question is how to get the highest possible product using the elements in the array. So, in my sample array, possible combinations would be:
63 * 54 = 3402 // Correct answer
6 * 543 = 3258 // My answer (wrong)
53 * 46 = 2438
4 * 536 = 2144
36 * 54 = 1944
5 * 634 = 3170
Easy way: brute force to all combinations. Let's divide the array into 2 parts, so we want to create two largest number from those numbers.
public int maxProduct(int[]data) {
Arrays.sort(data);//non-decreasing order
int n = data.length;
int result = 0;
for(int i = 0; i < (1 << n); i++){
int a = 0;
int b = 0;
for(int j = n - 1; j >= 0; j--){
if(((1 << j) & i) == 0){
a = a * 10 + data[j];
}else{
b = b * 10 + data[j];
}
}
result = Integer.max(result, a*b);
}
return result;
}
Time complexity : O(n*2 ^ n)
Here’s my go. I have no strict argument that it works correctly in all cases, nor that it’s the simplest possible solution. On the other hand I haven’t found any holes yet.
static int getProduct(int... arr) {
// Should validate arr
Arrays.sort(arr);
int a = arr[arr.length - 1];
int b = arr[arr.length - 2];
for (int ix = arr.length - 3; ix >= 0; ix--) {
int digit = arr[ix];
// append d to either a or b depending on where it makes the greater product
int candidate1 = (a * 10 + digit) * b;
int candidate2 = a * (b * 10 + digit);
if (candidate1 > candidate2) {
a = a * 10 + digit;
} else {
b = b * 10 + digit;
}
}
System.out.println("" + a + " * " + b + " = " + a * b);
return a * b;
}
For testing purposes I have put in a System.out.println that you may not want to be there in your final method. Some example calls:
getProduct(9, 8, 1);
getProduct(9, 2, 1);
getProduct(1, 2, 2, 1);
getProduct(1, 2, 3, 9);
getProduct(1, 2, 8, 9);
getProduct(1, 7, 8, 9);
getProduct(2, 3, 4, 5, 6);
getProduct(1, 3, 3, 4, 6, 7, 7, 9);
Output from same:
9 * 81 = 729
9 * 21 = 189
21 * 21 = 441
91 * 32 = 2912
91 * 82 = 7462
91 * 87 = 7917
63 * 542 = 34146
9631 * 7743 = 74572833
Please start shooting…
Edit: I think that a is always constructed from the digits at indices length - 1, length - 4, length - 6, length - 8, and b from length - 2, length - 3, length - 5, length - 7, but limitied to the length of the array, of course. This observation may lead to code that is simpler (and performs a bit more efficiently), but where it’s even less obvious that it gives the best result.

How can I optimize this solution? (Cutting a specific part of an array given bounds)

I'm given a list of numbers, and given a number N, cut out N numbers from the center of the list. So, if the list is:
1 2 3 5 7 11 13 17 19
And N = 3, output would be:
5 7 11
Or if the list is:
1 2 3 5 7 11 13 17
And N = 4, output would then be:
3 5 7 11
My current solution is O(N^2) (or at least I think it is? Idk if that nested for loop would mean this is O(N^2)), where I iterate over the array of numbers until the amount of numbers from the start to i is == the amount of numbers from (size of array - (i + cut size)). Because a cut in the middle would mean there's the same amount of numbers on the left side of the cut as the right side.
"nums" is the array of numbers I'm finding a cut in the middle for.
int rightof = 0;
ArrayList<Integer> cut = new ArrayList<Integer>();
for (int i = 0; i < nums.size(); i++) {
rightof = nums.size() - (i + cutsize);
if (i == rightof && i != 0) {
for (int j = i; j < (cutsize + i); j++) {
cut.add(nums.get(j));
}
break;
}
}
The thing that's slowing this down is adding the appropriate numbers to the "cut" array. So I'm not sure how I might optimize that step.
The Java 8 stream api makes this fairly easy. The number of elements to skip is the size minus n divided by two, and limit to n elements.
List<Integer> cut = Arrays.asList(1, 2, 3, 5, 7, 11, 13, 17, 19);
int n = 3;
int sk = (cut.size() - n) / 2;
List<Integer> al = cut.stream().skip(sk).limit(n).collect(Collectors.toList());
System.out.println(al);
Learn the power of sublist():
List<T> result = arr.subList((arr.size()+1)/2 - arr.size()/4, arr.size()/2 + arr.size()/4);
Where arr is your List
Example:
List<Integer> arr = Arrays.asList(1, 2, 3, 5, 7, 11, 13, 17);
arr.subList((arr.size()+1)/2 - arr.size()/4, arr.size()/2 + arr.size()/4)
.forEach(System.out::println);
Output:
3
5
7
11
If you just want to do this with simple loops:
List<Integer> list = new ArrayList<>();
int size = arr.size();
for(int i = (size+1)/2-size/4; i < size/2+size/4; i++) {
list.add(arr.get(i));
}

How to get all the sets of consecutive numbers that add up to form a number?

I wanna create a program that generates sets of consecutive numbers that add up to form a number. For example. if the input number is 15, it should give -
7, 8
4, 5, 6
1, 2, 3, 4, 5
Some formula/algorithm/loop that can do something that fits in. It could generate an array or print it. This may seem a math problem or silly question but I can't actually figure out how to do that programmatically in Java.
Please try to give exact code that can do the thing.
Say your input is N. You know each set of k consecutive numbers will be centered around N/k. A solution exists for even k if N/k ends with 0.5, and odd k if N/k is an integer. The solution, if one exists, is the k integers centered around N/k.
k=1: 15/1 = 15, so 15 (trivial; may want to omit)
k=2: 15/2 = 7.5, so 7,8
k=3: 15/3 = 5, so 4,5,6
k=4: 15/4 = 3.75, so no solution
k=5: 15/5 = 3, so 1,2,3,4,5
k=6: 15/6 = 2.5, so 0,1,2,3,4,5
etc...
k=15: 15/15 = 1, so -6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8
You can easily modify this to limit to positive or nonnegative solutions.
I'll expand on #MBo's answer as it conveys a very clean algorithm. Wiki provides a good intro on arithmetic progressions, copied below for your convenience.
Sum
Derivation
The sum of a sequence starting with number a and consisting of n consecutive numbers:
S = (n/2) * [2 * a + (n-1) * d]
For consecutive numbers the step d is 1.
S = (n/2) * [2 * a + (n-1)]
Here we can transition to #MBo's post.
P = 2 * S = n * [2 * a + (n-1)]
We can iterate all possible counts of consecutive numbers n and check if the resulting a is valid (i.e. a is an integer).
Let's factor out a.
Say P = n * q => q = 2 * a + (n-1) => 2 * a = q - n + 1 => a = (q - n + 1) / 2
Filters
1) we mentioned we could iterate all possible counts of consecutive numbers n, but given p = n * q it's safe to say n needs to be a divisor of p.
p % n == 0
nMax = (int)Math.sqrt(p)
2) a is an integer and a = (q - n + 1) / 2 => (q - n + 1) is even => q - n is odd.
((q - n) & 1) == 1
Implementation
import java.util.*;
import java.lang.Math;
import java.util.stream.IntStream;
import static java.util.stream.Collectors.toList;
public class Progressions
{
public static void main(String[] args)
{
List<List<Integer>> list = Calculate(15);
System.out.print(list);
}
public static List<List<Integer>> Calculate(int s)
{
List<List<Integer>> list = new ArrayList<>();
int p = 2*s;
int nMax = (int)Math.sqrt(p);
for (int n=2; n<=nMax; n++) {
if(p % n == 0) {
int q = p / n;
if(((q - n) & 1) == 1) {
int a = (q - n + 1) / 2;
list.add(range(a,n));
}
}
}
return list;
}
public static List<Integer> range(int a, int n) {
return IntStream.range(a, a+n)
.boxed()
.collect(toList());
}
}
Consecutive numbers form arithmetic progression. If it starts from number a and has n members, it's sum is
S = n * (2 * b + (n-1)) / 2
so
P = 2 * S = n * (2 * b + (n-1))
So for given input S we can factorize 2*S into all possible pairs of integer factors P = n * q where n<=q, then get starting number
a = (q - n + 1) / 2
If a is integer (oddity of q and n differs) then pair (a, n) represents valid sequence starting from a with n members
Example for S = 15, 2S = 30:
30 = 2 * 15 => n = 2, a = 7 => (7,8)
30 = 3 * 10 => n = 3, a = 4 => (4,5,6)
30 = 5 * 6 => n = 5, a = 1 => (1,2,3,4,5)
Simple Python example:
import math
def getseqs(s):
print(s)
p = 2 * s
for n in range(2, math.ceil(math.sqrt(p))):
if (p % n == 0):
q = p // n
if (((q - n) & 1) == 1): #compare parity
a = (q - n + 1) // 2
seq = list(range(a, a+n))
print(seq, sum(seq))
getseqs(17)
getseqs(15)
getseqs(72)
17
[8, 9] 17
15
[7, 8] 15
[4, 5, 6] 15
[1, 2, 3, 4, 5] 15
72
[23, 24, 25] 72
[4, 5, 6, 7, 8, 9, 10, 11, 12] 72
Consider the int input is your input number (ex. 15) and List<int[]> list as a storage of the result consecutive numbers, here you go:
List<int[]> list = new ArrayList<>();
int lower = 1; // Start searching from 1
int upper = (int) Math.floor(input + 1 / 2); // Up to the half of input (8+9 > 15)
while (lower < upper) { // Iterate between the bounds
int sum = 0;
for (int i = lower; i <= upper; i++) { // Iterate and sum the numbers
sum += i;
if (sum == input) { // If it matches the input
// Add the range to the List
// You have to loop them by one and add to the
// List before version Java-8
list.add(IntStream
.range(lower, i + 1)
.toArray());
break; // Found, no reason to continue
}
if (sum > input) { // Terminate the loop if the sum overlaps
break;
}
lower++; // Increment and try the sums from
// a higher starting number
sum = 0; // Reset the sum
}
The result for the input 15 is a List of these arrays:
[1, 2, 3, 4, 5]
[4, 5, 6]
[7, 8]
Here's a suggestion:
For an input number N:
you only have to consider numbers between 1 and N.
you can maintain an interval that represents the current subset of [1,...,N]. Maintain the sum of the current interval. The first interval will be [1,1], and its sum is 1.
As long as the sum < N, increase the right end of the interval by one (for example, you start with the interval [1,1]. Since 1 < N, you extend it to [1,2].
If the sum of the current interval is equal to N, you add that interval to the output, remove the left end of the interval (also removing it from the current sum), and continue.
If the sum exceeds N, you also remove the left end of the interval (also removing it from the current sum), and continue.
You finish when the interval becomes [N,N] (which is the final interval you should add to the output).
For the input 15, here's how the interval will change over time:
Interval Sum
[1] 1
[1,2] 3
[1,2,3] 6
[1,2,3,4] 10
[1,2,3,4,5] 15 -> output [1,2,3,4,5]
[2,3,4,5] 14
[2,3,4,5,6] 20
[3,4,5,6] 18
[4,5,6] 15 -> output [4,5,6]
[5,6] 11
[5,6,7] 18
[6,7] 13
[6,7,8] 21
[7,8] 15 -> output [7,8]
[8] 8
[8,9] 17
[9] 9
[9,10] 19
[10]
...
[15] 15 -> output 15
You can probably make some optimization once the sum of two consecutive numbers becomes higher than the target sum, at which point you can terminate the loop, and just add the final set (which contains just the target sum).
It used a Window Sliding Technique/Algorithm. You can also google sliding window algorithm sum.
I am writing Implementation of the #Dave solution.
Try to Solve before asking... That's how we learn. (only if we can't get then ask)
Scanner s = new Scanner(System.in);
int inputNumber = s.nextInt();
int k = 1;
while(inputNumber/k >= .5){
Float sequenceMid = (float) inputNumber/k;
if( k%2 == 0 && (sequenceMid *2 == Math.ceil(sequenceMid *2)) ){
for(int i = ((int)Math.floor(sequenceMid) - (k/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}else if( (k%2 == 1) && (sequenceMid == Math.ceil(sequenceMid))){
for(int i = (Math.round(sequenceMid) - ((k-1)/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}
k++;
}
Here is an idea that is similar to Eran's solution.
Since we're dealing with consecutive numbers, a cummulative sum (cumsum) can usually help. The basic idea is that we want to find the difference between two cummulative sums that gives exactly K, where K is 15 in your example.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
differences:
15 - 0 = 15 -> [1, 2, 3, 4]
21 - 6 = 15 -> [4, 5, 6]
36 - 21 = 15 -> [7, 8]
The cummulative sum starts from 0 so we can do 15 - 0 subtraction. The number included as the solution will be left-exclusive and right-inclusive. That just means add 1 to the left index (index starts from 0). Hopefully the pattern is quite clear.
The next task is to create an algorithm that does some sliding window with varying width across the cummulative sum. The idea is to search for the difference with the exact value of K. We can start at the beginning where the left and right side of the window points to 0. While the difference is <= K, we want to increase the right side of the window, enlarging the window and the difference.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (] -> 0 - 0 = 0
2nd: (---] -> 3 - 0 = 3
3rd: (------] -> 6 - 0 = 0
Once the algorithm hit 15, it will print out the first answer, and then it will increase it one more time. However, once we have the difference > K, we want to increase the left number, reducing the difference.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (-----------------] -> 15 - 0 = 15 <print>
2nd: (---------------------] -> 21 - 0 = 21
3rd: (-----------------] -> 21 - 1 = 20
Notice that the left side is bounded to be < K/2 since K//2 + (K//2 + 1) >= K (where the equality is possible due to integer division denoted by //). So we can stop the loop early when the left side reaches K//2 (due to left-exclusive).
public static int cumsum(int index) {
return index * (index + 1) / 2;
}
public static String printRange(int left, int right) {
StringBuilder buffer = new StringBuilder();
buffer.append('[');
for (int i=left+1;i<=right;i++) {
buffer.append(i);
buffer.append(',');
}
buffer.deleteCharAt(buffer.length()-1);
buffer.append(']');
return buffer.toString();
}
public static void main(String[] args) {
int K = 15;
int K_ov_2 = K/2;
int left_index = 0;
int right_index = 0;
int diff;
while (left_index < K_ov_2) {
diff = cumsum(right_index) - cumsum(left_index);
System.out.println("diff = " + diff + ", left = " + left_index + ", right = " + right_index);
if (diff == K) {
System.out.println(printRange(left_index,right_index));
}
if (diff <= K) {
right_index++;
} else {
left_index++;
}
}
}
I added the debug line so the output can become more obvious.
diff = 0, left = 0, right = 0
diff = 1, left = 0, right = 1
diff = 3, left = 0, right = 2
diff = 6, left = 0, right = 3
diff = 10, left = 0, right = 4
diff = 15, left = 0, right = 5
[1,2,3,4,5]
diff = 21, left = 0, right = 6
diff = 20, left = 1, right = 6
diff = 18, left = 2, right = 6
diff = 15, left = 3, right = 6
[4,5,6]
diff = 22, left = 3, right = 7
diff = 18, left = 4, right = 7
diff = 13, left = 5, right = 7
diff = 21, left = 5, right = 8
diff = 15, left = 6, right = 8
[7,8]
diff = 24, left = 6, right = 9

Project Euler, problem 2- Java [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I'm a relatively new java programmer and I've been tinkering around with this program for the better part of the day now and I'm still stuck; I was hoping that you could help me with this.
So the program is supposed to meet the following requirements:
Each new term in the Fibonacci
sequence is generated by adding the
previous two terms. By starting with 1
and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the
Fibonacci sequence whose values do not
exceed four million, find the sum of
the even-valued terms.
This is my code:
//Generates Fibonacci sequence
while (fibNum < 144)
{
int lastValue = (Integer) fibList.get(fibList.size()-1);
int secondToLastValue = (Integer) fibList.get(fibList.size()-2);
fibNum = secondToLastValue + lastValue;
if (fibNum < 144)
{
fibList.add(fibNum);
}
//Picks out the even numbers from limitFibList
for (int i = 0; i < fibList.size(); i++)
{
if ((Integer) fibList.get(i) % 2 == 0)
{
evenNumsFibList.add(fibList.get(i));
}
}
//Sums up the total value of the numbers in the evenNumsFibList
for (int i = 0; i < evenNumsFibList.size(); i++)
{
sum += (Integer) evenNumsFibList.get(i);
}
...and this is the output that I'm getting:
Fibonacci sequence list: [1, 2, 3]
Size of the Fibonacci list: 3
Even Numbers list: [2]
Total sum of even numbers: 2
Fibonacci sequence list: [1, 2, 3, 5]
Size of the Fibonacci list: 4
Even Numbers list: [2, 2]
Total sum of even numbers: 6
Fibonacci sequence list: [1, 2, 3, 5, 8]
Size of the Fibonacci list: 5
Even Numbers list: [2, 2, 2, 8]
Total sum of even numbers: 20
Fibonacci sequence list: [1, 2, 3, 5, 8, 13]
Size of the Fibonacci list: 6
Even Numbers list: [2, 2, 2, 8, 2, 8]
Total sum of even numbers: 44
Fibonacci sequence list: [1, 2, 3, 5, 8, 13, 21]
Size of the Fibonacci list: 7
Even Numbers list: [2, 2, 2, 8, 2, 8, 2, 8]
Total sum of even numbers: 78
Fibonacci sequence list: [1, 2, 3, 5, 8, 13, 21, 34]
Size of the Fibonacci list: 8
Even Numbers list: [2, 2, 2, 8, 2, 8, 2, 8, 2, 8, 34]
Total sum of even numbers: 156
Fibonacci sequence list: [1, 2, 3, 5, 8, 13, 21, 34, 55]
Size of the Fibonacci list: 9
Even Numbers list: [2, 2, 2, 8, 2, 8, 2, 8, 2, 8, 34, 2, 8, 34]
Total sum of even numbers: 278
Fibonacci sequence list: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Size of the Fibonacci list: 10
Even Numbers list: [2, 2, 2, 8, 2, 8, 2, 8, 2, 8, 34, 2, 8, 34, 2, 8, 34]
Total sum of even numbers: 444
Fibonacci sequence list: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Size of the Fibonacci list: 10
Even Numbers list: [2, 2, 2, 8, 2, 8, 2, 8, 2, 8, 34, 2, 8, 34, 2, 8, 34, 2, 8, 34]
Total sum of even numbers: 654
Obviously my while loop is contributing to my problems, but I don't know how to fix it.
Would greatly appreciate your help,
Haque
If you take a closer look at the numbers in the Fibonacci sequence that you actually need (only the even ones need to be summed), you will see a pattern:
0 1 1 2 3 5 8 13 21 34 55 89 144 ...
- O O E O O E O O E O O E
Notice that every 3rd number starting after 0 is even. Therefore, you can eliminate any checking for evenness if you calculate every third Fibonacci number. Looking again at the sequence, you can see that if k is the present even Fibonacci number you are looking at, and j is the one previous, the next even Fibonacci number n can be obtained by:
n = 4k + j
So in Java, you could try something like this:
int j = 0;
int k = 2;
int sum = j+k;
while (k < LIMIT) {
int tmp = 4*k + j;
sum = sum + tmp;
j = k;
k = tmp;
}
Looks like you are missing the close brackets on the while loop. So the other for's are running within it.
So:
while (fibNum < 144)
{
int lastValue = (Integer) fibList.get(fibList.size()-1);
int secondToLastValue = (Integer) fibList.get(fibList.size()-2);
fibNum = secondToLastValue + lastValue;
if (fibNum < 144)
{
fibList.add(fibNum);
}
}
//Picks out the even numbers from limitFibList
for (int i = 0; i < fibList.size(); i++)
{...
Am I missing something? Why do you need to create list? You just need a sum of even-valued numbers? Right? If I understand you correctly you can get your sum in 10 lines of code... I don't have Java IDE opend, so I'll give you Pythone code. If it is what you need I'll convert it into Java.
def fib(n=4000001): # write Fibonacci series up to n
r = 0
a, b = 0, 1
while b < n:
if not b%2 :
print(b, end=' ')
r += b
a, b = b, a+b
return r
OUTPUT:
2 8 34 144 610 2584 10946 46368 196418 832040 3524578
sum = 4613732
public class Euler002 {
int counter = 0;
public int getCounter () {
return counter;
}
public int getFibTotal () {
final int UPPER_LIMIT = 4000000;
int fib1 = 0;
int fib2 = 1;
int newFib = fib1 + fib2;
int total = 0;
while (newFib < UPPER_LIMIT) {
counter++;
fib1 = fib2;
fib2 = newFib;
newFib = fib1 + fib2;
if ((newFib % 2) == 0) {
total += newFib;
}
}
return total;
}
/**
* #param args
*/
public static void main(String[] args) {
Euler002 euler002 = new Euler002();
int total = euler002.getFibTotal();
System.out.println(" Counter = " + euler002.getCounter() + " And Fib Total is " + total);
}
}
The problem is here:
for (int i = 0; i < fibList.size(); i++)
{
if ((Integer) fibList.get(i) % 2 == 0)
{
evenNumsFibList.add(fibList.get(i)); <-- HERE
}
}
You're adppending a whole new list of all the even numbers to the end of the list you already have.
You need to delete everything in evenNumsFibList before calling this loop again, or modify the loop to only add even numbers that are not already in the list.
That's assuming your indentation is incorrect. If your indentation is actually how you want it, then you're simply missing a closing bracket on your while loop.

Categories

Resources