版权声明:本文为博主原创文章,欢迎大家转载,但是要注明我的文章地址。 https://blog.csdn.net/program_developer/article/details/83625544
题目描述:
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的子数组。如果存在该子数组返回true,否则返回false。
输入输出:
input:{3, 34, 4, 12,5, 2}
output:true
解题思路:
(1)最优子结构
(2)状态转移方程
(3)边界条件
情况1:如果s=0时,直接返回true。
情况2:当指针到数组下标为0的时候,判断arr[0]是否等于s。
情况3: 当arr[i] 大于s时,我们就不考虑选arr[i]的情况,只考虑不选arr[i]的情况。
代码实现:
(1)递归方法
public class subArrayEqualsK {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {3, 34, 4, 12, 5, 2};
System.out.println(rec_subSet(arr, arr.length-1, 9));
}
/**
* 递归方法
* @param arr
* @param i
* @param s
* @return
*/
public static boolean rec_subSet(int[] arr,int i, int s) {
if(s == 0)
return true;
else if(i == 0) {
if(arr[i] == s)
return true;
else
return false;
}
else if(arr[i] > s) {
return rec_subSet(arr, i-1, s);
}
else {
boolean a = rec_subSet(arr, i-1, s-arr[i]);
boolean b = rec_subSet(arr, i-1, s);
if(a || b)
return true;
else
return false;
}
}
}
(2)动态规划方法
public class subArrayEqualsK {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {3, 34, 4, 12, 5, 2};
System.out.println(dp_subSet(arr, 9));
System.out.println(dp_subSet(arr, 10));
System.out.println(dp_subSet(arr, 11));
System.out.println(dp_subSet(arr, 12));
System.out.println(dp_subSet(arr, 13));
}
/**
* 动态规划解法
* @param arr
* @param s
* @return
*/
public static boolean dp_subSet(int[] arr, int s) {
// 构建状态数组
boolean[][] subSet = new boolean[arr.length][s+1];
for(int i=0; i<arr.length; i++) {
subSet[i][0] = true;
}
for(int i=0; i<s+1; i++) {
subSet[0][i] = false;
}
subSet[0][arr[0]] = true;
// 在根据状态方程,填充状态数组
for(int i=1; i<arr.length; i++) {
for(int j=1; j<s+1; j++) {
if(arr[i] > j)
subSet[i][j] = subSet[i-1][j];
else {
boolean A = subSet[i-1][j-arr[i]];
boolean B = subSet[i-1][j];
if(A || B)
subSet[i][j] = true;
else
subSet[i][j] = false;
}
}
}
return subSet[arr.length-1][s];
}
}
Reference:
【1】https://www.bilibili.com/video/av18512769/?spm_id_from=333.788.videocard.0