编程练习 【0】(08-01)

1. 

题目描述

今天上课,老师教了小易怎么计算加法和乘法,乘法的优先级大于加法,但是如果一个运算加了括号,那么它的优先级是最高的。例如:

1+2*3=7
1*(2+3)=5
1*2*3=6
(1+2)*3=9

现在小易希望你帮他计算给定3个数a,b,c,在它们中间添加"+", "*", "(", ")"符号,能够获得的最大值。

输入描述:

一行三个数a,b,c (1 <= a, b, c <= 10)

输出描述:

能够获得的最大值

示例1

输入

复制

1 2 3

输出

复制

9

答案:  

# 直接将所有情况进行列举,然后打印出最大值。
if __name__ == '__main__':
    a, b, c = list(map(int, input().strip().split()))
    p = [a + b + c, a * b + c, a * (b + c), b+a*c, (b+a)*c, a + b * c, (a + b) * c, a * b * c]
    print(max(p))

2.   

题目描述

小易有一些立方体,每个立方体的边长为1,他用这些立方体搭了一些塔。

现在小易定义:这些塔的不稳定值为它们之中最高的塔与最低的塔的高度差。

小易想让这些塔尽量稳定,所以他进行了如下操作:每次从某座塔上取下一块立方体,并把它放到另一座塔上。

注意,小易不会把立方体放到它原本的那座塔上,因为他认为这样毫无意义。

现在小易想要知道,他进行了不超过k次操作之后,不稳定值最小是多少。

输入描述:

第一行两个数n,k (1 <= n <= 100, 0 <= k <= 1000)表示塔的数量以及最多操作的次数。
第二行n个数,ai(1 <= ai <= 104)表示第i座塔的初始高度。

输出描述:

第一行两个数s, m,表示最小的不稳定值和操作次数(m <= k)
接下来m行,每行两个数x,y表示从第x座塔上取下一块立方体放到第y座塔上。

示例1

输入

复制

3 2
5 8 5

输出

复制

0 2
2 1
2 3

解答:  

#  这道题的思想直接是每次的转移都是最高塔到最低塔。
import sys
if __name__ == "__main__":
    lines =  sys.stdin.readlines()
    n,k = list(map(int,lines[0].strip().split(" ")))
    A = list(map(int,lines[1].strip().split(" ")))
    # 结果记录list
    res_list = []
    num_step = 0
    for i in range(k):
        if max(A) == min(A):
            break
        num_step += 1
        max_index = A.index(max(A))
        min_index = A.index(min(A))
        res_list.append([max_index+1, min_index+1])
        A[max_index] -= 1
        A[min_index] += 1
        
    print("%d %d" % (max(A)-min(A), num_step))
    for i in range(len(res_list)):
        print("%d %d" % (res_list[i][0], res_list[i][1]))

3.  

题目描述

小易在学校中学习了关于字符串的理论, 于是他基于此完成了一个字典的项目。

小易的这个字典很奇特, 字典内的每个单词都包含n个'a'和m个'z', 并且所有单词按照字典序排列。

小易现在希望你能帮他找出第k个单词是什么。

输入描述:

 

输入包括一行三个整数n, m, k(1 <= n, m <= 100, 1 <= k <= 109), 以空格分割。

输出描述:

输出第k个字典中的字符串,如果无解,输出-1。

示例1

输入

复制

2 2 6

输出

复制

zzaa

说明

字典中的字符串依次为aazz azaz azza zaaz zaza zzaa

解题思路分析: 

排列组合,n个'a'和m个'z',只能组成$C_{n+m}^n$,记为count(n+m,n) 个单词。

思路:

  1. 假设第一个字符为a,则剩下n-1个'a'和m个'z'组成的子序列只能构成count(n-1+m,n-1)个单词,且是字典中前count(n-1+m,n-1)个单词。
  2. 比较k和count(n-1+m,n-1),若k小,说明k是前count(n-1+m,n-1)个单词,则第一个字符必为'a'。子问题化为在子序列(n-1个'a'和m个'z')找到第k个单词
  3. 若k大,则说明第一个字符必为'z',单词是以'z'开头的单词中的第k-count(n-1+m,n-1)个。子问题化为在子序列(n个'a'和m-1个'z')找到第k-count(n+m-1,m-1)个单词。

eg:n=2,m=2,k=5

  1. 假设第一个字符为a,则剩下1个a,2个z只能构成3个单词,且是字典中前3个单词(aamm,amam,amma)
  2. k>3,则第一个字符必为z。原问题化为在n=2,m=1,k=2,即在剩下2个a,1个z中找到第2个单词
# way second  False method  没有考虑所有的情况。
def C(n, m):
    ret = 1
    for i in range(n + 1, n + m + 1):
        ret *= I
    for i in range(1, m + 1):
        ret //= I
    return ret
 if __name__ == "__main__":
    n, m, k = map(int, input().strip().split(' '))
    ans = ""
    if C(n, m) < k:
        ans += '-1'
    else:
        while n and m:
            temp = C(n - 1, m)
            if temp < k:
                k -= temp
                ans += 'z'
                m -= 1
            else:
                ans += 'a'
                n -= 1
        ans += 'a' * n  #这应该是m=0的情况,应该单独while说明
        ans += 'z' * m  #这应该是n=0的情况,应该单独while说明
    print(ans)

# way third  True method
def func(k):
    re=1
    for i in range(1,k+1):
        re*=i
    return re
n,m,k=  [int(i) for i in input().split()]
re=''
if k>func(n+m)/func(n)/func(m):
    print(-1)
    exit()
while n!=0 and m!=0:
    half=func(n+m-1)/func(n-1)/func(m)
    if k>half:
        k-=half
        re+='z'
        m-=1
    else:
        re+='a'
        n-=1
while n!=0:
    n-=1
    re+='a'
while m!=0:
    m-=1
    re+='z'
print(re)

4.  

题目描述

小明在越南旅游,参加了当地的娱乐活动。小明运气很好,拿到了大奖, 到了最后的拿奖金环节。小明发现桌子上放着一列红包,每个红包上写着奖金数额。

现在主持人给要求小明在这一列红包之间“切”2刀,将这一列红包“切”成3组,并且第一组的奖金之和等于最后一组奖金和(允许任意一组的红包集合是空)。最终第一组红包的奖金之和就是小明能拿到的总奖金。小明想知道最多能拿到的奖金是多少,你能帮他算算吗。

 

举例解释:桌子上放了红包  1, 2, 3, 4, 7, 10。小明在“4,7”之间、“7,10” 之间各切一刀,将红包分成3组 [1, 2, 3, 4]   [7]   [10],其中第一组奖金之和=第三组奖金之和=10,所以小明可以拿到10越南盾。

输入描述:

第一行包含一个正整数n,(1<=n<= 200 000),表示有多少个红包。

第二行包含n个正整数d[i],表示每个红包包含的奖金数额。其中1<= d[i] <= 1000 000 000

输出描述:

小明可以拿到的总奖金

示例1

输入

复制

5
1 3 1 1 4

输出

复制

5

说明

[1,3,1]  [ ]   [1,4] ,其中第一组奖金和是5,等于第三组奖金和。所以小明可以拿到5越南盾

示例2

输入

复制

5
1 3 2 1 4

输出

复制

4

说明

[1,3]   [2,1]  [4],小明可以拿到4越南盾

示例3

输入

复制

3
4 1 2

输出

复制

0

说明

[ ]  [4, 1, 2] [ ] ,小明没办法,为了保证第一组第三组相等,只能都分成空的。所以小明只能拿到0越南盾。

思路:

/*

从左右两端共进。

若当前左端大于右端,右端前进一个。

若当前左端小于右端,左端前进一个。

如当前左端等于右端,左右两端都前进一个。

然后再判断左右两端和是否相等,若相等则更新答案。

左端坐标大于右端坐标时,跳出循环。

O(n)。

def redPacket(n, nums):
    left, right = -1, n
    sum_left, sum_right = 0, 0
    res = 0
    while left < right:
        if sum_left == sum_right:
            res = sum_left
            left, right = left+1, right-1
            sum_left += nums[left]
            sum_right += nums[right]
        elif sum_left < sum_right:
            left += 1
            sum_left += nums[left]
        else:
            right -= 1
            sum_right += nums[right]
    return res
if __name__ == '__main__':
    n = int(input())
    nums = list(map(int, input().split()))
    print(redPacket(n, nums))

5. 将满二叉树转换为求和树

题目描述

给满出二叉树,编写算法将其转化为求和树

什么是求和树:二叉树的求和树, 是一颗同样结构的二叉树,其树中的每个节点将包含原始树中的左子树和右子树的和。

二叉树:
                  10
               /      \
             -2        6
           /   \      /  \ 
          8    -4    7    5

求和树:
                 20(4-2+12+6)
               /      \
           4(8-4)      12(7+5)
            /   \      /  \ 
          0      0    0    0
 

二叉树给出前序和中序输入,求和树要求中序输出;

所有处理数据不会大于int;

 

输入描述:

2行整数,第1行表示二叉树的前序遍历,第2行表示二叉树的中序遍历,以空格分割

输出描述:

1行整数,表示求和树的中序遍历,以空格分割

示例1

输入

复制

10 -2 8 -4 6 7 5
8 -2 -4 10 7 6 5

输出

复制

0 4 0 20 0 12 0
def func(pre,inorder):
    if(len(pre)==1):
        return [0]
    elif(len(pre)==0):
        return []
    ind = inorder.index(pre[0])
    return func(pre[1:(ind+1)],inorder[0:ind]) + [sum(inorder[:])-inorder[ind]]+func(pre[(ind+1):],inorder[(ind+1):])  
 # 递归算法求解
pre=list(map(int,input().strip().split()))      # 前序遍历结果
inorder=list(map(int,input().strip().split()))  # 中序遍历结果
ans = func(pre,inorder)
print(' '.join(map(str,ans)))

6.  搭积木

题目描述

小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?

定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.

假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。

输入描述:

第一行为积木的总个数 N

之后一共有N行,分别对应于每一个积木的宽W和长L

输出描述:

输出总共可以搭的层数

示例1

输入

复制

5
2 2
2 4
3 3
2 5
4 5

输出

复制

4

分析思路: 针对现有的(w,l)序列进行宽的升序排列,然后基于此顺序抽取L的非递减序列。

import bisect
def upper(arr, num):
    index = bisect.bisect(arr, num)
    arr[index] = num 

n = int(input())
arr = []
for _ in range(n):
    w, l =  map(int, input().strip().split(' '))
    arr.append((w,l))
arr.sort(key=lambda x:x[0]) # 首先针对N组数据进行对宽的升序;再在此基础上寻找长的非递减序列
L = []
for w,l in arr:
    if not L:
        L.append(l)
    elif l >= L[-1]:
        L.append(l)
    else:
        upper(L, l)
print(len(L))

7.  魔法深渊 (跳台阶问题)

题目描述

前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。

由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。

 

已知深渊有N层台阶构成(1 <= N <= 1000),并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、....),请你编程告诉月神,月神有多少种方法爬出深渊

输入描述:

输入共有M行,(1<=M<=1000)

第一行输入一个数M表示有多少组测试数据,

接着有M行,每一行都输入一个N表示深渊的台阶数

输出描述:

输出可能的爬出深渊的方式

示例1

输入

复制

4
1
2
3
4

输出

复制

1
2
3
6

分析

"""

台阶问题考虑动态规划

每次仅可往上爬2的整数次幂个台阶(1、2、4、....)

当前台阶方法数 = 所有一次可到达当前台阶方法数的和

dp[n] = dp[n-1]+dp[n-2]+dp[n-4]+... ( n-t>=0,dp[0]=1 )

"""

if __name__ == '__main__': 
    m = int(input()) # m个测试数据
    stairs = []
    for i in range(0,m):
        stairs.append(int(input()))
    n = max(stairs) #  比N的最大值1000时用1001的时间消耗更小。
    dp = [0] * 1001
    dp[0] = 1
    MOD = 10**9 +3
    for i in range(1, n+1):
        t = 1
        while t <= i:
            dp[i] += dp[i-t]  # dp[n] = dp[n-1]+dp[n-2]+dp[n-4]+... ( n-t>=0,dp[0]=1 )
            dp[i] %= MOD  # 为了防止移除,需要对mod进行取模运算
            t *= 2
    for i in stairs:
        print(dp[i])

8. 善变的同伴 

题目描述

又到了吃午饭的时间,你和你的同伴刚刚研发出了最新的GSS-483型自动打饭机器人,现在你们正在对机器人进行功能测试。

为了简化问题,我们假设午饭一共有N个菜,对于第i个菜,你和你的同伴对其定义了一个好吃程度(或难吃程度,如果是负数的话……)A[i],

由于一些技(经)术(费)限制,机器人一次只能接受一个指令:两个数L, R——表示机器人将会去打第L~R一共R-L+1个菜。

本着不浪费的原则,你们决定机器人打上来的菜,含着泪也要都吃完,于是你们希望机器人打的菜的好吃程度之和最大

然而,你善变的同伴希望对机器人进行多次测试(实际上可能是为了多吃到好吃的菜),他想知道机器人打M次菜能达到的最大的好吃程度之和

当然,打过一次的菜是不能再打的,而且你也可以对机器人输入-1, -1,表示一个菜也不打

输入描述:

第一行:N, M

第二行:A[1], A[2], ..., A[N]

输出描述:

一个数字S,表示M次打菜的最大好吃程度之和

示例1

输入

复制

7 2
1 2 3 -2 3 -10 3

输出

复制

10

说明

[1 2 3 -2 3] -10 [3]

示例2

输入

复制

7 4
1 2 3 -2 3 -10 3

输出

复制

12

说明

[1 2 3] -2 [3] -10 [3]

第四次给机器人-1, -1的指令

备注:

N <= 10^5 = 100000

|A[i]| <= 10^4 = 10000

10%数据M = 1

50%数据M <= 2

80%数据M <= 100

100%数据M <= 10^4 = 10000

思路: 

1、先把整个数组改成正负交错的数组,去掉首尾的负数(相邻的正数合并成一个正数,负数合并成一个负数)

2、如果正数个数<=M,输出所有的正数之和

3、如果正数个数>M,将数组中[正负正]合并,该负数为数组中负数的最大值并且三者之和>三者最大值

4、直到3不满足或者正数个数<=M,输出最大的M个正数之和

N, M = list(map(int, input().split()))
ns = list(map(int, input().split()))
new_ns = [ns[0]]
for i in ns[1:]:
    if i == 0:
        continue
    if (new_ns[-1] > 0) == (i > 0):
        new_ns[-1] += i
    else:
        new_ns.append(i)
# 去掉首尾的负数块
if len(new_ns) >= 1 and new_ns[0] < 0:
    new_ns.pop(0)
if len(new_ns) >= 1 and new_ns[-1] < 0:
    new_ns.pop(-1)
# 按奇偶划分奇数和偶数块
ns_pos = new_ns[0::2]
ns_neg = new_ns[1::2]
cnt_pos = len(ns_pos)
# 如果 M 的值小于正数块的数量则进行合并
updated = True
while updated and M < cnt_pos:
    """"""
    updated = False
    mx_i = 0
    # mx = max(ns_pos[mx_i] + ns_pos[mx_i+1] + ns_neg[mx_i], ns_pos[mx_i], ns_pos[mx_i])
    mx = float("-inf")
    for i in range(len(ns_neg)):
        tmp = ns_pos[i] + ns_pos[i+1] + ns_neg[i]
        if tmp < max(ns_pos[i], ns_pos[i+1]):  # 如果合并后减小则不合并
            continue
        if tmp > mx:
            updated = True
            mx = tmp
            mx_i = i
    if updated:
        # 更新合并后的数组
        ns_neg.pop(mx_i)
        ns_pos[mx_i] = mx
        ns_pos.pop(mx_i+1)
        cnt_pos -= 1
ns_pos.sort(reverse=True)
print(sum(ns_pos[:M]))
#  不正确的解答,时间超时。

9.  字符串归一

题目描述

 

通过键盘输入一串小写字母(a~z)组成的字符串。

请编写一个字符串归一化程序,统计字符串中相同字符出现的次数,并按字典序输出字符及其出现次数。

例如字符串"babcc"归一化后为"a1b2c2"

 

 

 

输入描述:

每个测试用例每行为一个字符串,以'\n'结尾,例如cccddecca

输出描述:

输出压缩后的字符串ac5d2e

示例1

输入

复制

dabcab

输出

复制

a2b2c1d1

分析:注意使用collections下的counter类,更有效率

from collections import Counter
char_list = input()
char_dict = Counter(char_list)
res = ''
for key in sorted(char_dict.keys()):
    res += key
    res += str(char_dict[key])
print(res)

10.  字符串排序

题目描述

 

 

月神拿到一个新的数据集,其中每个样本都是一个字符串(长度小于100),样本的的后六位是纯数字,月神需要将所有样本的后六位数字提出来,转换成数字,并排序输出。

 

月神要实现这样一个很简单的功能确没有时间,作为好朋友的你,一定能解决月神的烦恼,对吧。

输入描述:

每个测试用例的第一行是一个正整数M(1<=M<=100),表示数据集的样本数目

接下来输入M行,每行是数据集的一个样本,每个样本均是字符串,且后六位是数字字符。

输出描述:

对每个数据集,输出所有样本的后六位构成的数字排序后的结果(每行输出一个样本的结果)

示例1

输入

复制

4
abc123455
boyxx213456
cba312456
cdwxa654321

输出

复制

123455
213456
312456
654321

分析: 注意最后输出的排序是M个数字进行整体的排序。

n = int(input())
res = []
for i in range(n):
    arr = input()
    arr = arr[-6:]
    res.append(int(arr))
res.sort()
for a in res:
    print(a)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值