算法思路汇总:77. 组合

145 阅读1分钟

77.组合

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

难度:mid 来源:力扣(LeetCode)

题目:

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

示例 2:

输入:n = 1, k = 1 输出:[[1]]

提示:

1 <= n <= 20 1 <= k <= n

思路:

回溯算法类似于树,所以我们可以利用树中的 dfs 和 bfs 进行解决问题。

首先明确两点:

  1. 组合是不强调元素顺序的,排列是强调元素顺序

  2. 集合的大小就构成了树的宽度,递归的深度,构成树的深度

根据题意知需要返回满足k大小的区间组合;所以我们需要建立两个集合:

List<List<Integer>> res = new ArrayList<>();
​
LinkedList<Integer> path = new LinkedList<>();

其中 res 为保存k区间的集合组合结果,path保存路径且区间大小需要满足k的范围。

path采用的数据类型为 LinkedList ,使用该类型可以在回溯恢复现场的时候直接删除最后一个添加的元素,比较方便。

在递归的时候需要考虑以下问题:

  1. 递归的终止条件
  2. 怎样进行路径的遍历

其实递归的终止条件比较好考虑,当path.size大小满足k范围,就把当前符合的path加入到res结果集中:

if(path.size() == k){
    res.add(new ArrayList<>(path));
    return;
}

然后开始递归遍历子树:

子树的个数为n的大小,可以采用for循环:

遍历为1的子树:index = 1;会递归n-index次。

for(int i = index; i <= n; i++){
    path.add(i);
    backtracking(n,k,i+1);
    path.removeLast();
}

这里我们通过index来控制在集合中选取元素的范围。

完整代码:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {    
        backtracking(n,k,1);
        return res;
    }
    void backtracking(int n,int k,int index){
        if(path.size() == k){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i = index; i <= n; i++){
            path.add(i);
            backtracking(n,k,i+1);
            path.removeLast();
        }
    }
}

调试代码如下:

package com.lc;
​
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
​
public class lc77 {
    static List<List<Integer>> res = new ArrayList<>();
    static LinkedList<Integer> path = new LinkedList<>();
    public static void main(String[] args) {
        List<List<Integer>> combine = combine(4, 2);
        for(List<Integer> temp : combine){
            for(int i : temp){
                System.out.print(i+" ");
            }
            System.out.println();
        }
    }
    public static List<List<Integer>> combine(int n, int k) {
        backtracking(n,k,1);
        return res;
    }
    static void backtracking(int n, int k, int index){
        if(path.size() == k){
            res.add(new ArrayList<>(path));
            return;
        }
        //类似树的宽度
        for(int i = index; i <= n; i++){
            path.add(i);
            //递归深度,类似树的高度
            backtracking(n,k,i+1);
            path.removeLast();
        }
    }
}

在此附赠dubug调试视频可供参考:点击进入