算法leetcode1409. 查询带键的排列(多语言实现)
Posted 二当家的白帽子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法leetcode1409. 查询带键的排列(多语言实现)相关的知识,希望对你有一定的参考价值。
文章目录
- 1409. 查询带键的排列:
- 样例 1:
- 样例 2:
- 提示:
- 分析
- 题解
- 原题传送门:https://leetcode.cn/problems/queries-on-a-permutation-with-key/
1409. 查询带键的排列:
给你一个待查数组 queries
,数组中的元素为 1
到 m
之间的正整数。 请你根据以下规则处理所有待查项 queries[i]
(从 i=0
到 i=queries.length-1
):
- 一开始,排列
P=[1,2,3,...,m]
。 - 对于当前的
i
,请你找出待查项queries[i]
在排列P
中的位置**(下标从 0 开始)**,然后将其从原位置移动到排列P
的起始位置(即下标为 0 处)。注意,queries[i]
在P
中的位置就是queries[i]
的查询结果。
请你以数组形式返回待查数组 queries
的查询结果。
样例 1:
输入:
queries = [3,1,2,1], m = 5
输出:
[2,1,2,1]
解释:
待查数组 queries 处理如下:
对于 i=0: queries[i]=3, P=[1,2,3,4,5], 3 在 P 中的位置是 2,接着我们把 3 移动到 P 的起始位置,得到 P=[3,1,2,4,5] 。
对于 i=1: queries[i]=1, P=[3,1,2,4,5], 1 在 P 中的位置是 1,接着我们把 1 移动到 P 的起始位置,得到 P=[1,3,2,4,5] 。
对于 i=2: queries[i]=2, P=[1,3,2,4,5], 2 在 P 中的位置是 2,接着我们把 2 移动到 P 的起始位置,得到 P=[2,1,3,4,5] 。
对于 i=3: queries[i]=1, P=[2,1,3,4,5], 1 在 P 中的位置是 1,接着我们把 1 移动到 P 的起始位置,得到 P=[1,2,3,4,5] 。
因此,返回的结果数组为 [2,1,2,1] 。
样例 2:
输入:
queries = [4,1,2,2], m = 4
输出:
[3,1,2,0]
提示:
- 1 <= m <= 1 0 3 10^3 103
- 1 <= queries.length <= m
- 1 <= queries[i] <= m
分析
-
面对这道算法题目,二当家的陷入了沉思。
-
按照题意去模拟,涉及到两个重要操作,一个是查找目标数字的位置,另一个是将目标数字移动到起始位置。
-
先来解决将目标数字移动到起始位置的问题。
-
直接使用动态数组,链表,双端队列等数据结构,可以简化操作,但是肯定会多花时间和空间,如果使用普通数组,在把查询数字放到起始位置时涉及到大量移动,太花时间。
-
事实上我们提前知道一共有多少次查询,也就知道有多少次移动,每次移动都会将一个数字移动到起始位置。
-
所以我们可以开始就在数组前面多申请一些空间,将开始的数字放在数组最后面,这样移动数字就可以用普通数组实现,用空间换时间。
_ _ _ _ 1 2 3 4 5
_ _ _ 3 1 2 _ 4 5
_ _ 1 3 _ 2 _ 4 5
_ 2 1 3 _ _ _ 4 5
1 2 _ 3 _ _ _ 4 5 -
再来看看查找目标数字的问题。
-
如果直接遍历,那就是O(n)的复杂度,已经不算慢了,但是如果想再提高点效率呢?
-
由于在查询几次后,排列是无序的,也不能用二分查找,还有什么其他办法呢?
-
我们提前知道数字的取值范围,所以我们可以使用一个数组来存储某个数字的当前位置,循环中动态维护,但是如前面所说,我们如果使用普通数组存储排列,在移动了数字之后,排列中就有一些空位,仅仅拿到数字的位置是不对的,还需要把这些空位排除掉。
-
计数可以使用线段树,但是有点大材小用了,我们还可以使用树状数组,统计某个位置前面有多少个数字。
题解
rust
impl Solution
pub fn process_queries(queries: Vec<i32>, m: i32) -> Vec<i32>
// 排列
let mut p = vec![0; m as usize + queries.len()];
(0..m).for_each(|i| p[queries.len() + i as usize] = i + 1; );
queries.iter().enumerate().map(|(i, &v)|
// 计数
let mut count = 0;
// 现在数字所在位置
let mut cur = queries.len() - i;
while p[cur] != v
if p[cur] > 0
count += 1;
cur += 1;
// 原来的位置赋空
p[cur] = 0;
// 新的位置
cur = queries.len() - i - 1;
p[cur] = v;
// 返回
count
).collect()
go
func processQueries(queries []int, m int) []int
// 排列
p := make([]int, m+len(queries))
for i := 0; i < m; i++
p[len(queries)+i] = i + 1
ans := make([]int, len(queries))
for i, v := range queries
// 查找位置
cur := len(queries) - i
for p[cur] != v
if p[cur] > 0
ans[i]++
cur++
// 原来的位置赋空
p[cur] = 0
// 新的位置
cur = len(queries) - i - 1
p[cur] = queries[i]
return ans
typescript
function processQueries(queries: number[], m: number): number[]
// 排列
let p = [];
for (let i = 1; i <= m; ++i)
p.push(i);
let ans = [];
for (let i = 0; i < queries.length; ++i)
const v = queries[i];
// 查找位置
const cur = p.indexOf(v);
ans.push(cur);
// 移动位置
p.splice(cur, 1);
p.unshift(v);
return ans;
;
c
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* processQueries(int* queries, int queriesSize, int m, int* returnSize)
// 排列
int p[m + queriesSize];
for (int i = 0; i < m; ++i)
p[queriesSize + i] = i + 1;
int *ans = calloc(queriesSize, sizeof(int));
for (int i = 0; i < queriesSize; ++i)
// 查找位置
int cur = queriesSize - i;
while (p[cur] != queries[i])
if (p[cur] > 0)
++ans[i];
++cur;
// 原来的位置赋空
p[cur] = 0;
// 新的位置
cur = queriesSize - i - 1;
p[cur] = queries[i];
*returnSize = queriesSize;
return ans;
c++
class Solution
public:
vector<int> processQueries(vector<int>& queries, int m)
// 排列
int p[m + queries.size()];
for (int i = 0; i < m; ++i)
p[queries.size() + i] = i + 1;
vector<int> ans;
for (int i = 0; i < queries.size(); ++i)
// 查找位置
int cur = queries.size() - i;
int count = 0;
while (p[cur] != queries[i])
if (p[cur] > 0)
++count;
++cur;
// 原来的位置赋空
p[cur] = 0;
// 新的位置
cur = queries.size() - i - 1;
p[cur] = queries[i];
ans.emplace_back(count);
return ans;
;
python
class Solution:
def processQueries(self, queries: List[int], m: int) -> List[int]:
# 排列
p = [i + 1 for i in range(m)]
# 结果
ans = []
for v in queries:
# 查找位置
cur = p.index(v)
ans.append(cur)
# 移动位置
p.pop(cur)
p.insert(0, v)
return ans
java
class Solution
public int[] processQueries(int[] queries, int m)
// 排列
int[] p = new int[m + queries.length];
for (int i = 0; i < m; ++i)
p[queries.length + i] = i + 1;
int[] ans = new int[queries.length];
for (int i = 0; i < queries.length; ++i)
// 查找位置
int cur = queries.length - i;
while (p[cur] != queries[i])
if (p[cur] > 0)
++ans[i];
++cur;
// 原来的位置赋空
p[cur] = 0;
// 新的位置
cur = queries.length - i - 1;
p[cur] = queries[i];
return ans;
树状数组实现
class Solution
public int[] processQueries(int[] queries, int m)
// 维护数字的位置
int[] pos = new int[m + 1];
// 维护位置前面有多少数字
BIT bit = new BIT(m + queries.length);
for (int i = 1; i <= m; ++i)
pos[i] = queries.length + i;
bit.update(queries.length + i, 1);
int[] ans = new int[queries.length];
for (int i = 0; i < queries.length; ++i)
// 现在的位置
int cur = pos[queries[i]];
bit.update(cur, -1);
ans[i] = bit.query(cur);
// 新的位置
cur = queries.length - i;
pos[queries[i]] = cur;
bit.update(cur, 1);
return ans;
/**
* 树状数组
* 下标从1开始
*/
class BIT
int[] a;
public BIT(int n)
// 多用一个空间,来简化下标计算
this.a = new int[n + 1];
public int query(int i)
int ret = 0;
while (i > 0)
ret += a[i];
i -= Integer.lowestOneBit(i);
return ret;
public int update(int i, int v)
while (i < a.length)
a[i] += v;
i += Integer.lowestOneBit(i);
return i;
原题传送门:https://leetcode.cn/problems/queries-on-a-permutation-with-key/
非常感谢你阅读本文~
欢迎【👍点赞】【⭐收藏】【📝评论】~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://le-yi.blog.csdn.net/ 博客原创~
以上是关于算法leetcode1409. 查询带键的排列(多语言实现)的主要内容,如果未能解决你的问题,请参考以下文章