AcWing 1490 最長上升子串
題目
給出一個長度爲n
的由正整數構成的序列,你需要從中刪除一個正整數,很顯然你有很多種刪除方式,你需要對刪除這個正整數以後的序列求其最長上升子串,請問在所有刪除方案中,最長的上升子串長度是多少。
這裏給出最長上升子串的定義:即對於序列中連續的若干個正整數,滿足ai+1 > ai
,則稱這連續的若干個整數構成的子串爲上升子串,在所有的上升子串中,長度最長的稱爲最長上升子串。
輸入格式
輸入第一行僅包含一個正整數n
,表示給出的序列的長度。
接下來一行有n
個正整數,即這個序列,中間用空格隔開。
輸出格式
輸出僅包含一個正整數,即刪除一個數字之後的最長上升子串長度。
數據範圍
1 ≤ n ≤ 100000
1 ≤ ai ≤ 100000
輸入樣例:
5
2 1 3 2 5
輸出樣例:
3
思路
這道題我們採用枚舉的做法進行求解,對於序列中任意位置 i
的數字,我們都求出它之前按順序遞增最遠可以到達的距離f[i]
,和它之後按順序遞增最遠可以到達的距離g[i]
,當我們要拿掉一個數字來得到最長上升子串時,我們只需要先判斷拿掉了i
後第i
個元素兩邊是否可以拼接上,如果可以,拿掉i
的連續上升子串的長度即爲f[i - 1] + g[i + 1]
,不能拼接的話即爲max(f[i - 1], g[i + 1])
,最後取所有情況的最大值,即爲最長上升子串的長度
代碼
c++
#include <iostream>
using namespace std;
const int N = 100010;
int nums[N], f[N], g[N];
int n;
int res = 0;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &nums[i]);
for (int i = 1; i <= n; ++i)
if (nums[i] > nums[i - 1]) f[i] = f[i - 1] + 1;
else f[i] = 1;
for (int i = n; i > 0; --i)
if (nums[i] < nums[i + 1]) g[i] = g[i + 1] + 1;
else g[i] = 1;
for (int i = 1; i <= n; ++i) {
if (nums[i - 1] < nums[i + 1]) {
int a = f[i - 1] + g[i + 1];
res = a > res ? a : res;
}
else {
int a = f[i - 1] > g[i + 1] ? f[i - 1] : g[i + 1];
res = a > res ? a : res;
}
}
printf("%d", res);
}
java
package AcWingCode;
import java.util.Scanner;
public class p1490 {
static final int N = 100010;
public static void main(String[] args) {
int n, res = 0;
int nums[] = new int[N];
int f[] = new int[N];
int g[] = new int[N];
Scanner myInput = new Scanner(System.in);
n = myInput.nextInt();
for (int i = 1; i <= n; ++i)
nums[i] = myInput.nextInt();
for (int i = 1; i <= n; ++i) {
if (nums[i] < nums[i - 1]) f[i] = f[i - 1] + 1;
else f[i] = 1;
}
for (int i = n; i >= 1; --i) {
if (nums[i] > nums[i + 1]) g[i] = g[i + 1] + 1;
else g[i] = 1;
}
for (int i = 1; i <= n; ++i) {
if (nums[i - 1] < nums[i + 1]) {
int add = f[i - 1] + g[i + 1];
res = res > add ? res : add;
}
else {
int max = f[i - 1] > g[i + 1] ? f[i - 1] : g[i + 1];
res = res > max ? res : max;
}
}
System.out.println(res);
}
}