刷题的一天——递归

本文探讨了如何通过递归和迭代方式合并两个升序链表,并实现单链表的反转操作。递归方法的时间复杂度为O(n+m),空间复杂度O(m+n);迭代方法则空间复杂度为O(1)。同时介绍了两种反转链表的算法,包括迭代和递归,以及它们的时间复杂度和空间占用。
摘要由CSDN通过智能技术生成

1、将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例:输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]

这个题目本来想着重新设置一个链表然后挨个对比两个链表的元素大小完成。但是要求了在两个链表基础上组成,所以这种方法就不可行。因此可以选择用递归的方法,在原有基础上完成。

代码:

(1)递归

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1,ListNode* list2) {               //设置mergeTwoLists,进行下一步递归
    if(list1==nullptr){
        return list2;
    }else if(list2 ==nullptr){ 
        return list1;
    }else if(list1->val < list2 ->val){                                         //在list上进行递归
        list1->next = mergeTwoLists(list1->next,list2);
        return list1;
    }else{
        list2->next = mergeTwoLists(list1,list2->next);
        return list2;
    }
    }
};

这个由于是利用递归,时间复杂度为O(n+m),即两个数组的元素数量,空间复杂度O(m+n),没有耗费多余空间,但在递归调用函数的时候用到了多余的栈空间(递归需要叠加栈)。

(2)迭代:即利用一个新开辟的头节点和指针来找出顺序值。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1,ListNode* list2) {           
    ListNode*prehead = new ListNode(-1);
    ListNode*prev = prehead;
    while(list1 !=nullptr && list2!=nullptr){
    if(list1->val < list2->val){
        prev->next = list1;                                //prev指针指向下一个list1,因为list1较小
        list1 = list1->next;                                //list1的指针在顺序链表上位移
    }else{
        prev->next = list2;
        list2 = list2->next;
    }
    prev = prev->next;                                      //移动prev指针
    }
    prev->next =list1== nullptr? list2:list1;                 //这一句不是太理解
    return prehead->next;                                    //输出prehead之后的链表
    }
};

主要就是最后依据把没有加入的链表元素加入的操作有点不懂,大概时间复杂度野味O(m+n),需要遍历。空间复杂度为O(1),没有使用多余空间。

2、给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例:输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]

这个是一个典型的链表题,可以多设置几个节点进行数值存储然后利用指针来得到反转的链表。

(1)迭代:这里之所以输出prev是因为有判定条件cur,这时候cur应当为空,所以输出prev。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
    ListNode*prev = nullptr;
    ListNode*cur = head;
    while(cur){
        ListNode*next = cur->next;                        //设置一个next存储cur下一个节点的数值
        cur->next = prev;                                 //cur指向prev
        prev = cur;                                       //prev节点的数值等于cur
        cur = next;                                       //cur的数值等于next
    }
    return prev;
    }
};

时间复杂度O(m),空间复杂度为O(1)。

(2)递归

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
    if( !head||!head->next){          //这一步代表head已经到了头,或者本身就一个节点,可以输出了
        return head;
    } 
    ListNode*ans =reverseList(head->next);
    head->next->next = head;                       //构建反向指针
    head->next = nullptr;                           //释放原有方向指针
    return ans;
    }
};

引用本身实现递归,时间复杂度O(m),由于递归调用栈空间,所以空间复杂度为O(m)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值