腾讯秋招编程题:01串的价值

给出一个只包含 0 和 1 的 01 串 s ,下标从 1 开始,设第 i 位的价值为 vali ,则价值定义如下:

i=1时:val1 = 1
i>1时:
2.1 若 si ≠ si-1 , vali = 1
2.2 若 si = si-1 , vali = vali-1 + 1
字符串的价值等于 val1 + val2 + val3 + … + valn
你可以删除 s 的任意个字符,问这个串的最大价值是多少。

思路:

1、整合字符串,将连续的1和连续的0看成是一个元素,可以减少需要处理的数据量

2、删除元素时候,连续的0和连续的1要么都删除,要么都保留

3、如果整合后的字符串元素数量小于40,进行递归计算,否则按照谁多留下谁,同时留下两端的异类。(如果1的数量大于0的数量,则删除所有的0,只留下两端的0,反之亦然)

代码如下:

#include <stdio.h>

struct data_compress {
    int subValue;   //这部分连续字串的value
    int cont_num;   //连续0或者连续1的长度
    char source_value;  //标识当前字串是1还是0
};


int cacu_count_value(int cont_num) {
    return cont_num * (cont_num + 1) / 2;
}

int max_value = 0;

/* 递归计算,选取最大值 */
void cacu_max_value(struct data_compress* data, int depth, int depthMax,
                    int cacuValue, int cont_num) {
    //printf("depth = %d cacuValue = %d cont_num = %d \n",depth,cacuValue,cont_num);
    int result;
    if (depth == depthMax - 1) {
        result = cacuValue + cont_num * (cont_num + 1) / 2;
        if (max_value < result) max_value = result;
    }
    if (depth + 1 < depthMax) {
        cacu_max_value(&data[1], depth + 1, depthMax, cacu_count_value(cont_num),
                       data[1].cont_num);
    }
    if (depth + 2 < depthMax) {
        cacu_max_value(&data[2], depth + 2, depthMax, cacuValue,
                       cont_num + data[2].cont_num);
    }
    return;
}

int main() {
    char array[5005];
    struct data_compress com_data[5005];
    int count;

    while (scanf("%d", &count) != EOF) { // 注意 while 处理多个 case
        scanf("%s", array);
        int cont_num = 0;
        int compress_num = 0;
        for (int i = 1; i < count; i++) {
            if (array[i] != array[i - 1]) {
                cont_num++;
                //printf("%d %d\n",com_data[compress_num].subValue, cont_num);
                com_data[compress_num].source_value = array[i - 1];
                com_data[compress_num].cont_num = cont_num;
                com_data[compress_num].subValue = cont_num * (cont_num + 1) / 2;
                compress_num++;
                cont_num = 0;
            } else {
                cont_num++;
            }
        }
        cont_num++;
        com_data[compress_num].source_value = array[count - 1];
        com_data[compress_num].cont_num = cont_num;
        com_data[compress_num].subValue = cont_num * (cont_num + 1) / 2;
        int num_1 = 0, num_0 = 0, max_con = 0;
        if (compress_num > 40) {  //元素数量大于40,选取多的元素进行组合计算
            max_value = 0;
            for (int i = 0 ; i <= compress_num; i++) {
                if (com_data[i].source_value == '0') num_0 = num_0 + com_data[i].cont_num;
                if (com_data[i].source_value == '1') num_1 = num_1 + com_data[i].cont_num;
            }
            if (num_0 > num_1) {
                max_con = num_0;
                if (com_data[0].source_value == '1') max_value += cacu_count_value(
                                com_data[0].cont_num);
                if (com_data[compress_num].source_value == '1') max_value += cacu_count_value(
                                com_data[compress_num].cont_num);
                max_value += cacu_count_value(max_con);
            } else {  // 元素数量小于40,进行递归计算
                max_con = num_1;
                if (com_data[0].source_value == '0') max_value += cacu_count_value(
                                com_data[0].cont_num);
                if (com_data[compress_num].source_value == '0') max_value += cacu_count_value(
                                com_data[compress_num].cont_num);
                max_value += cacu_count_value(max_con);
            }
        } else {
            cacu_max_value(com_data, 0, compress_num + 1, 0, com_data[0].cont_num);
        }
        printf("%d \n", max_value);
        for (int i = 0 ; i <= compress_num; i++)  {  //这个循环时调试打印
            //printf("%d, %d\n",max_value, com_data[i].cont_num);
        }
    }
    return 0;
}

这个代码可以通过18个案例,最后一个案例过不了。最后验算了一个,发现是腾讯给的答案是错的。

用例如下:

长度1000,具体值如下:

"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000011111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111110000000"

用例摘要
序列字符值长度
11714
2038
3145
40181
5115
607

根据连续字符提取为1个元素的方法,一共提取了6个元素。根据网上给的答案,是将第二个和第四个元素删除最后变成了两个元素。

第一个元素长度:714+45+15 = 774。按照题目给的方法计算结果是299925

第二个元素长度:7.按照题目给的方法计算结果是28。

两个元素相加 299925 + 28 =299953。

=============================================================

实际程序删除第二个和第五个得到最大值,同样是变成两个元素。

第一个元素长度:714 + 45 = 759。按照题目给的方法计算结果是288420

第二个元素长度:181 + 7 = 188。按照题目给的方法计算结果是17766

两个值相加:288420+ 17766= 306186

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值