Skip to content

Commit

Permalink
add solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
0xkookoo committed Oct 1, 2017
0 parents commit 856dfab
Show file tree
Hide file tree
Showing 250 changed files with 16,931 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
43 changes: 43 additions & 0 deletions 001._two_sum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
###1. Two Sum

题目:
<https://leetcode.com/problems/two-sum/>


难度:

Easy


思路

可以用O(n^2) loop

但是也可以牺牲空间换取时间,异常聪明的AC解法

```
2 7 11 15
不存在 存在之中
lookup {2:0} [0,1]
```

一点字典有了这个 `target - 当前数字`,找到它的index和当前index一起返回。


```
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
lookup = {}
for i, num in enumerate(nums):
if target - num in lookup:
return [lookup[target - num],i]
lookup[num] = i
return []
```


37 changes: 37 additions & 0 deletions 002._add_two_numbers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
###2. Add Two Numbers

题目:
<https://leetcode.com/problems/add-two-numbers/>


难度 : Medium


跟plus One, add Binary 玩的同一种花样


```
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
#easiest case
if l1 == None:
return l2
if l2 == None:
return l1
if l1.val + l2.val < 10:
l3 = ListNode(l1.val + l2.val)
l3.next = self.addTwoNumbers(l1.next, l2.next)
elif l1.val + l2.val >= 10:
l3 = ListNode(l1.val + l2.val - 10)
tmp = ListNode(1)
tmp.next = None
l3.next = self.addTwoNumbers(l1.next, self.addTwoNumbers(l2.next ,tmp))
return l3
```
56 changes: 56 additions & 0 deletions 003._longest_substring_without_repeating_characters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
###3. Longest Substring Without Repeating Characters


题目:
<https://leetcode.com/problems/longest-substring-without-repeating-characters/>


难度:

Medium



思路

粗一看是dp,细一看是greedy


idx 0 1 2 3 4 5 6 7
a b c a b c b b
rnd ↑ stop↑
↑ stop↑
↑ stop↑


因为其实只要每次记录下重复开始的位置,就可以解决问题。


注意最后还有一个 n - start 和 l 来比较,这相当于是最后一个round


如果当前重复的这个s[i]取值是限定大于start,就是在start之后再出现重复


```
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
n = len(s)
l = 0
maps = {}
start = 0
for i in range(n):
if maps.get(s[i],-1) >= start:
l = max(i - start, l)
start = maps.get(s[i]) + 1
print start
maps[s[i]] = i
return max(n - start, l)
```


151 changes: 151 additions & 0 deletions 004._median_of_two_sorted_arrays.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
###4. Median of Two Sorted Arrays

题目:
<https://leetcode.com/problems/median-of-two-sorted-arrays/>


难度:

Hard


一看到的时候,觉得跟CLRS书上的一道习题类似
求X[1....n] Y[1....n] 的 median

习题 9.3-8


Let X[1..n] and Y [1..n] be two arrays, each containing n numbers already in sorted order. Give an O(lg n)-time algorithn to find the median of all 2n elements in arrays X and Y .


> The median can be obtained recursively as follows. Pick the median of the sorted array A. This is just O(1) time as median is the n/2th element in the sorted array. Now compare the median of A, call is a∗ with median of B, b∗. We have two cases.
- a∗ < b∗ : In this case, the elements in B[n/2 ···n] are also greater than a . So the median cannot lie in either A[1 · · · n/2 ] or B[n/2 · · · n]. So we can just throw these away and recursively
- a∗ > b∗ : In this case, we can still throw away B[1··· n/2] and also A[ n/ · · · n] and solve a smaller subproblem recursively.
In either case, our subproblem size reduces by a factor of half and we spend only constant time to compare the medians of A and B. So the recurrence relation would be T (n) = T (n/2) + O(1) which has a solution T (n) = O(log n).
divide and conquer

- 如果X[n/2] == Y[n/2],则找到,return
- 如果X[n/2] < Y[n/2],找X[n/2+1….n]和Y[1,2…n/2]之间
- 否则找X[1..n/2]和Y[n/2…n]




但是实际上不同,这里需要考虑的问题更多:

- 两个数组长度不一样
- 并不是只找一个median,如果median有两个,需要算平均

思路

把它转化成经典的findKth问题

参考: <http://chaoren.is-programmer.com/posts/42890.html>


首先转成求A和B数组中第k小的数的问题, 然后用k/2在A和B中分别找。


比如k = 6, 分别看A和B中的第3个数, 已知 A1 < A2 < A3 < A4 < A5... 和 B1 < B2 < B3 < B4 < B5..., 如果A3 <= B3, 那么第6小的数肯定不会是A1, A2, A3, 因为最多有两个数小于A1, 三个数小于A2, 四个数小于A3。 关键点是从 k/2 开始来找。



B3至少大于5个数, 所以第6小的数有可能是B1 (A1 < A2 < A3 < A4 < A5 < B1), 有可能是B2 (A1 < A2 < A3 < B1 < A4 < B2), 有可能是B3 (A1 < A2 < A3 < B1 < B2 < B3)。那就可以排除掉A1, A2, A3, 转成求A4, A5, ... B1, B2, B3, ...这些数中第3小的数的问题, k就被减半了。每次都假设A的元素个数少, pa = min(k/2, lenA)的结果可能导致k == 1或A空, 这两种情况都是终止条件。


发问,为什么要从k/2开始寻找,依旧k = 6, 我可以比较A1 和 B5的关系么,可以这样做,但是明显的问题出现在如果A1 > B5,那么这个第6小的数应该存在于B6和A1中。

如果A1 < B5,这个时间可能性就很多了,比如A1 < A2 < A3 < A4 < B1 < B2,各种可能,无法排除元素,所以还是要从k/2开始寻找。

这个跟习题算法的区别是每次扔的东西明显少一些,但是k也在不断变小。


```
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
n = len(nums1) + len(nums2)
if n % 2 == 1:
return self.findKth(nums1, nums2, n / 2 + 1)
else:
smaller = self.findKth(nums1, nums2, n / 2)
bigger = self.findKth(nums1, nums2, n / 2 + 1)
return (smaller + bigger) / 2.0
def findKth(self, A, B, k):
if len(A) == 0:
return B[k-1]
if len(B) == 0:
return A[k-1]
if k == 1 :
return min(A[0],B[0])
a = A[ k / 2 - 1 ] if len(A) >= k / 2 else None
b = B[ k / 2 - 1 ] if len(B) >= k / 2 else None
if b is None or (a is not None and a < b):
return self.findKth(A[k/2:], B, k - k/2)
return self.findKth(A, B[k/2:],k - k/2)
```

这个findKth的算法单独抽出来也是题目。

给定两个已经排序好的数组,求第k大的,算法有O(m+n).类似merge sort的原理。否则利用的就是之上提到的,利用已经有序的原理,然后每次丢。

之所以这里还有一个丢弃条件是b is None 丢A的一部分,是因为B的数组长度是有限的,这个时候很明显丢A的k/2是不影响的,因为无论B[-1]是如何大或者小,因为整个B的长度没有达到k/2,所以丢掉的这部分最大的A[k/2-1]也不可能是第k个,因为即使整个B都比A[k/2-1],拼起来也不能使A[k/2-1]第k大,所以可以放心丢弃。


这里是两个sorted list/array findKth,想到了类似的题目,如果给一个n个linked list,findKth,能想到的办法也只能是用heap吧,类似merge k sorted lists.


再写一个O(m+n)类似merge sort的也可以AC的代码

```
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
def findKth(A, pa, B, pb, k):
res = 0
m = 0
while pa < len(A) and pb < len(B) and m < k:
if A[pa] < B[pb]:
res = A[pa]
m += 1
pa += 1
else:
res = B[pb]
m += 1
pb += 1
while pa < len(A) and m < k:
res = A[pa]
pa += 1
m += 1
while pb < len(B) and m < k:
res = B[pb]
pb += 1
m += 1
return res
n = len(nums1) + len(nums2)
if n % 2 == 1:
return findKth(nums1,0, nums2,0, n / 2 + 1)
else:
smaller = findKth(nums1,0, nums2,0, n / 2)
bigger = findKth(nums1,0, nums2,0, n / 2 + 1)
return (smaller + bigger) / 2.0
```
Expand Down
Loading

0 comments on commit 856dfab

Please sign in to comment.