Java leetcodetop100 (3,4) самая длинная непрерывная последовательность, движущийся ноль

топ-3 самой длинной непрерывной последовательности

Учитывая несортированный целочисленный массив nums, найдите длину самой длинной последовательности последовательных чисел (элементы последовательности не обязательно должны быть последовательными в исходном массиве). 
* 
* Пожалуйста, разработайте и реализуйте алгоритм с временной сложностью O(n) для решения этой проблемы. 
* 
* 
* 
* Пример 1: 
* 
* Входные данные: nums = [100,4,200,1,3,2] 
* Выходные данные: 4 
Объяснение: Самая длинная непрерывная последовательность чисел — это [1, 2, 3, 4]. Его длина равна 4.

Мы рассматриваем перечисление каждого числа xxx в массиве, рассматривая его как отправную точку и постоянно пытаясь сопоставить x+1,x+2,⋯x+1, x+2, \cdotsx+1,x+2,⋯ он существует, если предположить, что самое длинное совпадение — это x+yx+yx+y, тогда самая длинная непрерывная последовательность, начинающаяся с xxx, — это x,x+1,x+2,⋯ ,x+yx, x+1, x+2, \ cdots, x+yx,x+1,x+2,⋯,x+y, его длина равна y+1y+1y+1, мы можем продолжать перечислять и обновлять ответ.

Для процесса сопоставления метод грубой силы — это O(n)O(n)O(n) обход массива, чтобы проверить, существует ли число, но на самом деле более эффективный метод — использовать хеш-таблицу для хранения числа в массив, проверьте следующим образом. Существует ли число или нет, можно ли оптимизировать его до временной сложности O(1)O(1)O(1).

Именно из-за этого временная сложность нашего алгоритма все равно будет достигать O(n2)O(n^2)O(n 2 ) 
в худшем случае
 (т. е. внешний слой должен пересчитывать O(n)O(n )O(n) числа, внутренний слой требует насильственного сопоставления O(n)O(n)O(n) раз), что не может удовлетворить требованиям вопроса. Но внимательно проанализировав этот процесс, мы обнаружим, что выполняется множество ненужных перечислений.Если известно, что существует x,x+1,x+2,⋯ ,x+yx, x+1, x+2, \ cdots , непрерывная последовательность x+yx,x+1,x+2,⋯,x+y, но мы начинаем с x+1x+1x+1, x+2x+2x+2 или x+yx+yx+ If вы начнете пытаться сопоставить с y, результат, который вы получите, определенно не будет лучше, чем ответ, начиная с перечисления xxx, поэтому мы можем просто пропустить его, столкнувшись с такой ситуацией во внешнем цикле.

Так как же решить, стоит ли пропускать? Поскольку число xxx, которое мы хотим перечислить, не должно иметь предшествующего номера x-1x-1x-1 в массиве, в противном случае, согласно приведенному выше анализу, мы попытаемся сопоставить x-1x-1x-1, поэтому каждый раз, когда мы проверяем, x-1x-1x-1 существует в хеш-таблице, можно определить, нужно ли его пропустить.

Реализовано через хеш-таблицу

public class Top3 {

    public static void main(String[] args) {
        int[] num = {100,4,200,1,3,2};
        int longgest = getLongestNum(num);
        System.out.println(longgest);
    }

    /**
     * 由于我们要枚举的数 xxx 一定是在数组中不存在前驱数 x−1 的,不然按照上面的分析我们会从 x−1x-1x−1 开始尝试匹配,因此我们每次在哈希表中检查是否存在 x−1x-1x−1 即能判断是否需要跳过了。
     *
     * @param intData
     * @return
     */
    private static int getLongestNum(int[] intData) {
        Set<Integer> intSet = new HashSet();
        for(int i:intData){
            intSet.add(i);
        }

        int longgest = 0;

        for(int j:intSet)
        {
            if(!intSet.contains(j-1)){
                int curentData = j;
                int longgetIndex = 1;

                while (intSet.contains(curentData+1)){
                    longgetIndex++;
                    curentData++;
                }

                longgest = Math.max(longgest,longgetIndex);
            }
        }

        return longgest;
    }
}

top4 перемещает ноль (реализация двойного указателя)

/** 
 * Учитывая числа массива, напишите функцию, которая перемещает все 0 в конец массива, сохраняя при этом относительный порядок ненулевых элементов. 
 * 
 * Обратите внимание, что с массивами необходимо работать на месте, без копирования массива. 
 */
public class Top4 {

    private static void moveData(int[] num){
        /*我们创建两个指针 i 和 j,第一次遍历的时候指针 j 用来记录当前有多少 非0 元素。即遍历的时候每遇到一个 非0 元素就将其往数组左边挪,第一次遍历完后,j 指针的下标就指向了最后一个 非0 元素下标。
第二次遍历的时候,起始位置就从 j 开始到结束,将剩下的这段区域内的元素全部置为 0。
        */
        if(num.length==0)
        {
            return;
        }

        int j = 0;

        for(int i=0;i<num.length;i++){
            if(num[i]!=0){
                num[j]=num[i];
                j++;
            }
        }

        for(int i =j;i<num.length;i++){
            num[i] = 0;
        }
    }

    public static void main(String[] args) {
        int[] num = {1,0,2,3,4,0,5,9,0,7,8,0};
        moveData(num);
        for(int i = 0;i<num.length;i++){
            System.out.println(num[i]);
        }
        System.out.println("---------");
        int[] num2 = {5,0,2,3,4,0,5,9,0,7,8,0};
        moveDataTwo(num2);
        for(int i = 0;i<num2.length;i++){
            System.out.println(num2[i]);
        }
    }


    private static void moveDataTwo(int[] num){
        /*这里参考了快速排序的思想,快速排序首先要确定一个待分割的元素做中间点 x,然后把所有小于等于 x 的元素放到 x 的左边,大于 x 的元素放到其右边。
        这里我们可以用 0 当做这个中间点,把不等于 0(注意题目没说不能有负数)的放到中间点的左边,等于 0 的放到其右边。
        这的中间点就是 0 本身,所以实现起来比快速排序简单很多,我们使用两个指针 i 和 j,只要 nums[i]!=0,我们就交换 nums[i] 和 nums[j]
        */

        if(num.length==0){
            return;
        }
        int j=0;
        for(int i=0;i<num.length;i++){
            if(num[i]!=0){
                int temp = num[i];
                num[i] = num[j];
                num[j++] = temp;
            }
        }
    }

}

рекомендация

отblog.csdn.net/harryptter/article/details/132875097