1. 程式人生 > 實用技巧 >牛牛的數列

牛牛的數列

連結:https://ac.nowcoder.com/acm/problem/13134
來源:牛客網

題目

牛牛現在有一個n個數組成的數列,牛牛現在想取一個連續的子序列,並且這個子序列還必須得滿足:最多隻改變一個數,就可以使得這個連續的子序列是一個嚴格上升的子序列,牛牛想知道這個連續子序列最長的長度是多少。

思路

題目的想法是改變數列中的一個數字後,可以使該數字的前面和後面嚴格遞增序列合併成一個更大的數列。例如陣列[7 2 3 1 5 6],該陣列有三個嚴格遞增數列分別是[7]、[2 3] 和[1 5 6],那麼對於序列[7]和[2 3]來說,要合併他們的話,必須改變數字2且2前面數字要小於2後面的數字。同理看序列[2 3]和[1 5 6],要合併兩個序列必須保證1的前面一個數字小於1後面那個數字,這樣改變1後可以將倆個嚴格遞增的序列合併成更大的序列。所以該題目解法的基本思路是檢視陣列中的每個嚴格遞增序列是否能和後一個嚴格遞增序列進行合併

為了較快找到一個嚴格遞增的序列,設定兩個陣列left[]和right[]。left[]陣列是記錄以第i個數字為結尾的嚴格遞增連續子序列的長度,right[]陣列是記錄以第i個數字為開頭的嚴格遞增連續子序列的長度。還是以陣列a = [7 2 3 1 5 6]為例,left = [1 1 2 1 2 3],right = [1 2 1 3 2 1],那麼我們可以在o(1)時間內確定兩個遞增序列合併後的長度:在陣列a中,要合併序列[7]和[2 3],則判斷a[1]=2的前一個數字a[0]和後一個數字a[2]是否滿足a[0] < a[2],因為不滿足所以無法通過修改a[1]的數字合併兩個序列;再判斷是否能夠合併[2 3]和[1 5 6],因為a[2] < a[4],所以可以通過修改a[3]這個數字合併兩個序列,合併後的長度為left[2] + right[4] + 1。

總結

要想通過改變一個數字後得到更大的嚴格上升子序列,那麼必然是在改變一個數字後能將兩個相鄰的嚴格上升子序列進行合併得到一個更大的嚴格上升子序列,所以該題可以化簡為判斷相鄰的兩個嚴格上升子序列是否能合併,若能合併則記錄合併後最大的長度。

java程式碼

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        
long[] arr = new long[n]; for(int i=0; i<n; i++) { arr[i] = in.nextInt(); } long[] left = new long[n], right = new long[n]; left[0] = 1; for (int i = 1; i < n; i++) { left[i] = arr[i] > arr[i - 1] ? left[i - 1] + 1 : 1; } right[n-1] = 1; for (int i = n - 2; i >= 0; i--) { right[i] = arr[i] < arr[i + 1] ? right[i + 1] + 1 : 1; } long max = 1; for (int i = 1; i < n - 1; i++) { if (arr[i - 1] < arr[i + 1]) { max = max < left[i - 1] + right[i + 1] + 1 ? left[i - 1] + right[i + 1] + 1 : max; } } System.out.println(max); } }