链表系列题目合集:Leetcode链表题目
建议先看本人博客中算法通关面试40讲中的链表部分题目。
方法:

  • 使用prev前置指针,用于反转链表全部或部分类的题目
  • 使用快慢指针,用于判断链表内部是否有环类题目,以及删除节点题目
  • 环形问题找到环的入口方法:快慢指针第一次相遇后,快指针从头部再与慢指针相遇的位置
  • 获得链表的中间节点,使用快慢指针,快指针走两步,慢指针走一步,快指针next为null或者为null时,慢指针指向中间节点
  • 双指针连接链表法,用于查找相交链表

Leetcode-23. 合并K个排序链表

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

解法:1. 暴力算法,将所有节点放在一个数组中,排序之后输出,时间O(NlogN),N是节点总数。2. 分治,将k个list两两组合,用图来表示如下,时间复杂度O(NlogK),k是链表的条数,空间复杂度O(1)

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode mergeKLists(ListNode[] lists) {
   
        if (lists==null || lists.length==0) return null;
        int amount = lists.length;
        int i = 1;
        while (i < amount) {
   
            for (int j=0;j+i<amount;j += i*2) {
   
                lists[j] = this.mergeTwoLists(lists[j], lists[j+i]);
            }
            i *= 2;
        }
        return lists[0];
    }
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
   
        ListNode pointer = new ListNode(0);
        ListNode head = pointer;
        while (l1!=null && l2!=null) {
   
            if (l1.val > l2.val) {
   
                pointer.next = l2;
                l2 = l2.next;
            } else {
   
                pointer.next = l1;
                l1 = l1.next;
            }
            pointer = pointer.next;
        }
        if (l1==null) {
   
            pointer.next = l2;
        } else {
   
            pointer.next = l1;
        }
        return head.next;
    }
}
  • Python
class Solution(object):
    def mergeKLists(self, lists):
        """ :type lists: List[ListNode] :rtype: ListNode """
        amount = len(lists)
        interval = 1
        while interval < amount:
            for i in range(0, amount - interval, interval * 2):
                lists[i] = self.merge2Lists(lists[i], lists[i + interval])
            interval *= 2
        return lists[0] if amount > 0 else lists

    def merge2Lists(self, l1, l2):
        head = point = ListNode(0)
        while l1 and l2:
            if l1.val <= l2.val:
                point.next = l1
                l1 = l1.next
            else:
                point.next = l2
                l2 = l1
                l1 = point.next.next
            point = point.next
        if not l1:
            point.next=l2
        else:
            point.next=l1
        return head.next

Leetcode-82. 删除排序链表中的重复元素 II

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

示例 1:

输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:

输入: 1->1->1->2->3
输出: 2->3

解法:只要节点的左右值不同,那么节点就是一个可用节点,否则不是

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode deleteDuplicates(ListNode head) {
   
        if (head == null) return head;
        ListNode pointer = new ListNode(0==head.val? 1: 0);
        ListNode pre = pointer, l = pointer;
        while (head != null) {
   
            while (head!=null && (pre.val==head.val || (head.next!=null && head.val==head.next.val))) {
   
                pre = head;
                head = head.next;
            }
            pointer.next = head;
            pointer = pointer.next;
            pre = head;
            head = head==null? head: head.next;
        }
        return l.next;
    }
}

Leetcode-61. 旋转链表

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

解法:很简单,找到rotate的位置和null前的位置,进行rotate即可

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode rotateRight(ListNode head, int k) {
   
        if (head == null) return null;
        
        int length = 1;
        ListNode tmp = head, pre = tmp, cur = tmp;
        while (tmp.next != null) {
    //Get the total length 
            tmp = tmp.next;
            length++;
        }
        
        k = k%length;
        if (k==0) return head;
        
        for (int i=0;i<length-k-1;i++) {
    //Get the length-k%length th node
            pre = pre.next;
        }
        cur = pre.next; // rotate
        pre.next = null;
        tmp.next = head;
        return cur;
    }
}

Leetcode-86. 分隔链表

给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

你应当保留两个分区中每个节点的初始相对位置。

示例:

输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5

解法:用两个链表分别存储小于x的和不小于的,最后连接一下就可以

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode partition(ListNode head, int x) {
   
        ListNode pre = new ListNode(0);
        ListNode after = new ListNode(0);
        ListNode dummy1 = pre;
        ListNode dummy2 = after;
        while (head !=null) {
   
            if (head.val<x) {
   
                pre.next = head;
                pre = pre.next;
            } else{
   
                after.next = head;
                after = after.next;
            }
            head = head.next;
        }
        after.next = null;
        pre.next = dummy2.next;
        return dummy1.next;
    }
}

Leetcode-92. 反转链表 II

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

解法:我这里采用的办法是分开再连接,将要进行反转的部分拆出来,利用了头尾节点在翻转中的被调转过来的特性。这道题可以打个星号着重看一下,时间复杂度O(N),空间复杂度O(1)。

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode reverseBetween(ListNode head, int m, int n) {
   
        if (head==null || head.next==null) return head;
        ListNode pre = new ListNode(0);
        pre.next = head;
        ListNode dummy = pre;
        ListNode cur = head; 
        // 想要将pre移至m的前一个节点,cur移至n节点上,现在pre和cur相差1节点,达到目的时相差n-m+1节点,所以cur需要移动n-m个节点才能保持两者间距为n-m+1
        for (int i=0;i<n-m;i++) {
   
            cur = cur.next;
        }
        // 同时平移至目标位置
        for (int i=0;i<m-1;i++) {
   
            pre = pre.next;
            cur = cur.next;
        }
        // 记录下pre当前的位置
        ListNode node = pre;
        // 记录cur的下一个位置,因为reverse之后还要连接回去
        ListNode next = cur.next;
        cur.next = null;
        // 将pre调整到下一个节点进行翻转,传入的头尾节点是pre和cur,翻转之后的头尾节点是cur和pre,再进行重新连接即可
        pre = pre.next;
        // node.next = this.reverseList(pre); // 与node.next = cur是一个效果
        this.reverseList(pre);
        // 重新连接
        node.next = cur;
        pre.next = next;
        return dummy.next;
    }
    public ListNode reverseList(ListNode head) {
   
        ListNode pre = null;
        while (head != null) {
   
            ListNode tmp = head.next;
            head.next = pre;
            pre = head;
            head = tmp;
        }
        return pre;
    }
}

Leetcode-108.将有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

解法:利用中间节点使用递归,

  • Java
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */
class Solution {
   
    public TreeNode sortedArrayToBST(int[] nums) {
   
        if (nums==null || nums.length==0) return null;
        return this.helper(nums, 0, nums.length-1);
    }
    public TreeNode helper(int[] nums, int left, int right) {
   
        int mid = (left+right) / 2;
        TreeNode p = new TreeNode(nums[mid]);
        if (mid != left) {
   
            p.left = this.helper(nums, left, mid-1);
        }
        if (mid != right) {
   
            p.right = this.helper(nums, mid+1, right);
        }
        return p;
    }
}

Leetcode-109. 有序链表转换二叉搜索树

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

解法:1. 使用链表的快慢指针找到中间元素,然后将中间元素作为root,左边右边分别使用递归变为二叉搜索树,最终返回root即可,时间复杂度O(NlogN),空间复杂度O(logN)。2. 与上面的方法类似,不过是将链表转换成数组在进行操作,时间复杂度O(N),空间复杂度O(N)

  • Java
    链表
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */
class Solution {
   

  private ListNode findMiddleElement(ListNode head) {
   
    ListNode prevPtr = head;
    ListNode slowPtr = prevPtr;
    ListNode fastPtr = prevPtr;
    while (fastPtr != null && fastPtr.next != null) {
   
      prevPtr = slowPtr;
      slowPtr = slowPtr.next;
      fastPtr = fastPtr.next.next;
    }
      prevPtr.next = null;
    return slowPtr;
  }

  public TreeNode sortedListToBST(ListNode head) {
   

    if (head == null) {
   
      return null;
    }
    ListNode mid = this.findMiddleElement(head);
    TreeNode node = new TreeNode(mid.val);
    if (head == mid) {
   
      return node;
    }
    node.left = this.sortedListToBST(head);
    node.right = this.sortedListToBST(mid.next);
    return node;
  }
}


数组

class Solution {
   
    public TreeNode sortedListToBST(ListNode head) {
   
        if (head==null) return null;
        ArrayList<Integer> lst = new ArrayList<Integer>();
        lst = this.addList(head, lst);
        return this.helper(lst, 0, lst.size()-1);
    }
    public ArrayList<Integer> addList(ListNode head, ArrayList<Integer> lst) {
   
        ListNode tmp = head;
        while (tmp != null) {
   
            lst.add(tmp.val);
            tmp = tmp.next;
        }
        return lst;
    }
    public TreeNode helper(ArrayList<Integer> lst, int left, int right) {
   
        int mid = left + (right-left)/2;
        TreeNode root = new TreeNode(lst.get(mid));
        if (mid != left) {
   
            root.left = this.helper(lst, left, mid-1);
        }
        if (mid != right) {
   
            root.right = this.helper(lst, mid+1, right);
        }
        return root;
    }
}


Leetcode-138. 复制带随机指针的链表

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的深拷贝。

输入:
{“KaTeX parse error: Expected '}', got 'EOF' at end of input: …":"1","next":{"id”:“2”,“next”:null,“random”:{“KaTeX parse error: Expected 'EOF', got '}' at position 9: ref":"2"}̲,"val":2},"rand…ref”:“2”},“val”:1}

解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。

提示:

你必须返回给定头的拷贝作为对克隆列表的引用。

解法:深拷贝,要建立额外的node来进行保存,使用map判断对应的node是否之前建立过(因为有random),时间复杂度O(N),空间复杂度O(N)

  • Java
/* // Definition for a Node. class Node { public int val; public Node next; public Node random; public Node() {} public Node(int _val,Node _next,Node _random) { val = _val; next = _next; random = _random; } }; */
class Solution {
   
    HashMap<Node, Node> visited = new HashMap<>();
    public Node copyRandomList(Node head) {
   
        if (head==null) return null;
        Node oldNode = head;
        Node newNode = new Node(oldNode.val, null, null);
        this.visited.put(oldNode, newNode);
        while (oldNode != null) {
   
            newNode.next = this.getNode(oldNode.next);
            newNode.random = this.getNode(oldNode.random);
            oldNode = oldNode.next;
            newNode = newNode.next;
        }
        return this.visited.get(head);
    }
    public Node getNode(Node node) {
   
        if (node==null) return null;
        if (this.visited.containsKey(node)) {
   
            return this.visited.get(node);
        } else {
   
            this.visited.put(node, new Node(node.val, null, null));
            return this.visited.get(node);
        }
    }
}

Leetcode-143. 重排链表

给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

给定链表 1->2->3->4, 重新排列为 1->4->2->3.

示例 2:

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

解法:1. 先从中间拆开,翻转后面的,在挨个插入前面的。2. 每次都把最后一个元素放在第一个元素后面

递归挨个插入

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public void reorderList(ListNode head) {
   
        if (head==null) return;
        ListNode slow = head;
        ListNode fast = slow;
        ListNode pre = slow;
        while (fast!=null && fast.next!=null) {
   
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        pre.next = null;
        
        ListNode l1 = head;
        ListNode l2 = null; // 翻转后的头部
        while (slow!=null) {
   
            ListNode tmp = slow.next;
            slow.next = l2;
            l2 = slow;
            slow = tmp;
        }
        head = this.reorder(l1, l2);
    }
    public ListNode reorder(ListNode head1, ListNode head2) {
   
        if (head1==null && head2==null) {
   
            return null;
        } else if (head1 == null) {
   
            return head2;
        } else {
   
        ListNode next1 = head1.next;
        ListNode next2 = head2.next;
        ListNode dummy = head1;
        head1.next = head2;
        head2.next = this.reorder(next1, next2);
        return dummy;
        }
    }
}
class Solution {
   
    public void reorderList(ListNode head) {
   
		// Nothing to do if the list has 2 or fewer nodes
        if (head == null || head.next == null || head.next.next == null) return;

        ListNode slast = head; // second last node
        ListNode last = head.next; // last node
        
        while (last.next != null) {
   
            last = last.next;
            slast = slast.next;
        }
        
		// Insert the last node right after the first node
        ListNode tmp = head.next;
        head.next = last;
        last.next = tmp;
		
		// Second last node should point to null otherwise there would be a cycle
		slast.next = null;
        
        reorderList(tmp);
    }
}

Leetcode-147. 对链表进行插入排序

对链表进行插入排序。
在这里插入图片描述


插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。

插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

解法:此题考察的是插入算法,每次链表的左边都保持有序,在右边遍历元素插入左边的合适的位置,时间复杂度O(N),空间复杂度O(N)

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode insertionSortList(ListNode head) {
   
        if (head==null || head.next==null) return head;
        ListNode pre = new ListNode(head.val);
        ListNode l ;
        head = head.next;
        while (head != null) {
   
            ListNode next = head.next;
            head.next = null;
            pre = this.insertNode(pre, head);
            head = next;
        }
        return pre;
    }
    public ListNode insertNode(ListNode head, ListNode node) {
   
        if (head == null) {
   
            head = node;
            return head;
        }
        // 设置两个tmp是为了不改变head和node的结构
        ListNode tmp1 = head;
        ListNode tmp2 = node;
        ListNode pre = new ListNode(0);
        pre.next = tmp1;
        ListNode dummy = pre;
        while (tmp1 != null) {
   
            // 如果大于插入值的位置立马插入,并返回
            if (tmp1.val > tmp2.val) {
   
                ListNode next = tmp1.next;
                pre.next = tmp2;
                tmp2.next = tmp1;
                tmp1 = next;
                return dummy.next;
            } else{
   
                // 没找到的话继续向下找
                pre = tmp1;
                tmp1 = tmp1.next;
            }
        }
        // 如果到了最后还没有找到,说明插入的节点的值是最大的,插入到最后
        pre.next = node;
        node.next = null;
        return dummy.next;
    }
}

Leetcode-148. 排序链表

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4
示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

解法:由O(NlogN)联想到可能是归并排序(merge sort),使用递归即可。

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode sortList(ListNode head) {
   
        if (head==null || head.next==null) return head;
        ListNode pre = head;
        ListNode slow = head;
        ListNode fast = head;
        while (fast!=null && fast.next!=null) {
   
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        pre.next = null;
        ListNode l1 = this.sortList(head);
        ListNode l2 = this.sortList(slow);
        return this.mergeTwoList(l1, l2);
    }
    public ListNode mergeTwoList(ListNode l1, ListNode l2) {
   
        if (l1==null || l2==null) {
   
            return l1==null?l2:l1;
        }
        ListNode pointer = new ListNode(0);
        ListNode dummy = pointer;
        while (l1!=null && l2!=null) {
   
            if (l1.val<l2.val) {
   
                pointer.next = l1;
                l1 = l1.next;
            } else {
   
                pointer.next = l2;
                l2 = l2.next;
            }
            pointer = pointer.next;
        }
        if (l1==null) {
   
            pointer.next = l2;
        } else {
   
            pointer.next = l1;
        }
        return dummy.next;
    }
}

Leetcode-160. 相交链表

编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:

在节点 c1 开始相交。

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。

注意:

  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。
  • 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

解法:1. 使用set添加第一条链路的元素,然后在第二个链路中查找有无,时间复杂度O(M+N),空间复杂度O(M) 2. 双指针法。创建两个指针 pA 和 pB,分别初始化为链表 A 和 B 的头结点。然后让它们向后逐结点遍历。当 pA到达链表的尾部时,将它重定位到链表 B 的头结点 (你没看错,就是链表 B); 类似的,当 pB到达链表的尾部时,将它重定位到链表 A 的头结点。若在某一时刻 pApA 和 pBpB 相遇,则 pA/pB为相交结点。时间复杂度O(M+N),空间复杂度O(1)

  • Java
    使用Set
/** * 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) {
   
        if (headA==null || headB==null) {
   
            return null;
        } 
        Set<ListNode> set = new HashSet<>();
        ListNode l1 = headA;
        ListNode l2 = headB;
        while (l1 != null) {
   
            set.add(l1);
            l1 = l1.next;
        }
        while (l2 != null) {
   
            if (set.contains(l2)) return l2;
            l2 = l2.next;
        }
        return null;
    }
}

使用双指针法

public class Solution {
   
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
   
        ListNode ha = headA, hb = headB;
        while (ha != hb) {
   
            ha = ha != null ? ha.next : headB;
            hb = hb != null ? hb.next : headA;
        }
        return ha;
    }
}

Leetcode-203. 移除链表元素

删除链表中等于给定值 val 的所有节点。
示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

解法:相等就跳过,非常简单的题

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode removeElements(ListNode head, int val) {
   
        if (head==null) return null;
        ListNode l1 = new ListNode(0==val?-1:0);
        l1.next = head;
        ListNode l2 = l1;
        ListNode dummy = l1;
        while (l1 != null) {
   
            if (l1.val != val) {
   
                l2 = l1;
                l1 = l1.next;
            } else {
   
                ListNode tmp = l1.next;
                l2.next = tmp;
                l1 = tmp;
            }
        }
        return dummy.next;
    }
}

Leetcode-234. 回文链表

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

进阶:

  • 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解法:使用快慢指针找到中点,将后半条链表翻转再与前半条链表一一比较,时间复杂度O(N)

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode reverseList(ListNode head) {
   
        if (head==null || head.next==null) return head;
        ListNode l1 = head;
        ListNode pre = null;
        while (l1!=null) {
   
            ListNode tmp = l1.next;
            l1.next = pre;
            pre = l1;
            l1 = tmp;
        }
        return pre;
    }
    public boolean isPalindrome(ListNode head) {
   
        if (head==null || head.next==null) return true;
        ListNode pre = head;
        ListNode slow = pre;
        ListNode fast = pre;
        ListNode head1 = pre;
        while (fast!=null && fast.next!=null) {
   
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        pre.next = null;
        ListNode head2 = this.reverseList(slow);
        while (head1 != null && head2!=null) {
   
            if (head1.val != head2.val) return false;
            head1 = head1.next;
            head2 = head2.next;
        }
        return true;
    }
}

Leetcode-328. 奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

示例 2:

输入: 2->1->3->5->6->4->7->NULL 
输出: 2->3->6->7->1->5->4->NULL

说明:

  • 应当保持奇数节点和偶数节点的相对顺序。
  • 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

解法:分别记录奇偶节点,奇节点连接在一起,偶节点连接在一起,最后将偶链表连接在奇链表之后,时间复杂度O(N),空间复杂度O(1)

  • Java
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */
class Solution {
   
    public ListNode oddEvenList(ListNode head) {
   
        if (head==null || head.next==null) return head;
        ListNode odd = head;
        ListNode evenHead = head.next;
        ListNode even = evenHead;
        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;
    }
}