第零章 什么是算法?(例题)

我们已经了解了算法的概念以及时空复杂度的意义,那么如何具体计算时空复杂度呢?无论是时间复杂度还是空间复杂度,都常用大O渐进表示法来描述。回顾一下它的核心概念:

  • 仅仅保留最高次项。(忽略低阶项和常数项,只保留最高阶项)
  • 最高次项的系数为 1。
  • 假设代码的运行次数为常数,那么统一记作 O(1)。

接下来,通过几个代码示例来更好地理解时间复杂度的计算: 

1 时间复杂度: 

 1.1  常数时间复杂度 O(1)

int getMax(int a, int b) {  
    return (a > b) ? a : b;  
}

 分析:这个函数执行了一个简单的比较操作,并返回两个数中的较大值。无论输入的两个数是多少,这个函数总是执行相同数量的基本操作(一次比较和一次返回)。因此,其时间复杂度是O(1),表示运行时间不随输入规模的增长而变化。

1.2 线性时间复杂度 O(n)

void a(int N, int M)
{
    int count = 0;
    for (int k = 0; k < M; ++ k)
    {
         ++count;
    }
    for (int k = 0; k < N ; ++ k)
    {
         ++count;
    }
    cout << count << endl;
}
  • 时间复杂度:该函数的时间复杂度是 O(M + N)。这是因为无论 M 和 N 的大小如何,函数都需要执行 M + N 次基本操作(这里是 count 的递增)。

  • 重要点:虽然 M 和 N 可能很大,但时间复杂度是线性的,因为它与 M 和 N 的和成正比,而不是它们的乘积或其他非线性关系。

1.3对数时间复杂度 O(log n)

void cal_left(int[] a, int n, int x) {  
    int l = 0, r = n - 1;  
    while(l < r) {  
        int mid = l + r >> 1; // 相当于 (l + r) / 2,但避免了整数溢出  
        if(a[mid] >= x) {  
            r = mid; // 尝试在左半部分继续查找  
        }else {  
            l = mid + 1; // 否则,在右半部分继续查找  
        }  
    }  
}

分析:在这个二分查找算法中,每次迭代都将搜索范围减半。如果我们假设在最坏的情况下(即目标值不存在于数组中),算法需要迭代k次才能结束搜索,那么我们可以得出n=2^k(因为每次迭代都使剩余的元素数量减半)。解这个方程,我们得到k=\log_2 n(注意这里的底数是2,因为我们是将搜索范围减半)。因此,二分查找算法的时间复杂度是O(log n),表示其运行时间与输入规模n的对数成正比。(马上要学的二分算法)

2 空间复杂度:

2.1 常数空间复杂度 O(1)

int findMax(int[] arr, int n)
{  
    int max = arr[0];  
    for (int i = 1; i < n; ++i)
    {  
        if (arr[i] > max)
        {  
            max = arr[i];  
        }  
    }  
    return max;  
}

分析:这个算法只需要几个变量(max 和 i)来存储中间结果和索引,这些变量的数量不会随着输入数组 arr 的大小 n 的增长而增长。因此,该算法的空间复杂度是 O(1),即常数空间复杂度。

2.2 线性空间复杂度 O(n)

void reverseArray(int[] arr, int n)
{  
    int[] temp = new int[n];  
    for (int i = 0; i < n; ++i)
    {  
        temp[i] = arr[n - 1 - i];  
    }  
    for (int i = 0; i < n; ++i)
    {  
        arr[i] = temp[i];  
    }  
}

分析:这个算法使用了一个额外的数组 temp 来存储原数组 arr 的逆序元素。这个数组的大小与输入数组 arr 的大小相同,即 n。因此,该算法的空间复杂度是 O(n),即线性空间复杂度。

2.3 递归空间复杂度

对于递归算法,除了需要考虑递归函数内部使用的额外空间外,还需要考虑递归调用栈所占用的空间。

int factorial(int n)
{  
    if (n == 0)
    {  
        return 1;  
    }
    else
    {  
        return n * factorial(n - 1);  
    }  
}

分析:这个递归函数计算阶乘。在递归过程中,每一层递归调用都会占用一定的栈空间来保存局部变量和返回地址。由于递归深度与输入 n 成正比(在最坏情况下,即 n 连续递减到 0),因此递归调用栈的空间复杂度也是 O(n)。但是,请注意,这里的 O(n) 空间复杂度是由于递归调用栈引起的,而不是由于算法内部使用了额外的数组或数据结构。(这里有些名词不太明白没关系,马上要学)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值