My code is showing bellow
import math,sys
#create a list with numbers
def create_list():
num_list=[]
for num in range(int(input("insert start point: ")),int(input("Insert end point: "))):
num_list.append(num)
return num_list
#function to find triangular numbers
def get_triangles(numlist):
triangles = []
for i in numlist:
if (check_triangle(i)):
triangles.append(i)
return triangles
#function to check number is triangular or not
def check_triangle(n):
return math.sqrt((8*n)+1).is_integer()
#function main to run the process
def main():
numlist = create_list()
print(get_triangles(numlist))
Even though it seems like the task is completed it was not. I tried it with the range of 0 - 100000000(1*10^8) numbers . it is cause to stuck my laptop any method that can complete this task ?
DO NOT PRINT A LIST THAT LARGE. Instead write it to a file, that way you can open the file afterward. The program can't efficiently write that much information into the console. I find that printing stuff to the console makes a programs a ton less efficient.
Additionally, I read some of the comments on your code and they state it isn't efficient and I would have to concur.
Here is piece of code I wrote up. It takes a bit of interpretation, but I was in a hurry. Just reply if you need help understanding it.
def getTriangles(input1,input2): #input1 is the min value and input2 is the max value
li = [] #the list where all of the numbers will go
i = 0 #an integer that acts how much another layer of the triangle would have
j = 0 #the most current number that it is on
while True: #I whipped up this algorithm in a couple minutes, so there is probably a more efficient way than just looping through all of them, but it is faster than the current one being used
i += 1 #i has to increment to act as the increase of a side
if j > input2: #if the value that could be added is greater than the max number, than just end the function and return the list
return li
if j >= input1: #if the number qualifies the minimum number requirements, then the program will add it to the list, otherwise it will ignore it and continue on with the function
li.append(j)
j += i #this simulates adding in another layer of the triangle to the bottom
This would be a way to use it:
print(getTriangles(1,45))
I trust you can look up how to write content to a file.
It appears that you are just trying to generate all triangle numbers within a range. If this is so, computing them directly is substantially quicker than checking via square root.
Note that you can generate triangular numbers by simply adding consecutive numbers.
T_0 = 0
T_1 = T_0 + 1 = 1
T_2 = T_1 + 2 = 3
T_3 = T_2 + 3 = 6
...
If you want to keep it simple, you can create a function to keep generating these numbers from n = 0, keeping them when they enter the desired range, and continue until it exceeds the upper bound.
def generate_triangular_numbers(a, b):
"""Generates the triangular numbers in [a, b] (inclusive)"""
n, t = 0, 0
triangles = []
while t < a:
n += 1
t += n
while t <= b:
triangles.append(t)
n += 1
t += n
return triangles
Related
I have tried this following code and it takes a lot of time when I set lower = 0 and upper = 10000
def sumPdivisors(n):
'''This function returns the sum of proper divisors of a number'''
lst = []
for i in range(1,n//2+1):
if n%i == 0:
lst.append(i)
return(sum(lst))
lower = int(input("Enter the lower value of range: "))
upper = int(input("Enter the upper value of range: "))
lst = []
for i in range(lower, upper+1):
if i == 0:
continue
else:
for j in range(i, upper):
if i!=j and sumPdivisors(i) == j and sumPdivisors(j) == i:
lst.append((i,j))
break
print(lst)
There are two things that you could do here.
Memoization
There's already a great explanation of what memoization is elsewhere on this site [link], but here's how it's relevant to your problem:
sumPdivisors is called very frequently in the for-loop at the bottom of your code snippet. For really large inputs n, it will take a long time to run.
sumPdivisors is called with the same input n multiple times.
You can speed things up by saving the result of calling sumPdivisors on different inputs somehow, like in a dictionary that maps integers to the resulting output when you call sumPdivisors with that corresponding integer. This is kind of what memoization is. You're precomputing the possible outputs of sumPdivisors and storing them for later. Read the link for a more in-depth explanation.
Don't add the numbers in sumPdivisors to a list
You can just add these numbers as you iterate instead of appending them to a list, then summing them. This change won't have as great of an impact as adding memoization to your code.
I am able to solve this problem up the the 'even' part but I'm getting stuck in the odd part.
You will be given an array of n numbers. Your task is to first reverse the array (first number becomes last, 2nd number becomes 2nd from the last and so on) and then print the sum of the numbers at even indices and print the product of the numbers at odd indices.
Input
First line contains single integer N: number of elements
followed by N different integers separated by spaces
Output
Two space separated integers representing sum of the numbers at even places and the product of the numbers at odd places.
My code so far:
n = int(input())
arr = [int(x) for x in input().split()]
arr.reverse()
for ele in arr:
print(ele, end=" ")
print()
sum = 0
count = 1
while count <= n:
if count % 2 == 0:
sum += count
count += 1
print(sum)
There's a couple of issues in the code you've supplied which I'll address first:
Firstly, you need to be clear about what is meant by odd and even indices. In some languages (Matlab) for example, the first element of an array is index position 1. In Python and Java it's 0, so, whilst your example has assumed 1, it probably should be 0 unless otherwise specified.
Second, in your line sum+=count you're summing the index positions, not the index values, so that isn't what your question is asking for.
Last point on your code is that you've used sum as a variable name. Whilst that works, sum is also a Python keyword and you should avoid using them as variable names as if you later want to use the sum function, you will get the error TypeError: 'int' object is not callable because you've redefined the sum function to be an integer.
To the answer:
Considering the above, this provides the answer to part 1 by fixing your code:
total = 0
count = 0
while count < n:
if count % 2 == 0:
total += arr[count]
count += 1
print(total)
It's worth noting that as you're looking for even numbers, you could better write that as:
total = 0
count = 0
while count < n:
total += arr[count]
count += 2
print(total)
However, there are even easier ways to do this in much less code, and they involve list slicing. You can slice a list by specifying [start: end: step], so arr[::2] specifies a start of position 0 (the default), an end of the end of the list the default) and a step of 2. This means that if arr contains [1,2,3,4,5,6], then arr[::2] will be [1,3,5] (i.e. the values at all of the even indices) or if you specify a start position of 1 i.e. arr[1::2] you will get [2,4,6] (i.e. the values at all of the even indices).
So, rather using a while loop. You could use a for loop over just the even values:
total = 0
for even_val in arr[::2]:
total += even_val
print(total)
but for sum you can even more easily write is as a simple sum command on the list slice:
print(sum(arr[::2]))
Before Python 3.8, there was no simple equivalent of sum for product, so if you're using a lower version, you can either reuse the method above, allowing for the fact that you would need to prime the total with the first value, then multiply from the next one, i.e.:
total = arr[1]
count = 3
while count < n:
total *= arr[count]
count += 2
print(total)
or with a for loop:
total = arr[1]
for odd_val in arr[3::2]:
total *= odd_val
print(total)
But from Python 3.8 (documentation here) you can now import prod from the math library which will work in the same way as sum:
from math import prod
print(prod(arr[1::2]))
[Thanks #HeapOverflow for the nudge]
As this is for a problem set, it may not be an issue as all examples may have an array length N > 2, but the examples above do assume that there will be at least two entries in arr. If that's not the case, you should put in some validation before trying to access arr[1]
Here's a cute little recursive function to do that (assuming one-based indices):
# def prodSum(increment,multiplier=1,*rest): if zero based indices
def prodSum(multiplier,increment=0,*rest):
if not rest: return multiplier,increment
product,total = prodSum(*rest)
return (product * multiplier, total + increment)
x = [1,2,3,4,5]
print(prodSum(*reversed(x))) # 15,6
I'm struggling with while looping.
I have a list with Widths (double or integer, doesn't matter - don't need precision).
Basically I need number of items that sum is lower than limit.
Now it finds only the first number.
I'm not able to adapt while loop, so it would start calculation over again with the rest of items.
This code give 6 as output, cause sum(100,300,30,100,50,80) < limit = 850.
The desired loop would do this:
1st iteration: start from 0 until sum meet limit: [100,300,30,100,50,80,400,120,500,75,180] -> give 6
2nd iteration: start from the next(last index from 1st run +1) item and iterate over the rest: 400,120,500,75,180 -> give 2
3rd: iterate over 500,75,180 -> give 3
Number of widths = unknown
if width > limit -> break the code
Widths = [100,300,30,100,50,80,400,120,500,75,180]
def items(nums,limit):
sum=0
for i in range(0,len(nums)):
sum += nums[i]
if sum>limit-1:
return i
print (items(Widths,850))
I'd like to have output like this:
[6,2,3]
a return immediately exits out of the function. You need to store instead of returning, and go from there.
I have also pointed out some comments in code as well that should help.
Widths = [100,300,30,100,50,80,400,120,500,75,180]
def items(nums,limit):
acc = 0 #do not use sum as a variable name. it "shadows" or hides the builtin function with same name
length = 0
result = []
for num in nums: #You do not really need indexes here, so you can directly iterate on items in nums list.
acc += num
if acc >= limit: #greater than or equal to.
result.append(length)
acc = num
length = 1
else:
length += 1
result.append(length) #if you need the last length even if it does not add up.
return result
print (items(Widths,850))
#Output:
[6, 2, 3]
I wrote a python function largestProduct(n) which returns the largest number made from product of two n-digit numbers. The code runs fine for n untill 3, but shows memory error for n>3. Is there a way I can improve my code to avoid this error?
def largestProduct(n):
number_lst = []
prod_lst = []
count = 0
for i in range(10**(n-1),(10**n)):
number_lst.append(i)
while count!= len(number_lst):
for i in range(len(number_lst)):
prod_lst.append(number_lst[count]*number_lst[i])
count +=1
prod_set = list(set(prod_lst))
return max(prod_lst)
Well, you don't need any storage to loop through what you need:
def largestProduct(n):
range_low = 10**(n-1)
range_high = 10**n
largest = 0
# replace xrange with range for Python 3.x
for i in xrange(range_low, range_high):
for j in xrange(range_low, range_high):
largest = max(largest, i*j)
return largest
But why would you want to do this? The largest product of two n-long numbers is always the largest number you can write with n digits squared, i.e.:
def largestProduct(n):
return (10**n-1)**2
You should consider creating a generator function. In the end you can iterate over the output of your function which only processes each element one by one instead of holding the whole list in memory.
see https://wiki.python.org/moin/Generators
Having trouble figuring out a nice way to get this task done.
Say i have a list of triangular numbers up to 1000 -> [0,1,3,6,10,15,..]etc
Given a number, I want to return the consecutive elements in that list that sum to that number.
i.e.
64 --> [15,21,28]
225 --> [105,120]
371 --> [36, 45, 55, 66, 78, 91]
if there's no consecutive numbers that add up to it, return an empty list.
882 --> [ ]
Note that the length of consecutive elements can be any number - 3,2,6 in the examples above.
The brute force way would iteratively check every possible consecutive pairing possibility for each element. (start at 0, look at the sum of [0,1], look at the sum of [0,1,3], etc until the sum is greater than the target number). But that's probably O(n*2) or maybe worse. Any way to do it better?
UPDATE:
Ok, so a friend of mine figured out a solution that works at O(n) (I think) and is pretty intuitively easy to follow. This might be similar (or the same) to Gabriel's answer, but it was just difficult for me to follow and I like that this solution is understandable even from a basic perspective. this is an interesting question, so I'll share her answer:
def findConsec(input1 = 7735):
list1 = range(1, 1001)
newlist = [reduce(lambda x,y: x+y,list1[0:i]) for i in list1]
curr = 0
end = 2
num = sum(newlist[curr:end])
while num != input1:
if num < input1:
num += newlist[end]
end += 1
elif num > input1:
num -= newlist[curr]
curr += 1
if curr == end:
return []
if num == input1:
return newlist[curr:end]
A 3-iteration max solution
Another solution would be to start from close where your number would be and walk forward from one position behind. For any number in the triangular list vec, their value can be defined by their index as:
vec[i] = sum(range(0,i+1))
The division between the looking-for sum value and the length of the group is the average of the group and, hence, lies within it, but may as well not exist in it.
Therefore, you can set the starting point for finding a group of n numbers whose sum matches a value val as the integer part of the division between them. As it may not be in the list, the position would be that which minimizes their difference.
# vec as np.ndarray -> the triangular or whatever-type series
# val as int -> sum of n elements you are looking after
# n as int -> number of elements to be summed
import numpy as np
def seq_index(vec,n,val):
index0 = np.argmin(abs(vec-(val/n)))-n/2-1 # covers odd and even n values
intsum = 0 # sum of which to keep track
count = 0 # counter
seq = [] # indices of vec that sum up to val
while count<=2: # walking forward from the initial guess of where the group begins or prior to it
intsum = sum(vec[(index0+count):(index0+count+n)])
if intsum == val:
seq.append(range(index0+count,index0+count+n))
count += 1
return seq
# Example
vec = []
for i in range(0,100):
vec.append(sum(range(0,i))) # build your triangular series from i = 0 (0) to i = 99 (whose sum equals 4950)
vec = np.array(vec) # convert to numpy to make it easier to query ranges
# looking for a value that belong to the interval 0-4590
indices = seq_index(vec,3,4)
# print indices
print indices[0]
print vec[indices]
print sum(vec[indices])
Returns
print indices[0] -> [1, 2, 3]
print vec[indices] -> [0 1 3]
print sum(vec[indices]) -> 4 (which we were looking for)
This seems like an algorithm question rather than a question on how to do it in python.
Thinking backwards I would copy the list and use it in a similar way to the Sieve of Eratosthenes. I would not consider the numbers that are greater than x. Then start from the greatest number and sum backwards. Then if I get greater than x, subtract the greatest number (exclude it from the solution) and continue to sum backward.
This seems the most efficient way to me and actually is O(n) - you never go back (or forward in this backward algorithm), except when you subtract or remove the biggest element, which doesn't need accessing the list again - just a temp var.
To answer Dunes question:
Yes, there is a reason - to subtracts the next largest in case of no-solution that sums larger. Going from the first element, hit a no-solution would require access to the list again or to the temporary solution list to subtract a set of elements that sum greater than the next element to sum. You risk to increase the complexity by accessing more elements.
To improve efficiency in the cases where an eventual solution is at the beginning of the sequence you can search for the smaller and larger pair using binary search. Once a pair of 2 elements, smaller than x is found then you can sum the pair and if it sums larger than x you go left, otherwise you go right. This search has logarithmic complexity in theory. In practice complexity is not what it is in theory and you can do whatever you like :)
You should pick the first three elements, sum them and do and then you keep subtracting the first of the three and add the next element in the list and see if the sum add up to whatever number you want. That would be O(n).
# vec as np.ndarray
import numpy as np
itsum = sum(list[0:2]) # the sum you want to iterate and check its value
sequence = [[] if itsum == whatever else [range(0,3)]] # indices of the list that add up to whatever (creation)
for i in range(3,len(vec)):
itsum -= vec[i-3]
itsum += vec[i]
if itsum == whatever:
sequence.append(range(i-2,i+1)) # list of sequences that add up to whatever
The solution you provide in the question isn't truly O(n) time complexity -- the way you compute your triangle numbers makes the computation O(n2). The list comprehension throws away the previous work that want into calculating the last triangle number. That is: tni = tni-1 + i (where tn is a triangle number). Since you also, store the triangle numbers in a list, your space complexity is not constant, but related to the size of the number you are looking for. Below is an identical algorithm, but is O(n) time complexity and O(1) space complexity (written for python 3).
# for python 2, replace things like `highest = next(high)` with `highest = high.next()`
from itertools import count, takewhile, accumulate
def find(to_find):
# next(low) == lowest number in total
# next(high) == highest number not in total
low = accumulate(count(1)) # generator of triangle numbers
high = accumulate(count(1))
total = highest = next(high)
# highest = highest number in the sequence that sums to total
# definitely can't find solution if the highest number in the sum is greater than to_find
while highest <= to_find:
# found a solution
if total == to_find:
# keep taking numbers from the low iterator until we find the highest number in the sum
return list(takewhile(lambda x: x <= highest, low))
elif total < to_find:
# add the next highest triangle number not in the sum
highest = next(high)
total += highest
else: # if total > to_find
# subtract the lowest triangle number in the sum
total -= next(low)
return []