力扣链表笔试题--看这一篇就够了

目录

83.删除升序链表中重复的元素,使每个元素只出现一次

82.删除链表中所有存在数字重复情况的节点

剑指offer22.找链表中倒数第k个节点

876. 找链表的中间结点,若有两个中间节点,则返回第二个

206.将链表反向输出

234.判断该链表是否为回文链表

21.合并两个有序链表

 141.判断是否为环形链表

142.找环形链表的入环节点

 160.相交链表,找相交的节点

面试题02.04.分割链表,将小于x的放x前面,大于的放后面

 


83.删除升序链表中重复的元素,使每个元素只出现一次

第一个正方形的节点即为我们自己定义的虚拟头节点dummyHead,使cur从头节点出发一直向后移动,prev和cur一起移动,当遇到重复元素时,让prev指向第一个不重复元素

public class LeetCode83 {//存在一个按升序排列的链表,给你这个链表的头节点 head ,
    // 请你删除所有重复的元素,使每个元素 只出现一次 。
    public ListNode deleteDuplicates(ListNode head) {
        ListNode dummyHead=new ListNode(101);
        dummyHead.next=head;
        ListNode prev=dummyHead;
        ListNode cur=prev.next;
        while (cur!=null){

            if(cur.val==prev.val){
                prev.next=cur.next;
            }else {

                prev=prev.next;//prev和cur都不是重复元素
            } cur=cur.next;//cur一直向后走
        }return dummyHead.next;
    }
}

82.删除链表中所有存在数字重复情况的节点

方法一: 

使用三个索引:prev、cur、next 

    public ListNode deleteDuplicates(ListNode head) {
        ListNode dummyHead = new ListNode(101);
        dummyHead.next = head;
        ListNode prev = dummyHead;
        ListNode cur = prev.next;
        while(cur != null){
            ListNode next = cur.next;
            if(next == null){
                return dummyHead.next;
            }else{
                //当前链表至少有两个节点
                if(cur.val != next.val){
                    //三引用同时向后移动
                    prev = prev.next;
                    cur = cur.next;
                    next = next.next;
                }else{
                    while(next != null && cur.val == next.val){
                        next = next.next;
                    }
                    //prev指向重复节点前驱,next指向重复节点后继
                    prev.next = next;
                    //更新cur的指向
                    cur = next;
                }
            }
        }
        return dummyHead.next;
    }

方法二:

 if (head == null) {
            return head;
        }
        ListNode dummyHead = new ListNode(101);
        dummyHead.next = head;
        ListNode prev = dummyHead;
        ListNode next = prev.next;
        while (next != null) {
            //找到重复的开始
            while (next.next != null && next.val != next.next.val) {
                prev = prev.next;
                next = next.next;
            }
            //找到重复的范围
            while (next.next != null && next.val == next.next.val) {
                next = next.next;
            }
            //走到这里结果一共有三种:
            //1. next.next != null 并且限定了一段重复范围,此时进行去重
            //2. last.next == null && 限定了一段重复范围,此时进行去重,使prev.next = null
            //3. last.next == null && prev.next == next,这说明就不用进行去重
            if (prev.next != next) {
                //说明中间有重复节点
                //prev永远指向的是重复节点的前驱
                //next.next为重复节点的后继
                prev.next = next.next;
            }
            //为了保证恢复的和最开始一致
            next = next.next;
        }
        return dummyHead.next;
    }
}

 

剑指offer22.找链表中倒数第k个节点

定义一个fast和low指向头节点,fast先从头出发走k步,之和fast和low一起同步向后移,fast和low一直相隔k个单位,当fast为空时,low即为倒数第k个节点

public class LeetCodeOffer22 {//找链表中倒数第k个节点
    public ListNode getKthFromEnd(ListNode head, int k) {
      ListNode fast=head;
      ListNode low=head;
        for (int i = 0; i < k; i++) {
            fast=fast.next;
        }
        while (fast!=null){
            fast=fast.next;
            low=low.next;
        }return low;
    }
}

876. 找链表的中间结点,若有两个中间节点,则返回第二个

使用快慢指针,快指针一次走两步,慢指针一次走一步,当快指针为空或者它的下一个节点为空时,慢指针指向的就是中间节点

public class LeetCode876 {
   public ListNode middleNode(ListNode head) {
       ListNode fast=head;
       ListNode low=head;
       while (fast!=null&&fast.next!=null){
          fast=fast.next.next;
          low=low.next;
       }return low;
   }
}

206.将链表反向输出

 1.使用头插法创建出一个新的链表,不要求空间复杂度时使用

public class LeetCode206 {
    public ListNode reverseList(ListNode head) {
        if(head==null||head.next==null) {
            return head;
        }else {
            ListNode dummyHead=new ListNode(5001);
            while (head!=null){
                ListNode node=new ListNode(head.val);
                node.next=dummyHead.next;
                dummyHead.next=node;
                head=head.next;         
            }return dummyHead.next;
        }}

        

2.原地移动,在原来的链表上操作

  public ListNode reverseList(ListNode head) {
        if(head==null||head.next==null){
            return  head;

        }
        else {
            ListNode prev=null;
            ListNode cur=head;
            while (cur!=null){
                ListNode next=cur.next;
                cur.next=prev;
                prev=cur;
                cur=next;
            }return  prev;
        }

    }

3.递归

public ListNode reverseList(ListNode head) {
    if (head==null||head.next==null){
        return head;
    }else {

        ListNode sec = head.next;
        ListNode newHead = reverseList(head.next);
        sec.next = head;
        head.next = null;
        return newHead;
    }
}

234.判断该链表是否为回文链表

如1-->2-->2-->1反过来依然是1-->2-->2-->1

先找到中间节点,将中间节点以后的链表反向输出(使用上一题的方法回文),将新链表和前半段链表相比较即可。

也可以将整个链表回文,这里就不再赘述了

public class LeetCode234 {
 public boolean isPalindrome(ListNode head) {
ListNode middle=middleNode(head);
        ListNode l2=reverseList(middle);
        while (l2!=null){
            if(l2.val!=head.val) {
               return false;
            }l2=l2.next;
            head=head.next;
        }return true;

    } public ListNode middleNode(ListNode head) {//中间节点
        ListNode fast=head;
        ListNode low=head;
        while (fast!=null&&fast.next!=null){
            fast=fast.next.next;
            low=low.next;
        }return low;
    }
    public ListNode reverseList(ListNode head) {//使用递归将链表反序输出(第206题)
        if (head==null||head.next==null){
            return head;
        }else {

            ListNode sec = head.next;
            ListNode newHead = reverseList(head.next);
            sec.next = head;
            head.next = null;
            return newHead;
        }
    }}

21.合并两个有序链表

创建一个虚拟头节点,last指向它。从头节点开始比较,值小的链表接在虚拟头的后面,再用该链表的下一个值和另外一个链表的头节点比较,以此类推

public class LeetCode21 {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1==null){
            return list2;
        }
        if (list2==null){
            return list1;}
        ListNode dummyHead=new ListNode(101);
        ListNode last=dummyHead;
        while (list1!=null && list2!=null){

            if(list1.val<= list2.val){
                last.next=list1;
                last=list1;
                list1=list1.next;
            }else {
                last.next=list2;
                last=list2;
                list2=list2.next;
            }}
        if(list1==null){//此时l1或者l2为空
            last.next=list2;
    }else {
            last.next=list1;
        }return dummyHead.next;
}
}

 141.判断是否为环形链表

使用快慢指针,快慢指针相遇即为环形链表

public class LeetCode141 {
    public boolean hasCycle(ListNode head) {
        ListNode fast=head;
        ListNode low=head;
        while (fast!=null&&fast.next!=null){
            fast=fast.next.next;
            low=low.next;
            if (fast==low){
                return true;
            }
        }return false;



    }
}

142.找环形链表的入环节点

使用快慢指针,快慢指fast和low从头开始走,一个一次走两步,慢的一次走一步,根据上述141号题,若带环二者必会相遇,设在b点相遇,此时,

fast走的长度:a+n(b+c)

low走的长度:a+b

根据fast走的是low的二倍 可推出公式:a=(n-1)(a+b)+c

此时low在b点,使third从头开始和low同时开始以相同速度移动,根据推出的公式,二者在环的入口相遇

public class LeetCode142 {
    public ListNode detectCycle(ListNode head) {
        ListNode fast=head;
        ListNode low=head;
        while (fast!=null && fast.next!=null){
            fast=fast.next.next;
            low=low.next;
            if(low==fast){
                ListNode third=head;

                while (third!=low){
                    third=third.next;
                    low=low.next;

            }return low;
            }
        }return null;

    }
}

 160.相交链表,找相交的节点

 涉及相交部分长度是c,让A、B同时开始遍历,有一方到达终点,让其从对方的表头出发继续遍历,A走的路线:a+c+b,  B走的路线:b+c+a,二者会在交点处相遇

public class LeetCode160 {//相交链表
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode pA=headA;
ListNode pB=headB;
while (pA!=pB){
  pA=pA==null ? headB:pA.next;
  pB=pB==null ? headA:pB.next;
}return pA;
    }
}

面试题02.04.分割链表,将小于x的放x前面,大于的放后面

public class LeetCodeOffer0204 {//分割链表,将小于x的放x前面,大于的放后面
    public ListNode partition(ListNode head, int x) {
    if(head==null){
        return null;
    }
    ListNode smallHead=new ListNode(101);
    ListNode smallTail=smallHead;
    ListNode bigHead=new ListNode(101);
    ListNode bigTail=bigHead;

    while (head!=null){//遍历原链表
        if (head.val<x){
            smallTail.next=head;
            smallTail=head;//尾插入小链表
        }else {
            bigTail.next=head;
            bigTail=head;
        }
        head=head.next;
    }
    bigTail.next=null;//拼接两个链表
    bigTail.next=bigHead.next;
    return smallHead.next;
    }

}

链表有关的题就更新这么多啦,注意!!一定得多画图理解 !!

或许有描述不到位的或者代码有什么问题欢迎多多评论

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值