俄罗斯套娃信封问题 转https://www.jianshu.com/p/9d9495ef4372

286 阅读2分钟

给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

说明:

不允许旋转信封。

示例:

输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出: 3 
解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        if( envelopes.length == 0 || envelopes[0].length == 0 ){
            return 0;
        }
        Arrays.sort( envelopes , new Comparator<int[]>(){
            @Override
            public int compare( int[] o1 , int[] o2 ){
                if( o1[ 0 ] == o2[ 0 ] ){
                    return o1[ 1 ] - o2[ 1 ];
                }
                return o1[ 0 ] - o2[ 0 ];
            }
        } );
        int max = 0;
        int[] dp = new int[ envelopes.length ];
        for( int i = 0 ; i < envelopes.length ; i++ ){
            dp[ i ] = 1;
            for( int j = 0 ; j < i ; j++ ){
                if( envelopes[ i ][ 0 ] > envelopes[ j ][ 0 ] && envelopes[ i ][ 1 ] > envelopes[ j ][ 1 ]  ){
                    dp[ i ] =  Math.max( dp[ j ] + 1 , dp[ i ] );
                }
            }
            max = Math.max( max ,  dp[ i ] );
        }
        return max;
    }
}

针对情况I

当每个信封的宽度和高度不一样时,我们可以对信封按照宽度从小到大进行排序,比如针对信封[[3,2],[2, 4],[4,3],[5, 6],[6,5]排序后变为

w: 2 -> 3 -> 4 -> 5 -> 6

h: 4 -> 2 -> 3 -> 6 -> 5

此时,因为信封的宽度w已经是从小到大排列了,要想信封可以套,这要求关于信封高度h的数组[4, 2, 3, 6, 5]是的子序列是递增的,且要求是最长的(题目要求的是最多的信封),所以可以转化为另一个问题:给定数组,求它的最长递增子序列(也称最长上升子序列)。关于这个问题在leetcode300有具体描述。

最长递增子序列

比如给的数组arr = [3, 1, 2, 5, 4, 6]。

得到的最长递增子序列长度为4,即[1, 2, 5, 6]或[1, 2, 4, 6]。

这个问题的解法是动态规划,给一个相同长度的数组dp,dp[i]表示以arr[i]结尾的最长递增子序列,初始化都为1(本身构成最长递增子序列),即dp[i] = 1, 这个的动态转移方程(递推式)为,j从0到i - 1,如果arr[i] > arr[j], 这dp[i] = max(dp[i], dp[j] + 1)。