【问题标题】:Finding duplicates in an array using C使用C在数组中查找重复项
【发布时间】:2019-06-01 06:20:07
【问题描述】:

我在此链接https://leetcode.com/problems/contains-duplicate/ 中遇到了问题。有一个整数输入数组。找出是否有任何重复的整数,然后返回 true 否则返回 false。

  1. 如何优化此代码?

  2. 我可以进一步改进逻辑吗?

在我下面的代码中,有一个 if 条件 if(hPtr && hPtr->key == *(nums+i))。我使用数组元素作为键。如果是这样,如果相同的元素重复两次,每个键就不能是唯一的吗?那么我可以将if条件修改为if(hPtr->key == *(nums + i))?

如有其他错误,欢迎指出。

C http://troydhanson.github.io/uthash/userguide.html 中已经有一个可用的哈希表库,并编写了以下代码。

struct hash {
        int key;
        int value;
        UT_hash_handle hh;
};

    struct hash *hashtable = NULL;

    void addToHash(int key, int value)
    {
      struct hash *map;
      //I am using the array elements as hash keys
      HASH_FIND_INT(hashtable, &key, map);

      if(map == NULL)
      {
        map = (struct hash*)malloc(sizeof(struct hash));
        map->key = key;
        HASH_ADD_INT(hashtable, key, map);
      }     
      map->value = value;
    }   

    struct hash *findInHash(int key)
    {
        struct hash *h;
        HASH_FIND_INT(hashtable, &key, h);
        return h;
    }

    bool containsDuplicate(int* nums, int numsSize) {
        struct hash *hPtr;
        int target = 0;
        hashtable = NULL;
        if((numsSize <= 1) || (nums == 0)) return false;

        int i, index1 = 0;   

        for(i = 0; i < numsSize; i++)
        {
            /*The below statement will look if the key is already present in 
              the hashtable*/
            hPtr = findInHash(*(nums + i) - target);
            /*If the key is found already, then it look for the value of that 
            key. If the value and the current array element is same, then a 
            duplicate exist*/
            if(hPtr && hPtr->key == *(nums+i))
               return true;
            addToHash(*(nums + i), i);
        }
        struct hash *temp;
        HASH_ITER(hh, hashtable, hPtr, temp) {free(hPtr);}
        return false;
    }

【问题讨论】:

  • 你可以选择你的语言,我想用C来解决。
  • 如果你想在 C 中解决这个问题,那很好,但你必须进行某种单元测试,否则你会在没有任何形式的代码验证的情况下磕磕绊绊。正确完成的单元测试将很快验证您的代码是否正确,并将为您节省大量猜测、思考和调试的时间。
  • 就性能而言,即使使用time,也可以轻松地对这段代码进行基准测试,运行长度不同。
  • 很抱歉问这个问题,但我还没有进行任何单元测试。有什么要开始的指针吗?
  • 搜索“C单元测试框架”,有plethora of options

标签: c hashtable


【解决方案1】:

我认为解决方案比你想象的要简单:

typedef struct {
  int capacity;
  int len;
  int **keys;
  int *values;
} Map;

我的结构有两个整数数组的键,一个是标识符,另一个是值数组的索引,这就是哈希映射的工作原理。

void initMap(Map *map) {
  map -> capacity = 5;
  map -> len = 0;
  map -> keys = malloc(map -> capacity * sizeof(int));
  map -> values = malloc(map -> capacity * sizeof(int));
}

那么我们就有了一个初始化地图的函数,简单...

void add(Map *map, int k, int v) {
  if (map -> len == map -> capacity - 1) resize(map);
  map -> values[map -> len] = v;
  map -> keys[map -> len] = malloc(sizeof(int) * 2);
  map -> keys[map -> len][0] = k;
  map -> keys[map -> len][1] = map -> len;
  map -> len++;
}

将元素放入地图的函数

void resize(Map *map) {
  map -> capacity *= 2;
  map -> keys = realloc(map -> keys, map -> capacity * sizeof(int) * 2);
  map -> values = realloc(map -> keys, map -> capacity * sizeof(int));
}

以及一个在达到限制时调整地图大小的函数

通过解耦键索引和值数组上的索引,您可以对键进行排序,让您的生活更轻松。 这些值将在它们的数组中以与它们相同的顺序出现,但索引将从 0 到 N 排序。 为此,我将使用一个简单的 selsort 算法,它不是最好的但最简单的......

void sort(Map *map) {
  int i, j;
  int min, tmp;
  for (i = 0; i < map -> len - 1; i++) {
    min = i;
    for (j = i + 1; j < map -> len; j++) {
      if(map -> keys[j][0] < map -> keys[min][0] ) min = j;
    }

    tmp = map -> keys[min][0];
    map -> keys[min][0] = map -> keys[i][0];
    map -> keys[i][0] = tmp;
  }
}

这样你的索引就会被缩短。我会在向地图添加新条目后立即执行它,在 add() 函数中,它现在在这里只是为了测试。

对索引进行排序后,您可以编写二分搜索算法 eeeasy。现在,如果键已经在地图中,您现在就可以了。

int find_recursive(Map *map, int start, int end, int key) {
   if (end >= start) {
        int mid = start + (end - start) / 2;

        if (map -> keys[mid][0] == key)
            return mid;

        if (map -> keys[mid][0] > key)
            return find_recursive(map, start, mid - 1, key);

        return find_recursive(map, mid + 1, end, key);
    }
    return -1;
}

int find(Map *map, int key) {
    return find_recursive(map, 0, map -> len, key);
}

太棒了

  Map map;
  initMap(&map);

  add(&map, 3, 12);
  add(&map, 12, 1);
  add(&map, 1, 2);

  printf("%d %d %d\n",
      map.keys[0][0],
      map.keys[1][0],
      map.keys[2][0]
      );
  // Should print 3 12 1

  sort(&map);

  printf("%d %d %d\n",
      map.keys[0][0],
      map.keys[1][0],
      map.keys[2][0]
      );
  // Should print 1 3 12

  printf("%d\n", find(&map, 12));
  // Should print 2 (the index, 3rd entry)

我现在不能做一个有效的例子,我不能用我的机器编译,也许以后在家里......对不起:(

编辑:忘了说...要获得你必须做的价值map.values[map.keys[find(&amp;map, key)][1]]

当然这应该是一个函数:

int get(Map *map, key) {
  int keyindex = find(map, key);
  int valueindex = map -> keys[index][1];
  return map -> values[valueindex];
}

忘了说,通过将键与值解耦,您可以将其用作任何类型的值,甚至是整个结构...

享受

【讨论】:

    猜你喜欢
    • 2018-05-16
    • 2021-04-29
    • 1970-01-01
    • 2018-09-05
    相关资源
    最近更新 更多