Python 根據(jù)相鄰關(guān)系還原數(shù)組的兩種方式(單向構(gòu)造和雙向構(gòu)造)
題目描述
這是 LeetCode 上的 1743. 從相鄰元素對(duì)還原數(shù)組 ,難度為 中等。
Tag : 「哈希表」、「雙指針」、「模擬」
存在一個(gè)由 n 個(gè)不同元素組成的整數(shù)數(shù)組 nums ,但你已經(jīng)記不清具體內(nèi)容。好在你還記得 nums 中的每一對(duì)相鄰元素。
給你一個(gè)二維整數(shù)數(shù)組 adjacentPairs ,大小為 n - 1 ,其中每個(gè) adjacentPairs[i] = [ui, vi] 表示元素 ui 和 vi 在 nums 中相鄰。
題目數(shù)據(jù)保證所有由元素 nums[i] 和 nums[i+1] 組成的相鄰元素對(duì)都存在于 adjacentPairs 中,存在形式可能是 [nums[i], nums[i+1]] ,也可能是 [nums[i+1], nums[i]] 。這些相鄰元素對(duì)可以 按任意順序 出現(xiàn)。
返回 原始數(shù)組 nums 。如果存在多種解答,返回 其中任意一個(gè) 即可。
示例 1:
輸入:adjacentPairs = [[2,1],[3,4],[3,2]]
輸出:[1,2,3,4]
解釋:數(shù)組的所有相鄰元素對(duì)都在 adjacentPairs 中。
特別要注意的是,adjacentPairs[i] 只表示兩個(gè)元素相鄰,并不保證其 左-右 順序。
示例 2:
輸入:adjacentPairs = [[4,-2],[1,4],[-3,1]]
輸出:[-2,4,1,-3]
解釋:數(shù)組中可能存在負(fù)數(shù)。
另一種解答是 [-3,1,4,-2] ,也會(huì)被視作正確答案。
示例 3:
輸入:adjacentPairs = [[100000,-100000]]
輸出:[100000,-100000]
提示:
- nums.length == n
- adjacentPairs.length == n - 1
- adjacentPairs[i].length == 2
- 2 <= n <= 10510^5105
- -10510^5105 <= nums[i], ui, vi <= 10510^5105
- 題目數(shù)據(jù)保證存在一些以 adjacentPairs 作為元素對(duì)的數(shù)組
單向構(gòu)造(哈希表計(jì)數(shù))
根據(jù)題意,由于所有的相鄰關(guān)系都會(huì)出現(xiàn)在 numsnumsnums 中,假設(shè)其中一個(gè)合法數(shù)組為 ansansans,長(zhǎng)度為 nnn。
那么顯然 ans[0]ans[0]ans[0] 和 ans[n−1]ans[n - 1]ans[n−1] 在 numsnumsnums 中只存在一對(duì)相鄰關(guān)系,而其他 ans[i]ans[i]ans[i] 則存在兩對(duì)相鄰關(guān)系。
因此我們可以使用「哈希表」對(duì) numsnumsnums 中出現(xiàn)的數(shù)值進(jìn)行計(jì)數(shù),找到“出現(xiàn)一次”的數(shù)值作為 ansansans 數(shù)值的首位,然后根據(jù)給定的相鄰關(guān)系進(jìn)行「單向構(gòu)造」,為了方便找到某個(gè)數(shù)其相鄰的數(shù)是哪些,我們還需要再開一個(gè)「哈希表」記錄相鄰關(guān)系。

Java 代碼:
class Solution {
public int[] restoreArray(int[][] aps) {
int m = aps.length, n = m + 1;
Map<Integer, Integer> cnts = new HashMap<>();
Map<Integer, List<Integer>> map = new HashMap<>();
for (int[] ap : aps) {
int a = ap[0], b = ap[1];
cnts.put(a, cnts.getOrDefault(a, 0) + 1);
cnts.put(b, cnts.getOrDefault(b, 0) + 1);
List<Integer> alist = map.getOrDefault(a, new ArrayList<>());
alist.add(b);
map.put(a, alist);
List<Integer> blist = map.getOrDefault(b, new ArrayList<>());
blist.add(a);
map.put(b, blist);
}
int start = -1;
for (int i : cnts.keySet()) {
if (cnts.get(i) == 1) {
start = i;
break;
}
}
int[] ans = new int[n];
ans[0] = start;
ans[1] = map.get(start).get(0);
for (int i = 2; i < n; i++) {
int x = ans[i - 1];
List<Integer> list = map.get(x);
for (int j : list) {
if (j != ans[i - 2]) ans[i] = j;
}
}
return ans;
}
}
Python 3 代碼:
class Solution:
def restoreArray(self, adjacentPairs: List[List[int]]) -> List[int]:
m = n = len(adjacentPairs)
n += 1
cnts = defaultdict(int)
hashmap = defaultdict(list)
for a, b in adjacentPairs:
cnts[a] += 1
cnts[b] += 1
hashmap[a].append(b)
hashmap[b].append(a)
start = -1
for i, v in cnts.items():
if v == 1:
start = i
break
ans = [0] * n
ans[0] = start
ans[1] = hashmap[start][0]
for i in range(2, n):
x = ans[i - 1]
for j in hashmap[x]:
if j != ans[i - 2]:
ans[i] = j
return ans
- 時(shí)間復(fù)雜度:O(n)O(n)O(n)
- 空間復(fù)雜度:O(n)O(n)O(n)
雙向構(gòu)造(雙指針)
在解法一中,我們通過「哈希表」計(jì)數(shù)得到 ansansans 首位的原始作為起點(diǎn),進(jìn)行「單向構(gòu)造」。
那么是否存在使用任意數(shù)值作為起點(diǎn)進(jìn)行的雙向構(gòu)造呢?
答案是顯然的,我們可以利用 ansansans 的長(zhǎng)度為 2<=n<=1052 <= n <= 10^52<=n<=105,構(gòu)造一個(gè)長(zhǎng)度 10610^6106 的數(shù)組 qqq(這里可以使用 static 進(jìn)行加速,讓多個(gè)測(cè)試用例共享一個(gè)大數(shù)組)。
這里 qqq 數(shù)組不一定要開成 1e61e61e6 大小,只要我們 qqq 大小大于 ansansans 的兩倍,就不會(huì)存在越界問題。
從 qqq 數(shù)組的 中間位置 開始,先隨便將其中一個(gè)元素添加到中間位置,使用「雙指針」分別往「兩邊拓展」(l 和 r 分別指向左右待插入的位置)。
當(dāng) l 指針和 r 指針直接已經(jīng)有 nnn 個(gè)數(shù)值,說明整個(gè) ansansans 構(gòu)造完成,我們將 [l+1,r−1][l + 1, r - 1][l+1,r−1] 范圍內(nèi)的數(shù)值輸出作為答案即可。

Java 代碼:
class Solution {
static int N = (int)1e6+10;
static int[] q = new int[N];
public int[] restoreArray(int[][] aps) {
int m = aps.length, n = m + 1;
Map<Integer, List<Integer>> map = new HashMap<>();
for (int[] ap : aps) {
int a = ap[0], b = ap[1];
List<Integer> alist = map.getOrDefault(a, new ArrayList<>());
alist.add(b);
map.put(a, alist);
List<Integer> blist = map.getOrDefault(b, new ArrayList<>());
blist.add(a);
map.put(b, blist);
}
int l = N / 2, r = l + 1;
int std = aps[0][0];
List<Integer> list = map.get(std);
q[l--] = std;
q[r++] = list.get(0);
if (list.size() > 1) q[l--] = list.get(1);
while ((r - 1) - (l + 1) + 1 < n) {
List<Integer> alist = map.get(q[l + 1]);
int j = l;
for (int i : alist) {
if (i != q[l + 2]) q[j--] = i;
}
l = j;
List<Integer> blist = map.get(q[r - 1]);
j = r;
for (int i : blist) {
if (i != q[r - 2]) q[j++] = i;
}
r = j;
}
int[] ans = new int[n];
for (int i = l + 1, idx = 0; idx < n; i++, idx++) {
ans[idx] = q[i];
}
return ans;
}
}
Python 3 代碼:
class Solution:
N = 10 ** 6 + 10
q = [0] * N
def restoreArray(self, adjacentPairs: List[List[int]]) -> List[int]:
m = len(adjacentPairs)
n = m + 1
hashmap = defaultdict(list)
for a, b in adjacentPairs:
hashmap[a].append(b)
hashmap[b].append(a)
l = self.N // 2
r = l + 1
std = adjacentPairs[0][0]
lt = hashmap[std]
self.q[l] = std
l -= 1
self.q[r] = lt[0]
r += 1
if len(lt) > 1:
self.q[l] = lt[1]
l -= 1
while (r-1)-(l+1)+1<n:
alt = hashmap[self.q[l+1]]
j = l
for i in alt:
if i != self.q[l+2]:
self.q[j] = i
j -= 1
l = j
blt = hashmap[self.q[r-1]]
j = r
for i in blt:
if i != self.q[r - 2]:
self.q[j] = i
j += 1
r = j
ans = [0] * n
for idx in range(n):
ans[idx] = self.q[idx+l+1]
return ans
時(shí)間復(fù)雜度:O(n)O(n)O(n)
空間復(fù)雜度:O(n)O(n)O(n)
最后
到此這篇關(guān)于Python 根據(jù)相鄰關(guān)系還原數(shù)組的兩種方式(單向構(gòu)造和雙向構(gòu)造)的文章就介紹到這了,更多相關(guān)Python 相鄰還原數(shù)組內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python好玩的項(xiàng)目—色情圖片識(shí)別代碼分享
這篇文章主要介紹了python好玩的項(xiàng)目—色情圖片識(shí)別,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
安裝Python的web.py框架并從hello world開始編程
這篇文章主要介紹了安裝Python的web.py框架并從hello world開始編程,web.py的作者年輕的Aaron Swartz已經(jīng)離世,緬懷大神,需要的朋友可以參考下2015-04-04
python實(shí)現(xiàn)AES和RSA加解密的方法
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)AES和RSA加解密的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
Python進(jìn)行ffmpeg推流和拉流rtsp、rtmp實(shí)例詳解
Python推流本質(zhì)是調(diào)用FFmpeg的推流進(jìn)程,下面這篇文章主要給大家介紹了關(guān)于Python進(jìn)行ffmpeg推流和拉流rtsp、rtmp的相關(guān)資料,需要的朋友可以參考下2023-01-01
python中random.randint和random.randrange的區(qū)別詳解
這篇文章主要介紹了python中random.randint和random.randrange的區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
python實(shí)現(xiàn)兩個(gè)文件合并功能
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)兩個(gè)文件合并功能,一個(gè)簡(jiǎn)單的文件合并程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
Python基于Socket實(shí)現(xiàn)的簡(jiǎn)單聊天程序示例
這篇文章主要介紹了Python基于Socket實(shí)現(xiàn)的簡(jiǎn)單聊天程序,結(jié)合簡(jiǎn)單實(shí)例形式分析了Python聊天程序的客戶端與服務(wù)器端相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-08-08
使用Keras畫神經(jīng)網(wǎng)絡(luò)準(zhǔn)確性圖教程
這篇文章主要介紹了使用Keras畫神經(jīng)網(wǎng)絡(luò)準(zhǔn)確性圖教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06

