# LeetCode 128. [Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence)
contributed by < [Eric Lin](https://github.com/ericlinsechs) >
## Aim
* Refer [source code from Jserv's Linux Kernel Internals](https://hackmd.io/@sysprog/linux2022-quiz1#%E6%B8%AC%E9%A9%97-3) to solve [Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence).
* Describe how the code works.
## code implementation
### Data structure
Use circular doubly-linked list structure from [include/linux/types.h](https://github.com/torvalds/linux/blob/master/include/linux/types.h):
```c
struct list_head {
struct list_head *prev;
struct list_head *next;
};
```
* `seq_node`:
* `num`: integer number.
* `link`: Link for chaining elements having the same hash value in hash table.
```c
struct seq_node {
int num;
struct list_head link;
};
```
### find
* Generate hash value from the remainder.
* Due to the possibility of different key values producing the same hash value, it is necessary to access the hash table `heads[hash]` and check for a matching number.
```c
static struct seq_node *find(int num, int size, struct list_head *heads)
{
struct seq_node *node;
int hash = num < 0 ? -num % size : num % size;
list_for_each_entry (node, &heads[hash], link) {
if (node->num == num)
return node;
}
return NULL;
}
```
### longestConsecutive
* `node`: Used to represent each element in the sequence.
* `heads`: An array of linked list. Each index in the array corresponds to a hash value.
* `line 10`: Inserts each `num` (element) from the array `nums` into the appropriate linked list based on its hash value. It avoids duplicates using the find function.
* `line 19`: For each element in the array, it searches for a consecutive sequence by checking elements to the left and right. If the node is located in the linked list, deletes it to avoid duplicates.
* `line 42`: The length of the sequence is updated, and the maximum length is stored in the length variable.
```c=
int longestConsecutive(int *nums, int n_size)
{
int hash, length = 0;
struct seq_node *node;
struct list_head *heads = malloc(n_size * sizeof(*heads));
for (int i = 0; i < n_size; i++)
INIT_LIST_HEAD(&heads[i]);
for (int i = 0; i < n_size; i++) {
if (!find(nums[i], n_size, heads)) {
hash = nums[i] < 0 ? -nums[i] % n_size : nums[i] % n_size;
node = malloc(sizeof(*node));
node->num = nums[i];
list_add(&node->link, &heads[hash]);
}
}
for (int i = 0; i < n_size; i++) {
int len = 0;
int num;
node = find(nums[i], n_size, heads);
while (node) {
len++;
num = node->num;
list_del(&node->link);
free(node);
int left = num, right = num;
while ((node = find(--left, n_size, heads))) {
len++;
list_del(&node->link);
free(node);
}
while ((node = find(++right, n_size, heads))) {
len++;
list_del(&node->link);
free(node);
}
length = len > length ? len : length;
}
}
free(heads);
return length;
}
```
### Complete code
* Include `list.h` from [include/linux/list.h](https://github.com/torvalds/linux/blob/master/include/linux/list.h).
```c
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
struct seq_node {
int num;
struct list_head link;
};
static struct seq_node *find(int num, int size, struct list_head *heads) {
struct seq_node *node;
int hash = num < 0 ? -num % size : num % size;
list_for_each_entry(node, &heads[hash], link) {
if (node->num == num)
return node;
}
return NULL;
}
int longestConsecutive(int *nums, int n_size) {
int hash, length = 0;
struct seq_node *node;
struct list_head *heads = malloc(n_size * sizeof(*heads));
for (int i = 0; i < n_size; i++)
INIT_LIST_HEAD(&heads[i]);
for (int i = 0; i < n_size; i++) {
if (!find(nums[i], n_size, heads)) {
hash = nums[i] < 0 ? -nums[i] % n_size : nums[i] % n_size;
node = malloc(sizeof(*node));
node->num = nums[i];
list_add(&node->link, &heads[hash]);
}
}
for (int i = 0; i < n_size; i++) {
int len = 0;
int num;
node = find(nums[i], n_size, heads);
while (node) {
len++;
num = node->num;
list_del(&node->link);
free(node);
int left = num, right = num;
while ((node = find(--left, n_size, heads))) {
len++;
list_del(&node->link);
free(node);
}
while ((node = find(++right, n_size, heads))) {
len++;
list_del(&node->link);
free(node);
}
length = len > length ? len : length;
}
}
free(heads);
return length;
}
int main()
{
int nums[6] = {100, 4, 200, 1, 3, 2}, len;
len = longestConsecutive(nums, 6);
printf("len: %d\n", len);
int nums_2[10] = {0, 3, 7, 2, 5, 8, 4, 6, 0, 1};
len = longestConsecutive(nums_2, 10);
printf("len: %d\n", len);
return 0;
}
```
## Implement hash tables in the style of the Linux kernel
I use the same method on [Two sum](https://leetcode.com/problems/two-sum/). For more details, please refer [ericlinsechs: Leetcode 1. Two sum](https://hackmd.io/@ericlinsechs/two_sum).
```c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
typedef struct {
int size;
struct hlist_head *ht;
} map_t;
struct hash_key {
int num;
struct hlist_node node;
};
#ifndef container_of
#ifdef __LIST_HAVE_TYPEOF
#define container_of(ptr, type, member) \
__extension__({ \
const __typeof__(((type *)0)->member) *__pmember = (ptr); \
(type *)((char *)__pmember - offsetof(type, member)); \
})
#else
#define container_of(ptr, type, member) \
((type *)((char *)(ptr)-offsetof(type, member)))
#endif
#endif
map_t *map_init(int size) {
map_t *map = malloc(sizeof(map_t));
if (!map)
return NULL;
map->size = size;
map->ht = malloc(sizeof(struct hlist_head) * size);
if (map->ht) {
for (int i = 0; i < size; i++)
(map->ht)[i].first = NULL;
} else {
free(map);
map = NULL;
}
return map;
}
static struct hash_key *find_num(map_t *map, int num) {
int hash = num < 0 ? -num % map->size : num % map->size;
struct hlist_head *head = &(map->ht)[hash];
for (struct hlist_node *p = head->first; p; p = p->next) {
struct hash_key *kn = container_of(p, struct hash_key, node);
if (kn->num == num)
return kn;
}
return NULL;
}
void map_add(map_t *map, int num) {
struct hash_key *kn = find_num(map, num);
if (kn)
return;
kn = malloc(sizeof(struct hash_key));
kn->num = num;
int hash = num < 0 ? -num % map->size : num % map->size;
struct hlist_head *h = &map->ht[hash];
struct hlist_node *n = &kn->node, *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
static inline void hlist_del(struct hlist_node *n) {
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
int longestConsecutive(int *nums, int n_size) {
int length = 0;
map_t *map = map_init(n_size);
for (int i = 0; i < n_size; i++) {
if (!find_num(map, nums[i]))
map_add(map, nums[i]);
}
for (int i = 0; i < n_size; i++) {
int len = 0;
int num;
struct hash_key *kn = find_num(map, nums[i]);
while (kn) {
len++;
num = kn->num;
hlist_del(&kn->node);
free(kn);
int left = num, right = num;
while (kn = find_num(map, --left)) {
len++;
hlist_del(&kn->node);
free(kn);
}
while (kn = find_num(map, ++right)) {
len++;
hlist_del(&kn->node);
free(kn);
}
length = len > length ? len : length;
}
}
free(map->ht);
free(map);
return length;
}
int main()
{
int nums[6] = {100, 4, 200, 1, 3, 2}, len;
len = longestConsecutive(nums, 6);
printf("len: %d\n", len);
int nums_2[10] = {0, 3, 7, 2, 5, 8, 4, 6, 0, 1};
len = longestConsecutive(nums_2, 10);
printf("len: %d\n", len);
return 0;
}
```