算法题解 - 牛客编程巅峰赛S1第3场 - 黄金&钻石组

A. 找卧底

题目描述

牛牛今天和大家玩了一个新游戏,除了牛牛以外还有 n 个人参加游戏,现在这 n 个人中的每个人从 [1, n] 中选择一个数字,保证选出的数字均不重复。牛牛作为第 n + 1 个人,充当卧底的角色,要求卧底从 1 到 n 中选择一个数字,现在将 n + 1 个数字重新打乱顺序,请找出卧底选择的数字是多少。

备注:

其中1 <= n <= 100000。
要求时间复杂度为 O(n),额外空间复杂度为 O(1)。

示例1

输入

4,[1,2,1,4,3]

输出

1

解法一:原地哈希

思路分析

这种找重复数字的题目还挺常见的。最直接的方法是用哈希表存储数字,遇到新数字判断它是否在哈希表里,若在就说明重复。

不过题目要求空间复杂度为 O ( 1 ) O(1) O(1)。那么就不能用内置哈希表了。

注意到数字范围是 [1, n],并且数组长度为 n + 1,因此我们可以把原数组当成哈希表,通过交换,将数字放到对应下标的位置即可。

例如:遇到了数字10,那么我们就去看看下标为 10 的数字是不是 10,是的话说明数字重复了,否则交换这两个数字。

代码实现

public int search (int n, int[] a) {
   
  while(a[0] != a[a[0]]){
   
    int temp = a[0];
    a[0] = a[a[0]];
    a[temp] = temp;
  }
  return a[0];
}

解法二:求和相减

思路分析

记卧底选的数字是 b,那么 ∑ i ∈ [ 0 , n ] a [ i ] = ∑ x ∈ [ 1 , n ] x + b \sum_{i \in [0,n]} a[i] = \sum_{x \in [1,n]} x + b i[0,n]a[i]=x[1,n]x+b。显然求出两个求和的结果,相减即可得到答案。

代码实现

public int search (int n, int[] a) {
   
  int sum = 0;
  for(int i = 0; i <= n; i++) sum += a[i];
  for(int i = 1; i <= n; i++) sum -= i;
  return sum;
}

解法三:位运算

思路分析

剑指 offer 里有一道很经典的题:给一个数组,只有一个数字仅出现一次,其他数字都出现了两次,问如何找到这个数字。

那题是利用了异或运算得到答案的。并且我们知道异或的结果与奇偶次有关,并不局限于一次两次的限定。

这题是只有一个数字出现了两次,其他数字都仅出现一次。如何与那题关联起来呢?

很简单,就让 1 ~ n 再出现一次,这样只有一个数字出现了三次,其他数字都出现了两次。这样就可以用异或来解决啦。

代码实现

public int search (int n, int[] a) {
   
  int x = 0;
  for(int i = 1; i <= n; i++) x ^= i;
  for(int i = 0; i <= n; i++) x ^= a[i];
  return x;
}

B. 父子情深

题目描述

在一颗有 n 个结点且以 1 为根节点树上,起初每个结点的初始权值为 0 。

现在有 q 次操作,每次操作选择将以 r i r_i ri 为根节点的子树上的所有结点权值增加 x i x_i xi

求 q 次操作后从 1 到 n 每个结点的权值。

输入

第一个参数为 n,1 ≤ n ≤ 100,000

第二个参数为边 ( u i , v i ) (u_i, v_i) (ui,vi) 的集合,其中 ( u i , v i ) (u_i, v_i) (u

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值