归并排序、最大子数组

1.归并排序

分治模式:

(1)分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。

(2)解决子问题,递归求解子问题。子问题规模足够小时,直接求解。

(3)合并子问题的解,得到原问题的解。

归并排序完全遵循分治模式。

(1)分解待排序的n个元素列成各具n/2个元素的两个子序列。

(2)使用归并排序递归地排序两个子序列。

(3)合并两个已排序的子序列,产生已排序的答案。

时间复杂度:T(n)=O(n*lgn)

代码:

#include<iostream>
#include<vector>
using namespace std;

vector<int> merge(vector<int> vec1, vector<int> vec2)
{
    vector<int> vec;

    auto it1 = vec1.begin();
    auto it2 = vec2.begin();

    while (it1 != vec1.end() && it2 != vec2.end())
    {
        if (*it1<*it2)
        {
            vec.push_back(*it1);
            ++it1;
        }
        else
        {
            vec.push_back(*it2);
            ++it2;
        }
    }

    while (it1 != vec1.end())
    {
        vec.push_back(*it1);
        ++it1;
    }

    while (it2 != vec2.end())
    {
        vec.push_back(*it2);
        ++it2;
    }

    return vec;
}

void merge_sort(vector<int> &vec)
{
    if (vec.size()>1)//
    {
        vector<int> vec1;
        for (auto it = vec.begin(); it !=vec.begin() + (vec.end() - vec.begin()) / 2; ++it)
        {
            vec1.push_back(*it);
        }
        merge_sort(vec1);//

        vector<int> vec2;
        for (auto it = vec.begin()+(vec.end() - vec.begin()) / 2 ; it != vec.end(); ++it)
        {
            vec2.push_back(*it);
        }
        merge_sort(vec2);//

        vector<int> temp = merge(vec1, vec2);//

        vec = temp;////保存已排序的部分元素
    }
}

int main()
{
    vector<int> vec = { 2, 3, 2, 5, 6, 1, -1, 3, 14, 12 };
    merge_sort(vec);
    for (auto c : vec)
        cout << c << ",";

    cout << endl;

    system("pause");
    return 0;
}

2.最大子数组问题

在含有负数(如果数组元素全部为正数,那最大子数组就是整个数组)的数组中找出元素之和最大的子数组。

使用分治策略的求解方法:

设有A[low...high],mid=(low+high)/2,则最大子数组A[i...j]:

(1)完全在A[low...mid]中,low<=i<=j<=mid.//子问题

(2)完全在A[mid+1...high]中,mid<i<=j<=high.//子问题

(3)跨越了中点,low<=i<=mid<j<=high.//新问题

在三种情况中选取和最大者。

伪代码:

array<int,3> find_max_subarray(ivec,int low,int high)
{
    if(low==high)
        return {low,high,ivec[low]};//base case:only one element
    else{
        int mid=(low+high)/2;

        left=find_max_subarray(ivec,low,mid);
        right=find_max_subarray(ivec,mid+1,high);
        cross=find_max_crossing_subarray(ivec,low,mid ,high);

        if(left[2]>=right[2]&&left[2]>=cross[2])
            return left;
        else if(right[2]>=left[2]&&right[2]>=cross[2])
            return right;
        else
            return cross;
}

array<int,3> find_max_crossing_subarray(ivec,int low,int mid,int high)
{
    int left_sum=MIN;
    int right_sum=MIN;
    int sum=0;
    int max_left=mid,max_right=mid;

    for(int i=mid;i>=low;i--)
    {
        sum+=ivec[i];
        if(sum>left_sum)
        {
            left_sum=sum;
            max_left=i;
        }
    }

    sum=0;
    for(int j=mid+1;j<=high;j++)
    {
        sum+=ivec[j];
        if(sum>right_sum)
        {
            right_sum=sum;
            max_right=j;
        }
    }

    return {max_left,max_right,left_sum+right_sum};//最左下标、最右下标、元素之和
}

时间复杂度:T(n)=O(n*lgn)

不难发现,如果数组元素全为负数,则最大子数组就是最大元素。相应地,也有最小子数组问题。

时间: 2024-11-29 08:20:40

归并排序、最大子数组的相关文章

分治策略 &nbsp; 最大子数组问题

递归式 递归式与分治方法是紧密相关的,因为使用递归式可以很自然地刻画分治算法的运行时间.一个递归式就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数.例如,在2.3.2节,我们用递归式描述了MERGE-SORT过程的最坏情况运行时间T(n): Θ(1)        若n=1 T(n) =                         (4.1) 2T(n/2)+Θ(n)    若n>1 求解可得T(n)=Θ(nlgn) 递归式可以有很多形式.例如,一个递归算法可能将问题划分为规模

最大子数组

/*求子数组的最大和题目描述:输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). 例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18.*/ 1 #include<stdio.h> 2 typedef struct addelem{ 3 int low; 4 int high; 5 int max;

用分治和递归的思想——寻找最大子数组

寻找最大子数组的问题可描述为 输入: 一个数组,一个低位,一个高位 输出: 数组中从低位到高位中,连续和最大是多少 首先能想到的最直接的办法是暴力解决,遍历所有可能的序列组合,如果有n个元素,则需遍历的子序列有,复杂度为n2,稍有些经验的就能马上意识到,有很多重复计算在里面,比如最长的子序列计算,包含了之前所有子序列的计算.接下来我们使用分治的思想求解这个最大子序列,前一篇博文提过,分治的思想是将大问题分解为同等类型的子问题,再将子问题求解,然后合并子问题得出原问题的解,其中用到了递归的思想,因

分治法——最大子数组

题目描述: 给定一个n个元素的数组a,求a[i]+a[i+1]+-+a[j]的最大值(0 <= i <= j < n) 解题思路: 我们来试试用分治法来解决这个问题.首先我们想要找到一个子数组a[i-j]为最大子数组,我们假设数组的中点为mid,可以将数组a[low-high]分成两个子数组:a[low-mid]和a[mid+1-high],那么最大子数组必然为下述三种可能之一: 1) low <= i , j <= mid ; 2) mid < i , j <=

软件工程课程作业(四)--返回一个整数数组中最大子数组的和

伙伴链接:http://www.cnblogs.com/haoying1994/ 一.设计思想 本实验要求输入一个正负数混合的整型数组,长度不限,在此数组的所有子数组中找到和最大的数组,并求出相应数组的和,且时间复杂度为O(n).我们在课堂上共同讨论了多种解决方案,这些将在下面可能的解决方案中展示,在听了同学的思路和老师的讲解之后, 我们最终选取了老师课堂上描述的比较简便的思路.如下: 在输入数组的环节,采用for无限循环加if判断截止,直到触发回车键为止,将数组记录到Array中,数组长度记录

lincode.41 最大子数组

最大子数组 描述 笔记 数据 评测 给定一个整数数组,找到一个具有最大和的子数组,返回其最大和. 注意事项 子数组最少包含一个数 您在真实的面试中是否遇到过这个题? Yes 哪家公司问你的这个题? Airbnb Amazon LinkedIn Cryptic Studios Dropbox Apple Epic Systems TinyCo Yelp Hedvig Zenefits Uber Snapchat Yahoo Microsoft Bloomberg Facebook Google T

首尾相连求最大子数组和

题目要求: 1.输入一个一维整形数组,数组里有正数也有负数. 2.一维数组首尾相接,象个一条首尾相接带子一样. 3.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值. 设计思想: 遍历数组里面的每一个数将第一个数变为最后一个数,具体算法 a[i-1]=a[i],这样又变成了一个新的一维数组,输出每个数组的最大子数组和,然后比较每个输出的和,找出最大的数 代码: import java.util.Scanner; public class shuzu { p

最大子数组问题

小渣今天再来更新一波,欢迎看众 老爷们尽情喷(批评指导) 何为最大子数组:简言之,就是一数组A[n]中从i到j的连续子序列(i,j均在(0,n)区间内),且不存在另一对(a,b)对使得A[a]+A[a+1]+.....A[b]>A[i]+A[i+1]+...+A[j] 可见:①只有在数组含有负数元素时这个问题才有探讨的价值,否则整个数组本身即是最大子数组了: ②并且,i<=j(最大子数组可能只含有一个元素) ③最大子数组可能不唯一 思路:按照二分法来做,最大子数组两端无非有三种情况: 在左半部

结对开发——返回整数数组最大子数组和2

返回整数数组最大子数组和2 为了实现“敏捷开发”的目的,老师让我们采取“迭代”的方法进行项目的开发,这不,对于周一的求最大子数组和又有了新的要求,如下: 1.延续上次的要求,这里不再赘余… 2.如果数组A[0]……A[j-1]首尾相连,允许A[i-1],……A[n-1],A[0]……A[j-1]之和最大: 3.同时返回最大子数组的位置: 4.要求程序必须能处理1000 个元素,且每个元素是int32 类型的. 一.实验设计思路 首先实现的是数组首尾相连,先存入数组,再将原数组反向存储形成环形数组