leetcode刷题笔记——217.存在重复元素

题目描述

题目描述

分析

快排

描述

​ 最简单的想法是对每个元素与其之前的元素进行比较,但这种算法的时间复杂度是O(N^2),会超过题目的限制。于是考虑降低时间复杂度,思考O(NlogN)的做法,想到可以采取快速排序,然后检测排序后数组是否有相邻元素相等,这样时间复杂度就降到了NlogN。

​ 而空间复杂度应该是logN,考虑到快速排序中递归调用栈的深度。

代码

int cmpFunc(const void *a,const void *b){
    return (*(int *)a - *(int *)b);
}
bool containsDuplicate(int* nums, int numsSize){
    qsort(nums, numsSize, sizeof(int), cmpFunc);
    int i;
    for (i = 0; i < numsSize - 1;i++){
        if(nums[i]==nums[i+1]){
            return true;
        }
    }
    return false;
}

哈希表

描述

除了快速排序的算法,还可以采取用哈希表存储。用空间复杂度来换时间复杂度,可以把时间复杂度降到O(N),因为相当于只遍历了一遍数组。而空间复杂度就会变成O(N)。

代码

struct hashList
{
    int id;
    UT_hash_handle hh;
};
bool containsDuplicate(int *nums, int numsSize)
{
    struct hashList *set = NULL;
    int i;
    for (i = 0; i < numsSize; i++)
    {
        struct hashList *tmp;
        HASH_FIND_INT(set, nums + i, tmp); // nums+i为第i个元素的地址
        if (tmp == NULL)
        {
            tmp = malloc(sizeof(struct hashList));
            tmp->id = nums[i];
            HASH_ADD_INT(set, id, tmp);
        }
        else
        {
            return true;
        }
    }
    return false;
}

收获

对于数据结构为数组的题目,若时间复杂度要求为NlogN的,可以考虑采取快速排序后再线性求解。

快速排序qsort函数

C库函数

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))

其参数

base – 指向要排序的数组的第一个元素的指针

nitems – 由base指向的数组中元素的个数

size – 数组中每个元素的大小,以字节为单位。

compar – 用来比较两个元素的函数

实例

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

int values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b)
{
   return ( *(int*)a - *(int*)b );
}

int main()
{
   int n;

   printf("排序之前的列表:\n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }

   qsort(values, 5, sizeof(int), cmpfunc);

   printf("\n排序之后的列表:\n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }
 
  return(0);
}

uthash

uthash是C的比较优秀的开源代码,已经集成到最新的GCC。uthash可支持以下操作(包括但不局限于):增加、查找、删除、计数、迭代、排序、选择。

uthash支持C语言的任意数据结构作为key值(甚至是自定义的struct),甚至可以采用多个值作为key。但不同类型的key对其操作接口方式略有不同。

该代码采用宏的方式实现,所有的实现代码都在uthash.h文件中,因此只需要包含头文件#include"uthash.h"即可使用。

使用方式

定义数据结构

首先需要定义哈希表的单元结构体

struct hashList{
    int id;				//key
    void* value[10];	//value
    UT_hash_handle hh;	//makes this structure hashable
}
struct hashList *g_users = NULL;

※id是哈希寻址的key值,不止限于int。但不同的数据结构对应的hash操作可能不一样

※name是value值,也就是储存值。若除value无额外储存值可以去掉该变量。

※hh是uthash内部使用的hash处理句柄,必须定义一个UT_hash_handle类型的变量,但不需要为其赋值。

※在定义完自己的uthash类型后,可以先宏定义一个空的该类型指针,用于指向保存数据的hash表(也就是总表)。(必须初始化为空,uthash内部会根据其是否为空而进行不同的操作)

封装插入接口
//已经宏定义g_users为总表,id为hash的key变量名
void AddUser(int iKey, char *iValue)
{
    struct hashList *s;
    HASH_FIND_INT(g_users, &iKey, s);  /* 插入前先查看key值是否已经在hash表g_users里面了 */
    if (s==NULL) {/*若没有则进行插入*/
		s = (struct hashList *)malloc(sizeof(struct hashList));
		s->id = iKey;
		HASH_ADD_INT(g_users, id, s);  /* 第二个参数为hash结构里面,hash key值的变量名 */
    }
    strcpy(s->value, iValue);	/* 赋值value,注意是在if嵌套外面,若key值已经在g_users里也要进行赋值*/
}

※uthash要求key必须唯一,所以要先检查插入的key是否在当前的hash表中,否则会被当做一种错误

封装实现删除接口
void DeleteUser(int ikey)
{
    struct hashList *s = NULL;
    HASH_FIND_INT(g_users, &ikey, s);/*找到key值为ikey的元素,并将s指向它*/
    if (s!=NULL) {
		HASH_DEL(g_users, s);      // HASH_DEL 只将结构体从hash表中移除,并未释放结构体内容
		free(s);            	//所以需要手动释放
    }
}
统计hash表中的元素个数
unsighed int numUsers;
numUsers = Hash_COUNT(g_users);
printf("%d",numUsers);
遍历元素
struct hashList *s,*tmp;
HASH_ITER(hh,g_users,s,tmp){
	printf("%d%d",s->key,s->tmp);
}
清空hash表
void deleteHash(){
    struct hashList *currentUser, *tmp;
    HASH_ITER(hh, g_users, currentUser, tmp) {
		HASH_DEL(g_users, currentUser);  
		free(currentUser);            
	}
}
清空hash表
void deleteHash(){
    struct hashList *currentUser, *tmp;
    HASH_ITER(hh, g_users, currentUser, tmp) {
		HASH_DEL(g_users, currentUser);  
		free(currentUser);            
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值