707. 设计链表
class MyLinkedList {
private class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode() {
}
}
private ListNode dummy = new ListNode();
private int length = 0;
private ListNode tail = dummy;
public MyLinkedList() {
}
private ListNode getPreNode(int index) {
ListNode front = dummy.next;
ListNode back = dummy;
for (int i = 0; i < index; i ++) {
back = front;
front = front.next;
}
return back;
}
public int get(int index) {
if (index < 0 || index >= length) {
return -1;
}
return getPreNode(index).next.val;
}
public void addAtHead(int val) {
ListNode p = new ListNode(val);
p.next = dummy.next;
dummy.next = p;
if (tail == dummy) {
tail = p;
}
length ++;
}
public void addAtTail(int val) {
ListNode p = new ListNode(val);
tail.next = p;
tail = p;
length ++;
}
public void addAtIndex(int index, int val) {
if (index > length) {
return;
} else if (index == length) {
addAtTail(val);
return;
} else if (index <= 0) {
addAtHead(val);
return;
}
ListNode pre = getPreNode(index);
ListNode p = new ListNode(val);
p.next = pre.next;
pre.next = p;
length ++;
}
public void deleteAtIndex(int index) {
if (index < 0 || index >= length) {
return;
}
ListNode pre = getPreNode(index);
if (tail == pre.next) {
tail = pre;
}
length --;
pre.next = pre.next.next;
}
}
206. 反转链表
class Solution {
public ListNode reverseList(ListNode head) {
ListNode temp = head;
ListNode dummy = new ListNode();
while (null != temp) {
ListNode p = new ListNode(temp.val);
p.next = dummy.next;
dummy.next = p;
temp = temp.next;
}
return dummy.next;
}
}
203. 移除链表元素
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode back = dummy;
ListNode front = dummy.next;
while (null != front) {
while (null != front && val == front.val) {
front = front.next;
}
back.next = front;
back = back.next;
if (null != front) {
front = front.next;
}
}
return dummy.next;
}
}
83. 删除排序链表中的重复元素
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode front = head;
ListNode back = head;
while (null != front) {
while (null != front && back.val == front.val) {
front = front.next;
}
back.next = front;
back = front;
}
return head;
}
}
82. 删除排序链表中的重复元素 II
/**
* 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) {
// 这里我们采用新生成2条件新链表的思路
// ans 这个链表总是用来存放返回结果
ListNode ans = new ListNode();
ListNode ans_tail = ans;
// tmp 这个链表中总是用来存放相同元素。
// 如果发现要append一个不同的
ListNode tmp = new ListNode();
ListNode tmp_tail = tmp;
ListNode p = head;
while (p != null) {
ListNode back = p.next;
// 如果tmp链表为空,或者tmp链表中的元素和p.val
// 相等 => 那么把p添加到tmp链表中
if (tmp_tail == tmp || p.val == tmp_tail.val) {
tmp_tail.next = p;
tmp_tail = p;
} else {
// 如果发现和tmp链表中的元素不相等
// 那么看一下tmp链表中的结点个数
// 如果tmp链表中只有一个结点
if (tmp_tail == tmp.next) {
// 那么这里把这个结点放到ans中
ans_tail.next = tmp.next;
ans_tail = ans_tail.next;
}
// 如果tmp链表中有多个结点,那么什么也不做
// 无论tmp链表中是一个结点,还是有多个结点
// 都要清空tmp链表
tmp_tail = tmp;
tmp.next = null;
// 再把p结点安装到tmp上
// 可以和前面的语句合并
// 这里为了逻辑更清晰这么写。
tmp_tail.next = p;
tmp_tail = p;
}
p = back;
}
// 如果tmp链表中还有元素,并且只有一个
if (tmp_tail == tmp.next) {
ans_tail.next = tmp.next;
ans_tail = ans_tail.next;
}
ans_tail.next = null;
return ans.next;
}
}
21. 合并两个有序链表
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (null == list1 && null == list2) {
return null;
}
if (null == list1) {
return list2;
}
if (null == list2) {
return list1;
}
ListNode res = new ListNode(Integer.MIN_VALUE);
ListNode tail = res;
while (null != list1 && null != list2) {
if (list1.val < list2.val) {
tail.next = new ListNode(list1.val);
tail = tail.next;
list1 = list1.next;
} else {
tail.next = new ListNode(list2.val);
tail = tail.next;
list2 = list2.next;
}
}
while (null != list1) {
tail.next = new ListNode(list1.val);
tail = tail.next;
list1 = list1.next;
}
while (null != list2) {
tail.next = new ListNode(list2.val);
tail = tail.next;
list2 = list2.next;
}
return res.next;
}
}
23. 合并K个升序链表
/**
* 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) {
final int n = (null == lists ? 0 : lists.length);
Queue<ListNode> queue = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);
for (int i = 0; i < n; i ++) {
ListNode node = lists[i];
if (null != node) {
queue.add(node);
}
}
ListNode dummy = new ListNode();
ListNode tail = dummy;
while (!queue.isEmpty()) {
ListNode curNode = queue.poll();
tail.next = curNode;
tail = tail.next;
if (null != curNode.next) {
queue.add(curNode.next);
}
}
tail.next = null;
return dummy.next;
}
}
24. 两两交换链表中的节点
class Solution {
public ListNode swapPairs(ListNode head) {
if (null == head) {
return head;
}
ListNode front = head.next;
ListNode back = head;
while (null != front) {
int temp = back.val;
back.val = front.val;
front.val = temp;
if (null == front.next) {
front = null;
} else {
back = back.next.next;
front = front.next.next;
}
}
return head;
}
}
双指针
1.间隔指针:前面的指针先走一步,然后后面的指针再一起走;前面的指针先走 k 步,后面的指针再一起走。
2。快慢指针:两个指针的速度一快一慢前进,比如一个每次走一步,一个每次走两步。
19. 删除链表的倒数第 N 个结点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode();
dummy.next = head;
int preWalkedSteps = 0;
ListNode front = dummy;
while (preWalkedSteps < n && null != front && null != front.next) {
front = front.next;
preWalkedSteps ++;
}
ListNode back = dummy;
while (null != front && null != front.next) {
back = back.next;
front = front.next;
}
if (preWalkedSteps == n) {
back.next = back.next.next;
}
return dummy.next;
}
}
让指针指向链表最后一个结点的 while 语句的写法
while (null != front && null != front.next) {
// your code
}
141. 环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode front = head;
ListNode back = head;
while (null != front && null != front.next) {
back = back.next;
front = front.next.next;
if (back == front) {
return true;
}
}
return false;
}
}
142. 环形链表 II
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode front = dummy;
ListNode back = dummy;
boolean flag = false;
while (null != front && null != front.next) {
back = back.next;
front = front.next.next;
if (back == front) {
flag = true;
break;
}
}
if (!flag) {
return null;
}
back = dummy;
while (back != front) {
back = back.next;
front = front.next;
}
return front;
}
}
总结:
第一斧:假头。假头的作用主要是避免关于空链表的判断与讨论,假头还可以用来避免检查前驱结点为空的情况。
第二斧:新链表。新链表的引入是为了解决在旧链表中进行原地的交换、插入、删除,把复杂的操作变成在新链表中头部插入或者尾部添加。
第三斧:双指针。双指针主要是用于寻找链表中的特定结点,双指针的走法可以一次一步,可以有快有慢,出发点也可以有前有后。
148. 排序链表
class Solution {
public ListNode sortList(ListNode head) {
Queue<ListNode> queue = new PriorityQueue<>((v1, v2) -> (v1.val - v2.val));
while (null != head) {
queue.add(head);
head = head.next;
}
ListNode dummy = new ListNode();
ListNode tail = dummy;
while (!queue.isEmpty()) {
ListNode curNode = queue.poll();
tail.next = curNode;
tail = tail.next;
tail.next = null;
}
return dummy.next;
}
}
160. 相交链表
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode tempA = headA;
ListNode tempB = headB;
boolean flagA = false;
boolean flagB = false;
while (tempA != tempB) {
tempA = tempA.next;
if (null == tempA) {
if (flagA) {
return null;
}
flagA = true;
tempA = headB;
}
tempB = tempB.next;
if (null == tempB) {
if (flagB) {
return null;
}
flagB = true;
tempB = headA;
}
}
return tempA;
}
}
328. 奇偶链表
class Solution {
public ListNode oddEvenList(ListNode head) {
if (null == head) {
return null;
}
ListNode odd = head;
ListNode oddHead = head;
ListNode even = head.next;
ListNode evenHead = head.next;
while (null != even && null != even.next) {
odd.next = even.next;
odd = odd.next;
even.next = odd.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
}
234. 回文链表
class Solution {
public boolean isPalindrome(ListNode head) {
Stack<ListNode> stack = new Stack<>();
ListNode curNode = head;
while (null != curNode) {
stack.add(curNode);
curNode = curNode.next;
}
while (null != head) {
if (head.val != stack.pop().val) {
return false;
}
head = head.next;
}
return true;
}
}
430. 扁平化多级双向链表
class Solution {
public Node flatten(Node head) {
Node curNode = head;
while (null != curNode) {
if (null == curNode.child) {
curNode = curNode.next;
} else {
Node temp = curNode.next;
Node curNext = flatten(curNode.child);
curNode.child = null;
curNode.next = curNext;
curNext.prev = curNode;
while (null != curNode.next) {
curNode = curNode.next;
}
if (null != temp) {
curNode.next = temp;
temp.prev = curNode;
}
}
}
return head;
}
}