【问题标题】:Recursive solution to finding patterns寻找模式的递归解决方案
【发布时间】:2014-06-13 03:02:02
【问题描述】:

我正在解决一个递归问题,即计算一个数字中连续 8 的总数。例如:

input: 8801 output: 2
input: 801 output: 0
input: 888 output: 3
input: 88088018 output:4

我无法弄清楚将信息传递给下一个关于前一个数字是否为 8 的递归调用的逻辑。

我不想要代码,但我需要逻辑方面的帮助。对于迭代解决方案,我可以使用标志变量,但在递归中,我如何完成标志变量在迭代解决方案中所做的工作。此外,它不是任何任务的一部分。这就是我想到的,因为我正在尝试使用递归来练习编码。

【问题讨论】:

  • 88088018中连续8的最大个数是2个,不是4个。
  • @j_random_hacker 考虑字典中的示例:con·sec·u·tive: following continuously. e.g., "five consecutive months of serious decline." 这似乎更符合 88088018 中的四个连续 8。不是吗?
  • @גלעדברקן:我认为我完全同意的字典定义完全符合我的主张。 88088018 包含 4 个“连续”8 的唯一方法是我们不应该计算 0 位。
  • @j_random_hacker 不,总共是两个连续的 8 加上两个连续的 8。
  • @גלעדברקן:我错过了描述中的“total”这个词,再三考虑,这使您的解释合理。我仍然认为这是一个非常不清楚的问题描述,因为如果您谈论一些连续的事情,(我认为)普遍理解为意味着 整个集合 出现没有间隙。例如。如果你问某人在一个数据集中是否有“连续五个月严重下降”,其中 1 月、2 月、6 月、7 月和 8 月严重下降,而所有其他月份都没有,他们会说“不”。

标签: algorithm recursion logic


【解决方案1】:

对此的典型解决方案是向您的函数添加一个新参数以传递“标志”状态。此参数通常称为accumulator。如果您使用的语言允许嵌套函数,您通常希望定义一个接受实际参数的外部函数,然后定义一个带有累加器作为参数的内部递归函数。 Schemehere中有一个例子。

【讨论】:

    【解决方案2】:

    您可以使用此功能逐位扫描您的号码

    int totalConsecutive8(int digit, boolean last)
    

    while boolean last 表示最后一个数字(表示digit - 1)是否为 8。

    比如最后一个例子88088018,从0位开始,boolean last为false -> digit 1,因为最后一位为8,所以last为true...

    Java 代码

    public int numberOfConsecutive8(int val){
         String number = "" + val;
         return totalConsecutive8(number, 0, false, false);
    
    }
    
    public int totalConsecutive8(String number, int digit, boolean last, boolean first){
        if(digit == number.length()){
           return 0;
        }
        int result = 0;
        if(number.charAt(digit) == '8'){
           if(last){
              if(first){ 
                 result += 2 + totalConsecutive8(number, digit + 1, true, false);
              }else{
                 result += 1 + totalConsecutive8(number, digit + 1, true, false);
              }  
           }else{
                result += totalConsecutive8(number, digit + 1, true, true);
           }
        }else{
           result += totalConsecutive8(number, digit + 1, false, false);   
        }
        return result;
    }
    

    Barmar 建议的方法:

    int totalConsecutive8(int number, boolean last , boolean first){
         if(number == 0){
            return 0;
         }
         int result = 0;
         if(number % 10 == 8){
    
            if(last){
              if(first){
                 result += 2 + totalConsecutive8(number/10, true , false){
              }else{
                 result += 1 + totalConsecutive8(number/10, true , false){
              }
            } else{
              result += totalConsecutive8(number/10, true , true){
            } 
         }else{
            result +=   totalConsecutive8(number/10, false , false){
         }
         return result;
    }
    

    【讨论】:

    • 第一个参数应该是number,而不是digit,因为它是删除初始数字后的剩余数字。否则你将没有任何东西可以递归。
    • @Barmar 如果将数字转换为字符串,则可以通过字符串中的索引来引用每个数字,因此您不需要删除第一个数字,另外可以使用非常大的数字
    • 无论如何,我的观点是在递归算法中,参数必须是剩余的数字,而不是单个数字。每个递归步骤都会检查第一个数字,然后对余数进行递归。
    • @Barmar 是的,所以在 88088018 的情况下,我们慢慢地从 0 到 7,数字 0 是 8,数字 1 是 8,数字 2 是 0,.. 来检查当前数字是否是不是连续的 8,我们只需要基于我猜的最后一个数字,极端情况是我们第一次检测到连续的 8,我们需要在最终结果中添加 2,而不仅仅是一个。跨度>
    • @Barmar 明白你的意思:),我猜这是一个不同的实现。
    【解决方案3】:

    这里是上述问题的伪代码:-

    int max = 0;
    
    void cal_eight(char ch[],int i,int count) {
    
     if(ch[i]=='\0') {
    
         max = maximum(max,count);
     }
    
     else if(ch[i]=='8') {
    
        cal_eight(ch,i+1,count+1);
    
     }
    
     else {
        max = maximum(max,count);
        cal_eight(ch,i+1,0);
     }
    
    }
    
    call :- cal_eight(ch,0,0)
    

    【讨论】:

      【解决方案4】:

      当您专注于递归时,我会提到它的一个特点和好处,那就是根本不需要传递任何额外的参数或计数调用。

      您使用修改后的参数从函数内部执行调用 - 比如说字符串减去您在函数中检查的一位数 - 然后再次调用它直到字符串变为空。

      可能是多次 - 嵌套调用。

      [更新] 以下是 Python 中的示例,详细说明更具可读性。 我们用字符串调用我们的函数,如果当前字符串的第一个字符不是 '8',则刷新连续 8 的当前链(其中,并且已知总连续 8 秒

      def f8_trace(s, chainlen=0, total=0, indent=0):
          print '  '*indent, "invoked with s='%s', chainlen=%d, total=%d" % (s,chainlen, total)
          if len(s) == 0:
              if chainlen>1:
                  total += chainlen
              retval = total
          else:
              if s[0] == '8':
                  chainlen += 1
              else:
                  if chainlen>1:
                      total += chainlen
                  chainlen = 0
              retval = f8_trace(s[1:],chainlen,total,indent+1)
          print '  '*indent, 'returns %d' % (retval)
          return retval
      
      s = 'abc888d88e8f888'
      print f8_trace( s )
      

      输出:

       invoked with s='abc888d88e8f888', chainlen=0, total=0
         invoked with s='bc888d88e8f888', chainlen=0, total=0
           invoked with s='c888d88e8f888', chainlen=0, total=0
             invoked with s='888d88e8f888', chainlen=0, total=0
               invoked with s='88d88e8f888', chainlen=1, total=0
                 invoked with s='8d88e8f888', chainlen=2, total=0
                   invoked with s='d88e8f888', chainlen=3, total=0
                     invoked with s='88e8f888', chainlen=0, total=3
                       invoked with s='8e8f888', chainlen=1, total=3
                         invoked with s='e8f888', chainlen=2, total=3
                           invoked with s='8f888', chainlen=0, total=5
                             invoked with s='f888', chainlen=1, total=5
                               invoked with s='888', chainlen=0, total=5
                                 invoked with s='88', chainlen=1, total=5
                                   invoked with s='8', chainlen=2, total=5
                                     invoked with s='', chainlen=3, total=5
                                     returns 8
                                   returns 8
                                 returns 8
                               returns 8
                             returns 8
                           returns 8
                         returns 8
                       returns 8
                     returns 8
                   returns 8
                 returns 8
               returns 8
             returns 8
           returns 8
         returns 8
       returns 8
      8
      

      【讨论】:

        【解决方案5】:

        这是 Haskell 中的一个示例,这种语言通常与递归方法相关联。

        xxs 代表字符串,xxs 大致意思是“第一项”和“其余部分”(所以在我们检查 x 之后,我们通过 xs,字符串的其余部分, 到下一个函数调用)。

        previous 设置为 True 表示前一个数字是 8。我希望其余代码看起来更直接和不言自明。守卫,|,就像命令式的“if”子句(例如,if previous then ...)。

        f xxs first8 previous count
          | null xxs  = count
          | previous  = if x == 8 
                           then f xs 0 True (count + first8 + 1)
                           else g
          | otherwise = if x == 8 
                           then f xs 1 True count
                           else g
         where x:xs = xxs
               g = f xs 0 False count
        

        输出:

        *Main> f [8,0,1] 0 False 0
        0
        
        *Main> f [8,8,8] 0 False 0
        3
        
        *Main> f [8,8,0,8,8,0,1,8] 0 False 0
        4
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-29
          • 2013-07-22
          • 2016-10-02
          • 1970-01-01
          • 1970-01-01
          • 2014-07-20
          相关资源
          最近更新 更多