Jaccorot 日事日毕日清日高

ARTS-005

2020-06-26

一、Algorithm

有两个有序链表,将他们组成一个有序链表

21. Merge Two Sorted Lists

class Node:
    def __init__(self, val, next):
        self.val = val
        self.next = next


a = Node("8", None)
b = Node("5", a)
c = Node("3", b)
d = Node("1", c)

aa = Node("7", None)
bb = Node("6", aa)
cc = Node("4", bb)
dd = Node("2", cc)


def combine_node(a: Node, b: Node) -> Node:
    if a is None or b is None:
        return a or b
    result = t = Node(-1, None)
    while a is not None and b is not None:
        if a.val >= b.val:
            t.next = b
            b = b.next
        else:
            t.next = a
            a = a.next
        t = t.next
    if a is not None:
        t.next = a
    if b is not None:
        t.next = b
    return result.next


def print_node(node: Node):
    while node:
        print(f"{node.val} =>", end=" ")
        node = node.next
    print()


print_node(d)
print_node(dd)
temp = combine_node(d, dd)
print_node(temp)

# 1 => 3 => 5 => 8 => 
# 2 => 4 => 6 => 7 => 
# 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8 => 

括号校验

给一个字符串,字符串里有 (){}[]这六个符号,设计一个算法,判断这些符号是否成对匹配,即要检验这些括号是否都是成对出现的。

def brackets_check(s: str) -> bool:
    temp = []
    brackets_list = ["[", "]", "{", "}", "(", ")"]
    brackets_dict = {")": "(",
                     "]": "[",
                     "}": "{"}
    for i in s:
        if i in brackets_list:
            if i in brackets_dict.keys():
                if temp.pop() != brackets_dict.get(i):
                    return False
            else:
                temp.append(i)
    if len(temp) == 0:
        return True
    else:
        return False


ss = "s(sdf)ssdf{[]}"
print(brackets_check(ss))

最大的可能拼出的数字

179.Largest Number 给出一个数组,如 [7864, 284, 347, 7732, 8498],现在需要将数组中的数字拼接起来,如按顺序依次拼接为:786428434777328498,数组中的数字拼接顺序可以任意,编写程序,返回「最大的可能拼出的数字」。(以上面数组为例,返回:849878647732347284)

    def largestNumber(l: List[int]) -> str:
        for i in range(len(l) - 1):
            for j in range(len(l) - 1, i, -1):
                if self.bigger_than(l[j], l[j - 1]):
                    l[j], l[j - 1] = l[j - 1], l[j]
        print(l)
        return str(int("".join(map(str,l))))

    def bigger_than(n1: int, n2: int):
        return str(n1) + str(n2) > str(n2) + str(n1)

# print(max_combined_num([7864, 334, 447, 7732, 8498, 6, 33, 331, 1, 330, 2]))
# print(max_combined_num([3,30,34,5,9]))
print(max_combined_num([121, 12]))



# build-in function
def largestNumber1(self, nums):
    import functools
    if not any(nums):
        return "0"
    return "".join(sorted(map(str, nums), key=functools.cmp_to_key=lambda n1, n2: -1 if n1+n2>n2+n1 else (1 if n1+n2<n2+n1 else 0)))
    
# bubble sort
def largestNumber2(self, nums):
    for i in xrange(len(nums), 0, -1):
        for j in xrange(i-1):
            if not self.compare(nums[j], nums[j+1]):
                nums[j], nums[j+1] = nums[j+1], nums[j]
    return str(int("".join(map(str, nums))))
    
def compare(self, n1, n2):
    return str(n1) + str(n2) > str(n2) + str(n1)
    
# selection sort
def largestNumber3(self, nums):
    for i in xrange(len(nums), 0, -1):
        tmp = 0
        for j in xrange(i):
            if not self.compare(nums[j], nums[tmp]):
                tmp = j
        nums[tmp], nums[i-1] = nums[i-1], nums[tmp]
    return str(int("".join(map(str, nums))))
    
# insertion sort
def largestNumber4(self, nums):
    for i in xrange(len(nums)):
        pos, cur = i, nums[i]
        while pos > 0 and not self.compare(nums[pos-1], cur):
            nums[pos] = nums[pos-1]  # move one-step forward
            pos -= 1
        nums[pos] = cur
    return str(int("".join(map(str, nums))))

# merge sort        
def largestNumber5(self, nums):
    nums = self.mergeSort(nums, 0, len(nums)-1)
    return str(int("".join(map(str, nums))))
    
def mergeSort(self, nums, l, r):
    if l > r:
        return 
    if l == r:
        return [nums[l]]
    mid = l + (r-l)//2
    left = self.mergeSort(nums, l, mid)
    right = self.mergeSort(nums, mid+1, r)
    return self.merge(left, right)
    
def merge(self, l1, l2):
    res, i, j = [], 0, 0
    while i < len(l1) and j < len(l2):
        if not self.compare(l1[i], l2[j]):
            res.append(l2[j])
            j += 1
        else:
            res.append(l1[i])
            i += 1
    res.extend(l1[i:] or l2[j:])
    return res
    
# quick sort, in-place
def largestNumber(self, nums):
    self.quickSort(nums, 0, len(nums)-1)
    return str(int("".join(map(str, nums)))) 

def quickSort(self, nums, l, r):
    if l >= r:
        return 
    pos = self.partition(nums, l, r)
    self.quickSort(nums, l, pos-1)
    self.quickSort(nums, pos+1, r)
    
def partition(self, nums, l, r):
    low = l
    while l < r:
        if self.compare(nums[l], nums[r]):
            nums[l], nums[low] = nums[low], nums[l]
            low += 1
        l += 1
    nums[low], nums[r] = nums[r], nums[low]
    return low

合并两个有序列表???

# 尾递归
def _recursion_merge_sort2(l1, l2, tmp):
    if len(l1) == 0 or len(l2) == 0:
        tmp.extend(l1)
        tmp.extend(l2)
        return tmp
    else:
        if l1[0] < l2[0]:
            tmp.append(l1[0])
            del l1[0]
        else:
            tmp.append(l2[0])
            del l2[0]
        return _recursion_merge_sort2(l1, l2, tmp)

def recursion_merge_sort2(l1, l2):
    return _recursion_merge_sort2(l1, l2, [])


# 循环算法

# def loop_merge_sort(l1, l2): 
#     tmp = [] 
#     while len(l1) > 0 and len(l2) > 0: 
#         if l1[0] < l2[0]: 
#             tmp.append(l1[0]) 
#             del l1[0] 
#         else: tmp.append(l2[0]) 
#             del l2[0] 
#             tmp.extend(l1) 
#             tmp.extend(l2) 
#     return tmp

交叉链表求交点 ???

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
def node(l1, l2):
    length1, lenth2 = 0, 0
    # 求两个链表长度
    while l1.next:
        l1 = l1.next
        length1 += 1
    while l2.next:
        l2 = l2.next
        length2 += 1
    # 长的链表先走
    if length1 > lenth2:
        for _ in range(length1 - length2):
            l1 = l1.next
    else:
        for _ in range(length2 - length1):
            l2 = l2.next
    while l1 and l2:
        if l1.next == l2.next:
            return l1.next
        else:
            l1 = l1.next
            l2 = l2.next

二、Review

三、Tip

python

版本号比较

# cryptography < 1.3.4
    cryptography_version = "1.2.3"
    try:
        cryptography_version = list(map(int, cryptography_version.split('.')))
    except ValueError:
        return

    if cryptography_version < [1, 3, 4]:
        pass

创建字典的方法

#1 直接创建
dict = {'name':'earth', 'port':'80'}
#2 工厂方法
items=[('name','earth'),('port','80')]
dict2=dict(items)
dict1=dict((['name','earth'],['port','80']))
#3 fromkeys()方法
dict1={}.fromkeys(('x','y'),-1)
dict={'x':-1,'y':-1}
dict2={}.fromkeys(('x','y'))
dict2={'x':None, 'y':None}

去除列表中的重复元素

#用集合

list(set(l))

#用字典

l1 = ['b','c','d','b','c','a','a']
l2 = {}.fromkeys(l1).keys()
print l2

#用字典并保持顺序

l1 = ['b','c','d','b','c','a','a']
l2 = list(set(l1))
l2.sort(key=l1.index)
print l2

#列表推导式

l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]

@staticmethod和@classmethod

Python其实有3个方法,即静态方法(staticmethod),类方法(classmethod)和实例方法,如下:

def foo(x):
    print "executing foo(%s)"%(x)

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x

a=A()

# 这里先理解下函数参数里面的self和cls.这个self和cls是对类或者实例的绑定,对于一般的函数来说我们可以这么调用foo(x),这个函数就是最常用的,它的工作跟任何东西(类,实例)无关.对于实例方法,我们知道在类里每次定义方法的时候都需要绑定这个实例,就是foo(self, x),为什么要这么做呢?因为实例方法的调用离不开实例,我们需要把实例自己传给函数,调用的时候是这样的a.foo(x)(其实是foo(a, x)).类方法一样,只不过它传递的是类而不是实例,A.class_foo(x).注意这里的self和cls可以替换别的参数,但是python的约定是这俩,还是不要改的好.

# 对于静态方法其实和普通的方法一样,不需要对谁进行绑定,唯一的区别是调用的时候需要使用a.static_foo(x)或者A.static_foo(x)来调用.

Python中单下划线和双下划线

  • foo:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突.

  • _foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.

  • __foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名.双下划线开头的命名形式在 Python 的类成员中使用表示名字改编 (Name Mangling),即如果有一个Test 类里有一成员 __x,那么 dir(Test) 时会看到 _Test__x 而非 __x。这是为了避免该成员的名称与子类中的名称冲突。但要注意这要求该名称末尾没有下划线。

单例模式

# 1/使用__new__方法
class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance

class MyClass(Singleton):
    a = 1

#2 共享属性
#创建实例时把所有实例的__dict__指向同一个字典,这样它们具有相同的属性和方法.
class Borg(object):
    _state = {}
    def __new__(cls, *args, **kw):
        ob = super(Borg, cls).__new__(cls, *args, **kw)
        ob.__dict__ = cls._state
        return ob

class MyClass2(Borg):
    a = 1

#3 装饰器版本    
def singleton(cls, *args, **kw):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...



GIL线程全局锁

线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.

解决办法就是多进程和协程(协程也只是单CPU,但是能减小切换代价提升性能).

协程

协程是进程和线程的升级版,进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户自己控制切换的时机,不再需要陷入系统的内核态.

Python里最常见的yield就是协程的思想!

Python垃圾回收机制

Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。

  • 1 引用计数 PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。

优点:

简单 实时性 缺点:

维护引用计数消耗资源 循环引用

  • 2 标记-清除机制 基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。

  • 3 分代技术 分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。

Python默认定义了三代对象集合,索引数越大,对象存活时间越长。

举例: 当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。

操作系统

死锁

原因:

  • 竞争资源
  • 程序推进顺序不当

必要条件:

  • 互斥条件
  • 请求和保持条件
  • 不剥夺条件
  • 环路等待条件

处理死锁基本方法:

  • 预防死锁(摒弃除1以外的条件)
  • 避免死锁(银行家算法)
  • 检测死锁(资源分配图)
  • 解除死锁
    1. 剥夺资源
    2. 撤销进程

数据库

乐观锁和悲观锁

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

MyISAM和InnoDB

MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。

InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。

网络

三次握手

  1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三路握手的一部分。客户端把这段连接的序号设定为随机数 A。
  2. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK 的确认码应为 A+1,SYN/ACK 包本身又有一个随机序号 B。
  3. 最后,客户端再发送一个ACK。当服务端受到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包序号被设定为收到的确认号 A+1,而响应则为 B+1。

HTTP和HTTPS

HTTPS握手,对称加密,非对称加密,TLS/SSL,RSA

CSRF和XSS

  • CSRF(Cross-site request forgery)跨站请求伪造
  • XSS(Cross Site Scripting)跨站脚本攻击 CSRF重点在请求,XSS重点在脚本

幂等 Idempotence

幂等: get delete put 非幂等: post

HTTP1.0和HTTP1.1

  1. 请求头Host字段,一个服务器多个网站
  2. 长链接
  3. 文件断点续传
  4. 身份认证,状态管理,Cache缓存

网络四层协议,DNS 解析过程???

to be

测试

Appium 每层的结构,appium 底层是基于什么???

to be

get

本地存在未add文件,pull时提示合并

Your local changes to the following files would be overwritten by merge error: Your local changes to the following files would be overwritten by merge:

protected/config/main.php Please, commit your changes or stash them before you can merge.

git reset --hard HEAD    
git clean -f -d    
git pull  

git pull RPC failed; curl 56 LibreSSL SSL_read: SSL_ERROR_SYSCALL

1、修改提交缓存大小为500M,或者更大的数字
git config --global http.postBuffer 524288000
或者再增大
git config --global http.postBuffer 1048576000

2、配置git的最低速度和最低速度时间:
git config --global http.lowSpeedLimit 0
git config --global http.lowSpeedTime 999999  #单位 秒

3、 翻墙

摘自关于 Python 的最全面试题

四、Share

  • 识不足,则多虑;威不足,则多怒;信不足,则多言。
  • python多线程

Similar Posts

上一篇 ARTS-004

下一篇 ARTS-006