codeTop链表刷题记录

反转链表

反转链表需要会两种,一种是迭代,一种是递归。这里来看一下这两种的解法:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

迭代做法:我们考虑一下如何反转呢,反转即把原来的next指向反向,即原来是 1.next = 2变成2.next = 1,但next指针只要改变我们就无法找到下一节点,即 1 -> 2 -> 3 1.next =2  改为 2.next = 1 就变成 1<-2  3 3就变成孤魂,直接被垃圾回收掉,所以我们需要记录下一个节点是什么,然后不断移动两个节点的指向即可,移到什么时候结束呢,移动到最后的节点为null,可以简单已 1->2->null 举例  pre =null  1 = cur  tmp = 2   1.next = null ;  pre = 1 cur = 2 tmp = null  2.next = 1,此时全部移动结束,然后就可以跳出了,此时 cur再往前为null,即 pre = 2 cur = null tmp = null ,此时跳出,返回pre指针。 

// 迭代需要谨记一点: 反转链表结束后,pre 指向末尾, cur 指向下一段链表的开头或者null
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head, pre = null;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

 递归做法:

对于递归算法,最重要的就是明确递归函数的定义。具体来说,我们的 reverse 函数定义是这样的:

输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点

明白了函数的定义,再来看这个问题。比如说我们想反转这个链表:

那么输入 reverse(head) 后,会在这里进行递归:

ListNode last = reverse(head.next);

不要跳进递归(你的脑袋能压几个栈呀?),而是要根据刚才的函数定义,来弄清楚这段代码会产生什么结果:

这个 reverse(head.next) 执行完成后,整个链表就成了这样:

并且根据函数定义,reverse 函数会返回反转之后的头结点,我们用变量 last 接收了。

现在再来看下面的代码:

Copy

head.next.next = head;

接下来:

Copy

head.next = null;
return last;

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
 // 递归解法: 是递归问题吗?可以看到反转一个元素是里面一个子问题,一个总问题可以拆解成反转子问题,且相互独立,所以可以使用递归去解
class Solution {
    // 明确定义: 给一个头节点,反转以这个头结点为开始的所有元素,并且返回反转之后的头结点
    public ListNode reverseList(ListNode head) {
        // base case
        if (head == null) {
            return head;
        }
        // 要返回的末尾元素,即头结点,只有找到这个头结点,才不会被JVM回收
        if (head.next == null) {
            return head;
        }
        // 递归  反转下一个元素是什么? reverseList(head.next)
        // 假设以1为头, head.next = 2 , 后面的链表都反转结束后,此节点需要做什么操作呢? 1 -> 2 <-3 <-4 <-5  2 -> null  1为head last为反转后的头结点
        ListNode last = reverseList(head.next);
        
        // 递归之后
         head.next.next = head;
        head.next = null;
        return last;
    }
}

反转双向链表

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head, pre = null;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            cur.last = nxt;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}
//双向链表反转,递归反转
public DoubleListNode reverse2(DoubleListNode head) {  //参数传入链表的头指针(不带头结点)
	if(head==null || head.next==null)
		return head;
	DoubleListNode temp = reverse2(head.next);
	head.next.next = head;
	head.last = head.next;
	return temp;
}

反转链表II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode dummy = new ListNode(0, head);
        ListNode p0 = dummy;
        // 先找到前一个节点,反转之后需要续接
        for (int i = 0; i < left - 1; i++) {
            p0 = p0.next;
        }
        // 需要反转的元素是 right - left + 1个元素,需要循环 right - left + 1 次,可以举例
        ListNode pre = null, cur = p0.next;
        for (int i = 0; i < right - left + 1; i++) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        //  1 -> 2 <-3 <-4  5  cur = 5 pre = 4 
        p0.next.next = cur;
        p0.next = pre;
        return dummy.next;

    }
}
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    // 定义: 给一个头节点,整数left,整数right,反转left到right之间内的元素,并返回头节点
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // left = 1,反转前right个元素
        if (left == 1) {
            return reverseN(head, right);
        }
        // 递归
        head.next = reverseBetween(head.next, left -1, right - 1);
        // 递归后
        return head;
    }

    ListNode succssor = null;
    //定义:给一个头结点head,反转前n个元素,并且返回反转后的头节点
    private ListNode reverseN(ListNode head, int n) {
        if (n == 1) {
            succssor = head.next;
            return head;
        }
        // 递归
        ListNode last = reverseN(head.next, n - 1);
        // 递归后
        head.next.next = head;
        head.next = succssor;
        return last;
    }
}

K个一组反转链表

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        // 先获取有多少个元素,小于K个的时候不需要反转
        int n = 0;
        ListNode p = head;
        while (p != null) {
            p = p.next;
            n++;
        }
        ListNode dummy = new ListNode(0, head);
        ListNode p0 = dummy;
        ListNode pre = null, cur = head;
        for (;n>=k; n-=k) {
            for (int i = 0; i < k; i++) {
                ListNode nxt = cur.next;
                cur.next = pre;
                pre = cur;
                cur = nxt;
            }
            ListNode next = p0.next;
            p0.next.next = cur;
            p0.next = pre;
            p0 = next;
        }
        return dummy.next;
        
    }
}

class Solution {
    // 定义: 以head节点为头,并且k个元素反转链表,且返回反转后的头部
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode tail = head;
        for (int i = 0;i <k; i++) {
            if (tail == null) {
                return head;
            }
            tail = tail.next;
        }
        // 左闭右开
        ListNode newHead = reverse(head, tail);

        head.next = reverseKGroup(tail, k);
        return newHead;
    }

    private ListNode reverse(ListNode head, ListNode tail) {
        ListNode pre = null;
        ListNode next = null;
        while (head != tail) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;

    }
}

合并两个链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode(-1);
        ListNode p = dummy, p1 = list1, p2 = list2;
        while (p1 != null && p2 != null) {
            if (p1.val > p2.val) {
                p.next = p2;
                p2 = p2.next;
            }else {
                p.next = p1;
                p1 = p1.next;
            }
            p = p.next;
        }
        if (p1 != null) {
            p.next = p1;
        }
        if (p2 != null) {
            p.next = p2;
        }
        return dummy.next;

    }
}
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    // 定义:给定两个链表,按照元素值大小从头到尾拼接到一起,并且返回头结点
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // base case
        if (list1 == null) {
            return list2;
        }
        if (list2 == null) {
            return list1;
        }

        // 递归  当list1元素值小的时候,应该使用list1的值,合并list1.next和list2
        if (list1.val < list2.val) {
            list1.next = mergeTwoLists(list1.next, list2);
            return list1;
        }else {
            list2.next = mergeTwoLists(list1, list2.next);
            return list2;
        }


        // 递归后

       
    }
}

合并k个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) {
            return null;
        }
        ListNode dummy = new ListNode(-1);
        ListNode p = dummy;

        PriorityQueue<ListNode> pq = new PriorityQueue<>(
            lists.length, (a, b) -> (a.val - b.val)
        );
        for (ListNode head: lists) {
            if (head != null) {
                pq.add(head);
            }
        }
        while (!pq.isEmpty()) {
            ListNode node = pq.poll();
            p.next = node;
            if (node.next != null) {
                pq.add(node.next);
            }
            p = p.next;
        }
        return dummy.next;
    }
}

class Solution {
    // 最朴素的方法,就是两个链表,两个链表合并
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode ans = null;
        for (int i = 0; i < lists.length; i++) {
            ans = mergeTwoLists(ans, lists[i]);
        }
        return ans;
    }

    private ListNode mergeTwoLists(ListNode a, ListNode b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        ListNode dummy = new ListNode(0);
        ListNode p = dummy, p1 = a, p2 = b;
        while (p1 != null && p2 != null) {
            if (p1.val < p2.val) {
                p.next = p1;
                p1 = p1.next;
            }else {
                p.next = p2;
                p2 = p2.next;
            }
            p = p.next;
        }
        if (p1 != null) {
            p.next = p1;
        }
        if (p2 != null) {
            p.next = p2;
        }
        return dummy.next;
    }
}
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) {
            return null;
        }
        return mergeKLists(lists, 0, lists.length);
    }
    // 定义:给定一个链表数组,两两合并链表
    private ListNode mergeKLists(ListNode[] lists, int i, int j) {
        // base case 什么时候递归结束?
        int m = j - i;
        if (m == 1) {
            return lists[i];
        }
        // 递归
        ListNode left = mergeKLists(lists, i, i + m / 2);
        ListNode right = mergeKLists(lists, i + m / 2, j);
        // 递归后
        return mergeTwoLists(left, right);
    }
    private ListNode mergeTwoLists(ListNode left, ListNode right) {
        ListNode dummy = new ListNode(0);
        ListNode p = dummy, p1 = left, p2 = right;
        while (p1 != null && p2 != null) {
            if (p1.val < p2.val) {
                p.next = p1;
                p1 = p1.next;
                p = p.next;
            }else {
                p.next = p2;
                p2 = p2.next;
                p = p.next;
            }
        }
        if (p1 != null) {
            p.next = p1;
        }
        if (p2 != null) {
            p.next = p2;
        }
        return dummy.next;
    }
}

给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。

请你将 list1 中下标从 a 到 b 的全部节点都删除,并将list2 接在被删除节点的位置。

下图中蓝色边和节点展示了操作后的结果:

请你返回结果链表的头指针。

示例 1:

输入:list1 = [0,1,2,3,4,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]
输出:[0,1,2,1000000,1000001,1000002,5]
解释:我们删除 list1 中下标为 3 和 4 的两个节点,并将 list2 接在该位置。上图中蓝色的边和节点为答案链表。
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
        ListNode preA = list1;
        for (int i = 0; i < a -1; i++) {
            preA = preA.next;
        }
        ListNode preB = preA;
        for (int i = 0; i < b -a + 2; i++) {
            preB = preB.next;
        }
        preA.next = list2;
        ListNode p = list2;
        while (p.next != null) {
            p = p.next;
        }
        p.next = preB;
        return list1;
    }
}

环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }
}

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast) {
                break;
            }
        }
        if (fast == null || fast.next == null) {
            return null;
        }
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

给定一个头节点为 head 的链表用于记录一系列核心肌群训练项目编号,请查找并返回倒数第 cnt 个训练项目编号。

示例 1:

输入:head = [2,4,7,8], cnt = 1
输出:8

从前往后寻找单链表的第 k 个节点很简单,一个 for 循环遍历过去就找到了,但是如何寻找从后往前数的第 k 个节点呢?

那你可能说,假设链表有 n 个节点,倒数第 k 个节点就是正数第 n - k + 1 个节点,不也是一个 for 循环的事儿吗?

是的,但是算法题一般只给你一个 ListNode 头结点代表一条单链表,你不能直接得出这条链表的长度 n,而需要先遍历一遍链表算出 n 的值,然后再遍历链表计算第 n - k + 1 个节点。

也就是说,这个解法需要遍历两次链表才能得到出倒数第 k 个节点。

那么,我们能不能只遍历一次链表,就算出倒数第 k 个节点?可以做到的,如果是面试问到这道题,面试官肯定也是希望你给出只需遍历一次链表的解法。

这个解法就比较巧妙了,假设 k = 2,思路如下:

首先,我们先让一个指针 p1 指向链表的头节点 head,然后走 k 步:

现在的 p1,只要再走 n - k 步,就能走到链表末尾的空指针了对吧?

趁这个时候,再用一个指针 p2 指向链表头节点 head

接下来就很显然了,让 p1 和 p2 同时向前走,p1 走到链表末尾的空指针时前进了 n - k 步,p2 也从 head 开始前进了 n - k 步,停留在第 n - k + 1 个节点上,即恰好停链表的倒数第 k 个节点上:

这样,只遍历了一次链表,就获得了倒数第 k 个节点 p2

class Solution {
    public ListNode trainingPlan(ListNode head, int k) {
        ListNode p1 = head;
        for (int i = 0; i < k; i++) {
            p1 = p1.next;
        }
        ListNode p2 = head;
        while (p1 != null) {
            p2 = p2.next;
            p1 = p1.next;
        }
        return p2;
    }
}

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(-1, head);
        // 为什么传入dummy节点呢? 前面加几个元素,倒数第三个还是第三个,倒数是不会变的
        ListNode x = findNEnd(dummy, n + 1);
        x.next = x.next.next;
        return dummy.next;
    }
    private ListNode findNEnd(ListNode head, int k) {
        ListNode p = head;
        for (int i = 0; i < k; i++) {
            p = p.next;
        }
        ListNode p1 = head;
        while (p != null) {
            p1 = p1.next;
            p = p.next;
        }
        return p1;
    }
}

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

示例 1:

输入:head = [1,1,2]
输出:[1,2]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode slow = head, fast = head;
        while (fast != null) {
            if (slow.val != fast.val) {
                slow.next = fast;
                slow = slow.next;
            }
            fast = fast.next;
        }
        slow.next = null;
        return head;
    }
}

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    // 定义:给定head节点,删除重复元素,并返回删除之后的头结点
    public ListNode deleteDuplicates(ListNode head) {
        //base case
        if (head == null || head.next == null) {
            return head;
        }
        // 递归
        head.next = deleteDuplicates(head.next);
        // 递归后 后面已经没重复元素,看第一个元素,与后面的元素是否一致
        return head.val == head.next.val ? head.next : head;


    }
}

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

示例 1:

输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

示例 2:

输入:head = [1,1,1,2,3]
输出:[2,3]
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode dummy = new ListNode(0, head);
        ListNode p = dummy;
        while (p.next != null && p.next.next != null) {
          if (p.next.val == p.next.next.val) {
            int x = p.next.val;
            while (p.next != null && p.next.val == x) {
              p.next = p.next.next;
            }
          }else {
            p = p.next;
          }
        }
        return dummy.next;
    }
}

class Solution {
    // 定义:去除以head为头的重复元素,并且返回去重元素后的头结点
    public ListNode deleteDuplicates(ListNode head) {
        // base case
        if (head == null || head.next == null) {
          return head;
        }
        // 如何递归,从哪递归呢?需要判断第一个元素和第二个元素相不相等
        if (head.val != head.next.val) {
          head.next = deleteDuplicates(head.next);
          return head;
        }
          // 如果如果头结点和身后节点的值相同,则说明从 head 开始存在若干重复节点
        // 越过重复节点,找到 head 之后那个不重复的节点
        while (head.next != null && head.next.val == head.val) {
          head =head.next;
        }
        // 递归
        ListNode last = deleteDuplicates(head.next);
        // 递归后
        return last;
    }
}
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        Map<Integer, Integer> map = new HashMap<>();
        ListNode p = head;
        while (p != null) {
            map.put(p.val, map.getOrDefault(p.val, 0) + 1);
            p = p.next;
        }
        ListNode dummy = new ListNode(-1, head);
        p = dummy;
        while (p != null) {
            ListNode unqiue = p.next;
            while (unqiue != null && map.get(unqiue.val) > 1) {
                unqiue = unqiue.next;
            }
            p.next = unqiue;
            p = p.next;
        }
        return dummy.next;
    }
}

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        ListNode dummy = new ListNode(-1, head);
        ListNode p = dummy;
        while (p.next != null) {
            if (p.next.val == val) {
                p.next = p.next.next;
            }else {
                p = p.next;
            }
        }
        return dummy.next;
    }
}
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        head.next = removeElements(head.next, val);
        return head.val == val ? head.next : head;
    }
}

有一个单链表的 head,我们想删除它其中的一个节点 node

给你一个需要删除的节点 node 。你将 无法访问 第一个节点  head

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

  • 给定节点的值不应该存在于链表中。
  • 链表中的节点数应该减少 1。
  • node 前面的所有值顺序相同。
  • node 后面的所有值顺序相同。

自定义测试:

  • 对于输入,你应该提供整个链表 head 和要给出的节点 nodenode 不应该是链表的最后一个节点,而应该是链表中的一个实际节点。
  • 我们将构建链表,并将节点传递给你的函数。
  • 输出将是调用你函数后的整个链表。

示例 1:

输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

输入:head = [1,2,3,4]
输出:[1,4,2,3]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 // 1 -> 2-> 3 <-4
 // head1 = 1  head2 = 4
 // head1.next = nxt;
 // head.next = head2;
 // head2.next = nxt;
 // 
 */
class Solution {
    public void reorderList(ListNode head) {
        ListNode mid = middle(head);
        ListNode head2 = reverse(mid);
        while (head2.next != null) {
            ListNode nxt = head.next;
            ListNode nxt2 = head2.next;
            head.next = head2;
            head2.next = nxt;
            head = nxt;
            head2 = nxt2;
        }
    }

    private ListNode middle(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    private ListNode reverse(ListNode head) {
        ListNode pre = null, cur = head;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 // cur = 1 next = 2 last = 5  1 -> 5 -> 2
 // cur = 2 next = 3 last = 4  1 -> 5 -> 2 -> 4 -> 3
 // cur = 3 next = 4 last = 3  3.next = 4

 // cur = 1 next = 2 last = 4  1 -> 4 -> 2
 // cur = 2 next = 3  last = 3  1 -> 4 -> 2 -> 3
 */
class Solution {
    public void reorderList(ListNode head) {
        Stack<ListNode> stk = new Stack<>();
        ListNode p = head;
        while (p != null) {
            stk.push(p);
            p = p.next;
        }
        p = head;
        while (p != null) {
            ListNode last = stk.pop();
            ListNode next = p.next;
            if (last == next || last.next == next) {
                last.next = null;
                break;
            }
            p.next = last;
            last.next = next;
            p = next;
        }
    }
}

给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。

插入排序 算法的步骤:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。

对链表进行插入排序。

示例 1:

输入: head = [4,2,1,3]
输出: [1,2,3,4]
class Solution {
    public ListNode insertionSortList(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode dummy = new ListNode(-1, head);
        ListNode lastNode = head, curr = head.next;
        while (curr != null) {
            if (lastNode.val <= curr.val) {
                lastNode = lastNode.next;
                curr = lastNode.next;
            }else {
                // 找到要插入位置的前一个位置
                ListNode prev = dummy;
                while (prev.next != null && prev.next.val <= curr.val) {
                    prev = prev.next;
                }
                // -1 4 5 3 2  curr = 3 nxt = 2 prev = -1 
                lastNode.next = curr.next;
                curr.next = prev.next;
                prev.next = curr;
                curr = lastNode.next;
            }
        }
        return dummy.next;
    }
}

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]
class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        // 寻找中点
        ListNode fast = head, slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode tmp = slow.next;
        // 链表要切开,先切开再合并
        slow.next = null;
        // [left, slow] [tmp, right]
        // 左边递归拆分,并且返回左头节点
        ListNode left = sortList(head);
        // 右边递归拆分,并切返回右头节点
        ListNode right = sortList(tmp);
        // 合并最后的链表
        ListNode dummy = new ListNode(0);
        ListNode p1 = left, p2 = right, p = dummy;
        while (p1 != null && p2 != null) {
            if (p1.val <= p2.val) {
                p.next = p1;
                p1 = p1.next;
                p = p.next;
            }else {
                p.next = p2;
                p2 = p2.next;
                p = p.next;
            }
        }
        if (p1 != null) {
            p.next = p1;
        }
        if (p2 != null) {
            p.next = p2;
        }
        return dummy.next;

    }
}

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

示例 1:

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]
class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode dummy1 = new ListNode(-1);
        ListNode dummy2 = new ListNode(-1);
        ListNode p1 = dummy1, p2 =dummy2, p = head;
        while (p != null) {
            if (p.val < x) {
                p1.next = p;
                p1 = p1.next;
            }else {
                p2.next = p;
                p2 = p2.next;
            }
            ListNode tmp = p.next;
            p.next = null;
            p = tmp;
        }
        p1.next = dummy2.next;
        return dummy1.next;
    }
}

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode pre = new ListNode(0, head);
        ListNode tmp = pre;
        while (tmp.next != null && tmp.next.next != null) {
            ListNode start = tmp.next;
            ListNode end = tmp.next.next;
            tmp.next = end;
            start.next = end.next;
            end.next = start;
            tmp = start;
        }
        return pre.next;
    }
}

class Solution {
    // 定义:输入以head为头的链表,将这个单链表中的每两个元素翻转,并且返回反转后的头结点.
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode next = head.next;
        head.next = swapPairs(next.next);
        next.next = head;
        return next;
    }
}

给你链表的头节点 head 和一个整数 k 。

交换 链表正数第 k 个节点和倒数第 k 个节点的值后,返回链表的头节点(链表 从 1 开始索引)。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[1,4,3,2,5]

示例 2:

输入:head = [7,9,6,6,7,8,3,0,9,5], k = 5
输出:[7,9,6,6,8,7,3,0,9,5]

示例 3:

输入:head = [1], k = 1
输出:[1]

示例 4:

输入:head = [1,2], k = 1
输出:[2,1]

示例 5:

输入:head = [1,2,3], k = 2
输出:[1,2,3]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapNodes(ListNode head, int k) {
        ListNode dummy = new ListNode(0, head);
        ListNode pre1 = dummy, left = head, pre2 = dummy, right = head;
        // 寻找左边第k个节点和前一个节点
        // 从1开始,第k个,即偏移  k - 1
        for (int i = 0; i < k - 1; i++) {
            left = left.next;
            pre1 = pre1.next;
        }
       // 寻找右边第k个节点和前一个节点
       ListNode cur = left;
       while (cur.next != null) {
           cur = cur.next;
           right = right.next;
           pre2 = pre2.next;
       }
       // 分为两种方式开始,相邻还是不相邻
      // 1 2 3 4  pre1 = 2 left = 3  right = 2 pre2 = 1
      // 1 3 2 4
      ListNode temp = left.next;
      if (pre1 == right) {
          right.next = temp;
          left.next = right;
          pre2.next = left;
      }else {
          // 1 2 3 4 pre1 = 1 left = 2 pre2 = 2 right = 3
       // 1 3 2 4
       if (left == pre2) {
           left.next = right.next;
           right.next = left;
           pre1.next = right;
       }else {
           // 不相邻  1 2 3 4 5  pre1 = 1 pre2 = 3 left = 2 right = 4  变成 1 4 3 2 5

        ListNode tmp = left.next;
        left.next = right.next;
        pre2.next = left;
        right.next = tmp;
        pre1.next = right;
       }
      }

       



       

        return dummy.next;

    }
}

给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。

请你返回该链表所表示数字的 十进制值 。

示例 1:

输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)

示例 2:

输入:head = [0]
输出:0

示例 3:

输入:head = [1]
输出:1

示例 4:

输入:head = [1,0,0,1,0,0,1,1,1,0,0,0,0,0,0]
输出:18880

示例 5:

输入:head = [0,0]
输出:0
class Solution {
    public int getDecimalValue(ListNode head) {
        ListNode cur = head;
        int ans = 0;
        while (cur != null) {
            ans = ans * 2 + cur.val;
            cur = cur.next;
        }
        return ans;
    }
}

这就相当于,比如说计算十进制的数:526,你先读取到52,如果发现后面还有一个6,那直接把52乘10加6就可以了.

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        int carry = 0;
        // 两条链表都遍历结束后
        while (l1 != null || l2 != null) {
            int x = l1 == null ? 0 : l1.val;
            int y = l2 == null ? 0 : l2.val;
            int sum = x + y + carry;
            carry = sum / 10;
            cur.next = new ListNode(sum % 10);
            cur = cur.next;
            if (l1 != null) {
                l1 = l1.next;
            }
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry == 1) {
            cur.next = new ListNode(carry);
        }
        return dummy.next;
    }
}
class Solution {
    // 定义: 两个链表逐位相加,并返回相加后链表的头结点.
    // 需要考虑的是:元素相加 + carry 当sum > 9的时候
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // base case
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        int sum = l1.val + l2.val;
        ListNode head = new ListNode(sum % 10);
        // 递归
        head.next = addTwoNumbers(l1.next, l2.next);
        // 递归后
        if (sum > 9) {
            head.next = addTwoNumbers(head.next, new ListNode(1));
        }
        return head;
    }
}

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例1:

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        l1 = reverseList(l1);
        l2 = reverseList(l2);
        ListNode l3 = addTwo(l1, l2);
        return reverseList(l3);
    }

    private ListNode reverseList(ListNode head) {
        ListNode pre = null, cur = head;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }

    private ListNode addTwo(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        int carry = 0;
        while (l1 != null || l2 != null) {
            int x = l1 == null ? 0 : l1.val;
            int y = l2 == null ? 0 : l2.val;
            int sum = x + y + carry;
            carry = sum / 10;
            cur.next = new ListNode(sum % 10);
            cur = cur.next;
            if (l1 != null) {
                l1 = l1.next;
            }
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry == 1) {
            cur.next = new ListNode(carry);
        }
        return dummy.next;
    }
}
// 栈 + 相加的方式
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Stack<Integer> stk1 = new Stack<>();
        while (l1 != null) {
            stk1.push(l1.val);
            l1 = l1.next;
        }
        Stack<Integer> stk2 = new Stack<>();
        while (l2 != null) {
            stk2.push(l2.val);
            l2 = l2.next;
        }
        ListNode dummy = new ListNode(-1);
        int carry = 0;
        while (!stk1.isEmpty() || !stk2.isEmpty() || carry > 0) {
            int sum = carry;
            if (!stk1.isEmpty()) {
                sum += stk1.pop();
            }
            if (!stk2.isEmpty()) {
                sum += stk2.pop();
            }
            carry = sum / 10;
            sum = sum % 10;
            ListNode newNode = new ListNode(sum);
            newNode.next = dummy.next;
            dummy.next = newNode;
        }
        return dummy.next;
    }
}

用一个 非空 单链表来表示一个非负整数,然后将这个整数加一。

你可以假设这个整数除了 0 本身,没有任何前导的 0。

这个整数的各个数位按照 高位在链表头部、低位在链表尾部 的顺序排列。

示例:

输入: [1,2,3]
输出: [1,2,4]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode plusOne(ListNode head) {
        Stack<Integer> st = new Stack();
        while (head != null) {
            st.push(head.val);
            head = head.next;
        }
        int carry = 0;
        ListNode dummy = new ListNode(0);
        int adder = 1;
        while (!st.empty() || adder != 0 || carry > 0) {
            int digit = st.empty() ? 0 : st.pop();
            int sum = digit + adder + carry;
            carry = sum >= 10 ? 1 : 0;
            sum = sum >= 10 ? sum - 10 : sum;
            ListNode cur = new ListNode(sum);
            cur.next = dummy.next;
            dummy.next = cur;
            adder = 0;
        }
        return dummy.next;
    }
}

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

示例 1:

输入: head = [1,2,3,4,5]
输出: [1,3,5,2,4]
// 造两条链表,找出所有的奇偶元素,然后奇链表 续接偶链表 链表默认为null,返回head
class Solution {
    public ListNode oddEvenList(ListNode head) {
        ListNode oddHead = new ListNode();
        ListNode oddTail = oddHead;
        ListNode evenHead = new ListNode();
        ListNode evenTail = evenHead;
        boolean isOdd = true;
        while (head != null) {
            if (isOdd) {
                oddTail.next = head;
                oddTail = oddTail.next;
            }else {
                evenTail.next = head;
                evenTail = evenTail.next;
            }
            ListNode tmp = head.next;
            head.next = null;
            head = tmp;
            isOdd = !isOdd;
        }
        oddTail.next = evenHead.next;
        return oddHead.next;
    }
}

对着86题分割链表看

排序奇升偶降链表

题目描述 : 给定一个奇数位升序,偶数位降序的链表,将其重新排序。

输入: 1->8->3->6->5->4->7->2->NULL
输出: 1->2->3->4->5->6->7->8->NULL

要求: 时间复杂度为O(N),空间复杂度O(1)。

思路:

1. 按奇偶位置拆分链表,得1->3->5->7->NULL和8->6->4->2->NULL

2. 反转偶链表,得1->3->5->7->NULL和2->4->6->8->NULL

3. 合并两个有序链表,得1->2->3->4->5->6->7->8->NULL

public class SortList {

    @Data
    static class ListNode {
        int val;
        ListNode next;
        ListNode() {

        }
        ListNode(int val, ListNode next) { this.val = val; this.next = next; }
        ListNode(int val) {
            this.val = val;
            next = null;
        }
    }

    // 1.拆分成两个链表得1->3->5->7->NULL和8->6->4->2->NULL
    private ListNode[] partition(ListNode head) {
        ListNode oddHead = new ListNode();
        ListNode oddTail = oddHead;
        ListNode evenHead = new ListNode();
        ListNode evenTail = evenHead;
        boolean isOdd = true;
        while (head != null) {
            if (isOdd) {
                oddTail.next = head;
                oddTail = oddTail.next;
            }else {
                evenTail.next = head;
                evenTail = evenTail.next;
            }
            ListNode tmp = head.next;
            head.next = null;
            head = tmp;
            isOdd = !isOdd;
        }
        return new ListNode[]{oddHead.next, evenHead.next};
    }

    // 2.反转偶链表得1->3->5->7->NULL和2->4->6->8->NULL
    private static ListNode reverse(ListNode head) {
        ListNode pre = null, cur = head;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
    // 3.合并两个链表
    public  ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode(-1);
        ListNode p = dummy, p1 = list1, p2 = list2;
        while (p1 != null && p2 != null) {
            if (p1.val > p2.val) {
                p.next = p2;
                p2 = p2.next;
            }else {
                p.next = p1;
                p1 = p1.next;
            }
            p = p.next;
        }
        if (p1 != null) {
            p.next = p1;
        }
        if (p2 != null) {
            p.next = p2;
        }
        return dummy.next;

    }

    public ListNode sortList(ListNode list) {
        // 1. 拆分奇偶链表
        ListNode[] arr = partition(list);
        // 2. 翻转偶数链表
        ListNode oddList = arr[0];
        ListNode evenList = reverse(arr[1]);
        // 3. 合并有序链表
        return mergeTwoLists(oddList, evenList);
    }


    public static void main(String[] args) {
        ListNode listNode = new SortList().sortList(new ListNode(1, new ListNode(8, new ListNode(3, new ListNode(6, new ListNode(5,
                new ListNode(4, new ListNode(7, new ListNode(2)))))))));
        System.out.println(listNode);

    }


}

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

示例 1:

输入:head = [1,2,2,1]
输出:true
class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }
        ListNode first = endOfFirstHalf(head);
        ListNode second = reverse(first);
        ListNode p1 = head;
        ListNode p2 = second;
        while (p2 != null) {
            if (p1.val != p2.val) {
                return false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }
        return true;
    }

    private ListNode endOfFirstHalf(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    private ListNode reverse(ListNode head) {
        ListNode pre = null, cur = head;
        while (cur != null) {
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}
class Solution {
    // 定义: 给定一个头结点,如果此链表是回文链表则返回true,如果不是回文链表则返回false;
    // 需要一个节点从前往后遍历,另一个节点从后往前遍历,然后不断比较两个节点的值是否相同;
    // 一个节点指向头节点
    ListNode temp;
    boolean ans = true;
    public boolean isPalindrome(ListNode head) {
        temp = head;
        check(head);
        return ans;
    }
    private void check(ListNode head) {
        if (head == null) {
            return;
        }
        check(head.next);
        if (ans) {
            if (temp.val != head.val) {
                ans = false;
            }else {
                temp = temp.next;
            }
        }
    }
}

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码  接受原链表的头节点 head 作为传入参数。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
class Solution {
    public Node copyRandomList(Node head) {
         // 创建一个map,存之前的节点和复制后节点,这个问题在于,在创建后节点后还需要将对应的 next节点和random节点连接起来.
         Map<Node, Node> cache = new HashMap<>();
         Node p = head;
         while (p != null) {
             if (!cache.containsKey(p)) {
                 cache.put(p, new Node(p.val));
             }
             p = p.next;
         }
         p = head;
         while (p != null) {
             if (p.next != null) {
                 cache.get(p).next = cache.get(p.next);
             }
             if (p.random != null) {
                 cache.get(p).random = cache.get(p.random);
             }
             p = p.next;
         }
         return cache.get(head);
    }
}

你会得到一个双链表,其中包含的节点有一个下一个指针、一个前一个指针和一个额外的 子指针 。这个子指针可能指向一个单独的双向链表,也包含这些特殊的节点。这些子列表可以有一个或多个自己的子列表,以此类推,以生成如下面的示例所示的 多层数据结构 。

给定链表的头节点 head ,将链表 扁平化 ,以便所有节点都出现在单层双链表中。让 curr 是一个带有子列表的节点。子列表中的节点应该出现在扁平化列表中的 curr 之后 和 curr.next 之前 。

返回 扁平列表的 head 。列表中的节点必须将其 所有 子指针设置为 null 。

 

示例 1:

输入:head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
输出:[1,2,3,7,8,11,12,9,10,4,5,6]
解释:输入的多级列表如上图所示。
扁平化后的链表如下图:



// 定义将连边头位head的链表进行扁平话,并将扁平化的头节点返回;
class Solution {
    public Node flatten(Node head) {
        Node dummy = new Node(0);
        dummy.next = head;
        while (head != null) {
            if (head.child == null) {
                head = head.next;
            }else {
                // 递归扁平
                Node next = head.next;
                Node lastNode = flatten(head.child);
                head.next = lastNode;
                lastNode.prev = head;
                head.child = null;
                while (head.next != null) {
                    head = head.next;
                }
                head.next = next;
                if (next != null) {
                    next.prev = head;
                }
                head = next;
            }
        }
        return dummy.next;
    }
}

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || k == 0) {
            return head;
        }
        ListNode p = head;
        int n = 0;
        // 注意: 要获得最后一个节点
        while (p.next != null) {
            p = p.next;
            n++;
        }
        n++; // 加上最后一个节点  长度或者从1开始计数
        k = k % n;
        ListNode tail = p;
        p = head;
        for (int i = 0; i < n -k -1; i++) {
            p = p.next;
        }
        tail.next = head;
        ListNode newHead = p.next;
        p.next = null;
        return newHead;

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值