C++刷力扣、PAT第一周笔记
最近,出于巩固复习C++与数据结构、学习高级算法、准备PAT考试的需要,我开始照着网上的刷题教程,在力扣和PAT平台上逐题攻坚。以下是一些收获:
【1】map容器的使用
- make_pair返回pair对象,可以作为map容器的元素insert如下:
map.insert(make_pair(键,值));
- map的键值对访问:map[键]=值。其中,键为const修饰
- map的迭代器访问:
for(map<type1,type2>::iterator it=m.begin;it!=m.end();it++) {//对键进行操作(数值类型的键默认从小到大排序)it->first...//对值进行操作it->second... }
- map.find返回迭代器,搜不到时返回map.end()
- map.count(键)返回int值,搜不到时返回0
- 删除键值对:map.erase(it)
【2】iterator容器的使用
- 1.迭代器基础语法
- 定义+初始化(以vector<int>为例):
vector<int>::iterator it=v.begin();
- 取值:*it或it->
- 迭代:it++(单向迭代器,即iterator,不支持++外的数值操作符,包括--)
- 迭代器化为下标:std::distance(it1,it2)
- 定义+初始化(以vector<int>为例):
- 迭代中删除元素
- 格式:it=it.erase(element)
- erase的返回值为下一个元素(注意,“下一个”被定义为从begin到end的下一个)
- 因此,it++不应该写在for里,避免删除后发生2次迭代
- 反向迭代器
定义+初始化+迭代(以vector<int>为例):
for(vector<int>::reverse_iterator it=v.rbegin();it!=v.rend();it++)
【3】sort的使用
- STL容器:
sort(stlType.begin(),stlType.end());//以默认方式对stlType容器内的元素排序
- 函数对象(以lambda表达式为例,也可以自定义cmp函数并传入sort中执行):
sort(stlType.begin(),stlType.end(),[需要引用的外部变量](参数)->返回值
{函数体
});
//反向排序vector<int> v
sort(v.begin(),v.end(),[](int x,int y)->bool
{return x>y;
});
【4】二分法的巩固学习
长期以来,我对二分法报有抽象而不具体的认识,只会用binary_search、lower_bound和upperbound接口。经过分析和讨论,我认为二分法的具体实现其实并无模板可记,但有清晰的规则可考。
- 二分法的写法由以下因素决定:
- 开闭区间选择
- 目标条件
- 是否需要对重复元素求边界
- 二分法的写法由以下部分组成:
- 初始区间
- 终止条件
- 区间缩小条件(arr[m]==num之类的)
- 区间缩小语句(l=m,r=m-1之类的)
- 返回值
- 对各个细节的归纳:
- 目标条件和有无重复如何影响二分法: 二分法的直接产物是特定的数值,至于>=、<=、<、>均为间接产物。也就是说,是目标条件的端点而非范围,参与决定了二分法的写法。注:针对有重数组的二分法可以得到特定数值的上下边界。详情见5
- 关于初始区间和终止条件的归纳: 全闭区间[0,arrSize-1],l<=r;左闭右开区间[0,arrSize),l<r。注:这两种我比较常用,其它的写法其实都可以,但是要能够熟练而且正确地写出。
- 关于区间缩小条件的归纳: 由1知,根据目标条件中隐含的端点即可。需要注意的是有重数组,详情见5
- 关于区间缩小语句的归纳:
- 全闭区间直接用+1、-1。
- 半开区间或全开区间,在开的半边“隐式缩小”区间即可。对于[l,r),即令l=m+1或r=m。
- 关于返回值的归纳:
- 无重复数组: 左闭右闭,返回m;左闭右开,返回l
- 有重复数组: 返回pos。pos的取值:下边界,则在>=时取m;上边界,则<=时取m。如此,pos会随着m改变而改变。实现见下述代码段
//针对有重数组arr,求小于0的最右侧元素下标 int test0(int* arr,int arrSize) {//左闭右闭 int l=0,r=arrSize-1;int pos;while(l<=r){ int m=l+((r-l)>>1);//此处的写法应该记忆,2点好处不言自明//细节:这样的m始终取较小的值 if(arr[m]<0){l=m+1;}else{r=m-1;pos=m;} }return pos; }
【5】自动机实现的KMP算法
(两者都是我很早就感兴趣的知识点,但一直懒得看,最近学了一下。可能实用性不高)
- 名词解释
- 模式pattern: 如AAAB
- 文本text: 如AAACAAAB/AAAAAAAB
- 需求:在text里找pattern,而且不用暴力法,要求在遍历pattern的时候“聪明点”
- 状态: pattern在使用中由一个字符转换到一个字符(不一定是前一个字符转换到后一个字符),则前后为各为一个状态;
- 状态推进: text的下一个字符仍然匹配pattern的下一个字符,由前一个字符转换到后一个字符;
- 状态回退: 下一个字符不匹配,若可以匹配影子状态,则在pattern中发生有限的回退。否则,发生完整回退;
- 影子状态: 最长的相同前缀位置。比如,在pattern字符串ABABC中,第二个A的影子是第一个A,第二个B的影子是第1个B,C没有影子。
- 转移过程: 根据text的下一个字符,转移到pattern的哪个位置,整个过程由二维数组dfa记录;
- dfa:自动机。其实就是记录(状态,情况)映射至(新状态)的数组。
- dfa[状态][text的下一个字符]
- =下一个状态
- ={pattern下一个字符
- {dfa[最近的影子状态位置][text的下一个字符]
- (值得记录的细节)dfa[patternSize][charSetSize]对应关系:0~null 1~pattern[0] ... patternSize-1~pattern[patternSize-2]
例图与原博客
https://pic3.zhimg.com/v2-2788562d1059d7b8ff71aa342e4ae036_r.jpgKMP 算法详解 - 知乎 (zhihu.com)
构建dfa数组的具体实现
双层循环的含义:外层i表示pattern的各个位置,内层j表示(状态,各个可能的字符)对应的状态转移
重要变量x(记录下一个位置的影子状态,规则也是推进和回退):在外层循环中更新,x=dfa[x][pattern[i]],即pattern[i+1]的影子状态=pattern[i]的影子状态遇到字符pattern[i+1]的转移后状态。x初始化为0,因为pattern[0]、dfa[1]的影子状态一定为null
内层循环:推进和回退
#include<iostream>
using namespace std;class DFA_KMP
{
public:string pattern;int patternSize;int charSetSize;int** dfa;DFA_KMP(string pattern,int charSetSize){this->pattern=pattern;this->patternSize=pattern.size();this->charSetSize=charSetSize;dfa=new int*[patternSize];for(int i=0;i!=patternSize;i++){dfa[i]=new int[charSetSize];}}void dfaBuilder(){ //i:0-a,1-b,2-a,3-b,4-c//j:0-a,1-b,2-c //dfa[0][]为"ababc"之前的空位的状态转移数组 for(int i=0;i!=charSetSize;i++){if(i!=pattern[0]-97)dfa[0][i]=0;else dfa[0][i]=1;}//影子状态位置 int x=0;for(int i=1;i!=patternSize;i++){for(int j=0;j!=charSetSize;j++){//状态推进 if(pattern[i]-97==j)dfa[i][j]=i+1;//状态回退 else dfa[i][j]=dfa[x][j];}//更新影子状态位置x=dfa[x][pattern[i]-97];//cout<<x<<'\n';}}int matcher(string text){int textSize=text.length();int j=0;for(int i=0;i!=textSize;i++){j=dfa[j][text[i]-97];if(j==patternSize)return i-patternSize+1;}return -1;}
};int main()
{//只有a/b/c三个字母尝试进行KMP匹配,便于debug DFA_KMP algOb("ababc",3);algOb.dfaBuilder();cout<<"构建状态转移数组\n";for(int i=0;i!=algOb.patternSize;i++){for(int j=0;j!=algOb.charSetSize;j++){cout<<algOb.dfa[i][j]<<' ';}cout<<'\n';}cout<<"在text字符串下标为"<<algOb.matcher("abababc")<<"处发现模式字符串"<<'\n';//任务://学会构造dfa数组 //学会更新影子状态 //完成完整的KMP return 0;
}
C++刷力扣、PAT第一周笔记相关推荐
- 零基础的我刷力扣一周后,总结了点东西
一.前言 之前一直想学习数据结构与算法,因为一直听说这个很重要嘛,还有力扣这个网站那也是神交已久啊~~ 但是又不敢接触,因为恐惧嘛,害怕学不会,害怕被吊打~~~~~ 后来遇到了一个大佬,算法大佬,超强 ...
- 【关于为什么要刷力扣的思考】记第二次周赛AK
前言 从上次AK周赛的一月底,磕磕绊绊到五月初,总共经历了20多场的周赛 在这20场周赛中,四题:三题:两题:一题 = 2:12:8:1 总体来说应该还是在两到三题中间徘徊 但很多时候做出的两题,并非 ...
- 20210627:力扣第247周周赛(上)
力扣第247周周赛(上) 题目 思路与算法 代码实现 写在最后 题目 两个数对之间的最大乘积差 循环轮转矩阵 思路与算法 两个数对之间的最大乘积差:排序相减即可 循环轮转矩阵:模拟即可,注意逆时针和顺 ...
- 20210601:力扣第243周周赛(上)
力扣第243周周赛(上) 题目 思路与算法 代码实现 写在最后 题目 检查某单词是否等于两单词之和 插入后的最大值 思路与算法 检查某单词是否等于两单词之和:直接转化比较即可 插入后的最大值:负数,则 ...
- 20210426:力扣第238周周赛(上)
力扣第238周周赛(上) 题目 思路与算法 代码实现 写在最后 题目 K 进制表示下的各位数字总和 最高频元素的频数 思路与算法 第一题是数学题,考察各进制与十进制数的相互转换,不多赘述,连续取余求和 ...
- 20210424:力扣第237周周赛(下)
力扣第237周周赛(下) 题目 思路与算法 代码实现 写在最后 题目 单线程 CPU 所有数对按位与结果的异或和 思路与算法 第一题属于一类cpu流水线题目,实现常规方法堆加排序即可. 第二题属于数学 ...
- 20210217:力扣第228周周赛(上)
力扣第228周周赛(上) 题目 思路与算法 代码实现 写在最后 题目 生成交替二进制字符串的最少操作数 统计同构子字符串的数目 思路与算法 第一题需要注意不能直接翻译题意,直接翻译的代码存在先入为主定 ...
- 20210201:力扣第226周周赛(上)
力扣第226周周赛(上) 题目 思路与算法 代码实现 写在最后 题目 盒子中小球的最大数量 2. 1743. 从相邻元素对还原数组 思路与算法 第一题简单的数数问题,python比较方便,使用str函 ...
- 20200727:力扣第31周双周赛题解
力扣第31周双周赛题解 题目一:在区间范围内统计奇数数目 给你两个非负整数low和high,请你返回low和high之间(包含二者)奇数的数目 0 <= low <= high <= ...
最新文章
- snp可视化之瀑布图
- php 插入 mysql_php插入mysql数据返回id的方法
- 联想一体机电源键不亮_联想/兄弟打印机复印一体机激光器清洁教程
- Wrapper+map实现页面显示
- 题解 P1091 【合唱队形】
- 分子排列不同会导致_武汉理工《Matter》:构筑晶体内跨尺度分子筛单晶反应器...
- 二、Spring Cloud的配置 之 Eureka(服务注册中心)配置
- 个图标当十个用—多功能系统级图标制作攻略
- Java - 批量生成二维码压缩包
- elasticsearch中forcemerge清除文件占用的磁盘空间
- 删库跑路技巧 删库跑路命令
- WIN7 声音图标不见
- 中望3D 2021 自动缩放基准面大小
- 2.3.2 合并(拼接)字符串
- python中科学记数法表示_matplotlib中的科学记数法
- 线代9讲_特征值与特征向量相似理论
- 公众号h5获取手机号权限_微信公众号开发之网页授权(获取用户信息)
- ESP32 开发笔记(四)littleVGL LVGL 控件学习 Arc 弧形控件
- 笔记 - JavaScript - 超哥视频
- 编码 人的语言与机器语言转换