链表常见面试题(二)

链表中倒数第k个链表

**题目:**链表中倒数第k个结点
题目链接OJ链接
示例1
输入:1,{1,2,3,4,5}
返回值:{5}
**题目解析:**要求倒数第k个结点的位置,那么我们只需要找(length - k)的结点位置即可,具体分析如下:

        ListNode cur = head;
        for(int i = 0; i < count - k; i++){
            cur = cur.next;
        }

以示例1为例,那么上述代码就变成了这样:

        ListNode cur = head;
        for(int i = 0; i < 4; i++){
            cur = cur.next;
        }

当 i = 0 时,执行第一次循环,此时 cur.val = 2,i 自增为 1;
当 i = 1 时,执行第二次循环,此时 cur.val = 3,i 自增为 2;
当 i = 2 时,执行第三次循环,此时 cur.val = 4,i 自增为 3;
当 i = 3 时,执行第四次循环,此时 cur.val = 5,i 自增为 4;
当 i = 4时,不满足条件结束循环,自此循环完成,cur.val = 5;
在上述描述中, val 只是为了方便解析而自加的属性,在代码中只要求结点,并没有要求需要结点的值,望周知!
由此我们可以看出,第(length - k)个结点 = 倒数第k个结点 ,这样就可以顺利地写代码啦!
第一步:求出链表长度

for(ListNode cur = head; cur != null; cur = cur.next){
            length++;
        }

第二步:求第(length - k)个结点

 for(int i = 0; i < length - k; i++){
            cur = cur.next;
        }

代码实现注意事项:

  1. 注意链表是否为空,为空直接返回即可,节省时间
  2. 注意判断k的长度,如果k的长度大于链表长度的话,返回的应该是一个空结点,而由于没有 if 条件的限制,cur 不会进入第二个循环,返回的是头结点;

具体代码:

public class Solution {
    public ListNode FindKthToTail(ListNode head, int k) {
        //先确定特殊情况
        if(head == null){
            return null;
        }
        //先求出其总长度,然后总长度 - k,遍历到这个节点就是倒数第 k 个结点
        int length = 0;
        for(ListNode cur = head; cur != null; cur = cur.next){
            length++;
        }
        if(k > length){
            return null;
        }
        ListNode cur = head;
        for(int i = 0; i < length - k; i++){
            cur = cur.next;
        }
        return cur;
    }
}

合并两个有序链表

**题目:**将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
题目链接:OJ链接
示例:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
**题目解析:**题目中有两个字眼是值得注意的——有序,题目不是简单的要求 l1 的 尾结点指向 l2 的头结点,而是要求合并好的链表升序排列。解决方法也简单,l1 和 l2 的结点相互比较,那个结点的值比较小就先指向谁。具体解析如下:
以示例为例子:

 			if(l1.val == l2.val){
                tail.next = l1;
                l1 = l1.next;
                //更新tail
                tail = tail.next;
            }else if(l1.val > l2.val){
                //小的先进新链表
                tail.next = l2;
                //更新
                l2 = l2.next;
                tail = tail.next;
            }else{
                tail.next = l1;
                //更新
                l1 = l1.next;
                tail = tail.next;
            }

首先,建立一个傀儡结点(傀儡结点就是无关紧要的结点,其不具备实际意义),使得 tail = 傀儡结点;
第一次比较在这里插入图片描述以此类推,直至当两个链表中有一个链表的引用指向空结点为止;
题目注意事项:

  1. 在比较之前要先判断两个链表之中是否有着空链表,如果有直接返回非空链表;因为如果在比较中出现空链表会报空引用异常
  2. 循环结束条件为两个链表其中之一的引用指向空结点,否则在比较中也会报空引用异常
  3. 最后不要忘记处理非空链表

代码实现:

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        //判断特殊情况,即两个有序链表其中有一个是空链表的情况
        if(l1 == null){
            return l2;
        }
        if(l2 == null){
            return l1;
        }
        //创建一个新链表来存储,为了方便,创建一个带傀儡结点的链表
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;

        while(l1 != null && l2 != null){
            //判断二者的值是否相等,相等的话就让 l1 先进新链表
            if(l1.val == l2.val){
                tail.next = l1;
                l1 = l1.next;
                //更新tail
                tail = tail.next;
            }else if(l1.val > l2.val){
                //小的先进新链表
                tail.next = l2;
                //更新
                l2 = l2.next;
                tail = tail.next;
            }else{
                tail.next = l1;
                //更新
                l1 = l1.next;
                tail = tail.next;
            }
        }
        if(l1 == null){
            tail.next = l2;
        }else{
            tail.next = l1;
        }
        return dummy.next;
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值