题目描述:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

解题思路:

1、一般看到合并这类的题目就会很自然的想到创建一个新的链表,然后将两个链表根据一定的规则加入到新链表中。所以这里提出第一个比较容易理解的思路:

首先,创建一个新链表。然后,同时遍历两个链表的元素并比较大小,将小的元素首先插入到新链表中,并将小元素的遍历指针后移,大元素的遍历指针不动,就这样依次比较,直至两个链表至少有一个为空。如果有一个链表没有遍历完毕,那么就将该链表剩余的元素全部插入到新链表中。这样就完成了两个链表的合并。

当然,除了正序比较,我们也可以选择倒序比较,先将两个链表压入两个栈,然后依次弹出栈的栈顶元素并比较大小,将大的元素采用头插的方式插入到新链表中。注意:采用栈的时候,新链表的头结点是无法预先确定的,而我们又需要通过头指针完成头插操作,所以我们需要先创建一个新结点newHead作为新链表的头结点,当全部插入完毕后,newHead.next即为新链表的头结点。

2、还有一种方式,相比1会节省一些空间,不需要重新建立一个链表。即从两个链表中随便挑选一个作为被插入的链表。假设我们选择链表1作为合并链表,那么设定两个遍历指针walkNode1与walkNode2,分别指向链表1和链表2,并遍历链表2的元素node2,与链表1当前指针指向的元素node1进行比较

迭代遍历比较:

(1)如果node2.val>node1.val:将链表1指针后移,链表2指针不动

(2)否则:将node2插入到node1前面,继续遍历链表2的元素

注意:虽然我们选取链表1作为被插入链表,但是链表1的头结点不一定是合并后链表的头结点。比如链表2的头结点比链表1小,那么此时就需要将链表2的头结点插入到链表1的头结点之前,但是这是无法做到的,因为我们不知道头结点之前的结点是什么。因此,同思路1的处理方式,我们创建一个新的头结点newHead指向链表1的头结点,这样就可以解决以上提出的问题。

本篇只实现第二种思路,这里举一个例子

现有链表1{1,3,5},链表2{2,4,6}:

a.初始化遍历指针walkNode与前向指针preNode:

b.迭代:比较walkNode1与walkNode2大小并完成插入和指针的后移

walkNode1.val<walkNode2.val,walkNode1与preNode1指针后移

walkNode1.val>walkNode2.val,walkNode2插入进preNode与walkNode1之间。链表1的preNode1指针后移,链表2的walkNode2指针后移

以此类推·····

完整代码:

 class ListNode {
int val;
ListNode next = null; ListNode(int val) {
this.val = val;
}
}
public class mergeList {
public void insertNodes(ListNode preNode,ListNode walkNode){
ListNode startNode=preNode;
while(walkNode!=null){
startNode.next=walkNode;
startNode=startNode.next;
walkNode=walkNode.next;
}
}
public ListNode Merge(ListNode list1,ListNode list2) {
//有一个链表为空,则合并结果为另一个链表
if(list1==null){
return list2;
}
else if(list2==null){
return list1;
}
//将链表1作为被插入的链表(合并后的链表)
ListNode newHead=new ListNode();
newHead.next=list1;
ListNode walkNode1=newHead.next;
ListNode walkNode2=list2;
ListNode preNode1=newHead;
while(walkNode2!=null){
//如果链表1已经遍历结束,可以直接将链表2剩余元素插入到链表1
if(walkNode1==null){
insertNodes(preNode1,walkNode2);
break;
}
//如果链表2当前元素比链表1当前元素大,那么链表1指针后移
if(walkNode2.val>walkNode1.val){
preNode1=walkNode1;
walkNode1=walkNode1.next;
}
//否则,将该元素插入到链表1,链表1的preNode指针和链表2walkNode指针后移
else{
ListNode temp=walkNode2.next;
walkNode2.next=preNode1.next;
preNode1.next=walkNode2;
walkNode2=temp;
preNode1=preNode1.next;
}
}
return newHead.next;
}
}

测试代码:

 public static void main(String []args){
ListNode head = new ListNode(1);
ListNode node2 = new ListNode(4);
ListNode node3 = new ListNode(5);
ListNode head2= new ListNode(2);
ListNode node5 = new ListNode(3);
ListNode node6 = new ListNode(6);
head.next = node2;
node2.next = node3;
head2.next = node5;
node5.next = node6;
mergeList merge =new mergeList();
ListNode returnHead=merge.Merge(head,head2);
while (returnHead != null)
{
System.out.println(returnHead.val );
returnHead = returnHead.next;
}
}

合并两个排序链表——牛客offer的更多相关文章

  1. lintcode:合并两个排序链表

    题目: 合并两个排序链表 将两个排序链表合并为一个新的排序链表  样例 给出 1->3->8->11->15->null,2->null, 返回 1->2-& ...

  2. LintCode-165.合并两个排序链表

    合并两个排序链表 将两个排序链表合并为一个新的排序链表 样例 给出 1->3->8->11->15->null,2->null, 返回 1->2->3- ...

  3. [剑指offer] 14. 链表中倒数第K个节点+翻转+逆序打印+合并两个排序链表 + 链表相交(第一个公共节点) (链表)

    题目描述 输入一个链表,输出该链表中倒数第k个结点. 思路:  两个指针,起始位置都是从链表头开始,第一个比第二个先走K个节点,当第一个走到链表尾时,第二个指针的位置就是倒数第k个节点.(两指针始终相 ...

  4. LintCode-165 · 合并两个排序链表-题解

    描述:将两个排序(升序)链表合并为一个新的升序排序链表样例 1:输入: list1 = null, list2 = 0->3->3->null输出: 0->3->3-&g ...

  5. 剑指offer—第三章高质量代码(合并两个排序链表)

    题目:输入员两个递增排序的链表,合并这两个链表并使新的链表中的结点仍然是按照递增排序的. 思路:首先,定义两个头节点分别为Head1和Head2的链表,然后比较第一个节点的值,如果是Head1-> ...

  6. 《剑指offer》面试题17—合并两个排序链表

    题目:输入两个递增排顺序的链表,合并这两个链表并使合并后的链表仍是递增排序的. 重点: 1.代码鲁棒性:要判断输入的两个链表都为NULL:其中一个链表为NULL的情况. 2.用递归实现,注意递归的思路 ...

  7. [剑指Offer] 16.合并两个排序链表

    题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. [思路1]递归 /* struct ListNode { int val; struct Lis ...

  8. 【LeetCode每天一题】Merge Two Sorted Lists(合并两个排序链表)

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing t ...

  9. 16.合并两个排序的链表 Java

    题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 解题思路 两种解法:递归和非递归 参考代码 /* public class ListNode { ...

随机推荐

  1. Linux 删除文件夹和文件的命令(强制删除包括非空文件)

    linux删除目录很简单,很多人还是习惯用rmdir,不过一旦目录非空,就陷入深深的苦恼之中,现在使用rm -rf命令即可.直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字-r 就 ...

  2. RxJava(一):响应式编程与Rx

    一,响应式编程 响应式编程是一种关注于数据流(data streams)和变化传递(propagation of change)的异步编程方式. 1.1 异步编程 传统的编程方式是顺序执行的,必须在完 ...

  3. 剑指offer21----数组中奇数偶数

    题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 基本实现 如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每 ...

  4. Nginx-HTTP之静态网页访问流程分析一

    假设访问静态网页的配置如下: worker_processes 1; error_log stderr debug; daemon off; master_process on; events { w ...

  5. Android 网络请求Retrofit + RxJava

    一.背景 经常看到项目用Retrofit+RxJava+RxAndroid的框架,为了看懂项目的结构.现在来了解一下,Retrofit: Retrofit是Square 公司开发的一款正对Androi ...

  6. query和exec区别

    1.PDO::query PDO::query执行一条SQL语句,如果通过,则返回一个PDOStatement对象.PDO::query函数有个“非常好处”,就是可以直接遍历这个返回的记录集. 示例如 ...

  7. python基于OpenCV的人脸识别系统

    想获得所有的代码,请下载(来自我的CSDN): https://download.csdn.net/download/qq_40875849/11292912 主函数: from recognitio ...

  8. Linux命令集锦:ansible命令

    ansible 命令主要用于批量管理,来实现自动化管理.常用批量操作包括:主机分组管理.实时批量执行命令或脚本.实时批量分发文件或目录.定时同步文件等. 一.安装 ansible yum instal ...

  9. 一起学习linux环境的git

    第一节 GIT最初是由Linus Benedict Torvalds为了更有效地管理Linux内核开发而创立的分布式版本控制软件,与常用的版本控制工具如CVS.Subversion不同,它不必服务器端 ...

  10. ToolBar跟随键盘弹出和隐藏

    实现效果如下: 代码实现如下: // // ViewController.m // PopToolBarDemo // // Created by 思 彭 on 2017/7/20. // Copyr ...