How to check if all numbers in a list are steadily increasing?

耗尽温柔 提交于 2019-12-24 02:57:23

问题


I have several lists of varying length containing simple, positive integers, like (2 4 1 3) and I want to check whether or not all numbers are following each other after the list is sorted. This means the order itself doesn't matter but there are no gaps allowed.

(2 4 1 3) is correct

(2 4 1 5) isn't correct

Before I start to re-invent the wheel, I would like to know if there is an alternative to sorting the list and then checking whether or not the difference of the first and the second (and so on...) element is 1.

EDIT

My example was not showing the complete task. The list does not have to start with 1 each time, i.e., (6 8 7 9) could also be a valid input.


回答1:


Optimal Solution

You need to check whether the set defined by the list is identical to [a:b]. This is easily done by creating a bit vector of the appropriate length. This is linear (O(n)) in list length (requires scanning it once for length and min, and once for filling the bit vector), and requires some extra temporary memory for the vector:

(defun range-p (list)
  "Check that the list is identical to a..b as a set."
  (multiple-value-bind (min len)
      (loop for obj in list for len upfrom 0
        unless (integerp obj) do (return-from range-p nil)
        minimize obj into min
        finally (return (values min len)))
    (loop
      ;; 0: not seen this index in list yet
      ;; 1: already seen this index in list
      with indicator = (make-array len :element-type 'bit :initial-element 0)
      for obj in list for pos = (- obj min) do
        (unless (< pos len)
          ;; obj out of range
          (return-from range-p nil))
        (if (zerop (aref indicator pos))
            ;; obj is being seen for the 1st time; record that
            (setf (aref indicator pos) 1)
            ;; duplicate obj
            (return-from range-p nil)))
    ;; all list elements are unique and in the right range;
    ;; injectivity + same cardinality for finite sets => surjectivity
    t))

Tests:

(range-p '(2 4 1 3))
==> T
(range-p '(2 4 1 5))
==> NIL
(range-p '(-1 5 3 4 2 1 0))
==> T
(range-p '(-1 5 3 4 3 1 0))
==> NIL
(range-p '(2 4 1 a 5))
==> NIL

Sorting

Sorting is linearithmic (O(n*log(n))) and thus clearly suboptimal.

PS

This might be related to Check consecutive numbers recursively using Lisp.




回答2:


Putting together SDS's answer and Renzo's comment, I end up with this which works for me:

(defun min-obj (list)
   (loop with min = most-positive-fixnum ; sufficient in my case
         for obj in list
         when (< obj min)
           do (setf min obj)
         finally (return min))) 

(defun range-n-p (list)
   "Check that the list is identical to min..max as a set."
   (let* ((len (length list))
          (min (min-obj list))
          ;; 0: not seen this index in list yet
          ;; 1: already seen this index in list
          (indicator (make-array len :element-type 'bit :initial-element 0)))
          (loop for obj in list for pos upfrom 0 do
               (unless (< (- obj min) len) ; I deal only with integers
                  ;; obj out of range
                  (return-from range-n-p nil))
               (if (zerop (aref indicator (- obj min)))
                  ;; obj is being seen for the 1st time; record that
                  (setf (aref indicator (- obj min)) 1)
                  ;; duplicate obj
                  (return-from range-n-p nil)))
          ;; all list elements are unique and in the right range;
          ;; injectivity + same cardinality for finite sets => surjectivity
          t))

Thanks!




回答3:


you can solve this problem mathematically using some of natural numbers like scan list in o(n) to find min,max,length and total sum then calculate sum of natural number using this formula

 actualMax = min+(length(list)-1)
    nSum = ((actualMax -min+1)/2)*(actualMax +min)
    nSum-total==0?"yes":"no"

let us consider

Ex -1 (6,8,7,9) min = 6 actual max = 6+(4-1) = 9,max=9, total = 30 naturalSum = 30 it is true
Ex-2 (6,8,7,10) min = 6 actual max = 6+(4-1) = 9,max=10, total = 31 naturalSum = 30 it is false


来源:https://stackoverflow.com/questions/54620566/how-to-check-if-all-numbers-in-a-list-are-steadily-increasing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!