赞
踩
此题我们使用双指针法求解。
首先,我们要知道,倒数的第k个节点,距离倒数第一个节点还需要移动k-1次。
1.那么我们可以定义出两个指针,分别为fast和slow,他们初始均值均为头结点head。
2.先让fast指针向后移动k-1次,slow指针保持不动。
3.接着,fast指针和slow指针同步后移,直至fast指针指向最后一个节点。
4.此时,slow指针所指向的位置就是倒数第k个节点。
原理:这个解题思路的原理就是,fast指针和slow指针始终保持着k-1个移动次数,而当fast指针指向最后一个节点(即倒数第一个节点)时,那么slow指针指向的就是倒数第k个节点。
注意事项:
1.k的值是否合法 2.头指针head是否为null
- public int kthToLast(ListNode head, int k) {
- //当头指针为空时
- if (head == null) {
- return Integer.MAX_VALUE;
- }
-
- //当k的值<=0时
- ListNode cur = head;
- int size = 0;
- while (cur != null) {
- size++;
- cur = cur.next;
- }
- if (k <= 0) {
- return Integer.MAX_VALUE;
- }
-
- //双指针法求解
- ListNode fast = head;
- ListNode slow = head;
-
- //先让fast指针移动k-1次
- int count = 0;
- while (count != k - 1) {
- fast = fast.next;
- //当k值>size时(不合法),fast指针移动的k-1次中,必然会指向null
- if (fast == null) {
- return Integer.MAX_VALUE;
- }
- count++;
- }
-
- //slow和fast同步后移,直至fast指向倒数第一个元素(slow和fast始终保持k-1个移动次数)
- while (fast.next != null) {
- fast = fast.next;
- slow = slow.next;
- }
- //返回val
- return slow.val;
- }

此题我们使用头插法求解。
这道题的思路很简单:从第二个节点开始,每得到一个节点,将此节点进行头插操作。
注意:要将最开始的头结点的next置为null(因为链表的头节点在逆置后就变成了尾结点)
- public ListNode reverseList(ListNode head) {
- //当头结点head为空时
- if (head == null) {
- return head;
- }
- //获取第二个节点,将第一个节点的next置为null
- ListNode cur = head.next;
- head.next = null;
-
- //头插
- while (cur != null) {
- //先获取当前节点的下一个节点
- ListNode curN = cur.next;
- //将当前节点的next指向头结点(头插)
- cur.next = head;
- //将head更新为新头插的节点
- head = cur;
- //更新cur,继续头插
- cur = curN;
- }
-
- //返回逆置后的头结点
- return head;
- }

此题我们使用双指针法求解。
1.我们定义两个指针分别为prev(初始指向head头结点 即第一个节点)和cur(初始指向head的next节点 即第二个节点)。
2.遍历链表。
3.当cur所指节点的值为所要删除的val值时,cur向后移动,prev不动,且将prev的next指针指向移动后的cur,完成节点的删除。
4.若cur所指节点值不是所要删除的val值时,cur和prev同步后移一位。
5.当cur指向null时,遍历完成。
6.经过上述操作,除第一个节点外,其余的节点均已删除完成,我们只需额外判断第一个节点的值是否为要删除的val值即可。
- public ListNode removeElements(ListNode head, int val) {
- //当head为空时
- if(head == null) {
- return head;
- }
-
- //双指针法求解
- ListNode prev = head;
- ListNode cur = head.next;
-
-
- while (cur != null) {
- //判断当前节点的值是否为要删除的val值
- if (cur.val == val) {//若是,删除节点
- cur = cur.next;
- prev.next = cur;
- }else {//若不是,均向后移动
- cur = cur.next;
- prev = prev.next;
- }
- }
- //判断第一个节点的值是否我要删除的val值。
- if (head.val == val) {
- head = head.next;
- }
- //返回删除后的头结点
- return head;
- }

此题我们使用快慢指针法求解。
1.首先,定义两个指针分别为fast和slow。
2.fast指针,每次向后移两位;slow指针,每次向后移一位。
3.链表元素个数为奇数时,当fast.next == null时,slow指向的节点就是中间节点;链表元素个数为偶数时,当fast == null时,slow指向的节点就是中间节点。
注意:
循环结束条件一定要写为:
while(fast != null && fast.next != null)
原因:
1.两者只要有一个不满足就要结束循环,说明已经找到了中间节点
2.一定要fast != null在前,避免fast.next时出现空指针异常
- public ListNode middleNode(ListNode head) {
- //快慢指针法求解
- ListNode slow = head;
- ListNode fast = head;
-
- //找中间节点
- //一定要fast != null在前,避免出现空指针异常
- //两个条件只要有一个不满足就结束循环,说明到了中间节点的位置
- while (fast != null && fast.next != null) {
- ListNode fastN = fast.next;
- fast = fastN.next;
- slow = slow.next;
- }
-
- //返回中间节点
- return slow;
- }

给定 x, 把一个链表整理成前半部分小于 x, 后半部分大于等于 x 的形式
1.将链表进行遍历
2.将val < x的节点添加到新链表head1中
3.将val >= x的节点添加到新链表head2中
4.将head1和head2进行拼接
5.返回拼接后新表的头结点head1
注意:
1.无论如何,一定要将head2的最后一个节点next域置为null
2.当表中所以元素的val值都大于等于x时,那么head1将为空表,直接返回head2即可
- public ListNode partition(ListNode pHead, int x) {
- //当pHead为空时
- if (pHead == null) {
- return null;
- }
-
- ListNode cur = pHead;
- ListNode prev = null;
- ListNode head1 = null;
- ListNode head2 = null;
- ListNode cur1 = null;
- ListNode cur2 = null;
-
- //遍历链表 将val < x的节点添加到新表head1中
- //将val >= x的节点添加到新表head2中
- while (cur != null) {
- if (cur.val < x) {
- if (head1 == null) {
- head1 = cur1 = cur;
- }else {
- cur1.next = cur;
- cur1 = cur1.next;
- }
- }else {
- if (head2 == null) {
- head2 = cur2 = cur;
- }else {
- cur2.next = cur;
- cur2 = cur2.next;
- }
- }
- cur = cur.next;
- }
-
- //注意:需要将head2的最后一个节点的next置为null
- if(head2 != null) {
- cur2.next = null;
- }
- //如果旧表中所有元素的val值都大于x,那么head1将会是空表,直接返回head2即可
- if (head1 == null) {
- return head2;
- }
- //将head1和head2进行拼接
- cur1.next = head2;
- return head1;
- }

回文结构,其实就是对称结构:
当元素个数为奇数时:
1.找到中间节点(使用上面的例题已经讲到)
2.以中间节点为头,逆置其后链表
3.逆置后,链表存在下图结构,指针从两端开始比较val值是否相等,直到相遇时结束,若均相等则为回文结构。
当元素个数为偶数时:
1.偶数时,newH和slow无法相遇
2.我们只需额外判断 当 newH.next == slow 时,说明为回文结构。
- public boolean chkPalindrome(ListNode A) {
- // write code here
- if (A == null) {
- return true;
- }
- ListNode fast = A;
- ListNode slow = A;
-
- //找中间节点
- while (fast != null && fast.next != null) {
- fast = fast.next.next;
- slow = slow.next;
- }
-
- //逆置中间节点后的链表
- ListNode cur = slow.next;
- ListNode curN = null;
- while (cur != null) {
- curN = cur.next;
- cur.next = slow;
- slow = cur;
- cur = curN;
- }
-
- //从两端开始遍历,比较值是否相等
- ListNode newCur = A;
- while (slow != newCur) {
- if (slow.val != newCur.val) {
- return false;
- }
- if (newCur.next == slow) {
- return true;
- }
- slow = slow.next;
- newCur = newCur.next;
- }
- return true;
- }

首先,我们要知道,相交链表的形状为Y形,而非X形:
1.遍历求出各链表的长度,并求得长度的差值len。
2.将较长链表的头指针向后移动len个位置。
3.两个链表的头指针同时后移,会在交点处相遇。
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode curA = headA;
- ListNode curB = headB;
- int lenA = 0;
- int lenB = 0;
- //求链表1的长度
- while (curA != null) {
- lenA++;
- curA = curA.next;//curA发生改变
- }
- //求链表2的长度
- while (curB != null) {
- lenB++;
- curB = curB.next;//curB发生改变
- }
-
- //将curA和curB重新指向链表的起始位置
- curA = headA;
- curB = headB;
-
- //差值
- int len = lenA - lenB;
-
- //将较长的链表头指针后移差值个长度
- if (len < 0) {
- len = -len;
- while (len != 0) {
- curB = curB.next;
- len--;
- }
- }else {
- while (len != 0) {
- curA = curA.next;
- len--;
- }
- }
-
- //相遇处即为交点
- while (curA != curB) {
- curA = curA.next;
- curB = curB.next;
- }
- return curA;
- }

此题我们使用快慢指针法求解。
1.定义fast为快指针,一次移动两个位置;slow为慢指针,一次移动一个位置。
2.若链表带环,那么这两个指针必定相遇(追击问题)。
注意:
因为fast一次走两步,slow一次走一步,那进入环中后,每次移动,fast和slow之间的距离必定缩短一个节点,那么必定相遇。
(若每次移动两者间缩短的距离不为1时,那么即使有环,也可能不会相遇)
- public boolean hasCycle(ListNode head) {
- ListNode fast = head;
- ListNode slow = head;
-
- //判断是否相遇
- while (fast != null && fast.next != null) {
- fast = fast.next.next;
- slow = slow.next;
- if (fast == slow) {
- return true;
- }
- }
- return false;
- }
设:
起点到入口点的长度为X
相遇节点到入口点长度为Y
环的长度为C
因为fast所走路程为slow所走路程的两倍
故:
X + n*C + (C - Y) = 2*(X + C - Y)
则:
X + (2-n)*C = Y
说明:相遇节点到入口点的距离和起点到入口点的距离相等
则,从相遇节点和起点开始相向而行,相遇时的节点就是入口点
注意:我们还需要处理不是环的情况!!!
- public ListNode detectCycle(ListNode head) {
- //head为空时
- if (head == null) {
- return head;
- }
-
- ListNode fast = head;
- ListNode slow = head;
-
- //确定相遇时的节点
- while (fast != null && fast.next != null) {
- fast = fast.next.next;
- slow = slow.next;
- if (fast == slow) {
- break;
- }
- }
- //不是环
- if (fast == null || fast.next == null) {
- return null;
- }
- //从起点和相遇节点开始相向而行,相遇的节点就是入口点
- ListNode curH = head;
- while (curH != slow) {
- curH = curH.next;
- slow = slow.next;
- }
- return slow;
- }

思路很简单,就是从各链表起点开始遍历,比较val值,谁的值小,就插入到新链表当中。
若某一链表的元素全部插入新链表当中后,将另一链表剩余元素直接拼接即可。
- public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
- //链表为空时
- if (list1 == null) {
- return list2;
- }
- if (list2 == null) {
- return list1;
- }
-
- ListNode cur1 = list1;
- ListNode cur2 = list2;
- ListNode newH = null;
- ListNode newCur = null;
-
- //从头遍历各链表 谁值小 谁就尾插到新链表中
- while (cur1 != null && cur2 != null) {
- if (cur1.val < cur2.val) {
- if (newH == null) {
- newH = newCur = cur1;
- }else {
- newCur.next = cur1;
- newCur = newCur.next;
- }
- cur1 = cur1.next;
- }else {
- if (newH == null) {
- newH = newCur = cur2;
- }else {
- newCur.next = cur2;
- newCur = newCur.next;
- }
- cur2 = cur2.next;
- }
- }
-
- //某一链表的元素全部插入后,将另一链表剩余元素直接拼接即可
- if (cur1 == null) {
- newCur.next = cur2;
- }
- if (cur2 == null) {
- newCur.next = cur1;
- }
- return newH;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。