还是LeetCode上的一道题目:
现在有这么一个链表[1,1,2,3,4,5,5,5],要求你去去重,最后得到[1,2,3,4,5]
怎么来实现呢?
第一种方式:
/**
* 链表去重
* @param head 头结点
* @return 去重后的链表
*/
public ListNode distinct(final ListNode head)
{
if(head == null || head.getNext() == null)//如果链表为空或者只有一个节点,就直接返回
{
return head;
}
//让p1指向头结点,p2指向头结点的下一个节点
ListNode p1 = head;
ListNode p2 = p1.getNext() ;
while (p2 != null)//循环,直到p2为空
{
if(p1.getVal() == p2.getVal())//如果p1的值等于p2的值,就把p2移除
{
p1.setNext(p2.getNext());
}
else
{
p1 = p1.getNext();//如果p1的值不等于p2的值,就把p1后移
}
p2 = p1.getNext();//更新p2
}
return head;//返回去重后的链表的头结点
}
就是让p1一开始指向头节点,p2指向它的下一个节点,然后去比较,如果p1=p2就让p1指向p2的下一个节点,然后更新一下p2,只要p2不为空,就一直往下面循环比下去。
当然为了减少耦合我们可以整理一下代码:
/**
* 链表去重
* @param head 头结点
* @return 去重后的链表
*/
public ListNode distinct(final ListNode head)
{
if(head == null || head.getNext() == null)//如果链表为空或者只有一个节点,就直接返回
{
return head;
}
//让p1指向头结点,p2指向头结点的下一个节点
ListNode p1 = head;
ListNode p2 ;
while ((p2 = p1.getNext()) != null)//循环,直到p2为空
{
if(p1.getVal() == p2.getVal())//如果p1的值等于p2的值,就把p2移除
{
p1.setNext(p2.getNext());
}
else
{
p1 = p1.getNext();//如果p1的值不等于p2的值,就把p1后移
}
}
return head;//返回去重后的链表的头结点
}
第二种方式:递归
/**
* 链表去重
* @param p 起始指针
* @return 去重后的链表
*/
public ListNode distinct2(final ListNode p)
{
if(p == null || p.getNext() == null)//如果链表为空或者只有一个节点,就直接返回
{
return p;
}
if(p.getVal() == p.getNext().getVal())//如果当前节点的值等于下一个节点的值,就把下一个节点移除
{
return distinct2(p.getNext());//跳过当前节点继续往后比较
}
else//如果当前节点的值不等于下一个节点的值,就继续往后比较
{
p.setNext(distinct2(p.getNext()));//继续往后比较
return p;
}
}
递归思路就是拿第一个节点跟后面的一个比较,如果相等,跳过第一个节点,返回从第二个节点开始去重后的所有节点,通过递归调用的方式往后面比下去,如果两个节点的值不相等,那就给从第二个开始的后面的节点去重,最后返回头节点。
关于去重,还有一种要求就是一个都不留的:[1,1,2,3,4,5,5,5]--->[2,3,4]
/**
* 链表去重
* @param p 起始指针
* @return 去重后的链表
*/
public ListNode distinct3(final ListNode p)
{
if(p == null || p.getNext() == null)
{
return p;
}
if(p.getVal() == p.getNext().getVal())//如果当前节点的值等于下一个节点的值,就把下一个节点移除
{
ListNode temp = p.getNext();//记录下一个节点
while (temp != null && p.getVal() == temp.getVal())//循环,直到下一个节点为空或者下一个节点的值不等于当前节点的值
{
p.setNext(temp.getNext());//把下一个节点移除
temp = p.getNext();//重置下一个节点
}
return distinct3(p.getNext());//跳过当前节点继续往后比较
}
else
{
p.setNext(distinct3(p.getNext()));//继续往后比较
return p;
}
}
这个跟上面那个递归相比,多了一while循环,用于先将有重复的几个节点间进行去重,然后,去重后还剩一个,直接返回继续往后面去重后的链表。比如1重复了,先让它只有一个1,然后递归,返回1后面的去重后端链表,1就不要了。
用非递归:
/**
* 链表去重
* @param head 头结点
* @return 去重后的链表
*/
public ListNode distinct4(final ListNode head) {
ListNode s = new ListNode(-1, head);//头哨兵
ListNode p1 = s;
//p2和p3用于确定重复的范围
ListNode p2 ;
ListNode p3 ;
while ((p2 = p1.getNext()) != null && (p3 = p2.getNext()) != null)//循环,直到p2或p3为空
{
if(p2.getVal() == p3.getVal())//如果p2的值等于p3的值,就把p3移除
{
while (p3 != null && p2.getVal() == p3.getVal())//循环,直到p3为空或者p2的值不等于p3的值
{
p3 = p3.getNext();//把p3移除
}
p1.setNext(p3);//把p3移除
}
else//如果p2的值不等于p3的值,就继续往后比较
{
p1 = p2;
}
}
return s.getNext();
}
很明显这里又用了哨兵,p2,p3则标记一次重复的范围,标记完了后让p1直接指向p3后面那个节点。别看这里是p1.setNext(p3) 其实这里p3已经是p3.getNext()