牛客网 链表问题 C++实现 刷题汇总

 

11:两个单链表相交的一系列问题

/*
 * struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};*/
class Solution {
public:
    //获取两链表的相交节点
    ListNode* getIntersectNode(ListNode *head1,ListNode *head2){
        if(head1==NULL||head2==NULL)
            return NULL;
        ListNode *loop1=getLoopNode(head1);
        ListNode *loop2=getLoopNode(head2);
        if(loop1==NULL&&loop2==NULL)//返回两个无环链表的相交节点
            return noLoop(head1,head2);
        if(loop1!=NULL&&loop2!=NULL)//两个有环链表的相交节点
            return bothLoop(head1,loop1,head2,loop2);
        return NULL;//其他情况链表不可能相交

    }
    //判断链表有无环,有则返回第一个进入环的节点
    ListNode* getLoopNode(ListNode *head){
        if(!head||!head->next||!head->next->next)
            return NULL;
        ListNode *slow=head->next;
        ListNode *fast=head->next->next;
        while (slow!=fast){
            if(fast->next==NULL||fast->next->next==NULL)
                return NULL;
            slow=slow->next;
            fast=fast->next->next;
        }
        fast=head;//fast重新指向head
        while (slow!=fast){
            slow=slow->next;
            fast=fast->next;
        }
        return slow;

    }
    //判定两个无环链表是否相交,相交则返回第一个相交顶点
    ListNode* noLoop(ListNode *head1,ListNode *head2){
        if(!head1||!head2)return NULL;
        ListNode *cur1=head1;
        ListNode *cur2=head2;
        int n=0;//计数
        while (cur1->next!=NULL){
            n++;
            cur1=cur1->next;
        }
        while (cur2->next!=NULL){
            n--;
            cur2=cur2->next;
        }
        if(cur1!=cur2)
            return NULL;//end1!=end2,说明两个链表不相交,直接返回NULL
        cur1=n>0?head1:head2;//n>0说明第一条链表长
        cur2=cur1==head1?head2:head1;
        n=n>0?n:-n;
        while (n!=0){
            n--;//长链表先走
            cur1=cur1->next;
        }
        while (cur1!=cur2){
            cur1=cur1->next;
            cur2=cur2->next;
        }
        return cur1;

    }
    //判断两个有环链表是否相交,相交则返回一个相交节点
    ListNode* bothLoop(ListNode *head1,ListNode *loop1,ListNode *head2,ListNode *loop2){
        ListNode *cur1=loop1;
        ListNode *cur2=loop2;
        if(cur1==cur2){
            // 链表类似  -O
          cur1=head1;
          cur2=head2;
          int n=0;
          while (cur1!=loop1){//计算到入环节点的距离
              n++;
              cur1=cur1->next;
          }
          while (cur2!=loop2){
              n--;
              cur2=cur2->next;
          }
          cur1=n>0?head1:head2;
          cur2=cur1==head1?head2:head1;
          n=n>0?n:-n;
          while (n!=0){//长的先走
              n--;
              cur1=cur1->next;
          }
          while (cur1!=cur2){
              cur1=cur1->next;
              cur2=cur2->next;
          }
          return cur1;

        }
        else{
            cur1=loop1->next;
            while (cur1!=loop1){
                if(cur1==loop2)
                    return cur1;
                cur1=cur1->next;
            }
            return NULL;

        }

    }
};

 

12:将单链表的每K个节点之间逆序

class Solution{
public:
   //利用栈结构解法
   ListNode* reverseKNode1(ListNode *head,int k){
       if(k<2)return head;
       stack<ListNode*>stack;
       ListNode *newHead=head,*cur=head;
       ListNode *pre=NULL;
       ListNode *temp=NULL;
       while (cur!=NULL){
           temp=cur->next;
           stack.push(cur);
           if(stack.size()==k){
               pre=resign1(stack,pre,temp);//一段的结尾,也是下一段的前驱
               newHead=newHead==head?cur:newHead;
           }
           cur=temp;
       }
       return newHead;
   }
   //第一种方法辅助函数,实现元素逆序
   ListNode* resign1(stack<ListNode*>&stack,ListNode *left,ListNode *right){
       ListNode *cur=stack.top();
       stack.pop();
       if(left!=NULL)//与左边已经逆过序的相连
           left->next=cur;
       ListNode *temp=NULL;
       while (!stack.empty()){//弹出栈实现逆向连接
           temp=stack.top();
           stack.pop();
           cur->next=temp;
           cur=temp;
       }
       cur->next=right;//与右边下一段相连
       return cur;
   }
    //不利用栈结构,在原链表中直接调整
   ListNode* reverseKNode2(ListNode *head,int k){
       if(k<2)return head;
       ListNode *cur=head;
       ListNode *start,*pre,*temp;
       int count=1;
       while (cur!=NULL){
           temp=cur->next;
           if(count==k){
               start=pre==NULL?head:pre->next;
               head=pre==NULL?cur:head;
               resign2(pre,start,cur,temp);
               pre=start;
               count=0;
           }
           count++;
           cur=temp;
       }
       return head;
   }

    //变量记录每组的开始和结束节点,以及上组最后一个节点left,下一组开始节点right
    void resign2(ListNode *left,ListNode *start,ListNode *end,ListNode *right){
       ListNode *pre=start;
       ListNode *cur=start->next;
       ListNode *temp=NULL;
       while (cur!=right){//逆序
           temp=cur->next;
           cur->next=pre;
           pre=cur;
           cur=temp;
       }
       if(left!=NULL)//连接前后两段
           left->next=end;
       start->next=right;
    }

};

13:删除链表中重复出现的节点

class Solution{
public:
    //第一种方法,利用hash表,时间复杂度和空间复杂度均为O(n)
    ListNode* removeRep1(ListNode *head){
        if(head==NULL)
            return;
        set<int>set;
        ListNode *pre=head;
        ListNode *cur=head->next;
        set.emplace(head->val);//head是肯定保留的
        while (cur!=NULL){
            //集合中已经存在,直接跳过
            if(set.count(cur->val)==1)
                pre->next=cur->next;
            else{
                //添加到集合中
                set.emplace(cur->val);
                pre=cur;
            }
             cur=cur->next;
        }
        return head;

    }

    //类似选择排序,时间复杂度O(n**2),空间复杂度O(1)
    ListNode* removeRep2(ListNode *head){
        ListNode *cur=head;
        ListNode *pre=NULL;
        ListNode *temp=NULL;
        while (cur!=NULL){//外层循坏
            pre=cur;
            temp=cur->next;
            while (temp!=NULL){//内层循环
                if(cur->val==temp->val)
                    pre->next=temp->next;
                else
                    pre=temp;
                temp=temp->next;//遍历
            }
            cur=cur->next;
        }
        return head;

    }

};

 

14:在单链表中删除指定值的节点

class Solution{
public:
    //在链表中删除指定值的节点,利用栈
    //时间与空间复杂度都是O(n)
    ListNode* removeValue1(ListNode *head,int num){
        stack<ListNode*>stack;
        while (head!=NULL){
            if(head->val!=num)//值不等则压入栈
                stack.push(head);
            head=head->next;
        }
        //上述while结束后Head为NULL
        while (!stack.empty()){
            ListNode *node=stack.top();
            stack.pop();
            node->next=head;
            head=node;
        }
        return head;
    }

    //第二种方法直接删除
    ListNode* removeValue2(ListNode *head,int num){
        if(head==NULL)return NULL;
        while (head!=NULL){
            if(head->val!=num)
                break;
            head=head->next;//得到newHead
        }
        ListNode *pre=head;
        ListNode *cur=head->next;
        while (cur!=NULL){
            if(cur->val==num)
                pre->next=cur->next;
            else
                pre=cur;
            cur=cur->next;
        }
        return head;
    }
};

 

15:将搜索二叉树转化成双向链表

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值