今天看到一个很有意思的讨论,聊到程序员工资该不该统一定个标准。
有人说,既然程序员那么多,工资就定个10k得了,反正大家差不多嘛。
甚至有网友建议,程序员应该“国有化”,纳入编制,和公务员一样。
说实话,这个建议不靠谱。程序员这一行,技术差异性大得很,怎么可能统一工资?如果工资统一,那可真是对高技术人才的不公。
但说到“纳入编制”,我倒觉得挺有意思的。毕竟现在互联网行业的节奏那么快,一旦公司做不好,裁员就成了常态。
程序员这行的焦虑感也特别强——项目完结了,职位就不保了,转行又得学习新技术,竞争压力大得很。如果能像公务员那样,工作一旦有了编制,至少稳定,省心,也能让我们更安心地做技术。
我觉得,程序员如果能“纳入编制”,不但能避免频繁的裁员,还能让更多人专心做技术,而不是每天担心自己的职位会不会被外包、被裁撤。这种稳定性对于程序员来说,真的是一种很大的保障。
所以,统一工资的想法咱就算了,但“纳入编制”倒是个不错的主意。
算法题:不含连续1的非负整数
今天我们来聊一个非常经典的算法题:不含连续1的非负整数。
问题描述
题目大概是这样:给定一个整数 n
,返回从 0 到 n
中所有的非负整数,这些整数在其二进制表示中不含有连续的 1
。我们需要求的是符合这个条件的整数数量。
举个例子:
对于 n = 5
,从0
到5
的二进制数分别是:0
->0
,符合条件1
->1
,符合条件2
->10
,符合条件3
->11
,不符合,因为它有连续的1
4
->100
,符合条件5
->101
,符合条件
所以,符合条件的数有 0, 1, 2, 4, 5
,总共有 5 个数。
解题思路
这个问题看似很复杂,但其实有个挺巧妙的解法。我们可以通过动态规划来求解。
动态规划解法
我们可以用 dp[i]
来表示不超过 i
的符合条件的数字的个数。然后通过动态规划递推来解决。
首先,我们的状态转移方程可以这么理解:
dp[i] = dp[i-1] + dp[i-2]
,如果我们不考虑当前位的值的话。这个式子非常巧妙,原因是如果当前的二进制数是以 1
结尾的,它前面的数字必须符合条件,这就是递推公式的由来。
假设 n
的二进制长度是 L
,我们可以通过遍历来更新每一位的结果。
Python代码实现
def findIntegers(n: int) -> int:
# 计算n的二进制位数
bin_n = bin(n)[2:] # 转为二进制字符串,并去掉"0b"
L = len(bin_n)
# dp[i]表示长度为i的符合条件的数字的个数
dp = [0] * (L + 1)
# 初始条件:dp[0] = 1 (空串只有一种方式)
dp[0] = 1
dp[1] = 2 # 0和1的两个数
# 填充dp数组
for i in range(2, L + 1):
dp[i] = dp[i-1] + dp[i-2]
# 根据n的二进制表示进行判断
prev_bit = 0 # 前一位
result = 0
for i in range(L):
# 当前位是否是1
if bin_n[i] == '1':
result += dp[L - i - 1]
if prev_bit == 1: # 连续1
return result
prev_bit = int(bin_n[i])
result += 1 # 最后加上n本身
return result
代码解析
初始化:
我们首先计算出 n
的二进制表示长度,并初始化动态规划数组dp
,其中dp[i]
表示长度为i
的符合条件的数字的个数。
动态规划递推:
dp[0] = 1
是基础状态,表示空串只有一种情况。dp[1] = 2
表示从0
到1
,有0
和1
两个符合条件的数。对于每个 i
,我们递推公式dp[i] = dp[i-1] + dp[i-2]
。可以理解为:对于二进制数,当前位可以是0
或1
,但连续的1
需要特别处理。
根据n的二进制表示判断:
然后我们通过遍历 n
的二进制表示,检查每一位是否是1
,如果是1
,我们就加上不包含当前位的符合条件数。如果遇到连续的 1
,我们就返回结果,因为从这一点开始,后面的数一定不符合条件。
最终结果:
最后返回符合条件的数的总数。
复杂度分析
时间复杂度: O(L)
,其中L
是n
的二进制表示的长度,最多需要遍历L
次。空间复杂度: O(L)
,用来存储动态规划数组。
小结
这道题本身就是一个经典的动态规划应用,通过观察和推理,能够发现这个问题其实就是在计算一种符合特定条件的数字的个数。通过动态规划,我们避免了暴力枚举每个数字的复杂度,大大提升了效率。
对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。