I am trying to solve #78 Leetcode (Subsets) using backtracking recursion.
The idea is to create all possible combinations by either selecting the value at index 'i' or not selecting the value and then recursing through till the end of the list.
I wrote this code:
nums = [1,2,3]
res,r = [],[]
def bts(nums,r,i):
if(i == len(nums)):
print(i,r)
res.append(r)
return
r.append(nums[i])
print(i,r)
bts(nums,r,i+1)
print(i,r)
r = r[:-1]
print(i,r)
bts(nums,r,i+1)
print(i,r)
return
bts(nums,r,0)
print(res)
The various print(i,r) lines are written to debug and see where my algorithm goes wrong. I noticed that after [1,2] gets pushed through to the subset when bts(nums,[1,2],3) is called, the return statement at the end returns to i=1 iteration with the (i,r) value as (1,[1,2,3]) instead of (1,[1,2]). I am unable to understand why this is so.
I got the code to work. I had to make a couple of changes:
Replace res.append(r) with res.append(r.copy())
Instead of r = r[:-1], I used r.pop().
I don't understand the 2nd point though. Why does r.pop() work but not r = r[:-1].
Related
numbers = (2,3,4)
def product(n):
m = 1
for i in n:
m *= i
return print(numbers[0],'x',numbers[1],'x',numbers[2],'=',m)
product(numbers)
This is what I wrote for this problem. But I don't know how to make the result like "2x3x4=24" exactly. Another question is if I add '5' in the parentheses, it only shows "2x3x4=120", I cannot get "2x3x4x5=120". Could anyone helps me to fix my code??? Thanks.
There are two main issues with your code. The first in that your return statement is executed in the first iteration of your loop, but you want it to happen after the entire loop has finished. This happens because you have too much whitespace to the left of the return statement. The second is that you’re attempting to return the return value of a call to print. To fix this ditch the return or even better return a string then print that:
numbers = (2,3,4)
def product(n):
m = 1
for i in n:
m *= i
return f"{n[0]}x{n[1]}x{n[2]}={m}"
returned = product(numbers)
print(returned)
The answer linked in the comments points out there’s an even easier way to do this:
from math import prod
returned = prod((2,3,4))
print(returned)
And here's a bit of a kick-flip for fun:
from math import prod
numbers = (2,3,4)
print(*numbers, sep="x", end=f"={prod(numbers)}")
The code should be straight forward but I found that it works sometimes well and sometimes not at all. when trying to print the solutions immediately it works fine but when I try to store, use , or do anything else with them, the generator simply keeps giving the same solution over and over
def isvalid(grid,y,x,n):
for i in range(9):
if i!=y and grid[i][x]==n:
return False
if i!=x and grid[y][i]==n:
return False
sy=3*(y//3)
sx=3*(x//3)
for dy in range(3) :
for dx in range(3) :
if sy+dy!=y and sx+dx!=x:
if grid[sy+dy][sx+dx]==n: return False
return True
def solve(grid):
number_list = [1,2,3,4,5,6,7,8,9]
for y in range(9):
for x in range(9):
if grid[y][x]==0:
random.shuffle(number_list)
for i in number_list:
if isvalid(grid,y,x,i):
grid[y][x]=i
yield from solve(grid)
grid[y][x]=0
return
yield grid
with this code the first case works fine and prints different grids
but in the #2 one the solutions are the same and the result is true
grid=[[0]*9 for x in range(9)]
s= solve(grid)
# 1
for i in s:
print(i)
# 2
solutions=[]
for i,n in zip(s,range(3)):
solutions.append(i)
print(solutions[0]==solutions[1])
Your code uses a single mutable data structure grid which the solve function modifies in place at each step. Every yield grid statement is simply returning a reference to this mutable object, so the list you collect is a list of references to the same thing, in its latest state.
Note: you can see your solutions point to the same object by checking:
print(solutions[0] is solutions[1])
Try yielding a deep copy of the grid each time (if you want to collect a list of them), or print the grids as they are generated rather than collecting them (edit: IIUC your print approach #1 currently shows different solutions as expected):
yield [[entry for entry in row] for row in grid]
This could be memory intensive especially when you start with an empty grid as you have done. Probably better to test with an example which has fewer solutions first.
I'm new to a programming language and wanted to start with Python as its the recommendation of most people (as far as i see).
So, im practising on some functions to improve my understanding on loops, and basic statements etc. Though i'm not very good at it yet, i do believe that i'll improve sooner or later.
Here is an example where i'm stuck at:
def L():
List = []
TauS = []
a = 12
for i in range(1,a+1):
if a % i == 0:
List.append(i)
if a % len(List) == 0:
TauS.append(a)
print(List)
print(TauS)
L()
This is the function i want to have and the output is:
[1, 2, 3, 4, 6, 12]
[12]
As i expected.However, the problem is that i want "a" to be a variable instead of a constant.Something like:
def L():
List = []
TauS = []
for a in range(2,20):
for i in range(1,a+1):
if a % i == 0:
List.append(i)
if a % len(List) == 0:
TauS.append(a)
print(List)
print(TauS)
L()
Fails because it seems like for loop is working before the 2nd if statement (if a % len(list)) == 0: TauS.append(a)).I have also tried a "while" loop instead of a "for" loop as:
a = 2
while a <= 20:
for i in range(1,a+1):...(The rest is the same)
It would be a better idea if your help focus on the basic ideas instead of just giving the right function.
Thanks a lot from now!
Regards.
Python uses indention levels to tell whether code is in within a function, loop or condition, the general thing being that if there is a : then all the code indented underneath it is within that statement.
The problem with your code is that the second if statement is on the same indention level as the for loop rather than being on the indention level below the for loop. This means that rather than running in the for loop it runs after it.
So to fix your code all you need to do is select the if statement and press crtl + ] which is pythons keyboard shortcut for indent code section.
edit:
I think what you're asking for is to get all the factors of numbers from 2 to 19 and then print numbers where the number of factors is a factor of that number.
def L():
List = []
TauS = []
for a in range(2,20):
l=[] #this is the list for each individual number
#if i is a factor of a add it to l
for i in range(1,a+1):
if a % i == 0:
l.append(i)
#if length of l is a factor of a add a to TauS
if a % len(l) == 0:
TauS.append(a)
List.append(l)
print(List)
print(TauS)
L()
It fails because of variable scope.
Python uses indention to represent code block. So, here for loop and 2nd if condition has same indention which means they belong to same code block and can access variables defined in the same or the outer code block. "List" & "Taus" in this case.
However, Variable "a" is localize to outer for loop and can be access in the same or inner for loop and cant be access from outside. Similarly variable "i" is specific to inner for loop and cant be access outside of the loops block, not even from outer for loop.
Hope it helps...
I've created a function named number(x) that tests a number to see whether or not a number is perfect or not. Now my goal is to create a tester function that tests all numbers from 1 to 1000 and return numbers that are perfect. This is the code i have for the test function:
def unittest():
for i in range(0,1000):
perfect(i)
if True:
return i
It's not working, but i think i'm close. Any advice or help?
I think you meant this, and notice the correct parameters for range, and how we use a list to accumulate all the results - otherwise, the function will return only one value!
def unittest():
ans = []
for i in range(1, 1001):
if perfect(i):
ans.append(i)
return ans
Alternatively, and not recommended (it's redundant), you could test if the returned value was True:
def unittest():
ans = []
for i in range(1, 1001):
if perfect(i) is True :
ans.append(i)
return ans
Yet another alternative would be to use list comprehensions, which is more idiomatic and potentially faster than using an explicit loop:
def unittest():
return [i for i in range(1, 1001) if perfect(i)]
When you return, that's the end of your function. If you want to return all of the perfect numbers, you have to keep track of them and return them all at the end.
On top of that, your if True: means you'll return 0 whether it's perfect or not.
So, what you need to do is:
def unittest():
results = []
for i in range(1000):
if perfect(i):
results.append(i)
return results
There actually is a way to solve this without building the list, by using yield instead of return. That's probably too advanced for you to learn right now, but I'll explain it anyway. First, here's the code:
def unittest():
for i in range(1000):
if perfect(i):
yield i
See the tutorial section on Iterators, and the following two sections, for details. But basically, a yield is like a return that doesn't return. What your function actually returns is not a list, but a generator. If someone then iterates over that generator, it will go through your function until the first yield, then go through until the next yield, and so on until you're done. The tutorial explains this much better than a single paragraph ever could.
I have been working on generating all possible submodels for a biological problem. I have a working recursion for generating a big list of all the submodels I want. However, the lists get unmanageably large pretty fast (N=12 is just possible in the example below, N>12 uses too much memory). So I wanted to convert it to a generator function using yield instead, but I'm stuck.
My working recursive function looks like this:
def submodel_list(result, pat, current, maxn):
''' result is a list to append to
pat is the current pattern (starts as empty list)
current is the current number of the pattern
maxn is the number of items in the pattern
'''
if pat:
curmax = max(pat)
else:
curmax = 0
for i in range(current):
if i-1 <= curmax:
newpat = pat[:]
newpat.append(i)
if current == maxn:
result.append(newpat)
else:
submodel_generator(result, newpat, current+1, maxn)
result = []
submodel_list(result, [], 1, 5)
That gives me the expected list of submodels for my purposes.
Now, I want to get that same list using a recursion. Naively, I thought I could just switch out my result.append() for a yield function, and the rest would work OK. So I tried this:
def submodel_generator(pat, current, maxn):
'''same as submodel_list but yields instead'''
if pat:
curmax = max(pat)
else:
curmax = 0
for i in range(current):
print i, current, maxn
if i-1 <= curmax:
print curmax
newpat = pat[:]
newpat.append(i)
if current == maxn:
yield newpat
else:
submodel_generator(newpat, current+1, maxn)
b = submodel_generator([], 1, 5)
for model in b: print model
But now I get nothing. A (very dumb) bit of digging tells me the function gets to the final else statement once, then stops - i.e. the recursion no longer works.
Is there a way to turn my first, clunky, list-making function into a nice neat generator function? Is there something silly I've missed here? All help hugely appreciated!
You should change this:
submodel_generator(newpat, current+1, maxn)
to this:
for b in submodel_generator(newpat, current+1, maxn):
yield b
This will recursively yield the value from successive calls to the function.
[Update]: Note that as of Python 3.3, you can use the new yield from syntax:
yield from submodel_generator(newpat, current+1, maxn)