给定一个整数数组,最简单的方法是什么来遍历它并找出它所覆盖的所有范围?例如,对于这样的数组:
$numbers = array(1,3,4,5,6,8,11,12,14,15,16);
范围将是:
1,3-6,8,11-12,14-16
给定一个整数数组,最简单的方法是什么来遍历它并找出它所覆盖的所有范围?例如,对于这样的数组:
$numbers = array(1,3,4,5,6,8,11,12,14,15,16);
1,3-6,8,11-12,14-16
Range
结构或类。然后遍历数组。如果当前元素比前一个元素多1,则更新 Range.end ,否则使用此元素创建一个新的范围作为 Range.begin 。将范围存储到动态数组或链接列表中。或者在进行操作时直接打印它们。
如果数组未排序,则先对其进行排序。
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
我知道,我知道,这不是一个算法,但我发现如果没有缩进问题,很难解释它,所以我选择实现一个解决方案。
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;
}
}
你好,David
第一步:排序 第二步:分词 然后:打印第一个值并循环遍历后续值。如果“当前”值等于上一个值+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>
它类似于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
i.e
16-15 = 1
15-14 = 1
14-12 = 2,范围为16-14 - 开始一个新的范围。
我相信在Subversion 1.5版本中引入的合并信息属性具有与您所要求的相同的格式,因此您可以潜在地查看Subversion的源代码以找出他们是如何实现的。我会很惊讶如果它与已经发布在这里的其他建议有任何不同。
我会假设数组X()已经预先排序(如果没有,先对数组进行排序)。
对于X()中的每个元素$element(使用$i作为当前数组位置) 将$element添加到数组Y()的末尾 如果(X($i)+1小于X($i+1))且($i+1不大于sizeof(X())),则 将Y(1)-Y(sizeof(Y()))附加到Z()的末尾 取消设置Y() end if 下一个 如果Y()中仍有任何内容,则将其附加到Z()的末尾。
好吧,这就是我会做的方式。