删除链表中元素
先准备链表对象
public class ListNode {
private int val;
private ListNode prev;
private ListNode next;
public ListNode(int x){
val = x;
}
}
/**
* @description 删除链表[4,5,1,9] 中 5 这个元素
* @param listNode
* @return void
* @date 2022/12/14 14:39
*/
public static void deleteNode(ListNode listNode){
// 当前节点的值改为下个节点的值,例[4,5,1,9]中的5改为1,链表变为[4,1,1,9]
listNode.val = listNode.next.val;
// 删除下个节点,此时,node.next.next从[1,9]变为[9],链表最后为[4,1,9]
listNode.next = listNode.next.next;
}
找到链表中间的元素
利用快慢指针来查找,快指针移动步长=2,慢指针移动步长=1,当快指针移动到末尾,此时慢指针一定在中间元素位置
/**
* @description 找到链表中间的元素
* @param listNode
* @return ListNode
* @date 2022/12/14 14:41
*/
public static ListNode findMiddleNode(ListNode listNode){
//利用快慢指针查找,步长=1的慢指针,和步长=2的快指针
ListNode fast = listNode;
ListNode slow = listNode;
// 检测快指针是否可以安全移动
while (fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next;
}
//步长=2的快指针移到完成后,此时步长=1的指针肯定停留在中间位置
return slow;
}
判断链表是否有环
利用快慢指针查找,快指针移动步长=2,慢指针移动步长=1,如果在遍历过程中,满指针和快指针有重合,那就肯定链表有环
/**
* @description 判断链表是否有环
* @param listNode
* @return boolean
* @date 2022/12/14 15:01
*/
public static boolean hasCircle(ListNode listNode){
ListNode slow = listNode;
ListNode fast = listNode;
//利用快慢指针移动,当快指针和慢指针重合就说明有环
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
return true;
}
}
return false;
}
链表反转
输入:1->2->3->4->5
输出:4->5->3->2->1
利用头插法,把下一个节点存起来插入到头结点,然后指向下下个节点,以此类推,直到末尾节点
public static ListNode reversalList(ListNode head) {
if(head == null){
return null;
}
if(head.next == null){
return head;
}
ListNode next = null;
ListNode pre = null;
while (head != null) {
// 保存要反转插入到头的那个节点
next = head.next;
// 要反转的那个节点指向已经反转的上一个节点(备注:第一次反转的时候会指向null)
head.next = pre;
// 上一个已经反转到头部的节点
pre = head;
// 一直向链表尾走
head = next;
}
return pre;
}
返回链表值不为空的长度
输入: 1->3->5->null
输出: 3
输入: null
输出: 0
public class Solution {
public int countNodes(ListNode head) {
if(head == null){
return 0;
}
int count = 0;
while(head != null){
count ++;
head = head.next;
}
return count;
}
}
从链表尾部向头移动K个位置
输入:1->2->3->4->5 k = 2
输出:4->5->1->2->3
输入:3->2->1 k = 1
输出:1->3->2
记给定链表的长度为 nn,注意到当向右移动的次数 k \geq nk≥n 时,我们仅需要向右移动 k \bmod nkmodn 次即可。因为每 nn 次移动都会让链表变为原状。这样我们可以知道,新链表的最后一个节点为原链表的第 (n - 1) - (k \bmod n)(n−1)−(kmodn) 个节点(从 00 开始计数)。
这样,我们可以先将给定的链表连接成环,然后将指定位置断开。
具体代码中,我们首先计算出链表的长度 nn,并找到该链表的末尾节点,将其与头节点相连。这样就得到了闭合为环的链表。然后我们找到新链表的最后一个节点(即原链表的第 (n - 1) - (k \bmod n)(n−1)−(kmodn) 个节点),将当前闭合为环的链表断开,即可得到我们所需要的结果。
特别地,当链表长度不大于 11,或者 kk 为 nn 的倍数时,新链表将与原链表相同,我们无需进行任何处理。
public ListNode moveK(ListNode head, int k){
if (k == 0 || head == null || head.next == null) {
return head;
}
int n = 1;
ListNode iter = head;
while (iter.next != null) {
iter = iter.next;
n++;
}
int add = n - k % n;
if (add == n) {
return head;
}
iter.next = head;
while (add -- > 0) {
iter = iter.next;
}
ListNode ret = iter.next;
iter.next = null;
return ret;
}