归并——算法(四)

归并递归至底,再从底至上合并结果
一般用于存在重复子结构的问题
一般能用归并的题都可以用动态规划,不过动态规划不容易想到,归并不错
给个例题,将区间划分为多个子区间,使得所有区间拥有的回文子串和最少
input
aacabbcbadabcbh
output
5
解释
a aca b bcbadabcb h

#include <bits/stdc++.h>
using namespace std;
int helper(string str, int i, int j, int l, int r){
    while (i>=l && j<=r && str[i]==str[j]){
        i--; j++;
    }
    return j-i-1;
}
void mergefunc(string str, int l, int r, int &res){
    if (l > r)
        return;
    int start=0, end=0;
    for (int i=l; i<=r; i++){
        int len1 = helper(str, i, i, l, r);
        int len2 = helper(str, i, i+1, l, r);
        if (max(len1, len2) > end-start){
            start = i - (max(len1, len2)+1)/2; 
            end = i + max(len1, len2)/2; 
        }
    }
    res++;
    mergefunc(str, l, start, res);
    mergefunc(str, end+1, r, res);
}
int main(){
    string str;
    while (cin >> str){
        int res = 0;
        mergefunc(str, 0, str.length()-1, res);
        cout << res << endl;
    }
    return 0;
}

不得不说,归并是真的很神奇的方法,你只需要切分,不用去管怎么合并的。

一道笔试题,也是使用归并
对于一个数组,找到两个不重叠的子数组,长度和最小。每个子数组和均为T
input
arr:3 1 5 2 4
T:4
output
3
解释
两个子数组分别为3,1和4,所以长度和为3

#include <bits/stdc++.h>
using namespace std;
using Pair = pair<int, int>;
Pair findT(vector<int> arr, int T, int l, int r){
    queue<int> que;//滑动窗口利用队列
    int sum = 0; int start=INT_MIN+1, end=INT_MAX-1; int res = INT_MAX;
    for (int i=l; i<=r; i++){
        sum += arr[i]; que.push(i);
        while (!que.empty() && sum > T){
            sum -= arr[que.front()];
            que.pop();
        }
        if (sum == T){
            sum -= arr[que.front()];
            if (res > i-que.front()){
                res = min(res, i-que.front());
                start = que.front(); end = i;//记录子数组的前后下标
            }
            que.pop();
        }
    }
    return {start, end};
}
void merge(vector<int>& A, int T, int l, int r, vector<int>& res){
    if (l > r) return;
    Pair temp = findT(A, T, l, r);
    if (temp.first != INT_MIN+1)
        res.push_back(temp.second-temp.first+1);//存储满足的子数组的长度
    merge(A, T, l, temp.first-1, res);
    merge(A, T, temp.second+1, r, res);
}
void minSumOfLengths(vector<int>& A, int T) {
    vector<int> res;
    merge(A, T, 0, A.size()-1, res);
    sort(res.begin(), res.end());
    if (res.size() < 2 || res[0] == INT_MIN+1) {
        cout << -1 << endl; 
        return;
    }
    cout << res[0]+res[1] << endl;//取最小两个元素
}
int main(){
    vector<int> A; int i;
    while (cin >> i) A.push_back(i);
    int T = A.back(); A.pop_back();
    minSumOfLengths(A, T);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华为云计算搬砖工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值