动态规划(4)

128 阅读1分钟

Day08 括号匹配、最长递增子序列二维拓展(信封嵌套)

最长有效括号

  • 思路:
    • 难点在 括号匹配且连续

    动态规划个人思路

    • dp[i] 表示以第i个位置为有效括号的最大连续长度
    • 确定括号是否有效
      • 遍历 ( 并入栈。入 当前下标
      • 遍历 ) ,如果此时栈中没有与之匹配的,则dp[i]直接为 0
      • 如果有与之匹配的,dp[y]=dp[i]=dp[y1]+dp[i1]+2dp[y] = dp[i] = dp[y-1] + dp[i - 1] + 2
    class Solution {
        public int longestValidParentheses(String s) {
            char[] array = s.toCharArray();
            Stack<Integer> stack = new Stack<>();
            int ans = 0;
            int[] dp = new int[array.length];
            for (int i = 0; i < array.length; i++) {
                char item = array[i];
                if (item == '(') {
                    stack.push(i);
                } else {
                    if (stack.isEmpty()) {
                        dp[i] = 0;
                    } else {
                        Integer index = stack.pop();
                        int pre = 0, next = 0;
                        if (index - 1 >= 0) {
                            pre = dp[index - 1];
                        }
                        if (index + 1 < array.length) {
                            next = dp[i - 1];
                        }
                        dp[index] = 2 + pre + next;
                        dp[i] = dp[index];
                        ans = Math.max(dp[i], ans);
                    }
                }
            }
            return ans;
        }
    }
    
  • 标准动态规划思路
    • dp[i]表示以i为结尾的有效连续括号长度
    • 当i为 ) 并且对应 i - 1 为 (,则
      • dp[i]=dp[i2]+2dp[i] = dp[i - 2] + 2。上一个结果 +2
        • 注意判断 i - 2的边界
    • 当i为 ) 并且对应 i - 1 为 ),需要考虑前面是否有与之对应匹配的 (
      • 如果有,则它的下标一定为 idp[i1]1 i - dp[i - 1] - 1。前一个有效括号的 ( 的上一个
        • 注意判断 idp[i1]1 i - dp[i - 1] - 1的边界
      • 如果确实满足,还需要 和之前的dp数组是否能连接上
      • dp[i]=dp[i1]+dp[idp[i1]2]+2dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2
        • 注意判断idp[i1]2i - dp[i - 1] - 2 的边界
    class Solution {
        public int longestValidParentheses(String s) {
            int ans = 0;
            int[] dp = new int[s.length()];
            for (int i = 1; i < s.length(); i++) {
                char item = s.charAt(i);
                if (item == ')') {
                    if (s.charAt(i - 1) == '(') {
                        dp[i] = (i - 2 >= 0 ? dp[i - 2] : 0) + 2;
                    } else if (i - dp[i - 1] - 1 >= 0 
                    && s.charAt(i - dp[i - 1] - 1) == '(') {
                        // )对应的有效括号跟他对象的(之前的 dp时候能连接在一起
                        dp[i] = dp[i - 1] 
                        + ((i - dp[i - 1] - 2) >= 0 ? dp[i - dp[i - 1] - 2] : 0)
                        + 2;
                    }
                    ans = Math.max(ans, dp[i]);
                }
            }
            return ans;
        }
    }
    
    • 当前元素为 ( 时,下标入栈。栈始终维护最后一个匹配的 ) 的下标
    • 当前元素为 ) 时,先从栈中出栈
      • 当栈为空,将当前下标i入栈。维护最后一个匹配的 )
      • 栈不为空,ans=istack.peek()ans = i - stack.peek()
    class Solution {
       public int longestValidParentheses(String s) {
           int ans = 0;
           //stack存储上一个没有被匹配的)的下标
           Stack<Integer> stack = new Stack<>();
           stack.push(-1);
           for (int i = 0; i < s.length(); i++) {
               char item = s.charAt(i);
               if (item == '(') {
                   stack.push(i);
               } else {
                   stack.pop();
                   if (stack.isEmpty()) {
                       stack.push(i);
                   } else {
                       ans = Math.max(ans, i - stack.peek());
                   }
               }
           }
           return ans;
       }
    }
    

2、俄罗斯套娃信封问题

  • 思路:
    • 控制二维中的一维有序,然后在另一维上进行递增子序列求解
    class Solution {
        public int maxEnvelopes(int[][] envelopes) {
    	//按照宽度进行升序排序,当宽度一样时
                //,按照高度进行倒序排序(保证,相同宽度但高度大的不被计算在结果内)
    	PriorityQueue<int[]> queue = new PriorityQueue<>((a,b)->{
    		if (a[0] == b[0]){
    			return b[1] - a[1];
    		}else {
    			return a[0] - b[0];
    		}
    	});
    	for (int[] item : envelopes) {
    		queue.offer(item);
    	}
    	int[] arr = new int[envelopes.length];
    	for (int i = 0; i < arr.length; i++) {
    		arr[i] = queue.poll()[1];
    	}
    	return lengthOfLIS(arr);
            }
            private int lengthOfLIS(int[] arr){
    	int[] tail = new int[arr.length];
    	tail[0] = arr[0];
    	int last = 0;
    	for (int i = 1; i < arr.length; i++) {
    		int item = arr[i];
    		if (item > tail[last]){
    			tail[++last] = item;
    		}else {
    			int l = 0, r = last;
    			while (l <= r){
    				int mid = l + (r - l) / 2;
    				if (tail[mid] >= item){
    					r = mid - 1;
    				}else {
    					l = mid + 1;
    				}
    			}
    			tail[l] = item;
    		}
    	}
    	return last + 1;
    }
    }