【Leecode 随笔】C语言版看了不后悔系列持续更新中。。。

在这里插入图片描述

🌈你好呀!我是 山顶风景独好
🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊
🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。
📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟
🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨

一、电话号码的字母组合

题目描述:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。数字到字母的映射如下(与电话按键相同):
2 -> “abc”
3 -> “def”
4 -> “ghi”
5 -> “jkl”
6 -> “mno”
7 -> “pqrs”
8 -> “tuv”
9 -> “wxyz”

示例输入:

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”]
输入:“”
输出:[“”]

解题思路:

这是一个典型的回溯问题。我们可以使用递归函数来遍历每个数字对应的字母,并在递归的每一层将当前字母与之前的组合进行拼接。当遍历完所有数字时,将当前的组合添加到结果集中。

示例代码:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
  
#define MAX_COMBINATIONS 10000 // 预设一个足够大的空间来存储组合  
#define MAX_LENGTH 10 // 输入数字串的最大长度  
  
char* mappings[] = {  
    "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"  
};  
  
void backtrack(char* digits, char* combination, int index, int len, char** result, int* returnSize) {  
    if (index == len) {  
        // 当遍历完所有数字时,将组合添加到结果集中  
        result[*returnSize] = strdup(combination);  
        (*returnSize)++;  
        return;  
    }  
      
    // 遍历当前数字对应的字母  
    for (int i = 0; mappings[digits[index] - '0'][i] != '\0'; i++) {  
        combination[index] = mappings[digits[index] - '0'][i];  
        backtrack(digits, combination, index + 1, len, result, returnSize);  
    }  
}  
  
char** letterCombinations(char* digits, int* returnSize) {  
    if (digits == NULL || *digits == '\0') {  
        *returnSize = 1;  
        char** result = (char**)malloc(sizeof(char*) * 1);  
        result[0] = strdup("");  
        return result;  
    }  
      
    int len = strlen(digits);  
    char** result = (char**)malloc(sizeof(char*) * MAX_COMBINATIONS);  
    *returnSize = 0;  
    char* combination = (char*)malloc(sizeof(char) * (len + 1));  
    combination[len] = '\0';  
      
    backtrack(digits, combination, 0, len, result, returnSize);  
      
    free(combination);  
    return result;  
}  
  
// 测试函数  
void testLetterCombinations() {  
    char* digits = "23";  
    int returnSize = 0;  
    char** result = letterCombinations(digits, &returnSize);  
      
    for (int i = 0; i < returnSize; i++) {  
        printf("%s\n", result[i]);  
        free(result[i]);  
    }  
    free(result);  
}  
  
int main() {  
    testLetterCombinations();  
    return 0;  
}

深入剖析:

我们使用一个二维字符数组 mappings 来存储数字到字母的映射关系。
backtrack 函数是递归的核心,它负责遍历每个数字对应的字母,并在递归的每一层拼接组合。
letterCombinations 函数是入口函数,它处理边界情况,并为递归函数准备必要的参数。
注意在递归结束后要释放动态分配的内存,以避免内存泄漏。

二、四数之和

题目描述:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断数组中是否存在四个元素 a、b、c 和 d ,使得 a + b + c + d = target?你可以假设 nums 中的每个元素都不超过 INT_MAX 的绝对值,且 nums 的长度不超过 2000。

示例输入:

输入:nums = [1, 0, -1, 0, -2, 2], target = 0
输出:[[-1, -1, 0, 2], [-2, -1, 1, 2], [-2, 0, 0, 2]]
输入:nums = [], target = 0
输出:[]

解题思路:

这是一个经典的四指针问题。我们可以先对数组进行排序,然后使用四个指针来遍历数组。具体来说,我们可以固定前两个指针,然后使用双指针法来遍历后两个指针。当遍历完所有可能的组合后,即可得到结果。

示例代码:

#include <stdio.h>  
#include <stdlib.h>  
  
// 辅助函数:比较函数,用于qsort排序  
int compare(const void* a, const void* b) {  
    return (*(int*)a - *(int*)b);  
}  
  
// 辅助函数:检查结果集中是否已经包含当前组合  
int contains(int** result, int* returnSize, int* combination, int combinationSize) {  
    for (int i = 0; i < *returnSize; i++) {  
        int match = 1;  
        for (int j = 0; j < combinationSize; j++) {  
            if (result[i][j] != combination[j]) {  
                match = 0;  
                break;  
            }  
        }  
        if (match) {  
            return 1;  
        }  
    }  
    return 0;  
}  
  
// 主函数:寻找数组中四个数的和等于目标值的所有组合  
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {  
    if (numsSize < 4) {  
        *returnSize = 0;  
        return NULL;  
    }  
  
    qsort(nums, numsSize, sizeof(int), compare);  
  
    int** result = (int**)malloc(sizeof(int*) * numsSize * numsSize * numsSize);  
    *returnSize = 0;  
    *returnColumnSizes = (int*)malloc(sizeof(int) * numsSize * numsSize * numsSize);  
  
    for (int i = 0; i < numsSize - 3; i++) {  
        if (i > 0 && nums[i] == nums[i - 1]) {  
            continue; // 跳过重复元素  
        }  
        for (int j = i + 1; j < numsSize - 2; j++) {  
            if (j > i + 1 && nums[j] == nums[j - 1]) {  
                continue; // 跳过重复元素  
            }  
            int left = j + 1;  
            int right = numsSize - 1;  
            while (left < right) {  
                int sum = nums[i] + nums[j] + nums[left] + nums[right];  
                if (sum == target) {  
                    int combination[4] = {nums[i], nums[j], nums[left], nums[right]};  
                    if (!contains(result, returnSize, combination, 4)) {  
                        result[*returnSize] = (int*)malloc(sizeof(int) * 4);  
                        result[*returnSize][0] = nums[i];  
                        result[*returnSize][1] = nums[j];  
                        result[*returnSize][2] = nums[left];  
                        result[*returnSize][3] = nums[right];  
                        (*returnColumnSizes)[*returnSize] = 4;  
                        (*returnSize)++;  
                    }  
                    while (left < right && nums[left] == nums[left + 1]) {  
                        left++; // 跳过重复元素  
                    }  
                    while (left < right && nums[right] == nums[right - 1]) {  
                        right--; // 跳过重复元素  
                    }  
                    left++;  
                    right--;  
                } else if (sum < target) {  
                    left++; // 和太小,增大左指针  
                } else {  
                    right--; // 和太大,减小右指针  
                }  
            }  
        }  
    }  
  
    // 如果没有找到任何结果,释放内存并返回空  
    if (*returnSize == 0) {  
        free(result);  
        free(*returnColumnSizes);  
        result = NULL;  
        *returnColumnSizes = NULL;  
    }  
  
    return result;  
}  
  
// 测试函数  
void testFourSum() {  
    int nums[] = {1, 0, -1, 0, -2, 2};  
    int numsSize = sizeof(nums) / sizeof(nums[0]);  
    int target = 0;  
    int returnSize = 0;  
    int* returnColumnSizes = NULL;  
  
    int** result = fourSum(nums, numsSize, target, &returnSize, &returnColumnSizes);  
  
    for (int i = 0; i < returnSize; i++) {  
        printf("[");  
        for (int j = 0; j < returnColumnSizes[i]; j++) {  
            printf("%d", result[i][j]);  
            if (j < returnColumnSizes[i] - 1) {  
                printf(", ");  
            }  
        }  
        printf("]\n");  
        free(result[i]); // 释放每个结果数组的内存  
    }  
  
    free(result); // 释放结果数组指针的内存  
    free(returnColumnSizes); // 释放列大小数组的内存  
}  
  
int main() {  
    testFourSum();  
    return 0;  
}

深入剖析:

排序:首先对数组进行排序,这是使用双指针法的前提。
四指针遍历:通过四个指针的嵌套循环来遍历所有可能的四元组。
去重:在固定指针和内层双指针法中,都要注意跳过重复的元素,以避免结果集中出现重复。
内存管理:注意在函数结束时释放动态分配的内存。

三、不同的二叉树数量

题目描述:

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种不同的结构。

示例输入:

输入:3
输出:5
输入:1
输出:1

解题思路:

这是一个动态规划问题。对于给定的 n,我们可以选择 1 到 n 中的任何数字作为根节点。然后,对于根节点左边的数字(比根节点小),它们可以形成一棵左子树,右边的数字(比根节点大)可以形成一棵右子树。左子树和右子树本身也是二叉搜索树,因此我们可以递归地求解这个问题。
为了避免重复计算,我们可以使用动态规划来存储中间结果。定义一个数组 dp,其中 dp[i] 表示以 1 … i 为节点组成的二叉搜索树的数量。
动态规划状态转移方程:
dp[n] = sum(dp[i-1] * dp[n-i]) for i in [1, n]
特别地,当 n=0 或 n=1 时,dp[n] = 1,因为只有一个节点(或者没有节点)时,只有一种可能的树。

示例代码:

#include <stdio.h>  
#include <stdlib.h>  
  
int numTrees(int n) {  
    int* dp = (int*)malloc((n + 1) * sizeof(int));  
    dp[0] = 1;  
    dp[1] = 1;  
      
    for (int i = 2; i <= n; i++) {  
        dp[i] = 0;  
        for (int j = 1; j <= i; j++) {  
            dp[i] += dp[j - 1] * dp[i - j];  
        }  
    }  
      
    int result = dp[n];  
    free(dp);  
    return result;  
}  
  
// 测试函数  
void testNumTrees() {  
    int n = 3;  
    printf("Number of unique BSTs for n=%d: %d\n", n, numTrees(n));  
}  
  
int main() {  
    testNumTrees();  
    return 0;  
}

深入剖析:

动态规划数组:使用 dp 数组来存储以 1 … i 为节点组成的二叉搜索树的数量。
状态转移:通过遍历所有可能的根节点,并计算左子树和右子树的数量,来得到以当前数字为节点数量的二叉搜索树的数量。
边界条件:当 n=0 或 n=1 时,只有一种可能的树。
内存管理:在函数结束时释放动态分配的内存。


✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊
🏠 我在CSDN等你哦!我的主页😍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山顶风景独好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值