你将如何显示整数数组为一组范围? (算法)(How would you display an a

2019-07-30 18:33发布

鉴于整数数组,什么是迭代,并计算出所有覆盖范围最简单的方法? 例如,对于一个阵列,例如:

$numbers = array(1,3,4,5,6,8,11,12,14,15,16);

该范围是:

 1,3-6,8,11-12,14-16

Answer 1:

如果数组按升序排序,那么问题很容易。 限定Range的结构或类,其具有开始和结束。 然后经过阵列。 如果当前元素是比前一个更,更新Range.end ,否则创建一个新的范围与此元素为Range.begin 。 存储范围的动态数组或链表。 或只是打印出来,当您去。

如果阵列可能不会进行排序,然后先排序。



Answer 2:

下面是做这件事的C#3.0'y方式:

兴趣点:

  • 自动属性(公共int属性{获得;设置;})
  • 使用新的对象初始化(新范围{开始= XXX; ...}
  • 使用产量为懒惰的评价
  • 使用LINQ扩展方法(第一()和跳过())

-

class Demo
{
    private class Range
    {
        public int Begin { get; set; }
        public int End { get; set; }

        public override string ToString()
        {
            if (Begin == End)
                return string.Format("{0}", Begin);
            else
                return string.Format("{0}-{1}", Begin, End);
        }
    }

    static void Main(string[] args)
    {
        var list = new List<int> { 1, 3, 4, 5, 6, 8, 11, 12, 14, 15, 16 };
        // list.Sort();
        var ranges = GetRangesForSortedList(list);

        PrintRange(ranges);

        Console.Read();
    }

    private static void PrintRange(IEnumerable<Range> ranges)
    {
        if (ranges.Count() == 0)
            return;

        Console.Write("[{0}", ranges.First());

        foreach (Range range in ranges.Skip(1))
        {
            Console.Write(", {0}", range);
        }

        Console.WriteLine("]");
    }

    private static IEnumerable<Range> GetRangesForSortedList(IList<int> sortedList)
    {
        if (sortedList.Count < 1) 
            yield break;

        int firstItem = sortedList.First();
        Range currentRange = new Range { Begin = firstItem, End = firstItem };

        foreach (int item in sortedList.Skip(1))
        {
            if (item == currentRange.End + 1)
            {
                currentRange.End = item;
            }
            else
            {
                yield return currentRange;
                currentRange = new Range { Begin = item, End = item };
            }
        }

        yield return currentRange;
    }
}

欢呼声中,大卫·



Answer 3:

这里有一个Python实现,它应该很容易跟随

numbers = [1,3,4,5,6,8,11,12,14,15,16];

def is_predecessor(i1, i2):
    if i1 == i2 - 1:
        return True;
    else:
        return False;

def make_range(i1, i2):
    if i1 == i2:
        return str(i1);
    else:
        return str(i1) + "-" + str(i2);

previous_element = None;
current_start_element = None;

for number in numbers:
    if not is_predecessor(previous_element, number):
        if current_start_element is not None:
            print make_range(current_start_element, previous_element);
        current_start_element = number;
    previous_element = number;

# handle last pair
if current_start_element is not None:
    print make_range(current_start_element, previous_element);

这种输出:

1
3-6
8
11-12
14-16

我知道,我知道,这不是一个算法 ,但我发现它很难真正解释它,而不必不是只实现它的解决方案的缩进问题。



Answer 4:

第一:第二排序:tokenise然后:打印在随后的人的第一个值和循环。 如果“当前”值等于最后一个值+1,跳过它。 否则,如果你跳过价值几许打印和值,否则打印一个逗号和重复。

这应该做的。 除非你想我能写你的功课吗? :)



Answer 5:

如果数组进行排序,如在例子中,我将定义含有分钟和最大桶。

初始化:创建具有分钟,一个最大等于所述第一值的桶。

循环:每个值与当前桶的最大值进行比较。 如果它比当前的最大等于1或更多,更新最高。 如果它比最大值大超过1桶保存到桶的列表,并开始一个新的水桶。

在结束时,你将有一组与最低和每一个最大桶。 如果min是一样的最大值,打印单数(即:在你的例子中,第一桶将具有最小和的1最大值)。 如果它们是不同的,打印的范围。

在口齿不清示例实现:

CL-USER> (defun print-ranges (integer-list)
           (let ((sorted-list (sort integer-list #'<)))
             (loop with buckets = ()
                   with current-bucket
                   for int in sorted-list
                     initially (setf current-bucket (cons (first sorted-list) (first sorted-list)))
                   do (cond ((= int (cdr current-bucket))) ; do nothing, this number is already in range
                            ((= (1- int) (cdr current-bucket)) ; number is 1 higher--update bucket's max
                             (setf (cdr current-bucket) int))
                            (t
                             (push current-bucket buckets)
                             (setf current-bucket (cons int int)))) ; set up a new bucket
                   finally (push current-bucket buckets)
                           (loop for firstp = t then nil
                                 for bucket in (nreverse buckets) do
                                   (cond ((= (car bucket) (cdr bucket))
                                          (format t "~:[,~;~]~D" firstp (car bucket)))
                                         (t
                                          (format t "~:[,~;~]~D-~D" firstp (car bucket) (cdr bucket))))))))
PRINT-RANGES
CL-USER> (print-ranges (list 1 3 4 5 6 8 11 12 14 15 16))
1,3-6,8,11-12,14-16
NIL
CL-USER> 

基本上你最终得到的东西的清单,其中每个事物都有(最低的桶,入桶最高)。 这些都是你的范围。

如果列表尚未排序,第一个排序。



Answer 6:

C(GCC)

这是一个类似的Python的版本 。

void ranges(int n; int a[n], int n)
{
  qsort(a, n, sizeof(*a), intcmp);
  for (int i = 0; i < n; ++i) {
    const int start = i;
    while(i < n-1 and a[i] >= a[i+1]-1)
      ++i;
    printf("%d", a[start]);
    if (a[start] != a[i])
      printf("-%d", a[i]);
    if (i < n-1)
      printf(",");
  }
  printf("\n");
}

例:

/**
 * $ gcc -std=c99 -Wall ranges.c -o ranges && ./ranges
 */
#include <iso646.h> // and
#include <stdio.h>
#include <stdlib.h>

#define T(args...)                                              \
  {                                                             \
    int array[] = {args};                                       \
    ranges(array, sizeof(array) / sizeof(*array));              \
  }

int intcmp(const void* a, const void* b)
{
  const int *ai = a;
  const int *bi = b;

  if (*ai < *bi)
    return -1;
  else if (*ai > *bi)
    return 1;
  else
    return 0;
}

int main(void)
{
  T(1,3,4,5,6,8,11,12,14,15,16);
  T();
  T(1);
  T(1, 2);
  T(3, 1);
  T(1, 3, 4);
  T(1, 2, 4);
  T(1, 1, 2, 4);
  T(1, 2, 2, 4);
  T(1, 2, 2, 3, 5, 5);
}

输出:

1,3-6,8,11-12,14-16

1
1-2
1,3
1,3-4
1-2,4
1-2,4
1-2,4
1-3,5


Answer 7:

假设列表进行排序,你可以在年底动工,并保持减去下一个下来。 而不同的是1,你是在一个范围内。 如果它不是,你开始一个新的范围。

16-15 = 1

15-14 = 1

14-12 = 2,该范围为16-14 - 开始一个新的范围。



Answer 8:

startRange = array[0];    
for(i=0;i<array.length;i++)
{
   if (array[i + 1] - array[i] > 1)
   {
     endRange = array[i];
     pushRangeOntoArray(startRange,endRange);
     i++;
     startRange = array[i]
     // need to check for end of array here
   }
}


Answer 9:

这里是我的Perl的解决方案。 可能是更清洁,更快速,但它表明它是如何工作:

# Just in case it's not sorted...
my @list = sort { $a <=> $b } ( 1, 3, 4, 5, 6, 8, 11, 12, 14, 15, 16 );

my $range = [ $list[0] ];

for(@list[1 .. $#list]) {
    if($_ == $range->[-1] + 1) {
        push @$range, $_;
    }
    else {
        print $#$range ? $range->[0] . '-' . $range->[-1] : $range->[0], "\n";
        $range = [ $_ ];
    }
}


Answer 10:

我在Java 1.5的解决办法是:

public static List<String> getRanges(int... in) {
    List<String> result = new ArrayList<String>();
    int last = -1;
    for (int i : in) {
        if (i != (last + 1)) {
            if (!result.isEmpty()) {
                addRange(result, last);
            }
            result.add(String.valueOf(i));
        } 
        last = i;
    }
    addRange(result, last);
    return result;
}

private static void addRange(List<String> result, int last) {
    int lastPosition = result.size() - 1;
    String lastResult = result.get(lastPosition);
    if (!lastResult.equals(String.valueOf(last))) {
        result.set(lastPosition, lastResult + "-" + last);
    }
}

public static void main(String[] args) {
    List<String> ranges = getRanges(1, 3, 4, 5, 6, 8, 11, 12, 14, 15, 16);
    System.out.println(ranges);
}

其输出:

[1, 3-6, 8, 11-12, 14-16]

格尔茨,GHAD



Answer 11:

我相信,被介绍给颠覆了1.5版本的合并信息酒店的格式是一样的,你要问什么,所以你可能会去看看通过颠覆之源,了解他们是如何做到这一点。 我会感到惊讶,如果它不是已经被张贴在这里的其他建议有什么不同。



Answer 12:

我将假定阵列X()是预先排序(如果没有,前手对数组进行排序)。

for each element of X() as $element (with $i as current array posistion)
    add $element to end of array Y()
    if (X($i) + 1 is less than X($i + 1)) AND ($i + 1 is not greater than sizeof(X())) then
        append Y(1)."-".Y(sizeof(Y())) to end of Z()
        unset Y()
    end if    
next
if anything remains in Y() append to end of Z()

好,这是我会怎么做。



Answer 13:

创建包含范围的值开始/结束一个简单的范围类型。 添加一个构造函数,只需要一个值,并将开始=结束=价值。 维持区间物品堆,通过数组的排序复制你的工作方式,扩大高档产品或添加新的范围内适当。 更具体地,当阵列中的值是1个+为对范围对象到所述堆的端值,递增该范围的端值,当它不是,推送新范围(与起始=结束=值在在数组索引)压入堆栈。



Answer 14:

module Main where

ranges :: [Int] -> [[Int]]
ranges [] = []
ranges list@(x:xs) = let adj = adjacent list in
             let len = length adj in
                 if length adj == 1
                then [[x]] ++ ranges xs
                else [[x,(last adj)]] ++ ranges (drop ((length adj) - 1) xs)
    where adjacent [] = []
          adjacent (x:xs) = if (xs /= []) && (x + 1) == head xs
             then [x] ++ adjacent (xs)
             else [x]

main = do putStrLn $ show $ ranges [1,2,3,4,5,6,8,11,12,14,15,16]

-- Output: [[1,6],[8],[11,12],[14,16]]

这是我在Haskell最好的拍摄。



Answer 15:

Perl 6的

sub to_ranges( Int *@data ){
  my @ranges;

  OUTER: for @data -> $item {
    for @ranges -> $range {
      # short circuit if the $item is in a range
      next OUTER if $range[0] <= $item <= $range[1];

      given( $item ){
        when( $range[0]-1 ){ $range[0] = $item }
        when( $range[1]+1 ){ $range[1] = $item }
      }
    }

    push @ranges, [$item,$item];
  }

  return @ranges;
}


Answer 16:

蟒(> = 2.6)

该版本附加处理重复和未分选的序列。

from __future__ import print_function

def ranges(a):
    a.sort()
    i = 0
    while i < len(a):
        start = i
        while i < len(a)-1 and a[i] >= a[i+1]-1:
            i += 1
        print(a[start] if a[start] == a[i] else "%d-%d" % (a[start], a[i]),
              end="," if i < len(a)-1 else "\n")
        i += 1

例:

import random
r = range(10)
random.shuffle(r)
ranges(r)
ranges([1,3,4,5,6,8,11,12,14,15,16]);
ranges([])
ranges([1])
ranges([1, 2])
ranges([1, 3])
ranges([1, 3, 4])
ranges([1, 2, 4])
ranges([1, 1, 2, 4])
ranges([1, 2, 2, 4])
ranges([1, 2, 2, 3, 5, 5])

输出:

0-9
1,3-6,8,11-12,14-16
1
1-2
1,3
1,3-4
1-2,4
1-2,4
1-2,4
1-3,5


文章来源: How would you display an array of integers as a set of ranges? (algorithm)