Leetcode

[Leetcode] 128. Longest Consecutive Sequence

mjk- 2025. 3. 19. 16:36

문제

Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.

You must write an algorithm that runs in O(n) time.

 

Example 1:

Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.

Example 2:

Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9

Example 3:

Input: nums = [1,0,1,2]
Output: 3

 

Constraints:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109

 

풀이

 

qsort를 사용하면 time complexity가 nlog(n)이 되므로 사용할 수 없다.

핵심은 hash table을 사용해 빠르게 필요한 숫자(num+1 || num-1)를 찾고, 찾았다면 없애는 것이다. 

 

두개의 while loop을 사용한 이유는 보통 아래의 코드를 사용할 텐데: 

// Find longest consecutive sequence
    for (int i = 0; i < numsSize; i++) {
        if (!searchHash(table, nums[i] - 1)) { // (*****Start of a sequence *****) - avoid repeating
            int currentNum = nums[i];
            int currentLen = 1;

            while (searchHash(table, currentNum + 1)) { // Check next numbers - assuming currentNum is the smallest num of consecutive nums
                currentNum++;
                currentLen++;
            }

            maxLen = (currentLen > maxLen) ? currentLen : maxLen;
        }
    }

 

이 코드는 repeated number가 많을 때 에러가 난다.

예를 들어, this passes if the input is an array of [1,2,3,4,...,49999, 50000]. 

However, this does not pass if the input is an array of [1,2,3,4,...,49999, 50000, 0,0,0,0,0,0,0,0,0,...,0]. (0의 갯수가 클 때)

 

We know the number should be removed if it was searched. 

하지만 첫 번째로 찾은 숫자가 consecutive numbers 상의 가장 작은 숫자가 아닐때 없애버리면 max consecutive number를 찾지 못하므로, 한번에 모든 consecutive numbers를 찾기위해 2개의 while loop이 필요하다.

 

코드

 

Simpler code: 

typedef struct HashNode{ 
    int key;
    struct HashNode * next;
} HashNode;

typedef struct HashTable{ 
    HashNode** buckets;
    int size;
} HashTable;

int hashfunction(int key, int size) {
    return abs(key)%size;
}

HashTable* createTable(int size) {
    HashTable* table = (HashTable*)malloc(sizeof(HashTable));
    table->size = size;
    table->buckets = (HashNode**)calloc(size, sizeof(HashNode*));
    return table;
}

void insertTable(HashTable* table, int key) {
    int index = hashfunction(key, table->size);
    HashNode* node = (HashNode*)malloc(sizeof(HashNode));
    node->key = key;
    node->next = table->buckets[index];
    table->buckets[index] = node;
}
bool searchNode(HashTable* table, int key) {
    int index = hashfunction(key, table->size);
    HashNode* curr = table->buckets[index];
    while(curr) {
        if(curr->key == key) {
            curr->key = INT_MIN; // remove the number
            return true;
        }
        curr = curr->next;
    }
    return false;
}

void freeTable(HashTable * table) {
    for(int i=0; i<table->size; i++){
        HashNode* curr = table->buckets[i];
        while(curr) {
            HashNode* temp = curr->next;
            free(curr);
            curr = temp;
        }
    }
    free(table->buckets);
    free(table);
}
int longestConsecutive(int* nums, int numsSize) {
    // int tableSize = (numsSize > 30000)? 30000 : numsSize;
    int tableSize = numsSize;
    HashTable* table = createTable(tableSize);

    // create table
    for(int i=0; i<tableSize; i++) {
        insertTable(table, nums[i]);
    }

    int longest = 0;
    // search longest consec
    for(int i=0; i<tableSize; i++) {
        int num = nums[i];
        int j = 1;
        int consec = 1;

        while(searchNode(table, num-j)) {
            consec++;
            j++;
        }
        j=1;
        while(searchNode(table, num+j)) {
            consec++;
            j++;
        }
        longest = (longest < consec)? consec : longest;
    }
    freeTable(table);
    return longest;
}

 

* 여기서 숫자를 제거하는 코드는 간단히 가장 작은 숫자(INT_MIN)로 대체되었지만, linked list에서 제거하는 것이 logic이 맞다.

 

 

Correct code: (less runtime!)

typedef struct HashNode{ 
    int key;
    struct HashNode * next;
} HashNode;

typedef struct HashTable{ 
    HashNode** buckets;
    int size;
} HashTable;

int hashfunction(int key, int size) {
    return abs(key)%size;
}

HashTable* createTable(int size) {
    HashTable* table = (HashTable*)malloc(sizeof(HashTable));
    table->size = size;
    table->buckets = (HashNode**)calloc(size, sizeof(HashNode*));
    return table;
}

void insertTable(HashTable* table, int key) {
    int index = hashfunction(key, table->size);
    HashNode* node = (HashNode*)malloc(sizeof(HashNode));
    node->key = key;
    node->next = table->buckets[index];
    table->buckets[index] = node;
}
bool searchNode(HashTable* table, int key) {
    int index = hashfunction(key, table->size);
    HashNode* curr = table->buckets[index];
    while(curr) {
        if(curr->key == key) {
            curr->key = INT_MIN; // remove the number
            return true;
        }
        curr = curr->next;
    }
    return false;
}

// Search and remove from hash table
bool searchAndRemove(HashTable* table, int key) {
    int index = hashfunction(key, table->size);
    HashNode* curr = table->buckets[index];
    HashNode* prev = NULL;

    while (curr) {
        if (curr->key == key) {
            // Remove node from linked list
            if (prev) {
                prev->next = curr->next;
            } else {
                table->buckets[index] = curr->next;
            }
            free(curr);
            return true;
        }
        prev = curr;
        curr = curr->next;
    }
    return false;
}

void freeTable(HashTable * table) {
    for(int i=0; i<table->size; i++){
        HashNode* curr = table->buckets[i];
        while(curr) {
            HashNode* temp = curr->next;
            free(curr);
            curr = temp;
        }
    }
    free(table->buckets);
    free(table);
}

int longestConsecutive(int* nums, int numsSize) {
    // int tableSize = (numsSize > 30000)? 30000 : numsSize;
    int tableSize = numsSize;
    HashTable* table = createTable(tableSize);

    // create table
    for(int i=0; i<tableSize; i++) {
        insertTable(table, nums[i]);
    }

    int longest = 0;
    // search longest consec
    for(int i=0; i<tableSize; i++) {
        int num = nums[i];
        int j = 1;
        int consec = 1;

        while(searchAndRemove(table, num-j)) {
            consec++;
            j++;
        }
        j=1;
        while(searchAndRemove(table, num+j)) {
            consec++;
            j++;
        }
        longest = (longest < consec)? consec : longest;
    }
    freeTable(table);
    return longest;
}

'Leetcode' 카테고리의 다른 글

[Leetcode] 394. Decode String  (0) 2025.03.19
[Leetcode] 328. Odd Even Linked List  (0) 2025.03.19
[Leetcode] 189. Rotate Array  (0) 2025.03.19
[Leetcode] 97. Interleaving String  (0) 2025.03.17
[Leetcode] 1019. Next Greater Node In Linked List  (0) 2025.03.17