本题使用回溯法,深度优先搜索。使用隐式条件来进行加速。
public class Solution { int bestp = 0; int[] x; Dictionary<int, int> dic = new Dictionary<int, int>(); void Backtrack(int[] nums, int t) { if (t >= nums.Length) { var sum = 0; for (int i = 0; i < nums.Length; i++) { if (x[i] == 1) { //Console.Write(nums[i]+" "); sum++; } } //Console.WriteLine(); bestp = Math.Max(bestp, sum); return; } if (dic.Count == 0 || dic.LastOrDefault().Value < nums[t]) { x[t] = 1; dic.Add(t, nums[t]); Backtrack(nums, t + 1); dic.Remove(t); } if (dic.Count + nums.Length - (t + 1) > bestp) { x[t] = 0; Backtrack(nums, t + 1); } } public int LengthOfLIS(int[] nums) { if (nums.Length < 2) { return nums.Length; } x = new int[nums.Length]; Backtrack(nums, 0); return bestp; } }
补充一个使用动态规划的方法,使用python实现,但是效率不是很高:
1 class Solution: 2 def lengthOfLIS(self, nums: 'List[int]') -> 'int': 3 n = len(nums) 4 if n==0: 5 return 0 6 maxnum = 0 7 dp = [1] * n 8 for i in range(n): 9 for j in range(i): 10 if nums[i] > nums[j]: 11 dp[i] = max(dp[i],dp[j] + 1) 12 print(dp[i]) 13 maxnum = max(maxnum,dp[i]) 14 return maxnum
思路分析:双层循环,时间复杂度是O(n^2)。
dp[i]表示在nums中,以nums[i]为结尾的自增子序列的长度。
第13行是在外层循环,每次循环结束的时候更新,全局的最长自增子序列的长度,也就是所求。
内层循环,是从当前位置i,向前寻找[0,i-1]闭区间。如果在nums中,i前面有一个元素j,满足nums[i] > nums[j],则可以在以j为结尾的自增子序列上,增加1的长度,构成新的自增子序列,而dp[i]只保存这些可能构成的新自增子序列中最大的长度。
补充一个java的实现,使用二分查找加速查询,提升效率
1 class Solution { 2 public int lengthOfLIS(int[] nums) { 3 int n = nums.length; 4 int[] tails = new int[n]; 5 int len = 0; 6 for (int num : nums) { 7 int index = binarySearch(tails, len, num); 8 tails[index] = num; 9 if (index == len) { 10 len++; 11 } 12 } 13 return len; 14 } 15 16 private int binarySearch(int[] tails, int len, int key) { 17 int l = 0, h = len; 18 while (l < h) { 19 int mid = l + (h - l) / 2; 20 if (tails[mid] == key) { 21 return mid; 22 } else if (tails[mid] > key) { 23 h = mid; 24 } else { 25 l = mid + 1; 26 } 27 } 28 return l; 29 } 30 }