分治算法例题

本文通过LeetCode的例题介绍了分治算法的应用,包括找众数、合并排序链表、最小的k个数和连续子数组最大和等问题。文中详细分析了每个问题的分治解法,同时讨论了其他可能的解决方案,如使用哈希、堆等数据结构。尽管有些问题分治解法不是最优,但依然展示了分治思想在解决复杂问题时的作用。
摘要由CSDN通过智能技术生成

例题

以下例题均来自LeetCode
后续不再另注来源

众数

多数元素

  • 如果一个数在数组nums里是众数即count(x) >= length/2 + 1
    • 那么该数的个数必比其他所有数的个数的总数还多
    • 将数组分为两份,该众数一定为其中一份的众数
  • 尝试用分治法解决该问题,将原数组不断分解为比他小的子数组,寻找子数组中的众数,根据子数组中的众数判断原数组的众数
    • 基本情况:len == 1 ,数组里仅有一个元素的时候
    • 分解: mid = l(ow + high)/ 2
      • 原址操作,仅传递在数组中的索引
    • 解决:当问题规模为1的时候直接返回元素,问题规模大于1继续分解
    • 合并:这道问题的关键在于根据子数组中的众数判断原数组的众数
  • nums有两个数组nums_1和nums_2。如果x是nums_1的众数,y是nums_2的众数
    • x == y : x 是nums的众数
    • x ! = y : 需要在整个区间内寻找x和y的数目比较哪个数更多 O(n)
  • 最坏情况下:O(nlgn)

C++代码如下

int majorityElement(vector<int>& nums) {
   
        int len = nums.size();
        if(len == 1) return nums[0];
        else 
        {
   
            int n = len - 1;
            return SubElement(nums, 0, n);
        }
    }
    int SubElement(vector<int>& nums, int low, int high)
    {
   
        vector<int> rst;
        if (low == high)
            return nums[low];
        else
        {
   
            int mid = (low+high)/2;
            int left_element = SubElement(nums, low, mid);
            int right_element = SubElement(nums, mid+1, high);
            if(left_element == right_element)
            {
   
                return left_element;
            }
            else
            {
   
                int len = high-low+1;
                int left_count = 0;int right_count = 0;
                for(int i=low; i<len; ++i)
                {
   
                    if(nums[i] == left_element) ++left_count;
                    else if (nums[i] == right_element) ++ right_count;
                    else continue;
                }
                return left_count > right_count ? left_element : right_element;
            }
        }

    }

此题用分治算法并不是最优算法

相似例题

数组的度

  • 在这道题里面我们还要得到与数组的度d相同的子数组的最短长度
  • 如果我们继续尝试用分治法解决的话在源代码上我们需要增添一个max_nums数组存储d的最大元素(可能有多个最大元素个数为d的数组元素)
  • 然后分别比较所有这些元素的最小长度

需要添加的伪代码如下

len_max_nums = len(max_nums);
rst = len + 1;
for i = 0 to len_max_nums - 1

2	target = max_nums[i]
	for j = 0 to len
		if (nums[j] == target)
			left_cur = j
			break
	for j = len down to 0
		if(nums[j] == target)
			right_cur = j
			break
	rst = min(rst, right_cur - left_cur + 1)
  • 除了继续用分治以外我们思考以下两种解题思路
  • hash
    • hash函数可以使我们以O(1)的时间访问到所hash的值指向的数据
    • 如果一个元素x其个数为d(数组的度为d)那么其最后一个出现x元素的坐标right_cur和最先出现的坐标left_cur。sub = right_cur - left_cur + 1。对所有元素个数为d产生的sub选取最小值

扩展

合并两个排序的链表

合并两个排序的链表

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
   
        if (l1 == NULL)
            return l2;
        else if(l2 == NULL)
            return l1;
        else
        {
   
            ListNode* rst = new ListNode(-1);
            ListNode* pre = rst;
            while(true)
            {
   
                if(l1->val >= l2->val)
                {
   
                    pre->next = new ListNode(l2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值