I wrote this program which outputs pythagorean triplet whose sum is a certain number(this would be the parameter). The program runs perfectly but the same triplet is appearing multiple times and I want one triplet to appear just once. I was wondering if someone could help me out. Thanks!
def pythagoreanCheck(tripletList):
'''
Checks whether the three numbers are pythagorean triplet
returns True or False
'''
trip_list = [0,1,2]
if tripletList[0]**2 + tripletList[1]**2 == tripletList[2]**2:
return True
else:
return False
def givMeSum(target):
'''
returns 3 numbers such that their sum is equal to target
'''
listOfa = xrange(1,target)
listOfb = xrange(1,target)
listOfc = xrange(1,target)
for i in listOfa:
for j in listOfb:
for k in listOfc:
add = i + j + k
if add == target:
add_list = [i,j,k]
add_list.sort()
value = pythagoreanCheck(add_list)
if value:
print add_list
def main():
givMeSum(12)
main()
It's because you're doing your calculations in a nested list and then creating a sorted list of 3 different permutations of the same numbers.
Since i, j, and k will enter different combinations of the same three numbers 3 times, add will equal target each time, which means that add_list is created and sorted 3 times. Which means that it will create the same list 3 times.
I think that you should just take out
add_list.sort()
And Siddharth is right, your algorithm is really inefficient. You're turning it into an O(n^3) algorithm, which could take a really long time with larger target numbers.
Consider storing each tuple in a hash table (dictionary)instead of printing it within the innermost loop. At the end of all the loops completion, print all the values in the hash.
Aside from your question, you can make the algo faster by creating a hash of integers and replace the innermost loop with a hash search.
You need to make sure that i <= j <= k:
def pythagoreanCheck(tripletList):
'''
Checks whether the three numbers are pythagorean triplet
returns True or False
'''
a, b, c = tripletList
return a**2 + b**2 == c**2
def givMeSum(target):
'''
returns 3 numbers such that their sum is equal to target
'''
for i in xrange(1, target):
for j in xrange(i, target): # j >= i
for k in xrange(j, target): # k >= j
if i + j + k == target:
add_list = [i, j, k] # no need to sort any more
if pythagoreanCheck(add_list):
print add_list
def main():
givMeSum(12)
main()
As noted, this algorithm is far from optimal, but this will at least solve the problem you're seeing.
Here's a slightly better way (two nested loops instead of three):
def giveMeSum(target):
'''
returns 3 numbers such that their sum is equal to target
'''
for i in xrange(1, target):
for j in xrange(i, target):
k = target - i - j
if k < j:
break # skip to the next value of i - all remaining js are too big
add_list = [i, j, k]
if pythagoreanCheck(add_list):
print add_list
Related
I was trying an online test. the test asked to write a function that given a list of up to 100000 integers whose range is 1 to 100000, would find the first missing integer.
for example, if the list is [1,4,5,2] the output should be 3.
I iterated over the list as follow
def find_missing(num)
for i in range(1, 100001):
if i not in num:
return i
the feedback I receives is the code is not efficient in handling big lists.
I am quite new and I couldnot find an answer, how can I iterate more efficiently?
The first improvement would be to make yours linear by using a set for the repeated membership test:
def find_missing(nums)
s = set(nums)
for i in range(1, 100001):
if i not in s:
return i
Given how C-optimized python sorting is, you could also do sth like:
def find_missing(nums)
s = sorted(set(nums))
return next(i for i, n in enumerate(s, 1) if i != n)
But both of these are fairly space inefficient as they create a new collection. You can avoid that with an in-place sort:
from itertools import groupby
def find_missing(nums):
nums.sort() # in-place
return next(i for i, (k, _) in enumerate(groupby(nums), 1) if i != k)
For any range of numbers, the sum is given by Gauss's formula:
# sum of all numbers up to and including nums[-1] minus
# sum of all numbers up to but not including nums[-1]
expected = nums[-1] * (nums[-1] + 1) // 2 - nums[0] * (nums[0] - 1) // 2
If a number is missing, the actual sum will be
actual = sum(nums)
The difference is the missing number:
result = expected - actual
This compulation is O(n), which is as efficient as you can get. expected is an O(1) computation, while actual has to actually add up the elements.
A somewhat slower but similar complexity approach would be to step along the sequence in lockstep with either a range or itertools.count:
for a, e in zip(nums, range(nums[0], len(nums) + nums[0])):
if a != e:
return e # or break if not in a function
Notice the difference between a single comparison a != e, vs a linear containment check like e in nums, which has to iterate on average through half of nums to get the answer.
You can use Counter to count every occurrence of your list. The minimum number with occurrence 0 will be your output. For example:
from collections import Counter
def find_missing():
count = Counter(your_list)
keys = count.keys() #list of every element in increasing order
main_list = list(range(1:100000)) #the list of values from 1 to 100k
missing_numbers = list(set(main_list) - set(keys))
your_output = min(missing_numbers)
return your_output
I cannot pass the private cases my school provided. They say "Does your code work with other kind of sequence?"Can anybody help me to figure it out?
Write the function triplets(seq, R) which takes in a sequence of resistor seq as well as the value you need to find and returns a sequence of exactly three resistors that sums up to the required value R if there is such a solution. Otherwise returns None. You can assume that the input sequence contains only integers (int) sorted in ascending order.
def triplets(seq, R):
i=0
check=0
list1=[]
while len(seq)>=3:
i=seq[0]
seq.pop(0)
check=R-i
for m, j in enumerate(seq):
k = m+1
if seq[k:].count(check - j) > 0:
for n in range(seq[k:].count(check - j)):
b = seq.index(check - j, k)
list1.append((i,seq[m],seq[b]))
k = b+1
if len(list1)==0:
return None
else:
return min(list1)
I need to write a function that given a list of integers L, it returns True if the list contains a consecutive sequence of values whose sum is n, and False otherwise.
Let's say my list is: L = [2,2,4,4,0,0,2,8] and n = 3.
The function should return False because there are not consecutive values summing up to 3.
requirement: Python's modules are not allowed
I tried with:
def consecutive(L,n):
for i in range(len(L)):
for j in range(i+1, len(L)):
if sum(L[i:j+1])==n:
return True
return False
L = [2,2,4,4,0,0,2,8]
consecutive(L,3)
This is partially working because when I set n=12, it returns True. I understand there is something to fix with slicing, but I can't find out what it is.
The main problem is simple: in this situation, the range must be len+1, otherwise it will fail in fringe cases. Working code is:
def consecutive(L, n):
for i in range(len(L)+1):
for j in range(i+1,len(L)+1):
s=sum(L[i:j])
if s == n:
print(i,j,s,'TRUE') #DEBUG: remove when done
#return True #uncomment this to reintegrate
else: print(i,j,s) #DEBUG: remove when done
return False
L = [2,2,4,4,0,0,2,-3]
consecutive(L,3)
better yet, in your example, you didn't show negative numbers. If you have no negatives, you can make the code more efficient by skipping the loop when it exceeds your search value, n:
def consecutive(L, n):
for i in range(len(L)+1):
for j in range(i+1,len(L)+1):
s=sum(L[i:j])
if s == n:
print(i,j,s,'TRUE') #DEBUG: remove when done
#return True #uncomment
elif s > n:
print(i,j,s,'too big') #DEBUG: remove when done
break
else: print(i,j,s) #DEBUG: remove when done
return False
L = [2,2,4,4,0,0,2,1]
consecutive(L,3)
The naive way would be to loop through each starting potential starting point (each index) and each window size (any number from 0 to the length of the list):
def consecutive(L, n):
for i in range(len(L)):
for window_size in range(len(L)):
if sum(L[i:i + window_size]) == n:
return True
else:
return False
Note this could easily be improved, starting with not double checking the same windows multiple times (e.g., if the list is length 3, then L[2:4] and L[2:3] would be the same thing).
Given a set of integers 1,2, and 3, find the number of ways that these can add up to n. (The order matters, i.e. say n is 5. 1+2+1+1 and 2+1+1+1 are two distinct solutions)
My solution involves splitting n into a list of 1s so if n = 5, A = [1,1,1,1,1]. And I will generate more sublists recursively from each list by adding adjacent numbers. So A will generate 4 more lists: [2,1,1,1], [1,2,1,1], [1,1,2,1],[1,1,1,2], and each of these lists will generate further sublists until it reaches a terminating case like [3,2] or [2,3]
Here is my proposed solution (in Python)
ways = []
def check_terminating(A,n):
# check for terminating case
for i in range(len(A)-1):
if A[i] + A[i+1] <= 3:
return False # means still can compute
return True
def count_ways(n,A=[]):
if A in ways:
# check if alr computed if yes then don't compute
return True
if A not in ways: # check for duplicates
ways.append(A) # global ways
if check_terminating(A,n):
return True # end of the tree
for i in range(len(A)-1):
# for each index i,
# combine with the next element and form a new list
total = A[i] + A[i+1]
print(total)
if total <= 3:
# form new list and compute
newA = A[:i] + [total] + A[i+2:]
count_ways(A,newA)
# recursive call
# main
n = 5
A = [1 for _ in range(n)]
count_ways(5,A)
print("No. of ways for n = {} is {}".format(n,len(ways)))
May I know if I'm on the right track, and if so, is there any way to make this code more efficient?
Please note that this is not a coin change problem. In coin change, order of occurrence is not important. In my problem, 1+2+1+1 is different from 1+1+1+2 but in coin change, both are same. Please don't post coin change solutions for this answer.
Edit: My code is working but I would like to know if there are better solutions. Thank you for all your help :)
The recurrence relation is F(n+3)=F(n+2)+F(n+1)+F(n) with F(0)=1, F(-1)=F(-2)=0. These are the tribonacci numbers (a variant of the Fibonacci numbers):
It's possible to write an easy O(n) solution:
def count_ways(n):
a, b, c = 1, 0, 0
for _ in xrange(n):
a, b, c = a+b+c, a, b
return a
It's harder, but possible to compute the result in relatively few arithmetic operations:
def count_ways(n):
A = 3**(n+3)
P = A**3-A**2-A-1
return pow(A, n+3, P) % A
for i in xrange(20):
print i, count_ways(i)
The idea that you describe sounds right. It is easy to write a recursive function that produces the correct answer..slowly.
You can then make it faster by memoizing the answer. Just keep a dictionary of answers that you've already calculated. In your recursive function look at whether you have a precalculated answer. If so, return it. If not, calculate it, save that answer in the dictionary, then return the answer.
That version should run quickly.
An O(n) method is possible:
def countways(n):
A=[1,1,2]
while len(A)<=n:
A.append(A[-1]+A[-2]+A[-3])
return A[n]
The idea is that we can work out how many ways of making a sequence with n by considering each choice (1,2,3) for the last partition size.
e.g. to count choices for (1,1,1,1) consider:
choices for (1,1,1) followed by a 1
choices for (1,1) followed by a 2
choices for (1) followed by a 3
If you need the results (instead of just the count) you can adapt this approach as follows:
cache = {}
def countwaysb(n):
if n < 0:
return []
if n == 0:
return [[]]
if n in cache:
return cache[n]
A = []
for last in range(1,4):
for B in countwaysb(n-last):
A.append(B+[last])
cache[n] = A
return A
I've been working on some quick and dirty scripts for doing some of my chemistry homework, and one of them iterates through lists of a constant length where all the elements sum to a given constant. For each, I check if they meet some additional criteria and tack them on to another list.
I figured out a way to meet the sum criteria, but it looks horrendous, and I'm sure there's some type of teachable moment here:
# iterate through all 11-element lists where the elements sum to 8.
for a in range(8+1):
for b in range(8-a+1):
for c in range(8-a-b+1):
for d in range(8-a-b-c+1):
for e in range(8-a-b-c-d+1):
for f in range(8-a-b-c-d-e+1):
for g in range(8-a-b-c-d-e-f+1):
for h in range(8-a-b-c-d-e-f-g+1):
for i in range(8-a-b-c-d-e-f-g-h+1):
for j in range(8-a-b-c-d-e-f-g-h-i+1):
k = 8-(a+b+c+d+e+f+g+h+i+j)
x = [a,b,c,d,e,f,g,h,i,j,k]
# see if x works for what I want
Here's a recursive generator that yields the lists in lexicographic order. Leaving exact as True gives the requested result where every sum==limit; setting exact to False gives all lists with 0 <= sum <= limit. The recursion takes advantage of this option to produce the intermediate results.
def lists_with_sum(length, limit, exact=True):
if length:
for l in lists_with_sum(length-1, limit, False):
gap = limit-sum(l)
for i in range(gap if exact else 0, gap+1):
yield l + [i]
else:
yield []
Generic, recursive solution:
def get_lists_with_sum(length, my_sum):
if my_sum == 0:
return [[0 for _ in range(length)]]
if not length:
return [[]]
elif length == 1:
return [[my_sum]]
else:
lists = []
for i in range(my_sum+1):
rest = my_sum - i
sublists = get_lists_with_sum(length-1, rest)
for sl in sublists:
sl.insert(0, i)
lists.append(sl)
return lists
print get_lists_with_sum(11, 8)