最长递增子序列问题 - 朴素方法
Issues with Longest Increasing Subsequence - Naive Approach
我正在学习动态规划的基础知识并来到 question of finding the Longest Increasing Subsequence in an array. Before looking up the DP solution, I decided to code it myself and came up with the following algorithm, the complete code to which can be found here。
想法是创建一个List Array来存储所有递增的子序列,并存储每个子序列对应的最大值,以便更快地进行比较。
private void findLIS(int[] inputArr) {
List[] listOfSubs = new ArrayList[inputArr.length]; //Max different subsequences in an array would be N
//To store the max value of each of the subsequences found yet
List<Integer> maxValList = new ArrayList<Integer>();
listOfSubs[0] = new ArrayList<Integer>();
listOfSubs[0].add(inputArr[0]); //Add the first element of the array to the list
maxValList.add(inputArr[0]);
for (int i=1;i<inputArr.length;i++) {
boolean flag = false;
int iter=0;
//Compare inputArr[i] with the maxVal of each subsequence
for (int j=0; j<maxValList.size(); j++) {
if (inputArr[i]>maxValList.get(j)) {
maxValList.set(j, inputArr[i]); //Update the maxVal in the corresponding position in the list
listOfSubs[j].add(inputArr[i]);
flag = true;
}
iter = j;
}
//If inputArr[i] is not greater than any previous values add it to a new list
if (!flag) {
maxValList.add(inputArr[i]);
listOfSubs[iter+1] = new ArrayList<Integer>();
listOfSubs[iter+1].add(inputArr[i]);
}
}
//Finding the maximum length subsequence among all the subsequences
int max=0, iter=0, index=0;
for (List<Integer> lst : listOfSubs) {
if (lst!=null && lst.size() > max) {
max = lst.size();
index=iter;
}
iter++;
}
//Print the longest increasing subsequence found
System.out.println("The Longest Increasing Subsequence is of length " + listOfSubs[index].size() +
" and is as follows:");
for (int i=0;i<listOfSubs[index].size();i++) {
System.out.print(listOfSubs[index].get(i) + " ");
}
}
该代码在 O(n^2) 时间内运行并且完美适用于 small/medium 大小的输入。但是,当我针对某些在线练习门户(例如 HackerRank)尝试 运行 代码时,我得到了 TLE(超出时间限制错误)和错误答案。我理解 TLE 错误,因为有效的解决方案是 DP O(nlogn) 解决方案,但我对该算法生成的错误答案感到困惑。因为,这种情况下的输入太大(~10000),我无法手动验证解决方案出错的地方。
可以找到完整的代码以及对其中一个数据集的输出here。根据 HackerRank 的报告,正确答案应该是 195。
我发现我的解决方案存在问题。问题是因为没有仔细阅读问题陈述。
假设我们将输入视为 {3, 2, 6, 4, 5, 1}。我在我的代码中只考虑序列 {3,6} 和 {2,6},而不考虑序列 {2,4,5} 或 {3,4,5}。因此,在每次迭代中,如果我发现一个数字大于先前子序列的最大值,我会将其添加到所有此类子序列中,从而减少到达后一个子序列的可能性。
我正在学习动态规划的基础知识并来到 question of finding the Longest Increasing Subsequence in an array. Before looking up the DP solution, I decided to code it myself and came up with the following algorithm, the complete code to which can be found here。
想法是创建一个List Array来存储所有递增的子序列,并存储每个子序列对应的最大值,以便更快地进行比较。
private void findLIS(int[] inputArr) {
List[] listOfSubs = new ArrayList[inputArr.length]; //Max different subsequences in an array would be N
//To store the max value of each of the subsequences found yet
List<Integer> maxValList = new ArrayList<Integer>();
listOfSubs[0] = new ArrayList<Integer>();
listOfSubs[0].add(inputArr[0]); //Add the first element of the array to the list
maxValList.add(inputArr[0]);
for (int i=1;i<inputArr.length;i++) {
boolean flag = false;
int iter=0;
//Compare inputArr[i] with the maxVal of each subsequence
for (int j=0; j<maxValList.size(); j++) {
if (inputArr[i]>maxValList.get(j)) {
maxValList.set(j, inputArr[i]); //Update the maxVal in the corresponding position in the list
listOfSubs[j].add(inputArr[i]);
flag = true;
}
iter = j;
}
//If inputArr[i] is not greater than any previous values add it to a new list
if (!flag) {
maxValList.add(inputArr[i]);
listOfSubs[iter+1] = new ArrayList<Integer>();
listOfSubs[iter+1].add(inputArr[i]);
}
}
//Finding the maximum length subsequence among all the subsequences
int max=0, iter=0, index=0;
for (List<Integer> lst : listOfSubs) {
if (lst!=null && lst.size() > max) {
max = lst.size();
index=iter;
}
iter++;
}
//Print the longest increasing subsequence found
System.out.println("The Longest Increasing Subsequence is of length " + listOfSubs[index].size() +
" and is as follows:");
for (int i=0;i<listOfSubs[index].size();i++) {
System.out.print(listOfSubs[index].get(i) + " ");
}
}
该代码在 O(n^2) 时间内运行并且完美适用于 small/medium 大小的输入。但是,当我针对某些在线练习门户(例如 HackerRank)尝试 运行 代码时,我得到了 TLE(超出时间限制错误)和错误答案。我理解 TLE 错误,因为有效的解决方案是 DP O(nlogn) 解决方案,但我对该算法生成的错误答案感到困惑。因为,这种情况下的输入太大(~10000),我无法手动验证解决方案出错的地方。
可以找到完整的代码以及对其中一个数据集的输出here。根据 HackerRank 的报告,正确答案应该是 195。
我发现我的解决方案存在问题。问题是因为没有仔细阅读问题陈述。
假设我们将输入视为 {3, 2, 6, 4, 5, 1}。我在我的代码中只考虑序列 {3,6} 和 {2,6},而不考虑序列 {2,4,5} 或 {3,4,5}。因此,在每次迭代中,如果我发现一个数字大于先前子序列的最大值,我会将其添加到所有此类子序列中,从而减少到达后一个子序列的可能性。