备战菊厂笔试1

考点

题型

建议掌握内容

字符串

双指针、哈希、KMP

数组

前缀和、滑动窗口、二分查找、排序

栈与队列

单调栈、括号匹配、双端队列技巧

链表

快慢指针、翻转链表、合并链表

哈希表

判重、频次统计、哈希加滑窗技巧

二叉树

递归遍历、层序遍历、构造树

BFS、DFS、并查集、最短路(Dijkstra)

贪心

区间调度、背包类问题简化版

动态规划

背包问题、最长子序列/子数组

模拟题

比如“文件系统”、“装配线调度”

华为题目喜欢“工程场景模拟题”——既考算法又有业务背景。要熟练将题意转化为数据结构建模


✅ 二、笔试时的实战建议:

1. 分配时间:

  • 一般是 90 分钟 3 道题。

  • 第 1 题通常较简单(字符串/哈希/数组遍历),不要超过 15~20 分钟。

  • 第 2 题中等偏难,第 3 题较难(涉及DP/图),留足时间逐步完成。

2. 调试技巧:

  • 写自测样例,别只靠系统给的 case。

  • 提交前做边界值检查(空串、极大值、负数等)。

  • 注意输出格式,别因为“多了个空格”而 WA。

3. 善用函数封装、注释清晰:

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 动态规划:f(i)表示以nums[i]结尾的最大子数组和
        pass


✅ 三、刷题技巧(目标清晰,练重点)

推荐平台:

  • LeetCode 热题 100 + Top Interview Questions

  • 牛客网 华为笔试真题专区

  • 力扣每日一题(用自己语言快速写)

刷题方法:

  • 反复刷而不是广度刷:做过的题二刷、三刷,尤其是你错过/不会的。

  • 总结题型套路,而不是每题从零开始。

  • 建议你建一个错题本/代码本子:写下你不会的点、易错的细节。


✅ 四、考前其他的基础准备

  • ✅ 一份简洁、清晰、无错误的 简历(PDF格式)

  • ✅ 简历中的项目尽量能答出:你做了什么、为什么这么做、遇到什么问题

  • ✅ 对华为业务线有一定了解,比如你投的是“云计算”、“终端”、“ICT”哪一块

代码风格转换

首先我们要从传统算竞中的 io 风代码转到工程上的面向对象封装风

什么是面向对象编程(OOP)?

将 数据&功能打包成一个对象,通过对其进行描述

什么是                可以理解为一种模版,比如猫类包含了所有猫的共同特征

什么是对象            从类而来的具体实例,比如一只叫“小豆泥”的暹罗猫就是猫类里面的一个对象

面向对象的三大特性

封装        将数据和方法放在一起,对外只暴露接口        class + def 组合,通过__init__构造

继承        子类拥有父类的属性和方法,代码复用            class B( A ) 表示B继承A

多态        不同对象同样的方法调用                                                

class Cat:                      # 定义一个类
    def __init__(self, name):   # 构造函数(初始化)
        self.name = name

    def meow(self):             # 类的行为
        print(f"{self.name} 喵喵叫")

douni = Cat("小豆泥")              # 创建一个对象
douni.meow()                    # 调用对象的方法 => 输出:咪咪 喵喵叫

在这个例子里面 meow 就是一个方法

self 指代的是实例自身,是面向对象编程中类方法的第一个参数,通过 self 可以访问对象的属性和其他方法

变化

一、结构上的改变

OI风格

面向对象风格

全部写在 main() 或直接写在全局

封装为 class Solution 中的方法

输入用 input()

输入由函数参数传入

输出用 print()

输出用 return 返回,由调用者决定是否打印

一般直接运行

用 if __name__ == "__main__": 测试调用

二、必须封装成函数

你不仅要用 return,还要把算法逻辑写成函数形式,这才符合面向对象的结构。

例如:

# 原始 OI 风格
a, b = map(int, input().split())
print(a + b)

转为面向对象 + 函数封装是:

class Solution:
    def add(self, a: int, b: int) -> int:
        return a + b

if __name__ == "__main__":
    a, b = map(int, input().split())
    sol = Solution()
    print(sol.add(a, b))

三、输入不再写在函数内部,而是作为“参数”传入

这是最大区别之一:

  • OI风格:函数内直接 input()

  • OOP风格:函数内不写 input(),而是从参数接收数据

示例对比

OI 风格:

def solve():
    a, b = map(int, input().split())
    print(a + b)
solve()

面向对象风格:

class Solution:
    def add(self, a: int, b: int) -> int:
        return a + b

if __name__ == "__main__":
    a, b = map(int, input().split())
    sol = Solution()
    print(sol.add(a, b))

小结:过渡时需要做的 3 件事

步骤

说明

1. 把主逻辑写成函数

用类封装为 def 函数(self, 参数)

2. 用 return 代替 print

函数输出用 return,主程序再决定是否 print

3. 输入变成参数传入

函数内部不要再 input(),由主程序读取传入

技巧

类中多个子函数封装逻辑,结构更清晰        

类型标注        def func(self , a : int ) -> int :        提高可读性

写完函数写主程序调用测试        if __name__=='__main__'       

比如gcd

class Solution:
    def gcd(self, a: int, b: int) -> int:
        # 辗转相除法
        while b != 0:
            a, b = b, a % b
        return a

# 本地测试用的主函数
if __name__ == "__main__":
    a,b=map(int,input().split())
    sol = Solution()                 # 创建类的实例
    result = sol.gcd(a,b)         # 调用函数
    print("最大公约数是:", result)    # 输出结果

OK,下面我们开始刷题

3.无重复字符的最长子串

我的第一个思路是set去重

但是很明显不行,因为他必须是子串

那么双指针滑动?

答案是可以的

我们需要维护四个变量:

l        各个字符上次位置

vis        当前窗口里面包含的字符

lmax        答案目标

lnow        当前窗口的长度


class Solution:
    '''
    def __init__:
    '''
    def lengest(self,s:str)->int:
        l={}
        vis=''
        lmax=0
        lnow=0
        for i in range(len(s)):
            if s[i] not in vis:
                vis+=s[i]
                lnow+=1
                l[s[i]]=i
            else:#如果出现过:结算,更新
                lmax=max(lmax,lnow)

                last=l[s[i]]
                lnow=i-last

                l[s[i]]=i#记得更新l
                
                vis=s[last+1:i+1]

        lmax=max(lmax,lnow)#最后一次清算
        return lmax


if __name__=='__main__':
    s=input()
    
    sol=Solution()  #先创建类对象
    res=sol.lengest(s)  #再通过对象调用方法
    print(res)

146.LRU缓存

146. LRU 缓存

很显然是字典

而且还需要一个变量存储最先进来的,方便后面逐出(队列)

可以直接用这个变量的长度来判断是否应该逐出

但还是用个变量存储吧,否则每次都要len()

而且注意题意“最久未使用”,那么不只是存储,读取、覆盖的话也得更新他的位置

更新的话先remove再append

from collections import deque
class LRUCache:
    def __init__(self,capacity:int):
        self.lmax=capacity
        self.lnow=0
        #self.last=0
        self.deque=deque()
        self.d={}#defaultdict(int)


    def get(self,key:int)->int:
        if key in self.d:
            self.deque.remove(key)
            self.deque.append(key)
            return self.d[key]

        else:
            return -1


    def put(self,key:int,value:int)->None:
        if self.lnow<self.lmax:#未形成窗口
            #低级错误:竟然先放进去了self.d[key]=value
            if key not in self.d:
                self.d[key]=value
                self.deque.append(key)
                self.lnow+=1
            else:               #"最久未使用“
                self.d[key]=value
                self.deque.remove(key)#用remove删除后重新加
                self.deque.append(key)

        else:#形成窗口
            if key in self.d:
                self.d[key]=value
                self.deque.remove(key)#用remove删除后重新加
                self.deque.append(key)
                self.deque.append(key)
            else:
                s=self.deque.popleft()
                del self.d[s]   #

                self.deque.append(key)
                self.d[key]=value        

不难发现其实每次输入key“使用”都得更新他的地位 

但是这样只有5%用时击败和80%用存击败

正确的做法是用 OrderedDict

OrderedDict 是 Python collections 模块中的一个 有序字典,它和普通 dict 基本功能相同,但能记住键的插入顺序(或访问顺序)

导入

from collections import OrderedDict

主要特性

特性

说明

保留顺序

记录元素插入的顺序(或访问顺序)

支持 move_to_end(key)

可以将某个键移动到字典的开头或末尾

支持 popitem()

可以按顺序弹出最前面或最后面的元素

兼容 dict

用法和普通字典几乎一致

常用方法举例

1. 插入顺序保留

from collections import OrderedDict

od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3

print(od)  # 输出:OrderedDict([('a', 1), ('b', 2), ('c', 3)])

2. move_to_end(key, last=True)

  • 默认 last=True:将键移动到末尾(表示最近使用)

  • last=False:将键移到开头

od.move_to_end('a')          # 'a' 移到最后
od.move_to_end('b', last=False)  # 'b' 移到最前

3. popitem(last=True)

  • last=True(默认):弹出最后一个键值对(表示最近使用)

  • last=False:弹出最前的键值对(表示最久未使用)

od.popitem()          # 弹出最后一个
od.popitem(last=False)  # 弹出第一个

因此我们可以用:

  • move_to_end(key)        在使用时将更新其地位

  • popitem(last=False)      “删除不是last最新的”从左边删除最久未使用的项;

  • OrderedDict 本身就是 O(1) 操作,配合 dict 的查找速度,非常高效。

class LRUCache:

    def __init__(self, capacity: int):
        self.cache = OrderedDict()
        self.capacity = capacity

    def get(self, key: int) -> int:
        if key not in self.cache:
            return -1
        # 把访问的 key 提到最前(代表最近访问)
        self.cache.move_to_end(key)
        return self.cache[key]

    def put(self, key: int, value: int) -> None:
        if key in self.cache:
            # 更新值并将其移到末尾
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            # 弹出最旧的项(先进的)
            self.cache.popitem(last=False)

5.最长回文子串 

经典马拉车Malacher 

class Solution:
    def longestPalindrome(self, s: str) -> str:
        t='#'+'#'.join(s)+'#'
        n=len(t)
        p=[0]*n
        C=R=maxlen=center=0

        for i in range(n):
            p[i]=min(p[2*C-i],R-i) if R-i>0 else 0

            while i+p[i]+1<n and i-p[i]-1>=0\
                  and  t[i+p[i]+1]==t[i-p[i]-1]:
                p[i]+=1

            if i+p[i]>R:
                C,R=i,i+p[i]

            if p[i]>maxlen:
                maxlen,center=p[i],i

        return s[(center-maxlen)//2:(center+maxlen)//2]

我明天写一章讲讲马拉车,今天先休息了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值