zoukankan      html  css  js  c++  java
  • 复杂度与LeetCode

    复杂度

    什么是算法?

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

    // 计算a和b的和
    public static int plus(int a, int b){
    	return a + b;
    }
    
    // 计算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):估算所需占用的存储空间

    // 计算1+2+3+...+n的和
    public static int sum1(int n){
    	int result = 0;
    	for(int i = 1; i <= n; i++){
    		result += i;
    	}
    	return result;
    }
    //计算1+2+3+...+n的和
    public static int sum2(int n){
    	return (1 + n) * n / 2;
    }
    

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

    大O表示法(Big O)

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

    忽略常数、系数、低阶:

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

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

    对数阶的细节

    对数阶一般省略底数

    • log2n = log29 ∗ log2n

    所以 log2n 、log9n 统称为 logn

    常见的复杂度

    O(1) < O(logn) < O(n) < O(nlogn) < O(n2 ) < O(n3 ) < O(2n ) < O(n!) < O(nn)

    可以借助函数生成工具对比复杂度的大小

    函数图像绘制工具

    数据规模较小时

    数据规模较大时

    多个数据规模的情况

    时间复杂度: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(2n)

    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;
    	// 也可以使用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函数的时间复杂度分析

    fib1 函数和fib2 函数的差别有多大?

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

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

    时间复杂度:视为 O(1)

    算法的优化方向

    用尽量少的存储空间

    用尽量少的执行步骤(执行时间)

    根据情况,可以

    • 空间换时间
    • 时间换空间
  • 相关阅读:
    easyui 分页 MVC
    c#实现万年历示例分享 万年历农历查询
    GroupBy 带条件分组求和
    easyui_tree 复选框 动态加载树
    C#测试运行时间
    MVC 关于easyui-datebox 赋值问题
    MVC 上传 下载
    WindowsService 安装 cmd
    笔记 .Net反射机制
    C# 测试服务器连接 Ping
  • 原文地址:https://www.cnblogs.com/netu/p/14860373.html
Copyright © 2011-2022 走看看