Python如何根据相邻关系还原数组
小编给大家分享一下Python如何根据相邻关系还原数组,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
题目描述
这是 LeetCode 上的 1743. 从相邻元素对还原数组 ,难度为 中等。
Tag : 「哈希表」、「双指针」、「模拟」
存在一个由 n 个不同元素组成的整数数组 nums ,但你已经记不清具体内容。好在你还记得 nums 中的每一对相邻元素。
给你一个二维整数数组 adjacentPairs ,大小为 n - 1 ,其中每个 adjacentPairs[i] = [ui, vi] 表示元素 ui 和 vi 在 nums 中相邻。
题目数据保证所有由元素 nums[i] 和 nums[i+1] 组成的相邻元素对都存在于 adjacentPairs 中,存在形式可能是 [nums[i], nums[i+1]] ,也可能是 [nums[i+1], nums[i]] 。这些相邻元素对可以 按任意顺序 出现。
返回 原始数组 nums 。如果存在多种解答,返回 其中任意一个 即可。
示例 1:
输入:adjacentPairs = [[2,1],[3,4],[3,2]]
输出:[1,2,3,4]
解释:数组的所有相邻元素对都在 adjacentPairs 中。
特别要注意的是,adjacentPairs[i] 只表示两个元素相邻,并不保证其 左-右 顺序。
示例 2:
输入:adjacentPairs = [[4,-2],[1,4],[-3,1]]
输出:[-2,4,1,-3]
解释:数组中可能存在负数。
另一种解答是 [-3,1,4,-2] ,也会被视作正确答案。
示例 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
题目数据保证存在一些以 adjacentPairs 作为元素对的数组
单向构造(哈希表计数)
根据题意,由于所有的相邻关系都会出现在 numsnumsnums 中,假设其中一个合法数组为 ansansans,长度为 nnn。
那么显然 ans[0]ans[0]ans[0] 和 ans[n−1]ans[n - 1]ans[n−1] 在 numsnumsnums 中只存在一对相邻关系,而其他 ans[i]ans[i]ans[i] 则存在两对相邻关系。
因此我们可以使用「哈希表」对 numsnumsnums 中出现的数值进行计数,找到“出现一次”的数值作为 ansansans 数值的首位,然后根据给定的相邻关系进行「单向构造」,为了方便找到某个数其相邻的数是哪些,我们还需要再开一个「哈希表」记录相邻关系。
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
时间复杂度:O(n)O(n)O(n)
空间复杂度:O(n)O(n)O(n)
双向构造(双指针)
在解法一中,我们通过「哈希表」计数得到 ansansans 首位的原始作为起点,进行「单向构造」。
那么是否存在使用任意数值作为起点进行的双向构造呢?
答案是显然的,我们可以利用 ansansans 的长度为 2<=n<=1052 <= n <= 10^52<=n<=105,构造一个长度 10610^6106 的数组 qqq(这里可以使用 static 进行加速,让多个测试用例共享一个大数组)。
这里 qqq 数组不一定要开成 1e61e61e6 大小,只要我们 qqq 大小大于 ansansans 的两倍,就不会存在越界问题。
从 qqq 数组的 中间位置 开始,先随便将其中一个元素添加到中间位置,使用「双指针」分别往「两边拓展」(l 和 r 分别指向左右待插入的位置)。
当 l 指针和 r 指针直接已经有 nnn 个数值,说明整个 ansansans 构造完成,我们将 [l+1,r−1][l + 1, r - 1][l+1,r−1] 范围内的数值输出作为答案即可。
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
时间复杂度:O(n)O(n)O(n)
空间复杂度:O(n)O(n)O(n)
以上是“Python如何根据相邻关系还原数组”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341