leetcode 23. Merge k Sorted Lists (分治法)

本文介绍了一种使用分治策略高效合并多个有序链表的方法,通过递归将链表分为两组并逐一合并,有效减少不必要的比较,最终实现O(logn * n^2)的时间复杂度。

题意:

给你k个有序的链表,让你合并成一个有序的链表。

思路:

直接一个一个合并的话,耗时448ms,超时了,对于这种方法,最先合并的数据可能会多次和后面的数据进行比较,这大大浪费了时间,运行时间会大于n^3。运用分治的方法,如果分成两组两组比较,合并好的数据之间就不会在进行比较,大大减少了比较的次数,运行时间最高为logn*n^2。

//java是完全的面向对象编程,不能在类外定义函数,调用函数必须先生成对象,,这点和c++很不同。。。

java代码:

class Solution {
    public ListNode dfs(ListNode[] lists,int s,int e){
        if(s==e){
            return lists[s];
        }
        ListNode root = new ListNode(0);
        ListNode temp = root;
        int mid = (s+e)>>1;
        ListNode head = dfs(lists,s,mid);
        ListNode list = dfs(lists,mid+1,e);
        while(head!=null||list!=null){
            if(head==null){
                temp.next = list;
                list = list.next;
            }
            else if(list==null||head.val<=list.val){
                temp.next = head;
                head = head.next;
            }
            else{
                temp.next = list;
                list = list.next;
            }
            temp = temp.next;
        }
        return root.next;
    }
    public ListNode mergeKLists(ListNode[] lists) {
        int len = lists.length;
        if(len==0)
            return null;
        int s = 0;
        int e = len-1;
        Solution ss = new Solution();
        return ss.dfs(lists,s,e);
    }
    Solution(){}
}

数据集介绍:垃圾分类检测数据集 一、基础信息 数据集名称:垃圾分类检测数据集 图片数量: 训练集:2,817张图片 验证集:621张图片 测试集:317张图片 总计:3,755张图片 分类类别: - 金属:常见的金属垃圾材料。 - 纸板:纸板类垃圾,如包装盒等。 - 塑料:塑料类垃圾,如瓶子、容器等。 标注格式: YOLO格式,包含边界框和类别标签,适用于目标检测任务。 数据格式:图片来源于实际场景,格式为常见图像格式(如JPEG/PNG)。 二、适用场景 智能垃圾回收系统开发: 数据集支持目标检测任务,帮助构建能够自动识别和分类垃圾材料的AI模型,用于自动化废物分类和回收系统。 环境监测与废物管理: 集成至监控系统或机器人中,实时检测垃圾并分类,提升废物处理效率和环保水平。 学术研究与教育: 支持计算机视觉与环保领域的交叉研究,用于教学、实验和论文发表。 三、数据集优势 类别覆盖全面: 包含三种常见垃圾材料类别,覆盖日常生活中主要的可回收物类型,具有实际应用价值。 标注精准可靠: 采用YOLO标注格式,边界框定位精确,类别标签准确,便于模型直接训练和使用。 数据量适中合理: 训练集、验证集和测试集分布均衡,提供足够样本用于模型学习和评估。 任务适配性强: 标注兼容主流深度学习框架(如YOLO等),可直接用于目标检测任务,支持垃圾检测相关应用。
<think>我们参考了用户提供的引用内容,这些引用主要涉及LeetCode上使用分治法解决的题目和相关算法思想。结合引用内容,我们整理出一些典型的LeetCode分治法题目,并简要说明解题思路。 ### 分治法简介 分治法的核心思想是“分而治之”,即将一个复杂问题分解成若干个相同或相似的子问题,递归地解决这些子问题,然后合并子问题的解得到原问题的解。分治法通常适用于问题可以被分解为相互独立的子问题的情况。 ### LeetCode分治法题目示例 以下题目均可以使用分治法解决,并附上简要说明: 1. **108. 将有序数组转换为二叉搜索树 (Convert Sorted Array to Binary Search Tree)** - 题目描述:将一个按照升序排列的有序数组转换为一棵高度平衡的二叉搜索树。 - 分治思路:每次选择数组中间位置的元素作为根节点,然后递归构建左子树和右子树。这样保证左右子树的高度差不超过1。 - 参考引用[1]中提供了Java和Python的代码实现。 2. **241. 为运算表达式设计优先级 (Different Ways to Add Parentheses)** - 题目描述:给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。 - 分治思路:遍历表达式,当遇到运算符时,将表达式分成左右两部分,分别计算左右两部分的所有可能结果,然后根据当前运算符将左右结果组合。递归进行直到表达式为单个数字。 - 参考引用[2]中提到了该题。 3. **53. 最大子序和 (Maximum Subarray)** - 题目描述:给定一个整数数组,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 - 分治思路:将数组分成左右两部分,最大子序和要么在左半部分,要么在右半部分,要么跨越左右两部分。分别求出这三部分的最大值,取三者中的最大值。其中跨越中点的最大子序和需要从中点向左右两边扫描计算。 - 参考引用[3]中提到了该题的分治解法(尽管更常见的可能是动态规划解法,但分治法也是可行的)。 4. **4. 寻找两个有序数组的中位数 (Median of Two Sorted Arrays)** - 题目描述:给定两个大小为 m 和 n 的有序数组,找出这两个有序数组的中位数。 - 分治思路:利用分治法在两个有序数组中寻找第k小的元素。通过比较两个数组的第k/2个元素,每次可以排除掉一部分元素,从而缩小搜索范围,直到找到中位数。 - 参考引用[5]中提供了详细的代码实现。 5. **23. 合并K个升序链表 (Merge k Sorted Lists)** - 题目描述:合并k个有序链表,返回合并后的有序链表。 - 分治思路:将k个链表分成两组,递归合并每组链表,再将合并后的两个链表合并。这种分治合并比顺序合并效率更高。 6. **169. 多数元素 (Majority Element)** - 题目描述:给定一个大小为 n 的数组,找到其中的多数元素(出现次数大于⌊n/2⌋的元素)。 - 分治思路:将数组分成两半,分别递归寻找每一半的多数元素,然后合并结果。如果在某一半中某个元素是多数元素,则在整个数组中需要验证它是否也是多数元素。 7. **215. 数组中的第K个最大元素 (Kth Largest Element in an Array)** - 题目描述:在未排序的数组中找到第k个最大的元素。 - 分治思路:利用快速选择算法(快速排序的变种),每次选择一个基准值将数组分为两部分,然后根据基准值的位置与k的关系,在其中一个子数组中递归查找。 ### 分治法算法框架 参考引用[4]中给出了分治法的算法框架: ``` Divide-and-Conquer(int n){ if(n<=n0){ // n0为可解子问题的规模 解子问题; return(子问题的解); } for(i=1;i<=k;i++){ // 分解成k个子问题 yi=Divide-and-Conquer(|Pi|); // 递归解决子问题 } T=MERGE(y1,y2,...,yk); // 合并子问题 return T; // 返回问题的解 } ``` ### 分治法解题要点 1. **分解**:将原问题分解为多个子问题,子问题相互独立且形式相同。 2. **解决**:递归解决子问题。当子问题足够小,直接求解。 3. **合并**:将子问题的解合并成原问题的解。 §§相关问题§§ 1. 分治法与动态规划有什么区别和联系? 2. 分治法的时间复杂度分析通常使用什么方法? 3. 如何判断一个问题是否适合用分治法解决? 4. 除了LeetCode题目,分治法还有哪些经典应用场景? 以上整理希望能帮助您更好地理解LeetCode中的分治法题目。如需具体题目的详细题解,可以参考LeetCode官方题解或相关讨论区。 </think>### LeetCode上可用分治法解决的题目汇总 分治法(Divide and Conquer)是算法设计的核心思想之一,通过将问题分解为子问题、递归求解、合并结果来解决复杂问题。以下是LeetCode中典型的分治算法题目及解题要点: --- #### **1. 树结构构建类** - **108. 将有序数组转换为二叉搜索树** 将升序数组转化为高度平衡的二叉搜索树(BST)。 **分治策略**: 1. 取数组中间元素作为根节点 2. 递归构建左子树(左半部分数组) 3. 递归构建右子树(右半部分数组) ```python def sortedArrayToBST(nums): def helper(l, r): if l > r: return None mid = (l + r) // 2 root = TreeNode(nums[mid]) root.left = helper(l, mid-1) root.right = helper(mid+1, r) return root return helper(0, len(nums)-1) ``` 引用[1]中提供了相同思路的Java/Python实现[^1]。 - **105/106. 从前序/后序与中序遍历序列构造二叉树** 利用中序序列的根节点位置分割左右子树,递归构建二叉树。 --- #### **2. 表达式与计算类** - **241. 为运算表达式设计优先级** 给定含运算符的表达式(如`"2*3-4*5"`),通过不同括号组合返回所有可能结果。 **分治策略**: 1. 遇到运算符时分割左右子表达式 2. 递归计算左右子表达式的所有结果 3. 组合左右结果(根据运算符计算) ```python def diffWaysToCompute(expression): if expression.isdigit(): return [int(expression)] res = [] for i, char in enumerate(expression): if char in '+-*': left = diffWaysToCompute(expression[:i]) right = diffWaysToCompute(expression[i+1:]) for l in left: for r in right: res.append(calc(l, r, char)) return res ``` 引用[2]指出该题是典型的分治应用[^2]。 --- #### **3. 数组与序列类** - **53. 最大子序和** 在整数数组中寻找和最大的连续子数组。 **分治策略**: 1. 将数组分为左右两半 2. 分别求左右最大子序和 3. 计算跨越中点的最大子序和 4. 取三者最大值 引用[3]提供了分治解法的代码实现[^3]。 - **4. 寻找两个有序数组的中位数** 合并两个有序数组并求中位数(要求$O(\log(m+n))$复杂度)。 **分治策略**: 1. 将问题转化为求第k小元素 2. 比较两数组第k/2个元素,排除较小值所在数组的前半部分 3. 递归处理剩余部分 ```java // 引用[5]的核心代码 double findMedianSortedArrays(int[] A, int m, int[] B, int n) { int l = (m + n + 1) / 2; int r = (m + n + 2) / 2; return (getkth(A, m, B, n, l) + getkth(A, m, B, n, r)) / 2.0; } ``` 引用[5]详细描述了该分治算法[^5]。 --- #### **4. 其他经典问题** - **23. 合并K个升序链表** 分治合并:两两合并链表,递归减少合并次数(时间复杂度$O(n\log k)$)。 - **169. 多数元素** 递归统计左右子数组的多数元素,合并时验证全局多数性。 - **215. 数组中的第K个最大元素** 基于快速选择算法(QuickSelect),分治partition思想。 --- ### 分治算法框架 引用[4]给出了分治算法的通用框架[^4]: ``` Divide-and-Conquer(Problem): if Problem.size ≤ n0: # 子问题足够小 return direct_solution(Problem) subProblems = divide(Problem) # 分解为子问题 results = [] for sub in subProblems: results.append(Divide-and-Conquer(sub)) # 递归求解 return merge(results) # 合并结果 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值