算法学习
为成大道踏平坎坷
这个作者很懒,什么都没留下…
展开
-
单调栈C++实现-查找数组中某个数左右两边离他最近小于他的数
单调栈给出一个数组,求助每个位置上的数,左边比他小的和右边比他小的数,常规的方法时间复杂度是O(N^2),利用单调栈结构可以用O(N)解决上述问题。单调栈实现(无重复数)设置一个栈,栈底到栈顶从小到大,按照顺序将数据压入栈中,如某个数压入时不满足此时的大小顺序要求,就需要将栈中的数弹出,此时记录这个数的左右情况,右边比这个数小的是当前准备压入的这个数,左边比他小的这个数是栈中当前数压着的那个。当数组压完以后,栈中有剩余,则依次弹出,右边比当前数小的不存在,左边比当前数小的是栈中他压着的那个代码实现原创 2022-02-01 19:07:50 · 1209 阅读 · 0 评论 -
滑动窗口动态获取窗口最大值与最小值
滑动窗口滑动窗口是一种想象出来的数据结构,窗口有左边界L和右边界R。在数组或者字符串或者一个序列上,记为S,窗口就是S[L…R]这一部分,L往右滑动意味着有样本滑出窗口,R往右划动意味着有样本滑入窗口,L和R都只能往右滑动。窗口定义R边界向右移动,数组中的数从窗口右侧进入窗口L边界向右移动,数组中的数从窗口左侧出窗口左边界不能到右边界的右侧如何找到动态窗口中的最大值准备一个双端队列,数据可以从头部进头部出,也可以从尾部进尾部出。R++时,将数据从双端队列的尾部插入,此时队列为空,可以原创 2022-01-26 01:02:46 · 962 阅读 · 0 评论 -
图论算法-最小生成树-Kruskal和prim算法
最小生成树概念:在无向图中求一棵树T,使得这个树拥有图G中所有顶点,且所有边都是来自图G中的边,并且满足整颗树的边权之和最小,这棵树就是图G的最小生成树。特征:最小生成树是树,因此边的数量等于顶点数减1,并且树内一定不会有环图G生成的最小生成树,最小生成树可能不唯一,但是边权之和必然唯一由于是无向图,所以根据给出的结点开始生成最小生成树即可。Kruskal算法步骤以边的角度出发,将所有边按权值大小排序,先将边从小到大加入到集合中,看添加边后有没有形成环,若形成环,则不要这条边。判断是原创 2022-01-17 20:46:37 · 185 阅读 · 0 评论 -
图论算法-dijkstra算法
dijkstra算法思想:用于解决单源最短路问题,即给定有向图G和起点from,通过算法得到from到其他每个顶点的最短距离。步骤:设置集合selectedNode存放已被访问过的点,每次从未被访问的的结点集合distancemap中找到一个距离起点from最近的点minnode。令minnode为中介点,优化起点与其他所有能从u到达的所有点的最短距离。将minnode加入到已访问结点selectednode中。这样执行n次(图中结点数)以后,直到集合selectednode已包含所有顶点。原创 2022-01-17 20:45:06 · 491 阅读 · 0 评论 -
图论算法-拓扑排序C++实现
拓扑排序思想将有向无环图的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u、v,若存在u->v,则u一定在v的前面,这个序列又被称为拓扑序列。步骤定义一个队列q,将所有入度为0的结点加入到队列q中取队首结点,输出,然后删去所有从他出发的边,并令这些边到达顶点的入度-1,如果某个顶点的入度为0,则将其加入队列。不断执行2操作,直到队列为空。如果队列为空时,入过队的结点数目恰好为N,说明拓扑排序成功,图G为有向无环图;否则拓扑排序失败,图G中有环。或者根据返回的排序结果判断,若结果数组原创 2022-01-17 20:41:52 · 801 阅读 · 0 评论 -
图模板、BFS、DFS的C++实现
图图的存储方式有两种:邻接矩阵和邻接表。邻接矩阵用二维数组来表示顶点之间是否存在边,边的权重为多少。对于无向图来说,邻接矩阵是一个对称矩阵。缺点是邻接矩阵虽然比较好写但是需要开辟一个二维数组,如果顶点数量太多,容易超过题目的内存限制。邻接表把同一个顶点的所有出边都放在一个列表中,那么N个顶点就会有N个列表,这N个列表就是图G的邻接表,记为Adj[N]每个结点会存放一条边的信息(括号外的数字是边的终点编号,括号内的数字是边权。对于初学者来说,使用变长数组vector来表示邻接表更为简便。原创 2022-01-15 00:02:48 · 581 阅读 · 0 评论 -
并查集C++实现
并查集是什么是一种含有合并和查找功能的数据结构,用于处理一些不交集的合并和查询问题。主要含有两个功能:判断任意两个元素是否属于同一个集合;按照要求合并不同集合。并查集的基本操作查找:给出一个元素,查找元素属于哪个集合。步骤:不断向上查找,直到找到他的根节点,之后根据根节点是否相同判断两个元素是否属于同一个集合。查询操作完成后,并查集结构还会进行路径压缩操作,就是将查询节点到根节点之间的所有节点都指向根节点,可以有效限制因不断合并造成部分区域不匀称,使其保持较低的树高。合并:将两个子集合并成同一个原创 2022-01-12 22:07:32 · 440 阅读 · 0 评论 -
动态规划04数字转变为字符串结果数
规定1和A对应、2和B对应、3和C对应…26和Z对应那么一个数字字符串比如"111”就可以转化为:“AAA”、“KA"和"AK”给定一个只有数字字符组成的字符串str,返回有多少种转化结果暴力递归构建尝试函数,str为数字字符串,index为当前进行到哪个位置,返回值为当前转换结果数主函数中如何调用process(str,index)分析basecase当index==str的长度时,到达字符串的尾部,返回数字1,表示找到一种转换结果分析普通情况当index遇到的字符为0,因为没有以0开原创 2021-10-22 22:38:32 · 204 阅读 · 0 评论 -
动态规划03背包问题
题目给定两个长度都为N的数组weights和values,weights[i]和values[i]分别代表 i号物品的重量和价值给定一个正数bag,表示一个载重bag的袋子,装的物品不能超过这个重量返回能装下的最大价值暴力递归首先建立尝试函数process,参数为w数组、v数组、当前进行到的序号index、背包剩余的容量rest,返回值为包中物品的总价值那么主函数中调用的就是process(w,v,0,bag)首先分析basecase:当index==N时,所有物品都以选完,返回0当res原创 2021-10-22 22:37:20 · 251 阅读 · 0 评论 -
动态规划02左右取牌返回最大点数
题目给定一个整型数组arr,代表数值不同的纸牌排成一条线玩家A和玩家B依次拿走每张纸牌规定玩家A先拿,玩家B后拿但是每个玩家每次只能拿走最左或最右的纸牌玩家A和玩家B都绝顶聪明请返回最后获胜者的分数暴力递归首先设置一个尝试函数processf,参数为arr数组,L表示左边界,R表示右边界,返回值为int表示取到数的和。先来看basecase:当只有一张牌的时候,即L==R的时候,拿一张牌,拿到的就是最后这张牌。普通情况拿左边的牌,获得值为arr[L],但是对方接下来要拿牌 拿的就是[原创 2021-10-22 22:35:52 · 583 阅读 · 0 评论 -
LeetCode82 删除链表重复节点2
哑结点+非递归class Solution {public: ListNode* deleteDuplicates(ListNode* head) { ListNode dummyhead(-101, head); ListNode* cur = &dummyhead; while (cur->next != NULL && cur->next->next != NULL) { if (cur->next->val == cur-原创 2021-08-13 13:04:43 · 96 阅读 · 0 评论 -
LeetCode83 删除链表重复节点
创建两个节点保存前驱和当前节点,不断比较中向后移动,若相等前驱直接连到后继上,就完成了删除操作。若不相等,则同时后移。class Solution {public: ListNode* deleteDuplicates(ListNode* head) { ListNode dummyhead(999, head); ListNode* cur = head; ListNode* curPre = &dummyhead; while (cur != NULL) { if (原创 2021-08-13 13:03:55 · 102 阅读 · 0 评论 -
LeetCode148 排序链表
方法一 选择排序 时间复杂度O(N^2)空间复杂度O(1) 超时。。。class Solution {public: ListNode* sortList(ListNode* head) { ListNode* tail = NULL; ListNode* cur = head; ListNode* smallPre = NULL; ListNode* small = NULL; while (cur != NULL) { small = cur; smallPre =原创 2021-08-13 13:02:59 · 72 阅读 · 0 评论 -
LeetCode143重排链表
方法一找到中间后,右半区压入栈中,然后将两部分合并class Solution {public: void reorderList(ListNode* head) { ListNode* fast = head; ListNode* slow = head; ListNode* mid; stack<ListNode*> st; while (fast->next != NULL &&原创 2021-08-13 13:02:15 · 101 阅读 · 0 评论 -
LeetCode19 删除倒数k个节点
class Solution {public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* slow=head; ListNode* fast=head; // if(head->next==NULL){ // if(n==1){ // return NULL; // } // } // if(head->nex原创 2021-08-13 13:01:27 · 110 阅读 · 0 评论 -
程序员面试指南 删除链表中间节点c++
牛客上 题目给出的要比书上的简单,牛客上求的是删除第k个节点,所以只需要找到第k-1个即可。先写牛客上的内容list_node * remove_kth_node(list_node * head, int K){ //////在下面完成代码 list_node* cur=head; list_node* pre=head; if(K==1){ return head->next; } while(--K){ p原创 2021-08-13 12:49:50 · 138 阅读 · 0 评论 -
代码面试指南 打印有序链表公共部分c++
打印两个链表的公共部分,因为题目中给出的链表是有序的,所以只需要逐个比较即可void sol(list_node * a_head, list_node * b_head){ //////在下面完成代码 while(a_head!=NULL &&b_head!=NULL){ if(a_head->val<b_head->val){ a_head=a_head->next; }else if(a原创 2021-08-13 12:48:42 · 95 阅读 · 0 评论 -
LeetCode2 两数相加
class Solution {public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode* head = NULL; ListNode* tail = NULL; int carry = 0; while (l1 || l2) { int n1 = l1 ? l1->val : 0; int n2 = l2 ? l2->val : 0; int sum = n1 + n2+c原创 2021-08-13 12:46:49 · 75 阅读 · 0 评论 -
剑指offer22倒数k个节点
方法一 弹栈 笔试做法class Solution {public: ListNode* getKthFromEnd(ListNode* head, int k) { stack<ListNode*>st; ListNode* result=NULL; while(head){ st.push(head); head=head->next; } whi原创 2021-08-13 12:46:13 · 76 阅读 · 0 评论 -
LeetCode141142环形链表
##方法一 使用set 笔试做法class Solution {public: ListNode* detectCycle(ListNode* head) { set<ListNode*>st; while (head) { if (st.find(head) == st.end()) { st.insert(head); head = head->next; } else { return head; } } retu原创 2021-08-13 12:45:21 · 86 阅读 · 0 评论 -
LeetCode160相交链表
class Solution {public: ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { stack<ListNode*>stA; stack<ListNode*>stB; if (headA == NULL || headB == NULL) { return NULL; } while (headA) { stA.push(headA); headA原创 2021-07-15 22:44:44 · 106 阅读 · 0 评论 -
LeetCode21合并两个有序链表
class Solution {public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* newhead = NULL; ListNode* cur = NULL; while (l1 != NULL && l2 != NULL) { if (l1->val <= l2->val) { newhead = newhead == NULL ? l1 : newh原创 2021-07-15 22:42:10 · 77 阅读 · 0 评论 -
LeetCode25 k个一组链表反转
class Solution {public: ListNode* popstack(stack<ListNode*>& st, ListNode* left, ListNode* right) { if (left != NULL) { left->next = st.top(); } ListNode* ccc = st.top(); st.pop(); ListNode* next = NULL; while (!st.empty()) {原创 2021-07-15 22:40:37 · 105 阅读 · 1 评论 -
LeetCode92反转部分链表
class Solution {public: ListNode* reverseBetween(ListNode* head, int left, int right) { int len=right-left+1; ListNode* pre_head=nullptr; ListNode* result=head; while(head&&--left){ pre_head=head;原创 2021-07-15 22:39:14 · 365 阅读 · 1 评论 -
LeetCode206反转链表
反转单向链表单向链表的节点只有一个指针指向下一个元素。struct ListNode{ int val; ListNode* next;};ListNode* reverseList(ListNode* head){ ListNode* newhead=nullptr; while(head){ ListNode* next=head->next; head->next=newhead; newhead=head原创 2021-07-15 22:37:29 · 73 阅读 · 0 评论 -
算法学习15:求二叉树的最大宽度
分析:创建一个哈希表,储存每个节点和节点所在的层数。将头结点和他的层数1先记入哈希表中。接下来就是按照宽度优先遍历的顺序,按层逐个遍历。而且再将左右孩子推入队列的过程中,将节点所在层的信息记录到哈希表中。遍历的过程中记录节点的当前所在层,如果该节点与之前遍历的在同一层,则该层节点数增加,如果与之前遍历的不在同一层,说明进入下一层,需要将记录的节点数与之前的最大宽度取最大值,然后当前层数加一,当前层节点数置为1完整代码#include<iostream>#include<queue&原创 2021-03-09 16:52:34 · 865 阅读 · 0 评论 -
算法学习14:二叉树的宽度优先遍历
分析宽度优先遍历使用队列,先进先出,弹出就先放左再放右代码void levelOrder(Tree* head){ queue<Tree*> t; if(head==nullptr){ return; } t.push(head); while(!t.empty()){ head=t.front(); cout<<t.front()->val; if(head->left!=nullptr){ t.push(head->left原创 2021-03-09 10:14:26 · 223 阅读 · 0 评论 -
算法学习13:分别用递归和非递归方式实现二叉树先序、中序和后序遍历
数据结构树结点class Tree{ public: int data; Tree* left; Tree* right; Tree(int x){this->data=x;left=NULL;right=NULL;}};构造一颗二叉树Tree* head=new Tree(1);head->left=new Tree(2);head->right=new Tree(3);head->left->left=new Tree(4);head-原创 2021-03-05 10:05:32 · 870 阅读 · 1 评论 -
算法学习12:两个单链表相交的一系列问题
题目在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点 head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数, 如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。 要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外空间复杂度请达到O(1)。分析首先要判断这两个单链表是否有环。因为有环的情况下需要单独讨论。若两个链表都没环,有可能相交也有可能不相交,相交时,末节点必定为同一个。若两个都有环,则需要分三种情况讨论,不相交原创 2021-03-03 08:47:15 · 170 阅读 · 0 评论 -
算法学习11:复制含有随机指针节点的链表c++实现
题目 复制含有随机指针节点的链表一种特殊的链表节点描述如下typedef struct ListNode{ int data; ListNode* next; ListNode* random; ListNode(int x): data(x),next(NULL),random(NULL){}}ListNode类中的data是节点值,next指针和正常的单链表指针中的next指针的意义一样,都指向下一个节点,random指针是ListNode类中的新增的指针,这个指针可能指向链表中的原创 2021-03-03 08:46:56 · 239 阅读 · 0 评论 -
算法学习10:将单向链表按某值划分为左边小、中间相等、右边大的形式
题目给定一个单链表的头节点head,节点的值类型是整型,再给定一个整数pivot。实现一个调整链表的函数,将链表调整为左边部分都是值小于pivot的节点,中间部分都是值等于pivot的节点,右部分都是值大于pivot的节点分析根据题目可得,与之前的快排原型荷兰国旗问题十分相似。但是原问题的数据是在数组中,目前的数据在单链表中,需要我们将数据(就是节点)从单链表转移到数组中,完成要求后,再将数组中的内容转移到单链表中。代码一、 生成链表添加元素链表结构体定义,由数据域和指针域构成typedef原创 2021-02-26 00:20:40 · 560 阅读 · 0 评论 -
算法学习09:判断链表是否为回文结构C++实现
题目给定一个单链表的头结点head,请判断该链表是否为回文结构例子1->2->1,返回ture1->2->2->1返回ture15->6->15返回ture1->2->3返回false方法一 使用堆栈结构 额外空间复杂度O(N)分析将链表中的元素按顺序存入堆栈,那么栈的弹出顺序和链表的顺序刚好相反。对比栈顶元素和链表当前元素,如果不同,返回false,如果相同,弹出栈并将链表指向下一个元素,不断遍历至空,若全部相同,返回true#in原创 2021-02-22 10:17:47 · 515 阅读 · 0 评论 -
算法学习08:打印两个有序链表的公共部分c++实现
题目给定两个有序链表的头指针head1和head2,打印两个链表的公共部分要求如果两个链表的长度之和为N,时间复杂度要求为O(N),额外空间复杂度要求为O(1)分析首先让两个序列的头指针止住对应有序链表的头部,然后比较这两个指针所指元素的大小,谁的值小,对应序列的指针就后移,然后继续比较,谁小谁后移。若两者元素大小相等,则打印输出,之后同时后移。直到有一个序列的指针越界后,程序停止。代码首先需要创建一个链表结点结构struct node { int value; node *原创 2021-02-21 11:01:42 · 262 阅读 · 0 评论 -
算法学习07:反转单向和双向链表
题目分别实现反转单向链表和反转双向链表的函数。要求:如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度为O(1)分析用三个指针分别记录前一个节点,当前节点和后一个节点。反转时,将当前节点指向前一个节点...原创 2021-02-18 17:18:57 · 384 阅读 · 0 评论 -
算法学习06:单链表
单链表一个单向链表基本由两个元素组成,即数据字段和指针,而指针通常指向下一个节点内存所在的地址。最后一个节点没有其他节点可以连接,因此指针的值为NULL。class List{ public: int data; class List *next;}创建与遍历以动态分配产生链表节点的方式,可以先行定义一个类数据类型,要有一个数据字段,接着在类中定义一个指针变量,其数据类型与此类相同,作用是指向下一链表节点。遍历单向链表的过程,就是使用指针运算来访问链表中的每一个节点,为了便于操作可以定原创 2021-02-08 11:05:10 · 163 阅读 · 0 评论 -
算法学习05:哈希表和有序表
哈希表哈希表在使用层面上可以理解为一种集合结构如果只有key,没有value,可以使用UnOrderedSet结构如果既有key,又有value,可以使用UNOrderedMap结构有无伴随数据是两者的唯一区别,底层实际结构是一回事。使用哈希表增删改查的操作可以认为是时间复杂度O(1),但是常数时间比较大放入哈希表的东西,如果是基础类型,内部按值传递,内存占用就是这个东西的大小。如果不是基础类型,内部按引用传递,内存占用就是这个东西内存地址大小哈希表的使用unorderMap头文件原创 2021-02-06 16:48:09 · 372 阅读 · 0 评论 -
算法学习04:排序算法的稳定性及其汇总
稳定性相同值的个体之间,如果不因为排序改变相对次序,那么该排序具有稳定性复合数据,某个数据先按其中一个值排序,再使用稳定性的排序算法对第二个值排序,就可以得到按照第二个值排序,同时内部第二个值相同时,按第一个值排序的序列排序算法稳定性分析O(N^2)选择排序:选择序列中的一个最小值,与序列首交换,即破坏了稳定性冒泡排序:确保两数相等时,不交换位置,即可保证稳定性插入排序:插入的数在向左移动的过程中,遇到相等的数就停下来,也可以保证稳定性O(N*logN)归并排序:当左右序列的当前数相等的原创 2021-02-05 11:16:15 · 180 阅读 · 0 评论 -
算法学习03:桶排序
01计数排序首先遍历数组,找到最大值与最小值,设置一个长度为最大值-最小值+1的数组,再次遍历这个数组,以当前值-最小值作为下标,将该下标的计数器增1。扫描一遍计数器数组,按顺序将值收集起来。举个例子 nums=[2, 4, 3, 4, 7]遍历一次数组,找到数组元素的最小值与最大值分别为2和7,那么我们设置一个长度为7-2+1的数组counter,这是一个计数数组,每个位置分别代表最小值+小标值 这个数出现的次数,counter[0]代表最小值+0也就是2出现的次数。遍历原数组,数组中这个数每出原创 2021-02-04 18:04:47 · 123 阅读 · 0 评论 -
算法学习02:认识O(logN)的排序
01归并排序02归并排序拓展03堆04堆排序05堆排序扩展题目06荷兰国旗问题07不改进的快速排序08 随机快速排序原创 2021-02-04 16:52:10 · 2558 阅读 · 0 评论 -
算法学习01:复杂度和简单排序算法。
新年第一篇,最近开始学习数据结构和算法的课程,课程的里给的代码是用java写的,我打算自己听完课后整理一下内容,然后尽量用c++实现,起到一定的复习和巩固的作用。01 时间复杂度一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。那常见的常数操作有哪些呢?寻址操作,例如int a=air[i];加减乘除位运算时间复杂度是一个算法流程中,常数操作数量的一个指标,常用O表示。具体来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中,发生了多少次常数操作,原创 2021-01-13 01:18:37 · 243 阅读 · 0 评论