【题解】反转链表、链表内指定区间反转

文章目录

  • 反转链表
  • 链表内指定区间反转

反转链表

题目链接:反转链表

解题思路1:双指针迭代,改变每个指针的指向,每一步都有三个指针参与变换

代码如下:

    ListNode* ReverseList(ListNode* head) {
        // write code here
        //我们要将指针的指向从前一个指向后一个转变为从后一个指向前一个,所以一定要单独保留的节点
        //就是当前的节点,和当前节点的前一个节点,下一个节点可以不用保存,在使用的时候通过指针
        //改变的先后顺序来得到后一个节点
        //还需要一个节点,指向反转后链表的头节点
 
        ListNode* pReverseHead = nullptr;//定义时即初始化,防止野指针出现
        ListNode* pre = nullptr;
        ListNode* pcur = head;
        while(pcur != nullptr){
            ListNode* pnext = pcur->next;
            if(pnext == nullptr){
                pReverseHead = pcur;
            }
            pcur->next = pre;
            pre = pcur;
            pcur = pnext;
        }
        return pReverseHead;
    }

解题思路2:头插法,每一步调整一个节点到前面,保证pre指针和cur指针不变

代码如下:

    ListNode* ReverseList(ListNode* head) {
        if(head == nullptr){
            return nullptr;
        }
        //头插法
        ListNode* res = new ListNode(-1);
        res->next = head;
        ListNode* pre = res;
        ListNode* cur = res->next;
        while(cur->next != nullptr){
            ListNode* temp = cur->next;
            cur->next = temp->next;
            temp->next = pre->next;
            pre->next = temp;
        }
        return res->next;
    }

解题思路3:递归

当新头节点res指向head或者head->next为空时,递归就结束
每一层递归,都是让当前head的next指向自己,即head->next->next = head,再将head自己的next置为空,达到反转的目的

代码如下:

ListNode* ReverseList(ListNode* head) {
        if(head == nullptr || head->next == nullptr){
            return head;
            //递归结束条件
        }

        ListNode* res = ReverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return res;
    }

解题思路4:利用栈

利用栈先进后出的特性,完成反转,首先将链表中的节点都入栈,再得到栈顶节点,该节点就是最后得到的反转后的链表的头节点,之后再让剩下的节点依次出栈,最后记得将最后的节点置空,防止成环。

代码如下:

    ListNode* ReverseList(ListNode* head) {
        if(head == nullptr){
            return head;
        }
        //让元素入栈,再依次出栈
        stack<ListNode*> st;
        ListNode* phead = head;
        while (phead != nullptr) {
            st.push(phead);
            phead = phead->next;
        }

        ListNode* res = st.top();
        st.pop();
        ListNode* pcur = res;
        while(!st.empty()){
            ListNode* ptemp = st.top();
            st.pop();
            pcur->next = ptemp;
            pcur = pcur->next;
        }
        pcur->next = nullptr;//链表一开始的头结点,其next要置空,否则会和原本的next成环
        return res;
    }

链表内指定区间反转

题目链接:链表内指定区间反转
解题思路1:头插法

将pre节点固定,通过temp指针和cur指针位置的不断移动,将cur的next头插,实现局部链表的反转以及和整个链表的连接

代码如下:

    ListNode* reverseBetween(ListNode* head, int m, int n) {
        //加一个虚拟头结点,保证第一个节点永远不会反转
        ListNode * res = new ListNode(0);
        res->next = head;
        ListNode* pre = res;
        ListNode* cur = head;
        //找到m的位置开始进行反转
        for(int i=1; i<m; ++i){
            pre = cur;
            cur = cur->next;
        }
        //从m反转到n
        for(int i=m; i<n; ++i){
            ListNode* temp = cur->next;
            cur->next = temp->next;
            temp->next = pre->next;            
            pre->next = temp;
        }
        return res->next;
    }

解题思路2:递归

代码如下:

    ListNode* tmp = nullptr;
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if ( m == 1) return reverse(head, n);
        ListNode* p = reverseBetween(head->next, m - 1, n - 1);
        head->next = p;
        return head;
    }
    ListNode* reverse(ListNode* head, int n) {
        if (n == 1) {
            tmp = head->next;
            return head;
        }
        ListNode* new_head = reverse(head->next, n - 1);
        head->next->next = head; //反转
        head->next = tmp;  //拼接尾部
        return new_head;
    }

你可能感兴趣的:(题目练习,链表,算法,数据结构)