Algorithm 算法帮助:给定一个num,它最终可以是1吗

Algorithm 算法帮助:给定一个num,它最终可以是1吗,algorithm,Algorithm,给定一个数字,您可以将其或其相邻部分除以2,或将其或其连续部分乘以2。这个数字最终会是1吗 例如:13 3 is a part of 13, first we take 3 * 2 = 6, the num turn to be 16, second we can operate the whole num 16, 16 / 2 = 8, the num is 8 now, 8/2 = 4, num is 4 now, 4/2 = 2, num is 2 now, 2/2 = 1, num is

给定一个数字,您可以将其或其相邻部分除以2,或将其或其连续部分乘以2。这个数字最终会是1吗

例如:13

3 is a part of 13, first we take 3 * 2 = 6, the num turn to be 16,
second we can operate the whole num 16, 16 / 2 = 8, the num is 8 now,
8/2 = 4, num is 4 now,
4/2 = 2, num is 2 now,
2/2 = 1, num is 1 now.

finally we can say 13 can turn into 1, and the path is 13->16->8->4->2->1, we can use a List to store the path.
示例:27

first we operate the whole num 27, 27 * 2 = 54;
then we take 4 as the part of 54, 4 / 2 = 2 , so the 4 is 2 now, num becomes 52;
operate 52, 52 / 2 = 26, num is 26 now;
operate 26, 26 / 2 = 13, num is 13 now;

we just analyzed 13, so 27 can turn into 1 finally.
 
如何分析这样的问题?解决这类问题的主要思路是什么


对不起,关于这个混淆的描述,我们来举一个更复杂的例子:316

16是一个连续的部分,设16/2=8,所以num现在是38

然后取8/2=4,数值是34

取4/2=2,数值为32

现在取整个数值32/2=16

16/2=8,num为8

8/2=4,num为4

4/2=2,num为2

最后2/2=1

我们说,经过上述转换,原来的num 316最终可以变成1

而相邻部分表示,如果输入num是
12345

然后
123
234
345
12
2345
等等,它们都是连续的部分

num的任何连续子集都可以,包括head或tail都不是必需的


问题是:

  • 如何判断这样一个数字?如果num可以变成1,则打印路径
  • 你能找到最近的路吗

  • 我从面试官那里得到了一些提示(面试结束了):

  • 大多数数字是合格的,这意味着不合格的NUM,这些特征是显而易见的

  • 蛮前路的时间复杂度太高,我们应该及时修剪。(滑动窗口+修剪?)


  • 下面是一个简单且未优化的广度优先搜索

    def最短数字路径(n):
    路径_from={n:None}
    队列=[n]
    计数=0
    尽管如此:
    m=队列.pop(0)
    计数+=1
    如果0==计数%1000:
    打印((计数,m))
    如果m==1:
    打破
    x=str(m)
    对于范围内的i(len(x)):
    对于范围(i+1,len(x)+1)内的j:
    y=x[0:i]
    z=x[i:j]
    w=x[j:]
    如果z[0]=“0”:
    continue#连续段的编号不正确。
    #试试z的一半
    如果z[-1]位于['2','4','6','8']:
    下一步m=int(y+str(int(z)//2)+w)
    如果下一个\u m不在路径\u from中:
    路径_自[下一个_m]=m
    queue.append(下一步)
    #试着把z加倍
    下一步m=int(y+str(int(z)*2)+w)
    如果下一个\u m不在路径\u from中:
    路径_自[下一个_m]=m
    queue.append(下一步)
    路径=[]
    虽然m不是无:
    路径追加(m)
    m=路径_自[m]
    返回列表(反向(路径))
    
    在对此进行了一段时间的研究之后,我得出了以下观察结果

  • 如果数字以
    0
    5
    结尾,则没有路径可以在结尾处包含任何其他数字,因此您无法获得1。(以上功能将永远运行
  • 对于其他任何东西,我们都可以找到一条一次只处理1-2个数字的路径
  • 以下是观察2的特殊情况。我们的第一个目标是将0、1和5作为数字

    0: 0
    1: 1
    2: 2 -> 1
    3: 3 -> 6 -> 12 -> 24 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
    4: 4 -> 2 -> 1
    5: 5
    6: 6 -> 12 -> 24 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
    7: 7 -> 14 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
    8: 8 -> 4 -> 2 -> 1
    9: 9 -> 18 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
    
    现在从数字开始,我们必须处理以下情况,减少数字的数量,回到我们想要的形式

    10: 10 -> 5
    11: 11 -> 22 -> 24 -> 28 -> 56 -> 112 -> 16 -> 8 -> 4 -> 2 -> 1
    15: 15 -> 110 -> 220 -> 240 -> 280 -> 560 -> 1120 -> 160 -> 80 -> 40 -> 20 -> 10 -> 5
    50: 50 -> 25 -> 15 -> 110 -> 220 -> 240 -> 280 -> 560 -> 1120 -> 160 -> 80 -> 40 -> 20 -> 10 -> 5
    51: 51 -> 52 -> 26 -> 16 -> 8 -> 4 -> 2 -> 1
    55: 55 -> 510 -> 520 -> 260 -> 160 -> 80 -> 40 -> 20 -> 10 -> 5
    
    有了这套规则,我们可以首先将数字标准化为一种标准形式,然后我们可以一次将其缩短一个数字。这让我们基本上可以立即找到一条路径。几乎可以肯定的是,这不是最短的路径,但肯定是一条路径

    编写该函数留给读者作为练习

    现在返回最短路径。如果我们从两端开始宽度优先搜索并在中间相遇,则可以更快地进行广度优先搜索算法。为此,您还需要使用<代码> { 1:NO}} /代码>初始化一个<代码>路径> ->代码>,该队列包含格式>代码>(m,iSy-Read)的元素。< /代码>并使用<代码> [(1,true),(n:false)] /<代码>。然后,您必须在<代码> iSyReals<代码>上进行分支,然后在将值输入<代码> PATHOI/PATTION到之前检查它是否在<代码> PATSYOT/PATION/<代码>中。如果是,您已经在中间遇到了。现在将路径的两个部分都算出并加入到一起。


    该方法很复杂。但它可以让您在当前方法所采取的步数的平方根中找到最短路径。

    这里的
    连续部分是什么意思?您是指“连续”吗部分——例如,一些相邻的数字集。例如,如果数字是1234,你可以影响1、2、3、4、12、23、34、123、234或1234,但不能影响1和3。正如所有帖子所指出的,你的例子非常混乱,请尝试回答它们并得到一个清晰的数字。一个想法是将数字转换为2的幂,这样你就可以继续除法通过2最终得到1,或者将数字从预先计算的已知值表中转换成任意数字,然后使用存储的运算得到这些值,我们最终可以得到1。除此之外,我想不出任何多项式时间算法可以保证做到这一点,只是想指出27的路径更短:(214->224->112->16->8->4->2->1)。无论如何,就像我说的,我看不到可行的多项式时间算法,但它看起来像某种图形问题,路径修剪是一个优化步骤