在Python中检查数字是否按递增顺序排列

16
我正在解决一个问题,确定数字是否按升序排列。现在,我采用的方法是,例如,考虑数字5678。
为了检查5678是否是升序列,我取出第一位数字、下一位数字和最后一位数字,即5,6,8,并将它们代入range函数中,即range(first,last,(diff of first digit and the next to first digit)),即range(5,8+1,abs(5-6))。结果是升序排列的数字列表。
对于这个问题,有一个限制条件,即“对于递增序列,数字0应该在数字9之后,而不是在数字1之前,例如7890”。现在我的程序在输入7890时出现错误。我不知道如何编码这个逻辑。可以有人帮帮我吗?
升序列的代码是:
  len(set(['5','6','7','8']) - set(map(str,range(5,8+1,abs(5-6))))) == 0 

1
每个数字必须比上一个数字大一吗? - John Gordon
是的 @JohnGordon - James K J
2
目前被接受的答案似乎在78901上失败了。 - גלעד ברקן
抱歉,我没有注意到!! - James K J
1
从9到0并不是增加,无论你的问题陈述如何。问题陈述措辞不当。 - jpmc26
显示剩余2条评论
8个回答

31

您可以将数字转换为字符串并检查该字符串是否是'1234567890'的子字符串:

str(num) in '1234567890'

2
简单明了,完美回答。干得好。 - Jean-François Fabre
这个例子失败了,例如对于 '901',根据 OP 的定义是递增的(09 之后,显然 10 之后),但实际上不是。 - Jörg W Mittag
6
OP表示“0应该在9之后,而不是在1之前”,因此901不是有效的递增序列,因为0不应该出现在1之前。 - blhsing
1
这太聪明了。+1 - Parthapratim Neog
愿上帝保佑那个人。 - Amos Machora

3
你可以将数字的字符串表示与其自身进行位移并压缩,然后一起迭代连续的数字。使用 all 来检查数字是否跟随,并使用取模 10 来处理 0 的情况。
num = 7890

result = all((int(y)-int(x))%10 == 1 for x,y in zip(str(num),str(num)[1:]))

1
你可以通过使用zip(*[iter(str(num))] * 2)来避免双重str和切片,但我想在这种情况下它的开销更大...只是随便说一下... - Jon Clements
3
根据 OP 所说的“0 应该在 9 后面而不是在 1 前面”,这个函数会错误地返回 True,比如对于数值 78901。 - blhsing
@JonClements 不错,但在这种情况下,我会事先创建一个字符串。 - Jean-François Fabre

2

既然您已经拥有压缩版本,这里提供一种替代解决方案:

最初的回答

import sys


order = dict(enumerate(range(10)))
order[0] = 10

def increasing(n):
    n = abs(n)
    o = order[n % 10] + 1
    while n:
        n, r = divmod(n, 10)
        if o - order[r] != 1:
            return False
        o = order[r]
    return True


for n in sys.argv[1:]:
    print n, increasing(int(n))

1
n, r = divmod(n, 10) - thebjorn
感谢@thebjorn,令人惊讶的是,在SOI上我每天都在学习新东西 :) - khachik

2
我会创建一个自行车发电机并进行切片:

最初的回答

from itertools import cycle, islice

num = 5678901234

num = tuple(str(num))
print(num == tuple(islice(cycle(map(str, range(10))), int(num[0]), int(num[0]) + len(num))))

这种方法比检查每个数字之间的差异的解决方案更快。当然,你可以牺牲长度来使其更快:

最初的回答:

def digits(num):
    while num:
        yield num % 10
        num //= 10

def check(num):
    num = list(digits(num))
    num.reverse()
    for i, j in zip(islice(cycle(range(10)), num[0], num[0] + len(num)), num):
        if i != j:
          return False
    return True

1

以下是我的想法,只看数字并在发现不一致时退出:

def f(n):
  while (n):
    last = n % 10
    n = n / 10
    if n == 0:
      return True
    prev = n % 10
    print last, prev
    if prev == 0 or prev != (last - 1) % 10:
      return False

print f(1234)
print f(7890)
print f(78901)
print f(1345)

这应该是被接受的答案。没有字符串转换,纯数学计算。保证速度更快。 - TerryA

1

不知怎么的,这个问题让我想起了回文,这让我以一种不同的方式思考了这个问题。

5   6   7   8
8   7   6   5
-------------
13  13  13  13

9   0   1
1   0   9
---------
10  0   10


9   0   1   2
2   1   0   9
-------------
11  1   1   11

这导致了这个解决方案和测试。
pos_test_data = [5678, 901, 9012, 9012345678901]
neg_test_data = [5876, 910, 9021]

def monotonic_by_one(n):
    fwd = str(n)
    tgt = ord(fwd[0]) + ord(fwd[-1])
    return all([ord(f) + ord(r) in (tgt, tgt - 10) for f, r in zip(fwd, reversed(fwd))])


print("Positive: ", all([monotonic_by_one(n) for n in pos_test_data]))
print("Negative: ", all([not monotonic_by_one(n) for n in neg_test_data]))

结果:

Positive:  True
Negative:  True

不必使用完整的列表推导式,你可以使用for循环,在第一次失败时退出。我想要查看正在检查的数字的大小并计时,以决定哪种方法更快。


0
一个简单的解决方案是检查序列中的下一个数字,然后使用 current_number + 1 == next_number 来检测序列。
import bisect

def find_next(x, a):
  i = bisect.bisect_right(x, a)
  if i:
    return x[i]
  return None

def is_sequence(x):
  ans = True
  for i in x[:-1]:
    next_num = find_next(x, i)
    if next_num and i+1 != next_num:
      ans = False
      break
  return ans

print(is_sequence([1,2,3,4])) # True

0

我会尝试这个,为了可读性有点啰嗦:

seq = list(input())
seq1 = seq[1:]
seq2 = seq[:-1]

diff = [x-y for x,y in zip([int(x) if int(x)>0 else 10 for x in seq1],[int(x) if int(x)>0 else 10 for x in seq2])]

if any (t != 1 for t in diff) :
    print('not <<<<<')
else :
    print('<<<<<<')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接