链表
链表部分个人认为是最烦的,大部分链表题考的都是coding技巧,不需要怎么思考,但是没有写过几次的话,链表的coding是各种陷阱。
先总结一下题型,链表的题目主要两种:
1. 链表翻转(包括全翻转,部分翻转,分段翻转);
2. 链表删除/增加(包括删除某值,删除倒数第K个,去重)。
具体说,全翻转就是给你一个单向链表,你把它倒过来;部分翻转就是,给一个单向链表,给一个a和b,让你把第a到第b个节点翻转;分段翻转就是给一个单向链表,给一个k,让你把每k个作为一组,翻转过来。(真是你妹啊。。。。)
链表的删除就是,一个是删除某个值,一个是删除倒数第k个值(这个可以遍历两次,或者一次遍历同时保留k个指针,或者递归,在回溯时删除),一个是给一个链表,让你把出现超过一次的元素全部删除或者只留一个(这个又有有序链表和无序链表之分)。(真是你妹啊。。。。)
其实对于翻转,也可以直接使用删除,插入的方法。每次把下一个节点插入到头,就可以实现链表的翻转,所以,链表的插入删除是最重要的。要删除一个node节点,再把node放到head后面,核心代码就这三句,但是经常用到:
pre->next = node->next;//删除
node->next = head->next;//head->next接到node后面
head->next = node;//node接到head后面
先断开,再接node->next再head->next。其他要注意的是head是不是为NULL(用dummy head 可以解决)、如果只是删除记得断开后delete、记得更新你的迭代节点(就是例子中的node)。
主要的技巧就是要用dummy head,就是在链表头加一个节点指向head,这样可以避免判断头指针,统一处理所有情况,最后返回dummy->next;另外有一个跟dummy head等价的方法是用指针的指针**p去处理,也能达到dummy head的效果,比dummy好的地方是,不用delete dummy head,另外如果一个节点比较大的话,用**p也比较省空间,但是逻辑上比dummy要绕一点,可以参考这个文章:http://coolshell.cn/articles/8990.html
一般来说用dummy head就好,大概意思如下:
ListNode* ProcessList(ListNode* head){
ListNode* dummy = new ListNode();
dummy->next = head;
//process the list
head = dummy->next;
delete dummy;
return head; //再提醒一次,请记得delete
}
链表的东西不多说,主要就是记住删除插入时操作顺序(上面的那三行代码),记住delete自己new出来的node。
leetcode上关于链表的题目,还算蛮多的(代码放到另一篇blog里面);
Remove Duplicates from Sorted List
Remove Duplicates from Sorted List II
Remove Nth Node From End of List