检查子序列时循环后的重复条件
Duplicate condition after loop when checking subsequences
当我检查子序列时,我总是在循环后复制条件。
例如,我想找出相差不超过1的数的最大子序列。这是我的代码
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
我复制条件是因为如果序列以匹配的子序列结尾,那么如果没有附加条件就不会被计算在内。我想避免代码重复。
我的解决方案需要更改输入。有什么方法可以在不改变输入的情况下避免代码重复。
将代码从条件转移到函数的解决方案不适合,因为它没有消除重复,我仍然需要调用函数两次。
此类问题的一般模式是使用两个“指针”(实际上是列表中的索引):
- 一个“开始”指针,当它指向不属于子序列的元素时递增,直到到达列表的末尾,或者它指向子序列中的第一个元素(在特定在问题的情况下,没有不属于子序列的元素。
- 一个“结束”指针,最初等于开始(或比开始多一个),你递增它直到你到达列表的末尾,或者它指向第一个不属于列表的元素相同的子序列
- 你的子序列在开始和结束之间,分别包含和排除。根据需要进行处理
- 重复循环,起点等于上一个终点,直到到达列表末尾
所以,类似于:
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;
}
另一种使用 map 和 stream 解决它的方法
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)
}
当我检查子序列时,我总是在循环后复制条件。
例如,我想找出相差不超过1的数的最大子序列。这是我的代码
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
我复制条件是因为如果序列以匹配的子序列结尾,那么如果没有附加条件就不会被计算在内。我想避免代码重复。
我的解决方案需要更改输入。有什么方法可以在不改变输入的情况下避免代码重复。
将代码从条件转移到函数的解决方案不适合,因为它没有消除重复,我仍然需要调用函数两次。
此类问题的一般模式是使用两个“指针”(实际上是列表中的索引):
- 一个“开始”指针,当它指向不属于子序列的元素时递增,直到到达列表的末尾,或者它指向子序列中的第一个元素(在特定在问题的情况下,没有不属于子序列的元素。
- 一个“结束”指针,最初等于开始(或比开始多一个),你递增它直到你到达列表的末尾,或者它指向第一个不属于列表的元素相同的子序列
- 你的子序列在开始和结束之间,分别包含和排除。根据需要进行处理
- 重复循环,起点等于上一个终点,直到到达列表末尾
所以,类似于:
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;
}
另一种使用 map 和 stream 解决它的方法
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)
}