import java.util.*; /** * NC163 最长上升子序列(一) * @author d3y1 */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 给定数组的最长严格上升子序列的长度。 * @param arr int整型一维数组 给定的数组 * @return int整型 */ public int LIS (int[] arr) { return solution1(arr); // return solution2(arr); // return solution3(arr); } /** * 动态规划 * * dp[i]表示从前面到以第i个数字结尾的最长上升子序列的长度(arr[i]必须被选取) * * dp[j] = Math.max(dp[j], dp[i]+1) , (arr[i] < arr[j]) * * @param arr * @return */ private int solution1(int[] arr){ int len = arr.length; if(len <= 1){ return len; } int[] dp = new int[len]; Arrays.fill(dp, Integer.valueOf(1)); int result = 1; for(int i=0; i<len; i++){ for(int j=i+1; j<len; j++){ if(arr[i] < arr[j]){ dp[j] = Math.max(dp[j], dp[i]+1); result = Math.max(result, dp[j]); } } } return result; } /** * 动态规划 * * dp[i]表示从前面到以第i个数字结尾的最长上升子序列的长度(arr[i]必须被选取) * * dp[i] = Math.max(dp[i], dp[j]+1) , arr[j] < arr[i] * * @param arr * @return */ private int solution2(int[] arr){ int len = arr.length; if(len <= 1){ return len; } int[] dp = new int[len]; // 初始值 dp[0] = 1; // 最长上升子序列的长度 int max = 1; for(int i=1; i<len; i++){ dp[i] = 1; for(int j=0; j<i; j++){ if(arr[j] < arr[i]){ dp[i] = Math.max(dp[i], dp[j]+1); } } max = Math.max(max, dp[i]); } return max; } /** * 贪心 + 二分 * @param arr * @return */ private int solution3(int[] arr){ int len = arr.length; if(len <= 1){ return len; } // 表示从前面到以第i个数字结尾的最长上升子序列的长度(arr[i]必须被选取) int[] dp = new int[len]; // 最长上升子序列 单调增 int[] seq = new int[len+1]; seq[1] = arr[0]; dp[0] = 1; // 最长上升子序列的长度 int max = 1; for(int i=1; i<len; i++){ if(seq[max] < arr[i]){ seq[++max] = arr[i]; dp[i] = max; }else{ int left=1,right=max; // 上升子序列seq中二分查找最大的小于arr[i]的位置pos int pos = 0; while(left <= right){ int mid = (left + right) >> 1; if(seq[mid] < arr[i]){ pos = mid; left = mid + 1; }else{ right = mid - 1; } } // 替换 seq[pos+1] = arr[i]; dp[i] = pos + 1; } } return max; } }