链表数据结构刷题
leetcode206: Reverse Linked List 将链表反序
class Solution { public: ListNode* reverseList(ListNode* head) { //创建三个指针 ListNode *pre=NULL; ListNode *curr=head; if(head==NULL){ return head; } ListNode *Next=curr->next; while(Next!=NULL){ ListNode *temp=Next->next; curr->next=pre; Next->next=curr; pre=curr; curr=Next; Next=temp; } return curr; } };
时间复杂度为O(n);
leetcode83:Remove Duplicates from Sorted List 删除链表中的重复元素
ListNode* deleteDuplicates(ListNode* head) { //时间复杂度为o(n) 空间复杂度为O(1)的算法的实现 ListNode *temp; ListNode* returnhead=head; if(head==NULL){ return NULL; } while(head->next!=NULL){ if(head->val == head->next->val){ temp=head->next; head->next=head->next->next; delete temp; } else{ head=head->next;} } return returnhead; }
leetcode86:选取链表中的partion:将小于partion的值放在链表的开头,大于partion的值放在链表的后半部分
class Solution { public: ListNode* partition(ListNode* head, int x) { //没有空间限制的代码 也就是不考虑空间复杂度的情况 ListNode *curr=head; ListNode *less=new ListNode(-1); ListNode *more=new ListNode(-1); ListNode *l=less; ListNode *m=more; if(head==NULL||head->next==NULL){ return head; } while(curr!=NULL){ if(curr->val<x){ l->next=curr; l=l->next; } else{ m->next=curr; m=m->next; } curr=curr->next; } l->next=more->next; m->next=NULL; return less->next; } };
时间复杂度为O(n),空间复杂度为O(n)
算法改进:空间复杂度为O(1)的算法;需要注意边界条件,还是采用两个指针的方式;
class Solution { public: ListNode* partition(ListNode* head, int x) { //考虑到空间复杂度的使用,使用O(1)的空间复杂度 //添加两个头结点 ListNode *first=new ListNode(0); first->next=head; ListNode *p=first; ListNode *q=p->next;//设置好两个指针变量; while(q!=NULL&&q->val<x){ p=p->next; q=q->next; } while(q!=NULL){ ListNode *temp=q->next; if(temp==NULL){ break; } if(temp->val>=x){ q=q->next; } else{ q->next=temp->next; temp->next=p->next; p->next=temp; p=p->next; } } return first->next; } };
leetcode 82,关于leetcode83的改进
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { // //递归的思想来解决问题 // if(head==NULL||head->next==NULL){ // return head; // } // ListNode* p=head->next; // if(p->val!=head->val){ // head->next=deleteDuplicates(p); // return head; // } // else{ // //找到第一个不相等的结点 // while(p&&p->val==head->val){ // p=p->next; // } // return deleteDuplicates(p); // } // } //不使用递归的方式 //使用一个头结点的指针 if(head==NULL || head->next==NULL) return head; ListNode* node=new ListNode(-1); node->next=head; ListNode* re=node; ListNode *curr=head;//用于遍历的指针 while(curr->next!=NULL){ if(curr->next->val!=curr->val){ if(node->next==curr) node=curr; else node->next=curr->next; } curr=curr->next; } if(node->next!=curr) node->next=curr->next; return re->next; } };
leetcode86: 将链表进行排序,将小于x的链接结点放置在链表的前面,将大于x的链接结点放置在其后面;
使用两个指针来进行模拟,然后再将两个结点合并;
class Solution { public: ListNode* partition(ListNode* head, int x) { //题目的意思 就是将相应的代码所有值小于相应值x的结点都放置到器前面,将所有的值大于x都放置到相应的后面 //通过两个链表 先分开,再合并 ListNode *list1=new ListNode(-1); ListNode *list2=new ListNode(-1); ListNode* head2=list2; ListNode* head1=list1; if(head==NULL||head->next==NULL){ return head; } while(head!=NULL){ if(head->val<x){ list1->next=head; head=head->next; list1=list1->next; list1->next=NULL; } else{ list2->next=head; head=head->next; list2=list2->next; list2->next=NULL; } } list1->next=head2->next; return head1->next; } };
链表加法:
class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { //思路很简单将两个结点进行相加,然后将链表反转即可 if(l1==NULL){ return l2; } else if(l2==NULL){ return l1; } int cnt=0; ListNode *ans=new ListNode(-1); ListNode *head=ans; while(l1!=NULL&&l2!=NULL){ int num=(l1->val+l2->val+cnt)%10; cnt=(l1->val+l2->val+cnt)/10; ListNode *temp=new ListNode(num); ans->next=temp; ans=ans->next; l1=l1->next; l2=l2->next; } if(l1!=NULL){ while(l1!=NULL){ int num=(l1->val+cnt)%10; cnt=(l1->val+cnt)/10; ListNode *temp=new ListNode(num); ans->next=temp; ans=ans->next; l1=l1->next; } } if(l2!=NULL){ while(l2!=NULL){ int num=(l2->val+cnt)%10; cnt=(l2->val+cnt)/10; ListNode *temp=new ListNode(num); ans->next=temp; ans=ans->next; l2=l2->next; } } if(cnt==1){ ans->next=new ListNode(1); } return head->next; } };
leetcode21:将两个有序链表进行merge,使其任然有序(通过递归的方式来构建,或者使用新的存储空间);
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { //将两个链表进行连接 //一种使用递归的方式 if(l1==NULL){ return l2; } if(l2==NULL){ return l1; } ListNode* head=new ListNode(-1); ListNode* head2=head; if(l1->val<l2->val){ head->next=l1; head=head->next; head->next=mergeTwoLists(l1->next,l2); } else{ head->next=l2; head=head->next; head->next=mergeTwoLists(l1,l2->next); } return head2->next; }
leetcode23 合并多个链表的方式:比较难 需要采用的是优先队列来保存结点
leetcode24 Swap Nodes in Pairs 交换两个结点成对
多个指针穿针引线,注意边界条件等
ListNode* swapPairs(ListNode* head) { if(head==NULL){ return NULL; } if(head->next==NULL){ return head; } ListNode* pre=new ListNode(-1); ListNode* re=pre; ListNode* curr=head; // ListNode* Next=curr->next; while(curr->next!=NULL){ ListNode* Next=curr->next; ListNode* temp=Next->next; pre->next=Next; Next->next=curr; curr->next=temp; pre=curr; curr=temp; if(curr==NULL){ break; } } return re->next; }
leetcode148 对链表的排序(和数组中的排序的基本思想是一样的 但是在链表实现的时候归并排序可以是原址排序)
ListNode* sortList(ListNode* head) { //使用链表的排序,使用mergesort采用的是的排序的方式 将在两个结点的中点开始切分 if(head==NULL){ return NULL; } if(head->next==NULL){ return head; } int size=get_list_size(head); ListNode* mid=reach_mid(head,size/2-1); ListNode* right=mid->next; mid->next=NULL; ListNode* l=sortList(head); ListNode* r=sortList(right); return merge(l,r); } int get_list_size(ListNode* head){ int i=0; while(head!=NULL){ i++; head=head->next; } return i; } ListNode* reach_mid(ListNode* head,int step){ for(int i=0;i<step;i++){ head=head->next; } return head; } ListNode* merge(ListNode* left,ListNode* right){ if(left==NULL){ return right; } if(right==NULL){ return left; } ListNode* head=new ListNode(-1); ListNode* ans=head; if(left->val<right->val){ head->next=left; head=head->next; head->next=merge(left->next,right); } else{ head->next=right; head=head->next; head->next=merge(left,right->next); } return ans->next; }
leetcode160:
求两个链表的公共结点的方式:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { //只能说都好强啊, 通过走两轮来进行达到终点 ListNode *curr1=headA; ListNode *curr2=headB; while(curr1!=curr2){ curr1=curr1?curr1->next:headB; curr2=curr2?curr2->next:headA; } return curr1; }
leetcode328:将奇数和偶数的链表分离然后重新merge
ListNode* oddEvenList(ListNode* head) { //肯定是使用两个指针的方式 //一个奇数指针,一个偶数指针 if(head==NULL||head->next==NULL){ return head; } ListNode* first=head; ListNode* second=head->next; ListNode* cur=second; while(second!=NULL&&second->next!=NULL){ first->next=second->next; first=first->next; second->next=first->next; second=second->next; } first->next=cur; return head; }
leetcode141:判断一个链表是否有环:
bool hasCycle(ListNode *head) { //判断一个链表是否有环; //太强大了,真是聪明啊通过快慢指针的方式来进行操作,一个指针走两步,一个指针走一步,看有没有相交 //凡是能走到终点就是false if(head==NULL){ return false; } if(head->next==head){ return true; } if(head->next==NULL){ return false; } ListNode* fast=head->next; ListNode* slow=head; while(fast&&fast->next!=NULL){ if(slow==fast){ return true; } slow=slow->next; fast=fast->next->next; } return false; }
leetcode142:判断链表中环的入口:
思路:首先是判断链表是否有环,如果有环,得到环的长度(根据慢指针的步数来判断),然后再利用两个指针,第一个指针先走k步(k为链表中环的长度);代码如下:
ListNode *detectCycle(ListNode *head) { //检测环的入口,首先要判断是否有环; if(hashCircle(head)){ //首先得到环的长度,走了多少步相交 就是多少长度的环 ListNode* fast=head->next; ListNode* slow=head; int cnt=0; while(fast!=slow){ fast=fast->next->next; slow=slow->next; cnt++; } ListNode* first=head; ListNode* second=head; for(int i=0;i<cnt+1;i++){ first=first->next; } //然后让first指针首先前进cnt+1步,然后再和后指针 一步一步的前进直到相交(画图分析一下就行) while(first!=second){ first=first->next; second=second->next; } return first; } else{ return NULL; } } bool hashCircle(ListNode* head){ if(head==NULL){ return false; } if(head->next==NULL){ return false; } ListNode* slow=head; ListNode* fast=head->next; while(fast!=NULL&&fast->next!=NULL){ if(slow==fast){ return true; } else{ slow=slow->next; fast=fast->next->next; } } return false; }