#!/usr/bin/python2
"""
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.
"""
odd, even = 0,1
total = 0
while True:
odd = odd + even #Odd
even = odd + even #Even
if even < 4000000:
total += even
else:
break
print total
My algo:
If I take first 2 numbers as 0, 1; the number that I find first in while loop will be an odd number and first of Fibonacci series.
This way I calculate the even number and each time add the value of even to total.
If value of even is greater than 4e6, I break from the infinite loop.
I have tried so much but my answer is always wrong. Googling says the answer should be 4613732 but I always seem to get 5702886
Basically what you're doing here is adding every second element of the fibonacci sequence while the question asks to only sum the even elements.
What you should do instead is just iterate over all the fibonacci values below 4000000 and do a if value % 2 == 0: total += value. The % is the remainder on division operator, if the remainder when dividing by 2 equals 0 then the number is even.
E.g.:
prev, cur = 0, 1
total = 0
while True:
prev, cur = cur, prev + cur
if cur >= 4000000:
break
if cur % 2 == 0:
total += cur
print(total)
def fibonacci_iter(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
print sum(a for a in fibonacci_iter(4e6) if not (a & 1))
Here is simple solution in C:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i=1,j=1,sum=0;
while(i<4000000)
{
i=i+j;
j=i-j;
if(i%2==0)
sum+=i;
}
printf("Sum is: %d",sum);
}
Your code includes every other term, not the even-valued ones. To see what's going on, print even just before total += even - you'll see odd numbers. What you need to do instead is check the number you're adding to the total for evenness with the modulo operator:
total = 0
x, y = 0, 1
while y < 4000000:
x, y = y, x + y
if x % 2:
continue
total += x
print total
code in python3:
sum = 2
a = 1
b = 2
c = 0
while c <= 4000000:
c = a + b
if c%2 == 0:
sum += c
a,b = b,c
print(sum)
output >>> 4613732
You just misunderstood with the even sequence and even value.
Example: 1, 2, 3, 5, 8, 13, 21
In the above sequence we need to pick 1, 3, 5, 13, 21 and not 2, 5, 13.
Here is the solution fro JAVA
public static void main(String[] args) {
int sum = 2; // Starts with 1, 2: So 2 is added
int n1=1;
int n2=2;
int n=0;
while(n<4000000){
n=n1+n2;
n1=n2;
n2=n;
if(n%2==0){
sum=sum+n;
}
}
System.out.println("Sum: "+sum);
}
Output is,
Sum: 4613732
def fibLessThan(lim):
a ,b = 1,2
total = 0
while b<lim:
if b%2 ==0:
total+=b
a,b = b,a+b
return total
I tried this exactly working answer. Most of us are adding number after fib formula where we are missing 2. With my code I am adding 2 first then fib formula. This is what exact answer for the Euler problem.
This is the second problem in the Project Euler series.
It is proven that every third Fibonacci number is even (originally the zero was not part of the series). So I start with a, b, c being 0,1,1 and the sum will be every recurring first element in my iteration.
The values of my variables will be updated with each being the sum of the preceding two:
a = b + c, b = c + a , c = a + b.
The variable a will be always even. In this way I can avoid the check for parity.
In code:
def euler2():
a, b, c, sum = 0, 1, 1, 0
while True:
print(a, b, c)
a, b, c = (b + c), (2 * c + b), (2 * b + 3 * c)
if a >= 4_000_000:
break
sum += a
return sum
print(euler2())
it should be:
odd, even = 1,0
Also, every third numer is even (even + odd + odd = even).
If you add every second value of the fibonacci sequence you'll get the next fibonacci value after the last added value. For example:
f(0) + f(2) + f(4) = f(5)
0 + 1 + 3 + 8 = 13
But your code currently does not add the first even value 1.
Other answers are correct but note that to just add all even numbers in an array, just do
myarray=[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
sum(map(lambda k:k if k%2 else 0, myarray))
or
sum([k if k%2 else 0 for k in [1,2,3,4,5]])
Every 3rd item in the Fibonnaci sequence is even. So, you could have this:
prev, cur = 0, 1
count = 1
total = 0
while True:
prev, cur = cur, prev + cur
count = count + 1
if cur >= 4000000:
break
if count % 3 == 0:
total += cur
print(total)
or this (changing your code as little as possible):
even, odd = 0,1 # this line was corrected
total = 0
while True:
secondOdd = even + odd # this line was changed
even = odd + secondOdd #Even # this line was changed
if even < 4000000:
total += even
odd = secondOdd + even # this line was added
else:
break
print total
Another way would be (by the use of some simple math) to check that the sum of a2+a5+a8+a11+...+a(3N+2) (the sum of even Fibonacci values) is equal to (a(3N+4)-1)/2. So, if you can calculate directly that number, there is no need to calculate all the previous Fibonacci numbers.
not sure if your question is already answered or you've found a solution, but here's what you're doing wrong. The problem asks you to find even-valued terms, which means that you'll need to find every value in the fibonacci sequence which can be divided by 2 without a remainder. The problem does not ask you to find every even-indexed value. Here's the solution to your problem then, which gives a correct answer:
i = 1
total = 0
t = fib(i)
while t <= 4000000:
t = fib(i)
if t % 2 == 0:
total += t
i += 1
print total
Basically you loop through every each value in fibonacci sequence, checking if value is even by using 'mod' (% operator) to get remainder, and then if it's even you add it to sum.
Here is how I was able to solve this using native javascript.
var sum = 0,
x = 1,
y = 2,
z = 0;
while (z < 4000000) {
if (y%2==0){
sum +=y;
}
z = x + y;
x = y;
y = z;
} console.log(sum);
I did it differently.
def fibLessThan(lim):
#################
# Initial Setup #
#################
fibArray=[1, 1, 2]
i=3
#####################
# While loop begins #
#####################
while True:
tempNum = fibArray[i-2]+fibArray[i-1]
if tempNum <= lim:
fibArray.append(tempNum)
i += 1
else:
break
print fibArray
return fibArray
limit = 4000000
fibList = fibLessThan(limit)
#############
# summation #
#############
evenNum = [x for x in fibList if x%2==0]
evenSum = sum(evenNum)
print "evensum=", evenSum
Here is my Python code:
even_sum = 0
x = [1, 1] # Fibonacci sequence starts with 1,1...
while (x [-2] + x [-1]) < 4000000: # Check if the coming number is smaller than 4 million
if (x [-2] + x [-1]) % 2 == 0: # Check if the number is even
even_sum += (x [-2] + x [-1])
x.append (x [-2] + x [-1]) # Compose the Fibonacci sequence
print (even_sum)
Although it's hard to believe that a question with 17 answers needs yet another, nearly all previous answers have problems in my view: first, they use the modulus operator (%) aka division to solve an addition problem; second, they calculate all the numbers in the sequence and toss the odd ones; finally, many of them look like C programs, using little of Python's advantages.
Since we know that every third number of the Fibonacci sequence is even, we can generate every third number starting from 2 and sum the result:
def generate_even_fibonacci(limit):
previous, current = 0, 2
while current < limit:
yield current
previous, current = current, current * 4 + previous
print(sum(generate_even_fibonacci(4_000_000)))
OUTPUT
> python3 test.py
4613732
>
So much code for such a simple series. It can be easily shown that f(i+3) = f(i-3) + 4*f(i) so you can simply start from 0,2 which are f(0),f(3) and progress directly through the even values striding by 3 as you would for the normal series:
s,a,b = 0,0,2
while a <= 4000000: s,a,b = s+a,b,a+4*b
print(s)
I solved it this way:
list=[1, 2]
total =2
while total< 4000000:
list.append(list[-1]+list[-2])
if list[-1] % 2 ==0:
total += list[-1]
print(total)
long sum = 2;
int start = 1;
int second = 2;
int newValue = 0;
do{
newValue = start + second;
if (newValue % 2 == 0) {
sum += newValue;
}
start = second;
second = newValue;
} while (newValue < 4000000);
System.out.println("Finding the totoal sum of :" + (sum));`enter code here`
The first mistake was you messed the Fibonacci sequence and started with 0 and 1 instead of 1 and 2. The sum should therefore be initialized to 2
#!/usr/bin/python2
firstNum, lastNum = 1, 2
n = 0
sum = 2 # Initialize sum to 2 since 2 is already even
maxRange = input("Enter the final number")
max = int(maxRange)
while n < max:
n = firstNum + lastNum
firstNum = lastNum
lastNum = n
if n % 2 == 0:
sum = sum + n
print(sum)
I did it this way:)
It works completely fine:)
n = int(input())
f = [0, 1]
for i in range(2,n+1):
f.append(f[i-1]+f[i-2])
sum = 0
for i in f:
if i>n:
break
elif i % 2 == 0:
sum += i
print(sum)
There are many great answers here. Nobody's posted a recursive solution so here's one of those in C
#include <stdio.h>
int filt(int n){
return ( n % 2 == 0);
}
int fib_func(int n0, int n1, int acc){
if (n0 + n1 > 4000000)
return acc;
else
return fib_func(n1, n0+n1, acc + filt(n0+n1)*(n0+n1));
}
int main(int argc, char* argv){
printf("%d\n", fib_func(0,1,0));
return 0;
}
This is the python implementation and works perfectly.
from math import pow
sum=0
summation=0
first,second=1,2
summation+=second
print first,second,
while sum < 4*math.pow(10,6):
sum=first+second
first=second
second=sum
#i+=1
if sum > 4*math.pow(10,6):
break
elif sum%2==0:
summation+=sum
print "The final summation is %d" %(summation)
problem in your code basicly related with looping style and checking condition timing. with below algorithm coded in java you can find (second + first) < 4000000 condition check and it brings you correct ( which less than 4000000) result, have a nice coding...
int first = 0, second = 1, pivot = 0;
do {
if ((second + first) < 4000000) { // this is the point which makes your solution correct
pivot = second + first;
first = second;
second = pivot;
System.out.println(pivot);
} else {
break;
}
} while (true);
Related
Target sum prompt:
You are given a set of positive numbers and a target sum ‘S’. Each number should be assigned either a ‘+’ or ‘-’ sign. We need to find the total ways to assign symbols to make the sum of the numbers equal to the target ‘S’.
Input: {1, 1, 2, 3}, S=1
Output: 3
Explanation: The given set has '3' ways to make a sum of '1': {+1-1-2+3} & {-1+1-2+3} & {+1+1+2-3}
let’s say ‘Sum(s1)’ denotes the total sum of set ‘s1’, and ‘Sum(s2)’ denotes the total sum of set ‘s2’. Add negative sign to set 's2'
This equation can be reduced to the subset sum problem target + sum(nums)/2
sum(s1) - sum(s2) = target
sum(s1) + sum(s2) = sum(nums)
2 * sum(s1) = target + sum(nums)
sum(s1) = target + sum(nums) / 2
def findTargetSumWays(nums, S):
"""
:type nums: List[int]
:type S: int
:rtype: int
"""
if (sum(nums) + S) % 2 == 1 or sum(nums) < S:
return 0
ssum = (sum(nums) + S) // 2
dp = [[0 for _ in range(ssum + 1)] for _ in range(len(nums))]
# col == 0
for i in range(len(nums)):
# [] or [0]
if i == 0 and nums[i] == 0:
dp[i][0] = 2
# [] or [0] from previous
elif nums[i] == 0:
dp[i][0] = 2 * dp[i-1][0]
else: # empty set only
dp[i][0] = 1
# take 1st element nums[0] in s == nums[0]
for s in range(1, ssum + 1):
if nums[0] == s:
dp[0][s] = 1
for i in range(1, len(nums)):
for s in range(1, ssum + 1):
if nums[i] != 0:
# skip element at i
dp[i][s] = dp[i - 1][s]
# include element at i
if s >= nums[i]:
dp[i][s] += dp[i - 1][s - nums[i]]
else: # nums[i] = 0
dp[i][s] = dp[i-1][s] * 2
return dp[len(nums) - 1][ssum]
I've spent a few hours on this prompt but still couldn't pass the following example
[7,0,3,9,9,9,1,7,2,3]
6
expected: 50
output: 43 (using my algorithm)
I've also looked through other people's answers here, they all makes sense but I just want to know where could I have possibly missed in my algorithm here?
You can do it like this:
from itertools import product
def findTargetSumWays(nums, S):
a = [1,-1]
result=[np.multiply(nums,i) for i in list(product(a, repeat=len(nums))) if sum(np.multiply(nums,i))==S]
return(len(result))
findTargetSumWays(inputs,6)
50
Basically I get all possible combinations of -1,1 in tuples with the size the same as input elements and then I'm multiplying these tuples with input.
I ran into this same issue when handling zeroes but I did this on C++ where I handled zeroes seperately.
Make sure that in the knapsack approach skip zeroes i.e.
if(a[i-1] == 0)
dp[i][j] = dp[i-1][j];
We can handle zeroes seperately by simply counting the zero occurences and we can put them in either S1 or S2. So, for each zero it is 2*(answer) and for n zeroes its 2^n * (answer) i.e.
answer = pow(2, num_zero) * answer;
Also, don't forget to simply return zero if sum(nums) + target is odd as S1 can't be fractional or target is greater than sum(nums) i.e.
if(sum < target || (sum+target)%2 == 1)
return 0;
The overall code looks like this:
int subsetSum(int a[], int n, int sum) {
int dp[n+1][sum+1];
for(int i = 0; i<sum+1; i++)
dp[0][i] = 0;
for(int i = 0; i<n+1; i++)
dp[i][0] = 1;
for(int i = 1; i<n+1; i++) {
for(int j = 1; j<sum+1; j++) {
if(a[i-1] == 0)
dp[i][j] = dp[i-1][j];
else if(a[i-1]<=j)
dp[i][j] = dp[i-1][j-a[i-1]] + dp[i-1][j];
else
dp[i][j] = dp[i-1][j];
}
}
return dp[n][sum]; }
int findTargetSumWays(int a[], int target) {
int sum = 0;
int num_zero = 0;
for(int i = 0; i<a.size(); i++) {
sum += a[i];
if(a[i] == 0)
num_zero++;
}
if(sum < target || (sum+target)%2 == 1)
return 0;
int ans = subsetSum(a, a.size(), (sum + target)/2);
return pow(2, num_zero) * ans;
}
The source of the problem is this part, initializing col == 0:
# col == 0
for i in range(len(nums)):
# [] or [0]
if i == 0 and nums[i] == 0:
dp[i][0] = 2
# [] or [0] from previous
elif nums[i] == 0:
dp[i][0] = 2 * dp[i-1][0]
else: # empty set only
dp[i][0] = 1
This code treats zeros differently depending on how the list is ordered (it resets the value to 1 if it hits a nonzero value). It should instead look like this:
# col == 0
for i in range(len(nums)):
# [] or [0]
if i == 0 and nums[i] == 0:
dp[i][0] = 2
elif i == 0:
dp[i][0] = 1
# [] or [0] from previous
elif nums[i] == 0:
dp[i][0] = 2 * dp[i-1][0]
else: # empty set only
dp[i][0] = dp[i - 1][0]
This way, the first value is set to either 2 or 1 depending on whether or not it's zero, and nonzero values later in the list don't reset the value to 1. This outputs 50 in your sample case.
You can also remove room for error by giving simpler initial conditions:
def findTargetSumWays(nums, S):
"""
:type nums: List[int]
:type S: int
:rtype: int
"""
if (sum(nums) + S) % 2 == 1 or sum(nums) < S:
return 0
ssum = (sum(nums) + S) // 2
dp = [[0 for _ in range(ssum + 1)] for _ in range(len(nums) + 1)]
# col == 0
dp[0][0] = 1
for i in range(len(nums)):
for s in range(ssum + 1):
dp[i + 1][s] = dp[i][s]
if s >= nums[i]:
dp[i + 1][s] += dp[i][s - nums[i]]
return dp[len(nums)][ssum]
This adds an additional row to represent the state before you add any numbers (just a 1 in the top left corner), and it runs your algorithm on the rest of the rows. You don't need to initialize anything else or treat zeros differently, and this way it should be easier to reason about the code.
The issue with your function is related to the way you manage zero values in the list. Perhaps a simpler way for you to handle the zero values would be to exclude them from the process and then multiply your resulting count by 2**Z where Z is the number of zero values.
While trying to find the problem, I did a bit of simplification on your code and ended up with this: (which gives the right answer, even with zeroes in the list).
ssum = (sum(nums) + S) // 2
dp = [1]+[0]*ssum # number of sets that produce each sum from 0 to ssum
for num in nums:
for s in reversed(range(num,ssum + 1)):
dp[s] += dp[s-num]
return dp[ssum]
What I did was:
Eliminate a dimension in dp because you don't need to keep all the previous set counts. Only the current and next one. Actually it can work using only the current set counts if you process the sum values backwards from ssum down to zero (which i did).
The condition s >= nums[i]was eliminated by starting the s range from the current num value so that the index s - num can never be negative.
With that done, there was no need for an index on nums, I could simply go through the values directly.
Then I got rid of all the special conditions on zero values by initializing dp with 1 for the zero sum (i.e. initially an empty set is the one solution to obtain a sum of zero, then increments proceed from there).
Starting with the empty set baseline allows the progressive accumulation of set counts to produce the right result for all values without requiring any special treatment of zeroes. When num is zero it will naturally double all the current set counts because dp[s] += dp[s-0] is the same as dp[s] = 2 * dp[s]. If the list starts out with a zero then the set count for a sum of zero (dp[0]) will be doubled and all subsequent num values will have a larger starting count (because they start out from the dp[0] value initialized with 1 for the empty set).
With that last change, the function started to give the right result.
My assertion is that, because your solution was not starting from the "empty set" baseline, the zero handling logic was interfering with the natural progression of set counts. I didn't try to fine tune the zero conditions because they weren't needed and it seemed pointless to get them to arrive at the same states that a mere initialization "one step earlier" would produce
From there, the logic can be further optimized by avoiding assignments do dp[s] outside the range of minimum and maximum possible sums (which "slides" forward as we progress through the nums list):
ssum = (sum(nums) + S) // 2
dp = [1]+[0]*ssum
maxSum = 0
minSum = S - ssum # equivalent to: ssum - sum(nums)
for num in nums:
maxSum += num
minSum += num
for s in reversed(range(max(num,minSum),min(ssum,maxSum)+1)):
dp[s] += dp[s-num]
return dp[ssum]
The question is from here https://leetcode.com/problems/contiguous-array/
Actually, I came up with a DP solution for this question.
However, It won't pass one test case.
Any thought?
DP[i][j] ==1 meaning from substring[i] to substring[j] is valid
Divide the question into smaller
DP[i][j]==1
- if DP[i+2][j]==1 and DP[i][i+1]==1
- else if DP[i][j-2]==1 and DP[j-1][j]==1
- else if num[i],num[j] == set([0,1]) and DP[i+1][j-1]==1
```
current_max_len = 0
if not nums:
return current_max_len
dp = [] * len(nums)
for _ in range(len(nums)):
dp.append([None] * len(nums))
for thisLen in range(2, len(nums)+1, 2):
for i in range(len(nums)):
last_index = i + thisLen -1
if i + thisLen > len(nums):
continue
if thisLen==2:
if set(nums[i:i+2]) == set([0, 1]):
dp[i][last_index] = 1
elif dp[i][last_index-2] and dp[last_index-1][last_index]:
dp[i][last_index] = 1
elif dp[i][i + 1] and dp[i + 2][last_index]:
dp[i][last_index] = 1
elif dp[i + 1][last_index-1] and set([nums[i], nums[last_index]]) == set([0, 1]):
dp[i][last_index] = 1
else:
dp[i][last_index] = 0
if dp[i][last_index] == 1:
current_max_len = max(current_max_len, thisLen)
return current_max_len
```
Here is a counter example [1, 1, 0, 0, 0, 0, 1, 1]. The problem with you solution that it requires a list to be composed of smaller valid lists of size n-1 or n-2 in this counter example it's two lists of length 4 or n-2 . -- SPOILER ALERT -- You can solve the problem by using other dp technique basically for every i,j you can find the number of ones and zeroes between them in constant time to do that just store the number of ones from the start of the list to every index i
here is python code
def func( nums):
track,has=0,{0:-1}
length=len(nums);
ress_max=0;
for i in range(0,length):
track += (1 if nums[i]==1 else -1)
if track not in has:
has[track]=i
elif ress_max <i-has[track]:
ress_max = i-has[track]
return ress_max
l = list(map(int,input().strip().split()))
print(func(l))
Since given length of binary string may be at most 50000. So, running O(n * n) algorithm may lead to time limit exceed. I would like to suggest you to solve it in O(n) time and space complexity. The idea is :
If we take any valid contiguous sub-sequence and perform summation of numbers treating 0 as -1 then, total summation should be zero always.
If we keep track of prefix summation then we can get zero summation in the range L to R, if prefix summation up to L - 1 and prefix summation up to R are equal.
Since we are looking for maximum length, we will always treat index of newly found summation as a first one and put it into hash map with value as current index and which will persist forever for that particular summation.
Every time we calculate cumulative summation, we look whether it has any previous occurrence. If it has previous occurrence we calculate length and try to maximize , otherwise it will be the first one and will persist forever in hash map with value as current index.
Note: To calculate pure prefix, we must treat summation 0 is already in map and paired with value -1 as index.
The sample code in C++ is as follow:
int findMaxLength(vector<int>& nums) {
unordered_map<int,int>lastIndex;
lastIndex[0] = -1;
int cumulativeSum = 0;
int maxLen = 0;
for (int i = 0; i < nums.size(); ++i) {
cumulativeSum += (nums[i] == 0 ? -1 : 1);
if (lastIndex.find(cumulativeSum) != lastIndex.end()) {
maxLen = max(maxLen, i - lastIndex[cumulativeSum]);
} else {
lastIndex[cumulativeSum] = i;
}
}
return maxLen;
}
I have a problem where I need to (pretty sure at least) go through the entire list to solve. The question is to figure out the largest number of consecutive numbers in a list that add up to another (greater) element in that list. If there aren't any then we just take the largest value in the list as the candidate summation and 1 as the largest consecutive number of elements.
My general code works, but not too well for large lists (>500,000 elements). I am just looking for tips as to how I could approach the problem differently. My current approach:
L = [1,2,3,4,5,6,7,8,9,10]
candidate_sum = L[-1]
largest_count = 1
N = len(L)
i = 0
while i < N - 1:
s = L[i]
j = 0
while s <= (N - L[i + j + 1]):
j += 1
s += L[i+j]
if s in L and (j+1) > largest_count:
largest_count = j+1
candidate_sum = s
i+=1
In this case, the answer would be [1,2,3,4] as they add up to 10 and the length is 4 (obviously this example L is a very simple example).
I then made it faster by changing the initial while loop condition to:
while i < (N-1)/largest_count
Not a great assumption, but basic thinking that the distribution of numbers is somewhat uniform, so two numbers on the second half of the list are on average bigger than the final number in the list, and therefore are disqualified.
I'm just looking for:
possible bottlenecks
suggestions as to different approaches to try
Strictly ascending: no duplication of elements or subsequences, single possible solution
Arbitrary-spaced: no arithmetical shortcuts, has to operate brute-force
Efficient C implementation using pointer arithmetic, quasi polymorphic over numeric types:
#define TYPE int
int max_subsum(TYPE arr [], int size) {
int max_length = 1;
TYPE arr_fst = * arr;
TYPE* num_ptr = arr;
while (size --) {
TYPE num = * num_ptr++;
TYPE* lower = arr;
TYPE* upper = arr;
TYPE sum = arr_fst;
int length = 1;
for (;;) {
if (sum > num) {
sum -= * lower++;
-- length;
}
else if (sum < num) {
sum += * ++upper;
++ length;
}
else {
if (length > max_length) {
max_length = length;
}
break;
}
}
}
return max_length;
}
The main loop over the nums is parallelizable. Relatively straight-forward translation into Python 3 using the dynamic-array list type for arr and the for each loop:
def max_subsum(arr):
max_len = 1
arr_fst = arr[0]
for n in arr:
lower = 0
upper = 0
sum = arr_fst
while True:
if sum > n:
sum -= arr[lower]
lower += 1
elif sum < n:
upper += 1
sum += arr[upper]
else:
sum_len = upper - lower + 1
if sum_len > max_len:
max_len = sum_len
break
return max_len
This max_subsum is a partial function; Python lists can be empty. The algorithm is appropriate for C-like compiled imperative languages offering fast indexing and statically typed arithmetic. Both are comparatively expensive in Python. A (totally defined) algorithm rather similar to yours, using the set data type for more performant universal quantification, and avoiding Python's dynamically typed arithmetic, can be more efficiently interpreted:
def max_subsum(arr):
size = len(arr)
max_len = 0
arr_set = set(arr)
for i in range(size):
sum = 0
sum_len = 0
for j in range(i, size):
sum_mem = sum + arr[j]
if num_mem not in arr_set:
break
sum = sum_mem
sum_len += 1
if sum_len > max_len:
max_len = sum_len
return max_len
I'm going to ignore the possibility of a changing target value, and let you figure that out, but to answer your question "is there a faster way to do it?" Yes: by using cumulative sums and some math to eliminate one of your loops.
import numpy as np
L = np.random.randint(0,100,100)
L.sort()
cum_sum = np.cumsum(L)
start = 0
end = 0
target = 200
while 1:
total = cum_sum [end-1] - (cum_sum [start-1] if start else 0)
if total == target:
break
elif total < target:
end += 1
elif total > target:
start += 1
if end >= len(L):
raise ValueError('something informative')
l = [[i, i, 1] for i in range(1,1000000)]
def collatz(li):
for el in li:
if el[1] == 1:
li.remove(el)
elif el[1] % 2 == 0:
el[1] = el[1] / 2
el[2] += 1
elif el[1] % 2 == 1:
el[1] = 3*el[1] + 1
el[2] += 1
return li
while len(collatz(l)) >= 2:
l = collatz(l)
print l
Hi, this is a (partial) solution to Euler problem 14, written in Python.
Longest Collatz sequence
Problem 14
The following iterative sequence is defined for the set of positive integers:
n → n/2 (n is even)
n → 3n + 1 (n is odd)
Using the rule above and starting with 13, we generate the following sequence:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.
Which starting number, under one million, produces the longest chain?
NOTE: Once the chain starts the terms are allowed to go above one million.
I wrote partial because it does not really output the solution since I can't really run it in the whole 1 - 1000000 range. It's way too slow - taking more than 20 minutes the last time I killed the process. I have barely just started with python and programming in general (about 2 weeks) and I am looking to understand what's the obvious mistake I am making in terms of efficiency. I googled some solutions and even the average ones are orders of magnitude faster than mine. So what am I missing here? Any pointers to literature to avoid making the same mistakes in the future?
a little improvement upon sara's answer
import time
start = time.time()
def collatz(n):
k = n
length = 1
nList = []
nList.append(n)
while n != 1:
if n not in dic:
n = collatzRule(n)
nList.append(n)
length += 1
else:
# we dont need the values but we do need the real length for the for-loop
nList.extend([None for _ in range(dic[n] - 1)])
length = (length - 1) + dic[n]
break
for seq in nList:
if seq not in dic:
dic[seq] = len(nList) - nList.index(seq)
return length
def collatzRule(n):
if n % 2 == 0:
return n // 2
else:
return 3 * n + 1
longestLen = 0
longestNum = 0
dic = {}
for n in range(2, 1000001):
prsntLen = collatz(n)
if prsntLen > longestLen:
longestLen = prsntLen
longestNum = n
# print(f'{n}: {prsntLen}')
print(f'The starting num is: {longestNum} with the longest chain having: {longestLen} terms.')
print(f'time taken: {time.time() - start}')
Sara's answer is great, but can be more efficient.
If the value we return from the function is len(seq), why not just counting the number of iterations instead of conducting a list first?
I have changed the code slightly, and the performance improvement is significant
def collatz(x):
count = 1
temp = x
while temp > 1:
if temp % 2 == 0:
temp = int(temp/2)
if temp in has2: # calculate temp and check if in cache
count += has2[temp]
break
else:
count += 1
else:
temp = 3*temp + 1
if temp in has2:
count += has2[temp]
break
else:
count += 1
has2[x] = count
return count
837799 has 525 elements. calculation time =1.97099995613 seconds.
Compared to the original version
837799 has 525 elements. calculation time =11.3389999866 seconds.
Using list of int rather than building the whole list is ~80% faster.
the problem is you use brute force algorithm that is inefficient.this is my solution to problem 14 from project Euler. it takes a few second to run. the key is you should save previous results in a dictionary so you don't have to compute those results again.:
#problem 14 project euler
import time
start=time.time()
has2={}
def collatz(x):
seq=[]
seq.append(x)
temp=x
while(temp>1):
if temp%2==0:
temp=int(temp/2)
if temp in has2:
seq+=has2[temp]
break
else:
seq.append(temp)
else:
temp=3*temp+1
if temp in has2:
seq+=has2[temp]
break
else:
seq.append(temp)
has2[x]=seq
return len(seq)
num=0
greatest=0
for i in range(1000000):
c=collatz(i)
if num<c:
num=c
greatest=i
print('{0} has {1} elements. calculation time ={2} seconds.'.format(greatest,num,time.time()-start))
As #Sara says you could use dictionary to save previous results and then look them up for making program run faster. But I don't quite understand your results, taking more than 20 mins sounds like you have some problem.
By using bruteforce i get code to run about at 16 sec.
#!/bin/python3
########################
# Collatz Conjecture #
# Written by jeb 2015 #
########################
import time
current = 0
high = 0
# While number is not one, either divide it by 2
# or multiply with 3 and add one
# Returns number of iterations
def NonRecursiveCollatz(i):
counter = 1
while i != 1:
counter = counter + 1
if i%2 == 0:
i = i / 2
else:
i = 3*i + 1
return counter
time_start = time.time()
# Test all numbers between 1 and 1.000.000
# If number returned is higher than last one, store it nd remember
# what number we used as input to the function
for i in range(1,1000000):
current = NonRecursiveCollatz(i)
if current > high:
high = current
number = i
elapsed_time = time.time() - time_start
print "Highest chain"
print high
print "From number "
print number
print "Time taken "
print elapsed_time
With the output:
Highest chain
525
From number
837799
Time taken
16.730340004
//Longest Colletz Sequence
public class Problem14 {
static long getLength(long numb) {
long length = 0;
for(long i=numb; i>=1;) {
length++;
if(i==1)
break;
if(i%2==0)
i = i/2;
else
i = (3*i)+1;
}
return length;
}
static void solution(long numb) {
long number = numb;
long maxLength = getLength(number);
for(long i=numb; i>=1; i--) {
if(getLength(i)>=maxLength) {
maxLength = getLength(i);
number = i;
}
}
System.out.println("`enter code here`Length of "+number+" is : "+maxLength);
}
public static void main(String args[]) {
long begin = System.currentTimeMillis();
solution(1000000);
long end = System.currentTimeMillis();
System.out.println("Time : "+(end-begin));
}
}
output :
Length of 837799 is : 525
Time : 502
Can somebody tell me why this should be wrong?
#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, ...
#Find the sum of all the even-valued terms in the sequence
#which do not exceed four million.
sum=2
list = [1,2]
for x in range(2,100):
a = list[x-2]+list[x-1]
print(a)
list.append(a)
if a % 2 == 0:
sum += a
print('sum', sum)
if sum >= 4000000:
break
Here's a completely different way to solve the problem using a generator and itertools:
def fib():
a = b = 1
while 1:
yield a
a, b = b, a + b
import itertools
print sum(n for n in itertools.takewhile(
lambda x: x <= 4000000, fib()) if n % 2 == 0)
Output:
4613732
So your code, even though it is wrong (see other answers), happens to give the correct answer.
replace
sum += a
print('sum', sum)
if sum >= 4000000:
break
with
if a > 4000000:
break
sum += a
print('sum', sum)
You should compare "a" with 4000000, not "sum", like Daniel Roseman said.
The question asked for the sum of even terms which do not exceed four million. You're checking if the sum doesn't exceed 4m.
I'm trying to solve the same problem - although I understand the logic to do it, I don't understand why this works (outputs the right sum)
limit = 4000000
s = 0
l = [1,2]
while l[-1]<limit:
n = l[-1]+l[-2]
l.append(n)
print n
And then then moment I put in the modulo function, it doesn't output anything at all anymore.
limit = 4000000
s = 0
l = [1,2]
while l[-1]<limit:
n = l[-1]+l[-2]
if n % 2 == 0 :
l.append(n)
print n
I'm sure this is fairly simple...thanks!
This is the code I used. It is very helpful and teaches you about generators.
def fib():
x,y = 0,1
while True:
yield x
x,y = y, x+y
def even(seq):
for number in seq:
if not number % 2:
yield number
def under_a_million(seq):
for number in seq:
if number > 4000000:
break
yield number
print sum(even(under_a_million(fib())))
-M1K3
Keep it simple and it should take you less than 0.1 seconds.
from datetime import datetime
x, y = 1, 1
total = 0
for i in xrange (1, 100):
x = x + y
if x % 2 == 0 and x <= 4000000:
total += x
y = y + x
if y % 2 == 0 and x <= 4000000:
total += y
print total
starttime = datetime.now()
print datetime.now() - starttime