赞
踩
今天一直在刷题,没有来得及学一些知识,就分享一下今天的刷题心得吧。
1. 206. 反转链表
- public ListNode reverseList(ListNode head) {
- return reverse(head, null);
- }
-
- private static ListNode reverse(ListNode head, ListNode tail) {
- if(head == null) {
- return tail;
- }
- ListNode temp = head.next;
- head.next = tail;
- return reverse(temp, head);
- }
递归是关键:每次递归时要分清每个参数的真实意义,比如在进入reverse(temp, head) 后temp就是下一轮递归的head,而head则是下一轮递归的tail。
- public ListNode swapPairs(ListNode head) {
- ListNode dumyhead = new ListNode(-1, head);
- ListNode cur = dumyhead;
- ListNode temp1 = null;
- ListNode temp2 = null;
- while(cur.next != null && cur.next.next != null) {
- temp1 = cur.next;
- temp2 = cur.next.next.next;
- cur.next = cur.next.next;
- temp1.next = temp2;
- cur.next.next = temp1;
- cur = temp1;
- }
- return dumyhead.next;
- }
这个题本身逻辑不难,易错点在于要经过多次改变节点指向后要知道当前节点在哪,头节点在哪。
- public ListNode removeNthFromEnd(ListNode head, int n) {
- ListNode dummyHead = new ListNode(-1,head);
- ListNode fast = dummyHead;
- ListNode slow = dummyHead;
- for (int i = 0; i <= n; i++) {
- fast = fast.next;
- }
- while (fast != null) {
- fast = fast.next;
- slow = slow.next;
- }
- slow.next = slow.next.next;
- return dummyHead.next;
- }
这道题尤其要注意空指针的问题,当你的链表只有一个节点的时候,如果你在用双指针的方法不进行处理,你这个头节点就无法删掉,一定会报空指针异常。
所以在做链表相关题目的时候一定要考虑几个问题:(1) 当前链表是一个[]
(2) 当前链表只有一个节点(删除问题)
(3)考虑while循环里面的条件
这道题还是比较有意思的,我参考答案整理了三种方法。
1)这道题的原理是,如果两个单向链表有交点,那么他们自交点后一定是一样长的,也就是说从尾巴开始往前一直到第一个相同节点,两个链表都是一样的。那么我们就可以让他们的尾巴对齐,然后长的那个链表跳到和短的链表相同的位置,再一起向后跳,每跳一次比较这两个节点是否相等(val和next都要相等),直到找到为止。
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode cur1 = headA;
- ListNode cur2 = headB;
- int index1 = 0;
- int index2 = 0;
- while (cur1 != null) {
- cur1 = cur1.next;
- index1++;
- }
- while (cur2 != null) {
- cur2 = cur2.next;
- index2++;
- }
- cur1 = headA;
- cur2 = headB;
- int diff = index1 - index2;
- if (diff >= 0) {
- for (int i = 0; i < diff; i++) {
- cur1 = cur1.next;
- }
- } else {
- for (int i = 0; i < -diff; i++) {
- cur2 = cur2.next;
- }
- }
- while (cur1 != null && cur2 != null) {
- if (cur1 == cur2) {
- break;
- }
- cur1 = cur1.next;
- cur2 = cur2.next;
- }
- return cur1;
- }
2)方法二采用了hashSet。利用hashSet先把第一个链表中的节点都装进去,然后从第二个链表的头开始遍历,看看是否hashSet包含这个节点,如果包含,第一个找到的节点就是我们要找的。原因是:单向链表的next只有一个,不能分叉,所以只要找到第一个相同的节点,那么它就一定是。
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode cur = headA;
- Set<ListNode> set = new HashSet<>();
- while (cur != null) {
- set.add(cur);
- cur = cur.next;
- }
- cur = headB;
- while (cur != null) {
- if (set.contains(cur)) {
- break;
- }
- cur = cur.next;
- }
- return cur;
- }
3)方法三,采用了双指针的做法。它的思路其实和方法一是一致的,本质上还是让两个链表的尾巴对齐,然后到了两个链表一样长的位置,一起往后跳,直到找到第一个相同的节点。
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode cur1 = headA;
- ListNode cur2 = headB;
- if (headA == null || headB == null) {
- return null;
- }
- while (cur1 != cur2) {
- if (cur1 == null) {
- cur1 = headB;
- } else {
- cur1 = cur1.next;
- }
- if (cur2 == null) {
- cur2 = headA;
- } else {
- cur2 = cur2.next;
- }
- }
- return cur1;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。