华为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元组),则提前终止递归(剪枝),以提高效率。
- 去重:在排序的基础上,跳过连续相同的元素,确保生成的组合不重复。
JavaScript
const rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout,
});
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
// Author: code5bug
(async () => {
const nums = (await readline()).split(' ').map(Number);
const k = parseInt(await readline());
const target = parseInt(await readline());
nums.sort((a, b) => a - b); // 排序以便跳过重复元素
let ans = 0; // 记录满足条件的组合数
function backtrack(idx, total, left_k) {
/**
* 回溯函数,寻找满足条件的k元组
* @param {number} idx - 当前处理的元素索引
* @param {number} total - 当前已选元素的和
* @param {number} left_k - 剩余需要选择的元素个数
*/
// 找到答案组合
if (left_k === 0 && total === target) {
ans++;
return;
}
// 终止条件:索引越界或已无剩余元素需要选择
if (idx === nums.length || left_k === 0) {
return;
}
for (let i = idx; i < nums.length; i++) {
// 跳过重复元素,避免生成重复组合
if (i > idx && nums[i] === nums[i - 1]) {
continue;
}
// 递归处理下一个元素
backtrack(i + 1, total + nums[i], left_k - 1);
}
}
backtrack(0, 0, k); // 从索引0开始,初始和为0,剩余k个元素需要选择
console.log(ans);
rl.close();
})();
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);
}
}
}
Python
"""
@author: code5bug
"""
nums = list(map(int, input().split()))
k = int(input())
target = int(input())
nums.sort() # 排序以便跳过重复元素
ans = 0 # 记录满足条件的组合数
def backtrack(idx: int, total: int, left_k: int):
"""
回溯函数,寻找满足条件的k元组
:param idx: 当前处理的元素索引
:param total: 当前已选元素的和
:param left_k: 剩余需要选择的元素个数
"""
global nums, ans, target
# 找到答案组合
if left_k == 0 and total == target:
ans += 1
return
# 终止条件:索引越界或已无剩余元素需要选择
if idx == len(nums) or left_k == 0:
return
for i in range(idx, len(nums)):
# 跳过重复元素,避免生成重复组合
if i > idx and nums[i] == nums[i - 1]:
continue
# 递归处理下一个元素
backtrack(i + 1, total + nums[i], left_k - 1)
backtrack(0, 0, k) # 从索引0开始,初始和为0,剩余k个元素需要选择
print(ans)
C++
/ Author: code5bug
#include <bits/stdc++.h>
using namespace std;
int ans = 0;
vector<int> nums;
/**
* 回溯函数,寻找满足条件的k元组
* @param idx 当前处理的元素索引
* @param total 当前已选元素的和
* @param left_k 剩余需要选择的元素个数
* @param target 目标和
*/
void backtrack(int idx, int total, int left_k, int target) {
// 找到答案组合
if (left_k == 0 && total == target) {
ans++;
return;
}
// 终止条件:索引越界或已无剩余元素需要选择
if (idx == nums.size() || left_k == 0) {
return;
}
for (int i = idx; i < nums.size(); i++) {
// 跳过重复元素,避免生成重复组合
if (i > idx && nums[i] == nums[i - 1]) {
continue;
}
// 递归处理下一个元素
backtrack(i + 1, total + nums[i], left_k - 1, target);
}
}
int main() {
int num;
while (cin >> num) {
nums.push_back(num);
if (cin.get() == '\n') break;
}
int k, target;
cin >> k >> target;
sort(nums.begin(), nums.end()); // 排序以便跳过重复元素
backtrack(0, 0, k, target);
cout << ans << endl;
return 0;
}
希望这个专栏能让您熟练掌握算法, 🎁🎁🎁 。
整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏