算法训练营打卡Day7

今天继续来学习哈希表

题目1.四数相加II

题目链接:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili

. - 力扣(LeetCode)

关于如何选择集合/映射,可以参考以下表格

 C代码(来源-->代码随想录)笔者仅作注释

// 哈希表大小

const int HASH_SIZE = 101;

//这里定义了哈希表的大小为101。选择一个质数作为哈希表的大小是一个常见的做法,因为质数可以减少哈希冲突的概率。

typedef struct node {     //哈希表节点结构(node

    /*

这里定义了一个结构体node,它包含三个字段:val存储哈希键的值,count记录这个值出现的次数,next是指向下一个node的指针,用于处理哈希冲突。

    */

    int val;

    int count;

    struct node *next;

} node, *HashMap;

// 哈希表插入

void hash_insert(HashMap hashmap[], int val) {

   /*这个函数负责将给定的值val插入到哈希表中。首先,它计算val的哈希索引(考虑到负数情况),然后在相应的链表中查找该值。如果找到,就增加其计数;如果没有找到,就在链表末尾添加一个新的节点。

    */

    int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE, count = 0;

    node *p = hashmap[idx]; 

    while (p->next != NULL) {

        p = p->next;

        if (p->val == val) {

            (p->count)++;

            return;

        }

    }

    node *new = malloc(sizeof(node));

    new->val = val;

    new->count = 1;

    new->next = NULL;

    p->next = new;

    return;

}

// 哈希表查找

int hash_search(HashMap hashmap[], int val) {

    int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE;

    node *p = hashmap[idx];

    while (p->next != NULL) {

        p = p->next;

        if (p->val == val) return p->count;

    }

    return 0;

}

int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){

    // 初始化哈希表

    HashMap hashmap[HASH_SIZE];

    for (int i = 0; i < HASH_SIZE; i++) {

        hashmap[i] = malloc(sizeof(node));

        hashmap[i]->next = NULL;

    }

    // 统计两个数组元素之和的负值和出现的次数,放到哈希表中

    int count = 0, num;

    for (int i = 0; i < nums1Size; i++) {

        for(int j = 0; j < nums2Size; j++) {

            num = - nums1[i] - nums2[j];

            hash_insert(hashmap, num);

        }

    }

    // 统计另外两个数组元素之和,查找哈希表中对应元素的出现次数,加入总次数

    for (int i = 0; i < nums3Size; i++) {

        for(int j = 0; j < nums4Size; j++) {

            num = nums3[i] + nums4[j];

            count += hash_search(hashmap, num);

        }

    }

    return count;

}

小结:它初始化一个哈希表,并遍历nums1nums2的所有元素对,计算它们的和的负值,并将这些负值及其出现次数存储在哈希表中。然后,它遍历nums3nums4的所有元素对,计算它们的和,并在哈希表中查找这个和的相反数的出现次数(即查找在哈希表中之前存储的负值)。最后,它将所有找到的匹配次数累加,并返回这个总和。

Python代码

一开始就想到用字典的思路了,使用python做本题有油然而生的爽快感,毕竟个人认为python代码比C简单多了, 虽然思路大致相似。

class Solution(object):

    def fourSumCount(self, nums1, nums2, nums3, nums4):

        # 使用字典存储nums1和nums2中的元素及其和

        hashmap = dict()

        for n1 in nums1:

            for n2 in nums2:

                hashmap[n1+n2] = hashmap.get(n1+n2, 0) + 1       

        # 如果 -(n1+n2) 存在于nums3和nums4, 存入结果

        count = 0

        for n3 in nums3:

            for n4 in nums4:

                key = - n3 - n4

                if key in hashmap:

                    count += hashmap[key]

        return count

题目2.383. 赎金信

题目链接:力扣题目链接

 Python代码

代码思路比较简单、清晰,可供读者参考,内存占用这块我还是很有自信的。

 

# 使用两个字典分别记录 ransomNote 和 magazine 中字符的出现次数  
        dict1 = {}  
        dict2 = {}  
        # 遍历 ransomNote,记录每个字符的出现次数  
        for char in ransomNote:  
            dict1[char] = dict1.get(char, 0) + 1  
        # 遍历 magazine,记录每个字符的出现次数  
        for char in magazine:  
            dict2[char] = dict2.get(char, 0) + 1  

        # 检查 ransomNote 中的每个字符是否在 magazine 中有足够的数量  
        for char, count in dict1.items():  
            # 如果字符不存在于 magazine 的字典中,或者数量不足,则返回 False  
            if char not in dict2 or dict2[char] < count:  
                return False       
        # 如果所有字符都检查通过,则返回 True  
        return True

另外附两个其他版本的代码:

C代码

bool canConstruct(char* ransomNote, char* magazine) {

    int hashmap[26] = {0};

    //首先我们要获取magezine字符串中每个字符的出现频率

    while (*magazine != '\0'){

        hashmap[*magazine++ % 26]++;

    }

    // 遍历ransomNote,对应的字符自减,小于0说明该字符magazine没有或不足够表示

    while (*ransomNote != '\0'){

        hashmap[*ransomNote++ % 26]--;

    }

    // 如果数组中存在负数,说明ransomNote不能由magazine里面的字符构成

    for (int i = 0; i < 26; i++) {

        if (hashmap[i] < 0) return false;

    }

    return true;

}

题目3. 三数之和

题目链接: 力扣题目链接

梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili 

#此处应有夢消失 ~Lost Dream - Demetori - 单曲 - 网易云音乐

python代码

nums.sort()  # 先对数组进行排序,有助于减少不必要的搜索  
        res = []  
        n = len(nums)  
        for i in range(n-2):  # 只需要遍历到倒数第三个元素  
            if i > 0 and nums[i] == nums[i-1]:  # 跳过重复的元素  
                continue  
            left, right = i+1, n-1  
            while left < right:  
                total = nums[i] + nums[left] + nums[right]  
                if total < 0:  
                    left += 1  
                elif total > 0:  
                    right -= 1  
                else:  
                    res.append([nums[i], nums[left], nums[right]])  
                    # 移动左右指针,并跳过重复的元素  
                    while left < right and nums[left] == nums[left+1]:  
                        left += 1  
                    while left < right and nums[right] == nums[right-1]:  
                        right -= 1  
                    left += 1  
                    right -= 1  
        return res

C代码:

歇菜了

. - 力扣(LeetCode)

小结:使用双指针法来优化性能,通过排序和跳过重复元素来减少不必要的计算。同时,确保添加到 res 中的是具体的元素值而不是索引。

总结:
笔者C语言基础还不够扎实,很多代码反而是使用python完成的,要加强对C语言指针、哈希表的运用。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值