C++反转链表

dhttps://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca

正规解法(反转链表,通过调整链表指针达到反转链表)

时间复杂度:O(n), 遍历一次链表
空间复杂度:O(1)

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {    
        ListNode *pre = nullptr;
        ListNode *cur = pHead;
        ListNode *nex = pHead;
        while(cur != nullptr){
            nex = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nex;
        }
        return pre; // 返回反转后的链表的头结点
    }
};

利用vector构造链表

先用一个vector将单链表的指针都存起来,然后再构造链表。
时间复杂度:O(n)
空间复杂度:O(n), 因为用了一个vector来存单链表

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if (!pHead) return nullptr;
        vector<ListNode*> v;
        while(pHead){
            v.push_back(pHead);
            pHead = pHead->next;
        }
        reverse(v.begin(),v.end()); // 反转vector
        // 构造链表,以head为头结点。cur为head的复制结点,作为当前结点,用于构建链表。
        ListNode *head = v[0];
        ListNode *cur = head;
        for(int i=0; i<v.size(); i++){
            cur->next = v[i]; // 当前(cur)节点的下一个指针指向下一个节点
            cur = cur->next;  // 当前(cur)节点后移
        }
        cur->next = nullptr;  // 切记最后一个节点的下一个指针指向nullptr
        return head; // 返回反转后的链表的头结点
    }
};

递归

时间复杂度:O(n),其中 n是链表的长度。需要对链表的每个节点进行反转操作。

空间复杂度:O(n),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead==nullptr || pHead->next==nullptr )
            return pHead;
        
        ListNode *reverseListHead = ReverseList(pHead->next);
        pHead->next->next = pHead;
        pHead->next = nullptr;
        return reverseListHead; // 返回反转后的链表的头结点
    }
};

这里递归不好理解,下面是详细的:
https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode-solution-d1k2/

    /**
     * 以链表1->2->3->4->5举例
     */
    public ListNode reverseList(ListNode* head) {
        if (head == null || head.next == null) {
            /*
                直到当前节点的下一个节点为空时返回当前节点
                由于5没有下一个节点了,所以此处返回节点5
             */
            return head; /* 第一轮(最上层)出栈:传入的head为5,由于head.next为空,于是返回该节点5, reverseListHead接收该结点5 */           
        }
        //递归,一直递归到链表的最后一个结点,该结点就是反转后的头结点reverseListHead,即节点5。
        ListNode *reverseListHead  = reverseList(head.next); // 递归入栈,共5层栈。
                /*
            继上面的第一轮出栈后,此时head为4,于是
            第二轮(第二层)出栈,head为4,head.next为5,执行head.next.next=head也就是5.next=4,
                      把当前节点的子节点的子节点指向当前节点
                      此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
                      此时链表为1->2->3->4<-5
                      返回节点5
            第三轮(第三层)出栈,head为3,head.next为4,执行head.next.next=head也就是4.next=3,
                      此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
                      此时链表为1->2->3<-4<-5
                      返回节点5
            第四轮出栈,head为2,head.next为3,执行head.next.next=head也就是3.next=2,
                      此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
                      此时链表为1->2<-3<-4<-5
                      返回节点5
            第五轮出栈,head为1,head.next为2,执行head.next.next=head也就是2.next=1,
                      此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
                      此时链表为1<-2<-3<-4<-5
                      返回节点5
            出栈完成,最终头节点5->4->3->2->1
         */
        head.next.next = head;
        head.next = null;
        return reverseListHead; // 返回反转后的链表的头结点
    }
    /**
     * 以链表1->2->3->4->5举例
     */
    public ListNode reverseList(ListNode* head) {
        if (head == null || head.next == null) {
            /*
                递归的“递”过程的终止条件。从 'return head;' 开始,“归”已经开始了。
                “递”到最后,到达结点5,由于结点5没有下一个节点了(即5.next==null),所以此处返回节点5,即“归”5,由reverseListHead接收节点5。
             */
            return head;
        }
        //递归,一直递归到链表的最后一个结点,该结点就是反转后的头结点reverseListHead,即节点5。
        ListNode *reverseListHead  = reverseList(head.next);
                /*
            第一轮出栈,head为5,head.next为空,返回节点5
            第二轮出栈,head为4,head.next为5,执行head.next.next=head也就是5.next=4,
                      把当前节点的子节点的子节点指向当前节点
                      此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
                      此时链表为1->2->3->4<-5
                      返回节点5
            第三轮出栈,head为3,head.next为4,执行head.next.next=head也就是4.next=3,
                      此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
                      此时链表为1->2->3<-4<-5
                      返回节点5
            第四轮出栈,head为2,head.next为3,执行head.next.next=head也就是3.next=2,
                      此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
                      此时链表为1->2<-3<-4<-5
                      返回节点5
            第五轮出栈,head为1,head.next为2,执行head.next.next=head也就是2.next=1,
                      此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
                      此时链表为1<-2<-3<-4<-5
                      返回节点5
            出栈完成,最终头节点5->4->3->2->1
         */
        head.next.next = head;
        head.next = null;
        return reverseListHead; // 返回反转后的链表的头结点
    }

你可能感兴趣的:(剑指offer,链表,c++,算法)