动态规划(2)

139 阅读1分钟

Day06 递增子序列问题

1、最长递增子序列

  • 思路:
    • 动态规划。一维dp数组表示 以num[i]为结尾的最长递增子序列长度
        class Solution {
        public int lengthOfLIS(int[] nums) {
            int len = nums.length;
            //表示以num[i]为结尾的最长递增子序列长度
            int[] dp = new int[len];
            //最短递增子序列为1
            dp[0] = 1;
            int ans = 1;
            for (int i = 1; i < len; i++) {
                int cur = nums[i];
                //num[i]的前i-1个数中是否存在比num[i]小的数
                dp[i] = 1;
                //查询比cur小的最长递增子序列的长度
                for (int j = i - 1; j >= 0; j--) {
                    if (cur > nums[j]) {
                        dp[i] = Math.max(dp[j] + 1, dp[i]);
                    }
                }
                //记录最大值
                ans = Math.max(ans, dp[i]);
            }
            return ans;
        }
      }
      
    • 贪心+二分查找
      • 要想最长上升,每次上升的数都尽可能小。维护每一个上升子序列的tail值数组tail
      • 当存在一个数大于所有的tail时,应该新起一个上升子序列,即tail数组长度增加
      • tail数组也是递增的(需要证明,抽象理解可以想蜘蛛纸牌)
        class Solution {
        public int lengthOfLIS(int[] nums) {
            int len = nums.length;
            int[] tail = new int[len];
            //最短递增子序列为1
            tail[0] = nums[0];
            int ans = 0;
            for (int i = 1; i < len; i++) {
                //如果nums[i]比当前递增数组的末尾集合的最大值大的话,最长子序列增加
                if (nums[i] > tail[ans]) {
                    tail[++ans] = nums[i];
                } else {
                    //寻找第一个比他小的tail值,并加到他后边
                    int l = 0, r = ans;
                    while (l <= r) {
                        int mid = (l + r) / 2;
                        if (tail[mid] >= nums[i]){
                            r = mid - 1;
                        }else {
                            l = mid + 1;
                        }
                    }
                    tail[l] = nums[i];
                }
            }
            return ans + 1;
        }
      }
      

2、最长连续递增序列

  • 思路:
    • 动态规划
    class Solution {
        public int findLengthOfLCIS(int[] nums) {
    	int[] dp = new int[nums.length];
    	dp[0] = 1;
    	int ans = 1;
    	for (int i = 1; i < nums.length; i++) {
    		if (nums[i] > nums[i - 1]){
    			dp[i] = dp[i - 1] + 1;
    		}else {
    			dp[i] = 1;
    		}
    		ans = Math.max(ans,dp[i]);
    	}
    	return ans;
        }
    }
    
    • 优化空间复杂度
    class Solution {
        public int findLengthOfLCIS(int[] nums) {
    	int ans = 1;
    	int len = 1;
    	for (int i = 1; i < nums.length; i++) {
    		if (nums[i] > nums[i - 1]){
    			len ++;
    		}else {
    			len = 1;
    		}
    		ans = Math.max(ans,len);
    	}
    	return ans;
         }
    }