简体   繁体   English

查找数组是否可以转换为严格递增的顺序

[英]finding if an array can be converted to strictly increasing order

I have a porblem that I almost solved it but I'm facing problem with one test case, giving an array of numbers, it is allowed to choose any number and swap it digits so the array become strictly increasing, for example: [2, 4, 800, 12], we can choose 800 and convert it to 008 then array become [2,4,008,12], so it should return true, and it is allowed to it once, so the task is to check if it possible to convert an array to strictly increasing with at most one swap, here is my code我有一个几乎解决了它的问题,但是我遇到了一个测试用例的问题,给出了一个数字数组,允许选择任何数字并交换它的数字,因此数组变得严格增加,例如:[2, 4, 800, 12],我们可以选择 800 转换成 008 然后数组变成 [2,4,008,12],所以它应该返回 true,并且允许它一次,所以任务是检查是否可能将数组转换为最多一次交换严格增加,这是我的代码

def solution(numbers):
    swapped = 0
    for i in range(len(numbers)-1):
        if numbers[i] > numbers[i+1]:
            if swapped >= 1:
                return False

            s1= int(''.join(sorted(str(numbers[i]))))
            if s1 < numbers[i+1]:
                if i > 0 and s1 >= numbers[i-1]:
                    numbers[i] = s1
                    swapped += 1
                    continue

            s2 = int(''.join(sorted(str(numbers[i+1]), reverse=True)))
            if s2 >= numbers[i]:
                numbers[i+1] = s2
                swapped += 1
                continue
    return True

the only test case the code doesn't pass is [13,31,30] (returning True instead of False ) and I don't know how to solve this problem.代码没有通过的唯一测试用例是 [13,31,30] (返回True而不是False ),我不知道如何解决这个问题。

(apologies for any an un-elegant parts in my question, I'm new to this world and I'm trying my best) (为我的问题中任何不优雅的部分道歉,我是这个世界的新手,我正在尽我所能)

Your logic is largely right, except that I would put the check for the swap at the end of the loop, and I would check all the permutations instead of just the smallest and largest integer created from the digits.您的逻辑基本上是正确的,除了我会在循环结束时检查交换,并且我会检查所有排列,而不仅仅是从数字创建的最小和最大整数。

from itertools import permutations, pairwise
def soln(numbers):
    swapped = 0
    for i in range(len(numbers)):
        perms = list(int(''.join(shuffled_digits)) for shuffled_digits in permutations(str(numbers[i])))
        if i == 0:
            candidate_nums = [shuffled_number for shuffled_number in perms if shuffled_number < numbers[i+1]]
        elif i < len(numbers) - 1:
            candidate_nums = [shuffled_number for shuffled_number in perms if numbers[i-1] < shuffled_number < numbers[i+1]]
        else:
            candidate_nums = [shuffled_number for shuffled_number in perms if shuffled_number > numbers[i-1]]
        if candidate_nums:
            swapped_num = candidate_nums.pop()
            numbers[i] = swapped_num
            swapped +=1
    if all(x < y for x, y in pairwise(numbers)):
        return True
    return False

Output输出

In [80]: inlist                                                                                                                                                          
Out[80]: [2, 4, 8, 12]

In [81]: soln(inlist)                                                                                                                                                    
Out[81]: True

In [82]: inlist = [2, 4, 800, 12]                                                                                                                                        

In [83]: soln(inlist)                                                                                                                                                    
Out[83]: True

In [84]: inlist = [21, 21]                                                                                                                                               

In [85]: soln(inlist)                                                                                                                                                    
Out[85]: True

In [86]: inlist = [2, 1, 9, 7]                                                                                                                                           

In [87]: soln(inlist)                                                                                                                                                    
Out[87]: False

In [88]: inlist = [2, 1, 1]                                                                                                                                              

In [89]: soln(inlist)                                                                                                                                                    
Out[89]: False

In [90]: inlist = [100, 2, 3]                                                                                                                                            

In [91]: soln(inlist)                                                                                                                                                    
Out[91]: True

In [92]: inlist = [52, 53, 36]                                                                                                                                                      

In [93]: soln(inlist)                                                                                                                                                               
Out[93]: True

In [94]: inlist = [44,37,74]                                                                                                                                                        

In [95]: soln(inlist)                                                                                                                                                               
Out[95]: True

The code mentioned in the question also fails for this testcase: [52,31,30]问题中提到的代码对于这个测试用例也失败了:[52,31,30]

Here's the solution that returns True if there's atleast one increasing array / list by swapping only one number.如果通过仅交换一个数字至少有一个增加的数组/列表,则这是返回 True 的解决方案。

def solution(numbers):
    # Converts to str
    numbers = [str(i) for i in numbers]

    n = len(numbers)

    for j in range(n + 1):
        if j != n:
            # Reverse number
            numbers[j] = str(numbers[j])[::-1]
        # Checks if the array is in increasing order
        if all([int(numbers[i + 1]) > int(numbers[i]) for i in range(n - 1)]):
            return True

        if j != n:
            numbers[j] = str(numbers[j])[::-1]
    return False

When you have a candidate number that needs to change, I would suggest making a directed search in the (virtual) list of permutations to find the permutation whose value is as close as possible to the value you compared with in order to restore the strictly ascending order.当您有需要更改的候选编号时,我建议在(虚拟)排列列表中进行定向搜索,以找到其值尽可能接近您比较的值的排列,以恢复严格升序命令。

It is not necessary to generate all permutations for this, which would consume too much time and space when the number of digits in the input numbers exceeds 10.不需要为此生成所有排列,当输入数字中的位数超过 10 时,这将消耗过多的时间和空间。

The idea is to count the number of digits you have of each digit, in the number that needs a permutation, and then take the next digit for building a permutation in such a way that you stay as close as possible to the target value.这个想法是计算每个数字的位数,在需要排列的数字中,然后以尽可能接近目标值的方式取下一个数字来构建排列。 Some backtracking is needed, but for each digit position at most 2 attempts are needed: one for a digit that exactly matches the digit in the target (the value to compare with), and potentially a second attempt with another digit.需要进行一些回溯,但对于每个数字位置,最多需要 2 次尝试:一次用于与目标中的数字(要比较的值)完全匹配的数字,并且可能与另一个数字进行第二次尝试。

Here is an implementation of that idea.这是该想法的实现。

First a helper function to find a permutation of a given value that is as near as possible to a target value (but not equal to it), and must be either less or greater (last argument controls this):首先是一个辅助函数,用于找到尽可能接近目标值(但不等于它)的给定值的排列,并且必须小于或大于(最后一个参数控制它):

def permute_near(value, target, side=1):
    # If side is 1, we will look for the minimum permutation of value that is
    #   greater than the target.
    # If side is -1, we will look for the maximum permutation of value that is 
    #   less than the target.
    freedigit = 0 if side == 1 else 9
    end = freedigit + 10*side
    target += side
    # Get a count for each digit of value (could also use Counter module for this)
    s = str(value)
    n = len(s)
    digits = [0]*10
    for digit in s:
        digits[int(digit)] += 1
    # Pad the target value to have the same number of digits
    limit = [int(digit) for digit in str(target).rjust(n, "0")]

    # Use recursion to find the permutation of value that is nearest to the target
    def recur(k, isfree, accumulator):
        if k >= n:  # All digits were processed, we have the result
            return accumulator
        limitdigit = limit[k]
        for i in range(freedigit if isfree else limitdigit, end, side):
            if digits[i]:
                digits[i] -= 1  # Select this digit for the permutation
                permutation = recur(k + 1, isfree or i != limitdigit, accumulator * 10 + i)
                digits[i] += 1  # Backtrack
                if permutation > -1 or i != limitdigit:
                    return permutation
                # If it failed for the case where the chosen digit was the same
                #   as in the target, try with one alternative digit in a 
                #   second and also last iteration of this loop.
        return -1
        
    return recur(0, False, 0)

Here is the main function:这是主要功能:

def solution(numbers):
    try:
        # Find the first index where the next value is not greater
        i = next(i for i, val in enumerate(numbers) if val >= numbers[i+1])
    except:
         return numbers # The input is already completely ascending
    # Permute numbers[i], so it becomes less than its successor
    result = permute_near(numbers[i], numbers[i+1], -1)
    # Check that such permutation exists, and is still greater than its predecessor
    if result >= 0 and (i == 0 or numbers[i - 1] < result):
        numbers[i] = result  # OK, we have success
    else:
        #  ... or permute numbers[i+1], so it becomes greater than its predecessor
        result = permute_near(numbers[i+1], numbers[i], 1)
        # Check that such permutation exists, and is still less than its successor
        if result >= 0 and (i + 2 >= len(numbers) or result < numbers[i + 2]):
            numbers[i + 1] = result  # OK, we have success
    if all(a < b for a, b in zip(numbers, numbers[1:])):
        return numbers

Some runs:一些运行:

# A few test cases
print(solution([2,4,800,12]))  # [2, 4, 8, 12]
print(solution([44,37,74]))    # [44, 73, 74]
print(solution([52,53,36]))    # [52, 53, 63]
print(solution([64,52,53]))    # [46, 52, 53]
print(solution([89221173000,89221173456,13437127829,89221173477])) 
   # [89221173000, 89221173456, 89221173473, 89221173477]

The function returns the adjusted list if there is a solution, None otherwise.如果有解决方案,该函数返回调整后的列表,否则返回无。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM