链表翻转。给出一个链表和一个数K,按照分组逆置。

链表翻转。给出一个链表和一个数K,比如链表1->2->3->4->5->6->NULL,K=2,翻转后 2->1->4->3->6->5->NULL,若K=3,翻转后3->2->1->6->5->4->NULL,若K=4,翻转后4->3->2->1->5->6->NULL,用程序实现ListNode* RotateList(ListNode* list, size_t k)

递归实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *reverseKGroup(ListNode *head, int k) {
        // 为空或一个结点或 K 不符合 规范直接返回原head
        if( NULL == head || NULL == head->next || k < 2)
            return head;

        // 以k为步数,找到逆置前下一组的头指针
        ListNode* next_group_head = head;
        for(int i = 0; i < k; ++i){
            if(next_group_head)   
                next_group_head = next_group_head->next;
            else // 剩余结点数小于K 不够分一组时,下一组的头指针就是head
                return head;
        }

        // 递归去处理剩余组,直到不够 K 个结点,即求出下一组逆置后的头指针
        ListNode* new_next_group_head = reverseKGroup(next_group_head, k);
        ListNode* prev = NULL ,* cur = head;
        // 开始逆置处理当前组,从 head --- next_group_head下一组逆置前的第一个结点
        while(cur != next_group_head){
            ListNode* next = cur->next; // 保存下一个结点
            if(prev == NULL)      // 为空则将当前组的一个结点指向下一组逆置后的第一个结点
                cur->next = new_next_group_head;
            else                  // 不为空则表示逆置当前组的结点,指向prev即可
                cur->next = prev;
            prev = cur;   // 向后推进,直到走完当前组
            cur = next;           
        }
        // 返回逆置后的头指针
        return prev;
    }
};

迭代解法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
     ListNode *reverseKGroup(ListNode *head, int k)
    {
        // 特殊情况处理
        if (NULL == head || NULL == head->next || k < 2)
            return head;

        ListNode* prev = NULL, *pcur = head, *newhead = NULL;

        // 遍历链表,处理每一组
        while (pcur){

            // 找到下一组的头
            ListNode* next_group_head = pcur;
            int i = 0;
            for (; next_group_head && i < k; i++){
                next_group_head = next_group_head->next;
            }
            // 处理不足K 个元素的组
            if (i < k ){
                // 防止K 大于链表结点
                if (newhead == NULL)
                    newhead = head;
                break;
            }
            // 将当前分组[pcur, next_group_head) 逆置,并返回逆置后的头指针
            ListNode* tmp = reverse(pcur, next_group_head);

            if (prev == NULL) // 第一个分组需要更新新的头指针
                newhead = tmp;
            else  // 后续只需要将上一个分组的最后一个结点next 指向当前分组逆序后的的头指针
                prev->next = tmp;
            // 当前分组的最后一个结点next 指向下一个分组开始
            pcur->next = next_group_head;
            // prev 保存当前分组的最后一个结点
            prev = pcur;
            // pcur 向后推进到下一个分组的开始
            pcur = next_group_head;
        }
        return newhead;
    }
    //    [start, end)
    ListNode* reverse(ListNode* start, ListNode* end)
    {
        ListNode* prev = NULL;
        ListNode* pcur = start;
        while (pcur != end){
            ListNode* next = pcur->next;
            pcur->next = prev;
            prev = pcur;
            pcur = next;
        }
        return prev;
    }
};
实现链表逆置的一种常见方法是使用三个指针来迭代地翻转链表。具体步骤如下: 1. 定义三个指针:prev,curr和next。初始时,prev指向空,curr指向头结点,next指向curr的下一个结点。 2. 迭代地遍历链表,对于每个结点,执行以下操作: a. 将curr的next指针指向prev,实现逆置。 b. 将prev指针指向curr。 c. 将curr指针指向next。 d. 将next指针指向curr的下一个结点。 3. 遍历到链表末尾时,prev指向原链表的最后一个结点,curr指向空。此时,将头结点指向prev,完成链表逆置。 下面是一个基于C语言的链表逆置的示例代码: ```c #include <stdio.h> #include <stdlib.h> /* 链表结点 */ struct ListNode { int val; struct ListNode *next; }; /* 创建链表 */ struct ListNode *createList(int *nums, int size) { if (size == 0) { return NULL; } struct ListNode *head = (struct ListNode *)malloc(sizeof(struct ListNode)); head->val = nums[0]; head->next = NULL; struct ListNode *tail = head; for (int i = 1; i < size; i++) { struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode)); node->val = nums[i]; node->next = NULL; tail->next = node; tail = node; } return head; } /* 销毁链表 */ void destroyList(struct ListNode *head) { while (head != NULL) { struct ListNode *node = head; head = head->next; free(node); } } /* 打印链表 */ void printList(struct ListNode *head) { while (head != NULL) { printf("%d ", head->val); head = head->next; } printf("\n"); } /* 链表逆置 */ struct ListNode *reverseList(struct ListNode *head) { struct ListNode *prev = NULL; struct ListNode *curr = head; while (curr != NULL) { struct ListNode *next = curr->next; curr->next = prev; prev = curr; curr = next; } return prev; } /* 测试 */ int main() { int nums[] = {1, 2, 3, 4, 5}; int size = sizeof(nums) / sizeof(nums[0]); struct ListNode *list = createList(nums, size); printf("Original list: "); printList(list); struct ListNode *reversed = reverseList(list); printf("Reversed list: "); printList(reversed); destroyList(reversed); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值