(✌)链表——练习题

🤞1. 反转链表

代码实现:

方法一:非递归 + 无虚拟头结点
/**
 * 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 *p = head;
    struct ListNode *pc = NULL;
    head = NULL;
    while (p) {
        pc = p;
        p = p->next;
        pc->next = NULL;
        if (head == NULL) { // 从无到有
            head = pc;
        } else { // 从少到多,头插
            pc->next = head;
            head = pc;
        }
    }
    return head;
}
方法二:非递归 + 虚拟头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode *head) {
    struct ListNode *h = malloc(sizeof(*h));
    h->next = NULL;
    struct ListNode *p = head, *pc = NULL;
    while (p) {
        pc = p;
        p = p->next;
        pc->next = NULL;
        // 头插
        pc->next = h->next;
        h->next = pc;
    }
    return h->next;
}
方法三:递归
/**
 * 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 *tail = head->next;
    struct ListNode *new_head = reverseList(head->next);
    head->next = tail->next;
    tail->next = head;
    return new_head;
}

🤞2. 反转链表 ||

代码实现:

方法一:递归——>难点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseBetween(struct ListNode *head, int left, int right) {
    if (left == 1 && right == 1) {
        return head;
    }
    if (left != 1) {
        head->next = reverseBetween(head->next, left - 1, right - 1);
    } else {
        struct ListNode *tail = head->next;
        struct ListNode *new_head = reverseBetween(head->next, left, right - 1);
        head->next = tail->next;
        tail->next = head;
        head = new_head;
    }
    return head;
}
方法二:反转链表(递归) + 虚拟头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

// 反转链表
void reverse(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return;
    }
    struct ListNode *tail = head->next;
    reverse(head->next);
    head->next = tail->next;
    tail->next = head;
}

struct ListNode* reverseBetween(struct ListNode *head, int left, int right) {
    if (left == right) {
        return head;
    }
    struct ListNode *h = malloc(sizeof(*h)); // 虚拟头节点
    h->next = head;
    struct ListNode *pp = h; // 遍历指针
    struct ListNode *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
    int i = 0;
    while (pp) {
        if (i == left - 1) {
            p1 = pp;
        }
        if (i == left) {
            p2 = pp;
        }
        if (i == right) {
            p3 = pp;
        }
        if (i == right + 1) {
            p4 = pp;
        }
        if (p1 && p2 && p3 && p4) { // 都找到了,跳出循环
            break;
        }
        i++;
        pp = pp->next;
    }
    p3->next = NULL;
    reverse(p2);
    p1->next = p3;
    p2->next = p4;
    return h->next;
}
方法三:非递归 + 虚拟头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

// 反转链表
struct ListNode* reverseList(struct ListNode *head, struct ListNode **tail) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *p = head;
    struct ListNode *pc = NULL;
    *tail = head;
    head = NULL;
    while (p) {
        pc = p;
        p = p->next;
        pc->next = NULL;
        if (head == NULL) {
            head = pc;
        } else { // 头插
            pc->next = head;
            head = pc;
        }
    }
    return head;
}

struct ListNode* reverseBetween(struct ListNode *head, int left, int right) {
    if (left == right) {
        return head;
    }
    struct ListNode *h = malloc(sizeof(*h)); // 虚拟头节点
    h->next = head;
    struct ListNode *pp = h; // 遍历指针
    struct ListNode *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
    int i = 0;
    while (pp) {
        if (i == left - 1) {
            p1 = pp;
        }
        if (i == left) {
            p2 = pp;
        }
        if (i == right) {
            p3 = pp;
        }
        if (i == right + 1) {
            p4 = pp;
        }
        if (p1 && p2 && p3 && p4) { // 都找到了,跳出循环
            break;
        }
        i++;
        pp = pp->next;
    }
    p3->next = NULL;
    p2 = reverseList(p2, &p3);
    p1->next = p2;
    p3->next = p4;
    return h->next;
}

🤞3. 环形链表

代码实现:

快慢指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    // 快慢指针:快指针每次走两步,慢指针每次走一步,二者若重合则链表中有环,否则无环
    struct ListNode *slow = head, *fast = head;
    while (fast && fast->next) {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow) {
            return true;
        }
    }
    return false;
}

🤞4. 两数相加

代码实现:

方法一:逐位相加,模拟进位

设置虚拟头结点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) {
    struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode)); // 虚拟头结点
    struct ListNode *tail = head;
    int carry = 0;
    while (l1 || l2 || carry) {
        int a = l1 ? l1->val : 0;
        int b = l2 ? l2->val : 0;
        int sum = a + b + carry;
        carry = sum / 10;
        // 创建一个新结点
        struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode));
        p->val = sum % 10;
        p->next = NULL;
        // 尾插
        tail->next = p;
        tail = p;
        // 指针往后走
        if (l1) {
            l1 = l1->next;
        }
        if (l2) {
            l2 = l2->next;
        }
    }
    return head->next;
}
方法二:不设置虚拟头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) {
    int flag = 0; // 标志进位
    struct ListNode *h = NULL; // 返回头结点
    struct ListNode *tail = NULL; // 指向尾结点
    while (l1 || l2 || flag) {
        int sum = 0;
        if (l1) {
            sum += l1->val;
            l1 = l1->next;
        }
        if (l2) {
            sum += l2->val;
            l2 = l2->next;
        }
        sum += flag;
        struct ListNode *p = malloc(sizeof(*p));
        p->next = NULL;
        p->val = sum % 10;
        flag = sum / 10; // 进位
        if (h == NULL) { // 从无到有
            h = p;
            tail = p;
        } else { // 从少到多,尾插 
            tail->next = p;
            tail = p;
        }
    }
    return h;
}
方法三:递归
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int c = 0;
struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) {
    if (l1 == NULL && l2 == NULL && c == 0) { // 边界条件
        return NULL;
    }
    if (l1) {
        c += l1->val;
        l1 = l1->next;
    }
    if (l2) {
        c += l2->val;
        l2 = l2->next;
    }
    struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode));
    p->val = c % 10;
    c /= 10;
    p->next = addTwoNumbers(l1, l2);
    return p;
}

🤞5. 两数相加 ||

代码实现:

方法一:反转链表
/**
 * 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 *tail = head->next;
    struct ListNode *new_head = reverseList(head->next);
    head->next = tail->next;
    tail->next = head;
    return new_head;
}

// 两数相加
int c = 0;
struct ListNode* func(struct ListNode *l1, struct ListNode *l2) {
    if (l1 == NULL && l2 == NULL && c == 0) { // 边界条件
        return NULL;
    }
    l1 = l1 != NULL ? (c += l1->val, l1->next) : l1;
    l2 = l2 != NULL ? (c += l2->val, l2->next) : l2;
    struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode));
    p->val = c % 10;
    c /= 10;
    p->next = func(l1, l2);
    return p;
}

struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2){
    if (l1 == NULL || l2 == NULL) {
        return l1 ? l1 : l2;
    }
    // 反转l1
    l1 = reverseList(l1);
    // 反转l2
    l2 = reverseList(l2);
    struct ListNode *p = func(l1, l2); // 两数相加
    // 反转p
    p = reverseList(p);
    return p;
}
方法二:栈
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) {
    int stack1[100];
    int top1 = -1;
    int stack2[100];
    int top2 = -1;
    // l1进栈
    while (l1) {
        stack1[++top1] = l1->val;
        l1 = l1->next;
    }
    // l2进栈
    while (l2) {
        stack2[++top2] = l2->val;
        l2 = l2->next;
    }
    int c = 0;
    struct ListNode *head = malloc(sizeof(*head));
    head->next = NULL;
    while (top1 != -1 || top2 != -1 || c) {
        int a = top1 == -1 ? 0 : stack1[top1--];
        int b = top2 == -1 ? 0 : stack2[top2--];
        int cur = a + b + c;
        c = cur / 10;
        cur %= 10;
        struct ListNode *p = malloc(sizeof(*p));
        p->val = cur;
        // 头插
        p->next = head->next;
        head->next = p;
    }
    return head->next;
}

🤞6. 删除排序链表中的重复元素

代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* deleteDuplicates(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *p = head->next; // 遍历指针
    struct ListNode *pre = head; // 遍历指针的前驱节点
    struct ListNode *pc = NULL;
    while (p) {
        if (pre->val == p->val) {
            pc = p;
            pre->next = p->next;
            p = p->next;
            pc->next = NULL;
            free(pc);
        } else {
            pre = p;
            p = p->next;
        }
    }
    return head;
}

🤞7. 删除排序链表中的重复元素 ||

代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* deleteDuplicates(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *h = malloc(sizeof(*h)); // 创建虚拟头结点
    h->next = head;
    struct ListNode *pre = h;
    struct ListNode *p = head, *p_next = head->next, *pc = NULL;
    while (p_next) {
        if (p->val != p_next->val) {
            pre = p;
            p = p->next;
            p_next = p_next->next;
        } else {
            while (p_next && p->val == p_next->val) {
                p_next = p_next->next;
            }
            pre->next = p_next;
            while (p != p_next) {
                pc = p;
                p = p->next;
                pc->next = NULL;
                free(pc);
            }
            if (p_next) {
                p_next = p_next->next;
            }
        }
    }
    return h->next;
}

🤞8. 奇偶链表

代码实现:

分离节点后合并

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* oddEvenList(struct ListNode *head) {
    if (head == NULL) {
        return head;
    }
    struct ListNode *h = head->next;
    struct ListNode *p1 = head;
    struct ListNode *p2 = head->next;
    while (p2 != NULL && p2->next != NULL) {
        p1->next = p2->next;
        p1 = p1->next;
        p2->next = p1->next;
        p2 = p2->next;
    }
    p1->next = h;
    return head;
}

🤞9. 两两交换链表中的节点

代码实现:

方法一:(设置虚拟头结点) 非递归
struct ListNode* swapPairs(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }

    struct ListNode *h = (struct ListNode*)malloc(sizeof(struct ListNode));
    h->next = head;
    struct ListNode *now = h;
    while (now->next && now->next->next) {
        struct ListNode *l = now->next, *r = now->next->next;
        now->next = r;
        l->next = r->next;
        r->next = l;
        now = l;
    }
    return h->next;
}
方法二:(不设置虚拟头结点) 非递归
struct ListNode* swapPairs(struct ListNode *head) {
    // 若节点小于2个,直接返回
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *first = head;
    struct ListNode *second = head->next;
    // 至少交换一次,返回新头节点指向原head的第二个节点
    struct ListNode *newHead = second;
    struct ListNode *tail = NULL; // 指向每次交换的尾,用于指向以后交换的头

    while (first && second) {
        if (tail == NULL) {
            tail = first;
        } else {
            tail->next = second;
            tail = first;
        }
        first->next = second->next;
        second->next = first;
        first = first->next;
        if (first) {
            second = first->next;
        }
    }
    return newHead;
}
方法三:递归
struct ListNode* swapPairs(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *first = head;
    struct ListNode *second = head->next;
    head = second;
    first->next = second->next;
    second->next = first;
    first->next = swapPairs(first->next);
    return head;
}

🤞10. 删除链表的倒数第N个节点

代码实现:

方法一:双指针法
struct ListNode* removeNthFromEnd(struct ListNode *head, int n) {
    struct ListNode *h = (struct ListNode*)malloc(sizeof(struct ListNode)); // 虚拟头结点
    h->next = head;
    struct ListNode *slow = h, *fast = head;
    while (n--) {
        fast = fast->next;
    }
    while (fast) { // 让慢指针移到倒数第n个结点的前一个结点
        slow = slow->next;
        fast = fast->next;
    }
    struct ListNode *temp = slow->next;
    slow->next = temp->next;
    temp->next = NULL;
    free(temp);
    return h->next;
}
方法二:常规解法
struct ListNode* removeNthFromEnd(struct ListNode *head, int n) {
    struct ListNode *h = malloc(sizeof(*h)); // 虚拟头结点
    h->next = head;
    struct ListNode *p = head; // 遍历指针
    int len = 0; 
    while (p) { // 统计链表结点长度
        p = p->next;
        len++;
    }
    int i = len - n;
    p = h;
    while (i--) {
        p = p->next; // 让p指向倒数第n个结点的前一个结点
    }
    struct ListNode *pc = p->next;
    p->next = pc->next;
    pc->next = NULL;
    free(pc);
    return h->next;
}

🤞11. 环形链表 ||

代码实现:

使用一个数组来存储已经访问过的节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return NULL;
    }
    struct ListNode *slow = head;
    struct ListNode *fast = head;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) {
            break;
        }
    }
    if (slow != fast) {
        return NULL;
    }

    struct ListNode *arr[10000];
    int arrSize = 0;
    arr[arrSize++] = head;
    struct ListNode *p = head->next;
    while (p) {
        for (int i = 0; i < arrSize; i++) {
            if (arr[i] == p) {
               return p;
            }
        }
        arr[arrSize++] = p;
        p = p->next;
    }
    return NULL;
}

🤞12. 相交链表

代码实现:

暴力法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *l1 = headA;
    while (l1) {
        struct ListNode *l2 = headB;
        while (l2) {
            if (l1 == l2) {
                return l1;
            }
            l2 = l2->next;
        }
        l1 = l1->next;
    }
    return NULL;
}

13. 设计链表

代码实现:

🤞14. 从链表中移除节点

代码实现:

方法一:从前往后遍历 —> 超时(时间复杂度:O(n^2)
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeNodes(struct ListNode *head) {
    struct ListNode *h = malloc(sizeof(struct ListNode)); // 虚拟头节点
    h->next = head;
    struct ListNode *p = head; // 遍历指针
    struct ListNode *pre = h; // 遍历指针的前驱节点
    struct ListNode *pp = NULL; // 寻找p右侧是否有比p大的节点
    while (p) {
        pp = p->next;
        while (pp) {
            if (pp->val > p->val) {
                break;
            }
            pp = pp->next;
        }
        if (pp == NULL) { // 没有找到p右侧比p大的节点
            pre = p;
            p = p->next;
        }
        if (pp != NULL) { // 找到了
            // 移除p
            pre->next = p->next;
            p->next = NULL;
            free(p);
            p = pre->next;
        }
    }
    return h->next;
}
方法二:反转链表,如果当前节点值小于前一个节点的值,则移除,最后再反转链表 时间复杂度:O(n)
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* reverse(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *tail = head->next;
    struct ListNode *new_head = reverse(head->next);
    head->next = tail->next;
    tail->next = head;
    return new_head;
}

struct ListNode* removeNodes(struct ListNode *head) {
    // 反转链表
    head = reverse(head);
    struct ListNode *pre = head;
    struct ListNode *p = head->next;
    while (p) {
        if (p->val < pre->val) { // 移除
            pre->next = p->next;
            p->next = NULL;
            free(p);
            p = pre->next;
        } else {
            pre = p;
            p = p->next;
        }
    }
    // 反转链表
    head = reverse(head);
    return head;
}
方法三:递归  时间复杂度:O(n)
  • 该节点为空,那么递归函数返回空指针
  • 该节点不为空,那么先对它的右侧节点进行移除操作,得到一个新的子链表,如果子链表的表头节点值大于该节点的值,那么移除该节点,否则将该节点作为子链表的表头节点,最后返回该子链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeNodes(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    head->next = removeNodes(head->next);
    if (head->next->val > head->val) {
        return head->next;
    } else {
        return head;
    }
}

🤞15. 合并两个有序链表

代码实现:

方法一:递归
struct ListNode* mergeTwoLists(struct ListNode *list1, struct ListNode *list2) {
    if (list1 == NULL) {
        return list2;
    } else if (list2 == NULL) { 
        return list1;
    } else if (list1->val < list2->val) {
        list1->next = mergeTwoLists(list1->next, list2);
        return list1;
    } else {
        list2->next = mergeTwoLists(list1, list2->next);
        return list2;
    }
}
方法二:常规解法 + 设置虚拟头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode *list1, struct ListNode *list2) {
    if (list1 == NULL) {
        return list2;
    }
    if (list2 == NULL) {
        return list1;
    }
    struct ListNode *head = malloc(sizeof(*head)); // 设置虚拟头结点
    struct ListNode *tail = head; // 尾指针
    while (list1 && list2) {
        if (list1->val < list2->val) {
            tail->next = list1;
            list1 = list1->next;
        } else {
            tail->next = list2;
            list2 = list2->next;
        }
        tail = tail->next;
        tail->next = NULL;
    }
    if (list1) {
        tail->next = list1;
    }
    if (list2) {
        tail->next = list2;
    }
    struct ListNode *result = head->next;
    head->next = NULL;
    free(head);
    return result;    
}
方法三:常规解法 + 不设置虚拟头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode *list1, struct ListNode *list2) {
    if (list1 == NULL) {
        return list2;
    }
    if (list2 == NULL) {
        return list1;
    }
    struct ListNode *head = NULL; // 头
    struct ListNode *tail = NULL; // 尾
    while (list1 && list2) {
        if (list1->val < list2->val) {
            if (head == NULL) { // 从无到有
                head = list1;
                tail = list1;
                list1 = list1->next;
            } else { // 从少到多
                tail->next = list1;
                list1 = list1->next;
                tail = tail->next;
                tail->next = NULL;
            }
        } else {
            if (head == NULL) { // 从无到有
                head = list2;
                tail = list2;
                list2 = list2->next;
            } else { // 从少到多
                tail->next = list2;
                list2 = list2->next;
                tail = tail->next;
                tail->next = NULL;
            }
        }
    }
    if (list1) {
        tail->next = list1;
    }
    if (list2) {
        tail->next = list2;
    }
    return head;    
}

🤞16. 快乐数

代码实现:

快慢指针

int getNext(int x) {
    int sum = 0;
    while (x) {
        int bit = x % 10;
        sum += bit * bit;
        x = x / 10;
    }
    return sum;
}

// 快慢指针
bool isHappy(int n) {
    int slow = n, fast = n;

    // slow = getNext(slow);
    // fast = getNext(getNext(fast));
    // while (slow != fast && fast != 1) {
    //     slow = getNext(slow);
    //     fast = getNext(getNext(fast));
    // }

    do {
        slow = getNext(slow);
        fast = getNext(getNext(fast));
    } while (slow != fast && fast != 1);
    return fast == 1;
}

🤞17. 旋转链表

代码实现:

 方法一:在原链表中找到旋转之后的首尾,改变指向
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* rotateRight(struct ListNode *head, int k) {
    if (k == 0 || head == NULL || head->next == NULL) {
        return head;
    }
    int n = 1; // 统计链表节点数量
    struct ListNode *p = head;
    while (p->next != NULL) { // 循环使p指向尾
        p = p->next;
        n++;
    }
    int add = n - k % n;
    if (add == n) {
        return head;
    }
    p->next = head; // 将尾连接头
    while (add--) { // 让p指向最终移动后的尾
        p = p->next;
    }
    struct ListNode *ret = p->next; // ret指向最终移动后的头
    p->next = NULL;
    return ret;
}
方法二:反转链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
// 反转链表
struct ListNode* reverse(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *tail = head->next;
    struct ListNode *new_head = reverse(head->next);
    head->next = tail->next;
    tail->next = head;
    return new_head;
}

struct ListNode* rotateRight(struct ListNode *head, int k) {
    if (head == NULL || head->next == NULL || k == 0) {
        return head;
    }
    int len = 0; // 统计链表结点个数
    struct ListNode *p = head;
    while (p) {
        len++;
        p = p->next;
    }
    int n = k % len;
    if (n == 0) { // 向右移动 n 个位置
        return head;
    }
    // 翻转整个链表
    head = reverse(head);

    struct ListNode *p1 = head, *p2; // p1指向前段待翻转区间的尾  p2指向后段待翻转区间的头 
    while (n - 1) {
        p1 = p1->next;
        n--;
    }
    p2 = p1->next; // p2指向后段待翻转区间的头 
    p1->next = NULL;
    // 翻转前段区间,head变尾,p1变头
    reverse(head);
    // 翻转后段区间,将头赋值给p2
    p2 = reverse(p2);
    head->next = p2;
    return p1;
}

🤞18. K 个一组翻转链表

代码实现:

方法一:递归
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void reverse(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return;
    }
    struct ListNode *tail = head->next;
    reverse(head->next);
    head->next = tail->next;
    tail->next = head;
}

struct ListNode* reverseKGroup(struct ListNode *head, int k) {
    if (head == NULL || head->next == NULL || k == 1) {
        return head;
    } 
    // 判断剩下的节点数量是否足够
    int n = 0;
    struct ListNode *p = head; // 遍历指针,指向第k+1个
    struct ListNode *pre = NULL; // 遍历指针前驱节点,指向第k个节点
    while (p) {
        pre = p;
        p = p->next;
        n++;
        if (n == k) {
            break;
        }
    }
    if (n != k) { // 后面没有k个节点,直接返回head
        return head;
    }

    pre->next = NULL;
    // 翻转, head变尾,pre变头
    reverse(head);
    head->next = p;

    head->next = reverseKGroup(p, k);
    return pre;
}
方法二:迭代—模拟
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void reverse(struct ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return;
    }
    struct ListNode *tail = head->next;
    reverse(head->next);
    head->next = tail->next;
    tail->next = head;
}

struct ListNode* reverseKGroup(struct ListNode *head, int k) {
    struct ListNode *new_haed = malloc(sizeof(struct ListNode)); // 虚拟头节点
    new_haed->next = head;
    struct ListNode *h = new_haed; // h:指向每次翻转之后的尾节点,用于连接下次翻转的头节点
    struct ListNode *p = head; // p:遍历指针,指向第k+1个节点,每次要翻转区间的头
    struct ListNode *pre = NULL; // pre:遍历指针的前驱节点,指向第k个节点,每次要翻转的尾
    while (1) {
        int n = 0;
        while (p) {
            pre = p;
            p = p->next;
            n++;
            if (n == k) {
                break;
            }
        }
        if (n != k) {
            break;
        }
        pre->next = NULL;
        h->next = NULL;
        // 反转,head变尾,pre变头
        reverse(head);
        h->next = pre;
        head->next = p;

        h = head; // h指向每次翻转区间的尾
        head = p; // head:每次要翻转区间的头,用于翻转
    }   
    return new_haed->next;
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值