算法基础第一章

news/2024/7/15 17:06:36 标签: 算法, c++, 图论

算法基础

  • 第一章:基础算法
    • 1、排序
    • 2、二分查找
    • 3、大数据量的加法和减法(高精度加减法)
      • 3.1、加法
      • 3.2、减法
    • 4、前缀和
      • 4.1、一维前缀和
      • 4.2、二维前缀和
    • 5、差分
      • 5.1、一维差分
      • 5.2、二维差分
    • 6、双指针
    • 7、位运算
      • 7.1、lowbit的应用
    • 8、离散化
    • 9、区间合并
  • 第二章:数据结构
  • 第三章:搜索与图论
  • 第四章:数学知识
  • 第五章:动态规划
  • 第六章:贪心算法

第一章:基础算法

1、排序

2、二分查找

  • 描述:在一个有序数组里面查找某个目标值
  • 解析:
    • mid = left + (right - left)/2;
      • mid所在的val小于target_val的时候,left = mid + 1,即区间取右半区间
      • mid所在的val小于target_val的时候,right = mid - 1,即区间取左半区间
        在这里插入图片描述
  • 牛客题目链接:二分查找
  • 代码
class BinarySearch {
public:
    int getPos(vector<int> A, int n, int val) {
        // write code here
        int left = 0,right = n-1;
        while(left <= right)
        {
            int mid = left + (right - left)/2;
            if(A[mid] == val)
            {
                auto i = mid - 1;
                for(;i>=0 && A[i] == val;i--)
                {
                }
                return i+1;
            }
            else if(A[mid] > val)
            {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        return -1;
    }
};

3、大数据量的加法和减法(高精度加减法)

3.1、加法

  • 描述:超出数据类型范围的数的相加

  • 解析:

    • 存储:为了方便进位,则把低位数保存在容器的低位
    • 运算:对应位的和为(C+Ai+Bi)%10,进位为C/10;
    • 全部算完之后还要判断最高位是否有进位,有的话把进位再插入容器
    • 输出的时候逆序输出
      在这里插入图片描述
  • 牛客题目链接:高精度加法

  • 代码

#include <iostream>
#include<string>
#include<vector>

using namespace std;

const int N = 10000;

void add(vector<int>&A, vector<int>&B, vector<int>&C)
{
    int t = 0;
    for(int i=0; i < A.size() || i < B.size(); i++)
    {
        if(i < A.size()) t += A[i];
        if(i < B.size()) t += B[i];
        C.push_back(t%10);
        t /= 10;
    }
    if(t > 0)
        C.push_back(t);
}
int main() {
    string a,b;
    cin >> a >> b;
    vector<int>A,B,C;
    for(int i = a.length()-1; i >= 0; i--)
    {
        A.push_back(a[i] - '0');
    }
    for(int i = b.length()-1; i >= 0; i--)
    {
        B.push_back(b[i] - '0');
    }
    add(A,B,C);
    for(int i = C.size()-1; i >= 0; i--)
    {
        printf("%d",C[i]);
    }
}
// 64 位输出请用 printf("%lld")

3.2、减法

  • 描述:超出数据类型范围的数的减法

  • 解析:A>B则用A-B;A<B则用-(B-A),相减的时候为对应位相减且减去借位c,c起始为0,得到的结果分为大于0和小于0,大于0则直接得到输出结果,小于0则还需要加上10,两个可合并为(sum+10)%10,最后还要判断下一位的借位
    在这里插入图片描述

  • 题目链接:未找到

#include<iostream>
#include<vector>
#include<string>

using namespace std;
/* 比较两个数的大小,从高位往低位依次比较 */
bool cmp(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;
}

vector<int>sub(vector<int>&A,vector<int>&B)
{
    vector<int>C;
    for(int i = 0,c=0; i < A.size(); i++)
    {
    	/* c是借位 */
        c = A[i] - c;
        if(i < B.size())
            c -= B[i];
        C.push_back((c+10)%10);
        if(c < 0)
            c = 1;
        else
            c = 0;
    }
    /* 去掉前导0,全为0则保留最后一个0 */
    while(C.size() > 1 && C.back() == 0)
        C.pop_back();
    return C;
}


int main()
{
    string a,b;
    vector<int>A,B;
    cin >> a >> b;
    /* 低位数存入容器的低位位置 */
    for(int i = a.length()-1; i >= 0; i--)
    {
        A.push_back(a[i] - '0');
    }
    for(int i = b.length()-1; i >= 0; i--)
    {
        B.push_back(b[i] - '0');
    }
    
    if(cmp(A,B))
    {
        auto C = sub(A,B);

        for(int i = C.size()-1; i >= 0; i--)
        {
            printf("%d",C[i]);
        }
    }
    else
    {
        auto C = sub(B,A);
        printf("-");
        for(int i = C.size()-1; i >= 0; i--)
        {
            printf("%d",C[i]);
        }
    }
}

4、前缀和

4.1、一维前缀和

  • 描述:在一个一维数组里面求某一段区间内的和
  • 解析:
    • 数组a[N],S[i] = S[i-1]+a[i],区间l到r的和为S[r]-S[l-1]
  • 题目链接:前缀和
  • 代码
#include <iostream>
#include<vector>
#include<bits/stdc++.h>

using namespace std;

const int N = 100010;
int a[N];
long long S[N];

int main() {
    int n,q;
    cin >> n >> q;

    for(int i = 1; i <= n; i++)
    {
       scanf("%d",&a[i]);
       S[i] = S[i-1] + a[i];
    }
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%lld\n",S[r] - S[l-1]);
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

4.2、二维前缀和

  • 描述:一个二维矩阵A[n][m],求其(x1,y1)和其(x2,y2)之间的矩阵和
  • 解析:先算出S[i][j],再算两点间的和
  • 求S[i][j]的和
  • 计算两点间的和,注意边界,需要包含x1,y1
    在这里插入图片描述
  • 题目链接:二维前缀和
  • 代码
#include <iostream>
#include<bits/stdc++.h>
using namespace std;

const int N = 1010;
int A[N][N];
long long S[N][N];

int main() {
    int n,m,q;
    cin >> n >> m >> q;

    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> A[i][j];
            S[i][j] = S[i][j-1] + S[i-1][j] - S[i-1][j-1] + A[i][j];
        }
    }

    while(q--)
    {
        int x1,y1,x2,y2;
        cin >> x1 >> y1 >> x2 >> y2;
        cout << S[x2][y2] - S[x2][y1-1] - S[x1-1][y2] + S[x1-1][y1-1] << endl;
    }
}

5、差分

5.1、一维差分

  • 描述:在a[n]这个数组中的某一段全部加上某个数
  • 解析:an是bn的前缀和,bn是an的差分,在bl+k,在b(r+1)-k,相当于只在l到r这段里面的数加上了k
    在这里插入图片描述
  • 题目链接:一维差分
  • 代码
#include <iostream>
using namespace std;

const int N = 100010;
int n,m;
long long a[N],b[N];

void insert(int l,int r,int k)
{
    b[l] += k;
    b[r + 1] -= k;
}
int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        insert(i, i, a[i]);
    }
       
    while(m--)
    {
        int l,r,k;
        cin >> l >> r >> k;
        insert(l, r, k);
    }
    for(int i = 1; i <= n; i++)
    {
        b[i] += b[i-1];
        cout << b[i] << " ";
    }
}

5.2、二维差分

  • 描述:将二维矩阵中的其中一个子矩阵每个数都加上一个数
  • 解析:只将图中的子矩阵中的每个数加上c,表达式如图中所示
    在这里插入图片描述
  • 同样b[i][j]是a[i][j]的差分,a是b的前缀和,也就是b[i][i]上方的子矩阵的和就为a[i][j],前缀和公式如图
    在这里插入图片描述
  • 题目链接:二维差分
  • 代码
#include <iostream>
using namespace std;

const int N = 1010;
long long a[N][N],b[N][N];
int n,m,q;

void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1] += c;
    b[x2+1][y1] -= c;
    b[x1][y2+1] -= c;
    b[x2+1][y2+1] += c;
}
int main() {
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
            insert(i,j,i,j,a[i][j]);
        }
    while(q--)
    {
        int x1,y1,x2,y2,k;
        cin >> x1 >> y1 >> x2 >> y2 >> k;
        insert(x1,y1,x2,y2,k);
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];
            cout << b[i][j] << " ";
        }
        cout << endl;
    }
}

6、双指针

  • 题目链接:最长连续无重复子序列
  • 代码
#include <unordered_map>
class Solution {
public:
    int maxLength(vector<int>& arr) {
        int n = arr.size();
        unordered_map<int, int>mp;
        int ret = 0;
        for(int i = 0,j = 0; i < n; i++)
        {
            mp[arr[i]]++;
            while(mp[arr[i]] > 1)
            {
                mp[arr[j]]--;
                j++;
            }
            ret = max(ret,i-j+1);
        }
        return ret;
    }
};

7、位运算

7.1、lowbit的应用

  • 描述:求x的第k位的大小
  • 公式:(x >> k) & (-x)
    在这里插入图片描述
  • 题目链接:二进制数中1的个数

8、离散化

  • 描述:在一个无限长的坐标中进行添加和询问操作,坐标上的数起始全为0,add的(1,2)表示在坐标1加2,query的(1,2)表示求区间1,2之间的和,和为5,所以输出5
    在这里插入图片描述

  • 解析:1、将操作的下标全部存进容器,排序后去重;2、使用二分查找算出离散化的值;3、再使用前缀和算出结果

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

typedef pair<int,int>PII;

const int N = 300010;

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

vector<int>alls;
vector<PII>add,query;

int find(int x)
{
    int l=0,r=alls.size()-1;
    while(l<r)
    {
        int mid = l+r >> 1;
        if(alls[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return r + 1;
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n; i++)
    {
        int x,c;
        cin >> x >> c;
        add.push_back({x,c});
        alls.push_back(x);
    }
    for(int i = 0; i < m; i++)
    {
        int l,r;
        cin >> l >> r;
        query.push_back({l,r});
        alls.push_back(l);
        alls.push_back(r);
    }
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    for(auto item:add)
    {
        int x = find(item.first);
        a[x] += item.second;
    }
    for(int i=1;i<=alls.size();i++)
        S[i] = S[i-1] + a[i];
    for(auto item:query)
    {
        int l = find(item.first),r = find(item.second);
        cout << S[r] - S[l-1] << endl;
    }
    return 0;
}

9、区间合并

  • 描述:给定多个区间,将能合并的合并,不能合并的保留,最后输出所有区间
  • 解析:先将所有的区间排序,比较维护区间的右区间端点和新区间的左端点,如果新区间的左端点比维护区间的右端点大,则两个不能合并,将维护的区间保存起来,新区间变成维护区间接着往下比较,一直到最后一个
  • 题目链接:区间合并
#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

typedef pair<int,int>PII;

vector<PII>store;
vector<PII>ret;

void merge(vector<PII>&tmp)
{
    int st = -2e9,ed = -2e9;
    sort(tmp.begin(),tmp.end());
    for(auto c:tmp)
    {
        if(ed < c.first)
        {
            if(st != -2e9) ret.push_back({st,ed});
            st = c.first,ed = c.second;
        }
        else
            ed = max(ed,c.second);
    }
    if(st != -2e9) ret.push_back({st,ed});
}
int main()
{
    int n,st,ed;
    cin >> n >> st >> ed;
    for(int i = 0; i < n; i++)
    {
        int l,r;
        cin >> l >> r;
        store.push_back({l,r});
    }
    store.push_back({st,ed});
    merge(store);
    /* 输出 */
    for(auto c:ret)
    {
        cout << c.first << c.second << endl;
    }
}

第二章:数据结构

第三章:搜索与图论

第四章:数学知识

第五章:动态规划

第六章:贪心算法


http://www.niftyadmin.cn/n/270179.html

相关文章

用户注册和登录的页面代码分享

<!--注册页面--> <html> <head> <title>用户注册</title> </head> <body> <h2>用户注册</h2> <?php //如果用户已经提交表单 if(isset($_POST[submit])){ //获取用户输入的数据 $username = $_POST[user…

web集群第二次作业

文章目录 1. 对比 LVS 负载均衡群集的 NAT 模式和 DR 模式&#xff0c;比较其各自的优势 。2. 基于 CentOS 7 构建 LVS-DR 群集。1、环境准备2、安装httpd准备两个web页面3、配置LVS负载均衡服务4、手工在RS端绑定VIP&#xff0c;添加本机访问VIP的路由信息5、手工在RS端抑制AR…

魔兽世界服务端用户注册以及网页的搭建教程

魔兽世界服务端用户注册以及网页的搭建教程 大家好我是艾西&#xff0c;上一章我们讲解了怎么编译一个魔兽的服务端以及安装最后进到我们自己的游戏。那么在平时娱乐的同时肯定是需要和朋友们一起玩游戏才会更有意思&#xff0c;那么今天艾西教大家怎么搭建用户注册页面以及网…

标准C库之exit函数(程序退出函数)

前言 如果&#xff0c;想要深入的学习标准C库中exit函数&#xff0c;还是需要去自己阅读Linux系统中的帮助文档。 具体输入命令&#xff1a; man 3 exit即可查阅到完整的资料信息。 exit 函数 exit() 函数是标准 C 库&#xff08;也称为 C 标准库或 C89/C90/C99/C11 标准库&a…

SQL server增删改查(1)

SQL server数据类型 整数型: BIGINT INT SMALLINT 小数型: FLOAT DOUBLE 文本型: CHAR VARCHAR NCHAR NVARCHAR TEXT 日期和时间类型 DATE TIME DATETIME 布尔型: BIT 数据类型含义INT长整数(也可以写作INTEGER)SMALLINT短整数CHAR(n)长度为n的定长字符串, 不足n个字符的空白部…

MATLAB连续LTI系统的时域分析(十)

目录 1、实验目的&#xff1a; 2、实验内容&#xff1a; 1、实验目的&#xff1a; 1&#xff09;掌握利用MATLAB对系统进行时域分析的方法&#xff1b; 2&#xff09;掌握连续时间系统零输入响应的求解方法&#xff1b; 3&#xff09;掌握连续时间系统零状态响应、冲激响应和…

连接查询

在上一章中我们学习了子查询的相关内容&#xff0c;涉及标量子查询&#xff0c;列子查询&#xff0c;行子查询&#xff0c;表子查询&#xff0c;不相关子查询和相关子查询等内容。我们之前一致用student_info 和 student_score来储存学生的基本信息和成绩信息&#xff0c;其实也…

华为在软件工具生态埋下多颗“种子”,静候国产软件产业萌芽

文丨智能相对论 作者丨沈浪 当代的数字经济大厦由各种各样的软件一块一块地搭建起来。然而&#xff0c;站在国内软件行业的中心&#xff0c;热闹的大多是来自上层的软件应用&#xff0c;而沉寂的却总是底层又难又基础的领域&#xff0c;比如软件开发。 软件开发&#xff0c;…