我的解法 :
easy 难度的题目, 上来思路也比较简单, 开一个新的哨兵结点, 然后依次遍历给定链表, 如果链表当前结点的值与新链表的当前结点的值不同, 就将其加入到新链表中, 否则就直接跳过. 下面是代码 :
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode l = new ListNode(-1);
ListNode cur = l;
while(head != null) {
if(head.val != cur.val) {
cur.next = head;
cur = cur.next;
}
head = head.next;
}
return l.next;
}
}
代码的允许结果是部分通过, 未通过的案例有 :
Input : [ 1, 1, 2, 3, 3]
Output : [ 1, 2, 3, 3]
Expected : [ 1, 2, 3]
思考了一会发现问题所在, 所有最后连续重复的数字是无法通过的, 因为这里并不是新开一个结点放到新链表中, 而是通过指针将给定链表中的部分结点连接起来, (上例中)当连接到倒数第二个 3 的时候, 这个结点已经纳入了新的链表中, 但是它原有的结构关系还是在的, 所以遍历的时候, 会把最后重复数字都加上. 这就是错误所在.
找到了错误, 改进的方法也简单, 每个要加入新链表的值, 直接开一个新结点, 而不是连接到给定链表的结点上. 然后哨兵结点的值设置为最小的 int 型的值.
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode l = new ListNode(Integer.MIN_VALUE);
ListNode cur = l;
while(head != null) {
if(head.val != cur.val) {
ListNode tem = new ListNode(head.val);
cur.next = tem;
cur = cur.next;
}
head = head.next;
}
return l.next;
}
}
这样的话, 空间复杂度就上去了. 肯定不是最佳解法.
大神的解法 :
直接改变原链表的连接关系, 也不用添加哨兵结点, 直接开始比较.
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode list = head;
while(list != null) {
if(list.next == null)
break;
if(list.val == list.next.val)
list.next = list.next.next;
else
list = list.next;
}
return head;
}
}
使用递归
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null)
return head;
head.next = deleteDuplicates(head.next);
return head.val == head.next.val ? head.next : head;
}
}
这段代码的理解 : 首先递归要确定递归结束的条件, 所以 if 条件就给出了递归结束的情况.
然后 head.next = deleteDuplicates(head.next) 这句代码保证了 从 head.next 到链表的结尾, 都没有重复的结点.
所以我们要决定的是 head 指向当前的 head 还是 head.next, 通过比较值可以得到. 如果值不相同, 就从 head 开始, 加上后面不重复的链表, 如果值相同, 就直接指向后面不重复的链表即可.
递归的代码就是锻炼一下思维. 学习一下.