0.两个链表的第一个公共节点
描述
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
数据范围: n ≤ 1000 要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)\
例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。
输入描述
输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。
返回值描述
返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。
示例1
输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
说明:第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分
这3个参数最后在后台会组装成为2个两个无环的单链表,且是有公共节点的
示例2
输入:{1},{2,3},{}
返回值:{}
说明:2个链表没有公共节点 ,返回null,后台打印{}
解题思路1
双指针法,使用两个指针,依次遍历链表,当任一个指针走到链表末尾时,将该指针移动到另一个链表头节点位置继续移动,直到两个指针相遇,相遇节点即为公共链表起始节点。
设head1长度为n,head2长度为m,n < m,所以head1先遍历完,此时head2要遍历完得比head1多走m-n步,刚好相当于head1和head2在距离公共节点起始位置相同距离处移动,所以当两个指针相等时,当前位置即为公共链表起始节点。
可以把链表末尾节点指向null的当做公共节点,所以当两个链表没有公共节点时,返回null。
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode cur1 = pHead1;
ListNode cur2 = pHead2;
while (cur1 != cur2) {
cur1 = cur1 == null ? pHead2 : cur1.next;
cur2 = cur2 == null ? pHead1 : cur2.next;
}
return cur1;
}
时间复杂度O(N+M)
空间复杂度O(1)
解题思路2
使用一个集合来存储其中一个链表遍历的节点,然后遍历另一个链表,当另一个链表遍历的节点在集合中存在时,即为第一个公共节点。
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode cur1 = pHead1;
ListNode cur2 = pHead2;
Stack<ListNode> stack = new Stack<>();
while (cur1 != null) {
stack.push(cur1);
cur1 = cur1.next;
}
while (cur2 != null) {
if (stack.contains(cur2)) {
return cur2;
}
cur2 = cur2.next;
}
return cur2;
}
时间复杂度O(N+M)
空间复杂度O(N+M)
解题思路3
先得到两个链表的长度,然后先让长链表先移动两个链表长度差,使得两个链表从距离第一个公共节点相同位置出同时移动,直到两个指针相等。
public int getListLength(ListNode head) {
int len = 0;
ListNode p = head;
while (p != null) {
p = p.next;
len++;
}
return len;
}
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int len1 = getListLength(pHead1);
int len2 = getListLength(pHead2);
ListNode p1 = pHead1;
ListNode p2 = pHead2;
if (len1 < len2) {
for (int i = 0; i < len2-len1; i++) {
p2 = p2.next;
}
while (p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
} else {
for (int i = 0; i < len1-len2; i++) {
p1 = p1.next;
}
while (p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
}
return p1;
}
时间复杂度O(N+M)
空间复杂度O(1)
1.链表相加
描述
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
给定两个这种链表,请生成代表两个整数相加值的结果链表。
数据范围:0 ≤ n,m ≤ 1000000,链表任意值 0 ≤ val ≤ 9
要求:空间复杂度 O(n),时间复杂度 O(n)
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
示例1
输入:
[9,3,7],[6,3]
返回值:{1,0,0,0}
示例2
输入:\[0],\[6,3]
返回值:{6,3}
## 备注:
1 ≤ n,m ≤ 106
0 ≤ ai,bi ≤ 9
解题思路
先获取两个链表的长度,将longList指针指向长链表,shortList指针指向短链表,根据两个链表的长度差,先将长链表移动到和短链表一样长度的节点位置处,然后使用递归依次按位相加,第i个节点的值为长链表节点value加短链表节点value再加下一步的节点值,值保存在长链表节点处,如果当前节点值大于或等于10,则返回1,同时值减去10,否则返回0,处理完两个链表加法部分后,还要处理结果链长表的进位,对长链表依次进行和加法递归相同的操作,直到到达两个链表加法处理结果的第一个节点处为止。
public int getListLength(ListNode head) {
int len = 0;
ListNode p = head;
while (p != null) {
p = p.next;
len++;
}
return len;
}
public int listAdd(ListNode head1, ListNode head2) {
if (head1 == null || head2 == null) {
return 0;
}
head1.val = head1.val + head2.val + listAdd(head1.next, head2.next);
if (head1.val >= 10) {
head1.val = head1.val - 10;
return 1;
}
return 0;
}
public int singleListAdd(ListNode head, int k) {
if (k < 0 || head == null) {
return 0;
}
head.val = head.val + singleListAdd(head.next, k--);
if (head.val >= 10) {
head.val = head.val - 10;
return 1;
}
return 0;
}
public ListNode addInList (ListNode head1, ListNode head2) {
int len1 = getListLength(head1);
int len2 = getListLength(head2);
ListNode longList = len1 >= len2 ? head1 : head2;
ListNode shortList = len1 < len2 ? head1 : head2;
ListNode res = new ListNode(0);
res.next = len1 >= len2 ? head1 : head2;
int n = len1 > len2 ? len1-len2 : len2-len1;
ListNode pre = res;
for (int i = 0; i < n; i++) {
pre = pre.next;
longList = longList.next;
}
pre.val += listAdd(longList, shortList);
singleListAdd(res, n);
return res.val == 0 ? res.next : res;
}
时间复杂度O(N+M)
空间复杂度O(1)