经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 编程经验 » 查看文章
关于LeetCode上链表题目的一些trick
来源:cnblogs  作者:xinyuexy  时间:2018/10/8 8:49:41  对本文有异议

最近在刷leetcode上关于链表的一些高频题,在写代码的过程中总结了链表的一些解题技巧和常见题型。

结点的删除

指定链表中的某个结点,将其从链表中删除。

由于在链表中删除某个结点需要找到该结点的前一个位置,然后将前一个结点的next指针直接绕过该结点即可删除。但找到该结点的前一个位置需要指针遍历,其实还有一种更简单的trick,就是将要删除的结点的值设为该结点的后一个的值,然后删除该结点的后一个结点(间接删除,不需要找遍历前一个指针),代码如下:

  1. class Solution {
  2. public void deleteNode(ListNode node) {
  3. node.val = node.next.val;
  4. node.next = node.next.next;
  5. }
  6. }

在表头前增加虚拟结点

很多场合下,在链表的表头前增加一个虚拟结点(dummy),并让其指向head,能简化很多操作。如在新创建一个链表或对链表进行遍历操作时,如果不增加虚拟结点,就需要处理当前结点是头结点的特殊情况(因为头结点前没有其他结点,导致操作代码不一致)。加了虚拟结点后就可以像操作其他结点一样对待头结点了,最后只需要返回虚拟结点的next就可以了。

如LeetCode上的这一题:Remove Nth Node From End of List

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. ListNode dummy = new ListNode(0);
  4. dummy.next = head;
  5. ListNode p = dummy;
  6. ListNode q = dummy;
  7. while(n > 0) {
  8. q = q.next;
  9. n--;
  10. }
  11. while(q.next != null) {
  12. p = p.next;
  13. q = q.next;
  14. }
  15. p.next = p.next.next;
  16. return dummy.next;
  17. }
  18. }

链表转置

这应该是我碰到的链表中最频繁的问题了,很多其他链表的题目可能也需要借助于链表转置这一功能,所以需要能够熟练地写出代码,这里给出包括迭代和递归两种版本的代码:

  1. class Solution {
  2. //迭代实现链表转置
  3. public ListNode reverseList(ListNode head) {
  4. ListNode prev = null;
  5. while(head != null) {
  6. ListNode next = head.next;
  7. head.next = prev;
  8. prev = head;
  9. head = next;
  10. }
  11. return prev;
  12. }
  13. //递归实现链表转置
  14. public ListNode reverseList2(ListNode head) {
  15. if(head == null || head.next == null)
  16. return head;
  17. ListNode next = head.next;
  18. //对head.next执行转置
  19. ListNode newHead = reverseList(next);
  20. //此时next变成了转置后的尾结点
  21. next.next = head;
  22. head.next = null;
  23. return newHead;
  24. }
  25. }

快慢双指针

有时候需要找到链表的中间位置的结点,这时就需要设置两个指针slow和fast,slow每次往前移动一个,fast移动两个。当fast为空时,slow就指向了链表的中间位置。比如leetcode上的Palindrome Linked List在判断链表是否回文时,需要找到中间位置,然后将其后半部分转置和前半部分相比较,具体实现代码如下:

  1. class Solution {
  2. public boolean isPalindrome(ListNode head) {
  3. if(head == null || head.next == null) {
  4. return true;
  5. }
  6. //注意不能直接转置整个链表,需要找到链表的中间,只转置后半部分
  7. ListNode fast = head, slow = head;
  8. while(fast != null && fast.next != null) {
  9. fast = fast.next.next;
  10. slow = slow.next;
  11. }
  12. //这时slow指向了链表的中间结点(注意这种trick要记住)
  13. slow = reverseList(slow);
  14. while(head != null && slow != null) {
  15. if(head.val != slow.val) {
  16. return false;
  17. }
  18. head = head.next;
  19. slow = slow.next;
  20. }
  21. return true;
  22. }
  23. private ListNode reverseList(ListNode head) {
  24. ListNode prev = null;
  25. while(head != null) {
  26. ListNode next = head.next;
  27. head.next = prev;
  28. prev = head;
  29. head = next;
  30. }
  31. return prev;
  32. }
  33. }

合并两个有序链表

这也是碰到的很常见的问题了,合并两个有序链表使其仍然保持有序,一般采用双指针法,这也需要能够熟练地写出无bug的代码来。这里给出迭代和递归两种实现方式:

  1. class Solution {
  2. public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  3. if(l1 == null && l2 == null) {
  4. return null;
  5. }
  6. ListNode p = l1;
  7. ListNode q = l2;
  8. ListNode dummy = new ListNode(0);
  9. ListNode pp = dummy;
  10. while(p != null && q != null) {
  11. if(p.val < q.val) {
  12. dummy.next = new ListNode(p.val);
  13. p = p.next;
  14. }
  15. else {
  16. dummy.next = new ListNode(q.val);
  17. q = q.next;
  18. }
  19. dummy = dummy.next;
  20. }
  21. if(p != null) {
  22. //直接将dummy指过去
  23. dummy.next = p;
  24. }
  25. if(q != null) {
  26. dummy.next = q;
  27. }
  28. return pp.next;
  29. }
  30. //使用递归更简单
  31. public ListNode mergeTwoLists2(ListNode l1, ListNode l2) {
  32. if(l1==null) return l2;
  33. if(l2==null) return l1;
  34. if(l1.val<l2.val){
  35. l1.next = mergeTwoLists(l1.next,l2);
  36. return l1;
  37. }
  38. else{
  39. l2.next = mergeTwoLists(l1,l2.next);
  40. return l2;
  41. }
  42. }
  43. }

目前碰到的问题就这么多了,后面再继续补充吧。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号