2020年发生了湖北武汉肺炎疫情,居家不外出,so,每天按系列刷一些经典的题目。今天先从链表的5道题目走起。
206. Reverse Linked List(Easy)
题目:翻转一个单链表。
Example:
1->2->3->4->5->NULL
参考代码:
class Solution { public ListNode reverseList(ListNode head) { if(head==null || head.next==null) return head; ListNode pre = null; ListNode p = head; ListNode next; while(p!=null){ next = p.next; p.next = pre; pre = p; p= next; } return pre; }}
160. Intersection of Two Linked Lists(Easy)
题目:求两个单链表的交点。
举例:A链表和B链表有交叉点,返回值为c1。
思路1:暴力解法,两层循环,如果找到返回节点。否则返回空。
思路2:利用哈希表,遍历一个链表,存储到set集合中。然后遍历另一个链表,如果该节点在set中,则直接返回这个节点。遍历完没找到,则返回空。
思路3:计算两个链表的长度分别为m和n,长度较大的链表先走abs(m-n)步,然后两个链表一起往后走,判断节点是否相等。
参考代码(思路3):
public ListNode getIntersectionNode(ListNode headA, ListNode headB) { int m= lengthOfList(headA); int n =lengthOfList(headB); ListNode pA = headA; ListNode pB = headB; if(m>n){//先走m-n步 int k = m-n; for(int i=1;i<=k;i++) pA = pA.next; } else{ //先走n-m步 int k = n-m; for(int i=1;i<=k;i++) pB = pB.next; } while(pA!=null && pB!=null){ if(pA==pB) return pA; pA =pA.next; pB =pB.next; } return null; }public int lengthOfList(ListNode head){//辅助函数 if(head==null) return 0; int mCount =0; ListNode p = head; while(p!= null){ mCount++; p = p.next; } return mCount;}
141. Linked List Cycle(Easy)
题目:判断一个链表是否有环
举例:如下链表,-4节点的下一个节点又是2节点,返回true。
思路:采用快慢指针,快指针每次走两步,慢指针走一步,如果相遇则存在环。如果快指针遇到空结束,则返回false。
参考代码如下:
public boolean hasCycle(ListNode head) { if(head==null) return false; ListNode slow =head; ListNode fast = head; while(fast!=null && fast.next!=null){ fast = fast.next.next; slow = slow.next; if(fast == slow) return true; } return false; }
142. Linked List Cycle II(medium)
题目:返回一个带环链表的起始节点
举例:如下链表,-4节点的下一个节点又是2节点,返回2节点。
思路:使用快慢指针,相遇点到链表头节点的距离等于头结点到链表起始节点的距离。于是,我们从head节点和相遇点开始依次各走一步,直到再次相遇,这个点就是起始点。
参考代码如下:
public ListNode detectCycle(ListNode head) { if(head==null) return null; ListNode slow =head; ListNode fast = head; while(fast!=null && fast.next!=null){//先找到相遇点 slow = slow.next; fast = fast.next.next; if(fast == slow) break; } if(fast==null ||fast.next ==null) //没有环 return null; slow = head; //将slow从head节点开始遍历 while(slow!=fast){ slow = slow.next; fast = fast.next; } return slow; }
287. Find the Duplicate Number(Medium)
题目:寻找数组中的重复元素,元素个数n+1,每个元素取值范围为1-n。
举例:
2
思路1:采用暴力求解法,两层for循环,如果找到返回对应元素。否则返回0 代表没找到。
思路2:采用哈希表法,遍历每个元素,去哈希表中查找看看是否存在,如果存在直接返回该元素。否则,将该元素加入哈希表中。
思路3:不断将当前元素值作为下一个下标,能得到一个数组环,见下面示例。然后使用快慢指针分别指向数组尾部, 快指针执行两次,慢指针执行一次直到快慢指针相遇。最后让慢指针从尾节点开始,依次和快指针每次走一步,当相遇的时候即重复的元素。整个解题的思路和上面这个循环链表的初始节点题目(141题)思路一样。
参考代码如下:
public int findDuplicate(int[] nums) { if(nums==null||nums.length<=0) return 0; int n=nums.length;//数组长度 int slow =n-1; int fast = n-1; while(true){ slow = nums[slow]-1;//慢指针走一步 fast = nums[fast]-1;//快指针走两步 fast =nums[fast]-1; if(slow == fast) break; } slow = n-1; while(slow!=fast){ slow = nums[slow]-1; fast = nums[fast]-1; } return slow+1; }
总结: 今天先刷5道题目,这种链表环的思路很值得总结和体会。