Cho danh sách số không âm nums và số nguyên target. Gán dấu '+' hoặc '-' cho mỗi số sao cho tổng biểu thức bằng target. Đếm số cách gán dấu.
Ví dụ
nums = [2, 3, 3, 3, 2], target = 9
Cách 1: -2 + 3 + 3 + 3 + 2 = 9
Cách 2: +2 + 3 + 3 + 3 - 2 = 9
Kết quả: 2.
Quan sát quan trọng (Chuyển đổi thành Subset Sum)
Gọi P = tập số gán '+', N = tập số gán '-'.
sum(P) - sum(N) = target
sum(P) + sum(N) = total_sum
→ 2 * sum(P) = target + total_sum
→ sum(P) = (target + total_sum) / 2
Bài toán trở thành: đếm số subset có tổng = (target + total_sum) // 2.
Điều kiện
(target + total_sum)phải chẵn.target <= total_sum.
Thuật toán (DP 1D - Coin Change biến thể)
W = (total_sum + target) // 2.dp[w]= số cách đạt tổngw.- Khởi tạo
dp[0] = 1. - Với mỗi
numtrongnums: duyệtwtừWxuốngnum,dp[w] += dp[w - num].
Triển khai Python
class Solution:
def solve(self, nums, target):
total = sum(nums)
if (total + target) % 2 != 0 or target > total:
return 0
W = (total + target) // 2
dp = [0] * (W + 1)
dp[0] = 1
for num in nums:
for w in range(W, num - 1, -1):
dp[w] += dp[w - num]
return dp[W]
# Test
ob = Solution()
print(ob.solve([2, 3, 3, 3, 2], 9)) # Output: 2
Độ phức tạp
- Thời gian: O(n × W) với W = (sum + target)/2.
- Không gian: O(W).
Tương đương bài toán "Target Sum" (LeetCode 494).