力扣46. 全排列

LeetCode相关内容
博客虽未给出具体内容,但标签显示与LeetCode相关。LeetCode是知名算法练习平台,常用于提升编程和算法能力,在信息技术领域对算法学习和求职面试有重要作用。
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        int len = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        boolean[] used = new boolean[len];
        List<Integer> path = new ArrayList<>();
        if(len == 0) return res;
        dfs(nums, len, 0, path, used, res);
        return res;
    }

    public void dfs(int[] nums, int len, int depth, List<Integer> path, boolean[] used, List<List<Integer>> res){
        // if(depth == len){
        //     res.add(path);
        //     return;
        // }
        //一次添加结束
        if (depth == len) {
            res.add(new ArrayList<>(path));
       		return;
        }
		
		//每一次for循环相当于从一个根节点上引出多个子节点,例如第一次for循环,根节点为空,决定第一个子节点选择1,2还是3.三个节点分别再递归,选择没有出现过的节点
        for(int i = 0; i < len; i++){
            if(!used[i]){
                path.add(nums[i]);
                used[i] = true;
                dfs(nums, len, depth + 1, path, used, res);
                //只是清除标记,为下for循环的下一个i服务,本质上回溯就是递归
                used[i] = false;
                path.remove(path.size() - 1);
            }
        }

    }
}

在这里插入图片描述

<think>嗯,用户想让我讲解力扣全排列的C语言代码。首先,我需要确认题目是力扣中的哪一道全排列题。全排列问题通常指LeetCode 46题,也就是给定一个不含重复数字的数组,返回所有可能的全排列。用户需要C语言的实现,但C语言在处理动态数组和返回结果时比较麻烦,我得回忆一下怎么处理。 首先,全排列的常用方法是回溯算法。回溯的基本思路是递归地尝试每一个位置的可能数字,通过交换元素来生成不同的排列。对于C语言来说,需要手动管理内存,尤其是结果数组和路径数组的分配。这可能会比较复杂,因为需要计算有多少种排列,然后分配足够的空间。 那具体的步骤应该是怎样的呢?首先确定问题规模,比如数组的长度n,全排列的数量是n!,所以结果数组的大小是n! * n。然后,每个排列需要存储n个元素。所以在C中需要动态分配一个二维数组来存储结果,同时需要一个一维数组来暂存当前的路径,或者通过交换原数组的元素来生成排列。 回溯函数需要参数:原数组、当前深度、数组大小、结果数组、返回的行数指针。每次递归到深度等于数组大小时,将当前排列存入结果。否则,从当前深度开始,依次交换元素,递归下去,再交换回来恢复状态。 不过,C语言处理二维数组和动态内存分配容易出错,需要特别注意。比如,使用指针的指针来存储结果,每个结果是一个int数组。同时,需要计算n!来确定需要分配多少行,每行n个int。这可能会涉及到计算阶乘的函数,或者通过回溯时自动计算数量。 另外,用户可能希望代码有详细的注释,解释每一步的作用。比如,swap函数的作用,回溯函数的递归终止条件,以及如何通过交换元素生成不同的排列。 可能遇到的问题包括内存分配错误,数组越界,或者没有正确复制当前排列到结果中。例如,在每次找到一种排列时,必须将当前数组的元素复制到结果中的一行,而不是直接引用,因为后续的交换会改变原数组的内容。 还需要考虑测试用例,比如输入为空的情况,或者数组只有一个元素的情况,确保代码的鲁棒性。 总结下来,步骤大致如下: 1. 实现交换元素的函数。 2. 编写回溯函数,递归生成排列。 3. 在每次递归到底层时,将当前排列保存到结果数组。 4. 主函数中计算n!,分配结果数组的内存,调用回溯函数,返回结果。 需要特别注意内存的分配和释放,避免内存泄漏。但因为力扣的题目通常只需要返回结果,可能不需要手动释放,不过实际编写时可能需要根据题目要求处理。 现在,把这些思路整理成结构化的讲解,分步骤说明,并附上代码示例。同时指出代码中的关键点,比如交换和回溯的过程,以及如何避免重复。对于C语言来说,因为没有内置的动态数组,必须预先计算好所需内存,这在代码中需要体现。</think>### 力扣全排列问题(LeetCode 46)C语言实现详解 #### 一、问题描述 给定一个 **没有重复数字** 的整数数组,返回其所有可能的全排列。例如: 输入:`[1,2,3]` 输出: `[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]` --- #### 二、核心思路:回溯算法 1. **递归交换**:通过交换数组中不同位置的元素,生成所有可能的排列。 2. **终止条件**:当递归深度等于数组长度时,保存当前排列。 3. **路径回退**:每次递归后恢复数组状态,避免影响后续分支。 --- #### 三、C语言代码实现 ```c #include <stdio.h> #include <stdlib.h> // 交换两个整数 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 回溯函数 void backtrack(int* nums, int numsSize, int depth, int** res, int* returnSize) { if (depth == numsSize) { // 终止条件:生成一个完整排列 res[*returnSize] = (int*)malloc(numsSize * sizeof(int)); for (int i = 0; i < numsSize; i++) { res[*returnSize][i] = nums[i]; } (*returnSize)++; return; } // 从当前深度开始,尝试所有可能的交换 for (int i = depth; i < numsSize; i++) { swap(&nums[depth], &nums[i]); // 交换,固定当前深度的元素 backtrack(nums, numsSize, depth + 1, res, returnSize); swap(&nums[depth], &nums[i]); // 恢复,保证后续分支正确性 } } // 主函数 int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) { // 计算全排列总数 n! int total = 1; for (int i = 1; i <= numsSize; i++) total *= i; *returnSize = 0; // 分配结果数组内存 int** res = (int**)malloc(total * sizeof(int*)); *returnColumnSizes = (int*)malloc(total * sizeof(int)); for (int i = 0; i < total; i++) { (*returnColumnSizes)[i] = numsSize; } // 回溯生成排列 backtrack(nums, numsSize, 0, res, returnSize); return res; } ``` --- #### 四、代码关键点解析 1. **交换与回溯** - 通过 `swap` 函数修改数组元素顺序,逐步生成不同排列。 - 递归后必须恢复数组状态(再次 `swap`),否则会影响其他分支。 2. **内存管理** - 结果数组 `res` 需要预先分配 `n!` 行,每行存储一个排列。 - 每生成一个排列时,动态分配内存并复制当前数组内容。 3. **复杂度分析** - 时间复杂度:$O(n \times n!)$,共有 $n!$ 种排列,每次复制需 $O(n)$。 - 空间复杂度:$O(n \times n!)$,存储所有排列的结果。 --- #### 五、测试示例 ```c int main() { int nums[] = {1, 2, 3}; int numsSize = 3; int returnSize; int* returnColumnSizes; int** res = permute(nums, numsSize, &returnSize, &returnColumnSizes); for (int i = 0; i < returnSize; i++) { for (int j = 0; j < numsSize; j++) { printf("%d ", res[i][j]); } printf("\n"); free(res[i]); // 释放每行内存 } free(res); // 释放结果数组 free(returnColumnSizes); return 0; } ``` --- #### 六、总结 通过递归和交换实现回溯,是解决全排列问题的经典方法。C语言需要手动管理内存,需特别注意: 1. 结果数组的预分配和释放。 2. 每次递归后恢复数组状态。 3. 深拷贝当前排列到结果中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值