[LeetCode] Sequence Reconstruction 序列重建
Check whether the original sequence org
can be uniquely reconstructed from the sequences in seqs
. The org
sequence is a permutation of the integers from 1 to n, with 1 ≤ n ≤ 104. Reconstruction means building a shortest common supersequence of the sequences in seqs
(i.e., a shortest sequence so that all sequences in seqs
seqs
and it is the org
sequence.
Example 1:
Input: org: [1,2,3], seqs: [[1,2],[1,3]] Output: false Explanation: [1,2,3] is not the only one sequence that can be reconstructed, because [1,3,2] is also a valid sequence that can be reconstructed.
Example 2:
Input: org: [1,2,3], seqs: [[1,2]] Output: false Explanation: The reconstructed sequence can only be [1,2].
Example 3:
Input: org: [1,2,3], seqs: [[1,2],[1,3],[2,3]] Output: true Explanation: The sequences [1,2], [1,3], and [2,3] can uniquely reconstruct the original sequence [1,2,3].
Example 4:
Input: org: [4,1,5,2,6,3], seqs: [[5,2,6,3],[4,1,5,2]] Output: true
這道題給了我們一個序列org,又給我們了一些子序列seqs,問這些子序列能否唯一的重建出原序列。能唯一重建的意思就是任意兩個數字的順序必須是一致的,不能說在一個子序列中1在4的後面,但是在另一個子序列中1在4的前面,這樣就不是唯一的了。還有一點就是,子序列seqs中不能出現其他的數字,就是說必須都是原序列中的數字。那麼我們可以用了一個一維陣列pos來記錄org中每個數字對應的位置,然後用一個flags數字來標記當前數字和其前面一個數字是否和org中的順序一致,用cnt來標記還需要驗證順序的數字的個數,初始化cnt為n-1,因為n個數字只需要驗證n-1對順序即可,然後我們先遍歷一遍org,將每個數字的位置資訊存入pos中,然後再遍歷子序列中的每一個數字,還是要先判斷數字是否越界,然後我們取出當前數字cur,和其前一位置上的數字pre,如果在org中,pre在cur之後,那麼直接返回false。否則我們看如果cur的順序沒被驗證過,而且pre是在cur的前一個,那麼標記cur已驗證,且cnt自減1,最後如果cnt為0了,說明所有順序被成功驗證了,參見程式碼如下:
解法一:
class Solution { public: bool sequenceReconstruction(vector<int>& org, vector<vector<int>>& seqs) { if (seqs.empty()) return false; int n = org.size(), cnt = n - 1; vector<int> pos(n + 1, 0), flags(n + 1, 0); bool existed = false; for (int i = 0; i < n; ++i) pos[org[i]] = i; for (auto& seq : seqs) { for (int i = 0; i < seq.size(); ++i) { existed = true; if (seq[i] <= 0 || seq[i] > n) return false; if (i == 0) continue; int pre = seq[i - 1], cur = seq[i]; if (pos[pre] >= pos[cur]) return false; if (flags[cur] == 0 && pos[pre] + 1 == pos[cur]) { flags[cur] = 1; --cnt; } } } return cnt == 0 && existed; } };
下面這種方法跟上面的方法大同小異,用兩個雜湊表來代替了上面的陣列和變數,其中m為數字和其位置之間的對映,pre為當前數字和其前一個位置的數字在org中的位置之間的對映。跟上面的方法的不同點在於,當遍歷到某一個數字的時候,我們看當前數字是否在pre中有對映,如果沒有的話,我們建立該對映,注意如果是第一個位置的數字的話,其前面數字設為-1。如果該對映存在的話,我們對比前一位數字在org中的位置和當前的對映值的大小,取其中較大值。最後我們遍歷一遍org,看每個數字的對映值是否是前一個數字的位置,如果有不是的返回false,全部驗證成功返回true,參見程式碼如下:
解法二:
class Solution { public: bool sequenceReconstruction(vector<int>& org, vector<vector<int>>& seqs) { unordered_map<int, int> m, pre; for (int i = 0; i < org.size(); ++i) m[org[i]] = i; for (auto& seq : seqs) { for (int i = 0; i < seq.size(); ++i) { if (!m.count(seq[i])) return false; if (i > 0 && m[seq[i - 1]] >= m[seq[i]]) return false; if (!pre.count(seq[i])) { pre[seq[i]] = (i > 0) ? m[seq[i - 1]] : -1; } else { pre[seq[i]] = max(pre[seq[i]], (i > 0) ? m[seq[i - 1]] : -1); } } } for (int i = 0; i < org.size(); ++i) { if (pre[org[i]] != i - 1) return false; } return true; } };
參考資料: