Finding all numbers that evenly divide a number - python

So I'm trying to make a program that when I input a number it will give me all the factors(12->1,2,3,4,6,12). I only started programming very recently so there may be some very obvious things. But here's my code
numbers = [1]
newnum = 1
chosen = int(input("Enter what you want the factors of: "))
def factors(numbers,newnum,chosen):
lastnum = numbers[-1]
if (chosen == lastnum):
for number in numbers:
if (number % 1 != 0):
numbers.remove(number)
print (numbers)
else:
factors(numbers,newnum,chosen)
else:
newnum = numbers[-1] + 1
numbers.append(newnum)
print (numbers)
factors(numbers,newnum,chosen)
factors(numbers,newnum,chosen)
Ok, so I don't really need the redundancies addressed but if you see something that would completely stop the program from working please point it out. Sorry I bothered you all with this but I don't know what else to do.

There are lots of problems:
Every integer number modulo 1 is zero because each integer is divisible by one without remainder.
You remove items from the list you're iterating over, that will definetly give wrong results if you don't do it carefully!
You try to do recursion but you don't return the result of the recursive call. That's possible because you operate on a mutable list but it's generally not really good style
You don't have any inline comments explaining what that line is supposed to do, so it's hard to give any reasonable guidance on how to improve the code.
If you want a code that finds all factors, consider something like this:
chosen = int(input("Enter what you want the factors of: "))
def factors(chosen, currentnum=None, numbers=None):
# Recursion start, always append 1 and start with 2
if numbers is None:
numbers = [1]
currentnum = 2
# We're at the last value, it's always divisible by itself so
# append it and return
if currentnum == chosen:
numbers.append(currentnum)
return numbers
else:
# Check if the chosen item is divisible by the current number
if chosen % currentnum == 0:
numbers.append(currentnum)
# Always continue with the next number:
currentnum += 1
return factors(chosen, currentnum, numbers)
>>> factors(chosen)
Enter what you want the factors of: 12
[1, 2, 3, 4, 6, 12]
That's not the optimal solution but it uses recursion and gives a proper result. Just don't enter negative values or catch that case in the function at the beginning!

# Two Pointer Approach
ans = []
def divisor(val):
result = []
for i in range(1, val + 1):
ans.append(i)
i = 0
j = len(ans) - 1
while i < j:
if ans[i] * ans[j] == ans[-1]:
result.append(ans[i])
result.append(ans[j])
i += 1
else:
j -= 1
return sorted(result)
print(divisor(12))
# Output
>>> [1, 2, 3, 4, 6, 12]

Related

While loop keeps going back to end condition

I'm just going over some python basics, and wrote some code that I thought would print every even element inside of a list:
def print_evens(numbers):
"""Prints all even numbers in the list
"""
length = len(numbers)
i = 0
while i < length:
if numbers[i] % 2 == 0:
print (numbers[i])
i += 1
print_evens([1, 2, 3, 4, 5, 6])
I'm not sure why but the loop doesn't go past the end condition and just keeps cycling back and forth. I feel I'm missing something very simple.
If I had to guess where the problem lies, I'd say it's with the if statement, though I'm not sure what would be wrong about it.
The problem is that when you start with 1 the variable i never get updated, because it's not even. So the solution is to increment the i every time without a condition:
while i < length:
if numbers[i] % 2 == 0:
print (numbers[i])
i += 1
If you don't want to bother with indexes you can loop directly on the list items.
def print_evens(numbers):
"""Prints all even numbers in the list
"""
for n in numbers:
if n % 2 == 0:
print(n)

Issue in the top down approach to the Coin Change (Similar to the 0-1 backpack problem)

I am now working on the Leetcode 322. Coin Change, the question is as following:
You are given an integer array coins representing coins of different
denominations and an integer amount representing a total amount of
money.
Return the fewest number of coins that you need to make up that
amount. If that amount of money cannot be made up by any combination
of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3 Output: -1
Example 3:
Input: coins = [1], amount = 0 Output: 0
Example 4:
Input: coins = [1], amount = 1 Output: 1
Example 5:
Input: coins = [1], amount = 2 Output: 2
I tried to solve it via the top-down DP with memorization. I set a parameter in the helper function to remember the count.
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
c = set(coins)
dp = [0] * (amount + 1)
def helper(a, count):
if a == 0:
return count
# if a in c:
# return 1 + count
if dp[a] != 0:
return dp[a]
res = math.inf
for coin in c:
if a - coin >= 0 and helper(a-coin, count+1) != -1:
res = min(res, helper(a-coin, count+1))
dp[a] = res if res < math.inf else -1
return dp[a]
return helper(amount, 0)
But it won't pass the case as:
[1,2,5]
100
The result supposes to be 20, but I got 92.
I tried to figure it out the whole afternoon, but not sure where I did wrong. I hope you can give me some suggestion where I went wrong.
Thanks in advance for your help.
!!! THIS IS A COMPLETE SOLUTION !!!
Ok, so here is my solution to this problem (idea explained below):
def solve(lst, amount):
lst = sorted(lst, key=lambda x: x, reverse=True)
cases = []
for seq in [lst[i:] for i in range(len(lst))]:
current_amount = 0
count = 0
for item in seq:
while True:
if current_amount + item == amount:
count += 1
current_amount += item
break
elif current_amount + item > amount:
break
elif current_amount < amount:
count += 1
current_amount += item
if current_amount == amount:
break
if current_amount == amount:
cases.append(count)
if cases:
return min(cases)
return -1
print(solve([1, 2, 5], 100))
print(solve([1, 5, 7, 9], 12))
# 20
# 2
Explanation:
!!! MAIN IDEA
First You have to start with the largest number in the list because it takes the least amount of additions to come the closest or completely become the final amount.
!!!
EDIT
As suggested by #nitinkumarp in comments, previous version (can check edits but why?) failed in some cases as mentioned in the comment, a workaround for that issue is to check all sequences in order, still using the greedy approach but slicing the original list shorter and shorter so that it can also check the correct solution which is 7 + 5, which is 2 coins.
So first thing to do is sort the list from the largest to the smallest number as shown with .sort() function.
Then for each number in that list (for loop starts with the first item in the list so the largest number) put them in a while True loop so that they keep adding to the total until condition is met:
There are 3 conditions:
current amount (from all the additions) plus the current item in the list equals the final amount, in that case increase the count by one and add the current item to total and then break out of the loop
if the current amount + current item in list are bigger than the final amount just break out (this makes sure that no more of such number are added)
the one that will get used the most is the one that checks if the current amount is smaller than the final one, but it is important that they are elif statements because in that case if one statement turns out to be true it doesn't check the rest which is not needed in this case because otherwise it would turn out to be true even if You couldn't add more to the current amount to not exceed the final amount.
this if statement is outside of the while True loop and checks if the final amount is matched when a number 'breaks out' of the while True loop, this is to prevent continuous checking even tho the result would be already achieved.
Then the result get evaluated and if the current amount doesn't match the final print -1 else print the count
This is my solution.
The main idea is to make use of the max value element in the list as much as possible and when it becomes dysfunctional, it is about to remove it from the list and use the new max value element.
class Solution:
def coinChange(self, coins, amount):
result = []
new_amount = amount
while len(coins) > 0:
while new_amount >= max(coins):
new_amount -= max(coins)
result.append(max(coins))
coins.remove(max(coins))
if len(result) == 0:
return 0
if sum(result) != amount:
return -1
return len(result)
Let's test the results;
coins = [2, 5, 4, 1]
amount = 10
s = Solution()
print(s.coinChange(coins=coins, amount=amount))
Output: 2
Because it produced a result list like this; [5, 5]

Finding which values in a list are smaller/greater than a number

I've seen topics similar to this, but after trying out their methods it still didn't fix the part from if till the end. From what I read on other topics, the values are mismatched, yet I've been trying to fix it and trying out other methods with no success. Thank you for your help in advance.
Here's my code:
numbers = []
def calc():
d=0
m=0
single_number=int(input("Enter a number: "))
number = input("Enter a list of numbers: ")
numbers = [int(i) for i in number.split()]
summed =sum(numbers, 0)/len(numbers)
print("Average: ", summed)
minimum=min(numbers)
maximum=max(numbers)
print("Minimum", minimum)
print("Maximum", maximum)
if numbers > single_number:
d=d+1
else:
m=m+1
print("Amount of numbers in the list that are smaller than the 1st entered number:", m)
print("Amount of numbers in the list that are bigger than the 1st number:", d)
print(calc())
all you are missing is a loop:
for number in numbers:
if numbers > single_number:
d=d+1
else: # elif numbers < single_number: # what if numbers == single_number?
m=m+1
there are improvements you could make though. d = d+1 is correct; i prefer d += 1 though.
then (if you don't mind looping over your list twice):
d = sum(1 for number in numbers if number > single_number)
m = sum(1 for number in numbers if number < single_number)
would give you d and m in a compact way.
if numbers > single_number is doing something like:
if [1, 2, 3, 4, 5, 6, 7] > 4
That doesn't make any sense. Do you want a for loop?
for number in numbers:
if number > single_number:
d += 1
elif number < single_number:
m += 1
# else doesn't make sense here, since 4 is neither larger _nor_ smaller than 4.
You could use a list comprehension to filter and then get the length of the resulting list:
d = len([n for n in numbers if n > single_number])
m = len(numbers) - d

How can I display all numbers in range 0-N that are "super numbers"

The program asks the user for a number N.
The program is supposed to displays all numbers in range 0-N that are "super numbers".
Super number: is a number such that the sum of the factorials of its
digits equals the number.
Examples:
12 != 1! + 2! = 1 + 2 = 3 (it's not super)
145 = 1! + 4! + 5! = 1 + 24 + 120 (is super)
The part I seem to be stuck at is when the program displays all numbers in range 0-N that are "super numbers". I have concluded I need a loop in order to solve this, but I do not know how to go about it. So, for example, the program is supposed to read all the numbers from 0-50 and whenever the number is super it displays it. So it only displays 1 and 2 since they are considered super
enter integer: 50
2 is super
1 is super
I have written two functions; the first is a regular factorial program, and the second is a program that sums the factorials of the digits:
number = int(input ("enter integer: "))
def factorial (n):
result = 1
i = n * (n-1)
while n >= 1:
result = result * n
n = n-1
return result
#print(factorial(number))
def breakdown (n):
breakdown_num = 0
remainder = 0
if n < 10:
breakdown_num += factorial(n)
return breakdown_num
else:
while n > 10:
digit = n % 10
remainder = n // 10
breakdown_num += factorial(digit)
#print (str(digit))
#print(str(breakdown_num))
n = remainder
if n < 10 :
#print (str(remainder))
breakdown_num += factorial(remainder)
#print (str(breakdown_num))
return breakdown_num
#print(breakdown(number))
if (breakdown(number)) == number:
print(str(number)+ " is super")
Existing answers already show how to do the final loop to tie your functions together. Alternatively, you can also make use of more builtin functions and libraries, like sum, or math.factorial, and for getting the digits, you can just iterate the characters in the number's string representation.
This way, the problem can be solved in a single line of code (though it might be better to move the is-super check to a separate function).
def issuper(n):
return sum(math.factorial(int(d)) for d in str(n)) == n
N = 1000
res = [n for n in range(1, N+1) if issuper(n)]
# [1, 2, 145]
First I would slightly change how main code is executed, by moving main parts to if __name__ == '__main__', which will execute after running this .py as main file:
if __name__ == '__main__':
number = int(input ("enter integer: "))
if (breakdown(number)) == number:
print(str(number)+ " is super")
After that it seems much clearer what you should do to loop over numbers, so instead of above it would be:
if __name__ == '__main__':
number = int(input ("enter integer: "))
for i in range(number+1):
if (breakdown(i)) == i:
print(str(i)+ " is super")
Example input and output:
enter integer: 500
1 is super
2 is super
145 is super
Small advice - you don't need to call str() in print() - int will be shown the same way anyway.
I haven't done much Python in a long time but I tried my own attempt at solving this problem which I think is more readable. For what it's worth, I'm assuming when you say "displays all numbers in range 0-N" it's an exclusive upper-bound, but it's easy to make it an inclusive upper-bound if I'm wrong.
import math
def digits(n):
return (int(d) for d in str(n))
def is_super(n):
return sum(math.factorial(d) for d in digits(n)) == n
def supers_in_range(n):
return (x for x in range(n) if is_super(x))
print(list(supers_in_range(150))) # [1, 2, 145]
I would create a lookup function that tells you the factorial of a single digit number. Reason being - for 888888 you would recompute the factorial of 8 6 times - looking them up in a dict is much faster.
Add a second function that checks if a number isSuper() and then print all that are super:
# Lookup table for single digit "strings" as well as digit - no need to use a recursing
# computation for every single digit all the time - just precompute them:
faks = {0:1}
for i in range(10):
faks.setdefault(i,faks.get(i-1,1)*i) # add the "integer" digit as key
faks.setdefault(str(i), faks [i]) # add the "string" key as well
def fakN(n):
"""Returns the faktorial of a single digit number"""
if n in faks:
return faks[n]
raise ValueError("Not a single digit number")
def isSuper(number):
"Checks if the sum of each digits faktorial is the same as the whole number"
return sum(fakN(n) for n in str(number)) == number
for k in range(1000):
if isSuper(k):
print(k)
Output:
1
2
145
Use range.
for i in range(number): # This iterates over [0, N)
if (breakdown(number)) == number:
print(str(number)+ " is super")
If you want to include number N as well, write as range(number + 1).
Not quite sure about what you are asking for. From the two functions you write, it seems you have solid knowledge about Python programming. But from your question, you don't even know how to write a simple loop.
By only answering your question, what you need in your main function is:
for i in range(0,number+1):
if (breakdown(i)) == i:
print(str(i)+ " is super")
import math
def get(n):
for i in range(n):
l1 = list(str(i))
v = 0
for j in l1:
v += math.factorial(int(j))
if v == i:
print(i)
This will print all the super numbers under n.
>>> get(400000)
1
2
145
40585
I dont know how efficient the code is but it does produce the desired result :
def facto():
minr=int(input('enter the minimum range :')) #asking minimum range
maxr=int(input('enter the range maximum range :')) #asking maximum range
i=minr
while i <= maxr :
l2=[]
k=str(i)
k=list(k) #if i=[1,4,5]
for n in k: #taking each element
fact=1
while int(n) > 0: #finding factorial of each element
n=int(n)
fact=fact*n
n=n-1
l2.append(fact) #keeping factorial of each element eg : [1,24,120]
total=sum(l2) # taking the sum of l2 list eg 1+24+120 = 145
if total==i: #checking if sum is equal to the present value of i.145=145
print(total) # if sum = present value of i than print the number
i=int(i)
i=i+1
facto()
input : minr =0 , maxr=99999
output :
1
2
145
40585

Code is in Infinite Loop and I don't know Why

My code is stuck in an infinite loop on the following lines:
while i <= len(mylist):
if mylist[i][j] == number:
I've stepped through the code but still do not know how to fix it. The problem I'm trying to solve is as follows:
Define a procedure, check_sudoku,
that takes as input a square list
of lists representing an n x n
sudoku puzzle solution and returns the boolean
True if the input is a valid
sudoku square and returns the boolean False
otherwise.
A valid sudoku square satisfies these
two properties:
Each column of the square contains
each of the whole numbers from 1 to n exactly once.
Each row of the square contains each
of the whole numbers from 1 to n exactly once.
You may assume that the input is square and contains at
least one row and column.
The below code I've written should check for just the row, not the column. Any advice on how to fix it and what I've done wrong would be greatly appreciate, so I'll understand and not make the mistake again.
def check_sudoku(mylist):
i = 0
j = 0
number = len(mylist)
while i <= len(mylist):
if mylist[i][j] == number:
number = number - 1
j = 0
if number == 0:
i = i + 1
number = len(mylist)
else:
j = j + 1
if number not in list:
break
return False
return True
check_sudoku([[1, 2, 3, 4],
[1, 3, 1, 4],
[3, 1, 2, 3],
[4, 4, 4, 4]])
I'm going to explain the function with the list you supplied as an example.
What's happening is:
number = len(mylist)
number = 4
while 0 <= 4
if 1 == 4: // This condition will never be true and therefore doesn't run the code below it
The while will run again and the same will happen.
If you put this line
print("i: " + str(i) + " j: " + str(j))
Just under where the While Loop starts, you realise that i and j never increment and it stays on the first spot.
You have to increment i and j after your bigger if statement

Categories