【恋上数据结构】复杂度知识以及 LeetCode 刷题指南

简介: 本文主要介绍复杂度相关知识,以及的对 LeetCode 刷题方法做一个简单的介绍
感谢小码哥的 恋上数据结构,记录课程笔记。

什么是算法?

算法是用于解决特定问题的一系列的执行步骤。

以下算法是为了解决两数相加的问题:

// 计算a和b的和
public static int plue(int a, int b){
    return a + b;
}

以下算法是为了解决 n个数字的和 的问题:

// 1+2+3+...+n
public static int sum(int n){
    int result = 0;
    for(int i = 1; i <= n; i++){
        result += i;
    }
    return result;
}

使用不同算法,解决同一个问题,效率可能相差非常大。比如:

  • 求第 n 个斐波那契数(fibonacci number)

如何评判一个算法的好坏?

如果单从执行效率上进行评估,可能会想到这么一种方案:

  • 比较不同算法对同一组输入的执行处理时间
  • 这种方案也叫做:事后统计法

上述方案有比较明显的缺点:

  • 执行时间严重依赖硬件以及运行时各种不确定的环境因素
  • 必须编写相应的测算代码
  • 测试数据的选择比较难保证公正性

一般从以下维度来评估算法的优劣:

  • 正确性、可读性、健壮性(对不合理输入的反应能力和处理能力)
  • 时间复杂度(time complexity):估算程序指令的执行次数(执行时间)
  • 空间复杂度(space complexity):估算所需占用的存储空间

由于现在硬件发展的较好,一般情况下我们更侧重于时间复杂度


下面代码是一个测试时间效率的小工具:

package com.mj;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 测试时间效率的小工具
 */
public class Times {
    private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS");
    
    public interface Task {
        void execute();
    }
    
    public static void test(String title, Task task) {
        if (task == null) return;
        title = (title == null) ? "" : ("【" + title + "】");
        System.out.println(title);
        System.out.println("开始:" + fmt.format(new Date()));
        long begin = System.currentTimeMillis(); // 开始时间
        task.execute(); // 执行代码
        long end = System.currentTimeMillis(); // 结束时间
        System.out.println("结束:" + fmt.format(new Date()));
        double delta = (end - begin) / 1000.0; // 毫秒转换为秒
        System.out.println("耗时:" + delta + "秒");
        System.out.println("-------------------------------------");
    }
}

大O表示法(Big O)

一般用大O表示法来描述复杂度,它表示的是数据规模 n 对应的复杂度。

忽略常数、系数、低阶:

  • 9 >> O(1)
  • 2n + 3 >> O(n)
  • n^2^ + 2^n^ + 6 >> O(n^2^)
  • 4n^3^ + 3n^2^ + 22n + 100 >> O(n^3^)
  • 写法上,n^3^ 等价于 n^3

注意:大O表示法仅仅是一种粗略的分析模型,是一种估算,能帮助我们短时间内了解一个算法的执行效率。

对数阶的细节

对数阶一般省略底数:

  • 由于 log~2~^9^ ∗ log~9~^n^ >> log~2~^n^,即每个对数基本都可以常数乘另一个对数
  • 所以 O(log~2~^n^) 、O(log~9~^n^) 统称为 O(log^n^)

常见的复杂度

在这里插入图片描述
在这里插入图片描述

可以借助函数生成工具对比复杂度的大小: https://zh.numberempire.com/graphingcalculator.php

在这里插入图片描述

在这里插入图片描述

多个数据规模的情况

时间复杂度:O(n + k)

public static void test(int n, int k){
    for(int i = 0; i < n; i++){
        System.out.println("test");
    }
    for (int i = 0; i < k; i++){
        System.out.println("test");
    }
}

LeetCode刷题指南

首先去 https://leetcode-cn.com/ 注册一个力扣账号。

我们以力扣上一道斐波那契的题目为例,顺便分析算法的时间复杂度。
题目网址:LeetCode: 509.斐波那契数

在这里插入图片描述
以执行 斐波那契数列(递归) 为例,必须写成这样:
在这里插入图片描述

斐波那契数列复杂度分析

斐波那契数列 - 递归

很简单的代码,相信来学数据结构的同学都能看懂。

// O(2^n)
public static int fib1(int n) {
    if (n <= 1) return n;
    return fib1(n - 1) + fib1(n - 2);
}

复杂度分析:
在这里插入图片描述

我们放到力扣上去执行一下:效率奇差无比!
在这里插入图片描述

斐波那契数列 - 循环

不开辟任何空间,只使用循环完成。

// O(n)
public static int fib2(int n) {
    if (n <= 1) return n;
    
    int first = 0;
    int second = 1;
    for (int i = 0; i < n - 1; i++) {
        int sum = first + second;
        first = second;
        second = sum;
    }
    /*
    // 也可以使用while循环
    while (n-- > 1) {
        second += first;
        first = second - first;
    }
    */
    return second;
}

力扣上执行:速度变快了,内存消耗还是很多....
在这里插入图片描述

开辟新的数组空间,用空间换时间。

public static int fib3(int n){
    if(n <= 1) return n;
    
    int[] fib = new int[n+1];
    fib[0] = 0;
    fib[1] = 1;
    for(int i = 2; i < fib.length; i++){
        fib[i] = fib[i-1] + fib[i-2];
    }
    return fib[n];
}

力扣上执行:呃,和上面好像没啥区别。。
在这里插入图片描述

fib函数的时间复杂度分析

上面两种 fib 函数的差别有多大?

  • 如果有一台 1GHz 的普通计算机,运算速度 10^9^ 次每秒,n 为 64
  • O(n) 大约耗时 6.4 $*$ 10^-8^
  • O(2^n^) 大约耗时 584.94
  • 有时候算法之间的差距,往往比硬件方面的差距还要大

斐波那契的线性代数解法-特征方程

在这里插入图片描述

算法的优化方向

  • 用尽量少的存储空间
  • 用尽量少的执行步骤(执行时间)
  • 根据情况:空间换时间时间换空间

后序

【恋上数据结构】数据结构大全

相关文章
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
121 2
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
35 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
2月前
|
算法
数据结构(复杂度)
数据结构(复杂度)
25 0
|
2月前
|
存储 机器学习/深度学习 算法
探索数据结构:入门及复杂度的解锁
探索数据结构:入门及复杂度的解锁
|
2月前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
90 0
|
2月前
力扣(LeetCode)数据结构练习题(2)
力扣(LeetCode)数据结构练习题(2)
31 0
|
2月前
|
存储
力扣(LeetCode)数据结构练习题
力扣(LeetCode)数据结构练习题
53 0
|
4月前
|
机器学习/深度学习 存储 算法
【初阶数据结构篇】时间(空间)复杂度
复杂度是计算机科学中的一个基础概念,它帮助我们理解和评估算法的效率,对于算法设计和优化至关重要。
46 2
【初阶数据结构篇】时间(空间)复杂度