【C++】面试101,反转链表及变式,合并链表及变式

1.反转链表

  • 普通方法
#include <cstddef>
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
   ListNode *cur=pHead; //当前指针
   ListNode * tail=nullptr;  //尾指针
ListNode* tmp; //保存指向,防止找不到
while(cur) //一直遍历到链表尾
{  
	tmp=cur->next;  //首先保存下一个位置的指向
	cur->next=tail; //反转
	tail=cur; //tail往后走
	cur=tmp; //cur向后走,不能先写tail=cur要不然cur就丢了

}
	return tail;  
    }
};
  • 递归
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
if(!pHead||!pHead->next) return pHead;  //如果节点为空或者next为空 此时的返回值是最后一个节点
ListNode* tail=ReverseList(pHead->next);//tail接收最后一个节点,也就是结果链表的第一个节点
//pHead->next->next=pHead; //pHead->next是尾节点,把当前节点pHead挂到尾节点的后面
//pHead->next=nullptr; //当前节点指向置空
//return tail; //返回反转链表的第一个节点
pHead->next->next=pHead;
pHead->next=nullptr;
return tail;
};
};

在第一次归的时候,pHead->next 和 tail是相同的,都是结果链表的头结点,也是反转链表的第一个节点,那么为什么不写成tail->next =pHead 因为tail始终都是结果链表最后一个节点,所以他的next永远都是结果链表第二个节点,写成这样就直接永远输出两个节点

但是写成pHead->next->next,由于pHead在改变,才能正确连接

2. 指定区间的翻转

不知道这个题难度怎么样,我写了很久,最后总结了别人的代码写出我的理解

  •  头插入

翻转区间是m=2,n=4,

把cur移动到第二个节点(也就是m位置),同时保存cur前一个节点pre

每次头插的是cur->next 

1 2 3 4 5(cur->next=3,把3头插到3 2 4的最前面,其余顺移) ——> 1 3 2 4 5(cur->next=4) ——> 1 4 3 2 5

  注意:万一m=1,那么pre需要一个哨兵位安放

 ListNode* reverseBetween(ListNode* head, int m, int n) {
       ListNode* res=new ListNode(-1);  //设置哨兵位,防止pre越界
       res->next=head;  //哨兵位和链表连上
       ListNode* pre=res; 
       ListNode*cur=head;
       for(int i=1;i<m;i++)
       {
        pre=cur;
        cur=cur->next;
       }                    //cur在m个节点上,pre是他前一个节点
       for(int i=m;i<n;i++)  //头插迭代,看文字说明
       {
        ListNode*tmp=cur->next;
        cur->next=tmp->next;
        tmp->next=pre->next;
        pre->next=tmp;
       }
       return res->next;
    }
};

3.k个一组反转链表

其实k个一组是不是也是指定区间的反转!!!!!

class Solution {
public:
    /**
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
     ListNode* reserve(ListNode* head,int m,int n)  //m-n区间反转
     {
        ListNode* res=new ListNode(-1);
        res->next=head;
        ListNode* cur=head;
        ListNode* pre=res;
        for(int i=1;i<m;i++)
        {
            pre=cur;
            cur=cur->next;
        }
        for(int i=m;i<n;i++)
        {
            ListNode*tmp=cur->next;
            cur->next=tmp->next;
            tmp->next=pre->next;
            pre->next=tmp;
        }
        return res->next;
     }
    ListNode* reverseKGroup(ListNode* head, int k) {  
        // write code here
        if(!head) return head; //空直接返回
        
        int m=1,n=k;
ListNode* cur=head;
int size=0;  //计算节点个数
        while(cur)
        {
            cur=cur->next;
            size++;
        } 
        if(k>size) return head;  //k比节点总数多直接不反转
         head= reserve(head,m,n); //肯定反转一次
        
        m+=k;
        n+=k;
        while(n<=size) //迭代
        {
           head= reserve(head,m,n);
            m+=k;n+=k;
        }
        return head;
    }
};

4.合并有序链表

直接默写没什么好说的

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        ListNode* cur1=pHead1;
		ListNode*cur2=pHead2;
		ListNode* newhead=new ListNode(-1);
		ListNode* cur=newhead;
		while(cur1&&cur2)
		{
			ListNode* tmp1=cur1->next;
			ListNode*tmp2=cur2->next;
			if(cur1->val<cur2->val)
			{
				cur->next=cur1;
				cur1=tmp1;
			}
			else 
			{
              cur->next=cur2;
			cur2=tmp2;
			}
			cur=cur->next;
		}
		while(cur1)
		{
            cur->next=cur1;
             cur=cur->next;
			 cur1=cur1->next;
		}
		while(cur2)
		{
			cur->next=cur2;
			cur=cur->next;
			cur2=cur2->next;
		}
		return newhead->next;
    }
};

5.合并k个已排序的链表

感觉看到了之前k个一组反转链表

直接复用

class Solution {
public:
    ListNode* merge(ListNode*head1,ListNode*head2)
    {
         ListNode* newhead=new ListNode(-1);
    ListNode*cur=newhead;
    ListNode*cur1=head1;
    ListNode*cur2=head2;
    while(cur1&&cur2)
    {
         ListNode*tmp1=cur1;
         ListNode* tmp2=cur2;
         if(cur1->val<cur2->val)
         {
            cur->next=cur1;
            cur1=cur1->next;
         }
         else
         {
            cur->next=cur2;
            cur2=cur2->next;
         }
         cur=cur->next;
    }
    while(cur1)
    {
      cur->next=cur1;
      cur1=cur1->next;
      cur=cur->next;
    }
    while(cur2)
    {
        cur->next=cur2;
        cur2=cur2->next;
        cur=cur->next;
    }
    return newhead->next;
    }
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        if(lists.size()==0)return nullptr;   
      ListNode* newhead=lists[0];
     for(int i=1;i<lists.size();i++)
    {
      newhead= merge(newhead,lists[i]);
    }
    return newhead;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值