做leetcode的这两道题,感觉收获还是挺多的,总结一下。
I题题目:
给定一个单链表,删除其中重复数据,使原链表中的数据都只出现一次。
I题没有什么难点,当时做完之后针对链表的题目写了这么几句话:
1.需要几个指针先弄清楚。
2.最后需要返回的指针要预留出来。
后来在Discuss里研究别人的答案,又加了一条:
3.需要把废弃的节点都回收了。麻烦的是如果这么做一般还需要多搞出一个指针。
II题题目:
给定一个单链表,删除其中所有的重复数据,只留下原链表中单独存在的数据。
II题刚开始自己没做出来,主要是按照I题总结的方法做,越做越跑偏。
因为最终的头结点刚开始是不能确定的,如果按照上面的2来做,先要把返回节点确定下来,再继续过程,实在是太麻烦了,不知道要用到多少指针。
后来研究了别人的算法,在Discuss里号称是best c++ solution,刚开始都没看懂····分析了一半天才恍然大悟!
原来双重指针是有这样的作用啊,之前除了课本上要求,还从来没有主动用过双重指针。
大体思路是这样的:(head指针图中用h表示)
新定义了一个指向head指针的指针runner(图中用r表示)
1-->1-->1-->2-->3-->nullptr
h
r
用*r(最开始的时候其实就是head)控制指针的后移
如果满足条件((*runner)->next && (*runner)->val==(*runner)->next->val)则说明等于此值的所有元素需要被删除,即将*r指针后移,开始while循环,直到*runner指向一个新值,继续对上面的条件进行判定。
1-->1-->1-->2-->3-->nullptr
h
r
如果上面的条件不成立,则说明该节点是单一的,属于结果链表,不做处理直接跳过
重点就在这里,此时不是简单的指针后移,而是将双重指针进行了后移,即runner指向了下一个指针:runner=&((*runner)->next);
1-->1-->1-->2-->3-->nullptr
h
r
所以,在head没有找到返回节点之前,head是一直跟着*runner向后移动的,当head找到了第一个结果节点的时候,runner就更改了指向,指向head指针的下一个节点,之后head就不再移动了。
此方法可以更好的保持程序的一致性,不需要单独为寻找返回指针而写一段代码,感觉还是很好的。