【算法】剑指 Offer II 081. 允许重复选择元素的组合(多语言实现)

87 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情


剑指 Offer II 081. 允许重复选择元素的组合:

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。

candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的唯一组合数少于 150 个。

样例 1:

输入: 
	candidates = [2,3,6,7], target = 7
	
输出: 
	[[7],[2,2,3]]

样例 2:

输入: 
	candidates = [2,3,5], target = 8
	
输出: 
	[[2,2,2,2],[2,3,3],[3,5]]

样例 3:

输入: 
	candidates = [2], target = 1
	
输出: 
	[]

样例 4:

输入: 
	candidates = [1], target = 1
	
输出: 
	[[1]]

样例 5:

输入: 
	candidates = [1], target = 2
	
输出: 
	[[1,1]]

提示:

  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200
  • candidate 中的每个元素都是独一无二的。
  • 1 <= target <= 500

分析

  • 面对这道算法题目,二当家的陷入了沉思。
  • 最直观的方式就是递归套娃大法了。
  • 每个数字都可以选择,或者不选择。
  • 需要注意的就是每个数字都是可以重复选择的,由于是组合,所以我们就遍历数组,按顺序选择(选择当前数字或者跳过当前数字),直到和大于等于目标值。

题解

rust

impl Solution {
    pub fn combination_sum(candidates: Vec<i32>, target: i32) -> Vec<Vec<i32>> {
        fn dfs(candidates: &Vec<i32>, target: i32, idx: usize, row: &mut Vec<i32>, ans: &mut Vec<Vec<i32>>) {
            if target == 0 {
                // 符合条件的一个组合
                ans.push(row.clone());
                return;
            }
            if idx >= candidates.len() {
                // 尝试到底,开始回溯
                return;
            }
            // 跳过当前下标数字
            dfs(candidates, target, idx + 1, row, ans);
            // 选择当前下标数字
            if target - candidates[idx] >= 0 {
                row.push(candidates[idx]);
                dfs(candidates, target - candidates[idx], idx, row, ans);
                row.pop();
            }
        }

        let mut ans = Vec::new();
        dfs(&candidates, target, 0, &mut Vec::new(), &mut ans);
        ans
    }
}

go

func combinationSum(candidates []int, target int) [][]int {
    var ans [][]int

    var dfs func(int, int, []int, int)
    dfs = func(target int, idx int, row []int, rowSize int) {
        if target == 0 {
                // 符合条件的一个组合
                ans = append(ans, append([]int{}, row[0:rowSize]...))
                return
        }
        if idx >= len(candidates) {
                // 尝试到底,开始回溯
                return
        }
        // 跳过当前下标数字
        dfs(target, idx+1, row, rowSize)
        // 选择当前下标数字
        if target-candidates[idx] >= 0 {
                row[rowSize] = candidates[idx]
                dfs(target-candidates[idx], idx, row, rowSize+1)
        }
    }

    dfs(target, 0, make([]int, target), 0)

    return ans
}

typescript

function combinationSum(candidates: number[], target: number): number[][] {
    function dfs(target: number, idx: number, row: number[]) {
        if (target == 0) {
            // 符合条件的一个组合
            ans.push([...row]);
            return;
        }
        if (idx >= candidates.length) {
            // 尝试到底,开始回溯
            return;
        }
        // 跳过当前下标数字
        dfs(target, idx + 1, row);
        // 选择当前下标数字
        if (target - candidates[idx] >= 0) {
            row.push(candidates[idx]);
            dfs(target - candidates[idx], idx, row);
            row.pop();
        }
    }

    const ans = [];
    dfs(target, 0, []);
    return ans;
};

python

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        ans = []

        def dfs(target: int, idx: int, row: List[int]):
            if target == 0:
                # 符合条件的一个组合
                ans.append(row.copy())
                return
            if idx >= len(candidates):
                # 尝试到底,开始回溯
                return
            # 跳过当前下标数字
            dfs(target, idx + 1, row)
            # 选择当前下标数字
            if target - candidates[idx] >= 0:
                row.append(candidates[idx])
                dfs(target - candidates[idx], idx, row)
                row.pop()

        dfs(target, 0, [])
        return ans


c

void dfs(int *candidates, int candidatesSize, int target, int idx, int *row, int rowSize, int **ans, int *returnSize,
         int **returnColumnSizes) {
    if (target == 0) {
        // 符合条件的一个组合
        ans[*returnSize] = (int *) malloc(sizeof(int) * rowSize);
        memcpy(ans[*returnSize], row, sizeof(int) * rowSize);
        (*returnColumnSizes)[*returnSize] = rowSize;
        ++(*returnSize);
        return;
    }
    if (idx >= candidatesSize) {
        // 尝试到底,开始回溯
        return;
    }
    // 跳过当前下标数字
    dfs(candidates, candidatesSize, target, idx + 1, row, rowSize, ans, returnSize, returnColumnSizes);
    // 选择当前下标数字
    if (target - candidates[idx] >= 0) {
        row[rowSize] = candidates[idx];
        dfs(candidates, candidatesSize, target - candidates[idx], idx, row, rowSize + 1, ans, returnSize,
            returnColumnSizes);
    }
}

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int **combinationSum(int *candidates, int candidatesSize, int target, int *returnSize, int **returnColumnSizes) {
    *returnSize = 0;
    *returnColumnSizes = (int *) malloc(sizeof(int) * 150);
    int **ans = (int **) malloc(sizeof(int *) * 150);
    int row[target];
    dfs(candidates, candidatesSize, target, 0, row, 0, ans, returnSize, returnColumnSizes);
    return ans;
}

c++

class Solution {
private:
    void dfs(vector<int>& candidates, int target, int idx, vector<int>& row, vector<vector<int>>& ans) {
        if (target == 0) {
            // 符合条件的一个组合
            ans.emplace_back(row);
            return;
        }
        if (idx >= candidates.size()) {
            // 尝试到底,开始回溯
            return;
        }
        // 跳过当前下标数字
        dfs(candidates, target, idx + 1, row, ans);
        // 选择当前下标数字
        if (target - candidates[idx] >= 0) {
            row.emplace_back(candidates[idx]);
            dfs(candidates, target - candidates[idx], idx, row, ans);
            row.pop_back();
        }
    }
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ans;
        vector<int> row;
        dfs(candidates, target, 0, row, ans);
        return ans;
    }
};

java

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ans = new ArrayList<>();
        this.dfs(candidates, target, 0, new LinkedList<>(), ans);
        return ans;
    }

    private void dfs(int[] candidates, int target, int idx, Deque<Integer> row, List<List<Integer>> ans) {
        if (target == 0) {
            // 符合条件的一个组合
            ans.add(new ArrayList<>(row));
            return;
        }
        if (idx >= candidates.length) {
            // 尝试到底,开始回溯
            return;
        }
        // 跳过当前下标数字
        this.dfs(candidates, target, idx + 1, row, ans);
        // 选择当前下标数字
        if (target - candidates[idx] >= 0) {
            row.addLast(candidates[idx]);
            this.dfs(candidates, target - candidates[idx], idx, row, ans);
            row.pollLast();
        }
    }
}

原题传送门:https://leetcode.cn/problems/Ygoe9J/submissions/


非常感谢你阅读本文~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://juejin.cn/user/2771185768884824/posts 博客原创~