链表交换+递归+迭代 24. 两两交换链表中的节点 25. K 个一组翻转链表

24. 两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.

解题

递归解法
设定first节点和second节点,若传入节点为空或下一个为空,则停止交换;
若两者都不为空,则前一个节点的next指向后一个几点的second,当前second的next指向当前节点的first,返回当前second,即为反转后两者的新的头节点;

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(!head||!head->next) return head;
        ListNode* firstnode = head;
        ListNode* secondnode =head->next;

        firstnode->next= swapPairs(secondnode->next);
        secondnode->next=firstnode;

        return secondnode;
    }
};

递推解法(空间复杂度降至O(1))
一个节点保存头;
每次用previos节点,first节点和second节点,将previous节点指向second节点,first节点指向second节点的下一个,second节点指向fisrt节点,完成一对交换,且将该组头节点传至previos,在进行下一对交换时,previous=first,为下一组交换头节点的接收位置,head=first->next,为下一组交换的交换起点;

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //三个指针,另一个保存头节点
        ListNode dummy;
        dummy.next=head;
        ListNode *prev=&dummy;
        ListNode * first;
        ListNode * second;
        while(head&&head->next)
        {
            first=head;
            second=head->next;

            prev->next=second;
            first->next=second->next;
            second->next=first;

            prev=first;
            head=first->next;
        }
        return dummy.next;
    }
};

25. K 个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例:

给你这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

说明:

你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

解题
每隔K个数反转链表(从反转起点到反转终点必须要有k个数),常数额外空间(迭代递推)。
与反转两个数的迭代算法类似,先找到反转的头节点head,反转尾节点rear,若rear不为Null,说明可以完成这一段反转,则
(1)将从head到rear之间的节点全部反转
需要用到first,second和tmp三个指针,first指向反转头节点,second反转尾节点,tmp指向second后面的节点(不然反转second会导致后面节点丢失);
进行k-1次反转——反转k个数;

            ListNode *tmp;
            first=head;
            ListNode *second=first->next;
            for(int m=0;m<k-1;m++)   //从first到rear全部逆序
            {
                tmp=second->next;
                second->next=first;
                first=second;
                second=tmp;
            }

(2)反转后原来rear后面的节点丢失,所以反转前也要保存rear->next节点;

ListNode * p=rear->next;

(3)将rear节点传递给一开始的previos指针;
head节点下一个为原来rear的下一个节点p;

prev->next=rear;//传出的头节点为rear
head->next=p;

(4)为下一次反转做准备;
需要指向下一个传出的rear的节点为当前head,故prev=head;
下一个反转起点为前一个rear的next,故head=p;
重制rear,需要k-1次循环,找到head后面第k个数,故rear=p,然后k-1次next,若为null,则不会进行下一次反转,推出循环;

            prev=head;
            head = p;

            rear=p;     //关键点,rear后移
            for(int t=0;t<k-1;t++)
            {
                if(rear){
                rear=rear->next;     //要交换的最后一个节点
                }
            }

完整代码

/**
 * 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) {
        ListNode dummy;
        ListNode *prev= &dummy;
        prev->next=head;
        ListNode *first;
        ListNode *rear=head; 
        int i=0;
        while(i<k-1&&rear)
        {
            rear=rear->next;     //要交换的最后一个节点
            i++;
        }
        
        while(head&&rear)
        {   
            ListNode * p=rear->next;
            ListNode *tmp;
            first=head;
            ListNode *second=first->next;
            for(int m=0;m<k-1;m++)   //从first到rear全部逆序
            {
                tmp=second->next;
                second->next=first;
                first=second;
                second=tmp;
            }
            
            prev->next=rear;//传出的头节点为rear
            
            head->next=p;
            prev=head;
            head = p;

            rear=p;     //关键点,rear后移
            i=0;
            while(i<k-1&&rear)
            {
                rear=rear->next;     //要交换的最后一个节点
                i++;
            }
        }
        return dummy.next;
    }
};

优化思路+优化代码

/**
 * 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) {
        ListNode dummyhead;
        dummyhead.next=head;
        ListNode* start=&dummyhead;

        ListNode *first=head;
        ListNode * second;
        ListNode * tmp;

        while(1){

            //检查能否找到第k个点
            tmp=first;
            int n=k-1;
            while(tmp&&n) {
                tmp=tmp->next;
                n--;
            }
            if(!tmp) break;
            //检查能否找到第k个点
            
            second=first->next;
            for(int i=1;i<k;i++) {
                tmp=second->next;
                second->next=first;   //first保存在start->next中

                first=second;
                second=tmp;
            }
            start->next->next=second;
            tmp=start->next;
            start->next=first;
            start=tmp;
            first=tmp->next;
        }

        return dummyhead.next;

    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值