一、数组 / 字符串
1. 删除有序数组中的重复项 II
/*
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3。
不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length = 7, 并且原数组的前七个元素被修改为 0, 0, 1, 1, 2, 3, 3。
不需要考虑数组中超出新长度后面的元素。
*/
class Solution {
public int removeDuplicates(int[] nums) {
return process(nums, 2);
}
int process(int[] nums, int k) {
int u = 0;
for(int x : nums) {
if (u < k || nums[u - k] != x) nums[u++] = x;
}
return u;
}
}
2. 买卖股票的最佳时机
class Solution {
public int maxProfit(int[] prices) {
int cost =Integer.MAX_VALUE, profit = 0;
for (int price : prices) {
cost =Math.min(cost, price);
profit = Math.max(profit, price-cost);
}
return profit;
}
}
3. 跳跃游戏
class Solution {
public boolean canJump(int[] nums) {
int n = nums.length; //数组长度
int rightmost = 0; //跳跃到的最远位置
for (int i = 0; i < n; ++i) {
if (i <= rightmost) { //能够跳,并算出跳后所在位置
rightmost = Math.max(rightmost, i + nums[i]);
if (rightmost >= n - 1) { //跳的最大位置是否大于数组长度
return true;
}
}
}
return false;
}
}
4.跳跃游戏 II
/*
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
*/
class Solution {
public int jump(int[] nums) {
//1.变量定义:
int length = nums.length;
int end = 0;
int maxPosition = 0;
int steps = 0;
//2.遍历数组:
for (int i = 0; i < length - 1; i++) {
//3.更新maxPosition:
maxPosition = Math.max(maxPosition, i + nums[i]);
//4.检查是否到达当前跳跃的边界:
if (i == end) {
end = maxPosition;
steps++;
}
}
//5.返回结果:
return steps;
}
}
5. H 指数
/*
给你一个整数数组 citations,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数.
根据维基百科上h指数的定义:h代表“高引用次数” ,一名科研人员的 h 指数是指他(她)至少发表了 h 篇论文,并且至少有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数 是其中最大的那个。
示例 1:
输入:citations = [3,0,6,1,5]
输出:3
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。
示例 2:
输入:citations = [1,3,1]
输出:1
*/
class Solution {
public int hIndex(int[] citations) {
int n = citations.length;
int[] cnt = new int[n + 1];
for (int c : citations) {
cnt[Math.min(c, n)]++; //引用次数 > n,等价于引用次数为 n,cnt[i]将用来存储引用次数为i的论文数量。
}
int s = 0; //因为s是累加所有论文数量的
for (int i = n; ; i--) { // i=0 的时候,s>=i 一定成立
s += cnt[i];
if (s >= i) { // 说明有至少 i 篇论文的引用次数至少为 i
return i;
}
}
}
}
6.O(1) 时间插入、删除和获取随机元素
/*
示例:
输入
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]
解释
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomizedSet.remove(2); // 返回 false ,表示集合中不存在 2 。
randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
randomizedSet.remove(1); // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomizedSet.insert(2); // 2 已在集合中,所以返回 false 。
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
*/
class RandomizedSet {
List<Integer> nums;
Map<Integer, Integer> indices;
Random random;
public RandomizedSet() {
nums = new ArrayList<Integer>();
indices = new HashMap<Integer, Integer>();
random = new Random();
}
/*使用 HashMap (indices) 来存储每个元素及其对应的索引。这样,在插入新元素时,可以通过 HashMap 的 containsKey 方法在 O(1) 的时间复杂度内检查元素是否已经存在。
如果元素不存在,直接将元素添加到 ArrayList (nums) 的末尾,并在 HashMap 中记录该元素及其索引。因为 ArrayList 的 add 方法在末尾添加元素的时间复杂度是 O(1),所以这一步也是 O(1) 的。
*/
public boolean insert(int val) {
if (indices.containsKey(val)) {
return false;
}
int index =nums.size();
nums.add(val);
indices.put(val, index);
return true;
}
/*
使用 HashMap 来查找要删除元素的索引,这同样是 O(1) 的操作。
找到索引后,将 ArrayList 的最后一个元素移动到要删除元素的位置。
这一步涉及到两个操作:获取最后一个元素和设置新位置的值,都是 O(1) 的。
更新 HashMap 中最后一个元素的索引。
从 ArrayList 和 HashMap 中删除被删除的元素。ArrayList 的 remove 方法在已知索引的情况下删除元素的时间复杂度是 O(n-k),
其中 n 是列表的大小,k 是要删除元素的索引。然而,因为我们总是删除最后一个元素(通过交换),所以这个操作的平均时间复杂度实际上是 O(1)。
*/
public boolean remove(int val) {
if (!indices.containsKey(val)) {
return false;
}
int index = indices.get(val);
int last = nums.get(nums.size() - 1);
nums.set(index, last);
indices.put(last, index);
nums.remove(nums.size() - 1);
indices.remove(val);
return true;
}
/*
使用 Random 类的 nextInt 方法生成一个随机索引,这个操作是 O(1) 的。
通过随机索引从 ArrayList 中获取元素也是 O(1) 的操作。
*/
public int getRandom() {
int randomIndex = random.nextInt(nums.size());
return nums.get(randomIndex);
}
}
7.除自身以外数组的乘积
/*
示例 1:
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]
*/
class Solution {
public int[] productExceptSelf(int[] nums) {
int len = nums.length;
if (len == 0) return new int[0];
int[] ans = new int[len];
ans[0] = 1;
int tmp = 1;
for (int i = 1; i < len; i++) {
ans[i] = ans[i - 1] * nums[i - 1];
}
for (int i = len - 2; i >= 0; i--) {
tmp *= nums[i + 1];
ans[i] *= tmp;
}
return ans;
}
}