Python 根据相邻关系还原数组的两种方式(单向构造和双向构造)
作者:宫水三叶的刷题日记 发布时间:2023-09-24 17:08:06
目录
题目描述
示例 1:
示例 2:
示例 3:
单向构造(哈希表计数)
双向构造(双指针)
最后
题目描述
这是 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)
最后
来源:https://juejin.cn/post/6988676087307829255


猜你喜欢
- 现在很多以内容为核心的网站上都在文章底部添加了社会化分享按钮,能让浏览用户在发现一篇有价值的文章时,可以通过社会化网络快速分享给自己的好友,
- 最近使用python写一些东西,在参考资料的时候发现字典是没有顺序的,那么怎么样按照一定顺序访问字典呐,我找到了一个小方法:假设一个字典是:
- MySQL的默认的调度策略可用总结如下:· 写入操作优先于读取操作。· 对某张数据表的写入操作某一时刻只能发生一次,写入请求按照它们到达的次
- 第一部分 关于requests库(1) requests是一个很实用的Python HTTP客户端库,编写爬虫和测试服务器响应数据时经常会用
- 如果说亲密性原则是对元素的归类组合,是将元素之间逻辑理解上的差异在视觉上表现出来,是属于信息分类的话,那么对齐原则即是在视觉上串起这些差异化
- 看到网上有一篇文章,是介绍如何做网站测试的.从一开始的链接测试,页面内容测试,到浏览器兼容性测试,负载压力测试,一直到最后的安全性测试,甚至
- 这是支持的下载版本,去官网下载2020.3及以上(2021-03-18测试破解有效)官网下载地址:https://www.jetbrains
- tensorflow中对tensor对象进行像numpy数组一样便捷的操作是不可能的, 至少对1.2以及之前的版本而言。从issue上看到,
- HTML在线编辑器相信大家见得多了,有些流行的在线编辑器具有很丰富的功能。但美中不足的是,现有的HTML在线编辑器设置字号大小通常只限于1-
- # encoding: UTF-8import threadimport time# 一个用于在线程中执行的函数def func():&nb
- window运行:regedit然后找到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Contro
- MySQL手册中find_in_set函数的语法解释:FIND_IN_SET(str,strlist)str 要查询的字符串 strlist
- 内容概要:print() 是一个常用函数。那么,您是否注意过,print() 会在显示当前语句后换行。如果遇到需要连续显示、不换行的情况,比
- 不是说while就不用,比如前面所列举而得那个猜数字游戏,在业务逻辑上,用while就更容易理解(当然是限于那个游戏的业务需要而言)。另外,
- 1. 获取abi文件合约的接口在remix工具中编译合约后,会有一个abi,复制然后新建一个xx.abi文件,把赋值的粘贴到里面注意:代码变
- 本文实例为大家分享了Python实现简单层次聚类算法,以及可视化,供大家参考,具体内容如下基本的算法思路就是:把当前组间距离最小的两组合并成
- #第一种def delRepeat(liebiao): for x in liebiao: while li
- group_concat()函数的参数是可以直接使用order by排序的。666。。下面通过例子来说明,首先看下面的t1表。比如,我们要查
- 废话不多说了,下面通过一段代码示例介绍一下,希望能够给需要的朋友带来或多或少的帮助。示例代码:function GetOSInfo(){
- 数据备份与还原第三篇,具体如下基础概念:备份,将当前已有的数据或记录另存一份;还原,将数据恢复到备份时的状态。为什么要进行数据的备份与还原?