Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
每日刷题系列。今天的题目是力扣HOT100题单。
链表题目。
160. 相交链表
思路【我】:
1,计算链表长度
2,令A为较短链(如果B是短链,交换链表指针p和长度len)
3,长链B先遍历gap个长度
4,开始遍历,返回第一个相等点,遍历结束还没有相等点,就是没有。
java
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 思路:末端对齐,也就是长链先遍历gap个长度
// 然后遍历,返回第一个相等点,遍历结束还没有相等点,就是没有。
ListNode pa = new ListNode();
ListNode pb = new ListNode();
// 1,计算链表长度
int lenA = 0;
int lenB = 0;
pa = headA;
pb = headB;
while (pa != null) {
pa = pa.next;
lenA++;
}
while (pb != null) {
pb = pb.next;
lenB++;
}
// 2,令A为较短链(如果B是短链,交换链表指针p和长度len)
pa = headA;
pb = headB;
if (lenA > lenB) {
int temp = lenA;
lenA = lenB;
lenB = temp;
ListNode tem = pa;
pa = pb;
pb = tem;
}
// 3,长链B先遍历gap个长度
int gap = lenB - lenA;
while (gap-- > 0) {
pb = pb.next;
}
// 4,开始遍历
while (pa != null) {
if (pa == pb) {
return pa;
}
pa = pa.next;
pb = pb.next;
}
return null;
}
}
思路【@灵艾山茶府】:
p和q终会相等,要么在交点,要么都是null。
- 假设A链条长度为x+z,B链表长度为y+z,其中z为相交后共同的长度。
- 如果相交在交点,那么走过的路:p为x+z+y,q为y+z+x。
- 如果相等在null,那么走过的路:p为x+y,q为y+x。(此时没有z)
java
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p = headA;
ListNode q = headB;
while (p != q) {
p = p != null ? p.next : headB;
q = q != null ? q.next : headA;
}
return p;
}
}
206. 反转链表
思路【我】:
需要一个pre指针作为辅助,pre需要初始化为null不能为new ListNode(),因为这是反转后的尾巴,如果是new ListNode的话会多了一个节点。
- 当指针p不为空的时候,遍历。
- 需要temp缓存p.next,即下一个要反转的对象
- 然后将p.next往前指向pre
- pre指针到下一个对象,即p
- p指针到下一个对象,即temp
- 最后当p为null的时候,证明pre是原链表的结尾,返回pre
java
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode p = head;
while (p != null) {
ListNode temp = p.next;
p.next = pre;
pre = p;
p = temp;
}
return pre;
}
}
234. 回文链表
思路【我】:
反转链表+中心扩散法。
1,算长度len
2,反转左半部分
3,p是左半部分最后一位,temp=p.next,也就是右半部分的第一位了,所以right指向它。(如果len为奇数,temp是中间位置,中间位置的元素不用管,所以指针right = temp.next)
4,开始遍历。p和right现在在中间,向两遍扩散,一旦不相等返回false
5,遍历后,全部相等,返回true
java
class Solution {
public boolean isPalindrome(ListNode head) {
// 思路:反转链表+中心扩散法
// 找到中间位置mid,分成两半部分来处理
// 左半部分,反转链表
// 左指针从中间往左遍历,右指针从中间往右遍历
// 1,算长度len
int len = 0;
ListNode p = head;
while (p != null) {
p = p.next;
len++;
}
if (len == 1) {
return true;
}
// 2,反转前半部分
ListNode pre = null;
p = head;
// 这个temp本来是可以在循环体内的临时变量,但是下面需要用到,所以在外部定义.
ListNode temp = p.next;
for (int i = 0; i < len / 2; i++) {
temp = p.next;
p.next = pre;
pre = p;
// 这个if是为了,让p留在左半部分的最后一位
// p就是左半部分,反转后,链表的头
if (i + 1 == len / 2) {
break;
}
p = temp;
}
// 3,p是左半部分最后一位,temp=p.next,也就是右半部分的第一位了,所以right指向它
ListNode right;
if (len % 2 == 0) {
right = temp;
} else {
// 如果len为奇数,temp是中间位置,中间位置的元素不用管,所以指针right指向下一个
right = temp.next;
}
// 4,开始遍历。p和right现在在中间,向两遍扩散,一旦不相等返回false
while (p != null) {
if (p.val != right.val) {
return false;
}
p = p.next;
right = right.next;
}
// 5,遍历后,全部相等,返回true
return true;
}
}
876. 链表的中间结点
加餐题目
传统做法,先第一遍遍历找到长度len,第二遍遍历到n/2的位置,判断奇偶数返回对应位置。和我上题的找中间节点的方法是一样的。
但是这道题目,看了题解之后,看到@灵艾山茶府还可以用快慢指针法。
思路【@灵艾山茶府】:
快慢指针法,快指针走的速度是慢指针的2倍,当快指针到n,慢指针就是在中间位置。
java
class Solution {
public ListNode middleNode(ListNode head) {
// 快慢指针法,快指针走的速度是慢指针的2倍,当快指针到n,慢指针就是在中间位置
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
由此,234回文链表的做法,也可以直接调用反转链表的方法,和寻找链表中间点的方法:
java
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode mid = middleNode(head);
ListNode right = reverseList(mid);
ListNode left = head;
// right:从 mid 到结束
// left :从开始到 mid
while (right != null) {
if (left.val != right.val) {
return false;
}
left = left.next;
right = right.next;
}
return true;
}
// 876. 链表的中间结点
private ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
// 206. 反转链表
private ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
}