1.数组+移位/排序
1.数组元素循环左移p位后的结果。
循环左移和以下操作等价:
1.通过中间元素对称翻转
2.将数组分为n-p个和p个两部分
3.分别翻转这两个数组即可
c
// 中心翻转
void Reverse(int R[], int left, int right) {
while (left < right) {
int temp = R[left];
R[left] = R[right];
R[right] = temp;
left++;
right--;
}
}
//分组再翻转
void CyclicLeftShift(int R[], int n, int p) {
Reverse(R, 0, n-1); // 全部逆置
Reverse(R, 0, p-1); // 前p个逆置
Reverse(R, p, n-1); // 后n-p个逆置
}
2 .两个整数递增有序序列A,B分别有n和m个元素,求第K大的数(1≤k≤n+m),要求算法有最佳时间复杂度
例子:输入A={1,3,4,5,6},B={3,4,5,6},K=4
思路:
A、B递增,从大到小数到第k个即可。(时间复杂度o(k))
java
public class KthLargestInTwoArrays {
/**
* 方法1:双指针合并 - 时间复杂度O(K),空间复杂度O(1)
*/
public static int findKthLargest1(int[] A, int[] B, int k) {
int n = A.length, m = B.length;
int i = n - 1, j = m - 1; // 从后往前遍历(因为要求第K大)
int count = 0;
int result = 0;
// 两个数组都还没数完的情况
while (i >= 0 && j >= 0) {
count++;
if (A[i] >= B[j]) {
if (count == k) return A[i];
i--;
} else {
if (count == k) return B[j];
j--;
}
}
// 如果其中一个数组遍历完
while (i >= 0) {
count++;
if (count == k) return A[i];
i--;
}
while (j >= 0) {
count++;
if (count == k) return B[j];
j--;
}
return -1; // k超出范围
}
}
数学
3. 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0
思路:
相当于一个求一个减法运算,得到最大差值。
所以找到最大的被减数和最小的减数即可。
java
public class StockProfit {
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
//初始值-最低价格,遇到最低价格则更新
int minPrice = Integer.MAX_VALUE;
int maxProfit = 0;
for (int i = 0; i < prices.length; i++) {
// 更新最低价格
if (prices[i] < minPrice) {
minPrice = prices[i];
}else if (prices[i] - minPrice > maxProfit) {
// 计算当前价格卖出能获得的利润,更新最大利润
maxProfit = prices[i] - minPrice;
}
}
return maxProfit;
}
}
数组+双指针
**4.**给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
思路:
- 相当于求出宽*高,也就是(b-a)*min(b,a)的最大值。乘数越大越好
- 只需更换a,b的值就好,更换条件,比min(b,a)大则更换,否则不换
java
public class Solution {
public int maxArea(int[] height) {
int left = 0; // 左指针
int right = height.length - 1; // 右指针
int maxArea = 0; // 最大面积
while (left < right) {
// 计算当前容器的面积
int currentWidth = right - left;
int currentHeight = Math.min(height[left], height[right]);
int currentArea = currentWidth * currentHeight;
// 更新最大面积
maxArea = Math.max(maxArea, currentArea);
// 移动较短的指针,希望找到更高的垂线
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return maxArea;
}
}
列表 + 堆 遍历
**5.**有 k 个 非递减排列 的整数列表。找到一个最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
思路:
1.先随机取每个子列表的一个元素,存放在最小堆中,找出最大值和最小值组成区间
2.取出最小值,依次存入子列表的一个新值,更新最小区间
java
public int[] smallestRange(List<List<Integer>> nums) {
// 最小堆,存储三元组[元素值, 列表索引, 元素在列表中的索引]
// 堆按照元素值进行排序,最小的元素在堆顶
PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> a[0] - b[0]);
int currentMax = Integer.MIN_VALUE; // 记录当前堆中所有元素的最大值
int k = nums.size(); // 列表的数量
// 初始化堆:将每个列表的第一个元素加入堆中
for (int i = 0; i < k; i++) {
// 检查当前列表是否为空
if (!nums.get(i).isEmpty()) {
int val = nums.get(i).get(0); // 获取当前列表的第一个元素
// 将三元组[元素值, 列表索引, 元素索引]加入堆
minHeap.offer(new int[]{val, i, 0});
// 更新当前最大值
currentMax = Math.max(currentMax, val);
}
}
// 初始化最小区间的起点和终点,设置为一个非常大的范围
int start = -1000000, end = 1000000;
int minRange = end - start; // 初始化最小区间长度
// 当堆中有k个元素时继续处理(确保每个列表至少有一个元素在考虑范围内)
while (minHeap.size() == k) {
// 从堆中取出当前最小的元素
int[] current = minHeap.poll();
int currentVal = current[0]; // 最小元素的值
int listIdx = current[1]; // 当前元素所在的列表索引
int elementIdx = current[2]; // 当前元素在列表中的索引
// 检查当前区间[currentVal, currentMax]是否比之前记录的最小区间更小
// 或者区间长度相同但起点更小(题目要求返回最小的区间)
if (currentMax - currentVal < minRange ||
(currentMax - currentVal == minRange && currentVal < start)) {
// 更新最小区间信息
minRange = currentMax - currentVal;
start = currentVal;
end = currentMax;
}
// 如果当前元素所在的列表还有下一个元素
if (elementIdx + 1 < nums.get(listIdx).size()) {
// 获取下一个元素的值
int nextVal = nums.get(listIdx).get(elementIdx + 1);
// 将下一个元素加入堆中
minHeap.offer(new int[]{nextVal, listIdx, elementIdx + 1});
// 更新当前最大值(因为新加入的元素可能比当前最大值更大)
currentMax = Math.max(currentMax, nextVal);
} else {
// 如果当前列表已经遍历完,则退出循环
// 因为无法保证每个列表至少有一个元素在区间内了
break;
}
}
// 返回找到的最小区间
return new int[]{start, end};
}
main(){
Solution solution = new Solution();
// 创建测试数据
List<List<Integer>> nums = new ArrayList<>();
nums.add(Arrays.asList(4, 10, 15, 24, 26));
nums.add(Arrays.asList(0, 9, 12, 20));
nums.add(Arrays.asList(5, 18, 22, 30));
// 调用方法并输出结果
int[] result = solution.smallestRange(nums);
}