Middle-题目35:77. Combinations

本文介绍了一个经典的组合生成问题,即从1到n中选择k个数的所有可能组合,并提供了详细的Java实现代码。采用回溯法解决该问题,通过递归函数进行搜索。

题目原文:
Given two integers n and k, return all possible combinations of k numbers out of 1 … n.
For example,
If n = 4 and k = 2, a solution is:

[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

题目大意:
给出两个正整数n和k,求从1~n中取k个数的所有组合方式。
题目分析:
还是一个回溯法,用backtrack(List<List<Integer>> list, List<Integer> sublist, int n, int k, int start,int totaln)函数维护搜索过程,list代表最终返回结果,sublist记录当前搜索路径,n记录当前还有几个数要搜索,k记录当前还要取几个数,start记录当前要搜索的第一个数,totaln一直维持问题最开始的n。
这样递归关系是,每找到一个数字i, n=totaln-i(因为继续搜索的时候只需从i+1开始找),k=k-1,start=i+1.
一直找到k=0的时候搜索结束。
源码:(language:java)

public class Solution {
    public static List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        backtrack(list,new ArrayList<Integer>(),n,k,1,n);
        return list;
    }
    private static void backtrack(List<List<Integer>> list, List<Integer> sublist, int n, int k, int start,int totaln) {
        if(k == 0) 
            list.add(new ArrayList<Integer>(sublist));
        else {
            for(int i = start;i < start + n;i++) {
                sublist.add(i);
                backtrack(list,sublist,totaln-i,k-1,i+1,totaln);
                sublist.remove(sublist.size()-1);
            }
        }
    }
}

成绩:
3ms,beats 50.28%,众数3ms,37.00%
cmershen的碎碎念:
本题似乎还可以简化一个变量。

#include <iostream> #include <vector> #include <cmath> #include <algorithm> // 定义点的结构体 struct Point { double x; double y; }; // 计算两点之间的距离 double distance(const Point& p1, const Point& p2) { return std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } // 计算小狗能打到小猫的所有组合 std::vector<std::vector<int>> calculateCombinations(const std::vector<Point>& dogs, const std::vector<double>& dogRanges, const std::vector<Point>& cats) { std::vector<std::vector<int>> combinations(dogs.size()); for (size_t i = 0; i < dogs.size(); ++i) { for (size_t j = 0; j < cats.size(); ++j) { if (distance(dogs[i], cats[j]) <= dogRanges[i]) { combinations[i].push_back(j); } } } return combinations; } // 生成所有可能的小狗攻击小猫的组合 void generateAllCombinations(const std::vector<std::vector<int>>& dogCombinations, int dogIndex, std::vector<int>& currentCombination, std::vector<std::vector<int>>& allCombinations) { if (dogIndex == dogCombinations.size()) { allCombinations.push_back(currentCombination); return; } if (dogCombinations[dogIndex].empty()) { currentCombination.push_back(-1); generateAllCombinations(dogCombinations, dogIndex + 1, currentCombination, allCombinations); currentCombination.pop_back(); } else { for (int catIndex : dogCombinations[dogIndex]) { currentCombination.push_back(catIndex); generateAllCombinations(dogCombinations, dogIndex + 1, currentCombination, allCombinations); currentCombination.pop_back(); } } } // 计算组合的价值 int calculateValue(const std::vector<int>& combination, const std::vector<int>& catValues) { std::vector<bool> catUsed(catValues.size(), false); int totalValue = 0; for (int catIndex : combination) { if (catIndex != -1 && !catUsed[catIndex]) { totalValue += catValues[catIndex]; catUsed[catIndex] = true; } } return totalValue; } // 找到价值最大的所有组合 std::pair<int, std::vector<std::vector<int>>> findMaxValueCombinations(const std::vector<std::vector<int>>& allCombinations, const std::vector<int>& catValues) { int maxValue = 0; std::vector<std::vector<int>> maxCombinations; for (const auto& combination : allCombinations) { int value = calculateValue(combination, catValues); if (value > maxValue) { maxValue = value; maxCombinations.clear(); maxCombinations.push_back(combination); } else if (value == maxValue) { maxCombinations.push_back(combination); } } return {maxValue, maxCombinations}; } int main() { // 初始化 20 只小狗的坐标 std::vector<Point> dogs(20); for (int i = 0; i < 20; ++i) { dogs[i] = {i * 1.0, i * 1.0}; } // 初始化 20 只小狗能跑的最远距离 std::vector<double> dogRanges(20); for (int i = 0; i < 20; ++i) { dogRanges[i] = 5.0; } // 初始化 30 只小猫的坐标 std::vector<Point> cats(30); for (int i = 0; i < 30; ++i) { cats[i] = {i * 0.5, i * 0.5}; } // 初始化 30 只小猫的价值 std::vector<int> catValues(30); for (int i = 0; i < 30; ++i) { catValues[i] = i + 1; } // 计算小狗能打到小猫的所有组合 std::vector<std::vector<int>> dogCombinations = calculateCombinations(dogs, dogRanges, cats); // 生成所有可能的小狗攻击小猫的组合 std::vector<std::vector<int>> allCombinations; std::vector<int> currentCombination; generateAllCombinations(dogCombinations, 0, currentCombination, allCombinations); // 找到价值最大的所有组合 auto [maxValue, maxCombinations] = findMaxValueCombinations(allCombinations, catValues); // 输出小狗能打到小猫的所有组合 std::cout << "小狗能打到小猫的所有组合:" << std::endl; for (const auto& combination : dogCombinations) { for (int catIndex : combination) { std::cout << catIndex << " "; } std::cout << std::endl; } // 输出最大价值 std::cout << "最大价值: " << maxValue << std::endl; // 输出价值最大的所有组合 std::cout << "价值最大的所有组合:" << std::endl; for (const auto& combination : maxCombinations) { for (int catIndex : combination) { std::cout << catIndex << " "; } std::cout << std::endl; } return 0; } 运行时出现bad_alloc异常如何优化代码
10-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值