Topic 01

162 阅读3分钟

Topic 01 recap

1.1

PrintN 打印N:

void printN(int n) {
    for (int i = 1; i <= n; i ++) {
        printf("%d\n", i);
    }
}

void printN1(int n) {
    if (n) {
        printN1(n - 1);
        printf("%d\n", n);
    }
}
  • PrintNPrintN1打印数字一个采用循环打印,一个采用递归打印,当n的值过大时,则第二个打印会直接失败,因为递归所占用的内存超出限制

计算一元二次函数

f(x)=1+x+x2/2+x3/3+...+x100/100f(x) = 1 + x + x^2 / 2 + x^3 /3 + ... + x^{100} /100
double f1(int n, double x) {
    double res = 1;
    for (int i = 1; i <= n ; ++i) {
        res += pow(x, i) / i;
    }
    return res;
}

double f2(int n, double x) {
    double res = 0;
    for (int i = n; i > 0; --i) {
        res = res * x + 1.0 / i;
    }
    res += 1;
    return res;
}
  • 对于时间的计算,由于程序过快,故采用运行1e7次的时间(由于单次运行时间非常短,可能无法精确测量,因此通过重复运行多次来累积时间,然后除以运行次数来得到平均单次运行时间。这种方法可以提高测量精度),然后除1e7得到平均一次运行的时间

  • 对于 f1 采用一般的方法进行计算,对于 f2 采用秦九韶方法进行计算,得出的时间前者比后者多一个数量级别


关于抽象

  • 抽象只关注问题的解决思路;

  • 不关注处理的对象,进行操作的具体细节,便于设计 广泛的解决方法 处理同样原理的问题;

  • 提高 一种思路 的 普遍适用性。


1.2

算法定义

  • 一个有限指令集
  • 接受一些输入
  • 产生输出
  • 一定在有限步骤后终止
  • 每一条指令必须
    • 有充分的目标,不可以有歧义
    • 计算机能处理的范围之内
    • 描述应不依赖于任何一种计算机语言及具体实现手段

时间与空间复杂度

O(n)来评判,一般通过最坏的情况来判断一个程序的时间复杂度

空间复杂度类似

简单二分查找的时间复杂度计算

第一次比较后范围数:n / 2

第二次比较后:n / 4

第三次比较后:n / 8

...

假设第k次的范围数为1,也就是最坏的情况下,找到了数或没找到数(在比较时间复杂度是时候并不关心底数2还是10)

n2k=1=>k=log2(n)\frac{n}{2^k} = 1 => k = log_2(n)

程序如下:

#include <stdio.h>

int binary_search(const int x, const int arr[], const int n) {
    int l = 0, r = n - 1;

    while(l <= r) {
        int m = l + r >> 1;
        if(arr[m] == x) return m;
        if(arr[m] < x) l = m + 1;
        else r = m - 1;
    }
    return -1;
}

int main() {
    int arr[] = {1, 3, 4, 8, 54, 60, 100, 211};
    int x = 54;
    int n = sizeof(arr) / sizeof(arr[0]);
    int index = binary_search(x, arr, n);
    printf("Index of %d is %d\n", x, index);
    return 0;
}

// 1. 二分查找的前提是数组有序
// 2. 二分查找的时间复杂度是O(logn)
// 3. 二分查找的空间复杂度是O(1)
// 4. 二分查找的缺点是数组必须是有序的,如果数组是无序的,需要先排序
// 5. 二分查找的优点是速度快,时间复杂度低
// 6. 二分查找的应用场景是在有序数组中查找某个元素的位置

关于PTA作业:PTA Link

Position BinarySearch( List L, ElementType X ) {
    Position l = 0, r = L->Last;
    while(l <= r) {
        Position mid = l + r >> 1;
        if (X == L->Data[mid]) return mid;
        if (X < L->Data[mid]) {
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    return NotFound;
}

1.3

当我们有一个程序是O(n^2),我们要试想下能不能简化成O(nlog(n))

最大子序列和问题

[!note]

  1. O(n^3)
  2. O(n^2)
  3. O(nlog(n)) 分治法
  4. O(n)

PTA Link

// O(n)
#include <iostream>
#include <vector>

int main() {
    int n; std::cin >> n;
    
    std::vector<int>arr(n);
    for (int& elem : arr) std::cin >> elem; 
    
    int res = 0, temp = 0;
    
    for (const int& elem : arr) {
        temp += elem;
        if (temp > res) {
            res = temp;
        } else if (temp < 0) {
            temp = 0;
        }
    }
    
    std::cout << res;
    
    return 0;
}

返回前后数版本:PTA Link

#include <iostream>
#include <vector>

int main() {
    int n; std::cin >> n;
    std::vector<int>arr(n);
    for (int& a : arr) std::cin >> a;

    int maxRes, temp, beg, end, last;
    maxRes = - 1;
    temp = beg = last = end = 0;
    
    for (int i = 0; i < n; i++) {
        temp += arr[i];
        if (temp > maxRes) {
            maxRes = temp;
            beg = last;
            end = i;
        } else if (temp < 0) {
            temp = 0;
            last = i + 1;
        }
    }
    if (maxRes < 0) std::cout << 0 << " " << arr[0] << " " << arr[n - 1];
    else std::cout << maxRes << " " << arr[beg] << " "<< arr[end];
    return 0;
}

End...