zz: LeetCode 阶段性总结(一)
来源:互联网 发布:c语言的头文件在哪里 编辑:程序博客网 时间:2024/05/17 21:43
原文转自:http://www.yclod.com/leetcode-jie-duan-xing-zong-jie/
前段时间忙着准备面试找工作,抽空做了LeetCode上的题,由于时间的原因没有全部做完,而是根据“二爷”的难度表从各种分类里面挑着做了一些。后来给我的小伙伴们总结性的share了一下。主要内容包括3个部分:LinkedList, DFS/BFS, DP.
现在记录一些我总结出来的解题思路。
LinkedList
思路: 链表的题应该算是比较容易的题,因为数据结构较为单一,所以可想考点不多。那么最容易考什么呢?这就要从链表最大的特色说起 -- “没有Index”。因为链表没有index,一般不能直接寻址,所以一些在数组(直接寻址)上很容易做到的操作,在链表上会有更高的时间开销。比如经典题,寻找倒数第N个元素等。所以考点就在于如何利用一些方法,来尽可能小的减小时间和空间的开销(当你发现你的算法需要不止一次遍历链表或者需要额外存储O(n)以上的空间时,就至少应该考虑考虑有没有方法可以优化了)。其中最常见的方法是:
2个指针 : 一快一慢,一远一近,一前一后
这个方法,就是通过建立具有一定关系的两个(或更多)指针,用来减少遍历。
典型例题如:
1. Remove Nth Node From End of List
Given a linked list, remove the nth node from the end of list and return its head.
For example,
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5. Note:
Given n will always be valid.
Try to do this in one pass.
这道题建立2个指针,一前一后,相距n的距离,然后一起移动,当后者为空(遍历完链表),前者即为所求。
public class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { if(head == null) return null; if(n <= 0) return head; ListNode preHead = new ListNode(-1); preHead.next = head; ListNode p1 = head; ListNode p2 = p1; ListNode preP1 = preHead; while(n-- > 0){ p2 = p2.next; } while(p2 != null){ preP1 = p1; p1 = p1.next; p2 = p2.next; } preP1.next = p1.next; return preHead.next; }}
2. Linked List Cycle I / II
I. Given a linked list, determine if it has a cycle in it.
II. Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Follow up: Can you solve it without using extra space?
这道题第一问是要检查一个单链表中是否有环,这个问题乍一看需要用到O(n)的额外空间来记录之前遍历过的节点。此题依然用“两个指针”的思路来优化:建立两个指针,一快一慢,慢的每次走一步,快的每次走两步,那么如果有环,快指针一定会追上慢指针。条件判断一旦快指针全等于慢指针时,必然有环。为什么会相等?会不会永远正好错过不相等?考虑这样的情况:快指针绕了n圈以后出现在慢指针后面,在快要相交的时候,要么在慢指针身后距离2的地方,要么在距离1的地方,如果距离为2,那么在下一次移动时就变成了距离为1.所以总有一个时候,快指针在慢指针后面距离为1的地方,在这个时刻的下一个时刻,就会相等。而不会出现一次次错过的情况。
public class Solution { public boolean hasCycle(ListNode head) { if(head == null || head.next == null) return false; ListNode slowP = head; ListNode fastP = head.next; while(slowP != fastP){ if(fastP == null || fastP.next == null) return false; slowP = slowP.next; fastP = fastP.next.next; } return true; }}
第二问是返回可能存在环的起点。这一问比较难证明(有兴趣的同学可以证明一下),不过结论还是很好记住的,即:接第一问,当快慢两指针重合的时候,慢指针继续慢慢一步一步向前走,将快指针指向链表的开头,然后也改为很慢指针一样的速度一步一步向前走,当两个指针再次重合的时候,即为所求的环的起点。
public class Solution { public ListNode detectCycle(ListNode head) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. if(head == null || head.next == null) return null; ListNode slowP = head; ListNode fastP = head.next; while(slowP != fastP){ if(fastP == null || fastP.next == null) return null; slowP = slowP.next; fastP = fastP.next.next; } ListNode cur = head; while(slowP.next != cur){ cur = cur.next; slowP = slowP.next; } return cur; }}
总之,“两个指针”四个字,为解决很多链表题,提供了很好的思路。
DFS / BFS
掌握了哥的GetAdj,剩下的就是狂狂写代码了。
(未完,待续)
- zz: LeetCode 阶段性总结(一)
- html阶段性总结(一)
- Hibernate阶段性总结(一)
- python入门学习阶段性总结(一)
- 阶段性总结(一)
- MapReduce阶段性总结实例一
- Hive阶段性总结实例一
- 软件工程阶段性总结(一)——概述
- 阶段性总结一之线程互斥
- 阶段性学习总结(2)
- 阶段性学习总结(3)
- 阶段性总结(2016.夏)
- 阶段性总结
- 阶段性总结!
- 阶段性总结
- 阶段性总结
- 阶段性总结
- 阶段性总结
- 字符串处理_验证文件名和邮箱地址是否合法
- 字符串的拆分split
- 字符串应用_统计字符串中某个字符的个数
- StringBuffer类的使用
- StringBuffer类中insert()方法的使用
- zz: LeetCode 阶段性总结(一)
- StringBuffer类的方法应用_小数点前每隔三位加一个,号
- java实现中文汉字的首字母排序
- substring()的应用_查找某个字符在字符串中的具体位置
- SimpleDateFormat使用详解(转)
- 迷你DVD租用管理系统
- 构造方法与方法的重载
- 使用this调用重载的构造方法
- 继承关系中的构造方法