这个题是一个关于链表的基础题,也是LeetCode中的一个题(现在是203题,以后可能题号会变)
虽然这个题比较基础,但是还是有很多坑。请看代码:
/**
* 不带表头结点的链表的删除
* @param head 传进来的链表的头指针
* @param val 要删除的值
* @return
*/
public ListNode removeElements(ListNode head, int val) {
//当链表没有头结点的时候[又叫虚拟头结点],对于头结点和其他结点的删除方式是不一样的,所以需要分情况
//有可能删除了第一个结点是要找的节点,删除了之后下一个结点还是要找的结点,所以这里要用while循环删除
//头结点紧挨着的所有结点
while (head!=null&&head.val==val)//这里要判空,有可能传进来的结点就是一个头结点
{
head=head.next;//投指针后移
}
//当与头结点相连的要找的值全部删除完成之后,有可能链表为空,所以这里还需要判断一次
if(head==null)
return null;
//此时的head值一定不是一个val,所以从他的下一个结点开始判断
ListNode pre=head;
//直到某一个结点的下一个结点为空结束循环
while (pre.next!=null)
{
if(pre.next.val==val)
{
//删除pre指向的next结点,注意:删除了之后pre的下一个结点值变化了,所以此处不能由pre=pre.next
pre.next=pre.next.next;
}else
{
//当pre指向的值不等于val的时候,pre后移
pre=pre.next;
}
}
//返回该链表的头结点
return head;
}
/**
* 带表头结点的链表的删除
* @param head 链表的头结点
* @param val 需要删除的值
* @return
*/
public ListNode removeElements1(ListNode head, int val) {
//由于LeetCode测试的时候默认创建的是不带表头结点的,但是带表头结点使用起来更为方便,
//所以这里临时添加了一个表头结点
ListNode tempHead=new ListNode(0);
tempHead.next=head;
//pre之向这个表头结点
ListNode pre=tempHead;
//因为pre是自己new出来的,不可能为null,所以这里要自己不用判断pre是否为空
while (pre.next!=null)
{
if(pre.next.val==val)
{
pre.next=pre.next.next;
}else {
pre=pre.next;
}
}
//这里看似可以返回head,因为tempHead.next指向的就是head。实际则不行
//假如输入结点是1 要删除的也是1,删除了之后,head的空间没有释放,它还有值1,而此时preHead指向的next空值
return tempHead.next;
}
public static ListNode removeElements2(ListNode head, int val) {
if (head == null)
return null;
//找到最后一个节点,
head.next = removeElements2(head.next, val);
//判断是否符合条件,是value删除该节点,不是返回.然后回退
return head.val == val ? head.next : head;
}
public static ListNode removeElements3(ListNode head, int val) {
if (head == null)
return null;
if (head.val==val)
head=removeElements3(head.next,val);
else
head.next=removeElements3(head.next,val);
return head;
}
后两种知道楼主知道是什么意思,但是无法用语言描述,比较抽象的东西。如果对递归不清楚的,可以debug一下,然后一步一步看会比较有帮助