计算通过删除一项来进行排序的方式数量

时间:2018-08-19 15:14:09

标签: algorithm sorting

我最近遇到了一个基本上是以下问题的变体的问题:

我们想通过从数组中精确删除一项来使数组以不降序排序。我们有多少种方法?

例如,如果输入数组为[3, 4, 5, 4],答案将为2,因为我们可以删除5或第二个4

如果数组为[3, 4, 5, 2],答案将为1,因为我们可以删除2

如果数组是[1, 2, 3, 4, 5],答案将是5,因为我们可以删除任何一个元素。

我正在努力解决这个问题。有关解决方案策略的任何指示/方向都将受到高度赞赏。

3 个答案:

答案 0 :(得分:5)

您提供的示例已经涵盖了大多数情况;答案始终是0、1、2或N,并且您应该能够通过对序列进行一次迭代来找到解决方案。

从左到右遍历数组,以查找相邻元素对,其中左元素大于右元素。

如果到序列的末尾而没有找到减少的对,则该序列已经是非减少的,答案是N。

如果找到一个递减对,请检查删除左元素是否有效,即其前面的元素是否不大于右元素,然后检查删除右元素是否有效,即左元素是否不大于比右边元素后面的元素要大。

如果这两个选项都不起作用,则可以返回答案0,因为不可能使序列不递减;否则,返回0。例如[2,2,1,1]。

如果1个或2个选项起作用,请继续检查其余序列;如果找到另一个递减对,则答案变为0(不可能)。

使用伪代码:

options = 0
for i is 1 to array.length - 1
    if array[i-1] > array[i]
        if options is not 0
            return 0
        if i is 1 or array[i-2] <= array[i]
            ++options
        if i is array.length - 1 or array[i-1] <= array[i+1]
            ++options
        if options is 0
            return 0
if options is 0
    options = array.length
return options

或翻译成简单的Javascript代码段:

function numberOfWays(array) {
    var options = 0
    for (var i = 1; i < array.length; i++) {
        if (array[i-1] > array[i]) {
            if (options != 0) return 0;
            if (i == 1 || array[i-2] <= array[i]) ++options;
            if (i == array.length - 1 || array[i-1] <= array[i+1]) ++options;
            if (options == 0) return 0;
        }
    }
    return (options == 0) ? array.length : options;
}

var arrays = [[1,2,3,4],[1,3,2,4],[1,2,4,3],[1,3,4,2],[2,4,1,3],[2,2,1,1]];
for (var a in arrays)
    document.write(arrays[a] + " &rarr; " + numberOfWays(arrays[a]) + "<br>");

答案 1 :(得分:1)

这是Java中的解决方案

基本上,您维护两个数组 1. endHere数组,其中包含布尔值,该布尔值说明以索引结尾的数组是否已排序 2. startHere数组,其中包含布尔值,该布尔值说明在此处从索引处开始的数组是否已排序

一旦构造了数组,则可以删除索引处的数字,并且如果endHere [i-1]和startHere [i + 1]为true并且arr [i-1] <= arr [i + 1]

public static int noOfWays(int[] arr) {
        int count = 0;
        if (arr != null) {
            if (arr.length != 1) {
                boolean[] startHere = new boolean[arr.length];
                boolean[] endHere = new boolean[arr.length];
                endHere[0] = true;
                startHere[arr.length - 1] = true;
                int j = arr.length - 2;
                for (int i = 1; i < arr.length; i++) {
                    endHere[i] = endHere[i - 1] & (arr[i - 1] <= arr[i]);
                    startHere[j] = startHere[j + 1] & (arr[j] <= arr[j + 1]);
                    j--;
                }
                for (int i = 0; i < arr.length; i++) {
                    boolean leftSorted = true;
                    boolean rightSorted = true;
                    if (i - 1 >= 0)
                        leftSorted = endHere[i - 1];
                    if (i + 1 < arr.length)
                        rightSorted = startHere[i + 1];
                    if (leftSorted && rightSorted) {
                        if (i - 1 >= 0 && i + 1 < arr.length) {
                            if (arr[i - 1] <= arr[i + 1]) 
                                count++;
                        } else 
                            count++;
                    }
                }
            }
        }
        return count;
    }

答案 2 :(得分:0)

我解决了一个类似的问题,检查是否可以仅删除一个元素就可以使给定的整数列表不减量。

bool almostIncreasingSequence(std::vector<int> sequence) {
int err = 0;
int loc = 0;
for(int i=0;i<sequence.size()-1;i++){
    if(sequence[i]>=sequence[i+1]){
        err++;
        loc = i;
    }
}
if(err>1) return false;
if(err==0) return true;

if(loc==0) return true;
else if(loc == sequence.size()-2) return true;

if(sequence[loc-1]<sequence[loc+1]) return true;
if(sequence[loc-1]==sequence[loc+1]){
    if(sequence[loc]<sequence[loc+2])
        return true;
}


return false;
}

我认为这将为您提供解决问题的总体思路。