'''

1. 两个链表 求最大的公共后缀
'''

class ListNode:
def __init__(self, value):
self.value = value
self.next = None

dummy = ListNode(0)
result = dummy

tmp = head1.next  # Note bug here, we need to save the tmp, otherwise, head1.next will become None !
result = result.next
result.next = None

else:
break

return dummy.next

pre = None
while cur:
next = cur.next
cur.next = pre
pre = cur
cur = next
return pre

'''
2. permutations of a list without adjacent equal elements
'''

import collections
import heapq

def permutation_number(s):
counts = collections.Counter(s)
heap = [(-count, key) for key, count in counts.items()]
heapq.heapify(heap)
output = []
last = None
while heap:
minuscount1, key1 = heapq.heappop(heap)
if key1 != last or not heap:
last = key1
minuscount1 += 1
else:
minuscount2, key2 = heapq.heappop(heap)
last = key2
minuscount2 += 1
if minuscount2 != 0:
heapq.heappush(heap, (minuscount2, key2))
output.append(last)
if minuscount1 != 0:
heapq.heappush(heap, (minuscount1, key1))
return ''.join(output)

test1 = 'aaabbbccc'
test2 = 'aaaaaaaabbbddd'
print permutation_number(test1)
print permutation_number(test2)

'''
3. find h index element in the array, at least n elements in the array larger than n,
but here is no n+1 elements larger than n+1
'''
def find_h_index(arr):
n = len(arr) - 1
start = 0; end = n
distance = 0
while start <= end:
mid = (start + end + 1) / 2
if arr[mid] >= (n - mid):
distance = n - mid
#print "mid: ", mid
#print "distance: ", distance
end = mid - 1

elif arr[mid] < (n - mid):
start = mid + 1

return distance

test1 = [0,3,4,7,8,9,10]  -> 4
test2 = [0,3,4,7,8,9]  -> 3
test3 = [1,2,4,7,8,9]  -> 3
test4 = [1]

print find_h_index(test1)
print find_h_index(test2)
print find_h_index(test3)

[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python find_h_index.py
mid:  3
distance:  3
mid:  2
distance:  4
4
mid:  3
distance:  2
mid:  2
distance:  3
3
mid:  3
distance:  2
mid:  2
distance:  3
3

'''

(假设A.length-mid = distance），如果是那么distance有可能成为h index. 因为数组有序，如果distance小于A[mid]，

'''

'''
4. 给一个数，要求把这个数分解成一些平方数的和，并且要求使用最短的平方数list 如 13 = 9 + 4 而不是 13 = 4+4+4+1
'''
def min_square(n):
dp = [0 for i in xrange(n + 1)]
dp[0] = 0; dp[1] = 1

for i in xrange(2, n+1):
res = 1<<31 - 1
for j in xrange(1, i):
if j * j  > i:
break
else:
res = min(res, dp[i - j*j] + 1)
dp[i] = res
print "dp[%d]: %d" %(i, dp[i])
return dp[n]

n = 12
print min_square(n)

'''

f（12） = 3*3 + f（3） f（3） = 1 + 1 + 1  i = 3 结果为 12 = 9 + 1 + 1 + 1
f（12）=  2*2+ f( 8 )   f( 8 ) = 4 + 4   i = 2 结果为 12 = 4 + 4 + 4
f（12） = 1*1 + f（11） f（11）= 9+1+1 结果为 12 = 9 + 1 + 1 + 1

'''

# http://www.mitbbs.com/article_t/JobHunting/32966491.html
'''
5. 一种encoding只有1 byte encode或者两byte encode两种形式，如果说第一byte的第一

1，那么他一定是两个byte encode一个字符，并且他的第二个byte的首bit可以是1或者
0. 题目要求，给你一串encode，请问最后一个字符是一个byte encode的还是两个byte
encode的。不允许顺序parse bit串。
'''

// 末字节high bit为1，是非法单字节编码，所以必然是双字节编码
if (lastByte & 0x80 != 0) return DoubleByteEncoding;

// 末第二字节high bit为0，不带末字节混，所以末字节肯定是单字节编码
if (last2ndByte & 0x80 == 0) return SingleByteEncoding;

// 末字节high bit为0，末二字节high bit为1的情况，不能确定，需要检查末第三
if (last3rdByte & 0x80 == 0)
return DoubleByteEncoding; // 末第3个高位0，不带末第2混，所以倒数2和1是

if (last4thByte & 0x80 == 0) //末4不带末3混，末3和末2组成双字节，最末一个单了
return SingleByteEncoding;

if (n == 1) return 1;

// 末高位1，必然是双字节编码
if (bytes[n-1] & 0x80 != 0) return 2;
// 末高位0，需要倒着扫描
else {
for (int i = n - 2; i --; i >= 0) {
// 看到0，就可以确定答案了，因为0必然是一个编码序列的结尾，后面是11...
110
// n - 1 - i是这个11...110的串的长度，如果是奇数，那么末字节单溜
if (bytes[i] & 0x80 == 0)
return 2 - (n - 1 - i) % 2;
// 到了第1个字节，并且高位是1，那么11...110串的长度是n - i，包括当前字节
if (i == 0)
return 2 - (n - i) % 2;

// else, 当前是字节高位是1，继续倒扫，直到看到0，或者扫描完
}
}

'''
6. 题目： Given a rectangular grid of colored pixels and a particular
pixel in the grid, find the perimeter of the same-colored blob containing that pixel.

（也就是说这个格子周围四个方向有一个方向颜色不同或者越界），有几个边满足条件就加几
'''

def find_pixel(grid, pixel):
if not grid or not grid[0]: return 0
perimeter = [0]

for i in xrange(len(grid)):
for j in xrange(len(grid[0])):
if grid[i][j] == pixel:
find_pixel_helper(grid, pixel, i, j, perimeter)
return perimeter[0]

def find_pixel_helper(grid, pixel, x, y, perimeter):
if x < 0 or x >= len(grid) or y < 0 or y >= len(grid[0]) or grid[x][y] != pixel:
perimeter[0] += 1
if x >= 0 and x < len(grid) and y>= 0 and y < len(grid[0]) and grid[x][y] == 'D':
perimeter[0] -= 1
return
grid[x] = grid[x][:y] + 'D' + grid[x][y+1:]

find_pixel_helper(grid, pixel, x+1, y, perimeter)
find_pixel_helper(grid, pixel, x-1, y, perimeter)
find_pixel_helper(grid, pixel, x, y+1, perimeter)
find_pixel_helper(grid, pixel, x, y-1, perimeter)

grid = ['01100','00011','00011','01110','00000']
#grid = ['01100','00011']
print find_pixel(grid, '1')

'''
7. Median in stream data
'''

* [Median in Stream Data](https://github.com/UmassJin/Leetcode/blob/master/Experience/Median_in_stream_data.py)

'''
CTCI: from random5 to get random7
'''

import random

def rand5():
return random.randint(0,4)

def rand7():
num = 5 * rand5() + rand5()
print num
if num < 21:
return num % 7

print rand7()

'''
from random2 to get random6
'''

# 思路:这道题的核心是保证产生random的概率一样，比如random7，则每个数字0到6产生的概率都为1/7,
# 对于random5来说，我们通过5*random5 + random5产生数字 0到24，然后取最小的3*7=21，所以取20
# 再mod7, 这里我们可以将random2先产生random4，然后通过random4产生

import random

def rand2():
return random.randint(0,1)

def rand6():
rand4 = 2*rand2() + rand2()
num = 4 * rand4 + rand4 # 0 to 9
if num < 12:
return num % 6

print rand6()

'''
9. 让你设计个matrix class，提供两个方法：update(x, y) & query(x1, y1, x2, y2)，update方法是update matrix上一个cell的值，
query方法是查询matrix上用(x1, y1)和(x2, y2)确定的矩形内所有值的总和。

'''
'''

'''

'''
10. 题目是给一个string,一个set of string, 问string里面是否包含一个substring，使得这个substring的任意一个prefix + suffix能

input string里面找到一个substring的一个prefix+suffix组合构成。
'''

'''
11. 给一个List，里面存着一些一个双向链表上的结点，这个List里面所有在双向链表上邻接的结点组成一个strong component，

'''
class DoubleList_Node:
def __init__(self, val = 0, pre = None, inext = None):
self.val = val
self.pre = pre
self.next = inext

class Solution:
def find_strong_comp(self, nodelist):
if not nodelist: return []
idict = { node.val: node for node in nodelist}
count = 0

for node in nodelist:
if idict and (node.val in idict):
tmp_pre = node.pre
tmp_next = node.next
while tmp_pre and (tmp_pre.val in idict):
del idict[tmp_pre.val]
tmp_pre = tmp_pre.pre
while tmp_next and (tmp_next.val in idict):
del idict[tmp_next.val]
tmp_next = tmp_next.next
del idict[node.val]
count += 1
elif not idict:
break
return count

'''
test:
node1 = DoubleList_Node(2)
node2 = DoubleList_Node(3)
node3 = DoubleList_Node(5)
node4 = DoubleList_Node(7)
node5 = DoubleList_Node(9)
node6 = DoubleList_Node(8)
node7 = DoubleList_Node(6)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node6
node6.next = node7
node2.pre = node1
node3.pre = node2
node4.pre = node3
node5.pre = node4
node6.pre = node5
node7.pre = node6

l = [node2, node1, node5, node4, node6, node7]
test = Solution()
print test.find_strong_comp(l)
'''

'''
12.

follow-up是怎么判断两个文件内容是否相同，文件太大怎么优化。.

'''

'''
13. 设计一个SparseVector class，包含set(long idx, int val), get(long idx), dotProduct(SparseVector otherVec)三个方法
'''

'''
14. 有一排数量无限的object，每个object有两个状态，可以用true和false来表示，object的状态是可切换的，初始情况下所有object的状态都是false。

https://github.com/UmassJin/Leetcode/blob/master/Algorithm/Segment_Tree.md

'''

'''
15. 设计一个random queue，支持push，pop，要求pop是random的
follow-up，每次push的时候会有相应的权重，要求pop按照权重random，换句话说，push 1,2,3，相应的权重1,2,3。那第一次pop需要保证1被pop的概率是1/6，

'''

'''
16. 第二轮，偏向c++功底跟concurrency。实现memcopy，还有就是实现一个银行的类里面的几个算法，都很简单，但是对多线程调用的加锁需要有了解。

'''

'''
17.
UTF8 validation
http://codereview.stackexchange.com/questions/59428/validating-utf-8-byte-array

0xxxxxxx  single byte
10xxxxxx  continous byte
110xxxxx  2 bytes sequence
1110xxxx  3 bytes sequence
11110xxx  4 bytes sequence
111110xx  5 bytes sequence
1111110x  6 bytes sequence
11111110  7 bytes sequence
11111111  8 bytes sequence
Valid    0xxxxxxx
Valid    110xxxxx 10xxxxxx
Valid    1110xxxx 10xxxxxx 10xxxxxx.
Valid    0xxxxxxx 110xxxxx 10xxxxxx 0xxxxxxx
invalid  10xxxxxx
invalid  110xxxxx 0xxxxxxx 10xxxxxx
invalid  110xxxxx
'''

def validUTF8(data):
if not data: return False

size = 0
for c in data:
if size == 0 and c >> 7 == 0b0:
continue
elif size == 0:
if c >> 5 == 0b110: size = 1
elif c >> 4 == 0b1110: size = 2
elif c >> 3 == 0b11110: size = 3
elif c >> 2 == 0b111110: size = 4
elif c >> 1 == 0b1111110: size = 5
else:
return False
else:
if (c >> 6) != 0b10:
return False
size -= 1
return size == 0

data1 = [0b00000000] # T
data2 = [0b11011111,0b10000000] # T
data3 = [0b11011111,0b10000000,0b11000000] # F
data4 = [0b11011111,0b00000000, 0b10111111] # F
data5 = [0b00000000, 0b00011111, 0b11110111, 0b10111111,0b10111111] #F
data6 = [0b00000000, 0b00011111, 0b11110111, 0b10111111,0b10111111, 0b10000000] #T
print validUTF8(data1)
print validUTF8(data2)
print validUTF8(data3)
print validUTF8(data4)
print validUTF8(data5)
print validUTF8(data6)

# wiki: https://en.wikipedia.org/wiki/UTF-8#Description
# Reference: http://codereview.stackexchange.com/questions/59428/validating-utf-8-byte-array
# http://www.fgdsb.com/2015/01/10/valid-utf8/

'''
18.
Symetric rotation number boolean checkNum(String num)
ex: 16891 旋轉 180 以後還是 180 確認這個數有沒有符合這個規則

ex: len=3, {0,1,8,00,11,88,69,96,000,010,080,101,111,181,808,818,888,609,619,689,906,916,986}
'''

def rotation_number(number):
if not number: return False
idict = {'0':'0', '1':'1', '8':'8', '6':'9', '9':'6'}
n = len(number)
left = 0; right = n - 1

while left <= right:
if number[left] not in idict or \
number[right] not in idict:
return False
if idict[number[left]] != number[right]:
return False
left += 1
right -= 1
return True

number1 = '8'
number2 = '7'
number3 = '609'
number4 = '321'
number5 = '916'
print rotation_number(number1)
print rotation_number(number2)
print rotation_number(number3)
print rotation_number(number4)
print rotation_number(number5)

'''
19. Followup question

'''
def find_rotate_number(n):
if n < 1: return []
res = []; pre = ['']
list1 = ["0", "1", "8"]
idict = {'0':'0', '1':'1', '8':'8', '6':'9', '9':'6'}
i = 1
while i < n + 1:
cur = []
if i % 2 == 1:
if pre == ['']:
cur = list1
else:
for num in pre:
for digit in list1:
index = len(num)/2
newnum = num[:index] + digit + num[index:]
cur.append(newnum)
elif i % 2 == 0:
for num in pre:
for digit in idict:
newnum = digit + num + idict[digit]
cur.append(newnum)
pre = cur
res.extend(cur)
i += 1
return res

print find_rotate_number(4)

'''
20. The pattern could be across the given set of strings.

ex:
pattern: "horse"
strings: ["ah", "or", "settle"]

boolean contains(String pattern, Iterable<String> strs)
pattern: "abc"
strs : "ab", "cd"  -> true
strs : "aa", "bcd" -> true
strs : "ab", "ac"  -> false
'''

'''
21. Leetcode: count islands

Follow up: 如果是大地圖怎麼處理, 要你切 map, 考慮每個 submap 之間的關係.

ex: int add(int x, int y), the function should return the new count

Follow up3.1 這個 function 能不能做到比 O(N*N) 還要好? (N為 map 邊長)

----------------------
Given a n,m which means the row and column of the 2D matrix and an array of pair A( size k). Originally, the 2D matrix is all 0 which means there is only sea in the matrix. The list pair has k operator and each operator has two integer A[i].x, A[i].y means that you can change the grid matrix[A[i].x][A[i].y] from sea to island. Return how many island are there in the matrix after each operator.

Example

Given n = 3, m = 3, array of pair A = [(0,0),(0,1),(2,2),(2,1)].

return [1,1,2,2].

Note

0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island. We only consider up/down/left/right adjacent

--------------------

1. 能表示一组不相交的集合，比如{{1, 2, 3}, {4, 5}, {6}, {7}}；
2. 最少支持以下三个操作:
make-set(v): 加入一个新的集合，其中只有一个元素v。
find(v): 给定元素v，查询v在哪一个集合当中。
union(v1, v2): 给定元素v1和v2，将它们所在的集合合并为一个。

1           4       6         7
/ \         /
2   3      5

find(v)
while (v is not root)
v = v->parent
return v

struct DJSetNode{
int rank;
DJSetNode* parent;
DJSetNode(int r, DJSetNode* parent):
rank(r), parent(p)
{}
};

union函数可以实现如下：
union(v1, v2)
root1 = find(v1)
root2 = find(v2)
if (root1 is root2)
return root1
if (root1 has lower rank)
root2.parent = root1
return root1
else if (root2 has lower rank)
root1.parent = root2
return root2
else // root1 and root2 have same depth
root2.parent = root1
root1.rank ++
return root1

----------------

1. 创建一个新的DJSetNode对象N
2. 将N作为一棵孤立的树插入到forest当中
3. 让SEAMAP[i, j]指向N

------------------

struct DJSetNode {
int label;  // 保留字。本程序中并未用到。
int rank;   // 在本程序中就是树的深度。
DJSetNode* parent;
DJSetNode(int lb, int r, DJSetNode* p): label(lb), rank(r), parent(p) {}
};
class Solution {
unordered_set<DJSetNode*> forest;   // 包含当前所有树的根

// MAKESET: 产生一个仅含一个元素的set，并将其作为一棵树加入forest
DJSetNode* makeSet() {
DJSetNode* cur = new DJSetNode(0, 0, nullptr);
forest.insert(cur);
return cur;
}

// FIND: 给定任意一个元素，找到这个元素所在树的root
DJSetNode* find(DJSetNode* n) {
if (n == nullptr) return nullptr;
while (n->parent) {
n = n->parent;
}
return n;
}

// MERGE: 给定两个元素，合并这两个元素所在的树，并返回合并后树的root
DJSetNode* merge(DJSetNode* n1, DJSetNode* n2) {
DJSetNode* r1 = find(n1);   // 分别找到两元素所在的树的root
DJSetNode* r2 = find(n2);
if (r1 == r2) {             // 如果本来就在同一树，则不做任何事
return r1;
}

if (r1->rank > r2->rank) {  // 如果树1的“深度”大于树2，
r2->parent = r1;        // 则以树1为基础合并
forest.erase(r2);       // 然后从forest中除去树2
return r1;              // 这是为了保证合并后树的深度尽可能小
}
else if (r1->rank < r2->rank) { // 反之则以树2为基础合并，
r1->parent = r2;
forest.erase(r1);
return r2;
}
else {                      // 若深度相同，则任选一树为基础合并
r2->parent = r1;        // 此处选为树1
forest.erase(r2);
r1->rank++;             // 合并以后，树1的深度增加了1
return r1;
}
}

vector<DJSetNode*> nbs;
// 查看当前位置的四个邻点，如果为island，则将其加入队列
if (p.x > 0 && seaMap[p.y][p.x-1]) nbs.push_back(seaMap[p.y][p.x-1]);
if (p.y > 0 && seaMap[p.y-1][p.x]) nbs.push_back(seaMap[p.y-1][p.x]);
if (p.x < NC-1 && seaMap[p.y][p.x+1]) nbs.push_back(seaMap[p.y][p.x+1]);
if (p.y < NR-1 && seaMap[p.y+1][p.x]) nbs.push_back(seaMap[p.y+1][p.x]);

DJSetNode* cur = makeSet(); // 先把当前加入的点看做一个新的孤立岛屿。
seaMap[p.y][p.x] = cur;     //

for (int i = 0; i < nbs.size();++i) {
cur = merge(cur, nbs[i]);   // 将这个岛屿分别与周围的邻岛合并
}
return forest.size();       // 此时forest中的tree数就是孤立岛屿的数目
}
public:
vector<vector<DJSetNode*> > seaMap;
int NR, NC;
vector<int> numIslands2(int n, int m, vector<Point>& operators) {
seaMap = vector<vector<DJSetNode*> >(m, vector<DJSetNode*>(n, nullptr));
NR = m, NC = n;

vector<int> res;
//
for (int i = 0; i < operators.size(); ++i) {
res.push_back(a);
}
return res;
}
};

------------------------------

'''

'''
22.

# http://www.careercup.com/question?id=11353907
'''

class GetRandom:
def __init__(self):
self.idict = {}
self.array = []

def insert(number):
if number not in self.idict:
self.array.append(number)
index = self.array.index(number)
self.idict[number] = index

def remove(number):
if number in self.idict:
index = self.idict[number]
if index != len(self.array)-1:
self.array[len(self.array)-1], self.array[index] = \
self.array[index], self.array[len(self.array)-1]
idict[self.array[index]] = index
del self.array[len(self.array)-1]
del self.idict[number]

def getRandom():
randomnumber = random.randint(0, len(self.array)-1)
return self.idict[randomnumber]

# Some question:
# 1) How could we handle duplicate number ?
# 2) How could we ensure the insert sequence of the element ?
# Discussion: http://www.careercup.com/question?id=11353907

'''
23. surpass count
Inversion Count for an array indicates – how far (or close) the array is from being sorted.
If array is already sorted then inversion count is 0.
If array is sorted in reverse order that inversion count is the maximum.
Formally speaking, two elements a[i] and a[j] form an inversion if a[i] > a[j] and i < j
# http://www.geeksforgeeks.org/counting-inversions/
'''

'''
similar: Maximal Surpasser Count Problem

# http://www.fgdsb.com/2015/01/11/maximal-surpasser-count/

'''

def merge_sort(array):
if not array: return None
n = len(array)
result = [0 for _ in xrange(n)]
return rec_mergesort(array, result, 0, n-1)

def rec_mergesort(array, result, left, right):
inv_count = 0
if left < right:
mid = (left + right) / 2
inv_count = rec_mergesort(array, result, left, mid)
inv_count += rec_mergesort(array, result, mid+1, right)
inv_count += merge(array, result, left, mid+1, right)
return inv_count

def merge(array, result, left, mid, right):
i = left; j = mid
k = left
inv_count = 0

while (i < mid) and (j <= right):
if array[i] <= array[j]:
result[k] = array[i]
i += 1
else:
result[k] = array[j]
j += 1
inv_count += mid - i
k += 1

while i < mid:
result[k] = array[i]
k += 1
i += 1

while j <= right:
result[k] = array[j]
k += 1
j += 1

k = left
while k <= right:
array[k] = result[k]
k += 1
return inv_count

array = [1,20,6,4,5]  # output: 5
array = [2,4,1,3,5]   # output: 3
print merge_sort(array)

'''
24. 第二轮，面的人是华裔小哥，人很喜感也挺nice，也是一上来做题。题目是给你一个positive的值K，然后按照fraction的值的小到大输出所有n/d,

fraction怎么办，数学的一些东西，算下值范围就好了，还问了这种情况的复杂度。
'''

'''

'''
# https://github.com/UmassJin/Leetcode/blob/master/Algorithm/HashTable_Implement.md

'''
26. detect cycle in a given tree, valid Tree.
Union-Find Algorithm: 详见21题
'''
class Graph:
def __init__(self, V, E):
self.V = V
self.E = E
self.edge = [Edge() for _ in xrange(self.E)]

class Edge:
def __init__(self):
self.src = 0
self.dest = 0

class UnionFind:
def __init__(self):
self.father = []
self.rank = []

def find(self, x):
if self.father[x] == -1:
return x
return self.find(self.father[x])

def union(self, x, y):
x = self.find(x)
y = self.find(y)
if x == y: return
if self.rank[x] < self.rank[y]:
self.father[x] = y
else:
self.father[y] = x
if self.rank[x] == self.rank[y]:
self.rank[x] += 1

def validTree(self, graph):
if not graph: return False
self.father = [-1 for _ in xrange(graph.V)]
self.rank = [0 for _ in xrange(graph.V)]

for i in xrange(graph.E):
x = self.find(graph.edge[i].src)
y = self.find(graph.edge[i].dest)
if x == y:
print "this is cycle graph!"
return True
self.union(x, y)

'''
27. give a float array and the weight for each array element write a function to generate each element probablistically based on the weight,

follow-up，每次push的时候会有相应的权重，要求pop按照权重random，换句话说，push 1,2,3，相应的权重1,2,3。那第一次pop需要保证1被pop的概率是1/6，以此类推。

'''

'''
28. 一道面经题2D sparse matrix, how to get the number of 1's in constant time given two coordinate
'''

'''
29. 设计合并若干个字符串到一个字符串的encoding算法与对应的decoding算法
'''
def encode_strings(str_list):
if not str_list: return ""
result = ""

for s in str_list:
n = len(s)
result += str(n) + '#' + s
return result

def decode_strings(string):
if not string: return ""
result = []
while len(string) > 0:
index = string.index('#')
length = int(string[index-1])
substr = string[index+1: index+length+1]
result.append(substr)
string = string[index+length+1:]
print "string: ", string
return result

test = ['hello','world','how','are','you']
result =  encode_strings(test)
print result
print decode_strings(result)

'''
31.给int n，求n所有factors，然后问问算法的running time
# http://stackoverflow.com/questions/6800193/what-is-the-most-efficient-way-of-finding-all-the-factors-of-a-number-in-python
'''

def find_factor(x):
result = set()
i = 1
while i * i <= x:
if x % i == 0:
i += 1
return result

print find_factor(4)
print find_factor(8)
print find_factor(18)

[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python find_factor.py
set([1, 2, 4])
set([8, 1, 2, 4])
set([1, 2, 3, 6, 9, 18])

'''

# Analysis: http://www.fgdsb.com/2015/01/17/factors-of-product-of-distinct-primes/
'''
# None-duplicate input
def all_factors(primes):
result = []
dfs(result, primes, 0, 1)
print result

def dfs(result, primes, i, cur):
if i == len(primes):
result.append(cur)
return
dfs(result, primes, i+1, cur)
dfs(result, primes, i+1, cur*primes[i])

test = [2,3,7]
all_factors(test)

test1 = [2,3,5]
all_factors(test1)

# Duplicate input

# 通过一个pre来记录之前的数字primes，比如对于input[2,2,5]来说
# 1 --- 1 (not use primes[0])
#   ---- 1*2 (use primes[0])
# 1*2 --- 1*2 (not use primes[1])
#     ---- 1*2*2 (use primes[1])

'''
33. Efficient program to print all prime factors of a given number
http://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/
'''

def find_prime_factor(x):
result = set()
while x % 2 == 0:
x = x / 2
i = 3
while i * i <= x:
while x % i == 0:
x = x / i
i += 2

if x > 2:
return result

print "prime factor:"
print find_prime_factor(8)
print find_prime_factor(9)
print find_prime_factor(11)
print find_prime_factor(121)
print find_prime_factor(315)

'''
34. 两个input，第一个是一个机器的total_mem，第二个是一堆job，每个job包含starting_time，duration，mem_needed，mem_needed就是说这个工作需要这么多的memeory。

'''

Event{
bool is_in;
int time;
int mem_used;
}

Event{true,0,200}, Event{false,10,200}.

'''
Similar problem in G4G
http://www.geeksforgeeks.org/weighted-job-scheduling/
35. Weighted Job Scheduling
Given N jobs where every job is represented by following three elements of it.
1) Start Time
2) Finish Time.
3) Profit or Value Associated.
Find the maximum profit subset of jobs such that no two jobs in the subset overlap

# 思路：
DP + binary search
http://www.fgdsb.com/2015/01/03/non-overlapping-jobs/
1. first, sort each job based on the finish time
2. maintain the dp[i], which means the max profit for the jobs till arr[i] (arr[i] included)
3. initialization: dp[0] = arr[0].profit
4. state:
for i in xrange(1, n):
# calculate include this job, the max value
include_profit = arr[i].profit
l = latestNonConflict_job(arr, i)  # find the latest non-conflit previous job, if not, return -1
if l != -1:
include_profit += table[l]
# calculate exclude this job, and find the max value
table[i] = max(include_profit, table[i-1])
return table[n-1]
# http://cs.stackexchange.com/questions/11265/find-non-overlapping-scheduled-jobs-with-maximum-cost
'''

def non_overlapping(array):
if not array:
return None
result = []
n = len(array)
array = sorted(array, key = lambda x: x[1])
print "array: ", array
dp = [ 0 for _ in xrange(n+1)]
for i in xrange(1, n+1):
cur = array[i-1]
index = find_interval(array, cur[0], 0, n-1)
dp[i] = max( dp[index+1]+cur[2], dp[i-1])
print "dp: ", dp
return dp[n]

def find_interval(array, target, start, end):
if start > end:
return end # Note: here we return end, not start not None
while start <= end:
mid = (start + end)/2
if array[mid][1] == target:
return mid
elif array[mid][1] > target:
return find_interval(array, target, start, mid-1)
elif array[mid][1] < target:
return find_interval(array, target, mid+1, end)

test = [[3,8,3], [2,3,2],[1,5,2], [2,9,3], [8,13,2]]
print non_overlapping(test)

'''
36. input: 一个文件，包含了很多单词，可以全部装入内存一个target number
output： 一个单词的最小set，这些单词的出现的频率的总和大于等于t

'''
# Use quick select (O(n))
# https://github.com/UmassJin/Leetcode/blob/master/Algorithm/Quick_Select.md

'''
37. 题目就是设计一个RMQ(http://en.wikipedia.org/wiki/Range_minimum_query) (我也是后来才知道这是RMQ的)
'''
# https://github.com/UmassJin/Leetcode/blob/master/Algorithm/Segment_Tree.md

'''
38. 找出一个树是另一个树的子树
# http://www.geeksforgeeks.org/check-if-a-binary-tree-is-subtree-of-another-binary-tree/
# http://www.geeksforgeeks.org/check-binary-tree-subtree-another-binary-tree-set-2/
'''
# O(n) algorithm

# method 1
def check_subtree(tree1, tree2):
if not tree1: return False
if not tree2: return True

if identical_tree(tree1, tree2):
return True

return identical_tree(tree1.left, tree2) or \
identical_tree(tree1.right, tree2)

def identical_tree(tree1, tree2):
if not tree1 and not tree2:
return True
if not tree1 or not tree2:
return False

return tree1.val == tree2.val and \
identical_tree(tree1.left, tree2) and \
identical_tree(tree1.right, tree2)

# method 2
# Use the inorder and preorder/postorder equal to determine
def preorder(root):
result = []
queue = [root]
while queue:
node = queue.pop()
result.append(node.val)
if node.right:
queue.append(node.right)
if node.left:
queue.append(node.left)
result.append('#')
return result

def inorder(root):
result = []
queue = []
node = root
while True:
while node:
queue.append(node)
node = node.left
if not queue:
break
node = queue.pop()
result.append(node.val)
node = node.right
result.append('#')  # Check the special case
return result

def check_subtree(tree1, tree2):
pre_array1 = preorder(tree1)
pre_array2 = preorder(tree2)

in_array1 = inorder(tree1)
in_array2 = inorder(tree2)

return check_strstr(pre_array1, pre_array2) and \
check_strstr(in_array1, in_array2)

# here use KMP algorithm to check the strstr

# we need to add '#' at the end of the preorder and inorder result
# for the following special case
'''
Tree1
x
/    \
a       b
/
c

Tree2
x
/    \
a       b
/         \
c            d
'''

'''
39. Write a function to get a positive integer n as input and return 0 or 1. The probability of returning 1 should be 1/(2^n)
G家的题。因为是1/2^n，那么执行最多n次rand() % 2即可。连续n次随机到0的概率就是1/(2^n)，中途只要随机到1就立即返回0即可。
# http://www.fgdsb.com/tags/Random/
'''
import random
def random01(n):
for i in xrange(n):
if random.randrange(2) == 1:
return 0
return 1

print random01(2)

'''
40.给一个Quack的类，里面有三个方法：
pop(): 随机从头或者尾扔出一个元素；
peek(): 随机看头或者尾的一个元素，peek()之后pop()的话一定会pop()出peek()的那个元素；
push(): 向尾部插入一个元素

'''

from collections import deque

def recover_quack(quack):
queue = deque()
stack = []
result = []

while not quack.empty():
number1 = quack.pop()
if quack.empty():
queue.append(number1)
break

number2 = quack.peek()
if number1 > number2:
stack.append(number1)
else:
queue.append(number1)

while queue:
result.append(queue.popleft())

while stack:
result.append(stack.pop())

return result

'''
41. Random Node in A Binary Tree
Random return one node in the binary tree
'''

class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None

class Tree:
def __init__(self):
self.root = TreeNode(0)

def choose_random(self):
result = [None]
self.choose_random_helper(self.root, 1, result)
print "result: ", result
return result[0].value

def choose_random_helper(self, node, idx, result):
if not node: return
print "idx: ", idx
if random.randrange(idx) == 0:
result[0] = node

self.choose_random_helper(node.left, idx+1, result)
self.choose_random_helper(node.right, idx+1, result)

tree = Tree()
node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
tree.root.left = node1
tree.root.right = node2
tree.root.left.left = node3
tree.root.left.right = node4
print "tree: ", tree.root.left.left.value
print tree.choose_random()

'''
42. Implement rand10() with rand7()
'''
import random

def random7():
return random.randrange(7)

def random10():
tmp = 7 * random7() + random7()
if tmp <= 40:
print tmp % 10

'''
43 Minimum Sum of Manhattan Distance

# http://www.jiuzhang.com/problem/30/
O(klogk), k is the number of points in matrix, the time complexity of sort

'''

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def min_distance(pts):
pts = sorted(pts, key = lambda x: x[0])
x_sum = mht_sum(pts, True)

pts = sorted(pts, key = lambda x: x[1])
y_sum = mht_sum(pts, False)

result = -1 << 31
for i in xrange(len(pts)):
result = min(result, x_sum[(pts[i].x, pts[i].y)] + y_sum[(pts[i].x, pts[i].y)])
return result

def mht_sum(pts, get_x):
n = len(pts)
left = [0 for _ in xrange(n)]
right = [0 for _ in xrange(n)]

isum = 0
for i in xrange(n):
left[i] = isum
isum += pts[i].x if get_x else pts[i].y

isum = 0
for i in xrange(n-1, -1, -1):
right[i] = isum
isum += pts[i].x if get_x else pts[i].y

# calculate xi isum
# (xi - x(i-1)) + (xi - x(i-2)) + ... + (x(i+1)-xi) + x(i+2)-xi..
# i * xi - left[i] + right[i] - (n-1-i) * xi
result = {}
for i in xrange(n):
p = pts[i].x if get_x else pts[i].y
result[(pts[i].x, pts[i].y)] = p * i - left[i] + right[i] - (n-1-i) * p
return result

'''
44. wiggle sort

'''
# https://github.com/UmassJin/Leetcode/blob/master/Experience/wiggle_sort.py

'''
'''

'''
46. Peek Iterator

# http://anandology.com/python-practice-book/iterators.html
# https://docs.python.org/3/tutorial/classes.html#iterators
'''

class generator:
def __init__(self, n):
self.n = n
self.i = 0

def __iter__(self):
return self

def next(self):
if self.has_next():
i = self.i
self.i += 1
return i
else:
print "there is NO next value."
return None
#raise StopIteration()

def has_next(self):
if self.i >= self.n:
return False
else:
return True

class PeekIterator:
def __init__(self, generator):
self.peek = []
self.generator = generator

def __iter__(self):
return self

def get_peek(self):  # Previous there is the error here since peek() function is duplicate with self.peek
if self.peek == []:
if self.has_next():
cur = self.generator.next()
self.peek.append(cur)
print "cur: ", cur
return cur
else:
return self.peek[-1]

def has_next(self):
if not self.generator.has_next() and not self.peek:
return False
else:
return True

def get_next(self):
if not self.peek:
if self.has_next():
return self.generator.next()
else:
ret = self.peek[-1]
self.peek.pop()
return ret

gen = generator(5)
test = PeekIterator(gen)
print test.has_next()
print test.get_next()
print test.get_next()
print "peek: ", test.get_peek()
print test.get_next()

# Output:
[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python iterater.py
True
0
1
peek:  2
2

'''
47.写一个变形的iterator，给定两个iterator，让两个iterator进行交互输出。

A: 1234
B: abcd

G家电面题，又是iterator系列。很简单，但是尽量写的容易扩展一些，因为interviewer很可能会让你扩展到k个iterator的情况。
# http://www.fgdsb.com/2015/01/30/zigzag-iterator/
'''

import random

class generator:
def __init__(self, n):
self.n = n
self.i = random.randrange(n)
self.start = self.i
print "self.start: ", self.start

def __iter__(self):
return self

def next(self):
if self.has_next():
i = self.i
self.i += 1
return i
else:
print "there is NO next value."
return None
#raise StopIteration()

def has_next(self):
if self.i >= self.start + self.n:
return False
else:
return True

class ZigzagIterator:
def __init__(self, g1, g2):
self.its = [g1, g2]
self._pointer = 0 if g1.has_next() else 1

def get_next(self):
ret = self.its[self._pointer].next()
tmp = (self._pointer+1)%2
if self.its[tmp].has_next():
self._pointer = tmp
return ret

def has_next(self):
return self.its[self._pointer].has_next()

# test
t1 = generator(5)
t2 = generator(5)
test = ZigzagIterator(t1, t2)
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.get_next()
print test.has_next()

# output
[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python iterater.py
self.start:  3
self.start:  3
3
3
4
4
5
5
6
6
7
there is NO next value.
None
False

'''
48. We have a schedular. Timer is available to the schedular. The clients of this schedular want to call this schedular with 2 parameters,
1) time interval in ms 2) callback function. The schedular will invoke specified callback function after specified time intevals.
Design data structure and implement it.

Analysis:

G家电面题，题目的思路是按照时间点的顺序来维护一个数据结构。每次调用一个回调时，将自动注册下一个。

func1 -> func2 -> func3

'''

class CallBack:
def __init__(self):
self.record = {}
self.current_timer = (1 << 31)-1

def wrapper(self):
self.record[self.current_timer]()
del self.record[self.current_timer]

if self.record:
self.current_timer = self.record.keys()[0]
register_system_timer_callback(self.current_timer, wrapper)

def register_system_timer_callback(self, relative_time, callback):
if relative_time == 0:
callback()
return
cur_time = time.time()
record[cur_time + relative_time] = callback
if (cur_time + relative_time < self.current_timer):
self.current_timer = cur_time + relative_time
register_system_timer_callback(self.current_timer, wrapper)

'''
49. given a full binary tree, please write a function to encode the shape of the tree. Using the result that you get from part I to reconstruct the tree.
You should use as little space as you can to reconstrcut it.
Generall Tree serialization
https://github.com/UmassJin/Leetcode/blob/master/LintCode/Binary%20Tree%20Serialization.py
'''
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None

class Solution:
def __init__(self):
self.index = 0

def serization(self, root):
if not root: return None
ret = 0
queue = [root]
while queue:
node = queue.pop()
ret <<= 1
if node.left and node.right:
ret |= 1
queue.append(node.left)
queue.append(node.right)
return ret

def deserization(self, array):
if not array: return None
bit_array = []

while array:
digit = array & 1
bit_array.insert(0,digit)
array >>= 1
root = TreeNode(0)
queue = [root]
for bit in bit_array:
if bit == 1:
node = queue.pop(0)
node.left = TreeNode(0)
node.right = TreeNode(0)
queue.append(node.left)
queue.append(node.right)
elif bit == 0:
queue.pop()
return root
~

'''
50. 要求实现对于一个window_size， 不停插入值，返回当前的平均数，

For Window size: 2
MovingAverage m(2)
m.get_next(1) -> 1
m.get_next(2) -> 1.5
m.get_next(3) -> 2.5
m.get_next(4) -> 3.5
'''

class MovingAverage:
def __init__(self, n):
self.num = []
self.size = n
self.sum = 0

def get_next(self, number):
self.num.append(number)
self.sum += number
while len(self.num) > self.size:
tmp = self.num.pop(0)
self.sum -= tmp
average = (1.0*self.sum)/len(self.num)
return average

test = MovingAverage(3)
test.get_next(1)
test.get_next(2)
test.get_next(3)
test.get_next(4)
test.get_next(5)
test.get_next(6)

'''
51. Product of word length which words that share no letters(all lower case)
E.g {feed , see, stuck }: max product: 5x4=20
Complexity?
optimal way to exit earlier in loop.

# http://www.quora.com/Given-a-dictionary-of-words-how-can-we-efficiently-find-a-pair-words-s-t-they-dont-have-characters-in-common-and-sum-of-their-length-is-maximum
'''
'''

1. go through each word in the input list, then create the dictionary for each word like: O(n * m), m is len of word
'f': [0, ]
'e': [0, 1]
'd': [0]
's': [1, 2]
...

2. then for go through each word again, for the each word, find the union of each character, first one
is [0, 1], time complexity O(m * n), then find maxlen of the rest of word, check the product of this word
and max length of word, update the result.
'''

'''
52. RLE run-length compression
Encode: helll=> he3l,   decode
Requirements:1. Decode(encode(s))==s; 2. Shortest length
Follow up: unit test: test requirement 1&2

'''

'''
53. Word abbreviation,
e.g. Between=>b5n,  friend=>f4d
Follow-up: implement
Bool checkduplicate(string [] dict, string word)
E.g. {feed }, feed => false;  {door }, deer =>true;  {dare}, deer => false

some questions need to clear:
1) how about the word length less than 2 ?
2) we only consider the first letter and last letter ?
3) is there any limitation of the word length ?
brute force思路是: check each abbr of each word in dictionary, optimization is
use the trie to optimize the dictionary

'''

'''
54.Poland operation list convert to tree
E.g. {push 4, push 5, add, push 9, mul, sqrt} => tree: {sqrt,  {mul,{9, add(4,5)}}}
'''
import operator

class TreeNode:
def __init__(self, value):
self.value = value
self.operation = None
self.left = None
self.right = None

class polish_to_tree:
def __init__(self):
self.operation = {
'+': lambda y, x: x + y,
'-': lambda y, x: x - y,
'*': lambda y, x: x * y,
'/': lambda y, x: int(operator.truediv(x, y))
}

def build_tree(self, tokens):
if not tokens: return 0
stack = []
for char in tokens:
if char.isdigit():
newnode = TreeNode(int(char))
stack.append((int(char), newnode))
elif char[0] == '-' and char[1:].isdigit():
newnode = TreeNode(-int(char[1:]))
stack.append((-int(char[1:]), newnode))
elif char in self.operation:
y, nodey = stack.pop()
x, nodex = stack.pop()
value = self.operation[char](y, x)
newnode = TreeNode(int(value))
newnode.operation = char
newnode.left = nodey
newnode.right = nodex
stack.append((value, newnode))
print stack[-1][0]
return stack[-1][1].value

array = ["4", "13", "5", "/", "+"]
test = polish_to_tree()
print test.build_tree(array)

'''
55. 给定一个数字数组 ,其中每个元素是从末端数小于原数组中该元素的个数。求原数组。

For example:
Count array: [3, 0, 1, 0]
Original array: [4, 1, 3, 2]

Can you give an O(nlogn) solution?
original question: http://www.mitbbs.com/article_t/JobHunting/32856675.html

Count array 就是一个rank

count array
i  C[3,0,1,0]   N[1,2,3,4]
0 C[0] = 3     N中第3个,N[3] = 4,在N里面删除4, N=[1,2,3]
1 C[1] = 0     N中第0个,N[0] = 1,在N里面删除1, N=[2,3]
2 C[2] = 1     N中第1个,N[1] = 3,在N里面删除3, N=[2]
3 C[3] = 0     N中第0个,N[0] = 2

# 思路
1. 先简历一个segmenttree, 从[0, n-1]，每个叶子节点标记为1，

2. find_kth function, which find tree 中 the kth 小的数字

[1..n]里面的第k个数

3. delete that node, then find next one
'''
class Node:
def __init__(self, start, end):
self.start = start
self.end = end
self.count = 0
self.left = None
self.right = None

class SegmentTree:
def __init__(self, irange):
self.root = self.build_tree(0, irange-1)

def build_tree(self, left, right):
if left > right: return None
newnode = Node(left, right)
if left == right:
newnode.count = 1
return newnode

mid = (left + right) / 2
newnode.left = self.build_tree(left, mid)
newnode.right = self.build_tree(mid+1, right)
newnode.count = newnode.left.count + newnode.right.count
return newnode

def get_kth(self, k):
cur = self.root
while cur:
if cur.start == cur.end:
return cur.start
left_cover = 0
if cur.left:
left_cover = cur.left.count
if k <= left_cover:
cur = cur.left
else:
k -= left_cover
cur = cur.right
return -1

def remove_leaf(self, val):
self.remove_helper(self.root, val)

def remove_helper(self, cur, val):
if not cur: return
cur.count -= 1
if cur.left and cur.left.start == val and cur.left.end == val:
cur.left = None

if cur.right and cur.right.start == val and cur.right.end == val:
cur.right = None
mid = (cur.start + cur.end)/2
if val <= mid:
self.remove_helper(cur.left, val)
else:
self.remove_helper(cur.right, val)

if __name__ == "__main__":
array = [3, 0, 1, 0]
test = SegmentTree(4)
result = []
for i in array:
print "i: ", i
kth = test.get_kth(i)
print "kth: ", kth
result.append(kth + 1)
test.remove_leaf(kth)
print result

'''
56. You are given two array, first array contain integer which represent heights of persons and second array contain how many
persons in front of him are standing who are greater than him in term of height and forming a queue. Ex
A: 3 2 1
B: 0 1 1
It means in front of person of height 3 there is no person standing, person of height 2 there is one person in front of him
who has greater height then he, similar to person of height 1. Your task to arrange them
Ouput should be.
3 1 2
Here - 3 is at front, 1 has 3 in front ,2 has 1 and 3 in front.
# 讨论：http://www.careercup.com/question?id=24532662
'''

'''
# 解法1, time complexity O(nlogn)
This can be solved using rope data structure.
It's like a binary tree except that each node maintains the number of nodes in the left subtree+1 for itself. Whenever a new number is inserted, if the value is smaller than the node's number it goes to the left otherwise right. When it goes to the right, the value of the node is decreased by the value of the branch node.
Ex Nodes:	6	5	4	3	2	1
values:	0	0	0	2	2	4
1. Make 6 as the root of the tree, its value = 1;
2. Insert 5. Value of 5(0) < value of 6(1) so it goes to the left. New value of 6 = 2, value of 5=1;
3. Insert 4, value of 4 < value of 6 so goes to the left; again goes to the left of 5. New values of 4 = 1, value of 5 = 2, value of 6 = 3
4. Insert 3, goes to the left of 6 but to the right of 5. New values 6 = 4, value of 3 = 1, rest unchanged
5. Insert 2, goes to the left of 6, right of 5 (value of 2 is decreased by value of 5 so its now 0), left of 3. New values of 3 = 2, value of 2 = 1, value of 6 = 5
6. Insert 1, goes to the left of 6, right of 5, right of 3.
Do an in-order traversal of tree. It is imperative to insert the nodes in decreasing order

# 解法2, check the discussion in the career cup:
Input:
height:	6	5	4	3	2	1
values:	0	0	0	2	2	4

a) Each node when it enters has its "value" (Number of people greater in height) as its initial value. I am calling it the "current node" (till it reaches its final position).
b) A "current node" goes "left" to the existing node, when its value is <= the existing node's value. At that time it increments the existing node's value by 1.
When the "current node" goes "right", no change to any values.

Repeat for all nodes. Nodes to be pushed in decreasing order of height. Finally do in-order traversal.
The changes from the previous solution are no "right" rule & no +1 for the current node.

With this, the following will be the iterations...
a) 6 = 0
b) 5 = 0, 6 = 1
c) 4 = 0, 5 = 1, 6 = 2.
d) 4 = 0, 5 = 1, 3 = 2, 6 = 3.
e) 4 = 0, 5 = 1, 2 = 2, 3 = 3, 6 = 4.
f) 4 = 0, 5 = 1, 2 = 2, 3 = 3, 1 = 4, 6 = 5.

'''

'''
57. Given an array of ages (integers) sorted lowest to highest, output the number of occurrences for each age.
For instance:
[8,8,8,9,9,11,15,16,16,16]
should output something like:
8: 3
9: 2
11: 1
15: 1
16: 3
Problem: # http://www.fgdsb.com/2015/01/03/count-numbers/
'''
void count_number(const vector<int>& arr) {
if(arr.empty()) return;

int id = 0, step = 1, cur_num = arr[0], cur_count = 0;
while(id < arr.size()) {
cur_count += step;
step *= 2;
if(id + step >= arr.size() || arr[id + step] != cur_num) {
step = 1;
if(id + step < arr.size() && arr[id + step] != cur_num) {
cout << cur_num << ": " << cur_count << endl;
cur_count = 0;
cur_num = arr[id + step];
}
}
id += step;
}
cout << cur_num << ": " << cur_count << endl << endl;
}

'''
Count 1 bits

then check the 1s in each block, if 2 1s, output is 10, if only has 1 1s, output is 01,
then move to the 4 bits in one block
'''
def count_one_array(x):
x = ((x & 0b1010101010101010) >> 1) + (x & 0b0101010101010101)
x = ((x & 0b1100110011001100) >> 2) + (x & 0b0011001100110011)
x = ((x & 0b1111000011110000) >> 4) + (x & 0b0000111100001111)
x = ((x & 0b1111111100000000) >> 8) + (x & 0b0000000011111111)
return x

def count_one_array(x):
x = ((x & 0xAAAAAAAA) >> 1) + (x & 0x55555555)
x = ((x & 0xCCCCCCCC) >> 2) + (x & 0x33333333)
x = ((x & 0xF0F0F0F0) >> 4) + (x & 0x0F0F0F0F)
x = ((x & 0xFFFF0000) >> 8) + (x & 0x0000FFFF)
return x

'''
58.设计一个电话本系统，实现三个功能：查找号码 boolean isTaken()，添加号码 void takeNumber()，

giveMeANumber()的实现只要沿着value>0的node往下找就行了。这样三个函数的复杂度都是O(lgn).

Analytis:

class TrieNode{
int nAvail;
int curDepth;
TrieNode* next[10];
};

=============================

'''

'''
59. 给string a, string b,判断b里面是否存在子字符串是a的anagram。

pass一个start point什么的就行。。。
http://www.geeksforgeeks.org/anagram-substring-search-search-permutations/

# Better solution: http://www.geeksforgeeks.org/anagram-substring-search-search-permutations/

'''

import collections

def check_ana(a, b):
if len(a) < len(b) or not a or not b: return False
idict = collections.defaultdict(int)
for char in b:
idict[char] += 1
m = len(a); n = len(b)
for i in xrange(m-n+1):
tmp = idict
if isAna(a[i:i+n], tmp):
return True
return False

def isAna(a, tmp_idict):
for char in a:
tmp_idict[char] -= 1
if tmp_idict[char] < 0:
return False
if sum(tmp_idict.values()) > 0:
return False
return True

a = "helloworld"
b = "ollel"
print check_ana(a, b)

# General check if two string are anagram or not
import collections

def isAna(a, b):
if len(a) != len(b):
return False
idict = collections.defaultdict(int)
for char in a:
idict[char] += 1

for char in b:
idict[char] -= 1
if idict[char] < 0:
return False
if sum(idict.values()) > 0:
return False
return True

a = "hello"
b = "lloeh"
c = "helllo"
d = "heoool"

print isAna(a, b)
print isAna(a, c)
print isAna(a, d)

'''
60. 给一个整形数组，找离数组的平均值最近的数

'''

'''
61. 有序数组中都是正数且为unique number，找出两个数A、B，so that A-B = 一个给定的数C。要求使用常数空间和O(N)时间。
# http://www.mitbbs.com/article_t/JobHunting/32861939.html

if A[p1] - A[p0] < target: p1 +=1
elif A[p1] - A[p0] > target: p0 += 1
else return (p0, p1)

if p1 == p2, p2 = p1 + 1
'''

'''
63. 给一个字典，一个字符串， 找出可以由这个字串合法转成的最长单词。 转换操作时删除一个或多个字符

Apple orange banana

'''

'''
64. similar question:
Given a dictionary of words and an initial character. find the longest possible word in the dictionary by
successively adding a character to the word. At any given instance the word should be valid word in the dictionary.
ex : a -> at -> cat -> cart -> chart ....

# http://stackoverflow.com/questions/17717223/find-the-longest-word-in-the-dictionary-such-that-it-can-be-built-from-successiv
'''
import string
import collections

def find_longest_word(beginchar, wordDict):
if not beginchar or not wordDict:
return 0
chars = string.ascii_lowercase
queue = collections.deque([beginchar])
result = 0

while queue:
size = len(queue)
for _ in xrange(size):
word = queue.popleft()
for i in xrange(len(word)+1):
for char in chars:
newword = word[:i] + char + word[i:]
if newword in wordDict:
queue.append(newword)
print "queue: ", queue
result = max(result, len(newword))
print result

wordDict = ["hot","dot","dog","lot","log", "ta","tan", "tap","tape", "tang",
"taped", "tamped", "strang","strange","stamped","ta","ca","cat"]

find_longest_word('a', wordDict)

'''
65. You are given a dictionary, in the form of a file that contains one word per line. E.g.,
abacus
deltoid
gaff
giraffe
microphone
reef
qar
You are also given a collection of letters. E.g., {a, e, f, f, g, i, r, q}.
The task is to find the longest word in the dictionary that can be spelled with the collection of
letters. For example, the correct answer for the example values above is “giraffe”. (Note that
“reef” is not a possible answer, because the set of letters contains only one “e”.)
# http://www.careercup.com/question?id=16148684
'''
import collections

def find_longest_word(letters, words):
if not letters or not words:
return None
dict_letter = collections.Counter(letters)
letter_len = len(dict_letter)
result = 0

for word in words:
flag = True
tmp = dict_letter.copy()
if len(word) > letter_len:
continue
for char in word:
tmp[char] -= 1
if tmp[char] < 0:
flag = False
break
if flag:
result = max(result, len(word))
return result

words = ["abacus", "deltoid", "gaff", "giraffe", "microphone", "reef", "qar"]
letters = ['a','e','f','f','g','i','r','q']
print find_longest_word(letters, words)
~

'''
66. 一个logfile，有timestamp，userid，x，y。写个方法，找出任意两个userid，在一定的range里，timestamp最近的一对pair
'''

'''
67. 加了一个小问题，三角形三个顶点各有一只小虫，小虫只能沿着线走，但方向任选，问一段时间后，两只小虫碰一块儿的几率是多少
# http://www.programmerinterview.com/index.php/puzzles/3-ants-on-a-triangle-riddle/

The only possibility that ants can not meet each other is 2, clockwise or anti-clockwise, but the totally 3 ants could choose
the ways are 2^3 = 8, so the possiblity that any two ants meet each other is (8-2)/8 = 0.75
'''

'''
68. 先上来问了下quicksort, 举一个worse case 时间复杂度的例子， 然后coding, 一个n的数组，没有重复， 0到n-1都在这个数组里面，

# quick sort:
# https://github.com/UmassJin/Leetcode/blob/master/Algorithm/Different_Sort_Algorithms.md#quick-sort
# http://www.geeksforgeeks.org/when-does-the-worst-case-of-quicksort-occur/
# O(n) sort algorithm: swap the element to the correct position in array

The answer depends on strategy for choosing pivot. In early versions of Quick Sort where leftmost (or rightmost) element is
chosen as pivot, the worst occurs in following cases.

1) Array is already sorted in same order.
2) Array is already sorted in reverse order.
3) All elements are same (special case of case 1 and 2)

Since these cases are very common use cases, the problem was easily solved by choosing either a random index for the pivot,
choosing the middle index of the partition or (especially for longer partitions) choosing the median of the first, middle and
last element of the partition for the pivot. With these modifications, the worst case of Quick sort has less chances to occur,
but worst case can still occur if the input array is such that the maximum (or minimum) element is always chosen as pivot
'''

'''
69. Sort n numbers in range from 0 to n^2 – 1 in linear time
# http://www.geeksforgeeks.org/sort-n-numbers-range-0-n2-1-linear-time/

Sort a nearly sorted array:
http://www.geeksforgeeks.org/nearly-sorted-algorithm/
'''

'''
70. 问garbage collection和arc的区别，各自的优点和缺点，我运气好，以前学ios programming的时候专门看了的，然后他让我用doubly linked list给他展示，

2 给以个二叉搜索树和一个iterator,先问你怎么存data才能让这个树可以接受重复元素，我说存一个object,里面是Key和计数器，他说好，

'''

'''
71. Count frequencies of all elements in array in O(1) extra space and O(n) time
Given an unsorted array of n integers which can contain integers from 1 to n. Some elements can be repeated multiple times and
some other elements can be absent from the array. Count frequency of all elements that are present and print the missing elements.
# http://www.geeksforgeeks.org/count-frequencies-elements-array-o1-extra-space-time/
'''
def count_frequency(array):
if not array: return None
n = len(array)
i = 0

while i < n:
if array[i] < 0:
i += 1
continue
index = array[i] - 1
if array[index] > 0:
array[i] = array[index]
array[index] = -1
else:
array[index] -= 1
array[i] = 0
i += 1
return array

test = [2,3,3,2,5]
test1 = [3,3,3,3,3]
print count_frequency(test)
print count_frequency(test1)

def count_frequency2(array):
if not array: return None
n = len(array)
array = [array[i]-1 for i in xrange(n)]

for i in xrange(n):
array[array[i]%n] = array[array[i]%n] + n

array = [array[i]/n for i in xrange(n)]
return array

test = [2,3,3,2,5]
test1 = [3,3,3,3,3]
print count_frequency2(test)
print count_frequency2(test1)

Output:
[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python count_frequency.py
[0, -2, -2, 0, -1]
[0, 0, -5, 0, 0]
[0, 2, 2, 0, 1]
[0, 0, 5, 0, 0]

'''
72. 进制转换， 十进制转换为any进制，会给一个base input
'''

'''
73. BST构建，插入，删除, return the next node;
'''

'''
74. 给一个array of 硬币，第i次翻面所有i的倍数的位置的硬币，（第0次，第1次全翻，第2次翻2, 4, 6, ...）输出最后结果。要求O(n logn)解法。
'''

'''
75. cypher graphics equivalent, 判断两个string是不是cypher graphics equivalent，并证明cypher graphics equivalent是否symmetric和transitive。
cypher graphics equivalent是指，比如说ABC和DEF就cypher graphics equivalent，因为A=>D, B=>E, D=>F。ABC和ADD就不是。

'''

'''
76. input string：“+++--++-+”

Extra：这两个问题的implementation的Big-O. 1

# http://web.mit.edu/sp.268/www/nim.pdf

------------------------------

(2-2, 3, 4) => (3,4)
(2, 3-1, 4) => (2,4)
(2, 3, 4-2) => (2,2,3)
(2, 3, 2, 2) => (2,2,2,3)

g(x) = FirstMissingNumber(g(y1), g(y2), ... g(y3))

------------------------------

[转发]

------------------------------

(2-2, 3, 4) => (3,4)
(2, 3-1, 4) => (2,4)
(2, 3, 4-2) => (2,2,3)
(2, 3, 2, 2) => (2,2,2,3)

g(x) = FirstMissingNumber(g(y1), g(y2), ... g(y3))

------------

------------

------------

------------

g(0) = 0;        // 一个+都没有，先手必输
g(1) = 0;        // 只有一个+，先手必输
g(2) = FirstMissingNumber(g(0)) = 1     // 两个+，先手必赢
g(3) = FirstMissingNumber(g(1))        = 1            // 先手必赢
g(4) = FMN(g(2), g(1) XOR g(1)) = 2    // 两种情况：A 1111->0011 OR 1100，也就是状态2，B 1111-> 1001
...
g(9) = FMN(g(0)^g(7), g(1)^g(6), g(2)^g(5), g(3)^(4)).
...
g(x) = FMN(g(0)^g(x-2), g(1)^g(x-3), g(2)^g(x-4), ... g(x/2)^g(x/2)).

-----------------------------------

'''

'''
77. Three segments of lengths A, B, C form a triangle iff
A + B > C
B + C > A
A + C > B

e.g.
6, 4, 5 can form a triangle
10, 2, 7 can’t

Given a list of segments lengths algorithm should find at least one triplet of segments that form a triangle (if any).

Method should return an array of either:

3 elements: segments that form a triangle (i.e. satisfy the condition above)
empty array if there are no such segments
Could you return the number of all valid triangles? You can assume there’s no duplicates in the original array.

# http://www.geeksforgeeks.org/find-number-of-triangles-possible/
'''
def triangle(array):
if not array or len(array) < 3: return 0
count = 0
n = len(array)
for i in xrange(n-2):
k = i + 2
for j in xrange(i+1, n):
while k < n and  array[i] + array[j] > array[k]:
k += 1
count += k - j - 1
return count

arr = [10, 21, 22, 100, 101, 200, 300]
print triangle(arr)

'''
78.给定一个word list 和一个target word，要求输出在word list 里跟target word的edit distance 相差不大于k的所有words。

# 原题：http://www.mitbbs.com/article_t/JobHunting/32692817.html
# 解法：http://stevehanov.ca/blog/index.php?id=114
'''

'''
79.给一个dictionary, 一个string,找出dict 里能全部用string里的letter 表示的所有最长的词。
For example:

abcde, abc, abbbc, abbbccca, abbbcccabbcx

# http://www.mitbbs.com/article_t/JobHunting/32634303.html

80. Similar question:
You are given a string 's' and you are given a dictionary of english words.
You goal is to write an algorithm that returns all words from the dictionary the can be formed by
characters from that string 's'.

Example:
s = "ogeg"
following words can be formed from 's': go egg ego . . .
Further it is given that string 's' always consists of four lower case characters.
Lets say that the dictionary is contained in a file and can be fitted in the memory.
It is up to you which data structure you use to represent the dictionary.
How would you design an efficient algorithm? Follow up: What if the dictionary file can not be fitted in the memory?
# http://www.careercup.com/question?id=6270813198090240
'''
import collections

class TrieNode:
def __init__(self):
self.value = None
self.end = False
self.children = collections.defaultdict(TrieNode)

class Trie:
def __init__(self):
self.root = TrieNode()

node = self.root
word = word.strip()

for char in word:
node = node.children[char]
node.end = True
node.value = word

def search_longest_str(self, idict, string):
if not idict or not string:
return None
for word in idict:
print "node: ", self.root.children
result = [""]
self.search(result, "", self.root, string)
return result[0]

def search(self, result, cur, node, string):
if not node:
return
if node.end and len(cur) > len(result[0]):
print "node.value: ", node.value
result[0] = cur

for child in node.children:
if child in string:
self.search(result, cur + child, node.children[child], string)

test = Trie()
idict = ["abcde ", " abc", " abbbc", "abbbccca", "abbbcccabbcx"]
string = "abc"

'''
82. Given a dictionary of words, and a set of characters, judge if all the characters
can form the words from the dictionary, without any characters left.
For example, given the dictionary {hello, world, is, my, first, program},
if the characters set is "iiifrssst", you should return 'true' because you can form {is, is, first} from the set;
if the character set is "eiifrsst", you should return 'false' because you cannot use all the characters from the set.

P.S. there may be tens of thousands of words in the dictionary, and the chars set length could be up to hundreds,
so I really need some efficient algorithm.

1) If the input word could be used multiple times ?
2) Just find one of the answer is fine and return True or False, do not need the shortst one ?
'''

import collections

class TrieNode:
def __init__(self):
self.value = None
self.end = False
self.children = collections.defaultdict(TrieNode)

class Trie:
def __init__(self):
self.root = TrieNode()

node = self.root
word = word.strip()
word = ''.join(sorted(word))

for char in word:
node = node.children[char]
node.end = True
node.value = word

def search(self, word, idict):
wdict = collections.Counter(word)
result = []
for word in idict:
self.search_helper(wdict, result, "", self.root)
if len(result) > 0:
print "True"
else:
print "False"
return result

def search_helper(self, wdict, result, cur, node):
if sum(wdict.values()) == 0:
if node.end:
result.append(cur)
return

if node.end:
temp = wdict.copy()
self.search_helper(temp, result, cur, self.root)

for child in node.children:
if child in wdict and wdict[child]-1 >= 0:
wdict[child] -= 1
self.search_helper(wdict, result, cur + child, node.children[child])
wdict[child] += 1

def main():
test = Trie()
idict = ['abc', 'abde', 'cfg', 'cde','hello']
word = "abccde"
print test.search(word, idict)

if __name__ == "__main__":
main()

'''
83. 给一个dictionary, 再给一个set of coding string （g5, goo3, goog2, go2le………).
return all string from dictionary that can be matched with the coding string. 要求尽量减少dictionary look up 次数
# http://www.fgdsb.com/tags/Trie/
'''

'''
84. There are a set of dictionary words and a set of license plate numbers. Write a code/algorithm to find the shortest
dictionary word which contains all the characters in the license plate, irrespective of the order of characters.
Ex: RC101 is the license plate number. The shortest word that can be found in the dictionary is CAR which has
characters 'R' and 'C' in the license plate.

思路: 一个brute force的想法是，把每个word排序，然后去掉数字，然后把每个字典里面的字母排序，然后依次比较word在不在每个字典里，
找出最短的字典里的单词

ex:. 鐗涗汉浜戦泦,涓€浜╀笁鍒嗗湴

(1) 如果dictionary裡有上百萬個字，該如何加速
(2) 如果dictionary有上百萬個字，然後給你上千個車牌號碼，要你回傳相對應的最短字串，該如何optimize?.

利用trie，将dictionary里面每个单词放入trie里的时候，排序，查找的时候，如果trie_node[char] < string[char], 查找
'''

'''
# http://stackoverflow.com/questions/746082/how-to-find-list-of-possible-words-from-a-letter-matrix-boggle-solver#746345
'''

'''
86.Given a array of pairs where each pair contains the start and end time of a meeting (as in int),
Determine if a single person can attend all the meetings
For example:
Input array { pair(1,4), pair(4, 5), pair(3,4), pair(2,3) }
Output: false

determine the minimum number of meeting rooms needed to hold all the meetings.
Input array { pair(1, 4), pair(2,3), pair(3,4), pair(4,5) }
Output: 2
'''

class interval:
def __init__(self, start, end):
self.start = start
self.end = end

def meeting_room(meetings):
if not meetings: return 0
result = 0
cur = 0
times = []
for meeting in meetings:
times.append(meeting.start)
times.append(-meeting.end)
times = sorted(times, cmp = lambda x, y: cmp(abs(x), abs(y)))

for t in times:
if t >= 0:
cur += 1
result = max(cur, result)
else:
cur -= 1
return result

a1 = interval(1,4)
a2 = interval(2,3)
a3 = interval(3,4)
a4 = interval(5,6)
meetings = [a1, a2, a3, a4]
print meeting_room(meetings)

'''
87.Maximum Sum Rectangle in Matrix Feb 16 2015
Given a 2D array, find the maximum sum subarray in it.

For example:
Given a matrix:
# http://www.geeksforgeeks.org/dynamic-programming-set-27-max-sum-rectangle-in-a-2d-matrix/
'''
def findmaxsum(matrix):
if not matrix or not matrix[0]:
return 0
m = len(matrix)
n = len(matrix[0])
result = 0
for left in xrange(n):
temp = [0 for i in xrange(m)]
for right in xrange(left,n):
for k in xrange(m):
temp[k] += matrix[k][right]
current = 0
tmp_sum = temp[0]
for i in temp:
current += i
tmp_sum = max(current, result)
current = max(0, current)
result = max(result, tmp_sum)
return result

m = [[1, 2, -1, -4, -20],[-8, -3, 4, 2, 1],[3, 8, 10, 1, 3], [-4, -1, 1, 7, -6]]
print findmaxsum(m)

'''
88. 输入是一个 N*N的矩阵，代表地势高度。如果下雨水流只能流去比他矮或者一样高的地势。

For example:
Pacific: ~
Atlantic: *
~  ~   ~   ~   ~   ~  ~
~  1   2   2   3  (5) *
~  3   2   3  (4) (4) *
~  2   4  (5)  3   1  *
~ (6) (7)  1   4   5  *
~ (5)  1   1   2   4  *
*  *   *   *   *   *  *

[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]]
'''

def flow_water(matrix):
if not matrix or not matrix[0]:
return None
n = len(matrix)
result = []
visited_pac = {}
visited_alt = {}

for i in xrange(n):
visited_pac[(i,0)] = True
search(visited_pac, matrix, i, 0)

for i in xrange(n):
visited_pac[(0,i)] = True
search(visited_pac, matrix, 0, i)

print "pac: ", visited_pac
for i in xrange(n):
visited_alt[(i,n-1)] = True
search(visited_alt, matrix, i, n-1)

for i in xrange(n):
visited_alt[(n-1,i)] = True
search(visited_alt, matrix, n-1, i)

print "alt: ", visited_alt
for key, value in visited_pac.items():
if visited_alt.has_key(key):
result.append(key)
result.sort()
return result

def search(visited, matrix, x, y):
n = len(matrix)
dirs = [[0,1],[0,-1],[1,0],[-1,0]]
for d in dirs:
new_x = x + d[0]
new_y = y + d[1]
if new_x >= n or new_x < 0  or new_y >= n or new_y < 0:
continue
if matrix[x][y] > matrix[new_x][new_y] or visited.has_key((new_x, new_y)):
continue
visited[(new_x, new_y)] = True
search(visited, matrix, new_x, new_y)

test = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
print flow_water(test)

'''
89. I was given this problem in an interview. How would you have answered?

Design a data structure that offers the following operations in O(1) time:

insert
remove
contains
get random element

Consider a data structure composed of a hashtable H and an array A. The hashtable keys are the elements in the data structure, and the values are their positions in the array.

insert(value): append the value to array and let i be it's index in A. Set H[value]=i.
remove(value): We are going to replace the cell that contains value in A with the last element in A. let d be the last element in the array A at index m. let i be H[value], the index in the array of the value to be removed. Set A[i]=d, H[d]=i, decrease the size of the array by one, and remove value from H.
contains(value): return H.contains(value)
getRandomElement(): let r=random(current size of A). return A[r].
since the array needs to auto-increase in size, it's going to be amortize O(1) to add an element, but I guess that's OK.
'''

def __init__(self):
self.dict = {}
self.array = []
self.size = 0

def insert(self, number):
array.append(number)
self.dict[number] = self.size
self.size += 1

def remove(self, number):
if self.contains(number):
index = array.index(number)
if index != len(self.array) - 1:
hash[array[-1]] = index
array[index], array[-1] = array[-1], array[index]
del array[-1]
del hash[number]
self.size -= 1
else:
return False

def contains(self, number):
if number not in self.dict.keys():
return False
else:
return True

def get_random_ele(self, index):
if index < len(self.array):
return self.array[index]
else:
return False

'''

QuadNode(int num_ones = 0) : ones(num_ones) {}
int ones{ 0 };
};
Please build a quadtree to represent a 0-1 matrix, assume the matrix is a square and the dimension is power of 2.
Given two such quadtrees with same depth, please write a function to calculate how many 1s are overlapped.
For example:
Matrix 0:
0 1
1 1
Matrix 1:
0 0
1 1
'''
import collections

def __init__(self, num=0):
self.ones = num
self.children = {}

def __init__(self):

def build_tree(self, matrix):
if not matrix or not matrix[0]:
return None
n = len(matrix)
self.root = self.build_helper(n, matrix, 0, 0)
return self.root

def build_helper(self, size, matrix, row, col):
if size == 1:

size = size/2
coord = [[row, col], [row+size, col], [row, col+size], [row+size, col+size]]
for i in xrange(4):
node.children[i] = self.build_helper(size, matrix, coord[i][0], coord[i][1])
node.ones += node.children[i].ones
return node

class Solution:
def intersections(self, t1, t2):
return self.intersections_helper(t1, t2, 0)

def intersections_helper(self, t1, t2, sum):
if not t1 or not t2 or not t1.ones or not t2.ones:
return 0
ret = sum
if not t1.children or not t2.children:
ret += (t1.ones & t2.ones)
else:
for i in xrange(4):
ret += self.intersections_helper(t1.children[i], t2.children[i], sum)
return ret

matrix1 = [[0,1],[1,1]]
matrix2 = [[0,1],[1,1]]
test1.build_tree(matrix1)
test2.build_tree(matrix2)
test = Solution()
print test.intersections(test1.root, test2.root)

'''
91.给你一组Treenode，他们每个有一个id，一个parentId，一个value，让你输出所有subtree的sum of value。

'''
class TreeNode(object):
def __init__(self, id=0, parent=None, value=0):
self.id = id
self.parent = parent
self.value = value
self.level = 0
self.sum = value

class Solution:
def __init__(self):
self.maxlevel = 0

def all_sum(self, nodes):
if not nodes:
return
for node in nodes:
self.cal_level(node)

level = {}
for node in nodes:
level.setdefault(node.level, []).append(node)

for i in xrange(self.maxlevel, -1, -1):
for node in level[i]:
node.parent.sum += node.value

def cal_level(self, node):
ret = 0
if node.level != 0 and node.parent:
return node.level
if not node.parent:
node.level = 0
else:
ret = self.cal_level(node.parent) + 1
node.level = ret
self.maxlevel = max(self.maxlevel, ret)
return ret

'''
92. 给一个0/1数组R代表一条河，0代表水，1代表石头。起始位置R[0]等于1，

Sample solution like the following, always check the same speed and the speed + 1 part
we could use the similar solution like jump game II

if array[i+pre_speed]:
max_reachable = max(max_reachable, i + pre_speed)
if array[i+pre_speed]:
max_reachable = max(max_reachable, i + pre_speed + 1)
'''

int min_river_jumps_dp(const vector<int>& river) {
if (river.empty()) return 0;
vector<vector<pair<size_t, int>>> vp(river.size());
vp[0].emplace_back(1, 1);

int ret = INT_MAX;
for (auto i = 0; i < vp.size(); ++i) {
if (!river[i]) continue;

for (auto pr : vp[i]) {
if (i + pr.first >= vp.size()) {
ret = min(pr.second, ret);
} else if (river[i + pr.first]) {
vp[i + pr.first].emplace_back(pr.first, pr.second + 1);
}
if (i + pr.first + 1 >= vp.size()) {
ret = min(pr.second, ret);
} else if (river[i + pr.first + 1]) {
vp[i + pr.first + 1].emplace_back(pr.first + 1, pr.second + 1);
}
}
}
return ret == INT_MAX ? -1 : ret;
}

'''
93. Merge Two BST
You are given two balanced binary search trees.
Write a function that merges the two given balanced BSTs into a balanced binary search tree.
Your merge function should take O(M+N) time and O(1) space.
G家onsite题，算是很多小问题的综合题。因为不允许用extra space，可以先把两个输入BST给转换成链表，

'''

'''
94. Smallest Range
You have k lists of sorted integers. Find the smallest range that includes at least one number from each of the k lists.

For example,
List 1: [4, 10, 15, 24, 26]
List 2: [0, 9, 12, 20]
List 3: [5, 18, 22, 30]

The smallest range here would be [20, 24] as it contains 24 from list 1, 20 from list 2, and 22 from list 3.
G家题，实际上就是k路归并的变种题。维护一个长度为n的min heap（n为数组个数），每次找一个最小的，同时保持记录一个最大的。

heap初始化为[0,4,5]，min = 0, max = 5，当前最小range为[0,5]。
pop掉最小的再push，[4,5,9]，min = 4, max = 9，当前最小range还是[0,5]。

'''

'''
94.

'''

import collections
from collections import deque

class Node(object):
def __init__(self):
self.visited = False
self.dis = 0

def find_min_sum(matrix):
if not matrix or not matrix[0]:
return None
m = len(matrix); n = len(matrix[0])
food_queue = deque([])
node_matrix = [[Node() for i in xrange(n)] for j in xrange(m)]
for i in xrange(m):
for j in xrange(n):
if matrix[i][j] == 'P':
food_queue.append((i,j))
for q in food_queue:
# reset all the nodes as Non-visited
for i in xrange(m):
for j in xrange(n):
node_matrix[i][j].visited = False
# two queue to check the nodes around food
dis_queue = deque([0])
node_queue = deque([q])
# BFS, check the around nodes
node_matrix[q[0]][q[1]].visited = True
while node_queue:
node = node_queue.popleft()
dis = dis_queue.popleft()
row = node[0]; cal = node[1]
cord = [[0,1],[0,-1],[1,0],[-1,0]]
for c in cord:
newrow = row + c[0]
newcal = cal + c[1]
if newrow < 0 or newrow >= m or newcal < 0 or newcal >= n:
continue
if node_matrix[newrow][newcal].visited:
continue
if matrix[newrow][newcal] == '1':
continue
node_matrix[newrow][newcal].visited = True
node_matrix[newrow][newcal].dis += dis + 1
node_queue.append((newrow, newcal))
dis_queue.append(dis+1)
result = (1 << 31) -1
result1 = []
for i in xrange(m):
for j in xrange(n):
if matrix[i][j] == '0':
if node_matrix[i][j].dis < result:
result = node_matrix[i][j].dis
result1 = [i, j]
print result
print result1

matrix = [["0","0","1","0"],["1","P","0","0"],["0","0","P","0"],["0","0","0","P"]]
find_min_sum(matrix)

'''
95.
Rolling Ball Game Jan 6 2015

For example (1代表有障碍, 0代表可以通过):
'''
import collections
from collections import deque

def bolling_game(matrix, start, end):
if not matrix or not matrix[0]:
return False
m = len(matrix); n = len(matrix[0])
visited = {}
visited[start] = True
queue = deque([start])
while queue:
node = queue.popleft()
next_pos = get_next(matrix, node[0], node[1])
for p in next_pos:
if p in visited:
continue
if p[0] == end[0] and p[1] == end[1]:
return True
visited[p] = True
queue.append(p)
return False

def get_next(matrix, x, y):
m = len(matrix); n = len(matrix[0])
next_pos = []
stop = False
for i in xrange(x+1, m):
if matrix[i][y] == '1':
next_pos.append((i-1, y))
stop = True
break
if not stop and x != m-1:
next_pos.append((m-1,y))

stop = False
for i in xrange(x-1, -1, -1):
if matrix[i][y] == '1':
next_pos.append((i+1, y))
stop = True
break
if not stop and x != 0:
next_pos.append((0, y))

stop = False
for i in xrange(y+1, n):
if matrix[x][i] == '1':
next_pos.append((x, i-1))
stop = True
break
if not stop and y != n-1:
next_pos.append((x, n-1))

stop = False
for i in xrange(y-1, -1, -1):
if matrix[x][i] == '1':
next_pos.append((x, i+1))
stop = True
break
if not stop and y != 0:
next_pos.append((x, 0))

print "next: ", next_pos
return next_pos

matrix = [["0","0","0","1"],["1","0","0","1"],["1","0","0","0"]] # True
matrix1 = [["0","0","0","1"],["1","0","1","1"],["1","0","0","0"]] # False
print bolling_game(matrix, (0,0),(2,3))
print bolling_game(matrix1, (0,0),(2,3))

'''
96.

Similar question:
Given a heatmap which is a 3 dimension matirx and define a movement rule: a point on the heatmap can only go down hill.
Ask: given some points on the heatmap, find out the higest point that can meet all the given points.

1. 将每个给定的点的坐标放入一个deque里面，然后依次对每个点做BFS,
2. 对于每个给定的点周围的点，如果这个点value > 给定的点，那么将这个点的数字+1
3. 然后再走一遍整个matrix，找到数字等于k的点，并且找出matrix最大的值。

optimization:
1. 可以每次扫描一个点之后，只针对范围内的点再次扫描？
2. 从给定的点的最大值开始扫描？
'''

'''
97.3. given a probability = [.5 .1 .2 .2], label = [A B C D], write a data structure that generates the label based on the prob.

'''

'''
98.second is given a dict of words [aba, cbc], find the letter to letter probability. b->a 50%, b->c 50%. 这个做的还可以，有一个小bug

b之后出现a的机率是50%，b最为结尾的几率是50%。 a作为开头的机率是2/3， a最为结尾的机率是1/3。

'''

'''
99.hamming distance between a and b, a, b < 2^64. 这题很快就做了出来。就是把a^b>>i &1  64 次。 然后他就说要想办法speed up，

'''

'''
100.

# http://blog.csdn.net/acdreamers/article/details/18039073
# http://www.cnblogs.com/titicia/p/4344765.html

'''

def stone_merge(stones):
if not stones: return 0
n = len(stones)
dp = [[(1<<31)-1 for i in xrange(n)] for j in xrange(n)]
isum = [0 for i in xrange(n)]
isum[0] = stones[0]
for i in xrange(1, n):
isum[i] = isum[i-1] + stones[i]

for step in xrange(n):
i = 0; j = step
while j < n:
if step == 0:
dp[i][j] = 0
elif step == 1:
dp[i][j] = stones[i] + stones[j]
elif step > 1:
tmp = isum[j] - (isum[i-1] if i > 0 else 0)
for k in xrange(i, j):
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + tmp)
i += 1
j += 1

for i in xrange(n):
print "dp: ", dp[i]
return dp[0][n-1]

test1 = [13, 7, 8]
test = [7,13,7,8,16]
print stone_merge(test)

'''
similar question:
Least cost to cut a batten
The cost of cutting each segment is the cost of the segment length, an array is storing each end point,
For example:
[0, 3, 7, 8, 11, 12], the batten length is 12, there are 4 cuting point

int getMinCost(int a[], int n){
if (NULL == a || n <= 1)
return -1;
int rec[100][100] = {0};
for (int i = 2; i < n; i++){
for (int j = 0; j < n-i; j++){
int nMin = INT_MAX;
for (int k = 1; k < i; k++)
nMin=min(nMin,rec[j][j+k]+rec[j+k][j+i]+a[j+i]-a[j]);
rec[j][j+i] = nMin;
}
}

return rec[0][n-1];
}
'''

'''
101.
1.烙印，在面试前碰到了，刚刚好都等着，问我 你是哪个xxx么？ 我就是今天要面你的。。 当时我就心里想完了。。但是题目挺简单。

def getprobability(n):得到某个数出现的概率。

'''

'''
102.

Minimum vertex cover:
Formally, a vertex-cover of an undirected graph G=(V, E) is a subset V′ of V such that if edge (u, v) is an edge of G,
then u is in V′, or v is in V′, or both. The set V′ is said to "cover" the edges of G.
The following figure shows examples of vertex covers in two graphs (and the set V' is marked with red).
A minimum vertex cover is a vertex cover of smallest possible size.

Maximal matching:
Given a graph G = (V,E), a matching M in G is a set of pairwise non-adjacent edges; that is, no two edges share a common vertex.
In other words, a matching M of a graph G is maximal if every edge in G has a non-empty intersection with at least one edge in M.

# http://dingdongsheng.cool.blog.163.com/blog/static/1186187552009431405995/
# https://en.wikipedia.org/wiki/Bipartite_graph

'''

'''
103.
web server使用多线程处理用户请求还是多进程处理，进程间怎么通信，线程和进程区别什么，什么是死锁，如何防止死锁，什么是virtual memory，

'''

'''
104.

'''

'''
105.
How many balanced binary tree there are with n leaf nodes? Prove and write codes.
http://ideone.com/PRusHP
'''

'''
106.

'''
max_height = 0
result_node = tree_node(0)
def find_deepest_node(root):
if not root:
return None
global max_height
global result_node
find_deepest_helper(root, 0)
return result_node.val

def find_deepest_helper(root, height):
global max_height
global result_node
if not root:
return
if not root.left and not root.right:
if max_height < height:
print "height: ", height
max_height = height
result_node = root

find_deepest_helper(root.left, height+1)
find_deepest_helper(root.right, height+1)

max_height_left = 0
left_node = tree_node(0)
def find_deepest_left_node(root):
if not root:
return None
global max_height_left
global left_node
find_deepest_left_helper(root, 0, False)
return left_node.val

def find_deepest_left_helper(root, height, isleft):
global max_height_left
global left_node
if not root:
return
if not root.left and not root.right and isleft:
if max_height_left < height:
print "height: ", height
max_height_left = height
left_node = root

find_deepest_left_helper(root.left, height+1, True)
find_deepest_left_helper(root.right, height+1, False)

'''
107.
1. We can write a 3 level for loop body directly as follows:
for (int i  = 0;  i < 56; ++i){
do_something(i);
for(int j = 0; j < 151; ++j){
do_something(j);
for(int k = 0; k < 151; ++k){
do_something(k);.
}
}
}

However, when the levels are very deep (such as 50 levels), we cannot manually write the for loop body directly just like above codes.
Given an array arr, where arr[i] represents the loop count at level i, write an iterative algorithm to implement the multi-level loop.

void multiLevelOperation(int *levelCountArr, int n) {
if(n == 0) return;
int *levelStack = new int[n + 1];
int curSP = 0;
levelStack[0] = 0;
while(curSP >= 0) {
if(curSP == n || levelStack[curSP] == levelCountArr[curSP]) {
--curSP;
if(curSP >= 0) ++levelStack[curSP];
}
else {
do_operation(levelStack[curSP]);
levelStack[++curSP] = 0;
}
}
delete [] levelStack;
}

# http://ideone.com/JAAQ4Y

'''

'''
107. tic－tac－toe： 给一个board，以current state判断是o 赢， x 赢，

'''

'''
108. 给一个list和k（number）。找一个区域k，使得这个区域里k的最大值和最小值的差值最大，返回这个值。用heap或priority queue做dp。
'''

'''
109. tourament question:  input is players like（A,B,C,D）, print total rounds[[(A, B), (C, D)], [(A, C), (B, D)], [(A, D), (B, C)]]
'''

'''
110.
# http://www.mitbbs.com/article_t/JobHunting/32582249.html

# similar question: https://github.com/UmassJin/Leetcode/blob/master/Experience/Fence_Painter.py
'''
def valid_string(n):
dp_same = 3
dp_dif = 0

for i in xrange(n-1):
dp_same, dp_dif = dp_same+dp_dif, dp_same*2 + dp_dif
return dp_same + dp_dif

'''
111.

'''

'''
112.

'''

'''
113.

'''

'''
114.

'''

'''
115.
Given a rod of length n inches and an array of prices that contains prices of all pieces of size smaller than n.
Determine the maximum value obtainable by cutting up the rod and selling the pieces.
For example, if length of the rod is 8 and the values of different pieces are given as following,
then the maximum obtainable value is 22 (by cutting in two pieces of lengths 2 and 6)

Example:
Pricing list: {1, 5, 8, 9, 10, 17, 17, 20}
Result = 22 (cut into two pieces of length 2 and 6)
'''

def rod_cut(price):
'''
args; return; raise
'''
if not price: return 0
n = len(price)
dp = [0 for _ in xrange(n+1)]
for i in xrange(1, n+1):
dp[i] = price[i-1]
for j in xrange(1, i):
dp[i] = max(dp[i], price[j-1] + dp[i-j])
return dp[n]

price = [1, 5, 8, 9, 10, 17, 17, 20]
print rod_cut(price)

'''
116.
Given a rope of length n meters, cut the rope in different parts of integer lengths in a way that
maximizes product of lengths of all parts. You must make at least one cut. Assume that the length
of rope is more than 2 meters.
Examples:
Input: 2, return 1 because 1x1 = 1
Input: 5, return 6 because 2x3 = 6
'''
def cut_rope(length):
dp = [0 for i in xrange(length + 1)]
for i in xrange(2, length+1):
for j in xrange(1, i):
dp[i] = max(dp[i], j*(i-j), j*dp[i-j])
return dp[n]

'''

int cut_rope(int n) {
if (n == 2 || n == 3) return n - 1;

int ret = 1;
while (n > 4) {
n -= 3;
ret *= 3;
}
return n * ret;
}
'''

'''
117.
Given an integer array, adjust each integers so that the difference of every adjcent integers are not greater
than a given number target.
If the array before adjustment is A, the array after adjustment is B, you should minimize the sum of |A[i]-B[i]|
Note:
You can assume each number in the array is a positive integer and not greater than 100
Example:
Given [1,4,2,3] and target=1, one of the solutions is [2,3,2,3], the adjustment cost is 2 and it’s minimal. Return 2.

'''

'''
118.
Given an array of integers. Find two disjoint contiguous subarrays such that the absolute difference
between the sum of two subarray is maximum.
Note: The subarrays should not overlap.

For example:
Array: { 2, -1, -2, 1, -4, 2, 8 }
Result subarrays: {-1, -2, 1, -4 }, { 2, 8 }
Maximum difference = 16
'''

def max_diff_two_subarr(array):
"""
@ args:
@ return:
@ raise error:
"""
if not array:
return None
n = len(array)
left_max = list(array)
left_min = list(array)
right_max = list(array)
right_min = list(array)
sum_min = array[0]; sum_max = array[0]

for i in xrange(1, n):
if sum_min > 0: sum_min = 0
if sum_max < 0: sum_max = 0
sum_min += array[i]
sum_max += array[i]

left_min[i] = min(left_min[i-1], sum_min)
left_max[i] = max(left_max[i-1], sum_max)

sum_min = array[n-1]; sum_max = array[n-1]
for i in xrange(n-2, -1, -1):
if sum_min > 0: sum_min = 0
if sum_max < 0: sum_max = 0
sum_min += array[i]
sum_max += array[i]

right_min[i] = min(right_min[i+1], sum_min)
right_max[i] = max(right_max[i+1], sum_max)
print "left_max: ", left_max
print "left_mix: ", left_min
print "right_max: ", right_max
print "right_min: ", right_min

result = -1 << 31
for i in xrange(n-1):
result = max((right_max[i+1] - left_min[i]), result)
for i in xrange(1, n):
result = max((left_max[i-1] - right_min[i]), result)
print result

test = [2, -1, -2, 1, -4, 2, 8]
print max_diff_two_subarr(test)

[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python max_diff_subarr.py
left_max:  [2, 2, 2, 2, 2, 2, 10]
left_mix:  [2, -1, -3, -3, -6, -6, -6]
right_max:  [10, 10, 10, 10, 10, 10, 8]
right_min:  [-6, -6, -5, -4, -4, 2, 8]
16
None

'''
119.
Given a directed graph, check whether the graph contains a cycle or not. Your function should
return true if the given graph contains at least one cycle, else return false.
For example, the following graph contains three cycles 0->2->0, 0->1->2->0 and 3->3,
so your function must return true.

'''
class Graph:
def __init__(self, v, edge):
self.V = v
self.E = edge

def dfs(node, visited, backtrack):
if not visited[node]:
visited[node] = True
backtrack[node] = True
for neighbor in node.neighbors:
if not visited[neighbor] and dfs(neighbor, visited, backtrack):
return True
elif backtrack[neighbor]:
return True
backtrack[node] = False
return False

def detect_cycle_graph(graph):
if not graph: return None
visited = [False for i in xrange(graph.V)]
backtrack = [False for i in xrange(graph.V)]

for node in graph.V:  # Note, here we need to check each node
if dfs(node, visited, backtrack):
return True
return False

'''
120. Strongly Connected Graph
# https://github.com/UmassJin/Leetcode/blob/master/Algorithm/Strongly_Connect_Graph.py
'''

'''
121. Maximum length of the loop
Given an array
Indexes 0 1 2 3 4
Values 3 2 1 4 0
Values are the next index of the jump 0 -> 3 -> 4 -> 0... 1 -> 2 -> 1...
Write a function to detect if there are loops. If yes, get the max length of the loop possible, otherwise just return zero.
'''
def max_length_loop(array):
def dfs(index, len):
if visited[index]:
result[0] = max(result[0], len-length[index])
return
visited[index] = True
length[index] = len
dfs(array[index], len + 1)

if not array:
return 0
n = len(array)
visited = [False for _ in xrange(n)]
length = [0 for _ in xrange(n)]
result = [0]
for i in xrange(n): # check each index in the array
dfs(i, 0)
return result[0]

test = [1,2,3,4,0]
print max_length_loop(test)

'''
122.

input: dest-node: A0
output: all the source nodes: (A1, A3, A4)

'''

import collections

def find_all_source(array, dest):
if not array:
return None
graph = {}
visited = {}
result = []
n = len(array)
for i in xrange(len(array)):
if array[i] == 0:
continue
if array[i] + i < n and array[i] + i >= 0:
graph.setdefault((array[i]+i),[]).append(i)
if i - array[i] < n and i - array[i] >= 0:
graph.setdefault((i - array[i]),[]).append(i)

visited[dest] = True
queue = collections.deque([dest])
while queue:
node = queue.popleft()
if node in graph:
for src in graph[node]:
if src not in visited:
result.append(src)
queue.append(src)
visited[src] = True
return result

test = [1,3,0,2,4,7]
print find_all_source(test, 0)

'''
122.
Count Numbers Jan 3 2015
Given an array of ages (integers) sorted lowest to highest, output the number of occurrences for each age.
For instance:
[8,8,8,9,9,11,15,16,16,16]
should output something like:

'''
def count_number(array):
if not array:
return None
count = 0; step = 1; number = array[0]
index = 0
result = []
n = len(array)
while index < n:
count += step
step *= 2
if index + step >= n or array[index+step] != number:
step = 1
if index + step < n and array[index+step] != number:
result.append((number, count))
count = 0
number = array[index+step]
index += step
result.append((number, count))
return result

test1 = [8,8,8,9,9,11,15,16,16,16]
test2 = [1,2,3,4,5]
print count_number(test1)
print count_number(test2)

'''
123.
for example
Given
1->2->3->4
5->6
return 1->5->2->6->3->4
'''

ListNode * interleave(ListNode *p, ListNode *q) {
if(!p && !q) return nullptr;
if(!p) return q;
if(!q) return p;
q->next = interleave(p->next,q->next);
p->next = q;
return p;
}

'''
124.

2. Given a list of words, find two strings S & T such that:
a. S & T have no common character
b. S.length() * T.length() is maximized
'''

'''
125. given the level of the tree, find how many full trees are there.
'''
def full_tree(level):
'''
@args: level is input level of the tree
@output: how many full binary tree for this level
@let's say need to calculate level 4's full tree
@maintain the left tree as i-1, then right tree may have sum(dp[i-k] (2<=k<=i-1))
@maintain the right tree as i-1, left is also sum(dp[i-k] (2<=k<=i-1))
'''
if level == 0:
return 0
dp = [0 for _ in xrange(level+1)]
dp[1] = 1; dp[2] = 1
for i in xrange(3, level+1):
tmp = 1
for k in xrange(2, i):
tmp = tmp * dp[i-k]
dp[i] = dp[i-1] * (2 * tmp + dp[i-1])
#dp[i] = dp[i-1] * tmp * 2 + dp[i-1] * dp[i-1]
return dp[level]

print full_tree(3)
print full_tree(4)
print full_tree(5)

'''
126.
Given a BST and a number x, find two nodes in the BST whose sum is equal to x.
You can’t use extra memory like converting BST into one array and then solve this like 2sum.
# http://codercareer.blogspot.com/2013/03/no-46-nodes-with-sum-in-binary-search.html
'''

'''
'''

'''
128. Given a snake and ladder board, find the minimum number of dice throws required to reach the
destination or last cell from source or 1st cell. Basically, the player has total control over
outcome of dice throw and wants to find out minimum number of throws required to reach last cell.
If the player reaches a cell which is base of a ladder, the player has to climb up that ladder
and if reaches a cell is mouth of the snake, has to go down to the tail of snake without a dice throw.
# http://www.fgdsb.com/categories/Not-in-LeetCode/page/9/
'''

import collections
from collections import deque

'''
@ move: move[-1] means this is regular cell, move[i] != -1
means there is ladder or snake in this cell
@ n: means the total number of the board
'''
queue = [(0,0)]
visited = {0:True}

while queue:
node = queue.popleft()
index = node[0]
cur_dis = node[1]

while (move[index] != -1):
index = move[index]
for i in xrange(index+1, index+7):
if i in visited:
continue
if i == n -1:
return cur_dis + 1

visited[i] = True
queue.append((i, cur_dis+1))
return -1

'''
129.
define a tree, how to check whether a n-ary tree is unival tree (the value in each node is same).
How to get how many unival tree in a n-ary tree
'''

'''
130
'''
import random

def weighted_choice(seq):
if not seq:
return None
total_value = sum(v for _, v in seq)
random_value = random.randint(0, total_value-1)
print "random_value: ", random_value
pre = 0
partial_sum = 0
for value, i in seq:
partial_sum += i
if pre <= random_value < partial_sum:
print ""
return value
pre = partial_sum
return None

seq = [("a",3),("b",5),("c",8)]
print weighted_choice(seq)

'''
131.
http://www.mitbbs.com/article_t1/JobHunting/33021975_0_1.html
1.leetcode上原题  number of islands
2.follow up：count rank 2 islands, where a rank 2 island is an island inside
a lake located on a continent. A continent is a piece of land located in
the ocean; the ocean is any body of water that touches the edges of the map.

Example:
000000000
000001100
001111100
011000100
001010100
001000100
001111100
000000000

3.If the input 2d array is too large to fit in memory, how to handle?

up更是不知道怎么回答，瞎扯了一通。

'''

'''
132. 给一个binary tree 打印所有的path~~然后问了时间空间复杂度~~就用一般递归做的
'''
# 42. print out the path from root to the leaf in the binary tree

def print_path(root):
if not root:
return
result = []
print_path_helper(root, result, [])
return result

def print_path_helper(node, result, subpath):
if not node:
return
if not node.left and not node.right:
result.append(subpath[:]+[node.value])  # Note: here we should use the subpath[:], not the subpath directly
else:
print_path_helper(node.left, result, subpath+[node.value])
print_path_helper(node.right, result, subpath+[node.value])

# time complexity: O(nlogn)
# space complexity: O(n)

>>> list1 = [1,2,3]
>>> result = []
>>> result.append(list1)
>>> result
[[1, 2, 3]]
>>> id(result[0])
4565113024
>>> id(list1)
4565113024
>>> list1.append(5)
>>> result
[[1, 2, 3, 5]]

'''
133.
2. good number问题。 一个数如果能用（至少两组）两个立方数相加得到那么就是good number。print小于等于n的所有good number。
分析时间复杂度。
我先把小于n的所有立方数存起来。然后就变成了2 sum问题了。。。

'''
import collections

def happy_number(n):
if n == 0: return 0
seq = []
result = []
for i in xrange(1, n+1):
tmp = i * i * i
if tmp > n:
break
seq.append(tmp)
print "seq: ", seq
table = collections.defaultdict(int)
for i in xrange(len(seq)):
for j in xrange(i+1, len(seq)):
table[seq[i]+seq[j]] += 1
if table[seq[i]+seq[j]] > 1:
result.append(seq[i] + seq[j])
print result

happy_number(500)

'''
134.Implement a function to perform basic string compression using the counts of repeated characters.
For example, the string aabcccccaaa would become a2b1c5a3.
'''
def compress_string(string):
if not string: return None
count = 1; i = 1
cur = string[0]
result = []
while i <= len(string):
if i < len(string) and string[i] == cur:
count +=1
else:
result.append(cur+str(count))
if i < len(string):
cur = string[i]
count = 1
i += 1
return ''.join(result)

'''
135. compress string
For example, the string aabcccccaaa would become a*2b*1c*5a*3. the original string may still have
number and *
'''

def compress_string(string):
if not string: return None
count = 1; i = 1
cur = string[0]
result = []
while i < len(string):
if cur.isdigit():
result.append("#"+cur)
cur = string[i]
i += 1
elif cur == "*":
result.append("#"+cur)
cur = string[i]
i += 1
else:
while i < len(string) and string[i] == cur:
count +=1
i += 1
result.append(cur+"*"+str(count))
if i < len(string):
cur = string[i]
count = 1
i += 1
return ''.join(result)

print compress_string("aa2*5bccc")

'''
136.
Q)  Write a program to count the total number of pages reachable from a website.
For example, given "nytimes.com", count the number of pages reachable from there.
You can assume you are given a function to fetch the page and extract the inner links, e.g.:
List<String> fetchPageAndExtractUrls(String url);
'''
def fetch_pages(url):
visited = {}
total_url = [0]
fetch_helper(url, total_url, visited)

def fetch_helper(url, total_url, visited):
children = fetchPageAndExtractUrls(url)
if not children:
return
for child in children:
if child not in visited:
visited[child] = True
total_url[0] += 1
fetch_helper(child, total_url, visited)

'''
137.
Q) Given a tiny computer with a 1 MHz CPU and 1 KiB of RAM memory;
no input;
only output is an LED light that says “I am done”.
(1 MHz == 1 million instructions per second)
I load an arbitrary unknown program onto this computer..
How long do we have to wait in wall-clock time before we can prove the program has an infinite loop?
'''

1kilobyte = 2^13 bit, 所以该计算机内存可能存在的不同状态是2^14种。

'''
138.

precision是表示小数点后位数（2就要两位一致）。我就先找到result两边的integer标为l , r。

（2,3）大于1和（0,1）小于一两种范围二分的时候方向不同。大于一越平方越大，小于一越平方越小

'''

def sqrt_float(num, p):
'''
@num: float number
@p: precision after dot
'''
if num <=0: return 0
l = 0; r = num
if num < 1: r = 1

while l <= r:
mid = (l + r) / 2.0
print "l: %f, r: %f, mid: %f" %(l, r, mid)
if mid * mid > num:
r = mid
elif mid * mid < num:
l = mid
if judge_precision(num, mid*mid, p):
return mid
return None

def judge_precision(num, res, p):
if int(num*(10**p)) == int(res*(10**p)):
print "res: ", int(res*(10**p))
return True
return False

print sqrt_float(1.6, 2)

[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python sqrt_float.py
l: 0.000000, r: 1.600000, mid: 0.800000
l: 0.800000, r: 1.600000, mid: 1.200000
l: 1.200000, r: 1.600000, mid: 1.400000
l: 1.200000, r: 1.400000, mid: 1.300000
l: 1.200000, r: 1.300000, mid: 1.250000
l: 1.250000, r: 1.300000, mid: 1.275000
l: 1.250000, r: 1.275000, mid: 1.262500
l: 1.262500, r: 1.275000, mid: 1.268750
res:  160
1.26875

print sqrt_float(0.556, 2)

[JINZH2-M-20GQ: ~/Desktop/Python_training/Leetcode]: python sqrt_float.py
l: 0.000000, r: 1.000000, mid: 0.500000
l: 0.500000, r: 1.000000, mid: 0.750000
l: 0.500000, r: 0.750000, mid: 0.625000
l: 0.625000, r: 0.750000, mid: 0.687500
l: 0.687500, r: 0.750000, mid: 0.718750
l: 0.718750, r: 0.750000, mid: 0.734375
l: 0.734375, r: 0.750000, mid: 0.742188
res:  55
0.7421875

'''
139.
Given an array of N=10^6 int32 and an int32 X, compute the exact number of triples (a, b, c)
of distinct elements of the array so that a + b + c <= X

2）用一个数组表示，3）抛出异常，根据实际情况选择方案。这些方案都可以跟面试官提
'''

'''
140
Binary Tree Maximum Path Sum
Can not have the near node in the final path
'''
def maxpathsum_bt(root):
if not root:
return None
result = [-1<<32]
maxpath(root, result)
return result[0]

def maxpath(node, result):
'''
return (include node, exclude node)
'''
if not node: return (0,0)
l = maxpath(node.left, result)
r = maxpath(node.right, result)

isum = max(0, l[1]) + max(0, r[1]) + node.value
result[0] = max(result[0], isum)
include = node.value + max(0, l[1],r[1])

isum = 0
isum1 = max(0, l[0], l[1])
isum2 = max(0, r[0], r[1])
isum = isum1 + isum2
result[0] = max(result[0], isum)
exclude = max(isum1, isum2)

return (include, exclude)

'''
141.
# http://www.mitbbs.com/article_t1/JobHunting/32972467_0_1.html
2.combination

print:
Hello world
Hello girl
Hello boy
Hi world
Hi girl
Hi boy

followup： how to do it iteratively？

'''
def combination(lists):
if not lists or not lists[0]:
return None
result = []
n = len(lists)
combination_helper(lists, result, [], n)
return result

def combination_helper(lists, result, sublist, length):
if len(sublist) == length:
result.append(sublist)
return

for i, list_member in enumerate(lists):
for l in list_member:
combination_helper(lists[i+1:], result, sublist+[l], length)

#lists = [["hello", "world"], ["fight", "cisco", "hi"], ["google","fighting!"]]
#print combination(lists)

lists1 = [["hello", "world"], ["fight", "cisco", "hi"]]
print combination(lists1)

def combination2(lists):
if not lists or not lists[0]:
return None
result = [[]]
for list_member in lists:
ret = []
for comb in result:
for l in list_member:
ret.append(comb+[l])
#print "ret: ", ret
if ret:
result = ret
return result

#lists2 = [["hello", "world"], ["fight", "cisco", "hi"], ["google","fighting!"]]
#print combination2(lists2)

lists3 = [["hello", "world"], ["fight", "cisco", "hi"]]
print combination(lists3)
~

'''
142.

TreeNode pre = null;
int max = 0;.
int val = 0;.
public void commonValue(TreeNode root){
if(root == null){
max = Math.max(max, val);
return;
}

commonValue(root.left);.

if(pre == null){
val = 1;
}else if(pre.val == root.val){.
val++;
}else{
max = Math.max(max, val);
val = 1;
}-
pre = root;.

commonValue(root.right);
}

'''

'''
143.
input:一个字符串可能含有 ‘*’，‘*’可以代表'j' 或'k'

'''

def dfs(s, i):
if len(s) == i:
print s
return
if s[i] == '*':
dfs(s[:i]+'j'+s[i+1:], i+1)
dfs(s[:i]+'k'+s[i+1:], i+1)
else:
dfs(s, i+1)

s = "abc*e*d"
print dfs(s,0)

'''
144.
Find the longest increasing(increasing means one step) sequence in an integer matrix in 4 directions
(up down left right), return the sequence

DP方程很明显：
opt[i][j] = max{ opt[i+1][j], opt[i-1][j], opt[i][j+1], opt[i][j-1] } +１

'''
def longest_inc(matrix):
if not matrix or not matrix[0]:
return None
m = len(matrix); n = len(matrix[0])
mem = [[0 for _ in xrange(n)] for _ in xrange(m)]
path = 0; maxpath = 0
for i in xrange(m):
for j in xrange(n):
path = dfs(mem, matrix, i, j)
if path > maxpath:
maxstart = matrix[i][j]
maxpath = path
print "start: ",maxstart
return maxpath

def dfs(mem, matrix, i, j):
m = len(matrix); n = len(matrix[0])
if mem[i][j]:
return mem[i][j]
dirs = [[-1,0],[1,0],[0,-1],[0,1]]
for d in dirs:
newi = i + d[0]
newj = j + d[1]
if newi < 0 or newi >=m or newj < 0 or newj >= n:
continue
if matrix[newi][newj] == (matrix[i][j] + 1):
mem[i][j] = max(mem[i][j], dfs(mem, matrix, newi, newj))
mem[i][j] += 1
print mem
return mem[i][j]

matrix = [  [1,9,8,6],
[7,3,4,5],
[5,2,6,8]]

print longest_inc(matrix)

# mem table:
[[1, 1, 2, 1], [1, 4, 3, 2], [1, 5, 1, 1]]
start:  2
5

'''
145.
1. longest consecutive numbers
lc原题，但要考虑重复，而且numbers无序， 并且要输出最长的numbers,
example：
1, 2, 3, 4, 6, 7, 8, 9, 10, 11 → 6, 7,8, 9, 10, 11.
11, 10, 9, 8, 7, 6 4, 3, 2,1 ->11, 10, 9, 8, 7, 6
1, 2, 3, 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5
'''

def longest_consecutive(num):
if not num:
return None
n = len(num)
table = {}
result = 0
resultlist = []
for i in num:
left = 0; right = 0
leftlist = []; rightlist = []
if i not in table:
if i-1 in table:
left = table[i-1][0]
leftlist = table[i-1][1]
if i+1 in table:
right = table[i+1][0]
rightlist = table[i+1][1]

isum = left + right + 1
ilist = leftlist + [i] + rightlist

table[i] = (isum,ilist)
table[i-left] = (isum,ilist)
table[i+right] = (isum,ilist)
if len(ilist) > len(resultlist):
resultlist = ilist
result = max(isum, result)
print resultlist
return result

test = [100, 4, 200, 1, 3, 2, 201, 202, 5]
print longest_consecutive(test)

# Corner Case
# Input:	[0,3,7,2,5,8,4,6,0,1]
# Output:	7
# Expected:	9

'''
147.第1题的follow－up
numbers变成二叉树，找longest consecutive numbers
example:
1
2     3
5    3

→ 1, 2

'''

def longest_consecutive_list(root):
'''
@only consider the path from root to each leaf
@only consider the increasing path from root
'''
if not root:
return None
result = [-1<<32]
consecutive_helper(root, result)
return result[0]

def consecutive_helper(node, result):
if not node: return None
if not node.left and not node.right:
return (node.value, 1)

l = consecutive_helper(node.left, result)
r = consecutive_helper(node.right, result)

tmpleft = 0; tmpright = 0
if l and node.value == (l[0] + 1):
tmpleft = l[1] + 1
if r and node.value == (r[0] + 1):
tmpright = r[1] + 1
result[0] = max(tmpleft, tmpright, result[0])

return (node.value, max(tmpleft, tmpright))

'''
148.

'''

def compare_str(lists):
'''
assume the input string only has the lowercase letters
@first could transfer each string into the bit, then compare
each pair of string whether they are the same or not
'''
if not lists:
return None
n = len(lists)
bit_pattern = []
lists = sorted(lists, key=len)
for s in lists:
x = 0
for char in s:
x = x | 1 << ord(char)-ord('a')
bit_pattern.append(x)
print "bit: ", bit_pattern
maxlen = 0
for i in xrange(n):
j = n - 1
while i < j:
if not bit_pattern[i] & bit_pattern[j]:
maxlen = max(maxlen, len(lists[i])*len(lists[j]))
print "two lists: %s, %s" %(lists[i], lists[j])
break
j -= 1
return maxlen

lists = ['fighting', 'google', 'hello', 'hi', 'how','']
lists1 = ['hello','cisc','cisco','wlddd']
print compare_str(lists)
print compare_str(lists1)

'''
149.

# http://www.geeksforgeeks.org/array-rotation/
'''

'''
150.
1. 字符串匹配 -> anagram -> 结合起来 不用完全的字符串匹配 只要是anagram就算成功

# http://www.geeksforgeeks.org/anagram-substring-search-search-permutations/
# http://www.careercup.com/question?id=5389078581215232
'''

import collections

def string_anagram(lists, word):
if not lists or not word or (len(lists) < len(word)):
return False

m = len(lists); n = len(word)
target = collections.Counter(word)
cur = collections.Counter(lists[:n])
for i in xrange(n,m):
if target == cur:
return lists[i-n:i]

cur[lists[i]] += 1
cur[lists[i-n]] -= 1
if not cur[lists[i-n]]:
del cur[lists[i-n]]
if target == cur:
return lists[i-n+1:]
return False

w = "ABCD"
print string_anagram(l, w)

l1 = "cdsgsdgsa"
w1 = "a"
print string_anagram(l1, w1)

l2 = "abcfedgsfdaf"
w2 = "abcdefg"
print string_anagram(l2, w2)

'''
compare the string using heapq
'''

import heapq

class MyLine(object):
def __init__(self, string):
self.string = string

def __cmp__(self, other):
for i in xrange(min(len(self.string), len(other.string))):
if self.string[i] > other.string[i]:
return 1
elif self.string[i] < other.string[i]:
return -1
else:
continue
if len(self.string) > len(other.string):
return 1
elif len(self.string) < len(other.string):
return -1
else:
return 0

class Solution(object):
def heapq_str(self):
heap = ["hello","world","fighting","cisco"]
heap1 = []
for s in heap:
heap1.append(MyLine(s))
heapq.heapify(heap1)
result = []
while heap1:
element = heapq.heappop(heap1)
result.append(element.string)

return result

test = Solution()
print test.heapq_str()

========================================================================================

'''
Design
'''

This is just a plug, from me, for you to know about processes, threads and concurrency issues.
A lot of interviewers ask about that stuff, and it's pretty fundamental, so you should know it.
and livelock and how to avoid them. Know what resources a processes needs, and a thread needs,
and how context switching works, and how it's initiated by the operating system and underlying
hardware. Know a little about scheduling. The world is rapidly moving towards multi-core, and
you'll be a dinosaur in a real hurry if you don't understand the fundamentals of "modern"
(which is to say, "kinda broken") concurrency constructs.

The best, most practical book I've ever personally read on the subject is Doug Lea's Concurrent
Programming in Java. It got me the most bang per page. There are obviously lots of other books
on concurrency. I'd avoid the academic ones and focus on the practical stuff, since it's most
likely to get asked in interviews.

swap space

交换空间和虚拟内存的区别在于使用的系统不一样,产生的技术手段不一样,以下是详解,希望对你有所帮助!

Linux 中的交换空间（Swap space）在物理内存（RAM）被充满时被使用。如果系统需要更多的内存资源，而物理内存已经充满，

1 billion files  each file 4k you have more id than files, which means files are dupliacte.
your computer has 4k memory 1TB disk.
design a method to remove duplicate files and store those files
given id track the file from your disk...

'''

random模式就是每次随机播放列表里的一首歌；
shuffle模式就是shuffle列表里的歌，然后顺序播放，放完以后重新shuffle，再顺序播放；

'''

'''
3. design: distributed game ,   付费转账 如何 减少 transcation fee
4. group Card  ,  follow up: 如何定义接口 让客户可以自己定义 hashfunction.
'''

'''
1. 系统设计：给一个url和一个给定的api可以返回所有从这个url可以直接链接到的url。要求统计所有能访问到url数。

2. 第一题local minimum，第二题在数组中检查x距离内是否有重复。

3. 1000个文件每个有1TB的大小，服务器每台100GB内存，1TB硬盘。文件基本上一次写入就不会变化了，读的次数比较多。问怎么设计这样的系统。followup怎么解决fault tolerance，再增加1000个这样文件，怎么办，等等。
* if reads are more frequency than write, we should keep Availability (low latency) than Consistency, since write may be very
small, we could use the cache to save the logs.
* Total amount of file is 10^3 * 10^12 = 10^15; 100GB = 100 * 10^9 = 10^11B main memory, 10^13B Disk, use the latest Recent Cache.
* If there are many servers, could use the Quorums to ensure the consistency, choose W=N and R=1 to ensure the quick read.

follow-up是如何应对系统管理员尴尬地恰巧在这段时间内改了系统时间

6. Design Question: Get program running on data centers, try catch and scalability , cache followups

7. 第五题是design题。问我设计程序给一个program name, 得到它在哪些data center上运行

List<String> getProgramOnDataCenter(String ProgramName)
boolean isOnDataCenter(String ProgramName, String DCName)

8. 然后是一个design题，design一个cache，然后需要设计哪些操作，需要考虑哪些参数，用什么hardware储存。。

10. 设计售票系统， 要求
1. 每次返回5张可选最多
2. 保证不会给两个不同user返回同一个可选座位
3. 用户2分钟之内，没有购买，重新开始

11. system design，什么一堆page判断duplicate，如何断定一个page比另外一个page更trustful

12. 设计题，问用什么数组实现搜索推荐，先讨论了几种方案，最后说用trie

13. 德州扑克
we have n cards, four suites (H, C, D, S). 1<=value<=13， we have the following hands type:
Straight flush      Four of a kind      Full house  Flush Straight Three of a kind Two pair One pair
Questions: given n cards, and find out the best hands type we could have, n is not 52. and the output does
not have to be five. 如果你找到three of a kind，但是没有找到比它更大的了，那这三张就是Output3.

14. 选址建房子。图论的题，意思是给一个matrix，上面有一堆商店，每个商店有建房子需要的材料，要求找到建房子最佳的地址，

16. 一辆车有Year, Make, Model。假设一个Dealer有很多很多车，如何才能得到每一种unique car有多少辆。unique car的意思是说，
Year, Make, Model这三个特征，只要有一个和其他车不同，就是unique car。

17. 假设用一个N叉树存一个员工管理系统，从上到下按照级别一级一级递减，最顶端是CEO，往下是各个级别的经理，再是普通员工，

# http://martinfowler.com/apsupp/recurring.pdf
# http://stackoverflow.com/questions/85699/whats-the-best-way-to-model-recurring-events-in-a-calendar-application

1.2 system design：一种新型的storage，怎么样用来scan engineer的hard disk来做备份
4. system design：logging query － 有好几个小问，例如，如何得到过去一个月浏览某主页的次数，来自某个国家的浏览数，等等

5. design: chromecast, how to know which app can be supported? There is a
cloud that can give the information to the chrome cast, appID, deviceID,
cache design.

3. design: distributed game ,   付费转账 如何 减少 transcation fee
4. group Card  ,  follow up: 如何定义接口 让客户可以自己定义 hashfunction.

'''

'''
System Design 分类
'''
=========================================
'''

1. 设计贪吃蛇， 怎么定义蛇， 怎么移动， 怎么吃， 怎么判断时候活着， 怎么定义游戏版
# https://github.com/UmassJin/Leetcode/blob/master/Design/OS_concepts/Game/snake.md
# http://www.hawstein.com/posts/snake-ai.html
# https://github.com/Hawstein/snake-ai/blob/master/snake.py

# 我们可以通过一个二位数组来定义board, 一位数组定义snake
# Initialization: snake_size = 1; snake_head = snake_array[0];
# Move: up, down, left, right, avoid the snake itself, check the board size, recorde each step since snake need to move
# empty the tail block in snake
# Eat: the simplest method for "eat" is use the BFS to find the shortest path to the food, but this may lead to the no path
# then we need to use the "Wander" function, after discuss the simple verion, we could use the "virtual snake" to test the
# safe path, if the path is "safe", which means whether snake has the path to follow it's tail, here we could use the tail as
# the fake "food" and then find whether there is path, then for each move, we use the BFS and check the safety, if there is no
# path between head and food and head and tail, choose the random one,

1. 目标是食物时，走最短路径
2. 目标是蛇尾时，走最长路径

2. tic-tac-toe，给定场景是人机大战，人永远先开始下。要求把所有的棋盘布局组合都输出（人机各走一步算一个新的棋盘布局）。
# Minmax wiki: https://en.wikipedia.org/wiki/Minimax
# Minmax tic-tac-toe: http://neverstopbuilding.com/minimax
# 中文版: http://univasity.iteye.com/blog/1170226

Pseudocode:
==========
function minimax(node, depth, maximizingPlayer)
if depth = 0 or node is a terminal node
return the heuristic value of node
if maximizingPlayer
bestValue := -∞
for each child of node
val := minimax(child, depth - 1, FALSE)
bestValue := max(bestValue, val)
return bestValue
else
bestValue := +∞
for each child of node
val := minimax(child, depth - 1, TRUE)
bestValue := min(bestValue, val)
return bestValue

(* Initial call for maximizing player *)
minimax(origin, depth, TRUE)

def minimax(game, depth):
if game.over:
return score(game)
depth += 1
scores = []
moves = []

# Populate the scores array, recursing as needed
game.get_available_moves.each do |move|
possible_game = game.get_new_state(move)
scores.push minimax(possible_game, depth)
moves.push move
end

# Do the min or the max calculation
if game.active_turn == @player
# This is the max calculation
max_score_index = scores.each_with_index.max[1]
@choice = moves[max_score_index]
return scores[max_score_index]
else
# This is the min calculation
min_score_index = scores.each_with_index.min[1]
@choice = moves[min_score_index]
return scores[min_score_index]
end
end

# max-min pruning
https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning

1. 有两个值被传递到每个树的节点：
值alpha，记录着找到的最好的“大值”（MAX value）；
值beta，记录着找到的最好的“小值”（MIN value）。
2. 在MAX层时，在对每个子路径进行估值前，用前一路径的返回值与beta值作比较。如果该值大于beta值，那么跳过对当前节点的搜索；
3. 在MIN层时，在对每个子路径进行估值前，用前一路径的返回值与alpha值作比较。如果该值小于alpha值，那么跳过对当前节点的搜索。

01 function alphabeta(node, depth, α, β, maximizingPlayer)
02      if depth = 0 or node is a terminal node
03          return the heuristic value of node
04      if maximizingPlayer
05          v := -∞
06          for each child of node
07              v := max(v, alphabeta(child, depth - 1, α, β, FALSE))
08              α := max(α, v)
09              if β ≤ α
10                  break (* β cut-off *)
11          return v
12      else
13          v := ∞
14          for each child of node
15              v := min(v, alphabeta(child, depth - 1, α, β, TRUE))
16              β := min(β, v)
17              if β ≤ α
18                  break (* α cut-off *)
19          return v

3. 保龄球计分，给一组分数，输出实际每轮投完后的累计得分。

4. 设计扫雷游戏
# http://code.tutsplus.com/tutorials/build-a-minesweeper-game-within-200-lines-of-code--active-8578

'''

'''
'''
Please use this Google doc to code during your interview. To free your hands for coding, we recommend that you use a headset or a phone with speaker option.

Write a function that accepts an array of numbers as input, and returns the largest product (multiplication)  of any two numbers in that array

Input: [0, 3, 5, 7]
Output: 35

def maxProduct(nums):
if not nums or len(nums) < 2: return 0
minval = nums[0]
maxval = nums[0]
result = nums[0]

for i in xrange(1, len(nums)):
result = max(minval * nums[i], maxval* nums[i], result)
maxval = max(maxval, nums[i])
minval = min(minval, nums[i])
return result

def maxProduct(nums):
if not nums or len(nums) < 2: return 0
result = nums[0]
maxval = nums[0]

for i in xrange(len(nums)):
if nums[i] == 0:
result = max(result, 0)
continue
else:
for j in xrange(i+1, len(nums)):
tmp = nums[i] * nums[j]
result = max(tmp, result)
return result

test case:
[0] ⇒ 0
[1] ⇒ 0
[0, 1] ⇒ 0
[-1, -6, 3] => 6
[0, 3, 5, 7]

"internationalization" -> "i18n"
"localization" -> "l10n"

Such abbreviations are not always unique -- for example, “a11y” could stand for “accessibility”, “automatically”, etc.
Given a list of words, determine if the abbreviation of the word is unique.

"internationalization" -> "i18n"
"localization" -> "l10n"
accessibility -> “a11y”

True

"internationalization" -> "i18n"
"localization" -> "l10n"
accessibility -> “a11y”
automatically -> a11y
‘ab’ -> ‘a0b’
False

def abbreviation_unique(array):
if not array or len(array) < 2: return True
n = len(array)
check = {}
for i in xrange(n):
strlen = len(array[i])
abbre = array[i][0] + str(strlen-2) + array[i][strlen-1]
if abbre in check:
return False
else:
check[abbre] = 1
return True

n string in the input array
time complexity: O(n)
space complexity: O(n)

'''
onsite:
1. find the shortest distance for each unlocked cell in matrix (警察那题)
2. find whether three points in the same line, if in the same line, the rate is 1.0, otherwise is 0
3. game, matrix, each matrix is dead or alive, if x < 2, died, if x > 3 died, if x = 3, alive, others maintain the same
4. two rows array, find the minimum obstacle need to move if we want to move from the top left to right down
do the in-order for the two trees, use the minimum space, less than O(n), maybe O(logn)
'''

Given a list of words as input do two things, build a model which allows you to generate similar but pseudo random words based on the input corpus.

BuildModel(String[] words);
String GeneratePseudorandomWord();

A → C -> E
->P ->D
->L

root
|
A (value, time, possibility)
| |     |
C P     L
| |  |  |
E P  D  E
|
|     P
L     |
|     P
E

table:
{A: {P:2, C:1, (L,1), (D,1)}, C: [E], E: {A:1, ‘end’:2}, P: [(P:1)]}
src = [(A:3),(B:2),(E:1)]
des = [(D:1)]
random(0,1)

Input:
ACE  1/3
EAE

E
EA

⅔ end, ⅓ A

Output:
APPE
ACE

BuildModel(String[] words);
String GeneratePseudorandomWord();

def BuildModel(words):
if not words:
return None
src = collections.defaultdict(int)
chartable = {}
for word in words:
for i, char in enumerate(word):
if i == 0:
scr[char] += 1
if i + 1 < len(word):
if char not in chartable:
chartable[char] = collections.defaultdict(int)
chartable[char][word[i+1]] += 1
else:
chartable[char][word[i+1]] += 1
if i + 1 == len(word):
chartable[char][‘end’] += 1

{A: {P:2, C:1, L:1, D:1}, C: [E], E: {A:1, ‘end’:2}, P: [(P:1)]}

0.4
A:0.1, B:0.3, C:0.6

import random
def GeneratePseudorandomWord(src, chartable):
randomnum = random.randint(0,1)
srcsum = sum(src.values())
temp = {}
for item, value in src:
src[item] = operater.truediv(value/srcsum)
temp[src[item]] = item
sorted(temp)
pre = 0
for pos, item in temp:
cur = pre + pos
if pre <= randomnum < cur:
result.append(item)
break