java:链表面试题其二

文章介绍了如何解决LeetCode中的链表题目,包括寻找倒数第k个节点使用快慢指针优化方法,合并两个有序链表的步骤,以及链表分割的具体实现。
摘要由CSDN通过智能技术生成

一.返回倒数第k个节点

建议自己先动手试一试,20分钟做不出来才看解析

题目链接:面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)

本题目要找的是倒数第k个节点,我们首先要先去讨论一下这个k的合法性。

显然这个k不能小于等于0,同时也不能大于这个链表的长度。

但题目已经保证了给定的k是有效的,所以在本题中可以省去讨论。

有一种做法是先计算链表的长度,然后让该长度减去k值,设减后的值为c

然后从头节点开始走c步,返回走后的节点。

但是这么做的话就需要遍历链表快2遍了,有点麻烦。也不是这道题想要考你的初衷。

我们可以想一下链表的中间节点是怎么找的呢?

是快慢指针的方法,利用fast走完全程时,slow走了一半的特性。此时k为链表长度的一半。

受到启发:我们是不是可以先让fast先走,然后slow和fast一起走,fast走到最后,slow就是倒数第

k个节点。

那么fast应该先走几步呢?

1.如果此时有四个节点,要返回倒数第二个节点。即k=2,即slow要处于第三个节点。

那么就意味着fast要先于slow出发一步。

2.如果此时有六个节点,要返回倒数第三个节点。即k=3,即slow要处于第四个节点。

那么就意味着fast要先于slow2步出发。

上面2个例子,我们可以发现其中的规律:fast先走的步数等于要找的倒数节点数-1,即k-1

明白了这个,这道题就很容易了。

综上:

class Solution {
    public int kthToLast(ListNode head, int k) {
        ListNode fast=head;
        ListNode slow=head;
    while(k>1){
      if(fast==null){
              return -1;
         }
            fast = fast.next;
            k--;
      }
    while(fast.next!=null){
        fast=fast.next;
        slow = slow.next;
        }
           return slow.val;
    }
}

二.合并两个有序链表

建议自己先动手试一试,20分钟做不出来才看解析

题目链接:21. 合并两个有序链表 - 力扣(LeetCode)

看到这道题,我相信大多数人的思路都是让2个链表的节点一个一个进行比较,比较完成就将小的

插入到新链表的节点后就行了,直到其中一个链表结束,再将另一个链表的结点插入到新链表之后

我也是这个思路。

我们可以借助一个虚拟结点作为新链表的头节点,这个头节点的值并不重要,因为它只起到了链接

的作用。如下:

ListNode newTmp = new ListNode();

我们要返回新链表的头节点,那就得把它记录下来。

ListNode tmp = newTmp;

在开始之前,我们得确认传参得2个头节点headA,headB是否有效。

综上:

class Solution {
    public ListNode mergeTwoLists(ListNode headA, ListNode headB) {
           if(headA==null){
            return headB;
           }
           if(headB==null){
            return headA;
           }

           ListNode newH = new ListNode();//虚拟结点,值为多少都无所谓
           ListNode tmp = newH;
           while(headA!=null && headB!=null){
                if(headA.val>headB.val){
                   tmp.next=headB;
                   headB = headB.next;
                   tmp = tmp.next;
                } else{
                   tmp.next=headA;
                   headA = headA.next;
                   tmp = tmp.next;
                }
           }
         if(headA==null){
            tmp.next = headB;
         }
           if(headB==null){
            tmp.next = headA;
           }
           return newH.next;
    }
}

最后返回newH.next是因为从这里开始才是新链表,不包括newH.next。

三.链表分割

建议自己先动手试一试,20分钟做不出来才看解析

题目链接:链表分割_牛客题霸_牛客网 (nowcoder.com)

这个题我把它分为2个部分。

一部分是把所有小于x的数放在一个链表中,大于等于x放在另一个链表中。再进行链接就好了。

举个例子:x=35

综上:

import java.util.*;
public class Partition {
    public ListNode partition(ListNode head, int x) {
      //根据x,将链表中的数据划分成两部分
      //小于x的部分
        ListNode bs=null;
        ListNode be=null;
      //大于x的部分
        ListNode as=null;
        ListNode ae=null;
        while(head!=null){
          //判断当前head的val是哪一部分
            if(head.val<x){
              //判断是否是第一次插入
                if(bs==null){
                    bs=head;
                    be=head;
                }else{
                    be.next=head;
                    be=be.next;
                }
                head=head.next;
            }else{
                if(as==null){
                    as=head;
                    ae=head;
                }else{
                    ae.next=head;
                    ae=ae.next;
                }
                head=head.next;
            }
        }
      第一部分如果为空,返回第二部分 如果第二部分不为空,那么就拼接
        if(bs==null){
            return as;
        }
       //进行拼接
        be.next=as;
       //后半部分不为空,把后半部分最后一个节点置空
        if(as!=null){
            ae.next=null;
        }
       
        return bs;
    }
}

如果对你有帮助的话,请给我点点赞吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值