不知道我写的这段代码的大O,使用堆栈的效率低于递归吗? (Google Kickstart B轮机器人路径解码)

问题描述 投票:0回答:1

我当时正在尝试解决旧的Google Kick Start问题,即机器人路径解码。

https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ffc8/00000000002d83d

如果上面的链接不起作用,我已经粘贴了问题提示的精简版,它是该问题底部的解决方案。

对于第一个测试集,机器人可以执行的移动总数为10 ^ 4。第二个测试集(我看不到)没有任何限制。

该解决方案对第二个测试集说:“现在移动的数量在原始程序的长度上可能是指数的。因此,不可能在给定的时间内一一执行移动。“

我的解决方案在第二个测试集上超时。但是我希望我的解决方案是O(n),因为我只是遍历输入字符串并在遇到子路径时推入并弹出堆栈。我觉得我正在做的事情与提供的解决方案相似,使用堆栈代替了递归。关于为什么我的解决方案比他们的解决方案要慢的困惑(我将其粘贴在下面)

这是我的代码

#include <iostream> // includes cin to read from stdin and cout to write to stdout
#include<string>
#include<stack>


    using namespace std; // since cin and cout are both in namespace std, this saves some text

    int main() {
      int t; //the number of test cases
      cin >> t; 

      for (int i = 1; i <= t; ++i) {

         string path; 
         cin >> path;

         long width=0;
         long height=0;
         long n=0;

         stack<int> pos; //everytime a '(' is detected, the current 
                         //width and height are pushed onto the stack
                         //along with the number that precedes the '('
         string num="";

         for(int j=0;j<path.size();j++){

             switch(path[j]){
                 case 'N':
                    --height;
                 break;
                 case 'S':
                    ++height;
                 break;
                 case 'W':
                    --width;
                 break;
                 case 'E':
                    ++w;
                 break;
                 case '(':
                    n=stoi(num);
                    num = "";
                    pos.push(height);
                    pos.push(width);
                    pos.push(n);
                    height=0;
                    width=0;
                 break;
                 case ')':
                    n = pos.top();
                    pos.pop();
                    width = (width*n) + pos.top();
                    pos.pop();
                    //cout << pos.top() << endl;
                    h = (height*n) + pos.top();
                    pos.pop();
                 break;
                 default:
                    num+=path[j];
             }

         }

         width += 1;
         height += 1;

         int edgeOfPlane=1000000000;
         while(width > edgeOfPlane){
             width -= edgeOfPlane;
         }

         while(width <= 0){
             width+=edgeOfPlane;
         }

         while(height <= 0){
             height+=edgeOfPlane;
         }

         while (height > edgeOfPlane){
             h -= edgeOfPlane;
         }


        cout << "Case #" << i << ": " << width << " " << height << endl;



      }
      return 0;
    }

问题和解决方案可以在这里找到

https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ffc8/00000000002d83d

如果有人能解释为什么我的解决方案超时,以及为什么他们的2号测试集递归解决方案有效,我将非常感激!

如果Google链接断开,这里是问题提示的简短摘要。新行星上的漫游者,可以认为是由109列(从西到东从1开始编号)的正方形网格组成和109行(从北到南从1开始编号)。令(w,h)表示第w列和第h行的平方。流动站从正方形(1,1)开始。

流动站移动了代表四个基本方向运动的字符串。机械手按以下顺序执行字符串的每个字符:

还有一个特殊的指令X(Y),其中X是2到9之间的一个数字,且Y是一个非空子程序。这表示机器人应将子程序Y总共重复X次。例如:2(NWE)等效于NWENWE。3(S2(E))等同于SEESEESEE。EEEE4(N)2(SS)等效于EEEENNNNSSSS。

如果流动站移动到网格边缘,则将在开始时返回(圆行星)。

Google的解决方案:

为了简化程序的解析,让我们将ClosingBracket(i)定义为与索引i处的右括号相对应的右括号的索引。我们可以使用线性时间中的堆栈为每个左括号找到ClosingBracket(i),这类似于检查字符串是否为正确的括号序列。

为了便于说明,假定行和列的编号从0(含)到109(不含)。假设机器人处于位置(a,b),现在我们在程序中遇到指令X(Y)。让我们说子程序Y将流动站的当前位置更改为dx,dy(由于火星的圆环形状,我们可以假定0≤dx <109和0≤dy <109)。然后,随着子程序Y重复X次,遵循指令X(Y)之后的流动站位置将是((a + X * dx)mod 109,(b + X * dy)mod 109)。因此,我们只需要找到每个子程序的流动站相对位移即可。

对于在索引L和R之间的子程序,可以如下使用Evaluate(L,R)递归计算机器人的相对位移。考虑我们当前处于正方形(a,b),最初是正方形(0,0)。从左索引L到右索引R迭代子程序,并考虑两种情况:

如果第i个符号位于{'N','S','E','W'}中,请相应地更改机器人的当前位置。如果第i个符号是数字D,则调用Evaluate(i + 2,ClosingBracket(i + 1)-1)来递归下一个子程序的流动站相对位移(dx,dy),将当前位置更改为((a + D * dx)mod 109,(b + D * dy)mod 109)和将当前位置i移至ClosingBracket(i + 1)+1。

我们只访问程序中的每个字符一次。该解决方案的时间复杂度为O(N),其中N为程序的长度。

c++ algorithm recursion stack runtime
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.