2019阿里实习试题:数字串转换的最少步骤(python3)

本文探讨了一个有趣的问题:如何通过加减数字及交换位置等操作,将一个数字串转变成另一个数字串,旨在寻找最少的操作次数。作者使用Python实现了这一算法,并分享了其思考过程与解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定两个长度为 n ( 0 < n <= 8 ) 的 数字串 (由1到9构成) ,我们希望对第一个数字串做一系列如下操作:

1、将数字串的某一位加1

2、将数字串的某一位减1

3、交换数字串中任意两个数字的位置

最终使得第一个数字串变成第二个数字串, 请问最少需要多少操作。

--------------------

这个我试着用矩阵的方式实现:

A=(a1,a2,a3,a4,a5,a6,a7,a8)

B=(b1,b2,b3,b4,b5,b6,b7,b8)

  1. 不交换的话,操作数就应该是sum(|a1-b1|,|a2-b2|,...,|a8-b8|)
  2. 假设进行了1、2位的交换,那么操作数就会变成sum(|a1-b2|,|a2-b1|,|a3-b3|,...,|a8-b8|)这个和矩阵就有点像了,假设一个cij=|ai-bj|,那就相当于是sum(c12,c21,c33,c44,...,c88)。
    c=(c11,c12,c13,...,c18)
        (c21,c22,c23,...,c28)
        (.....               ....      )
        (c81,c82,c83,...,c88)
    于是应该构造一个8×8矩阵(cij),直接取(cij)中不同行同列的一组元素求和,就是(不考虑交换前提下的)操作数了。
    如果不考虑交换增加的操作数,直接在每行遍历1~8的不重复排列,对矩阵进行求和就可以了。
  3. 现在还要考虑交换的操作,2中结果里,同样的操作数下,应该选交换次数少的。交换次数少,其实意味着我们取了更多矩阵对角线上的数字cii,并且每多取一个对角线上的cii,就意味着少一次操作数。
    所以,我选择直接给对角线上的cii减1,表示选择了对角线上的cii意味着少一次操作次数。
  4. 这个时候还会出现一个问题,举例来说,如果是一个2×2矩阵,两个数字都在对角线上换成两个数字都不在对角线上只需要一次交换操作,而3中却把操作数-2了;在3×3,4×4,更大的矩阵下也出现了相似的问题。
    事实上,多减了操作数的原因是因为最后一次交换只交换一次,却可以让两个数字同时出现在对角线上,所以会导致多减了一次操作数。因此在最后要判断是否所有的数字都在对角线上,若是如此,那最后的操作数应该+1。

语言是用python3实现的,半路出家实在是不会其他语言,很多习惯都不太好,希望能得到站里大神的指点

from itertools import combinations, permutations
import math

#将int转换为list
def zh(a):
    j = 0
    for n in range(len(a)):
        j += 10**n*a[len(a)-n-1]
    return j
#将list转换为int
def anzh(a):
    j = math.floor(math.log(a,10))+1
    p = [0]*j
    for i in range(j):
        p[i-1] = math.floor(a/(10**(j-i)))
        a = a - p[i-1]*10**(j-i)
    p[-1] = a
    return p

#输入位数一致的a,b整数
a=37393412
b=18326412
print("a=",a)
print("b=",b)
#将a,b转换为list格式
a=anzh(a)
b=anzh(b)
#转化后应该是如下形式
#a=[3,7,3,9,3,4,1,2]
#b=[1,8,3,2,6,4,1,2]
#将x表示为a,b各数相减结果的形式(其实是一个1×64的list,而不是真正的矩阵)
x=[0]*len(a)*len(b)
m=[0]*len(a)
for i in range(len(a)):
    m[i] = i+1
    for j in range(len(b)):
        x[i*len(a)+j] = abs(a[i]-b[j])
        if i == j:
            x[i*len(a)+j] += -1
#构造矩阵,利用排列组合得到的不重复1~8的排列
L = 999
for each in list(permutations(m, len(m))):
    #print(each)
    LZ = 0
    NN = 0
    for F in each:
        LZ += x[int(F)+len(m)*NN-1]    #-1表示不交换的时候相对少计算一次步骤
        NN += 1
    if LZ < L and each != m:
        n = each
        L = LZ
        L0 = LZ
    elif LZ+1 < L and each == m:
        n = each
        L = LZ
        L0 = LZ

#计算交换方法和交换次数
a1 = [0]*len(a)
tims = 0 
a2 = [0]*len(a)
for i in range(len(a)):
    a1[i] = a[n[i]-1]
    a2[i] = abs(a1[i]-b[i])
    if n[i] != i+1:
        tims += 1

print("交换位置后")
print('a1=',zh(a1))
print("需交换次数")
print("n=",tims)
print("各位数上的差异为")
print("a1-b=",zh(a2))
print("合计次数为")
print("n0=",sum(a2)+tims)
题目非常好玩,可能也是因为以前没刷过题所以觉得有意思…

自学Python之后第一次做这种实机题,还没弄明白啥是sys.stdin就错过时间了,太尴尬了:(

希望毕业正式校招的时候能真的学到点东西



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值