华为OD机试 - 删除重复数字后的最大数字 - 贪心算法(Python/JS/C/C++ 2024 E卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

给定一个由纯数字组成以字符串表示的数值,现要求字符串中的每个数字最多只能出现 2 次,超过的需要进行删除;

删除某个重复的数字后,其它数字相对位置保持不变。

如"34533",数字 3 重复超过 2 次,需要删除其中一个 3,删除第一个 3 后获得最大数值 “4533”。

请返回经过删除操作后的最大值,以字符串表示。

二、输入描述

第一行为一个纯数字组成的字符串,长度范围:[1, 100000]

三、输出描述

输出经过删除操作后的最大数值

四、测试用例

测试用例1:

1、输入

34533

2、输出

4533

3、说明

数字3在字符串中出现了3次,超过2次,因此删除第一个3,得到最大数值"4533"。

测试用例2:

1、输入

5445795045

2、输出

5479504

3、说明

数字5在字符串中出现了3次,超过2次,因此删除第一个5,得到"5479504"。

五、解题思路

  1. 统计每个数字的总出现次数:
    • 在遍历字符串之前,首先统计每个数字在整个字符串中出现的总次数。这有助于我们在后续处理中决定是否可以删除某个数字以保留更大的数值。
  2. 使用栈(Stack)来构建结果字符串:
    • 栈的数据结构具有后进先出的特性,非常适合用于处理需要动态删除前面较小数字以保留更大数字的场景。
    • 在遍历字符串时,逐个处理每个数字,并决定是否将其加入栈中。
  3. 维护每个数字在栈中的保留次数:
    • 为了确保每个数字最多出现两次,我们需要记录当前数字在栈中的出现次数。如果某个数字已经在栈中出现了两次,再遇到该数字时直接跳过。
  4. 贪心策略:
    • 在决定是否删除栈顶数字以保留当前更大数字时,采用贪心策略。即如果当前数字比栈顶数字大,并且栈顶数字在后续仍有足够的出现次数(即总出现次数减去已处理次数仍大于等于2),则删除栈顶数字,保留当前更大的数字。
  5. 构建最终结果字符串:
    • 遍历完成后,栈中的数字即为删除多余数字后的结果。将栈中的数字按顺序拼接起来,得到最终的最大数值字符串。

六、Python算法源码

# 导入所需的库
from collections import defaultdict
import sys

def main():
    # 读取输入的数字字符串
    number_string = sys.stdin.read().strip()
    
    # 调用函数处理字符串,获取最大数值字符串
    max_number = remove_extra_digits_and_maximize(number_string)
    
    # 输出结果
    print(max_number)

def remove_extra_digits_and_maximize(number_string):
    # 用于记录每个数字字符在原字符串中剩余的未处理次数
    available_count = defaultdict(int)
    # 用于记录每个数字字符在结果栈中已保留的次数
    reserved_count = defaultdict(int)
    
    # 初始化available_count和reserved_count
    for digit in number_string:
        available_count[digit] += 1
        reserved_count[digit] = 0  # 初始化保留次数为0
    
    # 使用列表作为栈来构建结果字符串
    result_stack = []
    
    # 遍历输入字符串的每个数字字符
    for digit in number_string:
        # 如果当前数字在结果中已经保留了2个,则跳过当前数字
        if reserved_count[digit] == 2:
            # 减少该数字的剩余可用次数
            available_count[digit] -= 1
            continue
        
        # 尝试移除栈顶的数字以让位给更大的当前数字
        while result_stack:
            top_digit = result_stack[-1]
            # 检查是否可以移除栈顶数字
            # 条件:
            # 1. 栈顶数字小于当前数字
            # 2. 移除栈顶数字后,该数字在剩余字符串中仍有出现
            if top_digit < digit and available_count[top_digit] > 0:
                # 移除栈顶数字
                removed_digit = result_stack.pop()
                # 更新保留次数
                reserved_count[removed_digit] -= 1
            else:
                break
        
        # 将当前数字加入栈中
        result_stack.append(digit)
        # 更新保留次数
        reserved_count[digit] += 1
        # 更新剩余可用次数
        available_count[digit] -= 1
    
    # 构建结果字符串
    result = ''.join(result_stack)
    
    return result

if __name__ == "__main__":
    main()

七、JavaScript算法源码

// 导入 readline 模块用于读取输入
const readline = require('readline');

// 创建接口
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false
});

let input = [];

// 监听每一行输入
rl.on('line', function(line){
    input.push(line);
}).on('close', function(){
    // 读取输入的数字字符串
    let numberString = input[0].trim();
    
    // 调用函数处理字符串,获取最大数值字符串
    let maxNumber = removeExtraDigitsAndMaximize(numberString);
    
    // 输出结果
    console.log(maxNumber);
});

/**
 * 函数: removeExtraDigitsAndMaximize
 * 功能: 删除数字字符串中超过2次出现的数字,保留最大数值
 * @param {string} numberString 输入的数字字符串
 * @return {string} 处理后的最大数值字符串
 */
function removeExtraDigitsAndMaximize(numberString) {
    // 用于记录每个数字字符在原字符串中剩余的未处理次数
    let availableCount = {};
    // 用于记录每个数字字符在结果栈中已保留的次数
    let reservedCount = {};
    
    // 初始化availableCount和reservedCount
    for(let char of numberString){
        if(!(char in availableCount)){
            availableCount[char] = 0;
            reservedCount[char] = 0;
        }
        availableCount[char]++;
    }
    
    // 使用数组作为栈来构建结果字符串
    let resultStack = [];
    
    // 遍历输入字符串的每个数字字符
    for(let char of numberString){
        // 如果当前数字在结果中已经保留了2个,则跳过当前数字
        if(reservedCount[char] === 2){
            // 减少该数字的剩余可用次数
            availableCount[char]--;
            continue;
        }
        
        // 尝试移除栈顶的数字以让位给更大的当前数字
        while(resultStack.length > 0){
            let topDigit = resultStack[resultStack.length -1];
            // 检查是否可以移除栈顶数字
            // 条件:
            // 1. 栈顶数字小于当前数字
            // 2. 移除栈顶数字后,该数字在剩余字符串中仍有出现
            if(topDigit < char && availableCount[topDigit] > 0){
                // 移除栈顶数字
                resultStack.pop();
                // 更新保留次数
                reservedCount[topDigit]--;
            }
            else{
                break;
            }
        }
        
        // 将当前数字加入栈中
        resultStack.push(char);
        // 更新保留次数
        reservedCount[char]++;
        // 更新剩余可用次数
        availableCount[char]--;
    }
    
    // 构建结果字符串
    return resultStack.join('');
}

八、C算法源码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 定义最大长度
#define MAX_LEN 100005

int main(){
    char numberString[MAX_LEN];
    
    // 读取输入的数字字符串
    scanf("%s", numberString);
    
    int len = strlen(numberString);
    
    // 用于记录每个数字字符在原字符串中剩余的未处理次数
    int availableCount[10] = {0};
    // 用于记录每个数字字符在结果栈中已保留的次数
    int reservedCount[10] = {0};
    
    // 初始化availableCount和reservedCount
    for(int i = 0; i < len; i++){
        int digit = numberString[i] - '0';
        availableCount[digit]++;
    }
    
    // 使用字符数组作为栈来构建结果字符串
    char *resultStack = (char*)malloc(sizeof(char)*(len+1));
    int top = -1;
    
    // 遍历输入字符串的每个数字字符
    for(int i = 0; i < len; i++){
        char currentChar = numberString[i];
        int digit = currentChar - '0';
        
        // 如果当前数字在结果中已经保留了2个,则跳过当前数字
        if(reservedCount[digit] == 2){
            // 减少该数字的剩余可用次数
            availableCount[digit]--;
            continue;
        }
        
        // 尝试移除栈顶的数字以让位给更大的当前数字
        while(top >=0){
            char topChar = resultStack[top];
            int topDigit = topChar - '0';
            // 检查是否可以移除栈顶数字
            // 条件:
            // 1. 栈顶数字小于当前数字
            // 2. 移除栈顶数字后,该数字在剩余字符串中仍有出现
            if(topDigit < digit && availableCount[topDigit] >0){
                // 移除栈顶数字
                top--;
                // 更新保留次数
                reservedCount[topDigit]--;
            }
            else{
                break;
            }
        }
        
        // 将当前数字加入栈中
        top++;
        resultStack[top] = currentChar;
        // 更新保留次数
        reservedCount[digit]++;
        // 更新剩余可用次数
        availableCount[digit]--;
    }
    
    // 构建结果字符串
    resultStack[top+1] = '\0';
    
    // 输出结果
    printf("%s\n", resultStack);
    
    // 释放内存
    free(resultStack);
    
    return 0;
}

九、C++算法源码

#include <bits/stdc++.h>
using namespace std;

int main(){
    // 读取输入的数字字符串
    string numberString;
    cin >> numberString;
    
    int len = numberString.length();
    
    // 用于记录每个数字字符在原字符串中剩余的未处理次数
    int availableCount[10] = {0};
    // 用于记录每个数字字符在结果栈中已保留的次数
    int reservedCount[10] = {0};
    
    // 初始化availableCount和reservedCount
    for(char c : numberString){
        int digit = c - '0';
        availableCount[digit]++;
    }
    
    // 使用vector<char>作为栈来构建结果字符串
    vector<char> resultStack;
    
    // 遍历输入字符串的每个数字字符
    for(char c : numberString){
        int digit = c - '0';
        
        // 如果当前数字在结果中已经保留了2个,则跳过当前数字
        if(reservedCount[digit] == 2){
            // 减少该数字的剩余可用次数
            availableCount[digit]--;
            continue;
        }
        
        // 尝试移除栈顶的数字以让位给更大的当前数字
        while(!resultStack.empty()){
            char topChar = resultStack.back();
            int topDigit = topChar - '0';
            // 检查是否可以移除栈顶数字
            // 条件:
            // 1. 栈顶数字小于当前数字
            // 2. 移除栈顶数字后,该数字在剩余字符串中仍有出现
            if(topDigit < digit && availableCount[topDigit] >0){
                // 移除栈顶数字
                resultStack.pop_back();
                // 更新保留次数
                reservedCount[topDigit]--;
            }
            else{
                break;
            }
        }
        
        // 将当前数字加入栈中
        resultStack.push_back(c);
        // 更新保留次数
        reservedCount[digit]++;
        // 更新剩余可用次数
        availableCount[digit]--;
    }
    
    // 构建结果字符串
    string result(resultStack.begin(), resultStack.end());
    
    // 输出结果
    cout << result << "\n";
    
    return 0;
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哪 吒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值