leetcode初级链表之反转链表,包括整个链表和m/n位置的链表

反转整个链表

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
首先使用迭代的方法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head) {

    struct ListNode *prev, *cur, *next;
    prev = NULL;
    cur = head;
    while(cur){
        next = cur->next;
        cur->next = prev;
        prev = cur;
        cur = next;
    }
    return prev;

}

然后使用递归的方法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head) {
if( head == NULL || head->next == NULL )
        return head;
    struct ListNode* temp = reverseList(head->next);
    head -> next -> next = head;
    head -> next =  NULL;
    return temp;
}

反转链表中m、n位置的链表

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
方法1:从前往后扫描链表,用pre指针指向当前元素的前一个元素,每次将当前元素的next指针指向pre,扫描至最后即可完成整个链表的反转。时间复杂度为O(n),空间复杂度为O(1)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseBetween(struct ListNode* head, int m, int n) {

    if(head == NULL || head->next == NULL || m==n) return head; //排除掉极限情况
    struct ListNode *left = head, *right = NULL;                //分别定义两个指针指向m节点的前节点和n节点地后节点
    struct ListNode *temp = head;
    struct ListNode *nh = (struct ListNode *)malloc(sizeof(struct ListNode));//定义虚拟新头结点newhead
    struct ListNode *prev = nh, *cur = head, *next;     //分别指向前一个节点,当前节点(current)和下一个节点
    nh->next = head;                                               
    int pos = 1;                                        //pos跟踪cur的位置
    while(cur){
        if(pos <= m || pos > n){
            if(pos == m){                       //首先找到m处的节点,left指向m-1处地节点,保存m节点
                temp = cur;
                left = prev;
            }
            cur = cur->next;
            pos++;
            prev = prev->next;
        }else{                                  //然后遍历m-n,反转m-n的节点
            if(pos == n){                       //找到n节点,n+1用right指向,然后组成新的链表
                right = cur->next;
                left->next = cur;
                temp->next = right;
                nh->next = cur;                //对于m=1的情况,保存新的头节点
            }           
            next = cur->next;
            cur->next = prev;
            prev = cur;
            cur = next;  
            pos++;
        }
    }
    if(1 == m){
        return nh->next;
    }
    return head;
}

方法2:插入法【特别巧妙】。例如,我们要反转1->2->3->4->5的位于[2,4]之间的元素,我们可以依次将3和4向前插入,插入3之后变为1->3->2->4->5,再插入4变为1->4->3->2->5。

 /**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseBetween(struct ListNode* head, int m, int n) {

    if(head == NULL || head->next == NULL || m==n) return head; //排除掉极限情况
    struct ListNode *left = head, *right = NULL;                //分别定义两个指针指向m节点的前节点和n节点地后节点
    struct ListNode *nh = (struct ListNode *)malloc(sizeof(struct ListNode));                                 //定义一个虚拟的新的头节点newhead
    struct ListNode *prev = nh, *cur = head, *next;             //prev,cur, next分别指向前一个节点,当前节点和下一个节点
    int pos = 1;                                                //pos跟踪cur的位置
    nh->next = head;                                            //新的链表
    while(cur && pos < m){
        prev = prev->next;
        cur = cur->next;
        pos++;
    }
    left = prev;
    int i = n-m;
    while(i--){
        next = cur->next;
        cur->next = next->next;
        next->next = left->next;
        left->next = next;    
    }
    return nh->next;

}

猜你喜欢

转载自blog.csdn.net/u010132497/article/details/81739405