题目描述:
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
解题方法:
按照题目中的要求,我们知道待合并的两个链表都是升序有序的,所以我们就不需要考虑其他的特殊情况了。在此以 {1, 2, 3} 和 {2, 3, 4} 分别生成两个升序有序的链表来进行合并,代码如下:
public class ListNode {
/**
* 数据域
*/
private int val;
/**
* 指向下一个节点的链接
*/
private ListNode next;
public ListNode(int val) {
this.val = val;
this.next = null;
}
/**
* 打印链表
* @param listNode
*/
public static void display(ListNode listNode) {
if (listNode == null) {
return;
} else {
while (listNode.next != null) {
System.out.print(listNode.val + " -> ");
listNode = listNode.next;
}
}
System.out.println(listNode.val);
}
/**
* 获取链表中元素的个数
* @param listNode
* @return
*/
public static int getSize(ListNode listNode) {
int count = 0;
if (listNode == null) {
return count;
} else {
while (listNode != null) {
count++;
listNode = listNode.next;
}
return count;
}
}
/**
* 数组转链表
* @param arrays
* @return
*/
public static ListNode arrayToListNode(int[] arrays) {
if (arrays.length == 0) {
return null;
}
// 用数组的第一个元素生成一个新的链表
ListNode head = new ListNode(arrays[0]);
// 声明前一个节点等于头节点
ListNode pre = head;
for (int i = 1; i < arrays.length; i++) {
// 要插入的节点对象
ListNode node = new ListNode(arrays[i]);
// 前一个节点的 next 指向当前节点
pre.next = node;
// 更新前一个节点
pre = node;
}
return head;
}
/**
* 合并两个有序链表
* @param listNode1
* @param listNode2
* @return
*/
public static ListNode mergeTwoList(ListNode listNode1, ListNode listNode2) {
// 定义一个 val 为 0,next 为空的链表
ListNode listNode = new ListNode(0);
// 声明当前节点
ListNode cur = listNode;
while (listNode1 != null && listNode2 != null) {
if (listNode1.val < listNode2.val) {
// 当前节点的 next 域连接较小的一个节点
cur.next = listNode1;
// 更新当前节点
cur = cur.next;
// 更新 listNode1
listNode1 = listNode1.next;
} else {
cur.next = listNode2;
cur = cur.next;
listNode2 = listNode2.next;
}
}
// 任一为空,直接连接另一条链表
if (listNode1 == null) {
cur.next = listNode2;
} else {
cur.next = listNode1;
}
return listNode.next;
}
public static void main(String[] args) {
int[] arrays1 = {1, 2, 3};
ListNode listNode1 = arrayToListNode(arrays1);
System.out.println(getSize(listNode1));
display(listNode1);
int[] arrays2 = {2, 3, 4};
ListNode listNode2 = arrayToListNode(arrays2);
System.out.println(getSize(listNode2));
display(listNode2);
ListNode listNode3 = mergeTwoList(listNode1, listNode2);
display(listNode3);
}
}
根据以上代码,我们主要说明一下 mergeTwoList() 方法对两个待合并链表的处理过程。进入此方法之后,我们先定义一个最后返回的链表 listNode 和一个指向该链表的节点 cur,待合并的两个链表分别为 listNode1 和 listNode2。
listNode1、listNode2、listNode 此时的各节点的数据域和 next 域的情况如下图所示:我们可以认为此时 listNode1 链表的头节点就为第一个节点,数据域为 1,next 指向下一个存储了 2 的节点,listNode2 也类似,对于 listNode 来说,此时头节点的数据域为 0,next 域为空。
接下来我们进行主要的判断,即判断 listNode1 的头节点的数据域是否小于 listNode2 的头节点的数据域,如果是,则临时节点的 next 域指向 listNode1,然后更新临时节点和 listNode1:
进行一次判断之后,我们发现此时 listNode1 的头节点数据域为 2,listNode2 不变,listNode 的 next域已经连接了 listNode1,cur 位于 listNode 的第二个节点处:
第二次判断之后:
第三次判断后:
第四次判断后:
第五次判断之后:
第五次判断之后,listNode1 已经遍历完成了,所以不需要再走 while 循环去判断了,直接进行下一步当 listNode1 == null 的操作,执行之后:
此时我们直接返回 listNode.next 即可。打印出的合并之后的链表结构为:
除此之外,该题还有另外一种解法,即使用递归解决,每次都去找 listNode1 和 listNode2 中较小的节点去拼接 next 域。完整代码如下:
public class ListNode {
/**
* 数据域
*/
private int val;
/**
* 指向下一个节点的链接
*/
private ListNode next;
public ListNode(int val) {
this.val = val;
this.next = null;
}
/**
* 打印链表
* @param listNode
*/
public static void display(ListNode listNode) {
if (listNode == null) {
return;
} else {
while (listNode.next != null) {
System.out.print(listNode.val + " -> ");
listNode = listNode.next;
}
}
System.out.println(listNode.val);
}
/**
* 获取链表中元素的个数
* @param listNode
* @return
*/
public static int getSize(ListNode listNode) {
int count = 0;
if (listNode == null) {
return count;
} else {
while (listNode != null) {
count++;
listNode = listNode.next;
}
return count;
}
}
/**
* 数组转链表
* @param arrays
* @return
*/
public static ListNode arrayToListNode(int[] arrays) {
if (arrays.length == 0) {
return null;
}
// 用数组的第一个元素生成一个新的链表
ListNode head = new ListNode(arrays[0]);
// 声明前一个节点等于头节点
ListNode pre = head;
for (int i = 1; i < arrays.length; i++) {
// 要插入的节点对象
ListNode node = new ListNode(arrays[i]);
// 前一个节点的 next 指向当前节点
pre.next = node;
// 更新前一个节点
pre = node;
}
return head;
}
/**
* 合并两个有序链表--迭代
* @param listNode1
* @param listNode2
* @return
*/
public static ListNode mergeTwoList(ListNode listNode1, ListNode listNode2) {
// 定义一个 val 为 0,next 为空的链表
ListNode listNode = new ListNode(0);
// 声明当前节点
ListNode cur = listNode;
while (listNode1 != null && listNode2 != null) {
if (listNode1.val < listNode2.val) {
// 当前节点的 next 域连接较小的一个节点
cur.next = listNode1;
// 更新当前节点
cur = listNode1;
// 更新 listNode1
listNode1 = listNode1.next;
} else {
cur.next = listNode2;
cur = cur.next;
listNode2 = listNode2.next;
}
}
// 任一为空,直接连接另一条链表
if (listNode1 == null) {
cur.next = listNode2;
} else {
cur.next = listNode1;
}
return listNode.next;
}
/**
* 合并两个有序链表--递归
* @param listNode1
* @param listNode2
* @return
*/
public static ListNode mergeTwoList2(ListNode listNode1, ListNode listNode2) {
if (listNode1 == null) {
return listNode2;
}
if (listNode2 == null) {
return listNode1;
}
if (listNode1.val < listNode2.val) {
listNode1.next = mergeTwoList2(listNode1.next, listNode2);
return listNode1;
} else {
listNode2.next = mergeTwoList2(listNode1, listNode2.next);
return listNode2;
}
}
public static void main(String[] args) {
int[] arrays1 = {1, 2, 3};
ListNode listNode1 = arrayToListNode(arrays1);
System.out.println(getSize(listNode1));
display(listNode1);
int[] arrays2 = {2, 3, 4};
ListNode listNode2 = arrayToListNode(arrays2);
System.out.println(getSize(listNode2));
display(listNode2);
ListNode listNode3 = mergeTwoList2(listNode1, listNode2);
display(listNode3);
}
}