学习资料:
两两交换链表中节点
重点是画图把哪个指针指哪里弄清楚 思路:三指针实现两个元素,分别指向对应元素以及前一个实现互换。
// 定义头节点
ListNode h = new ListNode(-1,head);
// 指针
ListNode pre = h;
ListNode cur1;
ListNode cur2;
while (pre.next != null && pre.next.next != null){
// 定义位置
cur1 = pre.next;
cur2 = pre.next.next;
// 交换位置
cur1.next = cur2.next;
cur2.next = cur1;
pre.next = cur2;
pre = cur1;
}
return h.next;
19 删除链表的倒数第N个节点
自己做:
思路:
- 遍历链表,得出size,从而获得索引
- 继续遍历,删除指定元素
这种方法无疑时间复杂度达到了O(n2)
看文档
巧妙地运用倒数第n个的特点解决问题。 思路: 双指针:设置两个指针间距为n,当遍历完链表后前指针即为倒数第n个元素
// 方法1:
/*
* 遍历链表,得出size,从而获得索引
* 继续遍历,删除索引元素
* */
// 方法2:
/*
* 设置两个指针间距为n,当遍历完链表后前指针即为倒数第n个元素
* */
// 定义头节点
ListNode h = new ListNode(-1,head);
ListNode low = head;
ListNode fast = low;
ListNode pre = h;
for (; n - 1 > 0;n--){
fast = fast.next;
}
while (fast.next != null){
pre = pre.next;
fast = fast.next;
low = low.next;
}
// 删除节点
System.out.println(pre.val);
System.out.println(low.val);
System.out.println(fast.val);
pre.next = low.next;
return h.next;
160 相交链表
自己写:
- 疑惑:为什么例子中
listA = [4,1,8,4,5] listB = [5,6,1,8,4,5] 相交在 8 而不在 1
✅解决:用System.out.print打印两个数组每个元素地址值:(由于篇幅简化了地址值)
@5fcfe4b2 @6bf2d08e @5eb5c224 @53e25b76 @73a8dfcc @ea30797 @7e774085 @3f8f9dd6 @aec6354 @1c655221 @53e25b76 @73a8dfcc @ea30797
可以看出从 8 开始地址值相同,而 1 地址值是不同的,因此在 8 中相交 据此可以想成:只认地址值不认数值
因此思路很清晰:两个数组遍历,找到地址值相同的节点连接
- 疑惑2:如何找到相同节点的地址
✅解决:由于最后相交后两个列表长度相同,因此使两个列表右对齐后,按较短的第一个节点开始遍历。
代码:
//定义头节点
ListNode h1 = new ListNode(-1);
h1.next = headA;
ListNode h2 = new ListNode(-1);
h2.next = headB;
ListNode cur1 = h1;
ListNode cur2 = h2;
// 右对齐数组
// 获取两个数组长度 - 确定较长的数组
int count1 = 0, count2 = 0;
while (cur1.next != null){
count1++;
cur1 = cur1.next;
}
while (cur2.next != null){
count2++;
cur2 = cur2.next;
}
// cur指针归位
cur1 = h1;
cur2 = h2;
// 使较长数组为1
if (count2 > count1){
// 数组交换
ListNode temp = cur1;
cur1 = cur2;
cur2 = temp;
// 计算的长度也要交换!
int temp1 = count1;
count1 = count2;
count2 = temp1;
}
// 使listA指针对齐
int gap = count1 - count2;
for (int i = 0; i < gap; i++) {
cur1 = cur1.next;
}
// 开始遍历,寻找地址相同
while (cur1 != null){
// 在此点相交
if (cur1 == cur2){
return cur2;
}
cur1 = cur1.next;
cur2 = cur2.next;
}
return null;
142 环形链表Ⅱ
自己写:
- 如何判断有环
逐一遍历判断?时间复杂度O(n2)
- 判断尾节点指向哪一个节点
看视频
手写笔记:
✅使用快慢双指针判断是否有环:根据定义
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
环如同田径场,如果两人跑步速度不同,最后肯定会相遇
假设slow 每次只走一个单位 fast每次走2 或者更多 个单位 设环里有a个元素
难点:
- 快慢指针会在第一圈内相遇,即k = 0?
✅原因:
当fast 在环中:
fast > a 时,实际在环里位移是 fast % a < a,因此fast ∈ [1,a - 1]
那么也就说,至多走a - 1次就会相遇,而此时slow还没有走完一圈
有种特殊情况(当然不需要理会,只是会出现情况),
slow会走完一圈,当fast刚好等于a且x也等于a的情况下,但这不影响后面的计算。
- 为什么
fast再快速度相遇时也会满足x = z
✅根据公式推导可得出,n = 1时 x = z ;而无论n等于几,也只是转圈,最终回到原位。因此还是x = z,就可以利用这一性质求得相交点
而在上面说的特殊情况,可以看作z = 一圈的距离(而非等于零,所以说不影响后面计算)
- 需要一定数学基础,寻找规律
代码:
ListNode cur1 = head;
ListNode cur2 = head;
// 判断是否有环
while (cur2 != null && cur2.next != null){
cur1 = cur1.next;
cur2 = cur2.next.next;
if (cur1 == cur2){
// 有环 - 且头节点与此位置到相交点距离相同
ListNode index1 = head;
ListNode index2 = cur1;
while (index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;