给定单链表的头节点
head
,请反转链表,并返回反转后的链表的头节点。示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2:
输入:head = [1,2] 输出:[2,1]示例 3:
输入:head = [] 输出:[]提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
反转链表是一道考察对基础数据结构操作的一道非常好的题目,所以学会这道题真的至关重要哦~
在进行反转链表的操作时如果再定义一个新的链表实现会对内存空间产生极大的浪费,其实我们只需要改变链表next指针的指向就可以实现反转功能了(注:下图摘自代码随想录)
首先定义一个cur指针指向头结点,然后我们再定义一个pre指针指向cur结点的前一个位置,方便cur结点改向。观察反转后的链表可知,我们应该将pre初始化为NULL
接下来判断循环条件:当cur指针指向尾结点时,我们仍需对尾结点进行改向操作,所以得出结论,我们需要在cur指向NULL时停止循环操作
当我们将结点1进行反向操作之后,我们需要继续移动cur指针和pre指针,那么问题来了此时我们移动cur指针时(如下图),目标结点2的地址已经获取不到了,因为此时没有任何指针指向结点2 ,所以我们应该在对结点1进行反向操作之前,预先保存结点2的地址
下面还需要思考一个问题,就是cur指针和pre指针的移动顺序问题,其实正确答案是先移动pre指针后移动cur指针,因为如果我们先移动cur指针的话,cur=temp,此时cur的值已经改了,所以pre无法移动到当初cur的位置
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode *pre,*cur,*temp;
cur=head;
pre=NULL;
while(cur!=NULL)
{
temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]示例 2:
输入:l1 = [], l2 = [] 输出:[]示例 3:
输入:l1 = [], l2 = [0] 输出:[0]提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
这道题必须强推递归方法,其实递归方法在一定程度上还挺能简化代码和思考量的
思路就是直接用mergeTwoLists当作递归函数:
·递归边界:如果其中一个链表为空,直接返回另一个链表作为合并后的结果
·如果两个链表都不为空,则比较两个链表当前结点的值,并选择较小的结点作为新链表的当前结点(因为题目明确要求需要新链表严格升序排列)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if(list1==NULL) return list2;
if(list2==NULL) return list1;
if(list1->valval)
{
list1->next=mergeTwoLists(list1->next,list2);
return list1;
}else{
list2->next=mergeTwoLists(list1,list2->next);
return list2;
}
}
链表章节到此就结束了,新关注的友友们可以移步主页查看我的往期作品哦~