剑指 Offer 06. 从尾到头打印链表https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/
剑指 Offer 35. 复杂链表的复制https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/剑指 Offer 24. 反转链表https://leetcode.cn/problems/fan-zhuan-lian-biao-lcof/剑指 Offer 35. 复杂链表的复制概述: 这三个题都属于热点题,难度不高出现频率比较频繁很经典,从06开始做完这三个会对链表有一定的理解
考点:
1. 链表的考点太多了主要就是玩指针,指针明白了就没啥可看的
2. 双指针也可以算是指针的经典算法,虽然也能玩数组吧
3. 可以套用一些现有的结构处理比较复杂的问题,比如LinkedList之类的
题目一:从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2] 输出:[2,3,1]
解法一:求个长度用来newArray,之后顺序遍历链表 ,数组反向接收即可
不愿意循环求长度也可以直接上List转成数组
public int[] reversePrint(ListNode head) {
int len = 0;
ListNode node = head;
while (node!=null){
node = node.next;
len++;
}
int [] arr = new int[len];
int index = len-1;
while (head!=null){
arr[index--] = head.val;
head = head.next;
}
return arr;
}
解法二:直接用栈搞也行,LinkedList最适合当栈了,从尾部插进去,之后从尾部吐出来
public int[] reversePrint(ListNode head) {
LinkedList<Integer> stack = new LinkedList<Integer>();
while(head != null) {
stack.addLast(head.val);
head = head.next;
}
int[] res = new int[stack.size()];
for(int i = 0; i < res.length; i++)
res[i] = stack.removeLast();
return res;
}
题目二:复杂链表的复制
剑指 Offer 35. 复杂链表的复制
请实现
copyRandomList
函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个next
指针指向下一个节点,还有一个random
指针指向链表中的任意节点或者null
。示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]] 输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]] 输出:[[3,null],[3,0],[3,null]]示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
解法一: 整一个Map当额外存储的上帝视角,是否包含Head,只要不包含就塞进去,然后递归next和Random,一直薅到底就得了
Map<Node,Node> map = new HashMap<>();
public Node copyRandomList(Node head) {
if (head==null)return null;
if (!map.containsKey(head)){
Node headNew = new Node(head.val);
map.put(head,headNew);
headNew.next = copyRandomList(head.next);
headNew.random = copyRandomList(head.random);
}
return map.get(head);
}
解法二:
public Node copyRandomList(Node head) {
if (head == null) {
return head;
}
// 完成链表节点的复制
Node cur = head;
while (cur != null) {
Node copyNode = new Node(cur.val);
copyNode.next = cur.next;
cur.next = copyNode;
cur = cur.next.next;
}
// 完成链表复制节点的随机指针复制
cur = head;
while (cur != null) {
if (cur.random != null) { // 注意判断原来的节点有没有random指针
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
// 将链表一分为二
Node copyHead = head.next;
cur = head;
Node curCopy = head.next;
while (cur != null) {
cur.next = cur.next.next;
cur = cur.next;
if (curCopy.next != null) {
curCopy.next = curCopy.next.next;
curCopy = curCopy.next;
}
}
return copyHead;
}
题目三:反转链表
解法一/二:循环或者递归都可以,底层都差不多,效率类似
public ListNode reverseList(ListNode head) {
if (head == null) return head;
ListNode prev = null;
ListNode node = head;
while (node != null) {
ListNode next = node.next;
node.next = prev;
prev = node;
node = next;
}
return prev;
}
public ListNode reverseList2(ListNode head) {
if (head == null || head.next == null)return head;
ListNode node = reverseList2(head.next);
head.next.next = head;
head.next = null;
return node;
}