1.链表翻转经典代码
public static Node reverseLinkedList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static DoubleNode reverseDoubleList(DoubleNode head) {
DoubleNode pre = null;
DoubleNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
head.last = next;
pre = head;
head = next;
}
return pre;
}
2 题目:K个节点的组内逆序调整
路径:https://leetcode.com/problems/reverse-nodes-in-k-group/
给定一个单链表的头节点head,和一个正数k
实现k个节点的小组内部逆序,如果最后一组不够k个就不调整
例子:
调整前:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8,k = 3
调整后:3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7 -> 8
思路:
1.找到从start到第k个的listNode
2.会start到end的翻转
3循环遍历,每次翻转,把从第二次旋转后的 lastEnd.next = end;
代码实现:
public static class ListNode {
public int val;
public ListNode next;
}
public static ListNode reverseKGroup(ListNode head, int k) {
//头给start
ListNode start = head;
//从头往后数第K个给end
ListNode end = getKGroupEnd(start, k);
//end为空则不需要调整 因为没有够k个
if (end == null) {
return head;
}
// 第一组凑齐了! 那么end直接给头
// 因为第一组的逆序后的第一个也就是end 肯定为最后的返回值
head = end;
reverse(start, end);
// 上一组的结尾节点
ListNode lastEnd = start;
while (lastEnd.next != null) {
start = lastEnd.next;
end = getKGroupEnd(start, k);
if (end == null) {
return head;
}
reverse(start, end);
//上一个结尾的下一个指向这次调转后的end 也就是这一组的第一个
lastEnd.next = end;
//上一个的结尾的换位这次结尾的
lastEnd = start;
}
return head;
}
public static ListNode getKGroupEnd(ListNode start, int k) {
while (--k != 0 && start != null) {
start = start.next;
}
return start;
}
//翻转从s到e
public static void reverse(ListNode start, ListNode end) {
//找到e的下一个先
end = end.next;
ListNode pre = null;
ListNode cur = start;
ListNode next = null;
while (cur != end) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
//翻转过后start 指向下一个需要翻转的start 就是之前赋值的end
// 但是这个地方不对哈(你需要真正指向的下一个逆序后的第一个值) 后面的循环会赋值对的
start.next = end;
}
3题目:链表相加
路径:https://leetcode.com/problems/add-two-numbers/
给定两个链表的头节点head1和head2,
认为从左到右是某个数字从低位到高位,返回相加之后的链表
例子 4 -> 3 -> 6 2 -> 5 -> 3
返回 6 -> 8 -> 9
解释 634 + 352 = 986
思路:
1:L长链表S短链表都有 记录加的数和进位 4+2+0(进位)=6 记录6 进位carry0
3+5+0=8 记录8进位0
6+3+0=9 记录9进位0
2:L有S无 没有
3:LS都无 看进位 没有
返回986
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public static ListNode addTwoNumbers(ListNode head1, ListNode head2) {
int len1 = listLength(head1);
int len2 = listLength(head2);
//长链表
ListNode l = len1 >= len2 ? head1 : head2;
//短链表
ListNode s = l == head1 ? head2 : head1;
ListNode curL = l;
ListNode curS = s;
ListNode last = curL;
int carry = 0;
int curNum = 0;
//第一个阶段 LS都有
while (curS != null) {
curNum = curL.val + curS.val + carry;
curL.val = (curNum % 10);
carry = curNum / 10;
last = curL;
curL = curL.next;
curS = curS.next;
}
//第二个阶段 L有 S无
while (curL != null) {
curNum = curL.val + carry;
curL.val = (curNum % 10);
carry = curNum / 10;
last = curL;
curL = curL.next;
}
//只有进位
if (carry != 0) {
last.next = new ListNode(1);
}
return l;
}
// 求链表长度
public static int listLength(ListNode head) {
int len = 0;
while (head != null) {
len++;
head = head.next;
}
return len;
}
4 链表合并
路径:https://leetcode.com/problems/merge-two-sorted-lists
给定两个有序链表的头节点head1和head2,
返回合并之后的大链表,要求依然有序
例子 1 -> 3 -> 3 -> 5 -> 7 2 -> 2 -> 3 -> 3-> 7
返回 1 -> 2 -> 2 -> 3 -> 3 -> 3 -> 3 -> 5 -> 7
代码实现:
public static class ListNode {
public int val;
public ListNode next;
}
public static ListNode mergeTwoLists(ListNode head1, ListNode head2) {
if (head1 == null || head2 == null) {
return head1 == null ? head2 : head1;
}
ListNode head = head1.val <= head2.val ? head1 : head2;
ListNode cur1 = head.next;
ListNode cur2 = head == head1 ? head2 : head1;
ListNode pre = head;
while (cur1 != null && cur2 != null) {
if (cur1.val <= cur2.val) {
pre.next = cur1;
cur1 = cur1.next;
} else {
pre.next = cur2;
cur2 = cur2.next;
}
pre = pre.next;
}
//无论谁不为空,都把之后的给他赋值上就连一块了
pre.next = cur1 != null ? cur1 : cur2;
return head;
}
路径:https://leetcode.com/problems/merge-k-sorted-lists
Input: lists = [[1,4,5],[1,3,4],[2,6]] Output: [1,1,2,3,4,4,5,6] Explanation: The linked-lists are: [ 1->4->5, 1->3->4, 2->6 ] merging them into one sorted list: 1->1->2->3->4->4->5->6
思路:利用小根堆实现
代码实现:
public static class ListNode {
public int val;
public ListNode next;
}
public static class ListNodeComparator implements Comparator<ListNode> {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
}
public static ListNode mergeKLists(ListNode[] lists) {
if (lists == null) {
return null;
}
//小根堆
PriorityQueue<ListNode> heap = new PriorityQueue<>(new ListNodeComparator());
for (int i = 0; i < lists.length; i++) {
if (lists[i] != null) {
heap.add(lists[i]);
}
}
if (heap.isEmpty()) {
return null;
}
//先弹出一个作为头好返回
ListNode head = heap.poll();
ListNode pre = head;
//下一个不是空塞回小根堆
if (pre.next != null) {
heap.add(pre.next);
}
while (!heap.isEmpty()) {
ListNode cur = heap.poll();
pre.next = cur;
pre = cur;
if (cur.next != null) {
heap.add(cur.next);
}
}
return head;
}
一种特殊的单链表节点类描述如下
class Node {
int value;
Node next;
Node rand;
Node(int val) { value = val; }
}
rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点,也可能指向null。
给定一个由Node节点类型组成的无环单链表的头节点 head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。
【要求】
时间复杂度O(N),额外空间复杂度O(1) https://leetcode.com/problems/copy-list-with-random-pointer/
思路:如果使用map 直接记录node和新建node关系即可,但是不能使用额外空间,我们需要在node.next记录一个新的node,这样就和map一个套路了
public static class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
public static Node copyRandomList(Node head) {
if (head == null) {
return null;
}
Node cur = head;
Node next = null;
// 1 -> 2 -> 3 -> null
// 1 -> 1' -> 2 -> 2' -> 3 -> 3'
while (cur != null) {
next = cur.next;
cur.next = new Node(cur.val);
cur.next.next = next;
cur = next;
}
cur = head;
Node copy = null;
// 1 1' 2 2' 3 3'
// 依次设置 1' 2' 3' random指针
while (cur != null) {
next = cur.next.next;
copy = cur.next;
copy.random = cur.random != null ? cur.random.next : null;
cur = next;
}
Node res = head.next;
cur = head;
// 老 新 混在一起,next方向上,random正确
// next方向上,把新老链表分离
while (cur != null) {
next = cur.next.next;
copy = cur.next;
cur.next = next;
copy.next = next != null ? next.next : null;
cur = next;
}
return res;
}