我最近遇到了一个基本上是以下问题的变体的问题:
我们想通过从数组中精确删除一项来使数组以不降序排序。我们有多少种方法?
例如,如果输入数组为[3, 4, 5, 4]
,答案将为2,因为我们可以删除5
或第二个4
。
如果数组为[3, 4, 5, 2]
,答案将为1
,因为我们可以删除2
。
如果数组是[1, 2, 3, 4, 5]
,答案将是5
,因为我们可以删除任何一个元素。
我正在努力解决这个问题。有关解决方案策略的任何指示/方向都将受到高度赞赏。
答案 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] + " → " + 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;
}
我认为这将为您提供解决问题的总体思路。