算法设计与分析-实验4 利用动态规划的方法解决子集等和分割判断问题
一、实验目的
1. 了解动态规划的主要思想。
2. 掌握背包问题解决方法用以解决该问题。
3. 分析核心代码的时间复杂度和空间复杂度。
二、实验内容和要求
题目:给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
【请说明动态规划算法的核心思想】
动态规划算法核心思想是将待求解问题分解成若干个子问题。
【请说明背包问题与题目之间的关联性在哪】
判断其是否可以分为相等的两部分,看是否能在数组中挑选出和为数组和一半的序列。那么就可以转化为背包问题,在N个数中挑选数字使其和为数组和的一半。
【该判断函数原型及功能说明】
函数原型:
public boolean canPartition(int nums[0..n])
sum ← 0;
for i ← 0 to n-1 do sum ← sum + num[i]
if sum%2 != 0 return false;
target ← sum / 2;;
dp[0] ← true;
for i ← 0 to n-1 do
for j ← target downto num[i] do
dp[i] ← dp[i] or dp[i - num[i]];
return dp[target];
功能说明:计算出所有数字之和;将数字之和除以2。两个for循环,循环源数组的每个数字,以及遍历当前 剩余的总和的值。借助数组dp保存每次的结果符合与否。
【核心函数实现代码及时间复杂度与空间复杂度分析】
public boolean canPartition(int []nums) {
int sum = 0;
for (int num : nums) {
sum = sum + num;
}
if (sum % 2 != 0)
return false;
int target = sum / 2;
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for (int num : nums) {
for (int i = target; i >= num; i--) { //从后向前,先计算dp[i],再计算dp[i-num]
dp[i] = dp[i] || dp[i - num];
}
}
return dp[target];
}
时间复杂度:O(n)
空间复杂度:O(n)
三、实验总结
本次实验为本学期第四次实验,也是本学期最后的一下实验,实验主题为利用动态规划的方法解决子集等和分割判断问题。任务为将一个数组分割成两个子集,使得两个子集的元素和相等。通过本次实验,我学习到了动态规划的主要思想,学到了如何用背包问题解决方法用以解决该问题以及学到如何分析核心代码的时间复杂度和空间复杂度,为今后得程序开发奠定基础,更有利于今后对算法设计与分析这一门课程的学习。
四、优化及改进(选做)
【提出你觉得解决这个问题更好的算法,并加以说明】