华为OD机试题库《C++》限时优惠 9.9
华为OD机试题库《Python》限时优惠 9.9
华为OD机试题库《JavaScript》限时优惠 9.9
针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。
看不懂有疑问需要答疑辅导欢迎私VX: code5bug
题目描述
给定一个整数数组 nums、一个数字k,一个整数目标值 target,请问nums中是否存在k个元素使得其相加结果为target,请输出所有符合条件且不重复的k元组的个数
数据范围
- 2<= nums.length <= 200
- -109 <= nums[i] <= 109
- -109 <= target <= 109
- 2 <=k<= 100
输入描述
第一行是nums 取值:2 7 11 15
第二行是k的取值:2
第三行是target取值:9
输出描述
输出第一行是符合条件的元祖个数:1
补充说明:
[2,7]满足,输出个数是1
示例1
输入:
-1 0 1 2 -1 -4
3
0
输出:
2
说明:
-1 0 1, -1 -1 2 满足条件
示例2
输入:
2 7 11 15
2
9
输出:
1
说明:
2 7 符合条件
题解
目类型
这道题目属于**回溯算法(Backtracking)**的范畴,类似于组合求和问题。我们需要在给定的数组中找到所有不重复的k元组,使得它们的和等于目标值target。由于需要枚举所有可能的组合并避免重复,回溯算法是一个合适的选择。
解题思路
- 排序:首先对数组进行排序,这样可以方便地跳过重复的元素,避免生成重复的组合。
- 回溯:使用回溯算法来生成所有可能的k元组。在每一步,我们决定是否选择当前元素,并递归处理剩下的元素。
- 剪枝:在递归过程中,如果当前的和已经不可能满足条件(例如,剩余的元素不足以构成k元组),则提前终止递归(剪枝),以提高效率。
- 去重:在排序的基础上,跳过连续相同的元素,确保生成的组合不重复。
Java
import java.util.Arrays;
import java.util.Scanner;
/**
* @author code5bug
*/
public class Main {
private static int ans = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] nums = Arrays.stream(sc.nextLine().split(" "))
.mapToInt(Integer::parseInt).toArray();
int k = sc.nextInt();
int target = sc.nextInt();
Arrays.sort(nums); // 排序以便跳过重复元素
ans = 0;
backtrack(nums, 0, 0, k, target);
System.out.println(ans);
}
/**
* 回溯函数,寻找满足条件的k元组
*
* @param nums 数组
* @param idx 当前处理的元素索引
* @param total 当前已选元素的和
* @param left_k 剩余需要选择的元素个数
* @param target 目标和
*/
private static void backtrack(int[] nums, int idx, int total, int left_k, int target) {
// 找到答案组合
if (left_k == 0 && total == target) {
ans++;
return;
}
// 终止条件:索引越界或已无剩余元素需要选择
if (idx == nums.length || left_k == 0) {
return;
}
for (int i = idx; i < nums.length; i++) {
// 跳过重复元素,避免生成重复组合
if (i > idx && nums[i] == nums[i - 1]) {
continue;
}
// 递归处理下一个元素
backtrack(nums, i + 1, total + nums[i], left_k - 1, target);
}
}
}
希望这个专栏能让您熟练掌握算法, 🎁🎁🎁 。
整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏