算法通关村第一关--链表经典问题之合并两个有序链表笔记

引言:以下内容均只是个人看法,并无严格经过核对,如有异议,欢迎交流,发现错误,欢迎您的及时指正,感谢!本文所示代码均为java代码

本文中使用的结点定义语句如下

public class listNode {
    public int data;
    public listNode next;
    public listNode(int data) {
        this.data = data;
        this.next=null;
    }
}

单链表的遍历一般从第一个结点依次遍历整个链表,所以第一个结点十分重要,在本文中头节点指的是第一个存放数据的结点,与其他相关文章中关于它的定义可能不同,无需深究,理解相关操作的逻辑原理即可,本质上无较大差别。

1.合并两个有序链表

两个链表均有序,所以在合并时,两个链表均从头开始遍历,然后比较两个链表的当前元素,较小的插入新的链表,同时对应链表的指针后移,比较到其中一个链表为空,就把非空链表的剩下的结点直接连到新建链表的后面,对于其中的一些特殊情况我们采用试着化特殊为一般的方法,比如当有两个结点的数据相等时需要单独写一个if判断吗?

我们举例说明如何解决现有list1(1-2-3-4)和list2(2-5-6)两条链表,首先我们判断两个链表的第一个结点1<2,1放入新建的链表,同时对应指针后移,现在两个链表比较的结点的数据均为2,我们在代码中将等于的情况并入list1<=list2,此时符合条件,list1此时指向的2并入新链表,然后list1指向3,此时list2指向的2小于3,所以list2中的2也并入新链表,即实现了相等情况的判断

基本实现如下图

    /**
     * 0
     * @param list1 要合并的有序链表1
     * @param list2 要合并的有序链表2
     * @return
     */
    public listNode mergeTwoLists(listNode list1, listNode list2) {
        //新建的链表的虚拟结点,它的next才是第一个结点
        listNode newList=new listNode();
        listNode prev=newList;
        //prev作为实时指针进行新建链表的插入操作 尾插法
        //插入操作每次插入的时两个链表元素比较较小的元素
        while(list1!=null&&list2!=null){
            if(list1.data<=list2.data){
                prev.next=list1;
                list1=list1.next;
                prev=prev.next;
            }else{
                prev.next=list2;
                list2=list2.next;
                prev=prev.next;
            }
        }
        //如果有一个链表为空,直接把另一个链表加到newList之后
        prev.next=(list1==null)?list2:list1;
        return newList.next;
    }

2.合并K个链表

合并k个链表,有多种方式,比如堆,归并,我们在这里对于面试更倾向于先将前两个合并,再将后面的合并起来,因为这样前两个写清楚后面的合并k个就比较容易。目前仅阐述这一种方法,后面再做补充。前提每个链表都是非递减的,代码如下:

其中mergeTwoLists是上面的代码

    /**
     * 
     * @param lists 要合并的链表的头结点的数组
     * @return
     */
    //合并k个有序链表
   public ListNode mergeKLists(ListNode[] lists) {
     ListNode res = null;
     for (ListNode list: lists) {
         res = mergeTwoLists(res, list);
     }
     return res;
     }

3.一道很无聊的好题

leetcode1669,现有list1,list2两条链表,把list1中的下标从a开始到b的节点全部删除,然后把list2插入list1中空缺的位置,链表的第一个节点下标是0

    /**
     *
     * @param list1 第一个链表
     * @param a 删除节点的起始下标
     * @param b 删除节点的终点下标
     * @param list2 第二个链表
     * @return
     */
    //leetcode1669,现有list1,list2两条链表,把list1中的下标从a开始到b的节点全部删除,然后把list2插入list1中空缺的位置
    public listNode mergeInBetween(listNode list1, int a, int b, listNode list2) {
        listNode node=list1;//遍历list1找到进行指针操作的两个结点
        listNode node_a=null,node_b=null;
        listNode node2=list2;//遍历list2找到list2的尾节点
        int index=0;
        int remove=0;
        while(node!=null){
            if(index==a-1){
                node_a=node;
            }
            if(index==b+1){
                node_b=node;
            }
            node=node.next;
            index++;
        }
        //让第二个链表的尾节点连接第一个链表下标b后面的节点
        node_a.next=list2;
        while(node2.next!=null){
            node2=node2.next;
        }
        node2.next=node_b;
        return list1;
    }

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值