本题要求从尾到头打印链表,输出格式为数组,我们可以通过递归到链表的最后一位再回溯将链表的节点值加入ArrayList
中,再将它转化为数组即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
List<Integer> list = new ArrayList<>();
public int[] reversePrint(ListNode head) {
cur(head);
int[] res = new int[list.size()];
for(int i = 0;i<list.size();++i){
res[i] = list.get(i);
}
return res;
}
public void cur(ListNode node){
if(node == null) return;
cur(node.next);
list.add(node.val);
}
}
本题是合并两个有序的链表,那么我们用两个指针分别遍历两个链表再比较节点的值来连成一个新的链表即可。需要注意的地方是当一个链表被遍历完之后,另外一个链表可能还没有遍历完,那么我们在循环结束之后将链表中没遍历完的部分直接加入新的链表后面即可(没遍历完的部分就是两个链表中最大的部分)。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newHead = new ListNode(-1);
ListNode cur = newHead;
while(l1 != null && l2 != null){
if(l1.val < l2.val){
cur.next = l1;
l1=l1.next;
}else{
cur.next = l2;
l2=l2.next;
}
cur = cur.next;
}
cur.next = (l1 == null)?l2:l1;
return newHead.next;
}
}
本题用快慢节点的方法来解决,首先定义两个节点fast和slow,题目中求倒数第k个节点,我们只需要让fast节点先走k-1步,再让两个节点同时往后走,当fast节点走到最后一个节点时,slow节点指向的就是我们要的倒数第k个节点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if(k <= 0) return null;
ListNode slow = head;
ListNode fast = head;
while(k>1){
fast = fast.next;
k--;
}
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
本题方法是在遍历原链表的同时将其每个节点用头插法的方式插入我们构造的新的头结点中,最后返回新的头结点就完成了链表的反转操作。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode newHead = new ListNode(-1);
ListNode cur = head;
while(cur != null){
ListNode nextNode = cur.next;
cur.next = newHead.next;
newHead.next = cur;
cur = nextNode;
}
return newHead.next;
}
}
本题要求删除链表中的一个节点,那么我们只需创建一个定位节点和它的前驱节点即可,当定位节点的值等于val时,让pre.next = cur.next;
即可,问题在于我们要删除的节点可能是该链表的头结点,此时可以直接处理,也可以新定义一个头结点来指向该链表,让原链表的头结点成为第二个节点,那么就不需要进行特殊处理,本题定义新的头结点来实现。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head == null) return null;
ListNode newHead = new ListNode(-1);
newHead.next = head;
ListNode cur = head;
ListNode pre = newHead;
while(cur != null){
if(cur.val == val){
pre.next = cur.next;
}
pre = cur;
cur = cur.next;
}
return newHead.next;
}
}
本题核心:哈希表,用哈希表来存原链表的每个节点和新链表的每个节点,两者是一一对应的关系。我们先存储只带有val的每一个新节点,那么哈希表中存储的每一个旧节点和每一个新节点都是key-value的关系,接下来就是通过这种关系让新节点的next和random指向正确的节点,最后返回新节点的头结点即可。
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(head == null) return null;
Map<Node,Node> map = new HashMap<>();
Node cur = head;
while(cur != null){
Node node = new Node(cur.val);
map.put(cur,node);
cur = cur.next;
}
cur = head;
while(cur != null){
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
}
本题用双指针解法:我们设node为公共节点,链表headA
的长度为A,链表headB
的长度为B,两链表的公共部分长度为C,那么:
从headA
到node
的长度为:A-C
从headB
到node
的长度为:B-C
当指针a走完链表headA再走链表headB到node节点时一共走了:A+(B-C);
当指针b走完链表headB再走链表headA到node节点时一共走了:B+(A-C);
可以看出A+(B-C) = B+(A-C);
因此当指针a和b相遇时,他们走的节点个数相同,结果就显而易见了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode a = headA;
ListNode b = headB;
while(a != b){
a = (a == null) ? headB : a.next;
b = (b == null) ? headA : b.next;
}
return a;
}
}