1,042
社区成员




这是我参加朝闻道知识分享大赛的第 3 篇文章
小U和小R喜欢探索二进制数字的奥秘。他们想找到一个方法,将两个二进制字符串相加并以十进制的形式呈现。这个过程需要注意的是,他们的二进制串可能非常长,所以常规的方法可能无法处理大数。小U和小R希望你帮助他们设计一个算法,该算法能在保证时间复杂度不超过O(n^2)
的前提下,返回两个二进制字符串的十进制求和结果。
样例1:
输入:
binary1 = "101" ,binary2 = "110"
输出:'11'
样例2:
输入:
binary1 = "111111" ,binary2 = "10100"
输出:'83'
样例3:
输入:
binary1 = "111010101001001011" ,binary2 = "100010101001"
输出:'242420'
样例4:
输入:
binary1 = "111010101001011" ,binary2 = "10010101001"
输出:'31220'
样例5:
输入:
binary1 = "11" ,binary2 = "1"
输出:'4'
思路:二进制相加,模拟手动进位计算,然后二进制转十进制。时间复杂度O(n)。这里的测试用例不是很大,所以二进制数组转十进制我直接用一个整数保存(也可能是python的整数没有限制大小,所以能过)
def solution(binary1, binary2):
# Please write your code here
binary_array = []
size1 = len(binary1)
size2 = len(binary2)
index = -1
# 二进制数组相加:时间复杂度O(n)
while -index <= size1 or -index <= size2:
# 低位相加
add_num = 0
if -index <= size1:
add_num += int(binary1[index])
if -index <= size2:
add_num += int(binary2[index])
if -index > len(binary_array): # 如果位置不够,就开辟位置
binary_array.insert(0, 0)
if add_num + binary_array[index] > 1: # 进位
binary_array[index] = (add_num + binary_array[index]) % 2
binary_array.insert(0, 1)
else: # 不进位
binary_array[index] += add_num
index -= 1
# 二进制转十进制:时间复杂度O(n)
result = 0
index = -1
pow_num = 0
size = len(binary_array)
while -index <= size:
result += binary_array[index] * pow(2, pow_num)
pow_num += 1
index -= 1
return str(result)
上述代码思想是通用的,改写为其他语言也很简单,不过python的数据类型不限制大小,所以我向应该能用内置的语法特性来做:
def solution(binary1, binary2):
# Please write your code here
# 将二进制字符串转换为十进制整数并相加
decimal_sum = int(binary1, 2) + int(binary2, 2)
# 将十进制结果转换为字符串返回
return str(decimal_sum)
时间复杂度:O(n)
,主要在于 int
函数的转换复杂度,适用于较长的二进制字符串。
在一个超市里,有一个包含 n 个格子的货物架,每个格子中放有一种商品,商品用小写字母 a
到 z
表示。当顾客进入超市时,他们会依次从第一个格子查找到第 n 个格子,寻找自己想要购买的商品。如果在某个格子中找到该商品,顾客就会购买它并离开;如果中途遇到一个空格子,或查找完所有格子还没有找到想要的商品,顾客也会离开。
作为超市管理员,你可以在顾客到来之前重新调整商品的顺序,以便尽可能多地出售商品。当第一个顾客进入后,商品位置不能再调整。你需要计算在最优调整下,最多可以卖出多少件商品。输入变量说明:
n
:货物架的格子数
m
:顾客想要购买的商品种类数
s
:货物架上商品的初始顺序
c
:顾客想要购买的商品种类
样例1:
输入:
n = 3 ,m = 4 ,s = "abc" ,c = "abcd"
输出:3
样例2:
输入:
n = 4 ,m = 2 ,s = "abbc" ,c = "bb"
输出:2
样例3:
输入:
n = 5 ,m = 4 ,s = "bcdea" ,c = "abcd"
输出:4
思路:很简单,没有顺序,直接数数量即可,时间复杂度O(n)
def solution(n: int, m: int, s: str, c: str) -> int:
# write code here
goods = {}
needs = {}
for i in s:
goods[i] = goods.get(i, 0) + 1
for i in c:
needs[i] = needs.get(i, 0) + 1
num = 0
for k in needs:
num += min(goods.get(k, 0), needs.get(k, 0))
return num
小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values
中,其中 values[i]
表示第 i
个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i
表示。
一对景点 (i < j)
的观光组合得分为 values[i] + values[j] + i - j
,也就是两者评分之和减去它们之间的距离。
小R想知道,在哪种情况下能够获得观光景点组合的最高得分。
样例1:
输入:
values = [8, 3, 5, 5, 6]
输出:11
样例2:
输入:
values = [10, 4, 8, 7]
输出:16
样例3:
输入:
values = [1, 2, 3, 4, 5]
输出:8
思路一:两次循环,两两组合找最大。时间复杂度O(n^2)
def solution(values: list) -> int:
# write code here
max_value = 0
n = len(values)
for x in range(n - 1):
for y in range(x + 1, n):
max_value = max(max_value, values[x] + values[y] + x - y)
return max_value # Placeholder return
思路二:
给定的组合得分为:
我们可以将其重写为:
设定:
于是得分可以转化为:
在这种情况下,我们只需要遍历 values
数组一次,计算出所有的 A[i]
和 B[j]
,然后在遍历中更新最大得分。
时间复杂度O(n)
def solution(values: list) -> int:
# write code here
n = len(values)
max_score = 0
maxA = values[0] + 0 # A[0] = values[0] + 0
for j in range(1, n):
# 计算 B[j] = values[j] - j
currentB = values[j] - j
# 计算得分
max_score = max(max_score, maxA + currentB)
# 更新 maxA
maxA = max(maxA, values[j] + j)
return max_score
小C希望构造一个包含n个元素的数组,且满足以下条件:
数组中的所有元素两两不同。
数组所有元素的最大公约数为 k
。
数组元素之和尽可能小。
任务是输出该数组元素之和的最小值。
样例1:
输入:
n = 3 ,k = 1
输出:6
样例2:
输入:
n = 2 ,k = 2
输出:6
样例3:
输入:
n = 4 ,k = 3
输出:30
思路:元素要尽量的小,那就从最小的开始即可
def solution(n: int, k: int) -> int:
# write code here
return (k + n * k) * n // 2
小U和小R有两个字符串,分别是S和T,现在小U需要通过对SS进行若干次操作,使其变成T的一个前缀。操作可以是修改S的某一个字符,或者删除S末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让S变成T的前缀。
样例1:
输入:
S = "aba", T = "abb"
输出:1
样例2:
输入:
S = "abcd", T = "efg"
输出:4
样例3:
输入:
S = "xyz", T = "xy"
输出:1
样例4:
输入:
S = "hello", T = "helloworld"
输出:0
样例5:
输入:
S = "same", T = "same"
输出:0
思路:很简单,从前往后比较,不同则换,比完后还剩的就要删除
def solution(S: str, T: str) -> int:
# write code here
n = min(len(S), len(T))
result = 0
for i in range(n):
if S[i] != T[i]:
result += 1
if len(S) > len(T):
result += len(S) - len(T)
return result
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N
天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K
份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
样例1:
输入:
n = 5 ,k = 2 ,data = [1, 2, 3, 3, 2]
输出:9
样例2:
输入:
n = 6 ,k = 3 ,data = [4, 1, 5, 2, 1, 3]
输出:9
样例3:
输入:
n = 4 ,k = 1 ,data = [3, 2, 4, 1]
输出:10
思想:贪心,尽量拿价格小的。
我的想法是:
遍历到后面时,前面的价格应该也要算进来,也就是说走到这个站点,购买的食物应该是从该站点开始往前k个站点最小价格的那一个,因为最多只能携带k份食物,所以遍历到该站点时,那前面的第k+1个站点就需要从所选价格表中删除。
每次插入时都要快速的选取最小值,这就很容易想到一个数据结构——小顶堆(最小堆)。这里使用堆有个问题,就是删除的结点不一定是堆顶,因为不知道前面第k+1个站点价格大小,所以删除结点只能对列表删除结点,然后构建堆,时间复杂度O(n^2*log(n)),不如用一个min_value来记录最小值,复杂度为O(n^2)
def solution(n, k, data):
# Edit your code here
min_money = 0
ready = []
min_value = 0
for i in data:
# 当前站点加入ready
ready.append(i)
# 如果ready大于k,就将最先进入的站点价格删除
if len(ready) > k:
ready.pop(0)
# 找到最小值(这一步的时间复杂度应该为O(n))。如果在这里建堆就没必要了,时间复杂度可能提升至O(n*log()n)
min_value = min(ready)
min_money += min_value
return min_money