解决几乎增加的序列(Codefights)

时间:2017-03-25 13:57:22

标签: python arrays

给定一个整数序列作为数组,通过从数组中删除不超过一个元素来确定是否可以获得严格增加的序列。

实施例

对于序列[1, 3, 2, 1],输出应为:

almostIncreasingSequence(sequence) = false;

为了获得严格增加的序列,此数组中没有一个元素可以删除。

对于序列[1, 3, 2],输出应为:

almostIncreasingSequence(sequence) = true.

您可以从数组中删除3以获得严格增加的序列[1,2]。或者,您可以删除2以获得严格增加的序列[1,3]。

我的代码:

def almostIncreasingSequence(sequence):
    c= 0
    for i in range(len(sequence)-1):
        if sequence[i]>=sequence[i+1]:
            c +=1
    return c<1

但它无法通过所有测试。

input: [1, 3, 2]
Output:false
Expected Output:true

Input: [10, 1, 2, 3, 4, 5]
Output: false
Expected Output: true

Input: [0, -2, 5, 6]
Output: false
Expected Output: true

input:  [1, 1]
Output: false
Expected Output: true

Input: [1, 2, 3, 4, 3, 6]
Output: false
Expected Output: true

Input: [1, 2, 3, 4, 99, 5, 6]
Output: false
Expected Output: true

22 个答案:

答案 0 :(得分:25)

你的算法太简单了。你有一个正确的想法,检查连续的元素对,前面的元素小于后面的元素,但需要更多元素。

制作一个例程first_bad_pair(sequence),用于检查所有元素对按顺序排列的列表。如果是,请返回值-1。否则,返回前面元素的索引:这将是从0n-2的值。然后一个可行的算法是检查原始列表。如果它工作正常,但如果没有尝试删除较早或较晚的违规元素。如果其中任何一个工作,罚款,否则不好。

我可以想到其他算法,但这个算法似乎最简单。如果您不喜欢通过组合原始列表的两个切片而生成的最多两个临时列表,则可以使用更多if语句在原始列表中进行比较来完成等效。

这是通过您显示的所有测试的Python代码。

def first_bad_pair(sequence):
    """Return the first index of a pair of elements where the earlier
    element is not less than the later elements. If no such pair
    exists, return -1."""
    for i in range(len(sequence)-1):
        if sequence[i] >= sequence[i+1]:
            return i
    return -1

def almostIncreasingSequence(sequence):
    """Return whether it is possible to obtain a strictly increasing
    sequence by removing no more than one element from the array."""
    j = first_bad_pair(sequence)
    if j == -1:
        return True  # List is increasing
    if first_bad_pair(sequence[j-1:j] + sequence[j+1:]) == -1:
        return True  # Deleting earlier element makes increasing
    if first_bad_pair(sequence[j:j+1] + sequence[j+2:]) == -1:
        return True  # Deleting later element makes increasing
    return False  # Deleting either does not make increasing

如果您确实想要避免使用这些临时列表,则此处的其他代码具有更复杂的配对检查例程。

def first_bad_pair(sequence, k):
    """Return the first index of a pair of elements in sequence[]
    for indices k-1, k+1, k+2, k+3, ... where the earlier element is
    not less than the later element. If no such pair exists, return -1."""
    if 0 < k < len(sequence) - 1:
        if sequence[k-1] >= sequence[k+1]:
            return k-1
    for i in range(k+1, len(sequence)-1):
        if sequence[i] >= sequence[i+1]:
            return i
    return -1

def almostIncreasingSequence(sequence):
    """Return whether it is possible to obtain a strictly increasing
    sequence by removing no more than one element from the array."""
    j = first_bad_pair(sequence, -1)
    if j == -1:
        return True  # List is increasing
    if first_bad_pair(sequence, j) == -1:
        return True  # Deleting earlier element makes increasing
    if first_bad_pair(sequence, j+1) == -1:
        return True  # Deleting later element makes increasing
    return False  # Deleting either does not make increasing

这是我用过的测试。

print('\nThese should be True.')
print(almostIncreasingSequence([]))
print(almostIncreasingSequence([1]))
print(almostIncreasingSequence([1, 2]))
print(almostIncreasingSequence([1, 2, 3]))
print(almostIncreasingSequence([1, 3, 2]))
print(almostIncreasingSequence([10, 1, 2, 3, 4, 5]))
print(almostIncreasingSequence([0, -2, 5, 6]))
print(almostIncreasingSequence([1, 1]))
print(almostIncreasingSequence([1, 2, 3, 4, 3, 6]))
print(almostIncreasingSequence([1, 2, 3, 4, 99, 5, 6]))
print(almostIncreasingSequence([1, 2, 2, 3]))

print('\nThese should be False.')
print(almostIncreasingSequence([1, 3, 2, 1]))
print(almostIncreasingSequence([3, 2, 1]))
print(almostIncreasingSequence([1, 1, 1]))

答案 1 :(得分:5)

这是我的。希望您觉得这很有帮助:

def almostIncreasingSequence(sequence):

    #Take out the edge cases
    if len(sequence) <= 2:
        return True

    #Set up a new function to see if it's increasing sequence
    def IncreasingSequence(test_sequence):
        if len(test_sequence) == 2:
            if test_sequence[0] < test_sequence[1]:
                return True
        else:
            for i in range(0, len(test_sequence)-1):
                if test_sequence[i] >= test_sequence[i+1]:
                    return False
                else:
                    pass
            return True

    for i in range (0, len(sequence) - 1):
        if sequence[i] >= sequence [i+1]:
            #Either remove the current one or the next one
            test_seq1 = sequence[:i] + sequence[i+1:]
            test_seq2 = sequence[:i+1] + sequence[i+2:]
            if IncreasingSequence(test_seq1) == True:
                return True
            elif IncreasingSequence(test_seq2) == True:
                return True
            else:
                return False

答案 2 :(得分:4)

您的适度算法在这里失败的原因(除了返回的'='之外)是,它只是对大于下一个的元素进行计数,如果该计数大于1,则返回结果。

重要的是每次删除一个元素后查看列表,并确认它仍然是 sorted 列表。

我的尝试确实很简短,并且适用于所有情况。仅在练习中,它就没有对最后一个隐藏测试集的时间约束。

enter image description here

正如问题名称所暗示的,我直接想将列表与排序后的版本进行比较,并在以后处理“几乎”的情况-这样就具有了几乎增加的序列。即:

if sequence==sorted(sequence):
   .
   .

但正如问题所述:

  

确定是否有可能通过从数组中一次(一次)删除不超过一个元素来获得严格增加的序列。

我通过在迭代过程中一次删除一个元素来开始可视化列表,并检查列表的其余部分是否是其自身的排序版本。因此带我到这里:

for i in range(len(sequence)):
    temp=sequence.copy()
    del temp[i]
    if temp==sorted(temp):
        .
        .

在这里,我可以看到,如果整个列表都满足此条件,那么我们就有了所需要的-几乎是递增的序列!因此,我以这种方式完成了代码:

def almostIncreasingSequence(sequence):
    t=0
    for i in range(len(sequence)):
        temp=sequence.copy()
        del temp[i]
        if temp==sorted(temp):
            t+=1
    return(True if t>0 else False)

此解决方案在诸如[1、1、1、2、3]之类的列表上仍然失败。 正如@ rory-daulton在他的评论中指出的那样,我们需要在此问题中区分“排序”和“递增序列”。在对测试[1、1、1、2、3]进行排序时,它按问题要求的顺序递增。为了解决这个问题,下面是添加了一行条件以检查连续的相同数字的最终代码:

def almostIncreasingSequence(sequence):
    t=0
    for i in range(len(sequence)):
        temp=sequence.copy()
        del temp[i]
        if temp==sorted(temp) and not(any(i==j for i,j in zip(sorted(temp), sorted(temp)[1:]))):
            t+=1
    return t>0

由于仍然无法通过最后一次测试的执行时间限制(列表必须很大),因此我仍在寻找是否有一种方法可以优化我的解决方案。

答案 3 :(得分:1)

我还在为我工作。写得像这样,但我不能通过最后3个隐藏的测试。

def almostIncreasingSequence(sequence):

boolMe = 0
checkRep = 0

for x in range(0, len(sequence)-1):

    if sequence[x]>sequence[x+1]:
        boolMe = boolMe + 1
        if (x!=0) & (x!=(len(sequence)-2)):
            if sequence[x-1]>sequence[x+2]:
                boolMe = boolMe + 1
    if sequence.count(sequence[x])>1:
        checkRep = checkRep + 1

    if (boolMe > 1) | (checkRep > 2):    
        return False
return True

答案 4 :(得分:1)

这是一个非常酷的练习。

我是这样做的:

def almostIncreasingSequence(list):
  removedIdx = []                   #Indexes that need to be removed

  for idx, item in enumerate(list):
    tmp = []                        #Indexes between current index and 0 that break the increasing order
    for i in range(idx-1, -1, -1):
      if list[idx]<=list[i]:        #Add index to tmp if number breaks order
        tmp.append(i)
    if len(tmp)>1:                  #If more than one of the former numbers breaks order  
      removedIdx.append(idx)        #Add current index to removedIdx
    else:
      if len(tmp)>0:                #If only one of the former numbers breaks order
        removedIdx.append(tmp[0])   #Add it to removedIdx
  return len(set(removedIdx))<=1

print('\nThese should be True.')
print(almostIncreasingSequence([]))
print(almostIncreasingSequence([1]))
print(almostIncreasingSequence([1, 2]))
print(almostIncreasingSequence([1, 2, 3]))
print(almostIncreasingSequence([1, 3, 2]))
print(almostIncreasingSequence([10, 1, 2, 3, 4, 5]))
print(almostIncreasingSequence([0, -2, 5, 6]))
print(almostIncreasingSequence([1, 1]))
print(almostIncreasingSequence([1, 2, 3, 4, 3, 6]))
print(almostIncreasingSequence([1, 2, 3, 4, 99, 5, 6]))
print(almostIncreasingSequence([1, 2, 2, 3]))

print('\nThese should be False.')
print(almostIncreasingSequence([1, 3, 2, 1]))
print(almostIncreasingSequence([3, 2, 1]))
print(almostIncreasingSequence([1, 1, 1]))
print(almostIncreasingSequence([1, 1, 1, 2, 3]))

答案 5 :(得分:1)

使用Python3,我开始使用这样的东西......

def almostIncreasingSequence(sequence):
    for i, x in enumerate(sequence):
        ret = False
        s = sequence[:i]+sequence[i+1:]
        for j, y in enumerate(s[1:]):
            if s[j+1] <= s[j]:
                ret = True
                break
            if ret:
                break
        if not ret:
            return True
    return False

但在Check#29上保持超时。

当我意识到这也有效时,我踢了自己,但仍然超过#29。我不知道如何加快速度。

def almostIncreasingSequence(sequence):
    for i, x in enumerate(sequence):    
        s = sequence[:i]
        s.extend(sequence[i+1:])
        if s == sorted(set(s)):
            return True
    return False

答案 6 :(得分:1)

这是我的简单解决方案

def almostIncreasingSequence(sequence):
    removed_one = False
    prev_maxval = None
    maxval = None
    for s in sequence:
        if not maxval or s > maxval:
            prev_maxval = maxval
            maxval = s
        elif not prev_maxval or s > prev_maxval:
            if removed_one:
                return False
            removed_one = True
            maxval = s
        else:
            if removed_one:
                return False
            removed_one = True
    return True

答案 7 :(得分:1)

嗯,这也是我的解决方案, 我认为它比这里提出的其他解决方案要干净一些,因此我将其介绍如下。

它的作用是基本上检查索引 i 的值是否大于(i + 1)的索引(如果找到了这样的索引)索引,检查是否删除这两个列表中的任何一个会使列表按递增顺序排列。

def almostIncreasingSequence(sequence):

    def is_increasing(lst):
        for idx in range(len(lst)-1):
            if lst[idx] >= lst[idx + 1]:
                return False
        return True

    for idx in range(len(sequence) - 1):
        if sequence[idx] >= sequence[idx + 1]:
            fixable = is_increasing([*sequence[:idx], *sequence[idx+1:]]) or is_increasing([*sequence[:idx+1], *sequence[idx+2:]])
            if not fixable:
                return False

    return True

答案 8 :(得分:1)

只要您遇到以下情况,就有两种可能性 sequence [i-1]> = sequence [i]

  • 删除索引i-1
  • 删除索引i

因此,我的想法是创建副本并删除索引,并检查索引是否已排序,然后最后可以执行or或返回,如果可以得到ans。 复杂度为O(N2)[由于del]和空间O(N)

def almostIncreasingSequence(sequence):
    c0,c1=1,1
    n=len(sequence)
    l1=[]
    l2=[]
    for i in sequence:
        l1.append(i)
        l2.append(i)
    for i in range(1,n):
        if sequence[i-1]>=sequence[i]:
            del l1[i]
            del l2[i-1]
            break
    for i in range(1,n-1):
        if l1[i-1]>=l1[i]:
            c0=0
            break
    for i in range(1,n-1):
        if l2[i-1]>=l2[i]:
            c1=0
            break
    return bool(c0 or c1)

这是公认的解决方案。

答案 9 :(得分:1)

该解决方案接近于直观的解决方案,即检查序列中的当前项是否大于当前最大值(根据定义,该值是严格递增序列中的前一项)。

问题在于,在某些情况下,您应该删除违反上述规定的当前项目,而在其他情况下,您应该删除之前较大的项目。

例如考虑以下内容:

[1, 2, 5, 4, 6]

您检查值为 4 的 item 处的序列,发现它违反了递增序列规则。在此示例中,很明显您应该删除前一项 5,并且考虑原因很重要。原因是值 4 大于“前一个”最大值(5 之前的最大值,在本例中为 2),因此 5是异常值,应该被删除。

接下来考虑以下事项:

[1, 4, 5, 2, 6]

您检查值为 2 的 item 处的序列,发现它违反了递增序列规则。在此示例中,2 不大于 4 的“前一个”最大值,因此 2 是异常值,应删除。

现在您可能会争辩说,上述每个场景的净效果是相同的 - 从序列中删除一个项目,我们可以使用计数器进行跟踪。
然而,重要的区别在于您如何更新 maximumprevious_maximum 值:

  • 对于 [1, 2, 5, 4, 6],因为 5 是异常值,4 应该成为新的 maximum

  • 对于 [1, 4, 5, 2, 6],因为 2 是异常值,5 应保留为 maximum

这种区别对于评估序列中的其他项目至关重要,确保我们正确忽略之前的异常值。

以下是基于上述描述的解决方案(O(n) 复杂度和 O(1) 空间):

def almostIncreasingSequence(sequence):
    removed = 0
    previous_maximum = maximum = float('-infinity')
    for s in sequence:
        if s > maximum:
            # All good
            previous_maximum = maximum
            maximum = s
        elif s > previous_maximum:
            # Violation - remove current maximum outlier
            removed += 1
            maximum = s
        else:
            # Violation - remove current item outlier
            removed += 1
        if removed > 1:
            return False
    return True

我们最初将 maximumprevious_maximum 设置为 -infinity,并定义了一个值为 removed 的计数器 0

第一个测试用例是“通过”用例,它只是更新 maximumprevious_maximum 值。

第二个测试用例在 s <= maximum 时触发,并检查是否 s > previous_maximum - 如果为真,则前一个 maximum 值是异常值并被删除,{{1} } 更新为新的 s 并且 maximum 计数器递增。

第三个测试用例在 removeds <= maximum 时触发 - 在这种情况下,s <= previous_maximum 是异常值,因此删除了 s({{1} }} 和 s) 和 maximum 计数器递增。

要考虑的一个边缘情况如下:

previous_maximum

对于这种情况,第一项是异常值,但我们只有在检查第二项 (removed) 时才知道这一点。此时,[10, 1, 2, 3, 4]1maximum10,因此 previous_maximum(或任何第一项大于第二项的序列)将被正确识别为异常值。

答案 10 :(得分:1)

仅使用一次循环数组的 C++ 答案

bool almostIncreasingSequence(std::vector<int> a) 
{
    int n=a.size(), p=-1, c=0;
    
    for (int i=1;i<n;i++)
      if (a[i-1]>=a[i]) 
        p=i, c++;
    
    if (c>1) return 0;
    if (c==0) return 1;
    if (p==n-1 || p==1) return 1;
    if (a[p-1] < a[p+1]) return 1;
    if (a[p-2] < a[p]) return 1;
    return 0;
}

答案 11 :(得分:1)

def almostIncreasingSequence(sequence):
    if len(sequence) == 1:
        return True
    
    decreasing = 0
    for i in range(1,len(sequence)):
        if sequence[i] <= sequence[i-1]:
            decreasing +=1
            if decreasing > 1:
                return False
        
        if sequence[i] <= sequence[i-2] and i-2 >=0:
            if i != len(sequence)-1 and sequence[i+1] <= sequence[i-1]:
                return False
    return True

答案 12 :(得分:0)

这是 Swift 中的解决方案。

func almostIncreasingSequence(sequence: [Int]) -> Bool {

var alreadyRemoved = false

//Check for adjacent values

for i in 0..<sequence.count - 1 {
    if sequence[i] >= sequence[i+1] {
        if alreadyRemoved { return false }
        alreadyRemoved = true
    }
    //Check for not adjacent values | Expample [1, 2, 1, 2]

if i + 3 <= sequence.count - 1 && sequence[i] >= sequence[i+2] && sequence[i+1] >= sequence[i+3] {
        return false
    }
    
}
return true

}

答案 13 :(得分:0)

这是另一种解决方案。通过所有测试。只有一种方法。一过 清单。

def几乎递增序列(序列):

count = 0

if len(sequence) < 3:
    return True
for i in range(1, len(sequence) - 2): #to test only inner elements
    if (sequence[i] >= sequence[i+1]): 
        count += 1
        if count == 2:  # the second time this occurs
            return False
        #check if skipping one of these items solves the problem
        if sequence[i-1] >= sequence[i+1] and sequence[i] >= sequence[i+2]:
            return False
        i += 1
#handle the first element
if sequence[0] >= sequence[1]:
    count += 1
    if count == 2:
        return False
#handle the last element
if sequence[-2] >= sequence[-1] and count == 1:
    return False            
return True 

答案 14 :(得分:0)

我花了一整天试图让它尽可能短,但没有运气。但这是我在 CodeSignal 中接受的答案。

def almostIncreasingSequence(sequence):
    if len(sequence)<=2:
        return True
    
    def isstepdown(subsequence):
        return [a>=b for a,b in zip(subsequence, subsequence[1:])]
    
    stepdowns = isstepdown(sequence)
    n_stepdown = sum(stepdowns)
    if n_stepdown>1:
        return False
    else:
        sequence2 = sequence.copy()
        
        sequence.pop(stepdowns.index(True))
        stepdowns_temp = isstepdown(sequence)
        n_stepdown = sum(stepdowns_temp)

        sequence2.pop(stepdowns.index(True)+1)
        stepdowns_temp = isstepdown(sequence2)
        n_stepdown += sum(stepdowns_temp)   
        if n_stepdown<=1:
            return True
        else:
            return False

答案 15 :(得分:0)

这是我的,运行良好。我只是删除了建议的元素,看看新列表是否严格增加

检查列表是否严格递增。我首先检查是否有任何重复项。然后我检查排序列表是否与原始列表相同

import numpy as np

def IncreasingSequence(sequence):
    temp=sequence.copy()
    temp.sort()
    if (len(sequence) != len(set(sequence))):
        return False
    if (sequence==temp):
        return True
    
    return False
def almostIncreasingSequence(sequence):

    for i in range(len(sequence)-1):
        if sequence[i] >= sequence[i+1]:
            sequence_temp=sequence.copy()
            sequence_temp.pop(i)
            # print(sequence_temp)
            # print(IncreasingSequence(sequence_temp))
            if (IncreasingSequence(sequence_temp)):
                return True
            # Might be the neighbor that is worth removing
            sequence_temp=sequence.copy()
            sequence_temp.pop(i+1)
            if (IncreasingSequence(sequence_temp)):
                return True
    
    return False

答案 16 :(得分:0)

def almostIncreasingSequence(sequence):
    if len(sequence) == 1:
        return False
    if len(sequence) == 2:
        return True
    c = 0
    c1 = 0
    for i in range(1,len(sequence)):
        if sequence[i-1] >= sequence[i]:
            c += 1
        if i != 0 and i+1 < len(sequence):
            if sequence[i-1] >= sequence[i+1]:
                c1 += 1
        if c > 1 or c1 > 1:
            return False
    return c1 == 1 or c == 1

答案 17 :(得分:0)

这个很好用。

bool almostIncreasingSequence(std::vector<int> sequence) {
/*
if(is_sorted(sequence.begin(), sequence.end())){
    return true;
    }
*/
int max = INT_MIN;
int secondMax  = INT_MIN;
int count = 0;
int i = 0;

while(i < sequence.size()){
    if(sequence[i] > max){
        secondMax = max;
        max = sequence[i];

}else if(sequence[i] > secondMax){
        max = sequence[i];
        count++;
        cout<<"count after increase = "<<count<<endl;
    }else {count++; cout<<"ELSE count++ = "<<count<<endl;}


    i++;
}

return count <= 1;


}

答案 18 :(得分:0)

这是我的解决方案,

def几乎增加了序列(sequence):

def hasIncreasingOrder(slicedSquence, lengthOfArray):
    count =0
    output = True
    while(count < (lengthOfArray-1)) :
        if slicedSquence[count] >= slicedSquence[count+1] :
            output = False
            break
        count = count +1
    return output

count = 0
seqOutput = False
lengthOfArray = len(sequence)
while count < lengthOfArray:
    newArray = sequence[:count] + sequence[count+1:] 
    if hasIncreasingOrder(newArray, lengthOfArray-1):
        seqOutput = True
        break
    count = count+1
return seqOutput

答案 19 :(得分:0)

这在大多数情况下都有效,除了性能存在问题。

def almostIncreasingSequence(sequence):
    if len(sequence)==2:
        return sequence==sorted(list(sequence))
    else:
        for i in range(0,len(sequence)):
            newsequence=sequence[:i]+sequence[i+1:]
            if (newsequence==sorted(list(newsequence))) and len(newsequence)==len(set(newsequence)):
                return True
                break
            else:
                result=False
    return result

答案 20 :(得分:0)

下面是我使用的Python3代码,它运行良好:

def almostIncreasingSequence(sequence):
flag = False

if(len(sequence) < 3):
    return True

if(sequence == sorted(sequence)):
    if(len(sequence)==len(set(sequence))):
        return True

bigFlag = True
for i in range(len(sequence)):
    if(bigFlag and i < len(sequence)-1 and sequence[i] < sequence[i+1]):
        bigFlag = True
        continue
    tempSeq = sequence[:i] + sequence[i+1:]
    if(tempSeq == sorted(tempSeq)):
        if(len(tempSeq)==len(set(tempSeq))):
            flag = True
            break
    bigFlag = False
return flag

答案 21 :(得分:0)

boolean almostIncreasingSequence(int[] sequence) {
    int length = sequence.length;
    if(length ==1) return true;
    if(length ==2 && sequence[1] > sequence[0]) return true;
    int count = 0;
    int index = 0;
    boolean iter = true;

    while(iter){
        index = checkSequence(sequence,index);
        if(index != -1){
            count++;
            index++;
            if(index >= length-1){
                iter=false;
            }else if(index-1 !=0){
                if(sequence[index-1] <= sequence[index]){
                    iter=false;
                    count++;
                }else if(((sequence[index] <= sequence[index-2])) && ((sequence[index+1] <= sequence[index-1]))){
                    iter=false;
                    count++;                    
                }
            }
        }else{
            iter = false;
        }
    }
    if(count > 1) return false;
    return true;
}

 int checkSequence(int[] sequence, int index){
    for(; index < sequence.length-1; index++){
        if(sequence[index+1] <= sequence[index]){
            return index; 
        }
    }
    return -1;
}
相关问题