• 售前

  • 售后

热门帖子
入门百科

Python 根据相邻关系还原数组的两种方式(单向构造和双向构造)

[复制链接]
我是的十八簿 显示全部楼层 发表于 2021-8-13 14:20:23 |阅读模式 打印 上一主题 下一主题
目次


  • 题目形貌

    • 示例 2:
    • 示例 3:

  • 单向构造(哈希表计数)
  • 双向构造(双指针)
  • 末了

题目形貌


这是 LeetCode 上的 1743. 从相邻元素对还原数组 ,难度为 中等。

Tag : 「哈希表」、「双指针」、「模仿」

存在一个由 n 个不同元素构成的整数数组 nums ,但你已经记不清详细内容。好在你还记得 nums 中的每一对相邻元素。
给你一个二维整数数组 adjacentPairs ,巨细为 n - 1 ,此中每个 adjacentPairs = [ui, vi] 表现元素 ui 和 vi 在 nums 中相邻。
题目数据包管全部由元素 nums 和 nums[i+1] 构成的相邻元素对都存在于 adjacentPairs 中,存在情势大概是 [nums, nums[i+1]] ,也大概是 [nums[i+1], nums] 。这些相邻元素对可以 按恣意顺序 出现。

返回 原始数组 nums 。如果存在多种解答,返回 此中恣意一个 即可。

示例 1:

输入:adjacentPairs = [[2,1],[3,4],[3,2]]
输出:[1,2,3,4]
解释:数组的全部相邻元素对都在 adjacentPairs 中。
特别要注意的是,adjacentPairs 只表现两个元素相邻,并不包管其 左-右 顺序。

示例 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.length == 2   
  • 2 <= n <= 10510^5105   
  • -10510^5105 <= nums, ui, vi <= 10510^5105   
  • 题目数据包管存在一些以 adjacentPairs 作为元素对的数组

单向构造(哈希表计数)


根据题意,由于全部的相邻关系都会出现在 numsnumsnums 中,假设此中一个合法数组为 ansansans,长度为 nnn。

那么显然 ans[0]ans[0]ans[0] 和 ans[n−1]ans[n - 1]ans[n−1] 在 numsnumsnums 中只存在一对相邻关系,而其他 ansansans 则存在两对相邻关系。

因此我们可以使用「哈希表」对 numsnumsnums 中出现的数值进行计数,找到“出现一次”的数值作为 ansansans 数值的首位,然后根据给定的相邻关系进行「单向构造」,为了方便找到某个数其相邻的数是哪些,我们还须要再开一个「哈希表」纪录相邻关系。

Java 代码:
  1. class Solution {
  2.     public int[] restoreArray(int[][] aps) {
  3.         int m = aps.length, n = m + 1;
  4.         Map<Integer, Integer> cnts = new HashMap<>();
  5.         Map<Integer, List<Integer>> map = new HashMap<>();
  6.         for (int[] ap : aps) {
  7.             int a = ap[0], b = ap[1];
  8.             cnts.put(a, cnts.getOrDefault(a, 0) + 1);
  9.             cnts.put(b, cnts.getOrDefault(b, 0) + 1);
  10.             List<Integer> alist = map.getOrDefault(a, new ArrayList<>());
  11.             alist.add(b);
  12.             map.put(a, alist);
  13.             List<Integer> blist = map.getOrDefault(b, new ArrayList<>());
  14.             blist.add(a);
  15.             map.put(b, blist);
  16.         }
  17.         int start = -1;
  18.         for (int i : cnts.keySet()) {
  19.             if (cnts.get(i) == 1) {
  20.                 start = i;
  21.                 break;
  22.             }
  23.         }
  24.         int[] ans = new int[n];
  25.         ans[0] = start;
  26.         ans[1] = map.get(start).get(0);
  27.         for (int i = 2; i < n; i++) {
  28.             int x = ans[i - 1];
  29.             List<Integer> list = map.get(x);
  30.             for (int j : list) {
  31.                 if (j != ans[i - 2]) ans[i] = j;
  32.             }
  33.         }
  34.         return ans;
  35.     }
  36. }
复制代码
Python 3 代码:
  1. class Solution:
  2.     def restoreArray(self, adjacentPairs: List[List[int]]) -> List[int]:
  3.         m = n = len(adjacentPairs)
  4.         n += 1
  5.         cnts = defaultdict(int)
  6.         hashmap = defaultdict(list)
  7.         for a, b in adjacentPairs:
  8.             cnts[a] += 1
  9.             cnts[b] += 1
  10.             hashmap[a].append(b)
  11.             hashmap[b].append(a)
  12.         start = -1
  13.         for i, v in cnts.items():
  14.             if v == 1:
  15.                 start = i
  16.                 break
  17.         ans = [0] * n
  18.         ans[0] = start
  19.         ans[1] = hashmap[start][0]
  20.         for i in range(2, n):
  21.             x = ans[i - 1]
  22.             for j in hashmap[x]:
  23.                 if j != ans[i - 2]:
  24.                     ans[i] = j
  25.         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 代码:
  1. class Solution {
  2.     static int N = (int)1e6+10;
  3.     static int[] q = new int[N];
  4.     public int[] restoreArray(int[][] aps) {
  5.         int m = aps.length, n = m + 1;
  6.         Map<Integer, List<Integer>> map = new HashMap<>();
  7.         for (int[] ap : aps) {
  8.             int a = ap[0], b = ap[1];
  9.             List<Integer> alist =  map.getOrDefault(a, new ArrayList<>());
  10.             alist.add(b);
  11.             map.put(a, alist);
  12.             List<Integer> blist = map.getOrDefault(b, new ArrayList<>());
  13.             blist.add(a);
  14.             map.put(b, blist);
  15.         }
  16.         int l = N / 2, r = l + 1;
  17.         int std = aps[0][0];
  18.         List<Integer> list = map.get(std);
  19.         q[l--] = std;
  20.         q[r++] = list.get(0);
  21.         if (list.size() > 1) q[l--] = list.get(1);
  22.         while ((r - 1) - (l + 1) + 1 < n) {
  23.             List<Integer> alist = map.get(q[l + 1]);
  24.             int j = l;
  25.             for (int i : alist) {
  26.                 if (i != q[l + 2]) q[j--] = i;
  27.             }
  28.             l = j;
  29.             List<Integer> blist = map.get(q[r - 1]);
  30.             j = r;
  31.             for (int i : blist) {
  32.                 if (i != q[r - 2]) q[j++] = i;
  33.             }
  34.             r = j;
  35.         }
  36.         int[] ans = new int[n];
  37.         for (int i = l + 1, idx = 0; idx < n; i++, idx++) {
  38.             ans[idx] = q[i];
  39.         }
  40.         return ans;
  41.     }
  42. }
复制代码
Python 3 代码:
  1. class Solution:
  2.     N = 10 ** 6 + 10
  3.     q = [0] * N
  4.     def restoreArray(self, adjacentPairs: List[List[int]]) -> List[int]:
  5.         m = len(adjacentPairs)
  6.         n = m + 1
  7.         hashmap = defaultdict(list)
  8.         for a, b in adjacentPairs:
  9.             hashmap[a].append(b)
  10.             hashmap[b].append(a)
  11.         l = self.N // 2
  12.         r = l + 1
  13.         std = adjacentPairs[0][0]
  14.         lt = hashmap[std]
  15.         self.q[l] = std
  16.         l -= 1
  17.         self.q[r] = lt[0]
  18.         r += 1
  19.         if len(lt) > 1:
  20.             self.q[l] = lt[1]
  21.             l -= 1
  22.         while (r-1)-(l+1)+1<n:
  23.             alt = hashmap[self.q[l+1]]
  24.             j = l
  25.             for i in alt:
  26.                 if i != self.q[l+2]:
  27.                     self.q[j] = i
  28.                     j -= 1
  29.             l = j
  30.             
  31.             blt = hashmap[self.q[r-1]]
  32.             j = r
  33.             for i in blt:
  34.                 if i != self.q[r - 2]:
  35.                     self.q[j] = i
  36.                     j += 1
  37.             r = j
  38.         ans = [0] * n
  39.         for idx in range(n):
  40.             ans[idx] = self.q[idx+l+1]
  41.         return ans
复制代码
时间复杂度:O(n)O(n)O(n)
空间复杂度:O(n)O(n)O(n)

末了


到此这篇关于Python 根据相邻关系还原数组的两种方式(单向构造和双向构造)的文章就先容到这了,更多相关Python 相邻还原数组内容请搜刮脚本之家从前的文章或继承欣赏下面的相关文章希望大家以后多多支持脚本之家!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作