算法训练-数据结构

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 个元素 pricesi 表示一支给定股票第 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, heighti) 。

找出其中的两条线,使得它们与 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);
}
相关推荐
海石37 分钟前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石38 分钟前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry3 小时前
LeetCode 151. 反转字符串中的单词
算法
gugucoding3 小时前
31. 【C语言】堆栈与队列的实现
c语言·开发语言·数据结构·链表
ChaoZiLL4 小时前
我的数据结构3——链表(link list)
数据结构·链表
a1117765 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜5 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry5 小时前
LeetCode 541. 反转字符串 II
算法
Jerry6 小时前
LeetCode 344. 反转字符串
算法
搞科研的小刘选手6 小时前
【香港大学主办&IEEE出版】第六届计算机视觉、应用与算法国际学术会议(CVAA 2026)
算法·计算机视觉·应用·学术会议