最大数字问题

一、题目描述

给定一个由纯数字组成以字符串表示的数值,现要求字符串中的每个数字最多只能出现2次,超过的需要进行删除;删除某个重复的数字后,其它数字相对位置保持不变。

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

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

二、输入输出描述

输入描述
  • 第一行:纯数字字符串,长度范围 [1, 100000]。
输出描述
  • 删除重复数字后的最大数值字符串(无前置零,空串返回空)。

三、示例

|----|-------|
| 输入 | 34533 |
| 输出 | 4533 |
| 说明 | |

|----|------------|
| 输入 | 5445795045 |
| 输出 | 5479504 |
| 说明 | |

四、解题思路

1. 核心思想

通过 "贪心 + 栈" 策略重构数字字符串:优先让高位保留更大的数字,同时通过unusedreserve两个哈希表保证 "每个数字最终最多保留 2 个" 的约束 ------ 核心是 "栈顶优化(替换更小数字)+ 约束校验(保证数字保留数量)"。

2. 问题本质分析
  • 表层问题:在 "每个数字最多出现 2 次" 的约束下,将原数字字符串重构为尽可能大的新字符串;
  • 深层问题:带约束的贪心排序,核心矛盾是 "追求高位更大" 与 "保证数字出现次数不超 2 次" 的平衡;
  • 关键难点:优化栈顶时,需确保被弹出的数字仍能通过 "剩余未遍历数 + 已保留数" 满足 "最多 2 个" 的约束,避免某数字最终出现次数不足(或超量)。
3. 核心逻辑
  • 约束跟踪:用unused(未遍历的数字数量)和reserve(已保留的数字数量)跟踪每个数字的可用状态,确保最终出现次数≤2;
  • 贪心优化:遍历每个数字时,若当前数字比栈顶大,且弹出栈顶后该数字仍能满足 "保留≤2 个" 的约束,则弹出栈顶(让高位更大);
  • 边界控制:若某数字已保留 2 个,后续该数字直接跳过,不加入栈。
4. 步骤拆解
  1. 状态初始化

    • 统计每个数字的总个数,初始化unused(总个数)和reserve(0);
    • 初始化空栈,用于存储最终结果序列。
  2. 遍历处理每个数字字符

    • 跳过已保留 2 个的数字(直接减少unused,不处理);
    • 循环优化栈顶:若当前数字更大,且弹出栈顶后该数字仍能满足约束,则弹出栈顶;
    • 保留当前数字:入栈,更新unused(-1)和reserve(+1)。
  3. 结果生成

    • 拼接栈中所有字符,得到最终的最大数字字符串。

五、代码实现

java 复制代码
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    String str = sc.next();

    System.out.println(getResult(str));
  }

  public static String getResult(String str) {
    // 每个数字字符的可用个数
    HashMap<Character, Integer> unused = new HashMap<>();
    // 每个数字字符的保留个数
    HashMap<Character, Integer> reserve = new HashMap<>();

    // 初始时,每个数字有多少个,就可用多少个,由于还未使用,因此保留个数为0
    for (int i = 0; i < str.length(); i++) {
      char c = str.charAt(i);
      unused.put(c, unused.getOrDefault(c, 0) + 1);
      reserve.putIfAbsent(c, 0);
    }

    // 定义一个栈
    LinkedList<Character> stack = new LinkedList<>();

    // 遍历输入字符串的每个数字字符c
    for (int i = 0; i < str.length(); i++) {
      char c = str.charAt(i);

      // 如果该字符已经保留了2个了,则后续再出现该数字字符可以不保留
      if (reserve.get(c) == 2) {
        // 则可用c数字个数--
        unused.put(c, unused.get(c) - 1);
        continue;
      }

      // 比较当前数字c和栈顶数字top,如果c>top,那么需要考虑将栈顶数字弹出
      while (stack.size() > 0) {
        char top = stack.getLast();

        // 如果栈顶数字被弹出后,已保留的top字符数量和未使用的top字符数量之和大于等于2,则可以弹出,否则不可以
        if (top < c && unused.get(top) + reserve.get(top) - 1 >= 2) {
          stack.removeLast();
          reserve.put(top, reserve.get(top) - 1);
        } else {
          break;
        }
      }

      // 选择保留当前遍历的数字c
      stack.add(c);
      // 则可用c数字个数--
      unused.put(c, unused.get(c) - 1);
      // 已保留c数字个数++
      reserve.put(c, reserve.get(c) + 1);
    }

    StringBuilder sb = new StringBuilder();
    for (Character c : stack) {
      sb.append(c);
    }
    return sb.toString();
  }
}
相关推荐
java修仙传2 小时前
力扣hot100:搜索二维矩阵
算法·leetcode·矩阵
梦里不知身是客112 小时前
tomcat作用和功能以及默认端口号
java·tomcat
嗝o゚2 小时前
Flutter + 鸿蒙实现多模态智能终端实战:语音+手势+触控融合
flutter·华为·开源
luxy20042 小时前
HarmonyOS 5.0 AT指令4G透传控制器
华为·harmonyos
码界奇点2 小时前
基于SpringBoot与Vue3的多租户中后台管理系统设计与实现
java·spring boot·后端·spring·车载系统·毕业设计·源代码管理
浅川.252 小时前
xtuoj 字符串计数
算法
长安城没有风2 小时前
在 IntelliJ IDEA 中高效使用 Git 的实用指南
java·git·intellij-idea
Code blocks2 小时前
SpringBoot从0-1集成Netty实现自定义协议开发
java·spring boot·后端
天`南2 小时前
【群智能算法改进】一种改进的金豺优化算法IGJO[1](动态折射反向学习、黄金正弦策略、自适应能量因子)【Matlab代码#94】
学习·算法·matlab