完成给定方案的最短路径

时间:2015-06-27 09:08:43

标签: c# algorithm

我在接受采访时被要求编写以下方案

电视有0-450个频道但是远程按钮2,5,8,9发生故障所以写 一个程序,用于从用户获取输入并通过最短路径遍历该通道

实施例

  

47 - >无需遍历按钮4,7可用

     

45 - > 44 + 1输出来自哪个通道以及遍历的通道数   要求达到45。

     

55 - > 55可以从47到达只有coz 54有5. ||| ly(50-55)有5   因此,48和49分别有8和9。

我已经尝试过我的逻辑但是甚至无法以这样的方式编码它是所有输入的最佳最短路径请帮助我使用逻辑或向我展示程序。

4 个答案:

答案 0 :(得分:1)

以另一种方式思考。有效的解决方案只能由有效数字组成。

  1. 通过从所有可能的按钮中删除故障按钮来构建有效的按钮组
      

    0,1,3,4,6,7

  2. 从左到右查找频道编号的第一个无效数字。 如果找到,请转到第3步。否则,无需遍历按钮。
  3. 生成两个最靠近通道编号的数字,仅设置有效按钮。

      

    例如:频道号= 189

         

    隐藏第一个无效数字右侧的所有数字 - > 18X

         

    上限:从有效集中寻找稍大一点的8位数,但未找到。在这种情况下,我们寻找一个更大的有效数字1,我​​们得到3.然后填补其余的最小有效数字。我们得到300。

         

    下限:从有效集中寻找略小于8的数字,得到7.然后填充其余的最大有效数字。我们得到177。

  4. 考虑边界情况,如果不能形成下限或上限(通道号450应该为0作为有效解)并超出上限

  5. 将两个数字与频道编号进行比较,并获得最接近的数字。

  6. 格式和输出

  7. 时间复杂度:所有情况下的O(log(n))

答案 1 :(得分:0)

*更新并检查错误,最终解决方案可能是这样的:

    public static void Traverse(int channelToAccess, int maxChannels, params char[] brokenButtons)
    {      
        int result = -1;      // closest channel num

        for (int i = 1; result == -1 && i > 0 && i < maxChannels; i++)
        {
            if (!(channelToAccess + i).ToString().Any(brokenButtons.Contains)) { result = channelToAccess + i; break; }
            if (!(channelToAccess - i).ToString().Any(brokenButtons.Contains)) { result = channelToAccess - i; break; }
        }
       int difference = result - channelToAccess;
       Console.WriteLine("To open channel {0} you should turn channel {1} and press {2} button {3} times", channelToAccess, result, difference > 0 ? "-" : "+", Math.Abs(difference));
    }

使用示例:Traverse(255, 450, '2', '5', '8', '9');

输出:要打开通道255,您应该转动通道300并按下按钮&#39; - &#39; 45次

答案 2 :(得分:0)

对于电视遥控器,我们可以做出一些假设:

  • 它没有加起来所以我们必须使用从最近的频道开始的+1或-1按钮
  • 当达到上限时,+1将转到最低数字,-1以相同方式作用于另一个方向。

从这些假设开始,找到在任一方向上步数最少的通道:

public int NearestChannel(int channel)
{
   var forward = StepsForward(channel);
   var backward = StepsBackward(channel);

   if (forward < backward)
   {
      return channel - forward;
   }
   else
   {
      return channel + backward;
   }
}

StepsForwardStepsBackward方法只是计算,直到我们达到有效结果。唯一需要注意的是上限和下限(在您的示例中为0和450):

public int StepsForward(int channel)
{
   int steps = 0;

   while (!IsValid(channel))
   {
      channel--;
      if (channel < 0)
      {
         channel = 450;
      }
      steps++;
   }

   return steps;
}

public int StepsBackward(int channel)
{
   int steps = 0;

   while (!IsValid(channel))
   {
      channel++;
      if (channel > 450)
      {
         channel = 0;
      }
      steps++;
   }

   return steps;
}

然后验证只是查看要测试的数字是否包含任何无效数字:

public bool IsValid(int number)
{
   var numberAsString = number.ToString();
   foreach (var digit in numberAsString)
   {
      switch (digit)
      {
         case '2':
         case '5':
         case '8':
         case '9':
            return false;
      }
   }

   return true;
}

答案 3 :(得分:0)

我相信这是按预期工作的。
它可以进一步优化,但是我现在能做的最好。

格式化是必要的,因为用户输入8989..99时存在极端情况,在这些情况下,小数位数会发生变化,这是唯一的方法我找到了解决它。

class RemoteControl
{        
    public char[] brokenButtons = new char[4] {'2','5','8','9'};
    public char[] availableButtons = new char[6] { '0', '1', '3', '4', '6', '7'};        
    public char[] allButtons = new char[10] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

    private char[] HighestPriorChannel(char[] inputChannel)
    {
        char[] channel = inputChannel.ToArray();            

        int pos;
        bool changed, isMarked = false;
        for (int i = channel.Length - 1; i >= 0; i--)
        {
            changed = false;
            pos = Array.IndexOf<char>(allButtons, channel[i]);
            if (isMarked) pos--;

            while (pos >= 0)
            {
                channel[i] = allButtons[pos];
                pos--;
                if (!brokenButtons.Contains(channel[i])) break;
                else changed = true;
            }

            if (isMarked || changed)
            {
                for (int j = i + 1; j < channel.Length; j++)
                    channel[j] = availableButtons.Last();
            }
            isMarked = brokenButtons.Contains(channel[i]);
        }            

        return channel;
    }

    private char[] LowestNextChannel(char[] inputChannel)
    {
        char[] channel = inputChannel.ToArray();         
        int pos;
        bool changed, isMarked = false;
        for (int i = channel.Length - 1; i >= 0; i--)
        {
            changed = false;
            pos = Array.IndexOf<char>(allButtons, channel[i]);
            if (isMarked) pos++;

            while(pos < allButtons.Length)
            {
                channel[i] = allButtons[pos];
                pos++;
                if (!brokenButtons.Contains(channel[i])) break;
                else changed = true;
            }

            if (isMarked || changed)
            {
                for (int j = i + 1; j < channel.Length; j++)
                    channel[j] = availableButtons.First();
            }
            isMarked = brokenButtons.Contains(channel[i]);
        }            
        return channel;
    }

    private int FindNearestChannel(char[] channel)
    {
        char[] prior = HighestPriorChannel(channel);
        char[] next = LowestNextChannel(channel);

        int intChannel = Convert.ToInt32(new string(channel));
        int intPrior = Convert.ToInt32(new string(prior));
        int intNext = Convert.ToInt32(new string(next));

        bool nextInRange = IsChannelInRange(intNext);
        bool priorInRange = IsChannelInRange(intPrior);

        if (nextInRange && priorInRange)
        {
            if ((intChannel - intPrior) > (intNext - intChannel))
            {
                return intNext;
            }
            else
            {
                return intPrior;
            }
        }
        else if (nextInRange)
        {
            return intNext;
        }
        else
        {
            return intPrior;
        }

    }

    private void GoBackward(int desiredChannel, int nearestChannel)
    {
        int times = 0;
        while (desiredChannel != nearestChannel)
        {
            nearestChannel--;
            times++;

        }
        Console.WriteLine("Press button (-) {0} times", times);
    }

    private void GoForward(int desiredChannel, int nearestChannel)
    {
        int times = 0;
        while(desiredChannel != nearestChannel){
            nearestChannel++;
            times++;

        }
        Console.WriteLine("Press button (+) {0} times", times);
    }

    public void FindChannel(string channel)
    {
        if (channel.Intersect(brokenButtons).Count() > 0)
        {                
            int nearestChannel = FindNearestChannel(channel.ToArray());

            Console.WriteLine("Turn Channel {0}", nearestChannel);

            int asInt = Convert.ToInt32(channel);
            if (asInt > nearestChannel)
                GoForward(asInt, nearestChannel);
            else
                GoBackward(asInt, nearestChannel);
        }
        else
        {
            Console.WriteLine("Turn Channel {0}", channel);
            Console.WriteLine("Done.");
        }
    }        

    private bool IsChannelInRange(int channel)
    {
        return (channel < 451) && (channel >= 0);
    }

    public bool IsValidInput(string input)
    {            
        int asInt = 0;
        return Int32.TryParse(input, out asInt) && IsChannelInRange(asInt);
    }        
}
class Program
{
    static void Main(string[] args)
    {
        RemoteControl rm = new RemoteControl();
        string input = "";
        bool turnOff = false;
        do
        {
            Console.Clear();
            Console.WriteLine("Enter a valid channel or \"off\" to turn off");
            input = Console.ReadLine();
            turnOff = input.ToLower() == "off";
        }
        while (!(turnOff || rm.IsValidInput(input)));

        if (!turnOff)
        {                
            rm.FindChannel(input.PadLeft(3,'0'));
            Console.ReadLine();
        }
    }
}