IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> LeetCode 350. 两个数组的交集II 哈希表法 C语言 Intersection of Two Arrays II -> 正文阅读

[C++知识库]LeetCode 350. 两个数组的交集II 哈希表法 C语言 Intersection of Two Arrays II

本篇文章为笔者的LeetCode刷题笔记。文章整体分为两部分:1.笔者自己思考的算法及代码。2.LeetCode官方给出的最优算法及代码。通过对比这两部分算法和代码的异同,笔者的算法思想和编程水平有了显著地提升。如果这篇文章能帮到你那真是再好不过了!?

一、读者思考的算法

A.算法:利用哈希表,将较短的数组1放入哈希表。再遍历较长的数组2,依次与哈希表中的存货比较。



/**
 * Note: The returned array must be malloced, assume caller calls free().
 */         //注意此处返回数组必须是动态分配的才行
 
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){

    typedef struct {
     int key;                 //C语言对哈希表的配置 定义一个包含键值和出现次数value的结构体
     int value;
     UT_hash_handle hh;
 } Hash;
 Hash *hash = NULL;        //声明一个指向该结构体的指针hash

 Hash * find(int key){        //在哈希表中查找是否存在给定key值,若存在返回指向其地址的指针
     Hash *tep = NULL;        //否则返回空指针
     HASH_FIND_INT(hash,&key,tep);
     return tep;
 }
 void insert(int key){        //将较小数组key值和其出现次数插入哈希表
     Hash * tep = find(key);
     if(tep==NULL){            //若找不到,则插入
         Hash *s = (Hash*)malloc(sizeof(Hash)); //动态分配一个结构体
         s->key=key;                             //给其赋值
         s->value=1;
         HASH_ADD_INT(hash,key,s);  //调用库函数,将s所指的Hash结构体插入到hash老巢中key映射的地址上
     }else{
         tep->value++; //若已存在,则出现次数++
     }
 }
    if(nums1Size<nums2Size){  
        int *ret = (int*)malloc(sizeof(int)*(nums1Size));
        *returnSize=0;
        for(int i=0;i<nums1Size;i++){        //将较小数组插入哈希表
            insert(nums1[i]);
        }
        for(int j=0;j<nums2Size;j++){        //依次查找较大数组各元素是否在哈希表中
            Hash *it = find(nums2[j]);
            if(it==NULL){}     //若不存在则为空,且此处必须加这一行,否则下一行it为空会报错
            else if(it->key==nums2[j]&&it->value!=0){ //当存在且哈希表中此key出现次数>0
                it->value--;        //出现次数--
                ret[(*returnSize)++]=nums2[j];    //将交集依次放入新建数组ret
            }        //注意此处*returnSize初始化为0,这样写可以省一个int index变量
        }
        return ret;    //返回该数组
    }else{
        int *ret = (int*)malloc(sizeof(int)*(nums2Size));
        *returnSize=0;
        for(int i=0;i<nums2Size;i++){
            insert(nums2[i]);
        }
        for(int j=0;j<nums1Size;j++){
            Hash *it = find(nums1[j]);
            if(it==NULL){}
            else if(it->key==nums1[j]&&it->value!=0){
                it->value--;
                ret[(*returnSize)++]=nums1[j];
            }
        }
        return ret;
    }
    

}

B.算法复杂度分析

时间复杂度:O(m+n) m和n依次为两个数组的长度。需要对两个数组依次遍历,再对哈希表进行操作。操作哈希表的时间复杂度为O(1)。

空间复杂度: O( min(m,n) ) m和n依次为两个数组的长度。哈希表中需要存放较小数组的元素,所以哈希表的大小不大于较小数组大小。返回数组也不大于较小数组的长度。

二.官方算法

官方算法与我的算法几乎一致

第二种算法是先排序再用双指针,很容易实现。

A.算法:

如果两个数组是有序的,则可以使用双指针的方法得到两个数组的交集。首先对两个数组进行排序,然后使用两个指针遍历两个数组。初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,将该数字添加到答案,并将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。

int cmp(const void* _a, const void* _b) {
    int *a = _a, *b = (int*)_b;
    return *a == *b ? 0 : *a > *b ? 1 : -1;
}

int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size,
               int* returnSize) {
    qsort(nums1, nums1Size, sizeof(int), cmp);
    qsort(nums2, nums2Size, sizeof(int), cmp);
    *returnSize = 0;
    int* intersection = (int*)malloc(sizeof(int) * fmin(nums1Size, nums2Size));
    int index1 = 0, index2 = 0;
    while (index1 < nums1Size && index2 < nums2Size) {
        if (nums1[index1] < nums2[index2]) {
            index1++;
        } else if (nums1[index1] > nums2[index2]) {
            index2++;
        } else {
            intersection[(*returnSize)++] = nums1[index1];
            index1++;
            index2++;
        }
    }
    return intersection;
}

C.算法复杂度分析

时间复杂度:O(mlogm+nlogn),其中?m 和?n 分别是两个数组的长度。对两个数组进行排序的时间复杂度是O(mlogm+nlogn),遍历两个数组的时间复杂度是?O(m+n),因此总时间复杂度是O(mlogm+nlogn)。
空间复杂度:O(min(m,n)),其中m 和?n分别是两个数组的长度。为返回值创建一个数组intersection,其长度为较短的数组的长度。

三.笔者小结

1. 通过这道题学会了哈希表的使用方法。哈希表查找操作的时间复杂度为O(1)。因为哈希表有专门的映射函数,可以只通过一步计算就得出key所对应的地址,而不用像数组或链表一样依次遍历查找。例如Hash(key)=key,Hash(1)=1,指的是key为1的地址就为1。

2. 用C实现哈希表的都是勇士,我是学完考研408四门专业课后直接开始刷LeetCode的,所以只会C语言。现在在慢慢自学Java了,用Java或者C++直接可以用几行代码就搞定C几十行。。。

3. 关于C语言哈希表的使用:https://blog.csdn.net/nameofcsdn/article/details/107297361

Keep calm and carry on!

谢谢你看到这里!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 13:57:27  更:2021-07-22 13:58:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 4:52:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码