leetcode [491. 遞增子序列] (Rabin-Karp 字串編碼)
(https://leetcode-cn.com/problems/increasing-subsequences/)
這題剛開始自己寫的時候是沒有想到用dfs的,我的想法是開一個vector<vector
for (int i = 0; i < n; i++){ dp[i].push_back({nums[i]}); for (int j = 0; j < i; j++){ if (nums[i] >= nums[j]){ for (auto v : dp[j]){ v.push_back(nums[i]); dp[i].push_back(v); } } } }
但是這樣寫有一個問題,就是最後合併答案的時候,可能會有重複的子序列,這樣就需要解決另一個問題,如何進行序列判重?官方題解中也給出了方法:Rabin-Karp 字串編碼
Rabin-Karp 字串編碼:
這個其實思想很簡單,就將一個數列當成k進位制,k要比這個數列中最大的數大,而且最好選一個質數。在將k進位制轉化為10進位制,這樣一個數列就會對應一個hash值。
但這會存在一個問題,當數列很長的時候,這個ha sh值會很大很大,甚至longlong都裝不下,這樣自然而然就想到了取模,那問題又出現了,會不會有兩個不同的數列他們的hash值不一樣,但取模後就相等了呢?
這就涉及到概率問題了,就直接說結論:,只要我們將模數設定得很大,並且多選擇一些模數,Rabin-Karp 字串編碼產生雜湊碰撞的概率就微乎其微。一般來說,對於演算法題而言,我們只需要選擇一個模數即可,並且它最好是一個質數,例如 10^9+7。如有需要,還可以選擇第二個模數 10^9+9
知道了這個方法,我們就可以進行子序列判重了,將每個長度大於2的子序列進行hash,如果某個子序列的hash值已經存在,就說明這個子序列已經放到答案裡了,不需要重複放
//完整程式碼 const int BASE = 263; const int MOD = 1e9+7; class Solution { public: int GetHash(vector<int> now){ int n = now.size(); int res = 0; for (int i = 0; i < n; i++){ res = (1LL*res*BASE%MOD +(now[i]+101)) % MOD; } return res; } vector<vector<int>> findSubsequences(vector<int>& nums) { int n = nums.size(); if (n == 0) return {}; vector<vector<int>> dp[n]; for (int i = 0; i < n; i++){ dp[i].push_back({nums[i]}); for (int j = 0; j < i; j++){ if (nums[i] >= nums[j]){ for (auto v : dp[j]){ v.push_back(nums[i]); dp[i].push_back(v); } } } } vector<vector<int>> ans; map<int,bool> M; for (int i = 0; i < n; i++){ for (auto v : dp[i]){ int hash = GetHash(v); if (v.size() >= 2 && M.count(hash) == 0){ ans.push_back(v); M[hash] = true; } } } return ans; } };
另一種方法就是dfs,題解中說的應該也挺清楚的,這裡就直接放程式碼了
class Solution {
public:
vector<vector<int>> ans;
void dfs(vector<int>& nums,int begin,vector<int> cnt){
if (cnt.size() >= 2) ans.push_back(cnt);
map<int,bool> M;
for (int i = begin+1; i < nums.size(); i++){
if (begin == -1 || nums[i] >= cnt.back()){
if (M.count(nums[i])) continue;
M[nums[i]] = true;
cnt.push_back(nums[i]);
dfs(nums,i,cnt);
cnt.pop_back();
}
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
ans.clear();
dfs(nums,-1,{});
return ans;
}
};