Leetocde刷题之链表反转

34 阅读4分钟

跟孙哥学java

孙哥主页

1.指定区间反转

反转链表Ⅱ 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

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

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        //定义虚拟节点指向头节点
        ListNode dummyNode=new ListNode(-1,head);
        ListNode pre=dummyNode;
        //让cur指向反转前的节点
        for(int i=1;i<left;i++){
            pre=pre.next;
        }
        ListNode cur=pre.next;
        ListNode next;
        //将位于left-right节点反转
        for(int i=0;i<right-left;i++){
            next=cur.next;
            cur.next=next.next;
            next.next=pre.next;
            pre.next=next;
        }
        return dummyNode.next;


    }
}

方法二:穿针引线法

class Solution {
     public ListNode reverseBetween(ListNode head, int left, int right) {
        //穿针引线法
        //1. 先找到要反转的链表的头结点
        ListNode dummyNode=new ListNode(-1,head);
        ListNode pre=dummyNode;
        for(int i=0;i<left-1;i++){
            pre=pre.next;
        }

        //2.找到反转链表的尾节点
        ListNode cur=pre;
        for (int i=0;i<right-left+1;i++){
            cur=cur.next;
        }
        ListNode needReverse=pre.next;
        ListNode back=cur.next;
        cur.next=null;
        reverse(needReverse);
        ListNode leftNode=pre.next;
        pre.next=cur;
        leftNode.next=back;
        return dummyNode.next;

    }
   private void reverse(ListNode needReverse) {
        ListNode pre=new ListNode();
        ListNode cur=needReverse;
        while (cur!=null){
            ListNode next=cur.next;
            cur.next=pre;
            pre=cur;
            cur=next;
        }
    }
}

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

两两交换链表中的节点

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode cur=head;
        //只有一个节点或没有节点直接返回
        if(cur==null|| cur.next==null){
            return cur;
        }
        //第二个节点必是交换的链表的头结点
        ListNode res=cur.next;
        //定义虚拟头结点,指向头结点
        ListNode pre=new ListNode(-1,cur);
        //当前节点为空或只有一个节点了,直接返回,无法交换了
        while (cur!=null&&cur.next!=null){
            //后节点
            ListNode next=cur.next;
            //让pre指向后节点
            pre.next=next;
            //当前cur指向next.next
            cur.next=next.next;
            //next指向cur,交换了两个节点
            next.next=cur;
            //让pre变为下一组要交换的节点的头结点
            pre=cur;
            //cur后移动
            cur=cur.next;
        }
        return res;

    }
}

3.单链表加1

:::info leetcode369 用个非空单链表来表示一个非负整数,然后将这个整数加一。你可以假设这个整数除了0本身,没有任何前导的0。这个整数的各个数位按照高位在链表头部、低位在链表尾部的顺序排列。 :::

基于链表反转实现如果这里不使用栈,使用链表反转来实现该怎么做呢?很显然,我们先将原始链表反 转,这方面完成加1和进位等处理,完成,之后再次反转。

public class Solution {
   public static void main(String[] args) {
      ListNode listNode=new ListNode(9,new ListNode(9,new ListNode(9)));
      ListNode node = ListAddOne(listNode);

   }
   public static ListNode ListAddOne(ListNode head){
      head= reverseList(head);
      ListNode cur=head;
      while (cur!=null){
         cur.val=cur.val+1;
         if(cur.val==10){
            cur.val=0;
            if(cur.next==null){
               cur.next=new ListNode(1);
               break;
            }
            cur=cur.next;
         }else {
            break;
         }
      }
      return reverseList(head);
   }

   private static ListNode reverseList(ListNode head) {
      ListNode new_head=null;
      while (head!=null){
         ListNode next = head.next;
         head.next=new_head;
         new_head=head;
         head=next;

      }
      return new_head;

   }
}

4.链表加法

两数相加Ⅱ 给你两个 **非空 **链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。

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

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        l1=reverseList(l1);
        l2=reverseList(l2);
        int i=0;
        ListNode ans=new ListNode(-1);
        ListNode cur=ans;
        while (l1!=null&&l2!=null){
            int val= l1.val+l2.val+i;
            if(val>=10){
                int x= val%10;
                cur.next=new ListNode(x);
                i=1;
            }else {
                cur.next=new ListNode(val);
                i=0;
            }
            l1=l1.next;
            l2=l2.next;
            cur=cur.next;
        }
        while (l1!=null){
            int val=l1.val+i;
            if(val==10){
                i=1;
                cur.next=new ListNode(0);
            }else {
                i=0;
                cur.next=new ListNode(val);
            }
            cur=cur.next;
            l1=l1.next;
        }
        while (l2!=null){
            int val=l2.val+i;
            if(val==10){
                i=1;
                cur.next=new ListNode(0);
            }else {
                i=0;
                cur.next=new ListNode(val);
            }
            cur=cur.next;
            l2=l2.next;
        }
        if(i==1){
            cur.next=new ListNode(1);
        }
        ListNode node=ans.next;
        ans.next=null;
        return reverseList(node);


    }

    public ListNode reverseList(ListNode head){
        ListNode newHead=null;
        while (head!=null){
            ListNode next=head.next;
            head.next=newHead;
            newHead=head;
            head=next;
        }
        return newHead;
    }
}

5.再论链表的回文序列问题

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

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

在上一关介绍链表回文串的时候,我们介绍的是基于栈的,相对来说比较好理解,但是除此之外还有可以使用链 表反转来进行,而且还可以只反转一半链表,这种方式节省空间。 我们姑目称之为“快慢指针+一半反转”法。 这个实现略有难度,主要是在while循环中pre.next=prepre和orepre=pre两行实现了一边遍历一边将 访问过的链表给反转了,所以理解起来有些难度,如果不理解可以在学完链表反转之后再看这个问题。