学好数据结构与算法其实一点也不难

news2024/9/25 19:21:24

一. 初识算法

1.1 什么是算法?

定义

在数学和计算机科学领域,算法是一系列有限的严谨指令,通常用于解决一类特定问题或执行计算

In mathematics and computer science, an algorithm (/ˈælɡərɪðəm/) is a finite sequence of rigorous instructions, typically used to solve a class of specific problems or to perform a computation.[^1]

Introduction to Algorithm[^2]

不正式的说,算法就是任何定义优良的计算过程:接收一些值作为输入,在有限的时间内,产生一些值作为输出。

Informally, an algorithm is any well-defined computational procedure that takes some value, or set of values, as input and produces some value, or set of values, as output in a finite amount of time.

1.2 什么是数据结构?

定义

在计算机科学领域,数据结构是一种数据组织、管理和存储格式,通常被选择用来高效访问数据

In computer science, a data structure is a data organization, management, and storage format that is usually chosen for efficient access to data

Introduction to Algorithm[^2]

数据结构是一种存储和组织数据的方式,旨在便于访问和修改

A data structure is a way to store and organize data in order to facilitate access and modifications

接下来我们通过对一个非常著名的二分查找算法的讲解来认识一下算法

1.3 二分查找 [^3]

二分查找算法也称折半查找,是一种非常高效的工作于有序数组的查找算法。后续的课程中还会学习更多的查找算法,但在此之前,不妨用它作为入门。

二分查找基础版

需求:在有序数组 A A A 内,查找值 t a r g e t target target

  • 如果找到返回索引
  • 如果找不到返回 − 1 -1 1
算法描述
前提给定一个内含 n n n 个元素的有序数组 A A A,满足 A 0 ≤ A 1 ≤ A 2 ≤ ⋯ ≤ A n − 1 A_{0}\leq A_{1}\leq A_{2}\leq \cdots \leq A_{n-1} A0A1A2An1,一个待查值 t a r g e t target target
1设置 i = 0 i=0 i=0 j = n − 1 j=n-1 j=n1
2如果 i > j i \gt j i>j,结束查找,没找到
3设置 m = f l o o r ( i + j 2 ) m = floor(\frac {i+j}{2}) m=floor(2i+j) m m m 为中间索引, f l o o r floor floor 是向下取整( ≤ i + j 2 \leq \frac {i+j}{2} 2i+j 的最小整数)
4如果 t a r g e t < A m target < A_{m} target<Am 设置 j = m − 1 j = m - 1 j=m1,跳到第2步
5如果 A m < t a r g e t A_{m} < target Am<target 设置 i = m + 1 i = m + 1 i=m+1,跳到第2步
6如果 A m = t a r g e t A_{m} = target Am=target,结束查找,找到了

java 实现

public static int binarySearch(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {			// 在左边
            j = m - 1;
        } else if (a[m] < target) {		// 在右边
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}
  • i , j i,j i,j 对应着搜索区间 [ 0 , a . l e n g t h − 1 ] [0,a.length-1] [0,a.length1](注意是闭合的区间), i < = j i<=j i<=j 意味着搜索区间内还有未比较的元素, i , j i,j i,j 指向的元素也可能是比较的目标
    • 思考:如果不加 i = = j i==j i==j 行不行?
    • 回答:不行,因为这意味着 i , j i,j i,j 指向的元素会漏过比较
  • m m m 对应着中间位置,中间位置左边和右边的元素可能不相等(差一个),不会影响结果
  • 如果某次未找到,那么缩小后的区间内不包含 m m m

二分查找改变版

另一种写法

public static int binarySearch(int[] a, int target) {
    int i = 0, j = a.length;
    while (i < j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {			// 在左边
            j = m;
        } else if (a[m] < target) {		// 在右边
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}
  • i , j i,j i,j 对应着搜索区间 [ 0 , a . l e n g t h ) [0,a.length) [0,a.length)(注意是左闭右开的区间), i < j i<j i<j 意味着搜索区间内还有未比较的元素, j j j 指向的一定不是查找目标
    • 思考:为啥这次不加 i = = j i==j i==j 的条件了?
    • 回答:这回 j j j 指向的不是查找目标,如果还加 i = = j i==j i==j 条件,就意味着 j j j 指向的还会再次比较,找不到时,会死循环
  • 如果某次要缩小右边界,那么 j = m j=m j=m,因为此时的 m m m 已经不是查找目标了

衡量算法好坏

时间复杂度

下面的查找算法也能得出与之前二分查找一样的结果,那你能说出它差在哪里吗?

public static int search(int[] a, int k) {
    for (
        int i = 0;
        i < a.length;
        i++
    ) {
        if (a[i] == k) {
            return i;
        }
    }
    return -1;
}

考虑最坏情况下(没找到)例如 [1,2,3,4] 查找 5

  • int i = 0 只执行一次
  • i < a.length 受数组元素个数 n n n 的影响,比较 n + 1 n+1 n+1
  • i++ 受数组元素个数 n n n 的影响,自增 n n n
  • a[i] == k 受元素个数 n n n 的影响,比较 n n n
  • return -1,执行一次

粗略认为每行代码执行时间是 t t t,假设 n = 4 n=4 n=4 那么

  • 总执行时间是 ( 1 + 4 + 1 + 4 + 4 + 1 ) ∗ t = 15 t (1+4+1+4+4+1)*t = 15t (1+4+1+4+4+1)t=15t
  • 可以推导出更一般地公式为, T = ( 3 ∗ n + 3 ) t T = (3*n+3)t T=(3n+3)t

如果套用二分查找算法,还是 [1,2,3,4] 查找 5

public static int binarySearch(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {			// 在左边
            j = m - 1;
        } else if (a[m] < target) {		// 在右边
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}
  • int i = 0, j = a.length - 1 各执行 1 次

  • i <= j 比较 f l o o r ( log ⁡ 2 ( n ) + 1 ) floor(\log_{2}(n)+1) floor(log2(n)+1) 再加 1 次

  • (i + j) >>> 1 计算 f l o o r ( log ⁡ 2 ( n ) + 1 ) floor(\log_{2}(n)+1) floor(log2(n)+1)

  • 接下来 if() else if() else 会执行 3 ∗ f l o o r ( log ⁡ 2 ( n ) + 1 ) 3* floor(\log_{2}(n)+1) 3floor(log2(n)+1) 次,分别为

    • if 比较
    • else if 比较
    • else if 比较成立后的赋值语句
  • return -1,执行一次

结果:

  • 总执行时间为 ( 2 + ( 1 + 3 ) + 3 + 3 ∗ 3 + 1 ) ∗ t = 19 t (2 + (1+3) + 3 + 3 * 3 +1)*t = 19t (2+(1+3)+3+33+1)t=19t
  • 更一般地公式为 ( 4 + 5 ∗ f l o o r ( log ⁡ 2 ( n ) + 1 ) ) ∗ t (4 + 5 * floor(\log_{2}(n)+1))*t (4+5floor(log2(n)+1))t

注意:

左侧未找到和右侧未找到结果不一样,这里不做分析

两个算法比较,可以看到 n n n 在较小的时候,二者花费的次数差不多

但随着 n n n 越来越大,比如说 n = 1000 n=1000 n=1000 时,用二分查找算法(红色)也就是 54 t 54t 54t,而蓝色算法则需要 3003 t 3003t 3003t

画图采用的是 Desmos | 图形计算器

计算机科学中,时间复杂度是用来衡量:一个算法的执行,随数据规模增大,而增长的时间成本

  • 不依赖于环境因素

如何表示时间复杂度呢?

  • 假设算法要处理的数据规模是 n n n,代码总的执行行数用函数 f ( n ) f(n) f(n) 来表示,例如:

    • 线性查找算法的函数 f ( n ) = 3 ∗ n + 3 f(n) = 3*n + 3 f(n)=3n+3
    • 二分查找算法的函数 f ( n ) = ( f l o o r ( l o g 2 ( n ) ) + 1 ) ∗ 5 + 4 f(n) = (floor(log_2(n)) + 1) * 5 + 4 f(n)=(floor(log2(n))+1)5+4
  • 为了对 f ( n ) f(n) f(n) 进行化简,应当抓住主要矛盾,找到一个变化趋势与之相近的表示法

O O O 表示法[^4]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4RlAPIJv-1677477938691)(.\imgs\image-20221108103846566.png)]

其中

  • c , c 1 , c 2 c, c_1, c_2 c,c1,c2 都为一个常数
  • f ( n ) f(n) f(n) 是实际执行代码行数与 n 的函数
  • g ( n ) g(n) g(n) 是经过化简,变化趋势与 f ( n ) f(n) f(n) 一致的 n 的函数

渐进上界

渐进上界(asymptotic upper bound):从某个常数 n 0 n_0 n0开始, c ∗ g ( n ) c*g(n) cg(n) 总是位于 f ( n ) f(n) f(n) 上方,那么记作 O ( g ( n ) ) O(g(n)) O(g(n))

  • 代表算法执行的最差情况

例1

  • f ( n ) = 3 ∗ n + 3 f(n) = 3*n+3 f(n)=3n+3
  • g ( n ) = n g(n) = n g(n)=n
  • c = 4 c=4 c=4,在 n 0 = 3 n_0=3 n0=3 之后, g ( n ) g(n) g(n) 可以作为 f ( n ) f(n) f(n) 的渐进上界,因此表示法写作 O ( n ) O(n) O(n)

例2

  • f ( n ) = 5 ∗ f l o o r ( l o g 2 ( n ) ) + 9 f(n) = 5*floor(log_2(n)) + 9 f(n)=5floor(log2(n))+9
  • g ( n ) = l o g 2 ( n ) g(n) = log_2(n) g(n)=log2(n)
  • O ( l o g 2 ( n ) ) O(log_2(n)) O(log2(n))

已知 f ( n ) f(n) f(n) 来说,求 g ( n ) g(n) g(n)

  • 表达式中相乘的常量,可以省略,如
    • f ( n ) = 100 ∗ n 2 f(n) = 100*n^2 f(n)=100n2 中的 100 100 100
  • 多项式中数量规模更小(低次项)的表达式,如
    • f ( n ) = n 2 + n f(n)=n^2+n f(n)=n2+n 中的 n n n
    • f ( n ) = n 3 + n 2 f(n) = n^3 + n^2 f(n)=n3+n2 中的 n 2 n^2 n2
  • 不同底数的对数,渐进上界可以用一个对数函数 log ⁡ n \log n logn 表示
    • 例如: l o g 2 ( n ) log_2(n) log2(n) 可以替换为 l o g 10 ( n ) log_{10}(n) log10(n),因为 l o g 2 ( n ) = l o g 10 ( n ) l o g 10 ( 2 ) log_2(n) = \frac{log_{10}(n)}{log_{10}(2)} log2(n)=log10(2)log10(n),相乘的常量 1 l o g 10 ( 2 ) \frac{1}{log_{10}(2)} log10(2)1 可以省略
  • 类似的,对数的常数次幂可省略
    • 如: l o g ( n c ) = c ∗ l o g ( n ) log(n^c) = c * log(n) log(nc)=clog(n)

常见大 O O O 表示法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xrIHKZ6y-1677477938695)(.\imgs\image-20221108114915524.png)]

按时间复杂度从低到高

  • 黑色横线 O ( 1 ) O(1) O(1),常量时间,意味着算法时间并不随数据规模而变化
  • 绿色 O ( l o g ( n ) ) O(log(n)) O(log(n)),对数时间
  • 蓝色 O ( n ) O(n) O(n),线性时间,算法时间与数据规模成正比
  • 橙色 O ( n ∗ l o g ( n ) ) O(n*log(n)) O(nlog(n)),拟线性时间
  • 红色 O ( n 2 ) O(n^2) O(n2) 平方时间
  • 黑色朝上 O ( 2 n ) O(2^n) O(2n) 指数时间
  • 没画出来的 O ( n ! ) O(n!) O(n!)

渐进下界

渐进下界(asymptotic lower bound):从某个常数 n 0 n_0 n0开始, c ∗ g ( n ) c*g(n) cg(n) 总是位于 f ( n ) f(n) f(n) 下方,那么记作 Ω ( g ( n ) ) \Omega(g(n)) Ω(g(n))

渐进紧界

渐进紧界(asymptotic tight bounds):从某个常数 n 0 n_0 n0开始, f ( n ) f(n) f(n) 总是在 c 1 ∗ g ( n ) c_1*g(n) c1g(n) c 2 ∗ g ( n ) c_2*g(n) c2g(n) 之间,那么记作 Θ ( g ( n ) ) \Theta(g(n)) Θ(g(n))

空间复杂度

与时间复杂度类似,一般也使用大 O O O 表示法来衡量:一个算法执行随数据规模增大,而增长的额外空间成本

public static int binarySearchBasic(int[] a, int target) {
    int i = 0, j = a.length - 1;    // 设置指针和初值
    while (i <= j) {                // i~j 范围内有东西
        int m = (i + j) >>> 1;
        if(target < a[m]) {         // 目标在左边
            j = m - 1;
        } else if (a[m] < target) { // 目标在右边
            i = m + 1;
        } else {                    // 找到了
            return m;
        }
    }
    return -1;
}

二分查找性能

下面分析二分查找算法的性能

时间复杂度

  • 最坏情况: O ( log ⁡ n ) O(\log n) O(logn)
  • 最好情况:如果待查找元素恰好在数组中央,只需要循环一次 O ( 1 ) O(1) O(1)

空间复杂度

  • 需要常数个指针 i , j , m i,j,m i,j,m,因此额外占用的空间是 O ( 1 ) O(1) O(1)

二分查找平衡版

public static int binarySearchBalance(int[] a, int target) {
    int i = 0, j = a.length;
    while (1 < j - i) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m;
        } else {
            i = m;
        }
    }
    return (a[i] == target) ? i : -1;
}

思想:

  1. 左闭右开的区间, i i i 指向的可能是目标,而 j j j 指向的不是目标
  2. 不奢望循环内通过 m m m 找出目标, 缩小区间直至剩 1 个, 剩下的这个可能就是要找的(通过 i i i
    • j − i > 1 j - i > 1 ji>1 的含义是,在范围内待比较的元素个数 > 1
  3. 改变 i i i 边界时,它指向的可能是目标,因此不能 m + 1 m+1 m+1
  4. 循环内的平均比较次数减少了
  5. 时间复杂度 Θ ( l o g ( n ) ) \Theta(log(n)) Θ(log(n))

二分查找 Java 版

private static int binarySearch0(long[] a, int fromIndex, int toIndex,
                                     long key) {
    int low = fromIndex;
    int high = toIndex - 1;

    while (low <= high) {
        int mid = (low + high) >>> 1;
        long midVal = a[mid];

        if (midVal < key)
            low = mid + 1;
        else if (midVal > key)
            high = mid - 1;
        else
            return mid; // key found
    }
    return -(low + 1);  // key not found.
}
  • 例如 [ 1 , 3 , 5 , 6 ] [1,3,5,6] [1,3,5,6] 要插入 2 2 2 那么就是找到一个位置,这个位置左侧元素都比它小
    • 等循环结束,若没找到,low 左侧元素肯定都比 target 小,因此 low 即插入点
  • 插入点取负是为了与找到情况区分
  • -1 是为了把索引 0 位置的插入点与找到的情况进行区分

Leftmost 与 Rightmost

有时我们希望返回的是最左侧的重复元素,如果用 Basic 二分查找

  • 对于数组 [ 1 , 2 , 3 , 4 , 4 , 5 , 6 , 7 ] [1, 2, 3, 4, 4, 5, 6, 7] [1,2,3,4,4,5,6,7],查找元素4,结果是索引3

  • 对于数组 [ 1 , 2 , 4 , 4 , 4 , 5 , 6 , 7 ] [1, 2, 4, 4, 4, 5, 6, 7] [1,2,4,4,4,5,6,7],查找元素4,结果也是索引3,并不是最左侧的元素

public static int binarySearchLeftmost1(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            candidate = m; // 记录候选位置
            j = m - 1;     // 继续向左
        }
    }
    return candidate;
}

如果希望返回的是最右侧元素

public static int binarySearchRightmost1(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            candidate = m; // 记录候选位置
            i = m + 1;	   // 继续向右
        }
    }
    return candidate;
}

应用

对于 Leftmost 与 Rightmost,可以返回一个比 -1 更有用的值

Leftmost 改为

public static int binarySearchLeftmost(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target <= a[m]) {
            j = m - 1;
        } else {
            i = m + 1;
        }
    }
    return i; 
}
  • leftmost 返回值的另一层含义: < t a r g e t \lt target <target 的元素个数
  • 小于等于中间值,都要向左找

Rightmost 改为

public static int binarySearchRightmost(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else {
            i = m + 1;
        }
    }
    return i - 1;
}
  • 大于等于中间值,都要向右找

几个名词

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLPd6hbi-1677477938697)(./imgs/image-20221125174155058.png)]

范围查询

  • 查询 x < 4 x \lt 4 x<4 0.. l e f t m o s t ( 4 ) − 1 0 .. leftmost(4) - 1 0..leftmost(4)1
  • 查询 x ≤ 4 x \leq 4 x4 0.. r i g h t m o s t ( 4 ) 0 .. rightmost(4) 0..rightmost(4)
  • 查询 4 < x 4 \lt x 4<x,$rightmost(4) + 1 … \infty $
  • 查询 4 ≤ x 4 \leq x 4x l e f t m o s t ( 4 ) . . ∞ leftmost(4) .. \infty leftmost(4)..∞
  • 查询 4 ≤ x ≤ 7 4 \leq x \leq 7 4x7 l e f t m o s t ( 4 ) . . r i g h t m o s t ( 7 ) leftmost(4) .. rightmost(7) leftmost(4)..rightmost(7)
  • 查询 4 < x < 7 4 \lt x \lt 7 4<x<7 r i g h t m o s t ( 4 ) + 1.. l e f t m o s t ( 7 ) − 1 rightmost(4)+1 .. leftmost(7)-1 rightmost(4)+1..leftmost(7)1

求排名 l e f t m o s t ( t a r g e t ) + 1 leftmost(target) + 1 leftmost(target)+1

  • t a r g e t target target 可以不存在,如: l e f t m o s t ( 5 ) + 1 = 6 leftmost(5)+1 = 6 leftmost(5)+1=6
  • t a r g e t target target 也可以存在,如: l e f t m o s t ( 4 ) + 1 = 3 leftmost(4)+1 = 3 leftmost(4)+1=3

求前任(predecessor) l e f t m o s t ( t a r g e t ) − 1 leftmost(target) - 1 leftmost(target)1

  • l e f t m o s t ( 3 ) − 1 = 1 leftmost(3) - 1 = 1 leftmost(3)1=1,前任 a 1 = 2 a_1 = 2 a1=2
  • l e f t m o s t ( 4 ) − 1 = 1 leftmost(4) - 1 = 1 leftmost(4)1=1,前任 a 1 = 2 a_1 = 2 a1=2

求后任(successor) r i g h t m o s t ( t a r g e t ) + 1 rightmost(target)+1 rightmost(target)+1

  • r i g h t m o s t ( 5 ) + 1 = 5 rightmost(5) + 1 = 5 rightmost(5)+1=5,后任 a 5 = 7 a_5 = 7 a5=7
  • r i g h t m o s t ( 4 ) + 1 = 5 rightmost(4) + 1 = 5 rightmost(4)+1=5,后任 a 5 = 7 a_5 = 7 a5=7

求最近邻居

  • 前任和后任距离更近者

教程:2023新版Java数据结构与算法视频教程,java高级程序员必学的数据结构与算法


力扣高评价题目列表

引用自 面试最常考的 100 道算法题分类整理! - 知乎 (zhihu.com)

带 ✔️ 是本课程截至目前为止讲解过的

  • 1. Two Sum (两数之和), Easy, 11757 likes
  • 2. Add Two Numbers (两数相加), Medium, 6524 likes
  • 3. Longest Substring Without Repeating Characters (无重复字符的最长子串), Medium, 5845 likes
  • 4. Median of Two Sorted Arrays (寻找两个正序数组的中位数), Hard, 4303 likes
  • 5. Longest Palindromic Substring (最长回文子串), Medium, 3896 likes
  • 15. 3Sum (三数之和), Medium, 3582 likes
  • 53. Maximum Subarray (最大子序和), Easy, 3533 likes
  • 7. Reverse Integer (整数反转), Easy, 2970 likes
  • 11. Container With Most Water (盛最多水的容器), Medium, 2659 likes
  • 42. Trapping Rain Water (接雨水), Hard, 2552 likes
  • 20. Valid Parentheses (有效的括号), Easy, 2544 likes ✔️
  • 10. Regular Expression Matching (正则表达式匹配), Hard, 2273 likes
  • 26. Remove Duplicates from Sorted Array (删除有序数组中的重复项), Easy, 2146 likes ✔️
  • 136. Single Number (只出现一次的数字), Easy, 1958 likes
  • 22. Generate Parentheses (括号生成), Medium, 1946 likes
  • 206. Reverse Linked List (反转链表), Easy, 1886 likes ✔️
  • 21. Merge Two Sorted Lists (合并两个有序链表), Easy, 1832 likes ✔️
  • 70. Climbing Stairs (爬楼梯), Easy, 1791 likes ✔️
  • 300. Longest Increasing Subsequence (最长递增子序列), Medium, 1773 likes
  • 121. Best Time to Buy and Sell Stock (买卖股票的最佳时机), Easy, 1766 likes
  • 72. Edit Distance (编辑距离), Hard, 1743 likes
  • 14. Longest Common Prefix (最长公共前缀), Easy, 1707 likes
  • 198. House Robber (打家劫舍), Medium, 1585 likes
  • 9. Palindrome Number (回文数), Easy, 1568 likes
  • 146. LRU Cache (LRU 缓存机制), Medium, 1544 likes
  • 19. Remove Nth Node From End of List (删除链表的倒数第 N 个结点), Medium, 1494 likes ✔️
  • 33. Search in Rotated Sorted Array (搜索旋转排序数组), Medium, 1493 likes
  • 46. Permutations (全排列), Medium, 1484 likes
  • 101. Symmetric Tree (对称二叉树), Easy, 1483 likes
  • 84. Largest Rectangle in Histogram (柱状图中最大的矩形), Hard, 1472 likes
  • 39. Combination Sum (组合总和), Medium, 1466 likes
  • 13. Roman to Integer (罗马数字转整数), Easy, 1436 likes
  • 23. Merge k Sorted Lists (合并K个升序链表), Hard, 1436 likes ✔️
  • 17. Letter Combinations of a Phone Number (电话号码的字母组合), Medium, 1436 likes
  • 322. Coin Change (零钱兑换), Medium, 1414 likes
  • 32. Longest Valid Parentheses (最长有效括号), Hard, 1400 likes
  • 287. Find the Duplicate Number (寻找重复数), Medium, 1325 likes
  • 122. Best Time to Buy and Sell Stock II (买卖股票的最佳时机 II), Easy, 1306 likes
  • 160. Intersection of Two Linked Lists (相交链表), Easy, 1302 likes ✔️
  • 55. Jump Game (跳跃游戏), Medium, 1292 likes
  • 76. Minimum Window Substring (最小覆盖子串), Hard, 1280 likes
  • 200. Number of Islands (岛屿数量), Medium, 1270 likes
  • 78. Subsets (子集), Medium, 1269 likes
  • 31. Next Permutation (下一个排列), Medium, 1260 likes
  • 96. Unique Binary Search Trees (不同的二叉搜索树), Medium, 1257 likes
  • 148. Sort List (排序链表), Medium, 1248 likes
  • 236. Lowest Common Ancestor of a Binary Tree (二叉树的最近公共祖先), Medium, 1238 likes
  • 25. Reverse Nodes in k-Group (K 个一组翻转链表), Hard, 1230 likes
  • 6. ZigZag Conversion (Z 字形变换), Medium, 1226 likes
  • 152. Maximum Product Subarray (乘积最大子数组), Medium, 1223 likes
  • 215. Kth Largest Element in an Array (数组中的第K个最大元素), Medium, 1211 likes
  • 8. String to Integer (atoi) (字符串转换整数 (atoi)), Medium, 1168 likes
  • 41. First Missing Positive (缺失的第一个正数), Hard, 1163 likes
  • 283. Move Zeroes (移动零), Easy, 1162 likes
  • 141. Linked List Cycle (环形链表), Easy, 1161 likes ✔️
  • 98. Validate Binary Search Tree (验证二叉搜索树), Medium, 1156 likes
  • 124. Binary Tree Maximum Path Sum (二叉树中的最大路径和), Hard, 1152 likes
  • 105. Construct Binary Tree from Preorder and Inorder Traversal (从前序与中序遍历序列构造二叉树), Medium, 1149 likes
  • 34. Find First and Last Position of Element in Sorted Array (在排序数组中查找元素的第一个和最后一个位置), Medium, 1137 likes ✔️
  • 239. Sliding Window Maximum (滑动窗口最大值), Hard, 1114 likes
  • 142. Linked List Cycle II (环形链表 II), Medium, 1097 likes ✔️
  • 139. Word Break (单词拆分), Medium, 1097 likes
  • 45. Jump Game II (跳跃游戏 II), Medium, 1094 likes
  • 169. Majority Element (多数元素), Easy, 1089 likes
  • 234. Palindrome Linked List (回文链表), Easy, 1072 likes ✔️
  • 62. Unique Paths (不同路径), Medium, 1072 likes
  • 189. Rotate Array (旋转数组), Medium, 1057 likes
  • 94. Binary Tree Inorder Traversal (二叉树的中序遍历), Easy, 1052 likes ✔️
  • 56. Merge Intervals (合并区间), Medium, 1051 likes
  • 88. Merge Sorted Array (合并两个有序数组), Easy, 1041 likes ✔️
  • 560. Subarray Sum Equals K (和为K的子数组), Medium, 1036 likes
  • 279. Perfect Squares (完全平方数), Medium, 1035 likes
  • 35. Search Insert Position (搜索插入位置), Easy, 1005 likes
  • 24. Swap Nodes in Pairs (两两交换链表中的节点), Medium, 996 likes
  • 85. Maximal Rectangle (最大矩形), Hard, 983 likes
  • 28. Implement strStr() (实现 strStr()), Easy, 982 likes
  • 92. Reverse Linked List II (反转链表 II), Medium, 980 likes
  • 155. Min Stack (最小栈), Easy, 979 likes
  • 79. Word Search (单词搜索), Medium, 979 likes
  • 27. Remove Element (移除元素), Easy, 967 likes
  • 51. N-Queens (N 皇后), Hard, 965 likes
  • 75. Sort Colors (颜色分类), Medium, 961 likes
  • 102. Binary Tree Level Order Traversal (二叉树的层序遍历), Medium, 960 likes ✔️
  • 48. Rotate Image (旋转图像), Medium, 960 likes
  • 95. Unique Binary Search Trees II (不同的二叉搜索树 II), Medium, 955 likes
  • 64. Minimum Path Sum (最小路径和), Medium, 954 likes
  • 406. Queue Reconstruction by Height (根据身高重建队列), Medium, 947 likes
  • 226. Invert Binary Tree (翻转二叉树), Easy, 941 likes
  • 437. Path Sum III (路径总和 III), Medium, 937 likes
  • 104. Maximum Depth of Binary Tree (二叉树的最大深度), Easy, 937 likes
  • 237. Delete Node in a Linked List (删除链表中的节点), Easy, 936 likes ✔️
  • 337. House Robber III (打家劫舍 III), Medium, 929 likes
  • 18. 4Sum (四数之和), Medium, 918 likes
  • 91. Decode Ways (解码方法), Medium, 904 likes
  • 207. Course Schedule (课程表), Medium, 897 likes
  • 37. Sudoku Solver (解数独), Hard, 897 likes
  • 175. Combine Two Tables (组合两个表), Easy, 891 likes
  • 416. Partition Equal Subset Sum (分割等和子集), Medium, 886 likes
  • 238. Product of Array Except Self (除自身以外数组的乘积), Medium, 885 likes
  • 114. Flatten Binary Tree to Linked List (二叉树展开为链表), Medium, 877 likes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376370.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MSVCP140.dll下载及安装教程,dll修复方法

MSVCP140.dll是Windows操作系统中的一个DLL文件&#xff0c;许多程序依赖于它来正常运行。如果您尝试运行某个程序时&#xff0c;发现缺少MSVCP140.dll文件&#xff0c;那么您需要下载并安装它才能解决问题。本文将介绍如何MSVCP140.dll下载和安装MSVCP140.dll。 第一步&#x…

解决树莓派 bullseye (11) 系统无法通过 xrdp 远程连接的问题

我手上有一台树莓派 4B&#xff0c;使用官方镜像烧录器烧录老版本操作系统 buster (10) 时可以正常通过 Windows 远程桌面连接上&#xff0c;但换成最新的 bullseye (11) 系统后却无法正常连接远程桌面。 问题复现&#xff1a; 使用官方镜像烧录器烧录&#xff0c;配置用户名为…

CSDN 竞赛 32 期

CSDN 竞赛 32 期1、题目名称&#xff1a;传奇霸业2、题目名称&#xff1a;严查枪火3、题目名称&#xff1a;蚂蚁家族4、题目名称&#xff1a;运输石油小结1、题目名称&#xff1a;传奇霸业 传奇霸业&#xff0c;是兄弟就来干。 小春(HP a)遇到了一只黄金哥布林(HP x)。 小春每…

20个让你效率更高的CSS代码技巧

在本文中&#xff0c;我们想与您分享一个由各大css网站总结推荐的20个有用的规则和实践经验集合。有一些是面向CSS初学者的&#xff0c;有一些知识点是进阶型的。希望每个人通过这篇文章都能学到对自己有用的知识。好了&#xff0c;我们开始。1.注意外边距折叠与其他大多数属性…

从工地转行软件测试,拿下13k+年终奖是种什么体验?

最近&#xff0c;一则名为《我&#xff1a;毕业五年&#xff0c;存款5000。她:中传硕士&#xff0c;火锅店保洁》的视频走红网络&#xff0c;两位名校毕业生看似高开低走的就业经历&#xff0c;引起了很多人的共鸣。她们所传达的并不是所谓的躺平、摆烂&#xff0c;而是希望更多…

spark性能调优(一):Shuffle

Shuffle 一、配置项调优二、减少shuffle数据量三、避免shuffle何为shuffle? 集群中跨进程、跨节点的数据分发(Map的输出文件写到本地磁盘,Reducer把Map的输出文件拉到本地)为什么要shuffle? 准确的说,shuffle是刚需(业务场景决定的),分布式环境中,不同节点不能进行内存交换,只…

加快发展先进制造业势在必行!

众所周知&#xff0c;我国是制造大国&#xff0c;但并非制造强国。而我们在持续发展制造业的进程中也面临着诸多实际问题&#xff0c;如产业发展后续乏力&#xff0c;环境制约异常突出&#xff0c;技术创新能力薄弱&#xff0c;结构调整任务艰巨等等。故而要实现由制造大国向制…

数据结构与算法之二叉树大全

目录二叉树的定义二叉树的性质(特性)满二叉树与完全二叉树链式存储的二叉树顺序存储的二叉树线索二叉树(Threaded BinaryTree)二叉排序树&#xff08;Binary Sort Tree&#xff09;平衡二叉树&#xff08; Balanced Binary Tree&#xff09;为什么使用平衡二叉树&#xff1f;如…

Vue中如何利用websocket实现实时通讯

首先我们可以先做一个简单的例子来学习一下简单的websocket模拟聊天对话的功能 原理很简单&#xff0c;有点像VUE中的EventBus&#xff0c;用emit和on传来传去 首先我们可以先去自己去用node搭建一个本地服务器 步骤如下 1.新建一个app.js&#xff0c;然后创建pagejson.js文…

最简单的代码生成器,netcore平台,EF架构,smartsofthelp

1.dbhelper 原生SQL操作类2.Model 实体层3.EF dbfirst 生成entites 实体操作类4.EF实体接口增删改查操作方法成员5.UI 展示层SQL数据脚本Model/// <summary>/// Model实体层 /// </summary>namespace Smart.Model{/// <summary>/// 数据实体层 T_Eventsmart …

珠海数据智能监控器+SaaS平台 轻松实现SMT生产管控

数据智能监控器 兼容市面上99%的SMT设备 直接读取设备生产数据与状态&#xff0c;如&#xff1a;计划产出、实际产出、累计产出、停机、节拍、线利用率、直通率、停产时间、工单状态、OEE…… 产品功能价值 ◎ OEE不达标报警&#xff0c;一手掌握生产效能 ◎ 首检/巡检/成…

研发人员最希望项目经理和PMO能够做什么?看完不要惊讶

作为项目经理和PMO你考虑过自己在其他人眼中的形象么&#xff1f;知道各个环节最希望你做什么吗&#xff1f;对于最常打交道的研发人员&#xff0c;你知道他们最希望你做什么吗&#xff1f; 如果不能了解其他环节对你的期望&#xff0c;你往往很难获得认同&#xff0c;为此&am…

Golang实现RabbitMQ中死信队列各个情况

下面这段教程针对是你已经有一些基本的MQ的知识&#xff0c;比如说能够很清楚的理解queue、exchange等概念&#xff0c;如果你还不是很理解&#xff0c;我建议你先访问官网查看基本的教程。 文章目录1、造成死信队列的主要原因2、操作逻辑图3、代码实战3.1 针对原因1&#xff1…

win10下Vue环境搭建(脚手架初始化+项目启动)教程(详解多图)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、下载安装node.js二、node.js环境配置三、下载安装vue脚手架前言 初学Vue 搭环境快把我整死了QAQ 差点入门即入土 一、下载安装node.js ①下载地址&#x…

bug的创建和等级

1.如何合理的创建一个bug 创建bug的要素 &#xff1a;问题的版本&#xff0c;发现问题的环境&#xff0c;发现问题的步骤&#xff0c;预取结果&#xff0c;实际结果。 eg&#xff1a; 1.问题的版本&#xff1a;谷歌浏览器108版本 2.发现问题的环境&#xff1a;windows11家庭版…

算法训练营 day56 动态规划 最长递增子序列 最长连续递增序列 最长重复子数组

算法训练营 day56 动态规划 最长递增子序列 最长连续递增序列 最长重复子数组 最长递增子序列 300. 最长递增子序列 - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#x…

如何理解API?API 是如何工作的?(5分钟诠释)

大家可能最近经常听到 API 这个概念&#xff0c;那什么是API&#xff0c;它又有什么特点和好处呢&#xff1f; wiki 百科镇楼 …[APIs are] a set of subroutine definitions, protocols, and tools for building application software. In general terms, it’s a set of cle…

Linux文件属性--软连接和硬链接

文章目录软链接硬链接软链接和硬链接的区别软链接 软链接&#xff08;Soft Link&#xff09;又叫符号链接&#xff08;Symbolic Link &#xff09;&#xff0c;是linux特殊文件的一种&#xff0c;文件类型为l,它的数据是它所链接的文件或目录的路径。软链接可以跨磁盘和 分区…

《数据库系统概论》学习笔记——第三章 关系数据库标准语言SQL

教材为数据库系统概论第五版&#xff08;王珊&#xff09; 最重量级的一章。从后续的学习&#xff0c;基本所有实验&#xff0c;大作业和考试都会涉及SQL&#xff0c;SQL实际上是有很多变化的&#xff0c;书上讲的只是最基本的&#xff08;做了大作业才知道SQL能有这么多变化&a…

移动端自动化测试(一)appium环境搭建

自动化测试有主要有两个分类&#xff0c;接口自动化和ui自动化&#xff0c;ui自动化呢又分移动端的和web端的&#xff0c;当然还有c/s架构的&#xff0c;这种桌面程序应用的自动化&#xff0c;使用QTP&#xff0c;只不过现在没人做了。 web自动化呢&#xff0c;现在基本上都是…