給出兩個整數 n 和 k,找出所有包含從 1 到 n 的數字,且恰好擁有 k 個逆序對的不同的陣列的個數。
逆序對的定義如下:對於陣列的第i個和第 j個元素,如果滿i < j且 a[i] > a[j],則其為乙個逆序對;否則不是。
由於答案可能很大,只需要返回 答案 mod 109 + 7 的值。
示例 1:
輸入:n = 3, k = 0
輸出:1
解釋:
只有陣列 [1,2,3] 包含了從1到3的整數並且正好擁有 0 個逆序對。
示例 2:
輸入:n = 3, k = 1
輸出:2
解釋:
陣列 [1,3,2] 和 [2,1,3] 都有 1 個逆序對。
說明:
n 的範圍是 [1, 1000] 並且 k 的範圍是 [0, 1000]。
這道題給了我們1到n總共n個數字,讓我們任意排列陣列的順序,使其剛好存在k個翻轉對,所謂的翻轉對,就是位置在前面的數字值大,而且題目中表明了結果會很大很大,要我們對乙個很大的數字取餘。對於這種結果巨大的題目,勸君放棄暴力破解或者是無腦遞迴,想都不用想,那麼最先應該考慮的就是dp的解法了。我們需要乙個二維的dp陣列,其中dp[i][j]表示1到i的數字中有j個翻轉對的排列總數,那麼我們要求的就是dp[n][k]了,即1到n的數字中有k個翻轉對的排列總數。現在難點就是要求遞推公式了。我們想如果我們已經知道dp[n][k]了,怎麼求dp[n+1][k],先來看dp[n+1][k]的含義,是1到n+1點數字中有k個翻轉對的個數,那麼實際上在1到n的數字中的某個位置加上了n+1這個數,為了簡單起見,我們先讓n=4,那麼實際上相當於要在某個位置加上5,那麼加5的位置就有如下幾種情況:
***x5
***5x
xx5xx
x5***
5***x
這裡***x表示1到4的任意排列,那麼第一種情況***x5不會增加任何新的翻轉對,因為***x中沒有比5大的數字,而 ***5x會新增加1個翻轉對,xx5xx,x5***,5***x分別會增加2,3,4個翻轉對。那麼***x5就相當於dp[n][k],即dp[4][k],那麼依次往前類推,就是dp[n][k-1], dp[n][k-2]...dp[n][k-n],這樣我們就可以得出dp[n+1][k]的求法了:
dp[n+1][k] = dp[n][k] + dp[n][k-1] + ... + dp[n][k - n]
那麼dp[n][k]的求法也就一目了然了:
dp[n][k] = dp[n - 1][k] + dp[n - 1][k-1] + ... + dp[n - 1][k - n + 1]
那麼我們就可以寫出**如下了:
1class
solution 12}
13}14}
15return
dp[n][k];16}
17 }
我們可以對上面的解法進行時間上的優化,還是來看我們的遞推公式:
dp[n][k] = dp[n - 1][k] + dp[n - 1][k-1] + ... + dp[n - 1][k - n + 1]
我們可以用k+1代替k,得到:
dp[n][k+1] = dp[n - 1][k+1] + dp[n - 1][k] + ... + dp[n - 1][k + 1 - n + 1]
用第二個等式減去第乙個等式可以得到:
dp[n][k+1] = dp[n][k] + dp[n - 1][k+1] - dp[n - 1][k - n + 1]
將k+1換回成k,可以得到:
dp[n][k] = dp[n][k-1] + dp[n - 1][k] - dp[n - 1][k - n]
我們可以發現當k>=n的時候,最後一項的陣列座標才能為非負數,從而最後一項才有值,所以我們再更新的時候只需要判斷一下k和n的關係,如果k>=n的話,就要減去最後一項,這種遞推式算起來更高效,減少了乙個迴圈,參見**如下:
1class
solution 12}
13return
f[n][k];14}
15 }
LeetCode 629 K個逆序對陣列
略。首先,1 n 這 n 個數所能產生的最大逆序對為 n n 1 2 對。設 dp i j 表示 1 i 能產生 j 對逆序對的排列種數。這裡定義一下如果下標為負數,這一項為 0。在考慮接下來乙個事實 對於序列 1,2,3,4,5 和 2,5,7,9,10,在這個問題下,我可以說這兩個序列是等價的,...
Leetcode 629 K個逆序對陣列 C
給出兩個整數 n 和 k,找出所有包含從 1 到 n 的數字,且恰好擁有 k 個逆序對的不同的陣列的個數。逆序對的定義如下 對於陣列的第i個和第 j個元素,如果滿i j且 a i a j 則其為乙個逆序對 否則不是。由於答案可能很大,只需要返回 答案 mod 109 7 的值。示例 1 輸入 n 3...
629 K個逆序對陣列
給出兩個整數 n 和 k,找出所有包含從 1 到 n 的數字,且恰好擁有 k 個逆序對的不同的陣列的個數。逆序對的定義如下 對於陣列的第i個和第 j個元素,如果滿i j且 a i a j 則其為乙個逆序對 否則不是。由於答案可能很大,只需要返回 答案 mod 109 7 的值。示例 1 輸入 n 3...