C++第二阶段——数据结构和算法,之前学过一点点数据结构,当时是基于Python来学习的,现在基于C++查漏补缺,尤其是树的部分。这一部分计划一个月,主要利用代码随想录来学习,刷题使用力扣网站,不定时更新,欢迎关注!
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足的 Node.val == val 的节点,并返回新的头节点
头结点单独处理
/** * 单链表的定义。 * 结构ListNode { * int val; * 列表节点 *下一个; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x),下一个(下一个){} * }; */class 解决方案 { public: ListNode* removeElements(ListNode* head, int val) { //先判断头结点是不是val,如果是的话,head就后移 while(head!=NULL && head->val==val){ ListNode * temp ; 临时 = head; 头 = head->下一个; 删除 temp ; } //定义一个指针指向中间过程的结点 span> ListNode * cur = head; while(cur!= NULL&&cur-> 下一个!=NULL){ if(cur->下一个->val== val){ / / 删除下一个结点 ListNode *temp = cur ->下一个; cur->下一个= span> cur->下一个->下一个; 删除 temp; } span> else{ cur = span> cur->next; } } 返回 head; } };
虚拟头节点
/** * 单向链表的定义. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */class 解决方案 {public: ListNode* removeElements(ListNode* head, int val) { //定义一个虚拟头结点 ListNode * dummyHead = 新 ListNode(<跨度CLass="token number">0); dummyHead ->next = head; // 一个定义路径结点 ListNode *cur = dummyHead; while(cur!=NULL&&cur->下一个! =NULL){ if(cur->下一个->val==val){ ListNode * temp = cur->下一个; cur>->下一个 = cur->下一个-> 下一个; 删除 temp; } else{ cur = cur->下一个; } } < span class="3967-301e-1db2-3edb token punctuation">返回 dummyHead->next; }};
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。
是个体链表,则如果还需要属性 prev 来指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList 类:
MyLinkedList() 初始化 MyLinkedList 对象。
int get(int index) 获取链表中下标为索引的节点的值。如果下标无效,则返回 -1 。
void addAtHead(int val) 将一个值 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表
void addAtTail(int val) 将值 val 的节点追加到链表中作为链表的最后一个元素。
void addAtIndex(intindex, int val) 将一个值 val 的节点插入到链表中下标为索引的节点之前。如果索引等于链表的长度,那么该节点会被追加到链表的补充。如果索引比长度更大,该节点
void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为索引的节点。
示例:
输入
[“MyLinkedList”, “addAtHead”, “addAtTail”, “addAtIndex”, “get”, “deleteAtIndex”, “get”]
[[], [1], [3], [1, 2] , [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]
解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 3
提示:
0 <= index, val <= 1000
请不要使用内置的 LinkedList 库。
调用 get、addAtHead、addAtTail、addAtIndex 和 deleteAtIndex 的次数不超过2000。
//创建一个结点class LinkNode{< /span>public: LinkNode(int inputVal){ 这个->val =< /span> inputVal; } int val; LinkNode *下一个= NULL;};class MyLinkedList { dummyHead= 新 LinkNode(0); 大小=0; //获取链表长度 } int 获取(int索引) { if(索引<0||索引>(这个-> span>大小-1)){ 返回 -1; } LinkNode * cur = dummyHead->下一个 ; while(index--< span class="9697-e961-6b78-3967 token operator">){ cur = cur ->下一个; } 返回 cur->val; }< /span> void addAtHead(int val) { LinkNode * insertNode = 新 LinkNode(val ); insertNode->下一个= dummyHead->下一个; dummyHead->下一个=insertNode; 大小++; } void addAtTail( int val) { // 找到尾部 LinkNode * cur = dummyHead;< /span> while(cur!=NULL&&cur->下一个!=NULL){ if(索引>=此->大小+1 ){ showLink< span class="e961-6b78-3967-301e token function">(); return; } else if(index == span> 此->大小){ addAtTail(val); 返回; span> } else if(索引<=0) span>{ addAtHead(val); return; } LinkNode * cur = dummyHead; while(索引--){ cur = cur->下一个; } //添加 LinkNode * insertNode = 新 LinkNode(val); insertNode->下一个= cur-> 下一个; cur->下一个 = insertNode; 大小++;< /span> } void deleteAtIndex(int索引) { 如果(索引<0||索引> (这个- >大小-1)){ 返回 ; } LinkNode * cur = dummyHead; while(索引--){ cur = cur->下一个 ; } //删除 LinkNode * temp = cur->下一个; cur->下一个 = cur->下一个->下一个; 删除 temp;< /span> temp = NULL; 大小--; } LinkNode * dummyHead= new LinkNode(0); int 大小=< /span>0; //获取链表长度 < span class="e32e-d2b9-ca43-9f6d token comment">void showLink( ){ LinkNode * cur= dummyHead; while(cur!=NULL&&cur->下一个!=NULL){ cout<<cur< span class="9f6d-5c4a-7235-3898 令牌运算符">->下一个->val<<" "; cur = cur ->下一个; } cout<<endl; }};// 6,7,2,0,4, // 4/** * 您的 MyLinkedList 对象将被实例化并按如下方式调用: * MyLinkedList* obj = new MyLinkedList(); * int param_1 = obj->get(索引); * obj->addAtHead(val); * obj->addAtTail(val); * obj->addAtIndex(index,val); * obj->deleteAtIndex(索引); */
给你单链表的头节点 head ,请你链食物表,并返回工具后的链表。
双剪刀,注意先移动pre再移动cur。
< code class="9f6d-5c4a-7235-3898 token comment">/** * 单链表的定义。 * 结构ListNode { * int val; * 列表节点 *下一个; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * } ; */class 解决方案 {public: ListNode* reverseList(ListNode* head) { if(head==NULL|| span>head->下一个==NULL){ //只有一个结点 < span class="3967-301e-1db2-3edb token comment">返回 head; } //定义两个指针,一个指前面的,一指后面的 ListNode *pre = NULL; ListNode *cur = head; while( span>cur!=NULL){ //用一个值去接收curListNode *temp = cur->下一个; cur->下一个 = pre; 前 = cur; cur = span> temp; } 返回 pre; }}; span>
另外一种通过电位下降的方式碳水化合物链表,等增益电位再补上
给你一个链表,两两交换其中后继的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
每两个交换一次,需要找到交换之前的节点。注意交换实的逻辑,对于不变量需要提前保存信息。
/** * 单链表的定义。 * 结构ListNode { * int val; * 列表节点 *下一个; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x),下一个(下一个){} * }; */class 解决方案 {public: ListNode* 交换对(ListNode* head) { if(head==NULL|| 头->下一个==NULL ){ 返回 head ; } //创建一个虚拟头结点 ListNode * dummyNode = 新 ListNode(0)< span class="ca43-9f6d-5c4a-7235 token punctuation">; dummyNode->下一个 =head; ListNode * cur = dummyNode; while(cur->下一个!=NULL&&当前->下一个->下一个! =NULL){ ListNode * a = cur-> next; ListNode * b= cur->下一个->下一个->下一个; cur->下一个= cur->下一个->下一个; cur->下一个->下一个= a; a->下一个 = b; cur = cur->下一个->下一个; } return dummyNode->next; }};
给你一个链表,删除链表的倒数第一个n个结点,并返回链表的头结点。
双指针的经典问题,快指针先走n个,快慢指针再同时走,当快指针下一个为NULL时,慢指针下一个即为要删除的元素
/** * 单链表的定义. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x ), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */class< /span> 解决方案 {public: ListNode* removeNthFromEnd(ListNode* head, int n) { if (head==NULL){ 返回 head; } span> ListNode * dummyNode = 新 ListNode(0); dummyNode->下一个 = head; /使用快慢指针 ListNode* 快速 = dummyNode; ListNode*< /span> 慢= dummyNode; while(n--) { //快指针先走n个快速 = 快速->下一个; } 同时(快速!= NULL&&快速->下一个< span class="9f6d-5c4a-7235-3898 token 操作符">!=NULL){ 快速 = 快速->下一个; 慢= 慢->下一个 ; } //删除元素 ListNode * temp = Slow>->下一个;慢->下一个=< /span> 慢->下一个->下一个; 删除 temp; //删除 return dummyNode->next; } };
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的开始节点。如果两个链表没有交点,返回 null 。
/** * 单链表的定义。 * 结构ListNode { * int val; * 列表节点 *下一个; * ListNode(int x) : val(x), next(NULL) {} * }; */class 解决方案 {public: ListNode * getIntersectionNode(ListNode *headA, ListNode *headB) { //说明是找到合适的结点,不是值正确,而是同一个结点 //将两个链表右对齐//求两个链表的长度 if(headA ==NULL||headB==NULL){ 返回 NULL; } int lenA =1; int lenB =1; ListNode * curA = headA; ListNode *< /span> curB = headB; while(curA->下一个!=NULL){ lenA++; curA = curA->< /span>next; } while(curB->下一个!=NULL){ lenB++; curB = curB->下一个; }< /span> //寻找最短的链表 int minLen =min(lenA,lenB); // AB需要移动的长度 int needA= lenA-minLen; int needB = span> lenB - minLen; //右对齐两个节点 span> while(needA--){ headA = headA->下一个; } while(needB--)< span class="3967-301e-1db2-3edb token punctuation">{ headB = headB-> 下一个; } // 比较之后的链表是否相同 while(headA!=NULL||headB!= span>NULL){ if(headA== headB){ 返回 headA; } else{ headA = headA->下一个; headB = headB - >下一个; } } 返回 NULL; } };
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪下一个指针再次到达,则链表中环。为了表示给定链表中的环,运动系统内部使用整数 pos 来表示链表尾部连接到链表中的位置(索引从 0 开始) 。如果 pos 是-1,则修改在该链表中没有环。注意:pos不作为参数进行传递,为了达到标识链表的实际情况。
不允许链表。
/** * 单链表的定义。 * 结构ListNode { * int val; * 列表节点 *下一个; * ListNode(int x) : val(x), next(NULL) {} * }; */class 解决方案 {public: ListNode * detectCycle(ListNode *head) { //使用一个地图记录访问过的地址,不断将地址放入map,如果某次map的长度没有发生变化,说明入环了 map<ListNode *,ListNode *> addmap; if(head ==NULL){ 返回 NULL; } //创建虚拟头结点 ListNode * dummyHead = 新 ListNode(0); dummyHead->下一个 =< /span> head; //遍历 ListNode * cur = dummyHead; while(cur!=NULL){ //记录之前的大小 intfirstSize= addmap.大小< span class="e32e-d2b9-ca43-9f6d tokenfunction">(); addmap.插入( span>make_pair(cur->下一个,cur->下一个)); int endSize = addmap 。大小(); if(endSize< span class="ff7b-9697-e961-6b78 token punctuation">==firstSize){ //没有发生变化,说明已经入环 返回 addmap[cur->下一个]; } 其他< span class="ca43-9f6d-5c4a-7235 token keywords">{ cur = cur->下一个; } } 返回 NULL; } };
使用map存储每个结点的next,如果map存完之后长度没有变,那么说明进入环了,map中存储的值即为要返回的索引值。
使用双指针
/** * 单链表的定义。 * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class 解决方案 { ListNode * 第一个 = 头; ListNode * 慢 = head; while(first!=NULL&&第一个->下一个!=NULL){ 第一个 = 第一个->下一个-> 下一个;慢=慢->下一个; if(先==慢){ //此时相遇 ListNode * index1 = 第一个; ListNode * index2 = head; //找入环口 while(index1!=index2) {index1=index1 ->下一个;index2=index2->下一个; } 返回 index1; } } 返回 NULL< /span>; }};
C++数据结构与算法——链表原创由知识百科栏目发布,感谢您对的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++数据结构与算法——链表原创”