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
are subsequences of it). Determine whether there is only one sequence that can be reconstructed from 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; } };
參考資料:
https://leetcode.com/problems/sequence-reconstruction/submissions/
https://discuss.leetcode.com/topic/65737/concise-c-solution-inspired-by-previous-great-solutions
https://discuss.leetcode.com/topic/65961/simple-solution-one-pass-using-only-array-c-92ms-java-16ms