切断HackerRank Challenge Lisp实现

时间:2014-10-19 19:37:42

标签: algorithm lisp common-lisp

我现在很难过。请注意,斗争已经教会了我很多关于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))))))

我在俯瞰什么?根据测试用例,似乎上面的逻辑将根据其预期输出跳过切割操作。

4 个答案:

答案 0 :(得分:3)

y如何变化?在你的程序中,它没有改变......

风格:

  • 摆脱TAGBODY和GO。
  • 用IF代替COND。
  • 变量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))))

答案 1 :(得分:3)

作为一个小型的脑筋急转弯,这是解决问题的一个较短的解决方案:

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

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

答案 2 :(得分:1)

看起来你让事情复杂化了。为什么要使用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)))

答案 3 :(得分:0)

很少练习使用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