当前位置:   article > 正文

【刷题笔记】链表篇

【刷题笔记】链表篇

今天一直在刷题,没有来得及学一些知识,就分享一下今天的刷题心得吧。

1. 206. 反转链表

  1. public ListNode reverseList(ListNode head) {
  2. return reverse(head, null);
  3. }
  4. private static ListNode reverse(ListNode head, ListNode tail) {
  5. if(head == null) {
  6. return tail;
  7. }
  8. ListNode temp = head.next;
  9. head.next = tail;
  10. return reverse(temp, head);
  11. }

递归是关键:每次递归时要分清每个参数的真实意义,比如在进入reverse(temp, head) 后temp就是下一轮递归的head,而head则是下一轮递归的tail。

2. 24. 两两交换链表中的节点

  1. public ListNode swapPairs(ListNode head) {
  2. ListNode dumyhead = new ListNode(-1, head);
  3. ListNode cur = dumyhead;
  4. ListNode temp1 = null;
  5. ListNode temp2 = null;
  6. while(cur.next != null && cur.next.next != null) {
  7. temp1 = cur.next;
  8. temp2 = cur.next.next.next;
  9. cur.next = cur.next.next;
  10. temp1.next = temp2;
  11. cur.next.next = temp1;
  12. cur = temp1;
  13. }
  14. return dumyhead.next;
  15. }

这个题本身逻辑不难,易错点在于要经过多次改变节点指向后要知道当前节点在哪,头节点在哪。

3.19. 删除链表的倒数第 N 个结点

  1. public ListNode removeNthFromEnd(ListNode head, int n) {
  2. ListNode dummyHead = new ListNode(-1,head);
  3. ListNode fast = dummyHead;
  4. ListNode slow = dummyHead;
  5. for (int i = 0; i <= n; i++) {
  6. fast = fast.next;
  7. }
  8. while (fast != null) {
  9. fast = fast.next;
  10. slow = slow.next;
  11. }
  12. slow.next = slow.next.next;
  13. return dummyHead.next;
  14. }

这道题尤其要注意空指针的问题,当你的链表只有一个节点的时候,如果你在用双指针的方法不进行处理,你这个头节点就无法删掉,一定会报空指针异常。

所以在做链表相关题目的时候一定要考虑几个问题:(1) 当前链表是一个[]

                                                                                   (2) 当前链表只有一个节点(删除问题)

                                                                                   (3)考虑while循环里面的条件

4. 面试题 02.07. 链表相交

这道题还是比较有意思的,我参考答案整理了三种方法。

1)这道题的原理是,如果两个单向链表有交点,那么他们自交点后一定是一样长的,也就是说从尾巴开始往前一直到第一个相同节点,两个链表都是一样的。那么我们就可以让他们的尾巴对齐,然后长的那个链表跳到和短的链表相同的位置,再一起向后跳,每跳一次比较这两个节点是否相等(val和next都要相等),直到找到为止。

  1. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  2. ListNode cur1 = headA;
  3. ListNode cur2 = headB;
  4. int index1 = 0;
  5. int index2 = 0;
  6. while (cur1 != null) {
  7. cur1 = cur1.next;
  8. index1++;
  9. }
  10. while (cur2 != null) {
  11. cur2 = cur2.next;
  12. index2++;
  13. }
  14. cur1 = headA;
  15. cur2 = headB;
  16. int diff = index1 - index2;
  17. if (diff >= 0) {
  18. for (int i = 0; i < diff; i++) {
  19. cur1 = cur1.next;
  20. }
  21. } else {
  22. for (int i = 0; i < -diff; i++) {
  23. cur2 = cur2.next;
  24. }
  25. }
  26. while (cur1 != null && cur2 != null) {
  27. if (cur1 == cur2) {
  28. break;
  29. }
  30. cur1 = cur1.next;
  31. cur2 = cur2.next;
  32. }
  33. return cur1;
  34. }

2)方法二采用了hashSet。利用hashSet先把第一个链表中的节点都装进去,然后从第二个链表的头开始遍历,看看是否hashSet包含这个节点,如果包含,第一个找到的节点就是我们要找的。原因是:单向链表的next只有一个,不能分叉,所以只要找到第一个相同的节点,那么它就一定是。

  1. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  2. ListNode cur = headA;
  3. Set<ListNode> set = new HashSet<>();
  4. while (cur != null) {
  5. set.add(cur);
  6. cur = cur.next;
  7. }
  8. cur = headB;
  9. while (cur != null) {
  10. if (set.contains(cur)) {
  11. break;
  12. }
  13. cur = cur.next;
  14. }
  15. return cur;
  16. }

3)方法三,采用了双指针的做法。它的思路其实和方法一是一致的,本质上还是让两个链表的尾巴对齐,然后到了两个链表一样长的位置,一起往后跳,直到找到第一个相同的节点。

  1. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  2. ListNode cur1 = headA;
  3. ListNode cur2 = headB;
  4. if (headA == null || headB == null) {
  5. return null;
  6. }
  7. while (cur1 != cur2) {
  8. if (cur1 == null) {
  9. cur1 = headB;
  10. } else {
  11. cur1 = cur1.next;
  12. }
  13. if (cur2 == null) {
  14. cur2 = headA;
  15. } else {
  16. cur2 = cur2.next;
  17. }
  18. }
  19. return cur1;
  20. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/875604
推荐阅读
相关标签
  

闽ICP备14008679号