第五章:双指针与离散化的映射

news2024/11/19 4:38:25

第五章:双指针、离散化、二进制运算与区间合并

  • 一、双指针
    • 1、什么是双指针?
    • 2、双指针的模板
    • 3、双指针例题
      • (1)思路:
      • (2)解答:
        • C++版:
        • C版:
  • 二、离散化
    • 1、什么是离散化?
    • 2、离散化映射
    • 3、模板
      • (1)C++
      • (2)C

一、双指针

1、什么是双指针?

双指针运算常用在数组中,其实就是创建两个下标通过一定的规律去访问数组。基本上,两个指针最多都只会遍历数组一次,那么利用双指针算法的时间复杂度就是O(N)。除此之外,利用双指针算法的题目,大部分可以套双层循环去遍历,那么这种暴力方式的时间复杂度就是O(N^2^)

因此双指针算法可以大大地降低时间复杂度。

2、双指针的模板

C++和C的模板是一致的。

int j=0;
for(int i=0;i<n;i++)
{
	while(j<n&&check(j))j++;
}

这个模板中的重点是check函数的思考。

3、双指针例题

在这里插入图片描述

(1)思路:

我们创建两个指针,让j,i分别指向一段序列的两端,然后去判断这一段是否有重复的数字。倘若没有重复的元素,我们会记录此时的长度。
请添加图片描述
那么我们假设遇到重复,我们又该如何修正呢?
请添加图片描述
我们先明白以下的逻辑:
序列出现重复,一定是因为i所指的数组元素与序列中的某个元素重复了。
此时我们让j去寻找这个重复元素,在找到之前,此时i,j所包含的序列一定不是答案, 因此我们可以放心的移动。
当我们找到重复元素后,我们让j指向它的下一个元素,此时就排除了这个重复元素,那么此时的i,j区间的序列,满足了不重复的条件,那么此时我们继续让i去移动。
由上述操作:
我们就能够总结出i和j的作用:
(1)i是为了尽可能地寻找最长的序列。
(2)j是为了找到重复的序列。

那么我们的check函数如何写呢?
如下图所示:
请添加图片描述
因为一个序列是在变化的,那么我们如何维护一个动态的判断数组?

如下图所示:
请添加图片描述

(2)解答:

C++版:

#include<iostream>
using namespace std;
const int N=100010;
int arr[N];
int S[N];
int main()
{
    int n,res=0,j=0;
    cin>>n;
    for(int i=0;i<n;i++)scanf("%d",arr+i);
    for(int i=0;i<n;i++)
    {
        S[arr[i]]++;
        while(S[arr[i]]>1)
        {
            S[arr[j]]--;
            j++;
        }
        res=max(res,i-j+1);
    }
    cout<<res<<endl;
    return 0;
}

C版:

#include<stdio.h>
int arr[100010];
int S[100010];

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

int main()
{
    int n;
    int res=0,j=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",arr+i);
    for(int i=0;i<n;i++)
    {
        S[arr[i]]++;
        while(S[arr[i]]>1)
        {
            S[arr[j]]--;
            j++;
        }
        res=max(res,i-j+1);
    }
    printf("%d",res);
    return 0;
}

二、离散化

1、什么是离散化?

假设一个数组的长度是10,但是每个元素的数据范围是1-100,那么假设这个数组是:
1,44,77,34,23,45,56,12,2,100。

这个例子就是一个离散化的,他的数据的元素范围是大于这个数组长度范围的。我们可以用下面的图片进一步体会什么是离散化。请添加图片描述
上图所示,我们将6个元素之间数值差距很大的数组,放到黄色数组中,黄色数组的特点就是元素的下表和元素内容是一致的,这种情况下,我们的黄框数组就浪费了非常大的空间。

2、离散化映射

请添加图片描述
因此,实现映射的话,即将几个分散的数据去通过下表的方式聚合到一起。我们就可以通过下表访问具体的被聚合到一起的离散化数据。
但是,说到这里,大家一定还不明白为什么要实现离散化的映射?
所以我们看下面的例子:
在这里插入图片描述
我们看到这道题,思考五分钟后,在处理某个位置加上一个常数的操作,大家可能想到的是下面这个思路:我们开一个非常大的数组,然后通过下标来访问特定的位置,实现数值的插入。
请添加图片描述
这个想法理论上是可以的,但是实现起来是非常困难的,因为我们很难在堆区去开辟这么大的一块内存。
说到这里,就需要我们所提到的**离散化映射的算法。**离散化的对象就是每次访问的下标。

具体的做题思路如下:

  • 将每次插入的位置,以及最终求和的区间进行离散化映射处理。将其映射到一个数组中。
  • 通过访问映射后的位置,去实现数据的插入。
  • 通过前缀和运算去实现区间内的元素和。

3、模板

(1)C++

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=3e5+10;

int a[N];
int S[N];
vector<int>alls;
vector<pair<int,int>>add,quary;

int find(int x)
{
    int l=0;
    int 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()
{
    int n,m;
    scanf("%d %d",&n,&m);
    
    for(int i=0;i<n;i++)
    {
        int x,c;
        scanf("%d %d",&x,&c);
        add.push_back({x,c});
        alls.push_back(x);
    }
    
    for(int i=0;i<m;i++)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        quary.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(int i=0;i<add.size();i++)
    {
        int x=find((add[i]).first);
        a[x]+=(add[i]).second;
    }
    
    for(int i=1;i<=alls.size();i++)
    {
        S[i]=S[i-1]+a[i];   
    }
    
    for(int i=0;i<m;i++)
    {
        int l=find((quary[i]).first);
        int r=find((quary[i]).second);
        printf("%d\n",S[r]-S[l-1]);
    }
    return 0;
}

(2)C

#include <stdlib.h>
#include <stdio.h>
typedef struct pair
{
  int first;
  int second;
}pair;

int alls[300010];
pair add[300010];
pair quray[300010];

int a[300010];
int b[300010];

int cmp(const void*num1,const void*num2)
{
    int ret=*(int*)num1-*(int*)num2;
    return ret;
}

int unique(int*arr,int len)
{
    int j = 0;
    for(int i=0;i<len;i++)
    {
        if(i==0||arr[i]!=arr[i-1])arr[j++]=arr[i];
    }
    return j;
}

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

int main()
{
    int n,m;
    int count=0;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++)
    {
        int x,c;
        scanf("%d %d",&x,&c);
        add[i].first=x;
        add[i].second=c;
        alls[count++]=x;
    }
    
    for(int i=0;i<m;i++)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        quray[i].first=l;
        quray[i].second=r;
        alls[count++]=l;
        alls[count++]=r;
    }

    //排序去重
    qsort(alls,count,sizeof(int),cmp);
    
    int newcount=unique(alls,count);
    count=newcount;
    


    for(int i=0;i<n;i++)
    {
        int p=find(add[i].first,newcount);
        a[p]+=add[i].second;
    }
    for (int i = 1; i <= newcount; i++)
    {
        b[i] = b[i - 1] + a[i];
    }
        
    
    for(int i=0;i<m;i++)
    {
        int l=find(quray[i].first,newcount);
        int r=find(quray[i].second,newcount);
        
        printf("%d\n",b[r]-b[l-1]);
    }
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/11243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java面试强基(3)

重载和重写的区别? 重载 发生在同一个类中&#xff0c;方法名必须相同&#xff0c;参数类型不同、个数不同、顺序不同&#xff0c;方法返回值和访问修饰符可以不同。 重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。 重写 重写发生在运行期&#xff0c;…

go语言基本环境搭建

下载地址 Go官网下载地址&#xff1a;https://studygolang.com/dl 一、下载对应电脑得安装包 二、下载完成点击安装下一步&#xff08;选择目录尽量简单&#xff09; 三、是否安装成功 四、环境变量 GOROOT和GOPATH都是环境变量&#xff0c;其中GOROOT是我们安装go开发包的路…

【计算机毕业设计】Springboot医疗管理系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 医疗服务系统&#xff0c;主要的模块包括查看管理员&#xff1b;首页、个人中心…

tomcat官网下载配置全部详细步骤(包含各种报错解决办法)

前言&#xff1a; 名字由来&#xff1a;翻译是野猫&#xff0c;tomcat的作者初衷是希望这个软件可以自力更生&#xff0c;自给自足。不依赖其他插件&#xff0c;独立达到提供web服务的效果 1.tocat和java的关系&#xff1f; tomcat是用Java语言编写的&#xff0c;需要运行在…

大三,请问现在自学Java还来得及吗?

前言 如果还在为入门Java晚而发愁时间够不够&#xff0c;首先你是准备自学&#xff0c;那么我们可以看看现在网络上一些比较热门的Java全体系的学习需要化多长时间&#xff0c;先拿B站上做的比较好的黑马教程和尚硅谷举例&#xff1a; 2022黑马程序员Java学习路线图​www.bili…

耗时半月,终于把牛客网软件测试面试八股文,整理成了文档资料.....

一、面试基础题 简述测试流程: 1、阅读相关技术文档&#xff08;如产品PRD、UI设计、产品流程图等&#xff09;。 2、参加需求评审会议。 3、根据最终确定的需求文档编写测试计划。 4、编写测试用例&#xff08;等价类划分法、边界值分析法等&#xff09;。 5、用例评审(…

飞象星球落地重庆云阳86所学校,县乡4万学生迎来素质课堂

猜生字笔画顺序、学习硬笔书法&#xff1b;跟随老师认识情绪、写下心里话……自从重庆云阳县86所中小学引入飞象星球双师素质课堂&#xff0c;4万多名县城和乡村孩子的课后素质课堂一下子变得丰富多彩起来。 图&#xff1a;洞鹿小学双河村校上双师素质书法课 云阳县地处三峡库…

代码随想录算法训练营第三十六天| LeetCode435. 无重叠区间、LeetCode763. 划分字母区间、LeetCode56. 合并区间

一、LeetCode435. 无重叠区间 1&#xff1a;题目描述&#xff08;435. 无重叠区间&#xff09; 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 2&#xff1a;解题思路 class …

MySQL面试问题汇总(2022)

一、MySQL架构 锁 什么是锁&#xff1f; 当多个连接并发地存取MySQL数据时&#xff0c;在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据&#xff0c;破坏数据库的一致性。 加锁是实现数据库并发控制的一个非常重要的…

BFV同态加密方案初步学习

BFV是把Bra12的LWE版本推到了RLWE版本&#xff0c;Bra12也可以叫做BFV。 经典的RLWE的公钥加密算法回顾 对比以前的Regev的LWE公钥加密方案&#xff0c;其实几乎只是把明文空间换了&#xff0c;也就是在最大比特编码的时候把2换成t&#xff0c;即&#xff0c;Δ⌊q/t⌋\Delta…

web网页设计期末课程大作业——香格里拉旅游网页设计 5页 HTML+CSS+JavaScript

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

一起来看看AMD最新显卡驱动22.11.1!

AMD最新推出了显卡驱动22.11.1&#xff0c;可以支持新上线的使命召唤&#xff1a;战区2&#xff0c;并且还修复了一系列的问题&#xff0c;AMD忠实用户们期待了嘛~ 更新内容 支持 使命召唤&#xff1a;战区 2.0 漫威蜘蛛侠&#xff1a;迈尔斯莫拉莱斯™ 固定问题 Radeon™ RX 6…

【mycat】mycat水平分表

mycat完成水平拆分 简介 相对于垂直拆分&#xff0c;水平拆分不是将表做分类&#xff0c;而是按照某个字段的某种规则来分散到多个库之中&#xff0c;每个表中包含一部分数据。简单来说&#xff0c;我们可以将数据的水平切分理解为是按照数据行的切分&#xff0c;就是将表中的…

【Try Hack Me】内网专项---Wreath

THM 学习笔记 【Try Hack Me】内网专项—Wreath &#x1f525;系列专栏&#xff1a;Try Hack Me &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月17日&#x1f334; &#x1f36d;作…

编程基础都要懂的计算机组成

学习目标: 1. 能够说出计算机有那两部分组成 2. 能够说出操作系统的作用 1.1计算机组成 计算机是可以进行数值计算和逻辑运算, 并且具有存储功能的电子机器. 计算机由硬系统件和软件系统组成. 1.1.1 硬件系统 主要分为主机和外设两部分, 是指那些构成计算机系统的物理实体,…

123456

hostname web1 bash 113.219.215.44 ctyun/Ctyun2022 cd /data/html/ tar -cvf /home/ctyun/html_zy.tar ./ mysqldump -uctyun -p --skip-lock-tables -R ultrax>ultrax_zhouyue.sql cd /etc/httpd tar -cvf /home/ctyun/httpd_zhouyue.tar ./ 关机改云主机私有网卡…

APP逆向案例之(一)过 app 更新提示

案例&#xff1a;某APP打开时提示更新 思路&#xff1a;想这是查壳看看有没有加壳&#xff0c;没有就去反编译按照提示搜索下&#xff0c;结果却是没有加壳反编译了下搜索&#xff0c;搜索不到&#xff0c;后来想到是不是网络传过来的&#xff0c;那这样是不是就要先获取本身AP…

Spring(十四)- Spring注解原理解析

文章目录一、Spring注解原理解析1. 使用xml配置扫描组件的原理解析2. 使用配置类扫描组件的原理解析一、Spring注解原理解析 1. 使用xml配置扫描组件的原理解析 使用Component等注解配置完毕后&#xff0c;要配置组件扫描才能使注解生效 ⚫ xml配置组件扫描&#xff1a; <c…

springboot RestTemplate优化 http 池化

http通信之三次握手 为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 TCP在发送新的数据之前&#xff0c;以特定的顺序将数据包的序号&#…

【LeetCode 力扣】3.无重复字符的最长子串 Java实现 滑动窗口

题目链接&#xff1a;3.无重复字符的最长子串 1 原题描述&#xff1a; 2 解题思路 初看此题&#xff0c;其实并不难理解&#xff0c;我们一共有两个指针&#xff0c;一个时我们子串的头 start &#xff0c;一个是我们子串的尾 end。我们的尾 end 依次加一&#xff0c;然后判…