Leetcode打卡四:将给定的单链表L: L 0→L 1→…→L n-1→L n, 重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→… 要求使用原地算法,并且不改变节点的

题目:

将给定的单链表L: L 0→L 1→…→L n-1→L n,
重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→…
要求使用原地算法,并且不改变节点的值
例如:
对于给定的单链表{1,2,3,4},将其重新排序为{1,4,2,3}.

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public void reorderList(ListNode head) {
    }
 }

分析

思路一:

(这个思路是我一开始想的思路,不仅麻烦而且不符合题目要求)
1.将该链表复制为两个新的独立链表head1,head2
2.每次将head2的节点插入到head1的倒数第二个节点,然后将head1的最后两个节点一起拿出来链到我们的结果链表,然后将head1进行断链。
举个例子:

  • 第一次将head2的0节点,插入到head1的倒数第二个节点,也就是n节点的前驱,这样head1节点的最后两个节点就是0->n,
  • 之后就可以将这两个节点取出来插入到一个新的空链表,也就是我们的结果存储链表
  • 然后将head1链表断链,经过第一次的循环,我们的结果链表中存了0->n,head1中的尾节点变成了n-1,下次我们还是找到倒数第二个节点插入即可
  • 经过第二次插入,head1中最后两个节点为1->n-1,我们取出来,再断链!

3.而实际上这个算法是可行的,只是太过于复杂,因为我对链表的复制还不是很熟悉,以为直接指向就就可以了,但是实际上必须所有的节点全部创建新节点传值,才可以实现。

思路二:(标准解法)

1.找到head的中间节点,进行断链,分为head1,head2
2.将head2进行原地反转
3.将head2和head1进行交叉插入即可

这个方法是我没有想到的,首先如何找到中间节点,这样就要用到快慢节点去寻找,设置一个快节点,慢节点即可。其次链表的原地反转也是我没有接触过的,因为之前对算法基本没怎么学!后来链表的原地反转是从头开始,每次断一个节点,连一个节点!

public static void reorderList1(ListNode head) {

    if(head == null || head.next == null) return;
    ListNode fastPoint = head;//快节点
    ListNode slowPoint = head;//慢节点
    ListNode midPoint;//中间节点
    //找到中间节点
    while(fastPoint.next != null && fastPoint.next.next != null  ){
        fastPoint = fastPoint.next.next;
        slowPoint = slowPoint.next;
    }
    midPoint = slowPoint;

    //断成两个链表
    ListNode head2 = midPoint.next;
    midPoint.next = null;

    //后半段链表翻转
    ListNode q = head2.next;
    head2.next = null;
    while(q != null){
        ListNode qNext = q.next;
        q.next = head2;
        head2 = q;
        q = qNext;

    }

    //将head2 插入head1
    ListNode head1 = head;
    while( head2 != null){
        ListNode newList = head2.next;
        head2.next = head1.next;
        head1.next = head2;

        head2 = newList;
        head1 = head1.next.next;

    }

}

总结:
1.对于快慢节点寻找中间节点的方法第一次接触,另外我还知道快慢节点还可以判断是否为循环链表
2.链表原地反转也是我不会的,也要仔细琢磨
3.中间程序运行有一个bug就是,以后对于链表是否为空的判断,一定要先判断前驱节点,再判断后驱节点,例如不能这么写while(p->next && p),这样就会出现空指针异常的情况
4.关于链表复制和断链的问题,我要切记每次遍历只要将头结点记录好就行了,链表就不会断。链表的复制不是简单的指向

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值