算法基础(基础算法篇)


写在前面:
比起用cin和cout,用scanf和printf可以节省更多时间,如果超时可以选择改变写法

基础算法

快排

模板

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
}

注释
快速排序算法的基本思想是通过选取一个基准值,将数组分成两部分,使得左边的元素都小于等于基准值,右边的元素都大于等于基准值。然后对左右两部分继续递归地进行排序,直到数组中的每个元素都有序。

在这段代码中,l 表示当前待排序区间的左边界,r 表示右边界。初始时,整个数组作为待排iipo 序区间传入函数。

然后,在选择基准值时,使用数组中间位置的元素 q[l + r >> 1] 作为基准值 x。

接下来,使用两个指针 i 和 j 分别从左边和右边开始遍历数组。指针 i 向右移动直到找到第一个大于等于基准值的元素,指针 j 向左移动直到找到第一个小于等于基准值的元素。如果此时 i < j,交换 q[i] 和 q[j]。

重复上述操作,直到 i >= j,此时将数组分成了两部分,两部分中数据是不 一样多的,左边的元素都小于等于基准值,右边的元素都大于等于基准值。

然后,对左右两个部分分别进行递归调用 quick_sort 函数,继续进行排序。
为什么不能用j-1和j或i-1和i:

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

归并

模板

void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int mid = l + r >> 1;

    merge_sort(q, l, mid), merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r){
        if (q[i] <= q[j]) {
            tmp[k] = q[i];
            k ++; i ++;
        }
        else {
            tmp[k] = q[j];
            k ++; j ++;
        }
    }
    while (i <= mid) {
        tmp [k] = q[i];
        i ++; k ++;
    }
    while (j <= r) {
        tmp [k] = q[j];
        k ++; j ++;
    }
    
    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
//将临时数组中的元素复制回原数组 q,完成排序
}

注释
归并排序是一种分治算法,它将待排序的数组不断分割成两部分,分别对这两部分进行排序,然后合并这两部分的结果,最终得到完全有序的数组。(分成小部分排序,再合并)

二分

模板

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

注释
二分查找算法用于在区间 [l, r] 中查找满足某种性质的值。

首先定义了一个函数 check(int x),用于检查值 x 是否满足某种性质。

接下来,有两个二分查找函数 bsearch_1 和 bsearch_2,它们的区别在于如何划分区间。

bsearch_1 用于将区间 [l, r] 划分为 [l, mid] 和 [mid + 1, r] 时使用。具体步骤如下:

使用 l 和 r 来表示当前查找区间的左右边界。
在每一次循环中,计算中间位置索引 mid,通过将 l 和 r 相加除以 2 得到。
调用 check(mid) 函数判断 mid 是否满足性质。如果满足,则更新 r 为 mid,因为已经找到了一个可能的解,继续在左半部分查找。如果不满足,则更新 l 为 mid + 1,因为 mid 不满足性质,需要在右半部分查找。
当 l 小于 r 时重复步骤 2 和 3。
返回 l。
bsearch_2 与 bsearch_1 类似,但是在划分区间时略有不同。它将区间 [l, r] 划分为 [l, mid - 1] 和 [mid, r] 时使用。

高精度

高精度加法

模板

#include <iostream>
#include <vector>

using namespace std;

vector<int> add(vector<int> &A,vector<int> &B)/*首先定义了一个add函数,用于实现大整数的相加操作。
                                             add函数的输入是两个引用类型的vector<int>参数A和B,
                                             返回值是一个vector<int>类型的结果C*/

{
    if (A.size() < B.size()) return add(B, A);/*在add函数中,首先判断A和B两个向量的长度,
                                               如果A的长度小于B的长度,则交换A和B,
                                               以保证A的长度大于等于B的长度*/
    
    vector<int> C;//创建一个空的向量C,用于存储相加的结果
    int t = 0;//定义一个变量t,表示当前位的进位值,初始值为0
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];/*通过for循环依次遍历A的每一位,并将对应位上的数字相加,同时加上进位值t。
      如果当前位小于B的长度,则还需加上B对应位上的数字*/
        C.push_back(t % 10);//将每一位上相加的结果对10取余数,并将其存储到结果向量C中
        t = t / 10;//更新进位值t为相加结果除以10的商值
    }
    
    if (t) C.push_back(t);//循环结束后,如果进位值t不为0,则将其添加到结果向量C的末尾
    return C;//返回结果向量C
}
int main()
{
    string a, b;
    vector<int> A, B;
    
    cin >> a >> b;
       
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
    
    auto C = add(A, B);/*auto 关键字在这个上下文中可以被具体的类型替代,例如 vector<int>。但使用 auto 关键字可以简化代码*/
    
    for (int i = C.size() - 1; i >= 0; i -- ) printf("%d", C[i]);
    return 0;
}
/*在main函数中,首先读入两个大整数a和b,并将它们按照逆序存储到向量A和B中
然后调用add函数得到结果向量C
最后,通过逆序遍历结果向量C,并逐个输出每一位的数字*/

注释
1.需要注意的是,该代码实现了大整数相加的功能,可以处理任意位数的整数相加。但在使用中需要注意输入的合法性,确保输入的大整数不会超过系统的表示范围

2.A.push_back(a[i])和A.push_back(a[i] - ‘0’):在第一个代码中,字符 a 和 b 的每个数字被存储为其 ASCII 值。因此,在 A.push_back(a[i]) 中,字符直接被传递给 push_back 函数。

在第二个代码中,字符 a 和 b 被转换为整数。通过 A.push_back(a[i] - ‘0’),将字符转换为整数后再存储到 A 和 B 数组中

高精度减法

模板

#include <iostream>
#include <vector>

using namespace std;

bool compare(vector<int> &A, vector<int> &B)
{
    if (A.size() != B.size()) return A.size() > B.size();
    
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        if (A[i] != B[i]) return A[i] > B[i];
    }
    return true;
}//函数 compare 用于比较两个大整数的大小。如果 A 的长度大于 B 的长度,则返回 true;如果 A 的长度小于 B 的长度,则返回 false;如果两个长度相等,需要逐位比较,找出第一个不同的数位进行比较

vector<int> sub (vector<int> &A, vector<int> &B)
{
    vector<int> C;
    
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}//函数 sub 用于实现大整数相减。它采用借位的方式,从低位到高位逐位相减,并根据需要进行借位和取模操作,最后生成结果数组 C

int main()
{
    string a, b;
    vector<int> A, B;
    cin >> a >> b ;
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
    
    vector<int> C;
    
    if (compare(A, B)) C = sub(A, B);
    else C = sub(B, A), cout << '-';
    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i]; 
    cout << endl;
    return 0;
}//在 main 函数中,代码读取输入的两个大整数 a 和 b,将其存储到 A 和 B 数组中。然后根据 A 和 B 的大小关系,调用 sub 函数执行相应的操作,并将结果存储到数组 C 中。如果 B 大于 A,则输出结果前需要添加负号。最后,将结果数组 C 逆序输出

注释

高精度乘法

模板

注释

前缀和与差分

前缀和

模板

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int n, m;
int a[N], s[N];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    
    for (int i = 0; i < n; i ++ ) s[i] = s[i-1] + a[i];//前缀和数组的初始化
    
    while (m -- )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r-1] - s[l - 2]);//这段代码使用 printf 函数来输出区间 [l, r] 的和。
        //具体的输出格式是 %d\n,表示输出一个整数并换行。在这里,s[r] - s[l - 1] 表示区间 [l, r] 的和。
        //由于数组 s 存储的是前缀和,s[r] 表示从数组开头到第 r 个元素的和,而 s[l - 1] 表示从数组开头到第 l - 1 个元素的和。
        //因此,通过计算两者的差值,可以得到区间 [l, r] 的和
    }
    return 0;
}

注释

双指针

位运算

离散化

区间合并

  • 30
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构与算法是计算机科学和软件工程领域中非常重要的基础知识。数据结构是指组织和存储数据的方式,而算法则是解决问题的一系列步骤。在这里,我将简要介绍数据结构与算法基础知识。 1. 数组(Array):是一种线性数据结构,可以存储相同类型的元素。数组的特点是可以通过索引快速访问元素。 2. 链表(Linked List):也是一种线性数据结构,不同于数组,链表的元素在内存中可以不连续存储,每个元素包含一个指向下一个元素的指针。 3. 栈(Stack):是一种后进先出(LIFO)的数据结构,只能在栈的一端进行插入和删除操作。 4. 队列(Queue):是一种先进先出(FIFO)的数据结构,只能在队列的一端进行插入操作,在另一端进行删除操作。 5. 树(Tree):是一种非线性数据结构,由节点和边组成。树的一个节点可以有多个子节点。 6. 图(Graph):也是一种非线性数据结构,由节点和边组成。不同于树,图中的节点之间可以有多个连接。 7. 排序算法:常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等,它们用于将一组元素按照特定的顺序进行排列。 8. 查找算法:常见的查找算法包括线性查找、二分查找等,它们用于在一组元素中查找特定的值。 以上只是数据结构与算法基础知识,还有许多其他重要的概念和算法,如哈希表、堆、图算法等。掌握数据结构与算法基础知识可以帮助我们更好地理解和解决实际的计算机问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值