【leetcode354】. 俄羅斯套娃信封問題

零點-一條路走到底發表於2020-11-07

給定一些標記了寬度和高度的信封,寬度和高度以整數對形式 (w, h) 出現。當另一個信封的寬度和高度都比這個信封大的時候,這個信封就可以放進另一個信封裡,如同俄羅斯套娃一樣。

請計算最多能有多少個信封能組成一組“俄羅斯套娃”信封(即可以把一個信封放到另一個信封裡面)。

說明:
不允許旋轉信封。

示例:

輸入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
輸出: 3 
解釋: 最多信封的個數為 3, 組合為: [2,3] => [5,4] => [6,7]。

 

把寬度和高度分開看,就是LIS(最長遞增子序列問題),問題是把兩者結合在一起。

首先對問題進行預處理,針對寬度進行升序排序, 針對高進行升序排序,但在相同寬度時,使用降序。

第二步,把高存到陣列中,就是經典的LIS(最長遞增子序列)問題。

 

package problem0354

import "sort"

func maxEnvelopes(e [][]int) int {
	if len(e) <= 1 {
		return len(e)
	}
    // 第一步,進行預處理,針對寬進行升序排序,針對高進行升序排序,但是在相同寬度時使用降序
	sort.Sort(sortedEnvelopes(e))

	tails := make([]int, len(e))

	for i := 0; i < len(e); i++ {
		tails[i] =  e[i][1]
	}
	// 第二步,把高存到陣列中,就是經典的LIS(最長遞增子序列)問題
	return lengthOfLIS(tails)
}

func lengthOfLIS(nums []int) int {
	dp := make([]int, len(nums))
	// 陣列初始化值都為1
	for i := 0; i < len(nums); i++ {
		dp[i] = 1
	}
	res := 0
	for i := 0; i< len(nums); i++ {
		for j := 0; j < i; j++ {
			if nums[j] < nums[i] {
				dp[i] = max(dp[i], dp[j]+1)
			}
		}
		res = max(res, dp[i])
	}

	return res
}

func max(i int, i2 int) int {
	if i > i2 {
		return i
	} else {
		return i2
	}
}

type sortedEnvelopes [][]int

func (s sortedEnvelopes) Len() int {
	return len(s)
}

func (s sortedEnvelopes) Less(i, j int) bool {
	// 寬度相同的情況下,根據高度進行降序排序
	if s[i][0] == s[j][0] {
		// 同樣寬度時,矮信封排在後面
		return s[i][1] > s[j][1]
	}
	return s[i][0] < s[j][0]
}

func (s sortedEnvelopes) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

 

相關文章