Algorithm 从源到目标的最小操作数。

Algorithm 从源到目标的最小操作数。,algorithm,language-agnostic,dynamic-programming,Algorithm,Language Agnostic,Dynamic Programming,我在一次采访中遇到了这个问题- 以最少的操作次数将数字源转换为目标 允许的操作 乘以2 加1 减1 01,6->(0,6)x(2,6)->1,6->(0,6)x(1,6)->(0,6)x(2,6)->1,6。。 int movesLeft=minMoves(源-1,目标)=-1?最大值:最小移动(源-1,目标); int movesRight=minMoves(源+1,目标)=-1?整数。最大值:最小移动(源+1,目标); int moves2X=minMoves(2*源,目标)=-1?整数.M

我在一次采访中遇到了这个问题- 以最少的操作次数将数字源转换为目标

允许的操作

  • 乘以2
  • 加1
  • 减1
  • 0<源,目标2,6->1,6->(0,6)x(2,6)->1,6->(0,6)x(1,6)->(0,6)x(2,6)->1,6。。 int movesLeft=minMoves(源-1,目标)=-1?最大值:最小移动(源-1,目标); int movesRight=minMoves(源+1,目标)=-1?整数。最大值:最小移动(源+1,目标); int moves2X=minMoves(2*源,目标)=-1?整数.MAX_值:最小移动(2*源,目标); moves=1+Math.min(Math.min(movesRight,movesLeft),moves2X); 回击动作; }
    关于如何调整我的解决方案,有什么想法吗?或者可能是更好的解决方法?

    在保持递归实现的同时,可以加速(并可能修复)此代码的一种方法是使用
    记忆化


    这里的问题是,您多次重新计算相同的值。相反,您可以使用
    map
    存储已计算的结果,并在再次需要时重用这些结果。

    这个问题可以建设性地解决。首先,简单的案例。如果s=t,则答案为0。如果s>t,答案是s-t,因为减法1是降低s的唯一操作,而另外两个只能增加所需的减法次数

    现在我们假设s0,所以加倍始终是增加的最快方式(如果s为1,则与递增并列)。因此,如果挑战是使s>=t,那么答案将始终是这样做所需的加倍次数。该程序可能超出t,但第一次倍频大于t,最后一次倍频不大于t,必须在t的2倍以内

    让我们看看加减法的效果。首先,只看加法:

    (((s*2) * 2) * 2) + 1 = 8s + 1
    
    vs:

    在n个加倍之前加一个加法,最终结果会变大2^n。因此,如果S是3,T是8。最后一个不大于8的倍数是6。这是2关,所以如果我们在最后一个双精度前加1双精度,我们得到我们想要的:(3+1)*2。或者,我们可以尝试超调到大于8的第一个双精度,即12。这是4次,所以我们需要在最后一次:(3-1)*2*2=8之前加两次减法

    一般来说,如果x低于目标值x,那么如果x的二进制表示在第n处有1,则需要在最后一个之前的n倍处放置一个
    +1

    类似地,如果我们比目标高出x,我们对
    -1
    也会这样做

    对于x二进制表示法中的
    1
    ,如果其位置超过了双倍数,则此过程将不会有帮助。例如,如果s=100,t=207,则只需加倍1次,但x为7,即111。我们可以先做加法,把中间的那一个去掉,剩下的我们必须一个一个地做
    (s+1)*2+1+1+1+1+1

    下面是一个具有调试标志的实现,该标志在定义标志时还输出操作列表。运行时间为O(log(t)):

    #包括
    #包括
    #包括
    #定义调试信息
    int MinMoves(int s,int t)
    {
    int ans=0;
    
    如果(t如果你认为你的解决方案像一个图遍历,其中每个节点都是你可以产生的中间值,那么你的递归解决方案就像深度优先搜索(DFS)。你必须完全展开,直到你尝试了这个“分支”中的所有解决方案如果你有一个无限循环,这意味着即使存在较短的路径,它也不会终止,即使你没有无限循环,你仍然必须搜索解空间的其余部分以确保其最优

    取而代之的是,考虑类似于广度优先搜索(BFS)的方法。你均匀地向外扩展,并且永远不会搜索比最优解更长的路径。只需使用FIFO队列来调度下一个节点访问。这就是我用我的求解器所采取的方法。

    from queue import Queue
    
    def solve(source, target):
        queue = Queue()
        path = [source]
        queue.put(path)
        while source != target:
            queue.put(path + [source * 2])
            queue.put(path + [source + 1])
            queue.put(path + [source - 1])
    
            path = queue.get()
            source = path[-1]
        return path
    
    if __name__ == "__main__":
        print(solve(4,79))
    

    短BFS算法。它在每个顶点x连接到x+1、x-1和x*2;O(n)的图中寻找最短路径

    #包括
    使用名称空间std;
    const int_MAX_DIS=2020;
    常数int _MIN _DIS=0;
    int最小移动(int开始,int结束){
    队列Q;
    int dis[_MAX_dis];
    填充(dis,dis+\u MAX\u dis,-1);
    dis[begin]=0;
    推(开始);
    而(!Q.empty()){
    intv=Q.front();Q.pop();
    int tab[]={v+1,v-1,v*2};
    对于(int i=0;i<3;i++){
    int w=制表符[i];
    
    如果(_MIN_DIS)递归代码能工作吗?它不能,我在代码中有一个例子,我认为它会因为进入一个无限循环而失败。(100+1+1)*2+1=207尽管为了完整性,您可能需要path.length/size(或者在Python中调用它的方式)
    ((((s+1)*2) * 2) * 2) = 8s + 8
    
    #include <iostream>
    #include <string>
    #include <sstream>
    
    #define DEBUG_INFO
    
    int MinMoves(int s, int t)
    {
        int ans = 0;
        if (t <= s)
        {
            return s - t; //Only subtraction will help
        }
        int firstDoubleGreater = s;
        int lastDoubleNotGreater = s;
        int nDouble = 0;
        while(firstDoubleGreater <= t)
        {
            nDouble++;
            lastDoubleNotGreater = firstDoubleGreater;
            firstDoubleGreater *= 2;
        }
        int d1 = t - lastDoubleNotGreater;
        int d2 = firstDoubleGreater - t;
        if (d1 == 0)
            return nDouble -1;
        int strat1 = nDouble -1;        //Double and increment
        int strat2 = nDouble;           //Double and decrement
    
    
    #ifdef DEBUG_INFO
    std::cout << "nDouble: " << nDouble << "\n";
        std::stringstream s1Ops;
        std::stringstream s2Ops;
        int s1Tmp = s;
        int s2Tmp = s;
    #endif
    
        int mask = 1<<strat1;
        for(int pos = 0; pos < nDouble-1; pos++)
        {
    #ifdef DEBUG_INFO
            if (d1 & mask)
            {
                s1Ops << s1Tmp << "+1=" << s1Tmp+1 << "\n" << s1Tmp+1 << "*2= " << (s1Tmp+1)*2 << "\n";
                s1Tmp = (s1Tmp + 1) * 2;
            }
            else
            {
                s1Ops << s1Tmp << "*2= " << s1Tmp*2 << "\n";
                s1Tmp = s1Tmp*2;
            }
    #endif
            if(d1 & mask)
                strat1++;
            d1 = d1 & ~mask;
            mask = mask >> 1;
        }
        strat1 += d1;
    #ifdef DEBUG_INFO
        if (d1 != 0)
            s1Ops << s1Tmp << " +1 " << d1 << " times = " << s1Tmp + d1 << "\n";
    #endif
    
        mask = 1<<strat2;
        for(int pos = 0; pos < nDouble; pos++)
        {
    #ifdef DEBUG_INFO
            if (d2 & mask)
            {
                s2Ops << s2Tmp << "-1=" << s2Tmp-1 << "\n" << s2Tmp-1 << "*2= " << (s2Tmp-1)*2 << "\n";
                s2Tmp = (s2Tmp-1)*2;
            }
            else
            {
                s2Ops << s2Tmp << "*2= " << s2Tmp*2 << "\n";
                s2Tmp = s2Tmp*2;
            }
    #endif
    
    
            if(d2 & mask)
                strat2++;
            d2 = d2 & ~mask;
            mask = mask >> 1;
        }
        strat2 += d2;
    #ifdef DEBUG_INFO
        if (d2 != 0)
            s2Ops << s2Tmp << " -1 " << d2 << " times = " << s2Tmp - d2 << "\n";
    
    
    
        std::cout << "Strat1:   "  << strat1 << "\n";
        std::cout << s1Ops.str() << "\n";
        std::cout << "\n\nStrat2:   "  << strat2 << "\n";
        std::cout << s2Ops.str() << "\n";
    #endif
        if (strat1 < strat2)
        {
            return strat1;
        }
        else
        {
            std::cout << "Strat2\n";
            return strat2;
        }
    
    }
    
    
    
    
    int main()
    {
        int s = 25;
        int t = 193;
        std::cout << "s = " << s << "  t = " << t << "\n";
        std::cout << MinMoves(s, t) << std::endl;
    }
    
    from queue import Queue
    
    def solve(source, target):
        queue = Queue()
        path = [source]
        queue.put(path)
        while source != target:
            queue.put(path + [source * 2])
            queue.put(path + [source + 1])
            queue.put(path + [source - 1])
    
            path = queue.get()
            source = path[-1]
        return path
    
    if __name__ == "__main__":
        print(solve(4,79))
    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int _MAX_DIS = 2020;
    const int _MIN_DIS = 0;
    
    int minMoves(int begin, int end){
        queue<int> Q;
        int dis[_MAX_DIS];
        fill(dis, dis + _MAX_DIS, -1);
    
        dis[begin] = 0;
        Q.push(begin);
    
        while(!Q.empty()){
            int v = Q.front(); Q.pop();
            int tab[] = {v + 1, v - 1, v * 2};
            for(int i = 0; i < 3; i++){
                int w = tab[i];
                if(_MIN_DIS <= w && w <= _MAX_DIS && dis[w] == -1){
                    Q.push(w);
                    dis[w] = dis[v] + 1;
                }
            }
        }
    
        return dis[end];
    }
    
    int main(){
    
        ios_base::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cout << minMoves(1, 1000);
    
        return 0;
    }