时间空间复杂度

1.复杂度

1.1什么是算法?

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

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

// 计算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("-------------------------------------");
   }
   }

1.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表示法仅仅是一种粗略的分析模型,是一种估算,能帮助我们短时间内了解一个算法的执行效率。

对数阶的细节 对数阶一般省略底数:

由于 log29 ∗ log9n >> log2n,即每个对数基本都可以常数乘另一个对数 所以 O(log2n) 、O(log9n) 统称为 O(logn)

1.3fib函数的时间复杂度分析

斐波那契数

 public class Fib {
     //斐波那契数 0 1 1 2 3 5 8 13...
     public static int fib1(int n){
         if (n <= 1){
             return n;
         }
         return fib1(n-1) + fib1(n-2);
     }
     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;
         }
         return second;
     }
     public static void main(String[] args) {
         final int n = 45;
         Times.test("fib1", new Times.Task() {
             public void execute() {
                 System.out.println(fib1(n));
             }
         });
         Times.test("fib2", new Times.Task() {
             public void execute() {
                 System.out.println(fib2(n));
             }
         });
 ​
     }
 }

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

fib1函数采用递归的方式实现,fib会重复调用子递归,参考树形结构,复杂度为2^n次方

fib2采用循环的方式实现,复杂度仅为O(n)

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

1.4算法的优化方向

  • 用尽量少的存储空间

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

  • 根据情况:空间换时间时间换空间

1.5Leetcode

练习算法网站

平时练习可以不在leetcode网站上写,将模板复制下来到编译器上写

如果有的时候提交了效率不太行,点击详情可以查看效率高的人怎么写的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值