【问题标题】:Duplicate condition after loop when checking subsequences检查子序列时循环后重复条件
【发布时间】:2021-10-20 11:46:35
【问题描述】:

当我检查子序列时,我总是在循环之后复制条件。

例如,我想找到相差不超过一的数字的最大子序列。这是我的代码

public static List<Integer> maxSubsequence(List<Integer> array) {
    int ind = 0;
    int bestInd = 0;
    int cnt = 1;
    int maxCnt = 0;

    for(int i = 1; i < array.size(); i++) {
        if(Math.abs(array.get(ind) - array.get(i)) <= 1) {
            cnt++;
            continue;
        }

        if(cnt > maxCnt) {
            bestInd = ind;
            maxCnt = cnt;
        }

        if(Math.abs(array.get(ind) - array.get(i)) == 2) {
            cnt--;
            ind++;
            i--;
        } else {
            cnt = 1;
            ind = i;
        }
    }

    // duplicate from loop
    if(cnt > maxCnt) {
        bestInd = ind;
        maxCnt = cnt;
    }

    return array.subList(bestInd, bestInd + maxCnt);
}
for sequence 5, 1, 2, 3, 3, 3 answer is 2, 3, 3, 3

我正在复制条件,因为如果序列以匹配的子序列结尾,那么如果没有附加条件,它将不会被计算在内。我想避免代码重复。

我的解决方案需要更改输入。有什么方法可以在不改变输入的情况下避免代码重复。

将代码从条件转移到函数的解决方案不适合,因为它没有消除重复,我仍然需要调用函数两次。

【问题讨论】:

  • 为什么你的例子中的答案不是 2,3,3,3?
  • @JoachimIsaksson 这是一个错误。修复。输出真的应该是2, 3, 3, 3

标签: java code-duplication


【解决方案1】:

此类问题的一般模式是使用两个“指针”(实际上是列表中的索引):

  • “开始”指针,当它指向不属于子序列的元素时递增,直到到达列表末尾,或者它指向子序列中的第一个元素(在特定情况下问题中的问题,没有元素不是子序列的一部分)。
  • 一个“结束”指针,最初等于开始(或比开始多一个),您递增该指针直到到达列表的末尾,或者它指向不属于列表的第一个元素相同的子序列
  • 然后,您的子序列位于开始和结束之间,分别包含和排除。根据需要处理它
  • 重复循环,开始等于前一个结束,直到到达列表的末尾

所以,类似:

int start = 0;
while (start < list.size()) {
  // Increase end as much as you can for this subsequence
  int end = start + 1;
  while (end < list.size()) {
    if (/* condition meaning you don't want to increment end any more */) {
      break;
    }
    end++;
  }

  // See if this subsequence is "best"
  int cnt = end - start;
  if (cnt > maxCnt) {
    bestInd = start;
    maxCnt = cnt;
  }

  // Prepare for next iteration.
  start = end;
}

【讨论】:

  • 感谢您的回答,这个问题的两个指针确实工作得很好。但我提供的代码仅作为典型示例。我想了解如何摆脱重复条件。条件重复的另一个示例:stackoverflow.com/q/68689372/15777370
  • @vszholobov 你可以在那里应用完全相同的模式:因为结束指针最终指向下一个子序列的第一个元素,或者字符串的结尾,所以自然会处理字符串的结尾以同样的方式。
  • 真的。第二个问题也可以通过两个指针来解决。现在我看到了模式
【解决方案2】:

另一种使用地图和流解决它的方法

public static List<Integer> maxSubsequence(List<Integer> array) {

    Map<Integer, List<Integer>> result = new HashMap<>();
    List<Integer> firstArray = new ArrayList<>();
    firstArray.add(array.get(0));
    result.put(1, firstArray);
    for (int i = 0; i < array.size() - 1; i++) {
        if (Math.abs(array.get(i) - array.get(i + 1)) <= 1) {
            result.get(result.size()).add(array.get(i + 1));
        } else {
            firstArray = new ArrayList<>();
            firstArray.add(array.get(i + 1));
            result.put(result.size() + 1, firstArray);
        }
    }

    return result.values().stream().max(Comparator.comparingInt(List::size))
            .orElse(null); // add filter if you do not want to return and arraylist of single element like this .filter(ar -> ar.size() != 1)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    • 2011-09-09
    • 2015-10-27
    • 2016-01-19
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多