链表刷题(1)

本文介绍了如何对链表进行一系列操作,包括反转链表、找到链表的中间节点、查找倒数第k个节点以及合并两个有序链表。同时,还提供了将值为x的节点插入链表以保持有序的解决方案。这些基本操作是链表数据结构的重要组成部分,对于理解和处理链表问题非常关键。
摘要由CSDN通过智能技术生成

1.反转单链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表

LeetCode链接

得到如下链表

代码实现:

    public ListNode reverseList(ListNode head) {
            if(head == null){
                return null;
            }
            ListNode cur = head;
            ListNode curNext;
            ListNode prev = null;
            while(cur != null){
                curNext = cur.next;
                cur.next = prev;
                prev = cur;
                cur = curNext;   
            } 
      return prev;
    }

2.返回链表中间节点

LeetCode链接

给定一个头结点为 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

对于该题,可用快慢指针来解决:

定义一个fast,再定义一个slow,让fast一次走两步,slow一次走一步,当fast = null 时,此时,slow对应的节点就是该链表的中间节点。

奇数个节点 

 偶数个节点

代码实现:

    public ListNode middleNode(ListNode head) {
        if(head == null){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

3.返回链表倒数第k个节点

牛客网链接

方法一:一般做法

假设链表长度为len,则倒数第k个节点,就为正着数第len-k个节点,就可以直接返回第len-k个节点。

方法二:双指针

对于方法一,大多数人都能想到,但对于面试官来说,显然方法一不够好不够快。而本题可以利用快慢指针来解决。

从倒数第一个到倒数第k个,中间差k-1步。定义fast,slow都等于head。先让fast走k-1步,然后fast与slow一起走,直至fast走到最后一个节点,此时slow对应节点就是所求节点。

代码实现:

    public ListNode FindKthToTail(ListNode head,int k) {
        if(k <= 0 || head == null){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        for(int i = 0;i <= k-1;i++){
            fast = fast.next;
            if(fast == null){
                return null;
            }
        }
        while(fast != null){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

4.合并有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

LeetCode链接

假定链表为都为升序链表,该题涉及两个链表,可以利用一个傀儡节点来解决问题。

       傀儡节点:

        ListNode newhead = new ListNode(-1);
        ListNode tmp = newhead;

即val域为-1,next域为tmp

分析先对两个节点值进行判断,若headA.val <= headB.val,则令tmp.next = headA,使傀儡节点与headA串联起来,然后让headA向后走一步(为后续的headA与headB的大小进行判断),再让tmp向后走一步。若此时headA.val > headB.val,则tmp.next = headB,使得链表串起来,再让headB向后走一步,然后使tmp向后走一步。直至headA = null或headB = null。

代码实现:

    public ListNode mergeTwoLists(ListNode headA, ListNode headB) {
        ListNode newhead = new ListNode(-1);
        ListNode tmp = newhead;

        while(headA != null && headB != null){
            if(headA.val <= headB.val){
                tmp.next = headA;
                headA = headA.next;
                tmp = tmp.next;
            }else{
                tmp.next = headB;
                headB = headB.next;
                tmp = tmp.next;
            }
        }
        if(headA != null){
            tmp.next = headA;
        }
        if(headB != null){
            tmp.next = headB;
        }
        return newhead.next;
    }

5.将值为x的节点插入链表,使小于x的节点排在x之前

现有一链表的头指针 ListNode head,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针

牛客网链接

分析:本题可以将链表分开成两个,一边是小于x的,一边是大于x的,用cur遍历一遍数组 即可得到结果。小于x的部分,定义一个BeforStar,BeforEnd,大于x的部分AfterStar,AfterEnd,即bs,be,as,ae。若是第一次实例化小于x的部分,让bs,be同时指向cur,若是第一次实例化大于x的部分,让as,ae同时指向cur。若不是第一次,利用尾插法即可。

注意:1.小于x的部分可能为空    2.大于x的部分可能最一个节点的next域不是null

代码实现:

    public ListNode partition(ListNode head, int x) {
        ListNode cur = head;
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;
        while(cur != null){
            if(cur.val < x){
                if(bs == null){
                    bs = cur;
                    be = cur;
                }else{
                    be.next = cur;
                    be = be.next;
                }
            }else{
                if(as == null){
                    as = cur;
                    ae = cur;
                }
                else{
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        if(bs == null){
            return as;
        }
        be.next = as;
        if(as != null){
            ae.next = null;
        }
        return bs;
    }

6.删除链表中重复的的节点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表 1->2->3->3->4->4->5  处理后为 1->2->5

牛客网链接

分析:该题可以利用傀儡节点,分析对于cur.val != cur.next.val,即cur.val唯一(不重复),将该节点置于傀儡节点之后即可

注意:最后一个节点一定为null.

    public ListNode deleteDuplication(ListNode head) {
        ListNode cur = head;
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        while(cur != null){
            if(cur.next != null && cur.val == cur.next.val){
                while(cur.next != null && cur.val == cur.next.val){
                    cur = cur.next;
                }
                cur = cur.next;
            }else{
                tmp.next = cur;
                tmp = tmp.next;
                cur = cur.next;
            }
        }
        tmp.next = null;
        return newHead.next;
    }

           

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

噜噜噜噜鲁先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值