华为OD机试真题——硬件产品销售方案(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型
本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析;
并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式!
华为OD机试真题《硬件产品销售方案》:
目录
- 题目名称:硬件产品销售方案
- 题目描述
- Java
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 示例1输入:
- 示例2输入:
- 综合分析
- python
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 示例1输入:
- 示例2输入:
- 综合分析
- JavaScript
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 示例1输入:
- 示例2输入:
- 综合分析
- C++
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 示例1输入:
- 示例2输入:
- 综合分析
- C语言
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 示例测试
- 示例1输入:
- 示例2输入:
- 综合分析
- GO
- 问题分析
- 解题思路
- 代码实现
- 代码详细解析
- 1. 输入处理
- 2. 回溯函数
- 3. 结果格式化
- 示例测试
- 示例1输入:
- 示例2输入:
- 综合分析
- 扩展
- 更多内容:
题目名称:硬件产品销售方案
维度 | 描述 |
---|---|
知识点 | 回溯算法(DFS)、剪枝优化、排序预处理 |
时间限制 | 1秒 |
空间限制 | 256MB |
限定语言 | 不限 |
题目描述
某公司推出多种硬件产品,每种产品包含若干型号且价格唯一。现需为合作厂商列出所有总金额等于 amount
元的产品组合。已知产品库存充足,且价格列表 price
中的元素互不相同。
输入描述
- 第一行为正整数
amount
,表示采购金额。 - 第二行为逗号分隔的正整数列表
price
,表示各型号的价格。
输出描述
- 输出所有可能的组合列表,格式为二维数组。若无法组合,返回空列表。
- 注意:组合中元素的顺序不同视为不同方案(如
[100, 200]
和[200, 100]
视为两种组合),但实际题目中因允许重复选择同一产品,需按顺序枚举。
示例1
输入:
500
100,200,300,500
输出:
[[100,100,100,100,100], [100,100,100,200], [100,100,300], [100,200,200], [200,300], [500]]
示例2
输入:
100
100
输出:
Java
问题分析
我们需要找到所有可能的价格组合,使得它们的总和等于给定的金额。每个价格可以重复使用,且组合中的元素顺序不同视为不同方案。为避免重复组合,需按非降序排列生成组合。
解题思路
- 排序预处理:将价格数组排序,确保组合按非降序生成。
- 回溯算法(DFS):递归遍历所有可能的组合,记录满足条件的组合。
- 剪枝优化:当当前路径的和超过目标金额时,停止进一步搜索。
代码实现
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int amount = Integer.parseInt(sc.nextLine());String[] prices = sc.nextLine().split(",");List<Integer> priceList = new ArrayList<>();for (String p : prices) {priceList.add(Integer.parseInt(p.trim()));}// 排序以便后续剪枝和去重Collections.sort(priceList);List<List<Integer>> result = new ArrayList<>();backtrack(priceList, amount, 0, new ArrayList<>(), 0, result);// 输出格式化System.out.println(formatResult(result));}/*** 回溯函数,递归生成所有可能的组合* @param prices 排序后的价格列表* @param target 目标金额* @param start 当前遍历的起始索引(避免重复组合)* @param path 当前路径(组合)* @param sum 当前路径的和* @param result 结果集*/private static void backtrack(List<Integer> prices, int target, int start, List<Integer> path, int sum, List<List<Integer>> result) {if (sum > target) return; // 剪枝:总和超过目标,停止递归if (sum == target) { // 找到有效组合,加入结果集result.add(new ArrayList<>(path));return;}// 从start开始遍历,避免生成重复组合for (int i = start; i < prices.size(); i++) {int price = prices.get(i);if (sum + price > target) break; // 剪枝:后续元素更大,无需继续path.add(price); // 将当前元素加入路径backtrack(prices, target, i, path, sum + price, result);path.remove(path.size() - 1); // 回溯:移除当前元素}}/*** 将结果列表格式化为题目要求的字符串形式*/private static String formatResult(List<List<Integer>> result) {if (result.isEmpty()) return "[]";StringBuilder sb = new StringBuilder();sb.append("[");for (int i = 0; i < result.size(); i++) {sb.append("[");List<Integer> list = result.get(i);for (int j = 0; j < list.size(); j++) {sb.append(list.get(j));if (j < list.size() - 1) sb.append(",");}sb.append("]");if (i < result.size() - 1) sb.append(", ");}sb.append("]");return sb.toString();}
}
代码详细解析
- 输入处理:读取金额和价格列表,将价格转换为整数并排序。
- 回溯函数:
- 终止条件:若当前和超过目标,直接返回;若等于目标,保存组合。
- 循环遍历:从
start
索引开始遍历,避免重复组合。 - 剪枝优化:若当前和加当前价格超过目标,终止后续循环。
- 路径管理:递归前添加当前价格到路径,递归后移除(回溯)。
- 结果格式化:将结果列表转换为符合题目要求的字符串格式。
示例测试
示例1输入:
500
100,200,300,500
输出:
[[100,100,100,100,100], [100,100,100,200], [100,100,300], [100,200,200], [200,300], [500]]
解析:
- 排序后价格为
[100,200,300,500]
。 - 通过回溯生成所有非降序组合,如
[100×5]
、[100×3+200]
等。
示例2输入:
100
100
输出:
解析:
- 唯一可能的组合是
[100]
。
综合分析
- 时间复杂度:最坏情况下为O(2^n),但通过排序和剪枝优化,实际效率较高。
- 空间复杂度:O(n)递归栈深度,结果存储空间为O(k·m)(k为组合数,m为平均组合长度)。
- 优势:
- 剪枝优化:通过排序和提前终止无效搜索,减少计算量。
- 去重机制:通过固定遍历起点,避免生成重复组合。
- 适用场景:适用于小规模数据(价格列表长度≤30),符合题目约束。
python
问题分析
我们需要找到所有可能的价格组合,使得它们的总和等于给定的金额。每个价格可以重复使用,且组合按非降序排列以避免重复。
解题思路
- 排序预处理:将价格数组排序,确保组合按非降序生成。
- 回溯算法(DFS):递归遍历所有可能的组合,记录满足条件的组合。
- 剪枝优化:当当前路径的和超过目标金额时,停止进一步搜索。
代码实现
def main():amount = int(input())prices = list(map(int, input().strip().split(',')))prices.sort()result = []def backtrack(start, path, current_sum):if current_sum == amount:result.append(path.copy())returnfor i in range(start, len(prices)):price = prices[i]if current_sum + price > amount:break # 剪枝:后续价格更大,无需继续path.append(price)backtrack(i, path, current_sum + price)path.pop()backtrack(0, [], 0)print(format_result(result))def format_result(result):if not result:return "[]"formatted = []for combo in result:formatted.append("[{}]".format(",".join(map(str, combo))))return "[{}]".format(", ".join(formatted))if __name__ == "__main__":main()
代码详细解析
- 输入处理:读取金额和价格列表,转换为整数并排序。
- 回溯函数:
- 终止条件:若当前和等于目标金额,保存组合。
- 循环遍历:从
start
索引开始,保证组合非降序。 - 剪枝优化:若当前和加当前价格超过目标,终止循环。
- 路径管理:递归前添加价格到路径,递归后移除(回溯)。
- 结果格式化:将结果转换为题目要求的二维数组格式。
示例测试
示例1输入:
500
100,200,300,500
输出:
[[100,100,100,100,100],[100,100,100,200],[100,100,300],[100,200,200],[200,300],[500]]
解析:
- 排序后价格为
[100,200,300,500]
。 - 通过回溯生成所有非降序组合,如
[100×5]
、[100×3+200]
等。
示例2输入:
100
100
输出:
解析:
- 唯一可能的组合是
[100]
。
综合分析
- 时间复杂度:最坏情况下为O(2ⁿ),但通过剪枝优化,实际效率较高。
- 空间复杂度:O(n)递归栈深度,结果存储为O(k·m)(k为组合数,m为平均组合长度)。
- 优势:
- 剪枝优化:通过排序提前终止无效搜索。
- 去重机制:固定遍历起点,保证组合非降序。
- 适用场景:适用于小规模数据(价格列表长度≤30)。
JavaScript
问题分析
我们需要找到所有可能的价格组合,使得它们的总和等于给定的金额。每个价格可以重复使用,组合需按非降序排列以避免重复。
解题思路
- 排序预处理:将价格数组排序,确保组合按非降序生成。
- 回溯算法(DFS):递归遍历所有可能的组合,记录满足条件的组合。
- 剪枝优化:当当前路径的和超过目标金额时,停止进一步搜索。
代码实现
const readline = require('readline');const rl = readline.createInterface({input: process.stdin,output: process.stdout,terminal: false
});let lines = [];
rl.on('line', (line) => {lines.push(line.trim());
}).on('close', () => {const amount = parseInt(lines[0]);const prices = lines[1].split(',').map(Number).sort((a, b) => a - b);const result = [];// 回溯函数定义const backtrack = (start, path, currentSum) => {if (currentSum === amount) {result.push([...path]); // 存储路径副本return;}for (let i = start; i < prices.length; i++) {const price = prices[i];if (currentSum + price > amount) break; // 剪枝:超过目标金额path.push(price); // 添加当前价格backtrack(i, path, currentSum + price); // 递归探索path.pop(); // 回溯:移除最后添加的价格}};backtrack(0, [], 0); // 初始调用console.log(formatResult(result)); // 格式化输出
});// 结果格式化函数
const formatResult = (result) => {if (result.length === 0) return '[]';const formatted = result.map(combo => `[${combo.join(',')}]`);return `[${formatted.join(', ')}]`;
};
代码详细解析
-
输入处理:
- 使用
readline
模块读取两行输入,分别存储金额和价格列表。 - 将价格转换为数字数组并排序,确保后续生成非降序组合。
- 使用
-
回溯函数:
- 参数说明:
start
:当前遍历的起始索引,避免重复组合。path
:当前路径(组合)。currentSum
:当前路径的价格总和。
- 终止条件:当
currentSum === amount
时,将路径副本存入结果。 - 循环遍历:从
start
开始,避免生成逆序组合。 - 剪枝优化:若当前价格导致总和超限,终止后续循环。
- 路径管理:递归前添加价格,递归后弹出(回溯)。
- 参数说明:
-
结果格式化:
- 处理空结果返回
[]
。 - 将每个组合转换为字符串格式,用逗号分隔元素。
- 处理空结果返回
示例测试
示例1输入:
500
100,200,300,500
输出:
[[100,100,100,100,100], [100,100,100,200], [100,100,300], [100,200,200], [200,300], [500]]
解析:
- 排序后价格为
[100,200,300,500]
。 - 回溯生成所有非降序组合,如
[100×5]
、[100×3+200]
等。
示例2输入:
100
100
输出:
解析:
- 唯一可能的组合是
[100]
,直接命中目标金额。
综合分析
-
时间复杂度:O(2ⁿ)
- 最坏情况下需遍历所有组合,但通过剪枝大幅减少实际计算量。
- 示例1中有效剪枝:当
100×5=500
后,跳过更大价格的无效路径。
-
空间复杂度:O(n²)
- 递归调用栈深度为 O(n),结果存储空间为 O(k·m),k为组合数,m为平均组合长度。
-
优势:
- 去重机制:通过固定遍历起点,保证组合非降序。
- 剪枝优化:提前终止无效路径,提升效率。
-
适用场景:
- 价格列表长度 ≤ 30 的中小规模数据。
- 需要精确枚举所有可能性的场景,如商品组合推荐。
C++
问题分析
我们需要找到所有可能的价格组合,使得它们的总和等于给定的金额。每个价格可以重复使用,组合需按非降序排列以避免重复。
解题思路
- 排序预处理:将价格数组排序,确保组合按非降序生成。
- 回溯算法(DFS):递归遍历所有可能的组合,记录满足条件的组合。
- 剪枝优化:当当前路径的和超过目标金额时,停止进一步搜索。
代码实现
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>using namespace std;void backtrack(const vector<int>& prices, int target, int start, vector<int>& path, int sum, vector<vector<int>>& result) {if (sum == target) {result.push_back(path);return;}for (int i = start; i < prices.size(); ++i) {if (sum + prices[i] > target) break; // 剪枝:后续价格更大,无需继续path.push_back(prices[i]); // 添加当前价格backtrack(prices, target, i, path, sum + prices[i], result);path.pop_back(); // 回溯:移除最后添加的价格}
}string formatResult(const vector<vector<int>>& result) {if (result.empty()) return "[]";stringstream ss;ss << "[";for (size_t i = 0; i < result.size(); ++i) {ss << "[";const auto& combo = result[i];for (size_t j = 0; j < combo.size(); ++j) {ss << combo[j];if (j != combo.size() - 1) ss << ",";}ss << "]";if (i != result.size() - 1) ss << ", ";}ss << "]";return ss.str();
}int main() {int amount;cin >> amount;cin.ignore(); // 忽略换行符string line;getline(cin, line);vector<int> prices;stringstream ss(line);string token;while (getline(ss, token, ',')) {prices.push_back(stoi(token));}sort(prices.begin(), prices.end()); // 排序以便剪枝和去重vector<vector<int>> result;vector<int> path;backtrack(prices, amount, 0, path, 0, result);cout << formatResult(result) << endl;return 0;
}
代码详细解析
-
输入处理:
cin >> amount
读取金额。getline(cin, line)
读取价格行,并用stringstream
分割为整数数组。sort()
对价格排序,确保后续生成非降序组合。
-
回溯函数:
- 参数说明:
prices
:排序后的价格数组。target
:目标金额。start
:当前遍历的起始索引,避免生成逆序组合。path
:当前路径(组合)。sum
:当前路径的和。result
:结果集。
- 终止条件:当
sum == target
时,将路径存入结果。 - 剪枝优化:若当前价格导致总和超限,终止循环(
break
)。 - 路径管理:递归前
push_back
,递归后pop_back
恢复状态。
- 参数说明:
-
结果格式化:
- 处理空结果返回
[]
。 - 使用嵌套循环将每个组合转换为字符串,符合题目要求的二维数组格式。
- 处理空结果返回
示例测试
示例1输入:
500
100,200,300,500
输出:
[[100,100,100,100,100],[100,100,100,200],[100,100,300],[100,200,200],[200,300],[500]]
解析:
- 排序后价格为
[100,200,300,500]
。 - 回溯生成所有非降序组合,如
[100×5]
、[100×3+200]
等。
示例2输入:
100
100
输出:
解析:
- 唯一可能的组合是
[100]
,直接命中目标金额。
综合分析
-
时间复杂度:O(2ⁿ)
- 最坏情况下需遍历所有组合,但通过剪枝大幅减少实际计算量。
- 示例1中剪枝跳过所有无效路径(如
100×6
)。
-
空间复杂度:O(n²)
- 递归栈深度为 O(n),结果存储空间为 O(k·m),k为组合数,m为平均组合长度。
-
优势:
- 去重机制:固定遍历起点,保证组合非降序。
- 剪枝优化:提前终止无效路径,提升效率。
-
适用场景:
- 价格列表长度 ≤ 30 的中小规模数据。
- 需要精确枚举所有可能性的场景,如商品组合推荐。
C语言
问题分析
我们需要找到所有可能的价格组合,使得它们的总和等于给定的金额。每个价格可以重复使用,组合需按非降序排列以避免重复。
解题思路
- 排序预处理:将价格数组排序,确保组合按非降序生成。
- 回溯算法(DFS):递归遍历所有可能的组合,记录满足条件的组合。
- 剪枝优化:当当前路径的和超过目标金额时,停止进一步搜索。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义动态数组结构体(存储结果集)
typedef struct {int **data; // 二维数组存储组合int *sizes; // 每个组合的长度int capacity; // 当前分配的容量int size; // 实际元素数量
} ResultList;// 初始化结果集
ResultList* createResultList(int initialCapacity) {ResultList *list = malloc(sizeof(ResultList));list->data = malloc(initialCapacity * sizeof(int*));list->sizes = malloc(initialCapacity * sizeof(int));list->capacity = initialCapacity;list->size = 0;return list;
}// 向结果集中添加组合
void addToResult(ResultList *list, const int *path, int pathSize) {if (list->size >= list->capacity) { // 扩容list->capacity *= 2;list->data = realloc(list->data, list->capacity * sizeof(int*));list->sizes = realloc(list->sizes, list->capacity * sizeof(int));}// 复制路径数据int *newPath = malloc(pathSize * sizeof(int));memcpy(newPath, path, pathSize * sizeof(int));list->data[list->size] = newPath;list->sizes[list->size] = pathSize;list->size++;
}// 释放结果集内存
void freeResultList(ResultList *list) {for (int i = 0; i < list->size; i++) {free(list->data[i]);}free(list->data);free(list->sizes);free(list);
}// 回溯函数
void backtrack(int *prices, int pricesSize, int target, int start, int *path, int pathSize, int currentSum, ResultList *result) {if (currentSum == target) {addToResult(result, path, pathSize);return;}for (int i = start; i < pricesSize; i++) {if (currentSum + prices[i] > target) break; // 剪枝path[pathSize] = prices[i]; // 添加当前价格backtrack(prices, pricesSize, target, i, path, pathSize + 1, currentSum + prices[i], result);}
}// 比较函数(用于排序)
int compare(const void *a, const void *b) {return (*(int*)a - *(int*)b);
}// 格式化输出结果
void formatResult(ResultList *result) {if (result->size == 0) {printf("[]\n");return;}printf("[");for (int i = 0; i < result->size; i++) {printf("[");for (int j = 0; j < result->sizes[i]; j++) {printf("%d", result->data[i][j]);if (j != result->sizes[i] - 1) printf(",");}printf("]");if (i != result->size - 1) printf(", ");}printf("]\n");
}int main() {// 读取输入int amount;scanf("%d", &amount);getchar(); // 读取换行符char line[1000];fgets(line, sizeof(line), stdin);line[strcspn(line, "\n")] = '\0'; // 去除换行符// 分割字符串为价格数组int prices[100];int pricesSize = 0;char *token = strtok(line, ",");while (token != NULL) {prices[pricesSize++] = atoi(token);token = strtok(NULL, ",");}// 排序价格数组qsort(prices, pricesSize, sizeof(int), compare);// 初始化结果集和路径ResultList *result = createResultList(10);int *path = malloc(100 * sizeof(int)); // 路径最大长度设为100backtrack(prices, pricesSize, amount, 0, path, 0, 0, result);formatResult(result);// 释放内存free(path);freeResultList(result);return 0;
}
代码详细解析
- 动态数组结构体:
ResultList
用于存储所有找到的组合,包含二维数组、各组合长度、容量和实际大小。 - 内存管理函数:
createResultList
:初始化结果集,预分配内存。addToResult
:动态扩容并复制路径数据。freeResultList
:递归释放所有内存。
- 回溯函数:
- 通过
path
数组记录当前组合,pathSize
记录当前组合长度。 - 剪枝逻辑:若当前和超过目标,终止后续循环。
- 通过
- 输入处理:
- 用
fgets
读取价格行,分割为整数数组。 - 使用
qsort
对价格排序。
- 用
- 格式化输出:遍历结果集,按题目要求拼接字符串。
示例测试
示例1输入:
500
100,200,300,500
输出:
[[100,100,100,100,100],[100,100,100,200],[100,100,300],[100,200,200],[200,300],[500]]
解析:
- 排序后价格为
[100,200,300,500]
。 - 回溯生成所有非降序组合,如
[100×5]
、[100×3+200]
等。
示例2输入:
100
100
输出:
解析:
- 唯一可能的组合是
[100]
,直接命中目标金额。
综合分析
- 时间复杂度:O(2ⁿ)
- 最坏情况需遍历所有组合,剪枝大幅减少实际计算量。
- 空间复杂度:O(k·m)
- 结果集存储所有组合,k为组合数,m为平均组合长度。
- 优势:
- 手动内存管理:精准控制内存分配,适合嵌入式场景。
- 高效剪枝:通过排序和提前终止优化性能。
- 适用场景:
- 需要严格内存控制的系统。
- 中小规模数据(价格数量≤100)。
GO
问题分析
我们需要找到所有可能的价格组合,使得它们的总和等于给定的金额。每个价格可以重复使用,组合需按非降序排列以避免重复。例如,给定金额 500
和价格列表 [100,200,300,500]
,组合 [100,100,300]
是有效的,而 [300,100,100]
被视为重复。
解题思路
- 排序预处理:将价格数组排序,确保后续生成的组合按非降序排列。
- 回溯算法(DFS):递归遍历所有可能的组合,记录满足条件的组合。
- 剪枝优化:当当前路径的和超过目标金额时,停止进一步搜索。
- 路径管理:通过切片动态管理当前路径,回溯时恢复状态。
代码实现
package mainimport ("bufio""fmt""os""sort""strconv""strings"
)func main() {// 读取输入scanner := bufio.NewScanner(os.Stdin)scanner.Scan()amount, _ := strconv.Atoi(scanner.Text())scanner.Scan()pricesStr := strings.Split(scanner.Text(), ",")// 转换为整数并排序prices := make([]int, len(pricesStr))for i, s := range pricesStr {prices[i], _ = strconv.Atoi(strings.TrimSpace(s))}sort.Ints(prices)// 回溯搜索var result [][]intbacktrack(prices, amount, 0, []int{}, 0, &result)// 格式化输出fmt.Println(formatResult(result))
}// 回溯函数
func backtrack(prices []int, target, start int, path []int, sum int, result *[][]int) {if sum == target {// 深拷贝当前路径,避免后续修改影响结果newPath := make([]int, len(path))copy(newPath, path)*result = append(*result, newPath)return}for i := start; i < len(prices); i++ {price := prices[i]if sum+price > target {break // 剪枝:后续价格更大,无需继续}// 添加当前价格到路径path = append(path, price)backtrack(prices, target, i, path, sum+price, result)// 回溯:移除最后添加的价格path = path[:len(path)-1]}
}// 结果格式化函数
func formatResult(result [][]int) string {if len(result) == 0 {return "[]"}str := "["for i, combo := range result {str += "["for j, num := range combo {str += strconv.Itoa(num)if j < len(combo)-1 {str += ","}}str += "]"if i < len(result)-1 {str += ", "}}str += "]"return str
}
代码详细解析
1. 输入处理
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
amount, _ := strconv.Atoi(scanner.Text())
- 使用
bufio.Scanner
逐行读取输入。 - 第一行转换为整数金额
amount
。
pricesStr := strings.Split(scanner.Text(), ",")
prices := make([]int, len(pricesStr))
for i, s := range pricesStr {prices[i], _ = strconv.Atoi(strings.TrimSpace(s))
}
sort.Ints(prices)
- 第二行分割为字符串数组,转换为整数切片。
- 对价格排序,确保后续生成非降序组合。
2. 回溯函数
func backtrack(prices []int, target, start int, path []int, sum int, result *[][]int) {if sum == target {newPath := make([]int, len(path))copy(newPath, path)*result = append(*result, newPath)return}// 循环逻辑...
}
- 参数说明:
prices
:排序后的价格列表。target
:目标金额。start
:当前搜索的起始索引(避免重复组合)。path
:当前路径(组合)。sum
:当前路径的总和。result
:存储结果的切片指针。
for i := start; i < len(prices); i++ {price := prices[i]if sum+price > target {break // 剪枝}path = append(path, price)backtrack(prices, target, i, path, sum+price, result)path = path[:len(path)-1] // 回溯
}
- 剪枝逻辑:若当前价格导致总和超限,终止后续循环。
- 路径管理:递归前添加价格到路径,递归后移除(回溯)。
3. 结果格式化
func formatResult(result [][]int) string {// 拼接字符串逻辑...
}
- 处理空结果返回
[]
。 - 使用嵌套循环将每个组合转换为目标格式的字符串。
示例测试
示例1输入:
500
100,200,300,500
输出:
[[100,100,100,100,100],[100,100,100,200],[100,100,300],[100,200,200],[200,300],[500]]
解析:
- 排序后价格为
[100,200,300,500]
。 - 递归过程:
- 选择
100
5次 →[100×5]
。 - 选择
100
3次后选200
→[100×3,200]
。 - 其他组合类似,最终输出所有非降序组合。
- 选择
示例2输入:
100
100
输出:
解析:
- 唯一可能的组合是
[100]
,直接命中目标金额。
综合分析
-
时间复杂度:
- 最坏情况:O(2ⁿ),其中 n 为价格列表长度。
- 剪枝优化后:实际运行时间远小于理论值,例如示例1中跳过所有
price > 500
的路径。
-
空间复杂度:
- 递归栈:O(n),取决于价格列表长度。
- 结果存储:O(k·m),k 为组合数,m 为平均组合长度。
-
优势:
- 避免重复组合:通过排序和固定起始索引
start
实现。 - 内存高效:Go 的切片动态扩容机制减少内存浪费。
- 避免重复组合:通过排序和固定起始索引
-
适用场景:
- 价格数量 ≤ 100 的中小规模数据。
- 需要精确枚举所有可能性的场景(如商品推荐系统)。
扩展
Go语言特性带来的优势:
- 切片动态管理:无需手动处理数组扩容,简化代码。
- 值传递与指针:通过指针传递结果切片,避免深拷贝开销。
- 内置排序函数:
sort.Ints
一行代码完成排序。
潜在改进方向:
- 并行计算:利用
goroutine
分割搜索空间,加速大规模数据处理。 - 内存池优化:预分配结果切片内存,减少动态扩容次数。
- 字典树剪枝:对价格列表构建前缀树,进一步优化剪枝逻辑。
更多内容:
https://www.kdocs.cn/l/cvk0eoGYucWA
本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!
相关文章:
华为OD机试真题——硬件产品销售方案(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 华为OD机试真题《硬件产品销售方案》: 目录 题目名称࿱…...
鸿蒙应用元服务开发-Account Kit未成年人模式订阅和处理用户信息变更
一、概述 通过订阅用户信息变更,您可以接收有关用户及其账户的重要更新。当用户取消元服务的授权信息、注销华为账号时,华为账号服务器会发送通知到元服务,元服务可以根据通知消息进行自身业务处理。 二、用户信息变更事件介绍 三、订阅用…...
优化 Dockerfile 性能之实践(Practice of Optimizing Dockerfile Performance)
优化 Dockerfile 性能之实践 构建 Docker 镜像时,Dockerfile 的性能会显著影响构建过程的效率。经过优化的 Dockerfile 可以缩短构建时间、最小化镜像大小并提高整体容器性能。在本文中,我们将探讨优化 Dockerfile 性能的最佳实践。 尽量减少层数 影响…...
OpenShift介绍,跟 Kubernetes ,Docker关系
1. OpenShift 简介 OpenShift是一个开源项目,基于主流的容器技术Docker及容器编排引擎Kubernetes构建。可以基于OpenShift构建属于自己的容器云平台。OpenShift的开源社区版本叫OpenShift Origin,现在叫OKD。 OpenShift 项目主页:https://www.okd.io/。OpenShift GitHub仓库…...
Go:包和 go 工具
引言 通过对关联特性分类,组成便于理解和修改的单元,使包与程序其他包保持独立,助力大型程序的设计与维护 。模块化让包可在不同项目共享、复用、发布及全球范围使用。 每个包定义不同命名空间作为标识符,关联具体包,…...
GIS开发笔记(5)结合osg及osgEarth实现虚线环形区域绘制
一、实现效果:输入中点坐标点、内圆半径、外圆半径,绘制坐标点所在高度的水平面的两个圆形形成环形区域。 二、实现原理: 创建中心点所在平面的圆形几何体,将其分别挂接到同一个节点上,再将该节点挂接到用户绘制组节…...
天线静电防护:NRESDTLC5V0D8B
一. 物联网天线的使用环境 1.1 联网天线广泛应用于智能家居领域,比如智能门锁、智能摄像头等设备中,通过天线实现设备与家庭网络的连接,用户可以远程控制和监控家居设备。以智能摄像头为例,它通过天线将拍摄的画面实时传输到用户…...
Linux进程相关选择题及解析
1. 关于Linux进程创建,以下说法正确的是? A. fork()函数调用后,子进程从父进程的fork()之后开始执行 B. fork()函数返回两次,父进程返回子进程PID,子进程返回0[10][11] C. exec函数族会替换当前进程的代码段,但保留数据段和堆栈 D. wait()函数只能等待直接子进程退出 答…...
Day(22)--网络编程习题
习题 以下是这些 TCP 通信练习题的 Java 代码实现及解析: TCP 通信练习 1 - 多发多收 客户端(Client1.java) java import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class Client1 {public…...
Kubernetes 节点摘除指南
目录 一、安全摘除节点的标准流程 1. 确认节点名称及状态 2. 标记节点为不可调度 3. 排空(Drain)节点 4. 删除节点 二、验证节点是否成功摘除 1. 检查节点列表 2. 检查节点详细信息 3. 验证 Pod 状态 三、彻底清理节点(可选…...
SM4密码算法的CPA攻击技术
SM4算法简介 可参见博文 SM4分组密码算法研究。 SM4密码算法的CPA攻击技术 相关功耗攻击(CPA)是侧信道功耗分析攻击中较为常见的攻击方法之一,攻击者利用密码算法执行过程中,在侧信道泄露的信息(如时序、能量、缓存等)和通信信道的消息(如明文、私钥等)进行测试,通过…...
Golang|KVBitcask
文章目录 初识KVbitcask论文详解 初识KV bitcask论文详解 论文地址:https://riak.com/assets/bitcask-intro.pdf理想的存储引擎,应该满足下面一些特点:...
【Python进阶】元组:不可变序列的十大核心应用
目录 前言:技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现(10个案例)案例1:基础创建与访问案例2:解包…...
centos安装libheif
参考 解决docker: Error response from daemon: Get “https://registry-1.docker.io/v2/“:连接超时问题_error response from daemon :get-CSDN博客 HEIF编解码器安装 - navyum - 博客园 https://github.com/strukturag/libheif #升级gcc yum install centos…...
初步认识Model Context Protocol (MCP) Java SDK
1. Maven如何下载MCP Java SDK 基础配置(核心模块) 在您的pom.xml文件中添加以下依赖: <dependencyManagement> <dependencies> <dependency> <groupId>io.modelcontextprotocol.sdk</groupId> <artifactI…...
第三章 爬虫提速、selenium模块、requests模块进阶(终)
目录 一.requests进阶 (一)处理cookie (二)防盗链 (三)代理 二.爬虫提速 (一)线程池和进程池 (二)协程 (三)异步http请求-aio…...
unity使用内建组件给刚体增加重力
2019年3月9日11:10:24 unity开发中,有时候发现刚体上的重力不能满足我们的需要,可以通过使用内建组件Constant Force来增加重力: 在游戏对象上。请按照以下操作: 为Player添加一个名为Constant Force组件,选择Player在…...
Java开发中的设计模式之观察者模式详细讲解
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。这种模式在Java开发中非常常见,尤其是在事件驱…...
【学习笔记】计算机网络(九)—— 无线网络和移动网络
第9章 无线网络和移动网络 文章目录 第9章 无线网络和移动网络9.1 无线局域网WLAN9.1.1 无线局域网的组成9.1.2 802.11局域网的物理层9.1.3 802.11局域网的MAC层协议CSMA 协议CSMA/CD 协议 - 总线型 - 半双工CSMA/CA 协议 9.1.4 802.11局域网的MAC帧 9.2 无线个人区域网WPAN9.3…...
一个基于Django的写字楼管理系统实现方案
一个基于Django的写字楼管理系统实现方案 用户现在需要我用Django来编写一个写字楼管理系统的Web版本,要求包括增删改查写字楼的HTML页面,视频管理功能,本地化部署,以及人员权限管理,包含完整的代码结构和功能实现&am…...
C++面试考点:类(class)
1、类的定义 C中的类提供了面向对象编程、继承与多态的机制。其构成包括成员(各种自定义数据)、行为(定义的函数操作)、封装(private、public、protected)。核心是了解类的继承机制,以及各种封装…...
ThreadPoolExecutor 多线程用requests请求一个地址的时候为什么会报错,而多进程用requests请求一个地址的时候不会报错,为什么?
网络请求行为 多线程:requests 库底层依赖 urllib3,而 urllib3 使用连接池管理网络请求。在多线程环境中,连接池可能会因为线程间的竞争导致连接泄漏或超时。 多进程:每个进程独立管理自己的连接池,因此不会出现线程间…...
数据库脱裤
假设你已经getshell 找到mysql账号密码。 网站要连接mysql,就需要把mysql的账号密码保存在一个php文件中,类似config.php、common.inc.php等,在shell中,读取这些文件,找到其中信息即可 下面是一些常见平台的配置文…...
十二,<FastApi>中间件
什么是中间件? "中间件"是一个函数,它在每个请求被特定的路径操作处理之前,以及在每个响应之后工作. 代码示例: from fastapi import FastAPI, Response from fastapi import Request import uvicornapp FastAPI()app.middleware("http") async def m2…...
欢迎使用Markdown编辑器
使用Markdown编辑器 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注…...
RabbitMQ架构原理及消息分发机制
RabbitMQ架构原理及消息分发机制 在现代分布式系统中,消息队列是不可或缺的组件之一。它不仅能够解耦系统模块,还能实现异步通信和削峰填谷。在众多消息队列中,RabbitMQ 因其高并发、高可靠性和丰富的功能而备受青睐。本文将从 RabbitMQ 的基…...
智能麻将出牌组件
开篇引言 麻将作为一款风靡全球的策略性游戏,其复杂的规则和多变的牌局给玩家带来了无尽乐趣。在数字化时代,运用编程技术为麻将游戏赋予智能,实现自动出牌功能,不仅能提升玩家体验,还能深入探索算法在博弈游戏中的…...
python脚本补充
本文是对实用的 Python 小脚本_python写脚本-CSDN博客的一点补充。对简单脚本的一些操作上的优化。 ###Utilities ### ###重命名文件名 import os import tkinter as tk from tkinter import filedialog, simpledialog, messageboxdef batch_rename():# 弹出文件夹选择对话框d…...
【经验记录贴】活用shell,提高工作效率
背景 最近在做测试的时候,需要手动kill服务的进程,然后通过命令重启服务,再进行测试。每次重启都会涉及到下面三个命令的执行: 1)检索进程ID $ ps -elf | grep programname root 1123 112 1234 0 0 0 0:00…...
出现 ERR_CERT_COMMON_NAME_INVALID | 301 302 重定向的解决方法
目录 前言1. 问题所示2. 原理分析3. 解决方法前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 爬虫神器,无代码爬取,就来:bright.cn 1. 问题所示 执行代码时,出现如下提示: GET https://xxxx/admin-api/system...
解决本地浏览器访问服务器端语音识别项目显示“麦克风未授权”的问题
解决本地浏览器访问服务器端语音识别项目显示“麦克风未授权”的问题 在 chrome://flags 启用特殊权限(不推荐长期启用) 在浏览器地址栏输入: chrome://flags然后搜索: Insecure origins treated as secure 找到类似项ÿ…...
【数论】线性筛质数
线性筛质数 在之前的一篇筛质数的文章中只解释了埃式筛质数的方法,没有解释线性筛质数的方法 我们先看一下线性筛质数的代码 【例题】 给定一个正整数 n,请你求出 1∼n 中质数的个数。 输入格式 共一行,包含整数 n。 输出格式 共一行…...
视频孪生重构施工逻辑:智慧工地的数字化升级
当"智慧工地"概念在2017年首次写入《建筑业发展"十三五"规划》时,行业普遍将其等同于摄像头与传感器的简单叠加。十年数字浪潮冲刷下,智慧工地的内涵已发生本质跃迁:从工具层面的信息化改造,进化为基于视频数…...
【Lerobot】加载本地数据LeRobotDataset数据、读取并解析parquet
官方例子:https://github.com/huggingface/lerobot/blob/main/examples/1_load_lerobot_dataset.py https://github.com/NVIDIA/Isaac-GR00T/blob/main/getting_started/LeRobot_compatible_data_schema.md 使用SO100机械臂进行数据采集后,得到如下格式…...
卷积神经网络 CNN 模型介绍
卷积神经网络 CNN 模型介绍 一、经典CNN模型1. LeNet-5(基础模型)2. AlexNet3. VGGNet(VGG16/VGG19)4. ResNet(残差网络) 二、轻量化CNN模型1. MobileNet系列2. EfficientNet3. ShuffleNet 三、改进型CNN模…...
Vue —— 实用的工具函数
目录 响应式数据管理1. toRef 和 torefs2. shallowRef 和 shallowReactive3. markRaw 依赖追踪与副作用1. computed2. watch 和 watchEffect 类型判断与优化1. unref2. isRef 、isReactive 和 isProxy 组件通信与生命周期1. provide 和 inject2. nextTick 高级工具1. useAttrs …...
Langchain + Gemini API调用基本操作
本文参考Langchain中ChatGoogleGenerativeAI的官方文档,在本地的jupyter notebook中运行。 关于API的细节在官方文档最开头给出: 我们在使用时,可以选择model"gemini-2.0-flash-001"或者生成图片的ChatGoogleGenerativeAI(model“…...
软件线上故障复盘报告
软件线上故障复盘报告 故障编号:INC-2024XXX 复盘日期:YYYY-MM-DD 参与人员:研发/运维/测试/产品/客服负责人 一、故障概况 1.1 基础信息 字段内容数据来源故障等级P0/P1/P2(参考SLA分级标准)运维告警…...
分享:批量提取图片文字并自动命名文件,ocr识别图片指定区域并重命名文件名工具,基于WPF和腾讯OCR识别的接口的视线方案
一、项目背景 在处理大量图片时,常常需要从图片中提取特定区域的文字信息,并依据这些信息对图片进行重命名。例如,在档案管理领域,大量纸质文件被扫描成图片后,需要从图片中提取关键信息(如文件编号、日期等)来重命名图片,以便后续的检索和管理;在电商领域,商家可能…...
SIMULIA-Abaqus有限元分析软件针对汽车行业的解决方案
汽车行业是Abaqus软件的一个重要应用领域,许多知名的汽车企业都是Abaqus的用户,本文为您重点介绍Abaqus针对汽车行业有哪些应用及其解决方案。 Abaqus是一款什么软件: Abaqus公司是世界知名的计算机仿真行业的软件公司,成立于197…...
linux下使用php修改php.ini的session.save_path无效的解决办法
linux下安装php的组合还是php-fpm和nginx,其实已经安装好了,网站已经能够跑起来了,但是遇到后台登录的时候验证码一直不对,看了下报错,session无法存储,于是新增了一个phpinfo文件,使用web查看下…...
脚本-QQ批量发送消息(图片和文字)
目录 代码 代码功能详解 注意事项 致谢 代码 import io import traceback import win32clipboard import pyautogui import pyperclip import win32gui # 替换为pywin32的正确模块名 import pandas as pd import time from PIL import Imageclass QQAutoMessage:def __in…...
高等数学A1 期末救济(导数)
基于song复习 闭区间上连续函数的性质 在闭区间里,f(x)连续> f(x)有界 导数 导数三种定义及不同写法 常用导数公式 可导→连续,但连续❎→可导 切线类问题求解 求某点切线方程与求过某点的切线方程 反函数求导法则 反函数的导数直接函数导数的导数 例…...
前端VUE框架理论与应用(7)
一、用 v-for 把一个数组对应为一组元素 我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。 在 v-for 块中,我们可以访问所有父作用域的属性。v-for 还…...
argparse
argparse.add_argument 完全指南 🧱 基础篇:命令行参数解析入门 1. 模块初始化 import argparse# 创建参数解析器(所有操作的基础容器) parser argparse.ArgumentParser( progMyApp, # 程序名称(默认从sys.argv[0]…...
力扣-hot100(移动零)
283. 移动零 简单 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输…...
优先级队列的实模拟实现
优先级队列底层默认用的是vector来存储数据,实现了类似我们数据结构中学习过的堆的队列,他的插入和删除都是优先级高先插入和删除。下面我们来模拟实现它们常见的接口来熟悉优先级队列。 仿函数 在介绍优先级队列之前,我们先熟悉一个概念&a…...
ES6的`class`中,`super`关键字在构造函数和非构造函数中的行为有何不同?
在 ES6 的 class 中,super 关键字的行为在 构造函数 和 非构造函数(普通方法) 中有显著区别,主要体现在以下方面: 1. 构造函数中的 super 行为规则 必须显式调用: 在子类的构造函数中,必须先调…...
从 BI 与 SQL2API 的差异,看数据技术的多元发展路径
在数据驱动的商业世界里,商业智能(BI)与 SQL2API 如同两颗闪耀的星星,各自散发着独特的光芒。BI 早已在企业中广泛应用,成为数据分析领域的中流砥柱;而 SQL2API 作为新兴技术,虽潜力巨大&#x…...
UNet脑瘤医学影像分割训练实战(PyTorch 完整代码)
UNet是一种基于卷积神经网络(CNN)的医学影像分割模型,由Ronneberger等人于2015年提出。本文我们将简要介绍基于PyTorch框架,使用UNet模型在脑瘤医学影像分割数据集上进行训练,同时通过SwanLab监控训练过程,…...