链表-交换节点、旋转、反转、相交

51 阅读3分钟

链表

两两交换链表中的节点

leetcode.24

/**
 * 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* swapPairs(ListNode* head) {
        auto dummy = new ListNode(-1);
        dummy->next = head;
        for (auto p = dummy; p->next && p->next->next;){
            auto a = p->next, b = a->next;
            p->next = b;
            a->next = b->next;
            b->next = a;
            p = a;
        }
        return dummy->next;
    }
};

旋转链表

leetcode.61

/**
 * 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* rotateRight(ListNode* head, int k) {
        if (!head) return head;
        int n = 0;
        for (auto p = head; p; p = p->next) n ++;
        k %= n;
        if (k == 0) return head;

        auto p = head;
        for (int i = 0; i < n - k - 1; i ++) p = p->next;// 找到倒数第k+1个点
        
        auto tail = head;
        while (tail->next) tail = tail->next;// 找到尾节点

        tail->next = head;// 尾节点指向旧的头节点
        head = p->next;// 新的头节点
        p->next = nullptr;// 新的尾节点指向空
        return head;
    }
};

反转链表

leetcode.206

/**
 * 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* reverseList(ListNode* head) {
        if (!head || !head->next) return head;
        auto a = head, b = head->next;
        while (b){
            auto c = b->next;
            b->next = a;
            a = b;
            b = c;
        }
        head->next = nullptr;
        return a;
    }
};
  • 解题方法:递归,递归的返回值为新头节点
  • leetcode解题代码
/**
 * 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* reverseList(ListNode* head) {
        if (!head || !head->next) return head;
        auto p = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return p;
    }
};

leetcode.92

/**
 * 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* reverseBetween(ListNode* head, int m, int n) {
        auto dummy = new ListNode(-1);
        dummy->next = head;
        auto p = dummy;
        for (int i = 0; i < m - 1; i ++) p = p->next;// 找到第m-1个节点

        // 将[m, n]反转与上一题迭代法相似
        auto a = p->next, b = a->next;
        for (int i = 0; i < n - m; i ++){
            auto c = b->next;
            b->next = a;
            a = b;
            b = c;
        }
        
        p->next->next = b;
        p->next = a;
        return dummy->next;
    }
};

相交链表、环形链表

leetcode.160

  • 链接leetcode.cn/problems/in…
  • 解题方法:双指针+找规律
    A段+B段+重合段的总长度相等
    一个指针从A段向前遍历当遍历到结尾跳到B段开头
    另一个指针从B段向前遍历当遍历到结尾跳到A段开头
    由于两个指针走过的路程相等,移动速度也相等,所以必然在相交点相遇
  • leetcode解题代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        auto p = headA, q = headB;
        while (p != q){
            if (p) p = p->next;
            else p = headB;
            if (q) q = q->next;
            else q = headA;
        }
        return p;
    }
};

leetcode.141

  • 链接leetcode.cn/problems/li…
  • 解题方法:快慢指针
    一个指针每次向前移动一位,另一个指针每次向前移动两位
    如果链表不存在环则两个指针永远不可能相遇
  • leetcode解题代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (!head || !head->next) return false;
        auto fast = head, slow = head;
        while (fast){
            fast = fast->next, slow = slow->next;
            if (fast){
                fast = fast->next;
            }
            if (fast == slow) return true;    
        }
        return false;
    }
};

leetcode.142

  • 链接leetcode.cn/problems/li…
  • 解题方法:快慢指针+找规律
    当两个指针相遇的时候,将一个指针指向头节点,另一个指针留在原地
    令两个指针的移动速度相等,则再次相遇的位置就是环形入口
  • leetcode解题代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (!head || !head->next) return NULL;
        auto s = head, f = head;
        while (f){
            s = s->next, f = f->next;
            if (f) f = f->next;
            if (s == f){
                s = head;
                while (s != f){
                    s = s->next, f = f->next;
                }
                return s;
            }
        }
        return NULL;
    }
};

解题参考:www.acwing.com/