参考:
整理了以下几类问题:
- 反转链表
- 判断链表的环
- 链表加法
- 链表合并
- 链表分离
- 查询元素
- 删除元素
- 其他:排序、相交、回文、拷贝
问题列表
解题思路
// 递归写法
class Solution {
// 递归函数的定义为:将链表反转并返回反转后第一个节点
public ListNode reverseList(ListNode head) {
// 这其实就是找到最后一个节点
if (head == null || head.next == null) {
return head;
}
// 比如第一次反转,newHead就是5, 5432 -> 1
ListNode newHead = reverseList(head.next);
// 此时不能拿newHead指向head,必须要用head.next指向head
head.next.next = head;
head.next = null;
return newHead;
}
}
// 递归写法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode p = null, q = head;
while (q != null) {
// 执行反转操作
ListNode r = q.next;
q.next = p;
p = q;
q = r;
}
return p;
}
}
注意:头尾为空的时候需要特殊处理!!!
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode l1 = null;
ListNode l2 = head;
ListNode l3 = head;
ListNode l4 = null;
while (left > 1) {
l1 = l2;
l2 = l2.next;
left--;
}
while (right > 1) {
l3 = l3.next;
right--;
}
// 记录事后需要接上的部分
l4 = l3.next;
// 将中间需要反转的链表的尾部断开,不然无法反转
l3.next = null;
// 将中间部分翻转
l2 = revert(l2);
// 拼接前面的部分
if (l1 != null) {
// 如果前面不为空,还是使用原来的head作为开头
l1.next = l2;
} else {
// 如果前面为空,返回new2作为新的开头
head = l2;
}
// 拼接后面的部分
if (l4 != null) {
while (l2.next != null) {
l2 = l2.next;
}
l2.next = l4;
}
return head;
}
public ListNode revert(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = revert(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
}
//leetcode submit region end(Prohibit modification and deletion)
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode a = head;
ListNode b = head;
for (int i = 0; i < k; i++) {
// base条件
if (b == null) {
return head;
}
b = b.next;
}
ListNode pre = revert(a, b);
a.next = reverseKGroup(b, k);
return pre;
}
// 翻转[a,b)
public ListNode revert(ListNode a, ListNode b) {
ListNode pre = null;
ListNode cur = a;
while (cur != b) {
ListNode nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
}
class Solution {
// 将链表反转来计算
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode new1 = revert(l1);
ListNode new2 = revert(l2);
ListNode ans = addTwo(new1, new2);
return revert(ans);
}
public ListNode addTwo(ListNode l1, ListNode l2) {
int carry = 0;
ListNode head = new ListNode();
ListNode p = head;
while (l1 != null || l2 != null || carry != 0) {
int v1 = l1 != null ? l1.val : 0;
int v2 = l2 != null ? l2.val : 0;
int v = v1 + v2 + carry;
carry = v / 10;
head.next = new ListNode(v % 10);
head = head.next;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
return p.next;
}
public ListNode revert(ListNode root) {
if (root == null || root.next == null) {
return root;
}
ListNode head = revert(root.next);
root.next.next = root;
root.next = null;
return head;
}
}
判断链表是否有环。
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast!=null && fast == slow){
return true;
}
}
return false;
}
}
返回环的入口。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
ListNode intersection = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast != null && fast == slow) {
//相遇
while (intersection != fast) {
intersection = intersection.next;
fast = fast.next;
}
return intersection;
}
}
return null;
}
}
// 迭代写法
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1 == null){
return list2;
}
if(list2 == null){
return list1;
}
ListNode p = new ListNode();
ListNode head = p;
while(list1!=null && list2!=null){
if(list1.val < list2.val){
p.next = list1;
list1 = list1.next;
}else{
p.next = list2;
list2 = list2.next;
}
p = p.next;
}
if(list1!=null){
p.next = list1;
}
if(list2!=null){
p.next = list2;
}
return head.next;
}
}
递归写法要会写!!!
// 递归写法
class Solution {
// 将两个有序链表合并,并返回第一个链表
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null){
return l2;
}else if(l2 == null){
return l1;
}else if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}else{
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) {
return null;
}
// 用一个堆来确定每次取哪个链表
PriorityQueue<ListNode> minQueue = new PriorityQueue<ListNode>((o1, o2) -> {
return o1.val - o2.val;
});
ListNode p = new ListNode();
ListNode head = p;
for (ListNode l : lists) {
if (l != null) {
minQueue.add(l);
}
}
while (!minQueue.isEmpty()) {
ListNode min = minQueue.poll();
p.next = min;
if (min.next != null) {
minQueue.add(min.next);
}
p = p.next;
}
return head.next;
}
}
分治法要会写!!!
// 分治法
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return merge(lists, 0 , lists.length-1);
}
public ListNode merge(ListNode[] lists, int l , int r){
if(l == r){
return lists[l];
}
if(l > r){
return null;
}
int mid = (l+r) >> 1;
return mergeTwo(merge(lists, l ,mid), merge(lists, mid+1 ,r));
}
public ListNode mergeTwo(ListNode list1, ListNode list2){
if(list1 == null){
return list2;
}else if(list2 == null){
return list1;
}else if(list1.val < list2.val){
list1.next = mergeTwo(list1.next, list2);
return list1;
}else{
list2.next = mergeTwo(list1, list2.next);
return list2;
}
}
}
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;
ListNode head = new ListNode();
ListNode p = head;
while (l1 != null || l2 != null || carry != 0) {
int v1 = l1 != null ? l1.val : 0;
int v2 = l2 != null ? l2.val : 0;
int v = v1 + v2 + carry;
carry = v / 10;
head.next = new ListNode(v % 10);
head = head.next;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
return p.next;
}
}
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode lower = new ListNode(0);
ListNode lowerHead = lower;
ListNode higher = new ListNode(0);
ListNode higherHead = higher;
ListNode p = head;
while (p != null) {
if (p.val < x) {
lower.next = p;
lower = lower.next;
} else {
higher.next = p;
higher = higher.next;
}
ListNode next = p.next;
// 这个题目的关键就在于此,如果要做到原地分割,那么就得把临时节点的next断开,不然会产生环
p.next = null;
p = next;
}
lower.next = higherHead.next;
return lowerHead.next;
}
}
class Solution {
public ListNode oddEvenList(ListNode head) {
// 空链表返回null
if (head == null) {
return null;
}
ListNode odd = head;
ListNode even = head.next;
ListNode evenHead = even;
while (even != null && even.next != null) {
odd.next = even.next;
odd = odd.next;
even.next = odd.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
}
要注意的点就是,要拿中点后面那个节点。
为什么?因为合并链表的逻辑,是从l1开始,一次操作是↓↗
,第二个例子,4会直接指向空,所以我们应该保证l1大于等于l2。
如下两个链表合并的结果:
1->2->3
5->4
得到:1->5->2->4->3
1->2
5->4->3
得到:1->5->2->4
题解:
class Solution {
public void reorderList(ListNode head) {
ListNode slow = head;
ListNode fast = head;
ListNode pre = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
pre = slow;
slow = slow.next;
}
ListNode l2 = slow.next;
// 将第二个序列反转
l2 = revert(l2);
slow.next = null;
// 合并
mergeTwo(head, l2);
}
public ListNode revert(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = revert(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
public void mergeTwo(ListNode l1, ListNode l2) {
ListNode l1_tmp;
ListNode l2_tmp;
while (l1 != null && l2 != null) {
l1_tmp = l1.next;
l2_tmp = l2.next;
l1.next = l2;
l1 = l1_tmp;
l2.next = l1;
l2 = l2_tmp;
}
}
}
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode p = head;
while (p != null && k > 0) {
p = p.next;
k--;
}
ListNode ans = head;
while (p != null) {
p = p.next;
ans = ans.next;
}
return ans;
}
}
class Solution {
public ListNode rotateRight(ListNode head, int k) {
// base情况,链表为空或者k为0
if (head == null || k == 0) {
return head;
}
// 先计算出链表的长度
int size = 1;
ListNode tail = head;
while (tail != null && tail.next != null) {
tail = tail.next;
size++;
}
// k可能会大于链表长度,所以先取模,比如长度5,k为7和k为2的结果是一样的
k = k % size;
// k和长度相等,此时翻转的结果就是自身
if (k == 0) {
return head;
}
// 找到倒数第K个元素
ListNode tmp = head;
while (tmp != null && k > 0) {
tmp = tmp.next;
k--;
}
ListNode l1 = head;
// 倒数第K个元素的前一个元素,目的是为了断开前部分链表,避免产生环
ListNode pre = null;
while (tmp != null) {
tmp = tmp.next;
pre = l1;
l1 = l1.next;
}
if (pre != null) {
// 将链表从中间断开
pre.next = null;
}
// 重新连接起来
tail.next = head;
return l1;
}
}
class Solution {
public ListNode deleteDuplicates(ListNode head) {
// 因为已经排好序了,可以用双指针解决
ListNode pre = null;
ListNode cur = head;
ListNode ans = head;
while (cur != null) {
ListNode next = cur.next;
// 相等的时候,删除cur,此时pre不需要移动
if (pre != null && pre.val == cur.val) {
pre.next = next;
} else {
// 不删除的时候正常往前走
pre = cur;
}
cur = next;
}
return ans;
}
}
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return head;
}
ListNode dummy = new ListNode(0, head);
ListNode cur = dummy;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
int x = cur.next.val;
while (cur.next != null && cur.next.val == x) {
cur.next = cur.next.next;
}
} else {
cur = cur.next;
}
}
return dummy.next;
}
}
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
两种解法都要掌握!!!
class Solution {
// 递归解法
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
}
class Solution {
// 迭代解法
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0, head);
ListNode tmp = dummy;
while (tmp.next != null && tmp.next.next != null) {
ListNode node1 = tmp.next;
ListNode node2 = tmp.next.next;
tmp.next = node2;
node1.next = node2.next;
node2.next = node1;
tmp = node1;
}
return dummy.next;
}
}
class Solution {
public boolean isPalindrome(ListNode head) {
// 找到中间节点,将后一个链表翻转
ListNode slow = head;
ListNode fast = head;
ListNode pre = null;
while(fast!=null && fast.next!=null){
fast = fast.next.next;
pre = slow;
slow = slow.next;
}
if(pre!=null){
pre.next = null;
}
// 然后比较两个链表是否相等
ListNode l2 = revert(slow);
return equals(head, l2);
}
public ListNode revert(ListNode head){
if(head == null || head.next ==null){
return head;
}
ListNode newHead = revert(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
public boolean equals(ListNode l1, ListNode l2){
while(l1!=null){
if(l1.val != l2.val){
return false;
}
l1 = l1.next;
l2 = l2.next;
}
return true;
}
}