Java 链表合并相同元素

链表是一种常见的数据结构,它由多个节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。在实际开发中,我们经常需要对链表进行各种操作,如插入、删除、查找等。其中一个常见的操作是合并相同元素,即将链表中重复的元素合并为一个。

问题描述

给定一个链表,需要编写一个函数来合并链表中相同的元素。具体而言,如果链表中某两个相邻的元素值相同,则将它们合并为一个元素,并从链表中删除一个元素。最终,合并操作后的链表中不会存在相邻的相同元素。

示例

考虑以下链表作为输入:

1 -> 1 -> 2 -> 3 -> 3

经过合并相同元素操作后,链表应该变为:

1 -> 2 -> 3

解决方案

要解决这个问题,我们可以使用迭代的方式遍历链表,并比较每个节点与其后继节点的值是否相同。如果相同,则将当前节点的指针指向后继节点的后继节点,从而实现删除一个节点的效果。代码示例如下:

class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

class Solution {
    public ListNode merge(ListNode head) {
        ListNode curr = head;
        while (curr != null && curr.next != null) {
            if (curr.val == curr.next.val) {
                curr.next = curr.next.next;
            } else {
                curr = curr.next;
            }
        }
        return head;
    }
}

在上面的代码中,我们定义了一个 ListNode 类来表示链表的节点,并且每个节点包含一个整数值和一个指向下一个节点的指针。Solution 类中的 merge 方法接受一个链表的头节点作为参数,并返回合并相同元素后的链表的头节点。

性能分析

这个算法的时间复杂度是 O(n),其中 n 是链表的长度,因为我们只需一次遍历整个链表。空间复杂度是 O(1),因为我们只使用了常数级别的额外空间。

测试

为了验证我们的算法是否能正确地合并链表中的相同元素,我们可以编写一些测试用例,并使用 JUnit 框架执行测试。以下是一个示例测试用例:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class SolutionTest {
    @Test
    void testMerge() {
        ListNode head = new ListNode(1);
        head.next = new ListNode(1);
        head.next.next = new ListNode(2);
        head.next.next.next = new ListNode(3);
        head.next.next.next.next = new ListNode(3);

        Solution solution = new Solution();
        ListNode merged = solution.merge(head);

        Assertions.assertEquals(1, merged.val);
        Assertions.assertEquals(2, merged.next.val);
        Assertions.assertEquals(3, merged.next.next.val);
        Assertions.assertNull(merged.next.next.next);
   }
}

执行上述测试用例后,如果没有抛出任何异常,则说明我们的算法通过了测试。

总结

本文介绍了如何使用 Java 合并链表中的相同元素。我们通过遍历链表并比较每个节点与其后继节点的值,实现了删除链表中相同元素的操作。我们还对算法的时间复杂度和空间复杂度进行了分析,并提供了一个示例测试用例来验证算法的正确性。最后,我们可以将这个算法应用到实际的开发中,以解决类似的问题。