Python技术迷

大厂程序员爆料:原来30k,被裁后找了个外包25k,活少不加班, 感觉日子有点安逸了,还要不要继续找工作?

我最近看到一个有趣的爆料,说的是某位大厂程序员在被裁后,找了个外包工作,工资从原来的30K降到了25K,虽然工资低了点,但工作压力反而轻松了很多。

Image

基本上每天7点就能下班,生活也变得相对安逸。嗯…听起来,好像是很多程序员都梦寐以求的那种工作状态吧?😌

大家知道,大厂的工作节奏有多快,项目总是堆积如山,加班更是家常便饭。

那种压迫感真的很让人疲惫。不过,转到外包之后,尽管薪水缩水了一点,但工作强度减轻了,整个人都轻松了不少。

不过,很多人可能会问:“你会不会觉得自己降低了标准?会不会觉得自己没啥追求了?” 其实我觉得,“安逸”并不是一件坏事。

毕竟,工作也只是生活的一部分,能有时间去追求自己喜欢的事,何乐而不为呢?

所以,关于要不要继续找工作,怎么说呢?如果你已经觉得现在的日子挺好,那就不必急着去追求更高的薪水或更大压力的职位。

生活是自己的,做自己喜欢的事,才是最重要的。

算法题:贴纸拼词

嗨,大家好。今天咱们聊一个有点意思的算法题:贴纸拼词。

题目大致是这样:给定一个字符串 target 和一些“贴纸”,每个贴纸也是一个字符串。你需要通过使用这些贴纸的字母来拼出 target 字符串,并且每个贴纸的字母只能用一次。你要返回拼出 target 的最少贴纸数,如果无法拼出,则返回 -1。

让我们来逐步分析这个问题。

首先,看到这个题目,你可能会想,这不就像是典型的背包问题吗?但它和一般的背包问题有些不同,因为我们不是背包容量有限,而是“字母的数量有限”,也就是说我们只能使用每个字母一次。简单来说,这是一道“有字母限制的拼接问题”。但别着急,我们先不急着判断复杂度,先来理清楚怎么做。

思路一:字母计数

我们首先要做的是,把每个贴纸中的字母出现频率统计一下。你会发现,其实问题的核心就在于如何高效地利用这些贴纸中的字母。比如说,给你三个贴纸 "aab", "bc", "d" 和目标字符串 "abc", 那么显然我们需要从这些贴纸里找到能拼出 "abc" 的最少字母组合。通过统计频率,我们能够清楚地知道:a 和 b 需要被至少两次使用,而 c 需要被至少一次使用。

思路二:递归 + 剪枝

要解决这个问题,直接暴力穷举所有的贴纸组合是不可取的,因为贴纸数目可能非常大,目标字符串也可能很长。那么,怎么办呢?我们可以用递归和剪枝来优化。

递归的思路就是,每次从 target 中挑选一个字母,看看能不能用已有的贴纸来拼出这个字母,如果拼得出,就减去这个字母,继续拼接剩下的部分,直到全部字母拼出为止。如果拼不出来,就返回 -1。

但是递归带来的问题是重复计算,所以我们引入记忆化搜索(memoization)来缓存计算过的状态,避免重复计算。

具体实现时,我们可以用一个字典来记录当前 target 的字母数量,每次递归调用时,将 target 转换为一个字符串形式作为键,存储最少的贴纸数作为值。

代码实现

下面是我写的一个实现方法,使用了递归和剪枝的技巧。

from collections import Counter

def minStickers(stickers, target):
    # 将目标字符串转为字母计数
    target_count = Counter(target)

        # 将所有贴纸转为字母计数的列表
    sticker_counts = []
    for sticker in stickers:
        sticker_counts.append(Counter(sticker))

        # 使用记忆化搜索来记录已计算过的目标字母情况
    memo = {}

        def dfs(target_count):
        # 如果目标为空,说明已经拼完,返回0
        if not target_count:
            return 0

                # 如果已计算过这个目标字母组合,直接返回结果
        target_tuple = tuple(sorted(target_count.items()))
        if target_tuple in memo:
            return memo[target_tuple]

                # 初始化最小贴纸数为一个非常大的数
        res = float('inf')

                # 遍历每个贴纸
        for sticker_count in sticker_counts:
            # 如果当前贴纸不能帮助解决问题,跳过
            if target_count.most_common(1)[0][0] not in sticker_count:
                continue

                        # 减去当前贴纸能覆盖的字母
            new_target_count = target_count.copy()
            for letter in sticker_count:
                if letter in new_target_count:
                    new_target_count[letter] -= sticker_count[letter]
                    if new_target_count[letter] <= 0:
                        del new_target_count[letter]

                        # 递归求解剩下的目标字符串
            result = dfs(new_target_count)
            if result != -1:
                res = min(res, 1 + result)  # 使用1个贴纸 + 递归结果

                # 记录结果
        memo[target_tuple] = res if res != float('inf') else -1
        return memo[target_tuple]

        return dfs(target_count)

# 测试用例
stickers = ["with", "example", "science"]
target = "thehat"
print(minStickers(stickers, target))  # 输出: 3

解释

  • target_count 用来存储目标字符串中各个字母的数量。
  • sticker_counts 存储了所有贴纸的字母计数。
  • 我们使用递归 dfs 来尝试拼接 target 字符串,每次递归尝试减少目标字母的数量,直到完全拼出目标。
  • 通过 memo 字典缓存已经计算过的状态,避免重复计算。

复杂度分析

  • 时间复杂度:O(N * 2^M),其中 N 是目标字符串 target 的长度,M 是贴纸的数量。由于递归的深度受 target 中不同字母数的限制,实际表现比理论复杂度要好。
  • 空间复杂度:O(N),主要由字母计数和递归栈深度占用。

总结

这个题目看似简单,实际上考验了我们如何通过有效的计数和递归来减少计算量。记忆化搜索和剪枝的结合使用,极大地提高了算法的效率,避免了暴力递归的重复计算。对于程序员来说,这种技巧是非常实用的,尤其在处理组合问题时。

对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
🔥虎哥私藏精品 热门推荐🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。

资料包含了《IDEA视频教程》、《最全python面试题库》、《最全项目实战源码及视频》及《毕业设计系统源码》,总量高达650GB,全部免费领取。