zoukankan      html  css  js  c++  java
  • 00:其他类题目

    算法面试其他篇

    目录:

    1.1 python模拟LRU(Least recently used,最近最少使用)

        定义:算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

        核心:

          1. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;

          2. 当链表满的时候,将链表尾部的数据丢弃。

      1、实现原理

        1)使用三个数据标识这个缓存系统      

            self.cache = {}                   # cache模拟所有缓存系统中数据 key: val

            self.keys = []                     # keys只存放cache字典中的 key 

            self.size = size                  # size 来定义这个缓存系统最大容量

        2)模拟数据加入缓存(set)

            1. 如果缓存为达到最大长度,新数据key插入到 keys列表头部,将key:val存入字典

            2. 如果达到最大长度,先删除最后列表keys最后一个元素,将这个key:val 从cache字典中删除

        3)模拟获取缓存数据(get)

            1. 判断获取的key是否在 cache字典中,如果在就从列表keys中先删除原有key,然后将key插入到列表最前面,并返回val

            2. 如果key不在cache字典中,直接返回None即可

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    class LRUcache:
        def __init__(self, size=3):
            self.cache = {}
            self.keys = []
            self.size = size
    
        def get(self, key):
            if key in self.cache:
                self.keys.remove(key)
                self.keys.insert(0, key)
                return self.cache[key]
            else:
                return None
    
        def set(self, key, value):
            if key in self.cache:
                self.keys.remove(key)
                self.keys.insert(0, key)
                self.cache[key] = value
            elif len(self.keys) == self.size:
                old = self.keys.pop()
                self.cache.pop(old)
                self.keys.insert(0, key)
                self.cache[key] = value
            else:
                self.keys.insert(0, key)
                self.cache[key] = value
    
    
    if __name__ == '__main__':
        test = LRUcache()
        test.set('a', 1)
        test.set('b', 2)
        test.set('c', 3)
        test.set('d', 4)
        print test.keys  # ['d', 'c', 'b']
        print test.cache  # {'c': 3, 'b': 2, 'd': 4}
    
        print(test.get('a'))  # None   当d=4加入缓存是,缓存到达上线3,所以把a从缓存中移除了
        print(test.get('b'))  # 2
        print(test.get('c'))  # 3
        print(test.get('d'))  # 4
    python模拟LRU

    1.2 遍历文件夹

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import os
    def gci(filepath):
        files = os.listdir(filepath)    # 遍历filepath下所有文件,包括子目录
        for fi in files:
            fi_d = os.path.join(filepath, fi)
            if os.path.isdir(fi_d):
                gci(fi_d)
            else:
                print(os.path.join(filepath, fi_d))
    
    # 递归遍历/root目录下所有文件
    gci('C:Go')
    遍历文件夹

    1.3 is和==

      1.== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。

      2.is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。

    1.4 python读取超大文件

      1)普通读文件方法弊端分析

          1.with 上下文管理器会自动关闭打开的文件描述符,在迭代文件对象时,内容是一行一行返回的,不会占用太多内存

          2. 如果python读取文件如果被读取的文件里,根本就没有任何换行符,将会变成一个非常巨大的字符串对象,占用大量内存。

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    def read_file(fname):
        with open(fname) as file:
            for line in file:
                print(line.strip('
    '),)
    path = r'C:aaalutingedc-backendaaa.py'
    read_file(path)
    python普通方法读文件

      2)读取大文件正确方式

          1.  我们使用了一个 while 循环来读取文件内容,每次最多读取 8kb 大小

          2. 这样可以避免之前需要拼接一个巨大字符串的过程,把内存占用降低非常多。 

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    def read_big_file_v(fname):
        block_size = 1024 * 8
        with open(fname,encoding="utf8") as fp:
            while True:
                chunk = fp.read(block_size)
                # 当文件没有更多内容时,read 调用将会返回空字符串 ''
                if not chunk:
                    break
                print(chunk)
    path = r'C:aaalutingedc-backend	ttt.py'
    read_big_file_v(path)
    python读取大文件

     1.5 手写三级装饰器

      1、手写普通装饰器

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    def outer_wrapper(func):
        def wrapper(*args, **kwargs):
            print('---->')
            res = func(*args, **kwargs)
        return wrapper
    
    @outer_wrapper
    def home():
        print("welcome to home  page")
        return "from home"
    
    home()
    普通装饰器

      2、三级装饰器

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    def auth(auth_type):
        def outer_wrapper(func):
            def wrapper(*args, **kwargs):
                print("---->", auth_type)
                res = func(*args, **kwargs)
            return wrapper
        return outer_wrapper
    
    @auth(auth_type="local") # home = wrapper()
    def home():
        print("welcome to home  page")
        return "from home"
    
    home()
    三级装饰器

      3、计算函数执行时间装饰器

    #! /usr/bin/env pythonf
    # -*- coding: utf-8 -*-
    import time
    def timer(func):   #timer(test1)  func=test1
        def deco(*args,**kwargs):
            start_time = time.time()
            func(*args,**kwargs)      #run test1
            stop_time = time.time()
            print("running time is %s"%(stop_time-start_time))
        return deco
    @timer     # test1=timer(test1)
    def test1():
        time.sleep(3)
        print("in the test1")
    test1()
    计算函数执行时间装饰器

     1.6 使用yield生成器生成斐波拉契函数

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    def fib(max_num):
        a,b = 1,1
        while a < max_num:
            yield b
            a,b=b,a+b
    
    g = fib(10)               #生成一个生成器:[1,2, 3, 5, 8, 13]
    print(g.__next__())       #第一次调用返回:1
    print(list(g))            #把剩下元素变成列表:[2, 3, 5, 8, 13]
    生成斐波拉契函数

     1.7 单例模式

      1、单例模式原理及作用

        1、单例模式:永远用一个对象得实例,避免新建太多实例浪费资源
        2、实质:使用__new__方法新建类对象时先判断是否已经建立过,如果建过就使用已有的对象
        3、使用场景:如果每个对象内部封装的值都相同就可以用单例模式

      2、单例模式两种写法

    class Foo(object):
       instance = None
       def __init__(self):
          self.name = 'alex'
    
       def __new__(cls, *args, **kwargs):
          if Foo.instance:
             return Foo.instance
          else:
             Foo.instance = object.__new__(cls,*args,**kwargs)
             return Foo.instance
    
    obj1 = Foo()       # obj1和obj2获取的就是__new__方法返回的内容
    obj2 = Foo()
    print(obj1,obj2)   # 运行结果: <__main__.Foo object at 0x00D3B450>    <__main__.Foo object at 0x00D3B450>
    
    # 运行结果说明:
    # 这可以看到我们新建的两个Foo()对象内存地址相同,说明使用的•同一个类,没有重复建立类
    单例模式01
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    class Singleton(object):
        def __new__(cls, *args, **kwargs):           #new方法最后返回的是一个实例
            if not hasattr(cls, "_instance"):       #如果没有这个字段就调用父类创建
                cls._instance = super(Singleton, cls).__new__(cls)
            return cls._instance                     #永远返回的就是第一次创建的对象
    
    obj1 = Singleton()
    obj2= Singleton()
    print(obj1,obj2)
    单例模式02

     1.8 python高阶函数

       更多详见:https://www.cnblogs.com/xiaonq/p/7898817.html#i2

      1、三元运算 & lambda

    name = 'Tom' if 1 == 1 else 'fly'
    print(name)   # 运行结果: Tom

      2、lambda使用

    f = lambda x:x if x % 2 != 0 else x + 100
    print(f(10))                    # 110
    f = lambda x,y,z:x+y+z
    print(f(1,2,3))                    # 6

      3、 利用 filter、lambda表达式 获取l1中元素小于33的所有元素 l1 = [11, 22, 33, 44, 55]

    l1= [11,22,33,44,55]
    a = filter(lambda x: x<33, l1)
    print(list(a))

      4、利用map,lambda表达式将所有偶数元素加100

    l1= [11,22,33,44,55]
    ret = map(lambda x:x if x % 2 != 0 else x + 100,l1)
    print(list(ret))  # 运行结果: [11, 122, 33, 144, 55]

      5、总结:filter()和map()函数区别

        1. Filter函数用于对序列的过滤操作,过滤出需要的结果,一次性返回他的过滤设置于的是条件

        2. Map函数是对序列根据设定条件进行操作后返回他设置的是操作方法,无论怎样都会返回结果

      7、使用reduce求和

    from functools import reduce  # py3
    print(reduce(lambda x, y: x + y, [ 1, 2, 3, 4]))  # 10
    '''使用reduce将字符串反转'''
    s = 'Hello World'
    from functools import reduce
    
    result = reduce(lambda x,y:y+x,s)
    # 1、第一次:x=H,y=e  => y+x = eH
    # 2、第二次:x=l,y=eH  => y+x = leH
    # 3、第三次:x=l,y=leH  => y+x = lleH
    print( result )      # dlroW olleH
    reduce字符串反转

      8、sorted排序

    students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
    print( sorted(students, key=lambda s: s[2], reverse=False) )    # 按年龄排序
    # 结果:[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
    sorted对列表排序
    d = {'k1':1, 'k3': 3, 'k2':2}
    # d.items() = [('k1', 1), ('k3', 3), ('k2', 2)]
    a = sorted(d.items(), key=lambda x: x[1])
    print(a)            # [('k1', 1), ('k2', 2), ('k3', 3)]
    sorted对字典排序

     1.9 python求阶乘 & 青蛙跳问题

      1、求4的阶乘

    def test(n):
        if n == 1:
            return 1
        else:
            res = n*test(n-1)
        return res
    
    print(test(4))  # 24
    求4的阶乘代码

      2、青蛙跳问题

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    sys.setrecursionlimit(1000000000)             #设置系统最大递归深度
    
    def fib(n):
        if n <= 2:
            return n
        else:
            return fib(n-1) + fib(n-2)
    print(fib(4))         # 5
    二级台阶
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    sys.setrecursionlimit(1000000000)             #设置系统最大递归深度
    
    def fib(n):
        if n <= 2:
            return n
        elif n == 3:
            return 4
        else:
            return fib(n-1) + fib(n-2) + fib(n-3)
    print(fib(4))         # 7
    三级台阶
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    sys.setrecursionlimit(1000000000)             #设置系统最大递归深度
    
    def fib(n):
        if n <= 2:
            return n
        else:
            return 2 * fib(n - 1)
    print(fib(4))         # 8
    n级台阶

    1.10 瓶盖换酒问题 

      问题:2元一瓶酒,2个空瓶换一瓶,4个瓶盖换一瓶 问10块钱买几瓶酒??

    class Change:
        def __init__(self,money):
            self.money=money      # 总共的钱
            self.beer=money//2    # 买到酒的数量(第一次用钱买酒)
            self.cap=0            # 瓶盖数量
            self.bottle=0         # 空瓶数量
            self.count=0          # 总共和了多少瓶酒
    
        def ping(self):
            new_beer=self.bottle//2   # 当前空瓶可换酒的数量
            self.beer+=new_beer       # 更新酒的数量
            self.bottle-=(new_beer*2) # 将已使用的空瓶去除
    
        def gai(self):
            new_beer=self.cap//4     # 当前瓶盖换酒的数量
            self.beer+=new_beer      # 更新酒的数量
            self.cap-=(new_beer*4)   # 将已使用的瓶盖去除
    
        def drink(self):
            self.bottle+=self.beer   # 最终空瓶 = 酒的数量+当前空瓶数量
            self.cap+=self.beer      # 瓶盖数量 = 酒的数量+当前瓶数量
            self.count+=self.beer    # 喝酒数量 = 酒的数量+已经喝的数量
            self.beer=0              # 喝完后把酒的数量重置为0
    
        def run(self):
            while self.beer>0 or self.bottle>=2 or self.cap>=4:
                self.drink()   # 喝酒
                self.ping()    # 空瓶换酒
                self.gai()     # 瓶盖换酒
            return '喝了%d瓶酒,剩余%d个瓶子,剩余%d个盖子'%(self.count,self.bottle,self.cap)
    
    person=Change(10)
    print(person.run())  # 喝了15瓶酒,剩余1个瓶子,剩余3个盖子
    最终喝到酒的数量

     1.11  [lambda x: x*i for i in range(4)] 本质解析

      1、[lambda x: x*i for i in range(4)] 运行结果

    # -*- coding: utf-8 -*-
    fun = [lambda x: x*i for i in range(4)]
    for item in fun:
        print(item(1), end='	')
    # 预计结果为:0, 1, 2, 3
    # 实际输出为:3, 3, 3, 3
    意外结果
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    fun = [lambda x, i=i: x*i for i in range(4)]
    for item in fun:
        print(item(1), end='	')
    # 运行结果:0    1    2    3
    正确结果

      2、原因分析

         注:python解释器查找变量时,会按照顺序依次查找:局部作用域--->嵌套作用域--->全局作用域--->内建作用域

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    def func():
        tmp = []
        for i in range(4):
            print('外层:',i)  # 0 1 2 3
            def lambda_(x):
                print('内存i:',i) # 3
                return x * i
            tmp.append(lambda_)
        return tmp
    
    fl = func()
    fl[0](1)
    '''1. 运行结果如下:'''
    # 外层: 0
    # 外层: 1
    # 外层: 2
    # 外层: 3
    # 内存i: 3
    
    '''2. 原因分析'''
    # 1. 四次循环中外层函数命名空间中的 i 从 0-->1-->2-->3 最后固定为3
    # 2. 内嵌函数lambda_中因为没有定义 i ,从外层函数获取的值都为3
    # 3. 导致得不到预计输出结果:0,1,2,3 只能得到 3, 3, 3, 3
    自定义函数模拟意外结果

     1.12 ip地址转换

      1、求当前ip地址的下一个地址

          1) socket.inet_aton:  将IPv4点分地址转换成32位进制数     

          2) struct.unpack('!I':  将32位数转换成,十位无符号整形  

          3) struct.pack('!I':将十位数字转换成 32位进制数

          4) socket.inet_ntoa: 把32位进制数转换成ip 127.0.1.0

    import socket
    import struct
    if __name__ == '__main__':
        ip = '127.0.0.255'
        int_ip = struct.unpack('!I', socket.inet_aton(ip))[0]     # 2130706687 (int)
        str_ip = socket.inet_ntoa(struct.pack('!I', int_ip+1 ))   # 127.0.1.0
    求当前ip地址下一个地址
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    import struct
    if __name__ == '__main__':
        ip = '127.0.0.255'
    
        '''1. 将ip转成数字'''
        # 1.1 socket.inet_aton: 将IPv4点分地址转换成32位进制数
        ip_to_32dec = socket.inet_aton(ip)    # b'x7fx00x00xff'
        # 1.2 struct.unpack('!I': 将32位数转换成,十位无符号整形
        dec32_to_10 = struct.unpack('!I', ip_to_32dec)[0]  # 2130706687
    
        '''2. 将数字转换成ip'''
        # 2.1 struct.pack('!I':将十位数字转换成 32位进制数
        dec10_to_32 = struct.pack('!I', 2130706688)  # b'x7fx00x01x00'
        # 2.2 socket.inet_ntoa: 把32位进制数转换成ip 127.0.1.0
        f_ip = socket.inet_ntoa(dec10_to_32)
        print(f_ip)  # 127.0.1.0
    struct库常用方法

    1.13  统计文章中单词出现次数并进行排序

      1、统计指定文件中单词出现数量,并找到出现次数最多的前无个

    import io
    import re
    class Counter:
        def __init__(self, path):
            self.mapping = dict()
            with io.open(path, encoding="utf-8") as f:
                data = f.read()
                words = [s.lower() for s in re.findall("w+", data)]
                print(words)  # ['version', '3', 'services', .... ]
                for word in words:
                    self.mapping[word] = self.mapping.get(word, 0) + 1
    
        def most_common(self, n):
            return sorted(self.mapping.items(), key=lambda item: item[1], reverse=True)[:n]
    
    if __name__ == '__main__':
        pt = r'C:aaalutingedc-backenddocker-compose.yml'
        most_common_5 = Counter(pt).most_common(5)
        print(most_common_5)  # [('mysql', 5), ('root', 3), ('db', 3), ('environment', 2), ('3306', 2)]
    统计单词出现次数

     

     

     

    1111111111111111

  • 相关阅读:
    iOS语音合成
    5个可以帮你优化App的优秀网站
    全面谈谈Aspects和JSPatch兼容问题
    做一个 App 前需要考虑的几件事
    Swift 3必看:新的访问控制fileprivate和open
    iOS异常捕获
    LXNetwork – 基于AF3.0封装的iOS网络请求库
    POST方式提交表单时,后台接受实体如果继承了父类,将无法映射表单对应数据
    Angularjs promise对象解析
    H5基于iScroll实现下拉刷新,上拉加载更多
  • 原文地址:https://www.cnblogs.com/xiaonq/p/10489063.html
Copyright © 2011-2022 走看看