python小练(2)

130 阅读8分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情


1.

Tom听说朋友新开了一个柠檬水摊,每一杯柠檬水的售价为 5 元。 顾客排队购买产品,(按账单 bills 支付的顺序)一次购买一杯。 每位顾客只买一杯柠檬水,然后向老板付 5 元、10 元或 20 元。老板必须给每个顾客正确找零,也就是说净交易是每位顾客向老板支付 5 元。 但是因为是第一次做生意,一开始老板手头没有任何零钱,这就导致可能无法给顾客找零,得到差评。Tom的朋友想请你编写程序,判断按照账单是否能正确找零。

输入格式:

给定一个账单bills,列表形式。

输出格式:

如果你能给每位顾客正确找零,返回 True ,否则返回 False 。

输入样例:

[5,5,5,10,20]

输出样例:

True

样例说明

3 位顾客那里,我们按顺序收取 35 元的钞票。
第 4 位顾客那里,我们收取一张 10 元的钞票,并返还 5 元。
第 5 位顾客那里,我们找还一张 10 元的钞票和一张 5 元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 True

代码长度限制 16 KB

时间限制 400 ms

内存限制 64 MB

分析🤔:一道很简单的题目,只需要判断列表里面的元素即可。但是需要注意将每一 种情况都考虑在内。

def change(bills):
  if bills[0]!=5:
    return False
  else:
    bills2 = bills[1:]
    five_money=1
    ten_money=0
    for i in bills2:
      if i == 5:
        five_money += 1
      elif i == 10:
        five_money -= 1
        ten_money += 1
      else:
        if ten_money >= 1:
          ten_money -= 1
          five_money -= 1
        else:
          five_money -= 3
        if five_money < 0 or ten_money < 0:
          return False
    return True
if __name__ == '__main__':
  bills=list(map(int,eval(input())))
  canchange=change(bills)
  if canchange==False:
    print('False',end="")
  else:
    print("True",end="")

2.

Tom是个小菜菜,虽然有emoji大佬帮忙上强度,但是Tom觉得必须提高自己,来帮助emoji大佬给大家更好的训练,于是Tom去找kekao师傅"拜师学艺"。
恰巧碰到kekao师傅在串手链。哦,原来是kekao师傅觉得买的手链没有自己做的更有心意,于是他买了一堆珠子准备自己做一个,但他是一个重度选择困难症患者,于是Tom提议,至少保证手链一半以上的位置有珠子。但是Tom和kekao不知道有多少种串法,想请你帮忙计算一下。对于一个长度为n的绳子来说,每一个位置可以放上一个珠子,有珠子表示为1,没珠子表示为0。

输入格式:

输入一个正整数n (1≤n≤18)

输出格式:

输出每一个串,每个串占一行 (从小到大输出)串的长度是n。
\最后一行输出串法的数量。

输入样例:

在这里给出一组输入。例如:

3

输出样例:

在这里给出相应的输出。例如:

011
101
110
111
amount = 4

样例说明:

对于长度为3的串,所有串法是:
000
001
010
011
100
101
110
111
但是要保证每一个手链的珠子数量大于串长度的一半,于是得到上述答案。

输入样例:

在这里给出一组输入。例如:

6

输出样例:

在这里给出相应的输出。例如:

001111
010111
011011
011101
011110
011111
100111
101011
101101
101110
101111
110011
110101
110110
110111
111001
111010
111011
111100
111101
111110
111111
amount = 22

代码长度限制 16 KB Python (python3)

时间限制 2000 ms

内存限制 64 MB

时间限制 1000 ms

内存限制 64 MB

分析🤔:通过题意我们可以知道对于长度为n的绳子,01串的串法数量是2^n。而我们需要将其排序组合,不难发现对于长度为n,数值最小的串是n个0,最大的是n个1,这与二进制非常相似。事实证明,对于长度为n的01串,如果我们将其看成二进制,那么它转化为十进制的数值范围是0 ~ 2^n -1。所以问题就转化为求0~ 2^n-1的二进制,并判断01串中0与1的数量即可。但是我们知道2^n存在指数爆炸,所以要考虑时间问题,此处我们采用按位与运算,而不是内置bin()函数,可以大幅降低时间。

n = int(input())
amo = 0
def f(r):
  global amo
  st = ""
  while (r):
    # print(r&1,end=" ")
    st += str((r & 1))
    r >>= 1
  while (len(st) < n):
    st += "0"
  if st.count("1") > len(st)/2:
    print(st[::-1])
    amo += 1
temp = 2**n
for i in range(0,temp):
  f(i)
print(f"amount = {amo}")

3.

将1……N的数字按照升序排列,在下一行按照降序排列。

1      2     3        ... ...    N-1     N
N    N-1    N-2     ... ...       2       1

kekao师傅问Alan:按照上述排列,对于给定的n,有多少个素数对?

Alan想请你帮忙编写程序,帮助求解一下。

输入格式:

在一行中给定一个整数N (1≤N≤10^4)

输出格式:

输出一个整数表示素数对的个数

输入样例:

在这里给出一组输入。例如:

3

输出样例:

在这里给出相应的输出。例如:

1
样例说明
1   2   3
3   2   1
素数对是:
| 2 |
| 2 |

输入样例:

在这里给出一组输入。例如:

7

输出样例:

在这里给出相应的输出。例如:

2

代码长度限制 16 KB

时间限制 400 ms

内存限制 64 MB

分析🤔: 一道简单题,只需要注意位置即可。 对于上一列的第i个,在下一列与其成对的存在是n+1-i。

def prime(num):
  if num == 1:
    return 0
  elif num == 2:
    return 1
7-5 不同进制的A+B
本题主要是熟悉各进制数字间的运算,可以将其都转化为我们熟悉的十进制运
算,再输出二进制结果。
7-6 Alan的小假期
由题意得,即求得1-n中与n互质的数的个数。但是这里不采用force方法,使用欧
拉函数和线性筛的优化。
欧拉函数和线性筛
  else:
    for i in range(2,int(num**0.5)+2):
      if num%i == 0:
        return 0
    return 1
n = int(input())
res = 0
if n < 2:
  res = 0
else:
  for i in range(2,n+1):
    if prime(i) and prime(n+1-i):
      res += 1
print(res)

4.

我们将整数 x 的 权重 定义为按照下述规则将 x 变成 1 所需要的步数:

  • 如果 x 是偶数,那么 x = x / 2
  • 如果 x 是奇数,那么 x = 3 * x + 1 比方说,x=3 的权重为 7 。因为 3 需要 7 步变成 1 (3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)。

Alan现在给你三个整数 l, r 和 k 。你的任务是将区间 [l, r] 之间的整数按照它们的权重 升序排序 ,如果大于等于 2 个整数有 相同 的权重,那么按照数字自身的数值 升序排序 。

Alan想请你找出区间 [l, r] 之间的整数按权重排序后的第 k 个数。

注意,题目保证对于任意整数 x (l <= x <= r) ,它变成 1 所需要的步数是一个 32 位有符号整数。

输入格式:

第一行两个整数 l, r 。1≤ l ≤ r≤ 1000

第二行一个整数 k

输出格式:

输出一个整数,区间 [l, r] 之间的整数按权重排序后的第 k 个数。

输入样例:

12 15
2

输出样例:

13

样例说明:

12 的权重为 912 --> 6 --> 3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 113 的权重为 9
14 的权重为 17
15 的权重为 17
区间内的数按权重排序以后的结果为 [12,13,14,15] 。
对于 k = 2 ,答案是第二个整数也就是 13 。
注意,1213 有相同的权重,所以我们按照它们本身升序排序。1415 同理。

输入样例:

1 1
1

输出样例

1

输入样例:

1 1000
777

输出样例:

570

代码长度限制 16 KB

时间限制 100 ms

内存限制 64 MB

分析🤔:对于x的权重求值,我们可以采用递归的方式,构造如下递归式:

image.png

对于每一个数字,依据其权重排序,我们可以使用字典,以数字作为键key,权重作为值 value,进行排序。
在递归过程中我们可以发现,当我们求解 f(3) 的时候,会调用到 f(10),在求 f(20) 的 时候也会调用 f(10) ,同样的,如果单纯递归计算权重的话,会存在很多重复计算,我们可以 用记忆化的方式来加速这个过程,即「先查表,再计算」和「先记忆,再返回」。我们可以用一 个哈希映射作为这里的记忆化的「表」,这样保证每个元素的权值只被计算 1 次。在[1,1000] 中所有 x 求 f(x) 的值的过程中,只可能出现 2228 种 x,于是效率就会大大提高。代码如 下:

def getNum(l, r, k):
    d_index = {1: 0}
    
    def getF(x):
        if x in d_index:
            return d_index[x]
        d_index[x] = (getF(x * 3 + 1) if x % 2 == 1 else getF(x // 2)) + 1
            return d_index[x]
        arr = list(range(l, r + 1))
        arr.sort(key=lambda x: (getF(x), x))
            return arr[k - 1]
if __name__ == "__main__":
    l, r = map(int, input().split())
    k = int(input())
    print(getNum(l, r, k))

时间复杂度:平均情况下比较的次数为 nlogn