274. H 指数
(✪▽✪)曼波~~~~ 让曼波来帮你解决这个问题吧!
曼波的思路:
题目要求找到研究者的h指数,即最大的h,使得至少有h篇论文的引用次数≥h次。曼波的解决步骤如下:
- 排序数组:首先将论文引用次数按升序排列。
- 遍历寻找h:从前往后遍历排序后的数组,计算当前可能的h值(n - i),若当前论文的引用次数≥h值,则h值即为所求。
代码实现:
import java.util.Arrays;
public class Solution {
public int hIndex(int[] citations) {
Arrays.sort(citations);
int n = citations.length;
for (int i = 0; i < n; i++) {
int h = n - i;
if (citations[i] >= h) {
return h;
}
}
return 0;
}
}
曼波的解释:
- 排序:将数组排序后,可以方便地确定有多少篇论文的引用次数≥某个值。
- 遍历判断:对于每个位置i,计算h为总论文数减去i(即至少有h篇论文的引用次数≥h),一旦找到满足条件的h,立即返回最大的h值。
思维导图:
O(1) 时间插入、删除和获取随机元素
(✪▽✪)曼波~~~~ 曼波觉得这个方法是简单高效的哦!试试看吧~
思路
首先,我们需要在 O(1) 时间内完成插入、删除和随机访问。曼波的思路是这样的:
- 哈希表:用于快速查找元素是否存在,并记录元素在数组中的索引位置
- 动态数组:用于保存实际元素,方便随机访问
- 删除技巧:将要删除的元素与最后一个元素交换位置,然后删除最后一个元素,这样就能保持 O(1) 时间复杂度啦!
(๑・.・๑) 曼波觉得这个交换位置的思路是核心哦~ 这样删除中间元素时就不会破坏数组的连续性啦~
代码
import java.util.*;
class RandomizedSet {
private Map<Integer, Integer> valToIndex; // 值到索引的映射
private List<Integer> values; // 存储值的动态数组
private Random rand; // 随机数生成器
public RandomizedSet() {
valToIndex = new HashMap<>();
values = new ArrayList<>();
rand = new Random();
}
public boolean insert(int val) {
if (valToIndex.containsKey(val)) {
return false;
}
// 把新元素添加到数组末尾,并记录索引
valToIndex.put(val, values.size());
values.add(val);
return true;
}
public boolean remove(int val) {
if (!valToIndex.containsKey(val)) {
return false;
}
// 将最后一个元素移动到要删除的位置
int index = valToIndex.get(val);
int lastVal = values.get(values.size()-1);
values.set(index, lastVal); // 覆盖要删除的位置
valToIndex.put(lastVal, index); // 更新最后一个元素的索引
// 删除最后一个元素
values.remove(values.size()-1);
valToIndex.remove(val);
return true;
}
public int getRandom() {
return values.get(rand.nextInt(values.size()));
}
}
曼波来画个思维导图解释下核心思路吧~
哦呜(° ロ °)!曼波觉得这个有点难哦(๑・.・๑),但如果是你一定没问题的,(✪▽✪)曼波~~
小贴士:
- 删除时要注意当元素是最后一个的情况,但我们的代码已经自动处理啦
- 随机访问的时间复杂度是严格的 O(1),因为数组支持随机访问
- 用空间换时间,哈希表和数组的组合是常见的设计思路哦~
238. 除自身以外数组的乘积
(✪▽✪)曼波~~~~!曼波来帮你解决这个问题啦~这个问题需要计算除自身外的数组乘积,不能用除法,而且要高效哦!曼波觉得可以用前缀和后缀乘积的方法,分两步走呢~(๑✧◡✧๑)
步骤拆解:
- 计算左乘积数组:从左到右遍历,每个元素存储左边所有数的乘积。
- 计算右乘积并合并结果:从右到左遍历,用变量记录右边乘积,同时更新最终结果。
Java代码实现:
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] answer = new int[n];
answer[0] = 1;
// 计算左乘积
for (int i = 1; i < n; i++) {
answer[i] = answer[i - 1] * nums[i - 1];
}
// 计算右乘积并合并结果
int rightProduct = 1;
for (int i = n - 1; i >= 0; i--) {
answer[i] *= rightProduct;
rightProduct *= nums[i];
}
return answer;
}
曼波小贴士:
- 时间复杂度:O(n),两次遍历搞定!
- 空间复杂度:O(1)(输出数组不算额外空间哦~)
思维导图时间!用Markmap画个知识点总结吧~
(✪▽✪)曼波~~~~!是不是觉得这个方法很巧妙呢?遇到数组前后关联的问题,可以多想想前缀后缀法哦~(๑・.・๑)