Skip to content

Commit 4a11a99

Browse files
Auto-update blog content
1 parent 3efcc8e commit 4a11a99

File tree

63 files changed

+16155
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+16155
-0
lines changed
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
---
2+
layout: post
3+
title: "算法训练-数据结构"
4+
date: 2025-11-22T14:44:44+0800
5+
description: "本文介绍了五种算法问题的解决方案:1)数组循环左移通过三次翻转实现;2)双指针法在有序数组中寻找第K大数;3)股票买卖问题通过记录最小价格和最大利润求解;4)双指针法计算容器最大储水量;5)最小堆方法寻找包含k个列表元素的最小区间。这些算法涵盖了数组操作、双指针技巧和堆数据结构应用,展示了不同场景下的高效解决方案。"
6+
keywords: "算法训练-数据结构"
7+
categories: ['未分类']
8+
tags: ['算法', '数据结构']
9+
artid: "154796251"
10+
arturl: "https://blog.csdn.net/weixin_55800388/article/details/154796251"
11+
image:
12+
path: https://api.vvhan.com/api/bing?rand=sj&artid=154796251
13+
alt: "算法训练-数据结构"
14+
render_with_liquid: false
15+
featuredImage: https://bing.ee123.net/img/rand?artid=154796251
16+
featuredImagePreview: https://bing.ee123.net/img/rand?artid=154796251
17+
cover: https://bing.ee123.net/img/rand?artid=154796251
18+
img: https://bing.ee123.net/img/rand?artid=154796251
19+
---
20+
21+
22+
23+
# 算法训练-数据结构
24+
25+
**类型:数组+移位/排序**
26+
**1.数组元素循环左移p位后的结果。**
27+
循环左移和以下操作等价:
28+
1.通过中间元素对称翻转
29+
2.将数组分为n-p个和p个两部分
30+
3.分别翻转这两个数组即可
31+
32+
```c
33+
// 中心翻转
34+
void Reverse(int R[], int left, int right) {
35+
while (left < right) {
36+
int temp = R[left];
37+
R[left] = R[right];
38+
R[right] = temp;
39+
left++;
40+
right--;
41+
}
42+
}
43+
//分组再翻转
44+
void CyclicLeftShift(int R[], int n, int p) {
45+
Reverse(R, 0, n-1); // 全部逆置
46+
Reverse(R, 0, p-1); // 前p个逆置
47+
Reverse(R, p, n-1); // 后n-p个逆置
48+
}
49+
50+
51+
```
52+
53+
**2**.**两个整数递增有序序列A,B分别有n和m个元素,求第K大的数(1≤k≤n+m),要求算法有最佳时间复杂度**
54+
例子:输入A={1,3,4,5,6},B={3,4,5,6},K=4
55+
思路:
56+
A、B递增,从大到小数到第k个即可。(时间复杂度o(k))
57+
58+
```java
59+
public class KthLargestInTwoArrays {
60+
61+
/**
62+
* 方法1:双指针合并 - 时间复杂度O(K),空间复杂度O(1)
63+
*/
64+
public static int findKthLargest1(int[] A, int[] B, int k) {
65+
int n = A.length, m = B.length;
66+
int i = n - 1, j = m - 1; // 从后往前遍历(因为要求第K大)
67+
int count = 0;
68+
int result = 0;
69+
// 两个数组都还没数完的情况
70+
while (i >= 0 && j >= 0) {
71+
count++;
72+
if (A[i] >= B[j]) {
73+
if (count == k) return A[i];
74+
i--;
75+
} else {
76+
if (count == k) return B[j];
77+
j--;
78+
}
79+
}
80+
81+
// 如果其中一个数组遍历完
82+
while (i >= 0) {
83+
count++;
84+
if (count == k) return A[i];
85+
i--;
86+
}
87+
88+
while (j >= 0) {
89+
count++;
90+
if (count == k) return B[j];
91+
j--;
92+
}
93+
94+
return -1; // k超出范围
95+
}
96+
}
97+
98+
```
99+
100+
**类型:数学**
101+
**3.** 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
102+
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
103+
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0
104+
**思路:**
105+
相当于一个减法运算,得到最大差值。
106+
所以找到最大的被减数和最小的减数即可。
107+
108+
```java
109+
public class StockProfit {
110+
public int maxProfit(int[] prices) {
111+
if (prices == null || prices.length == 0) {
112+
return 0;
113+
}
114+
//初始值-最低价格,遇到最低价格则更新
115+
int minPrice = Integer.MAX_VALUE;
116+
int maxProfit = 0;
117+
118+
for (int i = 0; i < prices.length; i++) {
119+
// 更新最低价格
120+
if (prices[i] < minPrice) {
121+
minPrice = prices[i];
122+
}else if (prices[i] - minPrice > maxProfit) {
123+
// 计算当前价格卖出能获得的利润,更新最大利润
124+
maxProfit = prices[i] - minPrice;
125+
}
126+
}
127+
return maxProfit;
128+
}
129+
}
130+
131+
```
132+
133+
**类型 :数组+双指针**
134+
**4.** 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
135+
136+
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
137+
思路:
138+
139+
* 相当于求出宽*高,也就是(b-a)*min(b,a)的最大值。乘数越大越好
140+
* 只需更换a,b的值就好,更换条件,比min(b,a)大则更换,否则不换
141+
142+
```java
143+
public class Solution {
144+
public int maxArea(int[] height) {
145+
int left = 0; // 左指针
146+
int right = height.length - 1; // 右指针
147+
int maxArea = 0; // 最大面积
148+
149+
while (left < right) {
150+
// 计算当前容器的面积
151+
int currentWidth = right - left;
152+
int currentHeight = Math.min(height[left], height[right]);
153+
int currentArea = currentWidth * currentHeight;
154+
155+
// 更新最大面积
156+
maxArea = Math.max(maxArea, currentArea);
157+
158+
// 移动较短的指针,希望找到更高的垂线
159+
if (height[left] < height[right]) {
160+
left++;
161+
} else {
162+
right--;
163+
}
164+
}
165+
166+
return maxArea;
167+
}
168+
}
169+
170+
```
171+
172+
**类型:列表 + 堆 遍历**
173+
**5.** 有 k 个 非递减排列 的整数列表。找到一个最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
174+
**思路:**
175+
1.先随机取每个子列表的一个元素,存放在最小堆中,找出最大值和最小值组成区间
176+
2.取出最小值,依次存入子列表的一个新值,更新最小区间
177+
178+
```java
179+
public int[] smallestRange(List<List<Integer>> nums) {
180+
// 最小堆,存储三元组[元素值, 列表索引, 元素在列表中的索引]
181+
// 堆按照元素值进行排序,最小的元素在堆顶
182+
PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> a[0] - b[0]);
183+
184+
int currentMax = Integer.MIN_VALUE; // 记录当前堆中所有元素的最大值
185+
int k = nums.size(); // 列表的数量
186+
187+
// 初始化堆:将每个列表的第一个元素加入堆中
188+
for (int i = 0; i < k; i++) {
189+
// 检查当前列表是否为空
190+
if (!nums.get(i).isEmpty()) {
191+
int val = nums.get(i).get(0); // 获取当前列表的第一个元素
192+
// 将三元组[元素值, 列表索引, 元素索引]加入堆
193+
minHeap.offer(new int[]{val, i, 0});
194+
// 更新当前最大值
195+
currentMax = Math.max(currentMax, val);
196+
}
197+
}
198+
199+
// 初始化最小区间的起点和终点,设置为一个非常大的范围
200+
int start = -1000000, end = 1000000;
201+
int minRange = end - start; // 初始化最小区间长度
202+
203+
// 当堆中有k个元素时继续处理(确保每个列表至少有一个元素在考虑范围内)
204+
while (minHeap.size() == k) {
205+
// 从堆中取出当前最小的元素
206+
int[] current = minHeap.poll();
207+
int currentVal = current[0]; // 最小元素的值
208+
int listIdx = current[1]; // 当前元素所在的列表索引
209+
int elementIdx = current[2]; // 当前元素在列表中的索引
210+
211+
// 检查当前区间[currentVal, currentMax]是否比之前记录的最小区间更小
212+
// 或者区间长度相同但起点更小(题目要求返回最小的区间)
213+
if (currentMax - currentVal < minRange ||
214+
(currentMax - currentVal == minRange && currentVal < start)) {
215+
// 更新最小区间信息
216+
minRange = currentMax - currentVal;
217+
start = currentVal;
218+
end = currentMax;
219+
}
220+
221+
// 如果当前元素所在的列表还有下一个元素
222+
if (elementIdx + 1 < nums.get(listIdx).size()) {
223+
// 获取下一个元素的值
224+
int nextVal = nums.get(listIdx).get(elementIdx + 1);
225+
// 将下一个元素加入堆中
226+
minHeap.offer(new int[]{nextVal, listIdx, elementIdx + 1});
227+
// 更新当前最大值(因为新加入的元素可能比当前最大值更大)
228+
currentMax = Math.max(currentMax, nextVal);
229+
} else {
230+
// 如果当前列表已经遍历完,则退出循环
231+
// 因为无法保证每个列表至少有一个元素在区间内了
232+
break;
233+
}
234+
}
235+
236+
// 返回找到的最小区间
237+
return new int[]{start, end};
238+
}
239+
main(){
240+
Solution solution = new Solution();
241+
// 创建测试数据
242+
List<List<Integer>> nums = new ArrayList<>();
243+
nums.add(Arrays.asList(4, 10, 15, 24, 26));
244+
nums.add(Arrays.asList(0, 9, 12, 20));
245+
nums.add(Arrays.asList(5, 18, 22, 30));
246+
247+
// 调用方法并输出结果
248+
int[] result = solution.smallestRange(nums);
249+
}
250+
251+
```
252+
253+
254+

0 commit comments

Comments
 (0)