I was trying to solve a knapsack problem using DP. Basically, the goal is to see if we can have certain elements in the list sum up to half of the total sum.
def canPartition(nums):
"""
:type nums: List[int]
:rtype: bool
"""
run_sum = 0
for num in nums:
run_sum += num
if run_sum & 1 == 1:
return False
run_sum //= 2
n = len(nums)
dp = [[False] * (run_sum+1)] * (n+1)
for i in range(n+1):
dp[i][0] = True
for j in range(1, run_sum+1):
dp[0][j] = False
print("initial stage")
print(dp)
for i in range(1, 2):
for j in range(1, run_sum+1):
dp[i][j] = dp[i-1][j]
print("inner loop after operation 1:")
print(dp)
if j >= nums[i-1]:
print("inner loop after operation 2:")
print(i, j)
dp[i][j] |= dp[i-1][(j - nums[i-1])]
print(dp)
print(" ")
return dp[n][run_sum]
nums = [1, 2, 5]
canPartition(nums)
The goal itself is not so important here. But the flow control of the last nested loop behaves really strange. Below is the printed result.
initial stage
[[True, False, False, False, False], [True, False, False, False, False], [True, False, False, False, False], [True, False, False, False, False]]
inner loop after operation 1:
[[True, False, False, False, False], [True, False, False, False, False], [True, False, False, False, False], [True, False, False, False, False]]
inner loop after operation 2:
1 1
[[True, True, False, False, False], [True, True, False, False, False], [True, True, False, False, False], [True, True, False, False, False]]
inner loop after operation 1:
[[True, True, False, False, False], [True, True, False, False, False], [True, True, False, False, False], [True, True, False, False, False]]
inner loop after operation 2:
1 2
[[True, True, True, False, False], [True, True, True, False, False], [True, True, True, False, False], [True, True, True, False, False]]
inner loop after operation 1:
[[True, True, True, False, False], [True, True, True, False, False], [True, True, True, False, False], [True, True, True, False, False]]
inner loop after operation 2:
1 3
[[True, True, True, True, False], [True, True, True, True, False], [True, True, True, True, False], [True, True, True, True, False]]
inner loop after operation 1:
[[True, True, True, True, False], [True, True, True, True, False], [True, True, True, True, False], [True, True, True, True, False]]
inner loop after operation 2:
1 4
[[True, True, True, True, True], [True, True, True, True, True], [True, True, True, True, True], [True, True, True, True, True]]
You can see that, even the value of i was 1 for the entire nested loop, somehow the values of dp[i>1] was modified in the loop. And even j from 1 to 4 was modified as well. It was like there was another "for i in range()" inside the loop. Does anyone have an idea why is this happening? I runned the code with python 3.6.1
This line
dp = [[False] * (run_sum+1)] * (n+1)
creates a list of n + 1
references to the same list of False
s. A simpler example:
>>> x = [[False]]*3
>>> x
[[False], [False], [False]]
>>> x[0][0] = True
>>> x
[[True], [True], [True]]
You almost never want to use *
with a list; use a list comprehension instead to get independent lists:
dp = [[False for _ in range(run_sum+1)] for _ in range(n+1)]
In this line
dp = [[False] * (run_sum+1)] * (n+1)
the * (n+1)
doesn't magically create copies of the inner list. Instead it's just making a list of (n+1)
references to the same list.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.