【剑指每日一题】合并递增链表为单调不减链表

一、写在前面

最近在练习编程题目,每天写一道以上剑指编程题。加油,坚持就是胜利!

二、题目一

1 题目描述

这是剑指上的一个链表题目。
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

2 解题思路

这道题有两种思路,一种是递归方式解决,这个方式的代码较为简单,但是时间复杂度会比较高,另一种是非递归方式解决。递归方式不讲,大体讲一下非递归方式的思路。
非递归方式的流程:首先通过比较pHead1和pHead2两个结点的值,来确定新链表的表头head,将表尾tail也指向表头head。之后通过一个while循环,每次通过比较pHead1和pHead2两个结点的值来构建新链表,直到pHead1或者pHead2全部遍历完,循环结束。由于此时pHead1和pHead2两个链表中还有一个没有遍历完(不是NULL),所以还需要把pHead1或者是pHead2剩余的链表链接到tail后面。最后return表头也就是head。

3 通过的代码

(1)递归代码

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1==NULL)
            return pHead2;
        if(pHead2==NULL)
            return pHead1;
        ListNode* Head=NULL;
        if(pHead1->val>pHead2->val)
        {
            Head=pHead2;
            Head->next=Merge(pHead2->next,pHead1);
        }
        else
        {
            Head=pHead1;
            Head->next=Merge(pHead1->next,pHead2);
        }
        return Head;
    }
};

(2)非递归代码

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        ListNode* head;//表头
	    ListNode* tail;//表尾
	    if(pHead2==NULL)
	    return pHead1;//如果pHead2是空链表,直接返回pHead1。
	    else if(pHead1==NULL)
	    return pHead2;//这里和上面一个意思
        if(pHead1->val<=pHead2->val)
        {
            head=pHead1;
            pHead1=pHead1->next;
        }//这里是为了构建好新链表的表头head,也就是以pHead1和pHead2中较小的结点作为新链表表头head
        else
        {
            head=pHead2;
            pHead2=pHead2->next;
        }//这里和上面一个意思
        tail=head;//此时将tail表尾指向head表头
        while(pHead1&&pHead2)//while循环是主体部分,构建新链表。
        {
            if(pHead1->val<=pHead2->val)
            {
                tail->next=pHead1;//tail一直是表尾,这里用的是尾插法,将pHead1插到tail后面
                pHead1=pHead1->next;
            }
            else
            {
                tail->next=pHead2;
                pHead2=pHead2->next;
            }
            tail=tail->next;//由于tail一直指向表尾,所以这里tail指向tail->next。
        }
        if(pHead2)
        {
            tail->next=pHead2;
        }//由于pHead1或者pHead2可能还没有全部构建到新链表中,这里需要把剩余部分挂到新链表后面。
        else if(pHead1)
        {
            tail->next=pHead1;
        }//和上面一个意思
        return head;
    }
};

题目二

1 题目描述

这是小红书2019年校园招聘技术类在线笔试题目。
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。
说明:

  1. 你需要自行定义链表结构,将输入的数据保存到你的链表中;
  2. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换;
  3. 你的算法只能使用常数的额外空间。
    输入描述:
    第一行输入是链表的值
    第二行输入是K的值,K是大于或等于1的整数

输入形式为:
1 2 3 4 5
2
输出描述:
当 k = 2 时,应当输出:
2 1 4 3 5

当 k = 3 时,应当输出:
3 2 1 4 5

当k=6时,应当输出:
1 2 3 4 5
在这里插入图片描述

2 解题思路

可以采用递归的思想,每次对K个结点进行反转,并且返回K个结点反转后的头结点。
下面描述了一下在k=3的条件下,reverse(ListNode *head,int k)函数在一次递归的结点变化过程。可以看到,在k=3的条件下,前面3个结点最后顺序被反转。

在这里插入图片描述

3 通过的代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>input;
struct ListNode{
    int val;
    ListNode *next;
};
ListNode* Create()
{
    ListNode *head=new ListNode;
    head->val=input[0];
    head->next=NULL;
    ListNode *tail=head;
    for(int i=1;i<input.size();i++)
    {
        ListNode *node=new ListNode;
        node->val=input[i];
        node->next=NULL;
        tail->next=node;
        tail=tail->next;
    }
    return head;
}
ListNode *reverse(ListNode *head,int k)
{
	if(k==1||!head)
	   return head;
	ListNode *pre=head;
	ListNode *tail=head;
	ListNode *q;
	ListNode *p;
	for(int i=1;i<k;i++)
	{
		if(!(tail->next))
		{
			return head;
		}
		tail=tail->next;
	}
	p=pre;
	while(p->next!=tail)
	{
		q=p->next;
		p->next=p->next->next;
		q->next=pre;
		pre=q;
	}
	p->next=reverse(tail->next,k);
	tail->next=pre;
	return tail;
}
void print(ListNode *head)
{
	while(head!=NULL)
	{
		cout<<head->val<<" ";
		head=head->next;
	}
	cout<<endl;
}
int main()
{
    int value;
    int K;
    int num;
    while(cin>>value)
    {
    	input.push_back(value);
    	if(cin.get()=='\n')
    	break;
    }
    num=input.size();
    ListNode *head=Create();
    cin>>K;
    ListNode *newHead=reverse(head,K);
    print(newHead);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值