Рубрики
Без рубрики

Решение: самая длинная последовательная последовательность

Это является частью серии пояснений решения LeetCode (индекс). Если вам понравилось это решение или Фу … помечены алгоритмами, JavaScript, Java, Python.

Это является частью серии объяснений решения LeetCode ( index ). Если вам понравилось это решение или нашел его полезным, Пожалуйста, как Этот пост и/или УПОТАТЬ Мое решение пост на форумах LeetCode Отказ

Проблема летакода № 128 (средний): Самая длинная последовательная последовательность

Описание:

( Перейти к : Идея решения Код : JavaScript | Python |. Java |. C ++

Учитывая несортированный массив целых чисел Nums , вернуть Длина самых длинных последовательных последовательных элементов Отказ

Вы должны написать алгоритм, который работает в O (n) время.

Примеры:

Вход: nums = [100,4,200,1,3,2]
Вывод: 4
Объяснение: Самые длинные последовательные последовательные элементы представляют собой [1, 2, 3, 4]. Поэтому его длина 4.
Вход: nums = [0,3,7,2,5,8,4,6,0,1]
Вывод: 9

Ограничения:

  • 0.Length ^ 5.
  • -10 ^ 9 [I] ^ 9

Идея:

( Перейти к : Описание проблемы Код : JavaScript | Python |. Java |. C ++

Для того, чтобы выполнить эту задачу в O (n) время , мы должны иметь возможность поиска ценностей ( NMAP ), что означает Установить или карта объект. Нам также понадобится какой-то способ отслеживать, какие номера уже были видно Отказ

( Примечание : Мы могли бы отказаться видимый Структура данных полностью и просто следуйте каждому пути к его концу каждый раз, но это заставит нас переделать одни и те же разделы снова и снова, толкая Сложность времени к O (n ^ 2) .)

Если мы используем набор для NMAP тогда нам нужно было бы использовать карту для видно Для того, чтобы иметь возможность посмотреть номера по значению. Если мы вместо этого используем карту для NMAP , с каждым числом, указывающим на его индекс, то мы можем вместо этого использовать эти индексы с Массив для видно , что будет более эффективным.

( Примечание : Так как мы будем итерации числа С фронта до обратно в следующем разделе мы должны убедиться, что мы храним только первый индекс, на котором находится номер в невысокий . Позже показатели дублированных чисел могут быть проигнорированы, как к тому, номер уже будет рассмотрено видимый .)

Но теперь мы столкнулись с проблемой потенциально нахождения середины последовательности, прежде чем находить начало последовательности. Для этого мы можем вдохновлять из Союз найди подход и/или Динамическое программирование ( DP ) подход; Мы можем использовать видно хранить длину последовательности, найденной при запуске с указанного номера.

( Примечание : Нам не нужно хранить данные длины пути в любом, но наименьшее количество найденных цепочек, так как эти узлы никогда не могут быть активно посещены снова. Только точка входа, которая является наименьшим числом, необходимо хранить точную длину пути. Для других чисел нам просто нужно зарегистрировать их, как видно, поэтому мы можем просто заполнить их a 1 или любой ненулевой номер, чтобы сделать чек простой.)

Затем, если мы позже найдем более раннее число в той же последовательности, мы можем заметить значение, хранящееся в видно Когда мы связываемся с уже посещенным хвостовым концом одной и той же последовательности и просто добавьте это значение (представляющее длину хвоста) нашим Считать чисел.

Например, рассмотрим nums = [4,5,6,1,2,3,0] . Мы начинаем в 4 Затем отслеживать 5 и 6 , заполняя видно Индексы, соответствующие 5 и 6 с 1 Каждый ( видел [1] , видел [2] ). Как только мы достигнем конца этой цепочки и имеют Считать 3 мы храним это 3 в видно Индекс, соответствующий 4 ( видно [0] ).

Тогда, потому что мы видели 5 и 6 при проверке 4 мы пропускаем 1 Отказ На 1 мы отслеживаем через 2 и 3 , заполняя их 1 S ( видно [4] , видел [5] ). После этого мы бежим в 4 , который имеет значение 3 хранится в видимый . На данный момент Считать это 3 (Из чисел 1 , 2 и 3 ), но мы просто бегали в другую уже обнаруженную цепочку 3 (Числа 4 , 5 и 6 ), чтобы мы могли заполнить видно Индекс, соответствующий 1 с 6 ( видно [3] ).

Тогда мы пропустим мимо 2 и 3 и 0 приведет нас к 1 Итак, у нас будет результат 7 для видно Индекс, соответствующий 0 ( видно [6] ).

На каждом шаге, когда мы собираемся хранить Считать в видно , мы также можем обновить наш лучший результат до сих пор ( ANS ). Затем, как только мы достигли конца итерации, мы можем просто Вернуть АНС Отказ

  • Сложность времени: O (n) где N это длина числа
  • Космическая сложность: O (n) за невысокий и видимый

Код JavaScript:

( Перейти к : Описание проблемы Идея решения

var longestConsecutive = function(nums) {
    let nmap = new Map(), ans = 0,
        seen = new Uint32Array(nums.length)
    for (let i = 0; i < nums.length; i++)
        if (!nmap.has(nums[i])) nmap.set(nums[i], i)
    for (let n of nums) {
        let curr = n, count = 1
        if (seen[nmap.get(curr)]) continue
        while (nmap.has(curr+1)) {
            let ix = nmap.get(++curr)
            if (seen[ix]) {
                count += seen[ix]
                break
            } else seen[ix] = 1, count++
        }
        seen[nmap.get(n)] = count
        ans = Math.max(ans, count)
    }
    return ans
};

Код Python:

( Перейти к : Описание проблемы Идея решения

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        nmap, seen, ans = defaultdict(int), [0] * len(nums), 0
        for i in range(len(nums)):
            if nums[i] not in nmap: nmap[nums[i]] = i
        for n in nums:
            curr, count = n, 1
            if seen[nmap[n]]: continue
            while curr+1 in nmap:
                curr += 1
                ix = nmap[curr]
                if seen[ix]:
                    count += seen[ix]
                    break
                else:
                    seen[ix] = 1
                    count += 1
            seen[nmap[n]], ans = count, max(ans, count)
        return ans

Java код:

( Перейти к : Описание проблемы Идея решения

class Solution {
    public int longestConsecutive(int[] nums) {
        Map nmap = new HashMap<>();
        int ans = 0;
        int[] seen = new int[nums.length];
        for (int i = 0; i < nums.length; i++)
            if (!nmap.containsKey(nums[i])) nmap.put(nums[i], i);
        for (int n : nums) {
            int curr = n, count = 1;
            if (seen[nmap.get(curr)] > 0) continue;
            while (nmap.containsKey(curr+1)) {
                int ix = nmap.get(++curr);
                if (seen[ix] > 0) {
                    count += seen[ix];
                    break;
                } else {
                    seen[ix] = 1;
                    count++;
                }
            }
            seen[nmap.get(n)] = count;
            ans = Math.max(ans, count);
        }
        return ans;
    }
}

C ++ код:

( Перейти к : Описание проблемы Идея решения

class Solution {
public:
    int longestConsecutive(vector& nums) {
        unordered_map nmap;
        int ans = 0;
        vector seen(nums.size());
        for (int i = 0; i < nums.size(); i++)
            if (nmap.find(nums[i]) == nmap.end())
                nmap[nums[i]] = i;
        for (auto& n : nums) {
            int curr = n, count = 1;
            if (seen[nmap[curr]]) continue;
            while (nmap.find(curr+1) != nmap.end()) {
                int ix = nmap[++curr];
                if (seen[ix]) {
                    count += seen[ix];
                    break;
                } else seen[ix] = 1, count++;
            }
            seen[nmap[n]] = count;
            ans = max(ans, count);
        }
        return ans;
    }
};

Оригинал: “https://dev.to/seanpgallivan/solution-longest-consecutive-sequence-27ni”