Day8–HOT100–160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
每日刷题系列。今天的题目是力扣HOT100题单。
链表题目。
160. 相交链表
思路【我】:
1,计算链表长度
2,令A为较短链(如果B是短链,交换链表指针p和长度len)
3,长链B先遍历gap个长度
4,开始遍历,返回第一个相等点,遍历结束还没有相等点,就是没有。
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)
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
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
class Solution {public boolean isPalindrome(ListNode head) {// 思路:反转链表+中心扩散法// 找到中间位置mid,分成两半部分来处理// 左半部分,反转链表// 左指针从中间往左遍历,右指针从中间往右遍历// 1,算长度lenint 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现在在中间,向两遍扩散,一旦不相等返回falsewhile (p != null) {if (p.val != right.val) {return false;}p = p.next;right = right.next;}// 5,遍历后,全部相等,返回truereturn true;}
}
876. 链表的中间结点
加餐题目
传统做法,先第一遍遍历找到长度len,第二遍遍历到n/2的位置,判断奇偶数返回对应位置。和我上题的找中间节点的方法是一样的。
但是这道题目,看了题解之后,看到@灵艾山茶府还可以用快慢指针法。
思路【@灵艾山茶府】:
快慢指针法,快指针走的速度是慢指针的2倍,当快指针到n,慢指针就是在中间位置。
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回文链表的做法,也可以直接调用反转链表的方法,和寻找链表中间点的方法:
class Solution {public boolean isPalindrome(ListNode head) {ListNode mid = middleNode(head);ListNode right = reverseList(mid);ListNode left = head;// right:从 mid 到结束// left :从开始到 midwhile (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;}
}