算法通关村第二关——链表反转白银挑战笔记

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本篇文章主要研究了链表反转的几个问题


一、指定区间链表反转

leetcode92:给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
在这里插入图片描述

示例1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]

在上一篇文章中《算法通关村第二关——链表反转青铜挑战笔记》我们已经提到反转链表主要两种方法,一种是借助虚拟头节点的头插法和不借助虚拟头节点的穿针引线法

1.1 头插法

由于是在指定区间进行链表反转,使用头插法,我们需要得到两个条件,一个是确定虚拟头节点的位置,一个是反转区间的长度。确定玩这两个基本的条件,代码就很简单啦!

代码如下

 ListNode newnode=new ListNode(-1,head);
        ListNode pre=newnode;
        int left_temp=left;
        while(pre!=null){
        //经常喜欢直接用left--,导致下面再用left的时候还以为是原来的值
            if(--left_temp==0){
                break;
            }
            pre=pre.next;
        }
        /*也可以用循环直接找到pre,这样就不怕啦
		*for(int i=0;i<left-1;i++){
        *    pre=pre.next;
        *}
		*/
        
        ListNode cur =pre.next;
        for(int i=0;i<right-left;i++){
            ListNode next =cur.next;
            cur.next=next.next;
            next.next=pre.next;
            pre.next=next;
        }
        return newnode.next;

    }

1.2 穿针引线法

使用穿针引线法,需要把反转的链表单独摘出来进行翻转。这样就把原链表分割成三分:反转区间前面的链表,反转区间的链表,反转区间后面的链表。在反转区间的链表反转完成后,在将该链表拼接回去,我们得到四个节点,反转区间左边节点的前驱pre_left,反转区间左边节点leftnode,反转区间右边节点rightnode,反转区间右边节点的后继right_next。

代码如下

 public ListNode reverseBetween(ListNode head, int left, int right) {
      ListNode newnode=new ListNode(-1,head);
      ListNode pre_left=newnode,leftnode,rightnode,right_next;
      //寻找反转区间左边节点的前驱pre_left,反转区间左边节点leftnode
      for(int i=0;i<left-1;i++){
        pre_left=pre_left.next;
      }
      leftnode=pre_left.next;
      //寻找反转区间右边节点rightnode,反转区间右边节点的后继right_next
      rightnode=leftnode;
      for(int i=0;i<right-left;i++){
          rightnode=rightnode.next;
      }
      right_next=rightnode.next;
      //要把反转区间最后一个置空,否则就会导致反转区间后面的链表全部被反转
      rightnode.next=null;
      //进行区间反转,并对反转后的三块链表进行拼接
      pre_left.next= fanzhuan(leftnode);
      leftnode.next=right_next;
      return newnode.next;

    }
    public ListNode fanzhuan(ListNode head){
    //使用穿针引线法进行链表反转
        ListNode pre=null,cur=head;
        while(cur!=null){
            ListNode next =cur.next;
            cur.next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
    }

二、两两交换链表中的节点

Leetcode24:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

在这里插入图片描述

示例1
输入:head = [1,2,3,4]
输出:[2,1,4,3]

   public ListNode swapPairs(ListNode head) {
        ListNode newnode=new ListNode(-1,head);
       ListNode temp=newnode;
        while(temp.next!=null&&temp.next.next!=null){
            ListNode l1=temp.next;
            ListNode l2=temp.next.next;
            l1.next=l2.next;
            l2.next=temp.next;
            temp.next=l2;
            temp=l1;
        }
        return newnode.next;
    }

三、 链表加法

leetcode445:给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。


在这里插入图片描述

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

将链表反转,对位相加,并要考虑进位,最后再将链表反转

 public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
            l1=fanzhuan(l1);
            l2=fanzhuan(l2);
            ListNode newnode =new ListNode(-1,null);
            int i=0;
            ListNode temp=newnode;
            while(l1!=null&&l2!=null){
                int val =(l1.val+l2.val+i)%10;
                i=(l1.val+l2.val+i)>=10?1:0;
                temp.next=new ListNode(val);
                l1=l1.next;l2=l2.next;
                temp=temp.next;
            }
            if(l1==null){
                while(l2!=null){
                    int val=(l2.val+i)%10;
                    i=(l2.val+i)>=10?1:0;
                    temp.next=new ListNode(val);
                    l2=l2.next;
                    temp=temp.next;
                }
            }
            if(l2==null){
                while(l1!=null){
                    int val=(l1.val+i)%10;
                    i=(l1.val+i)>=10?1:0;
                    temp.next=new ListNode(val);
                    l1=l1.next;
                    temp=temp.next;
                }
            }
            if(i==1){
                temp.next=new ListNode(1);
            }
            return fanzhuan1(newnode.next);

    }
    //体验不同的反转方法
    public ListNode fanzhuan (ListNode head){
        if(head==null||head.next==null){
            return head;
        }
        ListNode newhead=fanzhuan(head.next);
        head.next.next=head;
        head.next=null;
        return newhead;
    }
    public ListNode fanzhuan1(ListNode head){
        ListNode newnode =new ListNode(-1,null);
        ListNode temp=head;
        while(temp!=null){
            ListNode next = temp.next;
            temp.next = newnode.next;
            newnode.next=temp;
            temp=next;
        }
        return newnode.next;
    }
    public ListNode fanzhuan2(ListNode head){
        ListNode pre=null,cur=head,next;
        while(cur!=null){
            next=cur.next;
            cur.next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
    }

四、 链表回文序列在思考

leetcode234:给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。


在这里插入图片描述

示例
输入:head = [1,2,2,1]
输出:true

使用快慢指针找到中点,并使用慢指针直接将前半部分进行链表反转

public boolean isPalindrome(ListNode head) {
        ListNode fast=head,slow=head;
        ListNode cur=null,pre=null;
        while(fast!=null&&fast.next!=null){
            cur=slow;
            slow=slow.next;
            fast=fast.next.next;
            cur.next=pre;
            pre=cur;
        }
        if(fast!=null){
            slow=slow.next;
        }
        while(pre!=null){
            if(pre.val!=slow.val){
                return false;
            }
            pre=pre.next;
            slow=slow.next;
        }
        return true;
    }

总结

主要记录了链表反转的一些拓展应用题目

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值