一刷Day6|242.有效的字母异位词 349. 两个数组的交集 1. 两数之和

文章目录

  • 242.有效的字母异位词
    • 识别
    • 核心/易错
    • 难点/亮点
    • 算法设计思路
    • 代码实现
  • 349. 两个数组的交集
    • 识别
    • 核心/易错
    • 难点/亮点
    • 算法设计思路
    • 代码实现
    • 改进建议
  • 1.两数之和
    • 识别
    • 核心/易错
    • 难点/亮点
    • 算法设计思路
    • 代码实现
    • 详细分析

242.有效的字母异位词

识别

检查两个字符串是否为变位词(anagram)的C语言程序。变位词是指两个字符串由完全相同的字符组成,但字符的顺序可以不同。

核心/易错

核心功能是判断两个字符串是否为变位词。
易错点:

  1. 字符串长度不等时直接返回false,这是正确的,因为变位词的长度必须相同。
  2. 使用一个大小为26的数组来统计字符频率,假设输入只包含小写字母。如果输入包含大写字母或其他字符,程序将无法正确处理。

难点/亮点

难点在于如何高效地统计字符频率并比较两个字符串。亮点是使用一个固定大小的数组来存储字符频率,这种方法在时间复杂度上是高效的(O(n)),其中n是字符串的长度。

算法设计思路

  1. 首先检查两个字符串的长度是否相等,不等则直接返回false。
  2. 初始化一个大小为26的数组,用于统计每个字符的出现次数。
  3. 遍历第一个字符串,统计每个字符的出现次数。
  4. 遍历第二个字符串,从数组中减去每个字符的出现次数。如果在减去之前数组中的对应值已经为0,则说明第一个字符串中该字符的数量多于第二个字符串,直接返回false。
  5. 最后,遍历数组,如果所有元素都为0,则两个字符串是变位词,返回true;否则返回false。

代码实现

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool isAnagram(char* s, char* t) {
    int len1 = strlen(s), len2 = strlen(t);
    if (len1 != len2) {
        return false;
    }

    int freq[26] = {0};
    for (int i = 0; i < len1; i++) {
        freq[s[i] - 'a'] += 1;
    }

    for (int i = 0; i < len2; i++) {
        if (freq[t[i] - 'a'] == 0) {
            return false;
        }
        freq[t[i] - 'a'] -= 1;
    }

    for (int i = 0; i < 26; i++) {
        if (freq[i] != 0) {
            return false;
        }
    }

    return true;
}

int main() {
    char s[] = "anagram";
    char t[] = "nagaram";
    
    if (isAnagram(s, t)) {
        printf("'%s' and '%s' are anagrams.\n", s, t);
    } else {
        printf("'%s' and '%s' are not anagrams.\n", s, t);
    }
    
    return 0;
}

349. 两个数组的交集

识别

这段代码的目的是找出两个整数数组 nums1nums2 的交集。它使用哈希表来存储 nums1 中的元素,然后遍历 nums2,检查每个元素是否存在于哈希表中,如果存在并且不在结果数组中,则将其添加到结果数组中。

核心/易错

核心逻辑是使用哈希表来快速查找元素是否存在于 nums1 中,这是一个常见的优化策略,可以显著提高查找效率。易错点在于:

  1. 哈希表的初始化和使用:需要确保哈希表的大小足够大,以避免哈希冲突。
  2. 处理负数:通过添加偏移量 5000 来处理负数,确保它们在哈希表中有有效的索引。
  3. 去重:在将元素添加到结果数组之前,需要检查该元素是否已经存在,以避免重复。

难点/亮点

难点在于如何高效地处理可能存在的大量数据和避免重复元素。亮点是使用哈希表来优化查找过程,这通常比直接遍历数组要快得多。

算法设计思路

  1. 使用一个大小为 10001 的哈希表来存储 nums1 中的元素,索引为元素值加上 5000(以处理负数)。
  2. 遍历 nums2,对于每个元素,检查它是否在哈希表中存在,并且不在结果数组中。
  3. 如果满足条件,则将其添加到结果数组中,并更新结果数组的大小。

代码实现

#include <stdio.h>
#include <stdlib.h>

int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size,
                  int* returnSize) {
    // 创建一个哈希表,用于存储nums1中的元素
    int* hashTable = (int*)calloc(10001, sizeof(int)); // 假设数组元素范围为0到10000

    // 遍历nums1,将元素添加到哈希表中
    for (int i = 0; i < nums1Size; i++) {
        hashTable[nums1[i] + 5000] = 1; // 使用一个偏移量,防止负数问题
    }

    // 创建一个数组,用于存储结果
    int* result = (int*)malloc(nums1Size * sizeof(int));
    int resultSize = 0;

    // 遍历nums2,检查元素是否在哈希表中
    for (int i = 0; i < nums2Size; i++) {
        if (hashTable[nums2[i] + 5000] == 1) {
            // 检查结果数组中是否已经包含该元素
            int isDuplicate = 0;
            for (int j = 0; j < resultSize; j++) {
                if (result[j] == nums2[i]) {
                    isDuplicate = 1;
                    break;
                }
            }
            if (!isDuplicate) {
                result[resultSize++] = nums2[i];
            }
        }
    }

    // 释放哈希表内存
    free(hashTable);

    *returnSize = resultSize;
    return result;
}

改进建议

  1. 可以考虑使用动态数组(如 std::vector 在 C++ 中)来存储结果,以避免预先分配固定大小的数组。
  2. 如果 nums1nums2 的元素范围不是 010000,需要调整哈希表的大小和偏移量。
  3. 可以考虑使用更高效的数据结构,如 std::unordered_set(在 C++ 中),以进一步优化性能。

1.两数之和

识别

这段代码实现了一个经典的算法问题:两数之和。它使用哈希表(通过 uthash 库)来存储数组元素的值和它们的索引,以便快速查找两个数的和是否等于目标值。

核心/易错

核心功能是快速查找数组中是否存在两个数,它们的和等于给定的目标值。易错点包括:

  1. 正确管理内存分配和释放,避免内存泄漏。
  2. 确保哈希表操作正确,包括添加、查找和删除元素。
  3. 处理边界情况,如空数组或所有元素都不满足条件。

难点/亮点

难点在于如何高效地实现查找操作,亮点是使用哈希表来优化查找过程,将时间复杂度从可能的 O(n^2) 降低到 O(n)。

算法设计思路

  1. 初始化哈希表:使用 uthash 库创建一个哈希表,用于存储数组元素的值和它们的索引。
  2. 填充哈希表:遍历数组,将每个元素的值作为键,索引作为值添加到哈希表中。
  3. 查找目标:再次遍历数组,对于每个元素,计算目标值与当前元素值之差,然后在哈希表中查找这个差值。如果找到且对应的索引不是当前元素的索引,则找到了两个数的和等于目标值。
  4. 清理资源:在找到结果或遍历完成后,清理哈希表并释放所有分配的内存。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include "uthash.h"

typedef struct {
    int key;
    int value;
    UT_hash_handle hh; // make this structure hashable
} map;

// 向哈希表中添加键值对
void hashMapAdd(map** hashMap, int key, int value) {
    map* s;
    HASH_FIND_INT(*hashMap, &key, s);
    if (s == NULL) {
        s = (map*)malloc(sizeof(map));
        if (s == NULL) {
            fprintf(stderr, "Memory allocation failed\n");
            exit(EXIT_FAILURE);
        }
        s->key = key;
        s->value = value;
        HASH_ADD_INT(*hashMap, key, s);
    }
}

// 从哈希表中查找键对应的值
map* hashMapFind(map* hashMap, int key) {
    map* s;
    HASH_FIND_INT(hashMap, &key, s);
    return s;
}

// 清理哈希表,释放所有内存
void hashMapCleanup(map** hashMap) {
    map* cur;
    map* tmp;
    if (*hashMap != NULL) {
        HASH_ITER(hh, *hashMap, cur, tmp) {
            HASH_DEL((*hashMap), cur);
            free(cur);
        }
        *hashMap = NULL;
    }
}

int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    int i, *ans;
    map* hashMap = NULL; // 初始化哈希表为空
    ans = malloc(sizeof(int) * 2); // 动态分配内存,用于存储两个索引
    if (ans == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        return NULL;
    }

    for (i = 0; i < numsSize; i++) {
        // 将数组元素的值作为键,索引作为值添加到哈希表中
        hashMapAdd(&hashMap, nums[i], i);
    }

    for (i = 0; i < numsSize; i++) {
        // 查找target - nums[i]是否存在于哈希表中
        map* hashMapRes = hashMapFind(hashMap, target - nums[i]);
        if (hashMapRes && hashMapRes->value != i) { // 如果找到且索引不相同
            ans[0] = i;                             // 存储第一个索引
            ans[1] = hashMapRes->value;             // 存储第二个索引
            *returnSize = 2;                        // 设置返回数组的大小
            hashMapCleanup(&hashMap);               // 清理哈希表
            return ans;                             // 返回结果
        }
    }

    hashMapCleanup(&hashMap); // 清理哈希表
    free(ans);                // 释放内存
    return NULL;              // 如果没有找到结果,返回NULL
}

详细分析

  1. 初始化哈希表

    map* hashMap = NULL;
    

    使用 NULL 初始化哈希表指针。

  2. 添加元素到哈希表

    void hashMapAdd(map** hashMap, int key, int value) {
        map* s;
        HASH_FIND_INT(*hashMap, &key, s);
        if (s == NULL) {
            s = (map*)malloc(sizeof(map));
            if (s == NULL) {
                fprintf(stderr, "Memory allocation failed\n");
                exit(EXIT_FAILURE);
            }
            s->key = key;
            s->value = value;
            HASH_ADD_INT(*hashMap, key, s);
        }
    }
    
    • 使用 HASH_FIND_INT 宏查找哈希表中是否存在给定键的元素。
    • 如果不存在,分配内存并添加到哈希表中。
  3. 查找元素

    map* hashMapFind(map* hashMap, int key) {
        map* s;
        HASH_FIND_INT(hashMap, &key, s);
        return s;
    }
    
    • 使用 HASH_FIND_INT 宏查找哈希表中是否存在给定键的元素。
  4. 清理哈希表

    void hashMapCleanup(map** hashMap) {
        map* cur;
        map* tmp;
        if (*hashMap != NULL) {
            HASH_ITER(hh, *hashMap, cur, tmp) {
                HASH_DEL((*hashMap), cur);
                free(cur);
            }
            *hashMap = NULL;
        }
    }
    
    • 使用 HASH_ITER 宏遍历哈希表中的所有元素,删除并释放内存。
  5. 两数之和函数

    int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
        int i, *ans;
        map* hashMap = NULL;
        ans = malloc(sizeof(int) * 2);
        if (ans == NULL) {
            fprintf(stderr, "Memory allocation failed\n");
            return NULL;
        }
    
        for (i = 0; i < numsSize; i++) {
            hashMapAdd(&hashMap, nums[i], i);
        }
    
        for (i = 0; i < numsSize; i++) {
            map* hashMapRes = hashMapFind(hashMap, target - nums[i]);
            if (hashMapRes && hashMapRes->value != i) {
                ans[0] = i;
                ans[1] = hashMapRes->value;
                *returnSize = 2;
                hashMapCleanup(&hashMap);
                return ans;
            }
        }
    
        hashMapCleanup(&hashMap);
        free(ans);
        return NULL;
    }
    
    • 初始化哈希表和结果数组。
    • 遍历数组,将每个元素的值和索引添加到哈希表中。
    • 再次遍历数组,查找是否存在一个元素的值加上当前元素的值等于目标值。
    • 如果找到,将这两个元素的索引存储在结果数组中并返回。
    • 如果没有找到,清理哈希表并返回 NULL

通过这些步骤,代码实现了两数之和的功能,同时确保了内存的正确管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值