max sub array

题外话,写“算法是一门技术”系列主要是感觉自己对算法背后的东西没有一个统一的认识,应该是功力尚浅,本系列大致计划是按照《算法导论》第三版的每个大的专题顺序进行撰写,记录些许自己的理解(所以会比较凌乱),不当之处,欢迎指正。

1,最直观的想法就是暴力,最终需要找到一个最大子序列,即数组A中的两个索引 i, j. 计算每个以i开头的子序列的最大值,然后比较每个max_sub_sum[i]即可。
2,divide and conquer,这是一种思想,首先要尝试这种方法的可行性。简单操作,一分为二,max_sub_array 要么left, 要么right,当然如果只有两个子问题那就好办,类似大事化小,小事化无,可惜没有免费的午餐,那就是子问题之间的联系必须考虑,题意中就是cross项, 而cross项不同于问题本身,或者说他是一个新问题(其实是添加了限制条件的子问题),正因为这个限制条件(left以mid为终点,right以mid+1为起点)使得我们在O(n)内解决他,整个问题自然就成了O(nlgn).
3,dynamic programming, 这也是一种思想,核心有两个:问题的解可以分为子问题的解,具有重叠子问题。如何构造子问题就是核心了,一般文章中会直接跳到下一步,即构造m[i]代表以i结尾max_sub_array, 然后直接给出递推公式就完了,但是m[i]是如何得到?这里就有些“尝试”的味道了,首先划分子问题,最终目标就是找到索引i, j。划分为不同索引结尾的子问题(有人说为什么不分为以不同索引开头的呢?其实也可以这么分,只不过这样就找不到递推式了,所以说有些“尝试”的味道),然后剩下的东西就水到渠成了!

/********Description*******/
//find the sum of contiguous sub array within a one-dimensional array of numbers 
//which has the largest sum and return the elements

//from "introduction to algorithms"  P38

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

//O(n^2)
void brute_force(vector<int>& array, int& s, int& e)
{
    int max_sum = INT_MIN;
    for (int i = 0; i < array.size(); i++)
    {
        int sub_sum = 0;
        for (int j = i; j < array.size(); j++)
        {
            sub_sum += array[j];
            if (sub_sum > max_sum)
            {
                max_sum = sub_sum;
                s = i;
                e = j;
            }
        }
    }
}

//O(nlgn): divide and conquer
int max_cross(vector<int>& a, int left, int mid, int right)
{
    //find left max_sum
    int left_max_sum = INT_MIN;
    int left_sum = 0;
    for (int i = mid; i >= left; i--)
    {
        left_sum += a[i];
        if (left_sum > left_max_sum)
            left_max_sum = left_sum;
    }

    //find right max_sum
    int right_max_sum = INT_MIN;
    int right_sum = 0;
    for (int i = mid + 1; i <= right; i++)
    {
        right_sum += a[i];
        if (right_sum > right_max_sum)
            right_max_sum = right_sum;
    }

    return left_max_sum + right_max_sum;
}

int max_sub(vector<int>& a, int left, int right)
{
    if (left == right)
        return a[left];
    else
    {
        int mid = (left + right) / 2;
        int sum_left = max_sub(a, left, mid);
        int sum_right = max_sub(a, mid + 1, right);
        int sum_cross = max_cross(a, left, mid, right);
        int ret = sum_right;
        if (sum_left > ret)
            ret = sum_left;
        if (sum_cross > ret)
            ret = sum_cross;
        return ret;
    }

}

//dynamic programming
int dp(vector<int>& a, int& s, int& e)
{
    if (a.size() < 1)
    {
        cout << "error" << endl;
        return -1;
    }

    vector<int> m(a.size(), 0);
    m[0] = a[0];
    int max_sum = m[0];

    int sub_s = 0;
    int sub_e = 0;
    for (int i = 1; i < m.size(); i++)
    {
        if (m[i - 1] + a[i] < a[i])
        {
            sub_s = i;
            sub_e = i;
        }
        else
        {
            sub_e = i;
        }
        m[i] = max(m[i - 1] + a[i], a[i]);
        if (m[i] > max_sum)
        {
            max_sum = m[i];
            s = sub_s;
            e = sub_e;
        }

    }

    return max_sum;
}

int main(int argc, char** argv)
{
    //test
    int start, end;
    vector<int> array{-2, -3, 4, -1, -2, 1, 5, -3};
    brute_force(array, start, end);

    for (int i = start; i <= end; i++)
        cout << array[i] << "   ";
    cout << endl;

    int ret = max_sub(array, 0, array.size() - 1);
    cout << ret << endl;

    int dp_ret = dp(array,start,end);
    cout << dp_ret << endl;
    for (int i = start; i <= end; i++)
        cout << array[i] << "   ";
    cout << endl;

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
This problem can be solved using a sliding window approach. We will maintain a window of indices [left, right] such that the sub-array A[left, right] contains at most K distinct elements. We will also maintain a hash table to keep track of the count of each element in the current window. Initially, left = 1, right = 1, and the hash table is empty. We will iterate over the array A from left to right and for each element A[right], we will update the hash table and the number of distinct elements in the current window. If the number of distinct elements is greater than K, we will move the left pointer to the right and update the hash table and the number of distinct elements accordingly. We will continue this process until the number of distinct elements is less than or equal to K. We will keep track of the maximum length of the sub-array found so far and the corresponding indices. At the end, we will output the indices of the longest sub-array found. Here's the Python code that implements this approach: ```python n, k = map(int, input().split()) a = list(map(int, input().split())) left = right = 0 count = {} max_len = 0 max_indices = (1, 1) while right < n: # Update count of current element count[a[right]] = count.get(a[right], 0) + 1 # Update number of distinct elements while len(count) > k: count[a[left]] -= 1 if count[a[left]] == 0: del count[a[left]] left += 1 # Update maximum sub-array length if right - left + 1 > max_len: max_len = right - left + 1 max_indices = (left, right+1) right += 1 print(max_indices[0], max_indices[1]) ``` This code has a time complexity of O(n) and a space complexity of O(k).

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值