【问题标题】:Cut the stick HackerRank Challenge Lisp implementation切棒 HackerRank Challenge Lisp 实现
【发布时间】:2014-10-19 19:37:41
【问题描述】:

我现在很困惑。请注意,这场斗争已经教会了我很多关于 lisp 的知识。不过,此时我可能需要一点推动或指导。

Cut the sticks challenge

给你 N 根棍子,每根棍子的长度都是正整数。对木棍执行切割操作,使所有木棍都减去最小木棍的长度。

假设我们有 6 根长度的棍子

5 4 4 2 2 8 然后在一次切割操作中,我们从 6 根棍子中的每一根切出长度为 2 的片段。对于下一次切割操作,剩下 4 根棍子(长度非零),长度为

3 2 2 6 重复上述步骤,直到没有留下任何棍子。

给定 N 根棍子的长度,打印在后续切割操作中切割的棍子数。

输入格式 第一行包含一个整数 N。 下一行包含 N 个整数:a0, a1,...aN-1,以空格分隔,其中 ai 表示第 i 根棍子的长度。

输出格式 对于每个操作,分别打印被切割的棒数。

约束 1≤N≤1000 1 ≤ ai ≤ 1000

所以我得到了所有示例测试用例,但其他一些我没有。例如

输入:

8
8 8 14 10 3 5 14 12

他们期望输出为

8
7
6
4
3
2

但是我的代码给出了

8
7
6
4
2


这是我现在想出的功能。

(defun cut-print (numbers cut-length)

    (let ((x numbers) (y cut-length) (k 0))
        (loop while (> (length x) 0) do
            (tagbody
                ;; subtracting the min value from all list elements
                (setq x (map 'list (lambda (i) (- i y)) x)) 

                ;; Don't print if the list length hasn't changed
                ;; from last iteration
                ;; else save length changes and print
                (cond ((= k (length x)) (go bottom))
                      ((not (= k (length x)))
                        (setq k (length x))
                        (format t "~d~%" k)))

                ;; move to here if nothing is printed to
                ;; stdout during the current iteration
                bottom
                    (setq x (remove-if (lambda (x) (<= x 0)) x))))))

我忽略了什么?根据测试用例,上面的逻辑似乎会根据预期的输出跳过剪切操作。

【问题讨论】:

    标签: algorithm lisp common-lisp


    【解决方案1】:

    y 有什么变化?在你的程序中它没有改变......

    风格:

    • 摆脱 TAGBODY 和 GO。
    • 将 COND 替换为 IF。
    • 变量 x 和 y 有什么用?
    • 使用描述性名称代替 x、y、i、k。

    一个简单的递归版本:

    (defun cut (sticks)
      (when sticks
        (print (length sticks))
        (let ((smallest (reduce #'min sticks)))
          (cut (remove-if-not #'plusp
                              (mapcar (lambda (stick)
                                        (- stick smallest))
                                      sticks))))))
    

    另一个递归版本可能如下所示:

    (defun cut (sticks)
      (labels ((%cut (sticks)
                 (when sticks
                   (print (length sticks))
                   (let ((smallest (first sticks)))
                     (%cut (mapcar (lambda (stick)
                                     (- stick smallest))
                                   (member smallest (rest sticks)
                                           :test-not #'=)))))))
        (%cut (sort sticks #'<))))
    

    甚至:

    (defun cut (sticks)
      (labels ((%cut (sticks length)
                 (when sticks
                   (print length)
                   (let ((prefix-length (or (position (first sticks) sticks
                                                      :test-not #'=)
                                            1)))
                     (%cut (nthcdr prefix-length sticks)
                           (- length prefix-length))))))
        (setf sticks (sort sticks #'<))
        (%cut sticks (length sticks))))
    

    一个简单的 LOOP 版本:

    (defun cut (numbers)
      (loop with smallest
            while numbers do
            (print (length numbers))
            (setf smallest (reduce #'min numbers)
                  numbers (loop for n in numbers 
                                for n1 = (- n smallest)
                                when (plusp n1)
                                collect n1))))
    

    【讨论】:

    • 哦,好的,我现在明白了。最初我认为最小长度是静态的。因此,从第一根棍子获得的最小长度将是减去整个棍子之前的最小长度。如果您在每个步骤中计算最小值,则更有意义。也感谢风格指针。我认为我把事情复杂化了,因为我对 lisp 还没有透彻的了解,但你指出的内容很有帮助。
    【解决方案2】:

    作为一个小脑筋急转弯,这里有一个简短的解决问题的方法:

    (defun sticks (&rest sticks)
      (do ((rest (sort sticks #'<) (remove (car rest) rest)))
          ((null rest))
          (print (length rest))))
    

    编辑:我同意 Rainer Joswig,但保留代码不变,以便他的评论仍然有意义。

    【讨论】:

    • 我不会使用 &amp;rest 参数 - 但否则是一个很好的简短解决方案。
    • 是的,我必须删除棒参数中的 &rest 才能使其正常工作。顺便说一句,很好的解决方案。如果您在 do 循环的开头声明它,我不确定它为什么会在那里。你能解释一下吗?
    • 我假设 'it' 意味着 'rest',在这种情况下 &amp;rest - lambda 列表语法的一部分 - 与声明和绑定的变量 rest 无关do 宏。我建议阅读 Practical Common Lisp 的功能章节。
    【解决方案3】:

    看起来你把事情复杂化了。为什么要使用 tagbody 呢?对于这个所谓的挑战,这里有一个简单的 Common Lisp 解决方案。它通过了他们的测试。

    (defun cut (sticks)
      (let ((shortest (reduce #'min sticks)))
        (mapcan (lambda (x) ;; I user mapcan to not traverse list twice
                 (let ((res (- x shortest)))
                    (when (plusp res) (list res)))) sticks)))
    
    (defun cut-the-sticks (n sticks)
      (if (null sticks)
        nil
        (let ((cutted (cut sticks)))
          (format t "~&~D" n)
          (cut-the-sticks (length cutted) cutted))))
    
    (cut-the-sticks (read)
                    (with-input-from-string (in (read-line))
                      (loop :for x = (read in nil nil)
                            :while x :collect x)))
    

    【讨论】:

    • 不是APPLY,使用REDUCE。否则,您可以计算的列表的最小值只能达到CALL-ARGUMENTS-LIMIT 长度。
    • 你完全正确,谢谢。我忘记了。我会改变答案。
    【解决方案4】:

    很少练习 lisp(无法掌握 cons 单元格),所以我将在 python 中给出解决方案

    def cutprint(lst):
        #sort the list
        lst = sorted(lst)
        #let the maxcut so far be the size of first stick
        maxcut = lst[0]
        #get the size of the list
        n = len(lst)
    
        #submit the initial size of the list
        yield n    
        #Loop over all sticks in the list
        for stick in lst:
            #subtract the current max cut from the stick
            stick -= maxcut
            #if the cut was to little, we have done the maximum cuts possible
            if stick > 0:        
                #Add the remainder of the last cut to maxcut
                maxcut += stick            
                #submit the current value of n
                yield n        
            #Since we are cutting at each iteration, subtract 1 from n
            n -= 1
    

    我认为代码很容易解释,应该很容易理解

    用法:

    >>> import stick
    >>> for k in stick.cutprint([2, 2, 3, 4, 5, 7, 4, 2, 3, 4, 5, 6, 7, 34]):
    ...     print k
    ...
    14
    11
    9
    6
    4
    3
    1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 2022-11-14
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2020-08-16
      相关资源
      最近更新 更多