Leetcode.2522 将字符串分割成值不超过 K 的子字符串

题目链接

Leetcode.2522 将字符串分割成值不超过 K 的子字符串 rating : 1605

题目描述

给你一个字符串 s s s ,它每一位都是 1 1 1 到 9 9 9 之间的数字组成,同时给你一个整数 k k k 。

如果一个字符串 s s s 的分割满足以下条件,我们称它是一个 分割:

  • s s s 中每个数位 恰好 属于一个子字符串。
  • 每个子字符串的值都小于等于 k k k 。

请你返回 s s s 所有的 分割中,子字符串的 最少 数目。如果不存在 s s s 的 分割,返回 − 1 -1 −1 。

注意:

  • 一个字符串的 是这个字符串对应的整数。比方说,"123" 的值为 $1234 ,"1" 的值是 1 1 1 。
  • 子字符串 是字符串中一段连续的字符序列。
示例 1:

输入:s = "165462", k = 60

输出:4

解释:我们将字符串分割成子字符串 "16" ,"54" ,"6" 和 "2" 。每个子字符串的值都小于等于 k = 60 。

不存在小于 4 个子字符串的好分割。

示例 2:

输入:s = "238182", k = 5

输出:-1

解释:这个字符串不存在好分割。

提示:
  • 1 ≤ s . l e n g t h ≤ 1 0 5 1 \leq s.length \leq 10^5 1≤s.length≤105
  • s i si si'1''9' 之间的数字。
  • 1 ≤ k ≤ 1 0 9 1 \leq k \leq 10^9 1≤k≤109

解法一 : 动态规划

我们定义 f ( i ) f(i) f(i) 为 s s s 的前 i i i 个字符中,好分割的最少个数。按照定义,最终我们返回的答案就是 f ( n ) f(n) f(n)。

那么我们很容易就能得出状态转移方程:

f j = m a x ( f j , f i + 1 ) ( s i + 1 , j ≤ k , i < j ) fj = max(fj , fi + 1) \qquad (si + 1,j \leq k , i < j) fj=max(fj,fi+1)(si+1,j≤k,i<j)

由于 k ≤ 1 0 9 k \leq 10^9 k≤109,所以 j − i j - i j−i 最大就是 9 9 9。

时间复杂度: O ( n × 9 ) O(n \times 9) O(n×9)

C++代码:

cpp 复制代码
class Solution {
public:
    int minimumPartition(string s, int k) {
        int n = s.size();
        vector<int> f(n + 1,1e9);
        f[0] = 0;

        for(int i = 0;i <= n;i++){
            int len = min(n , i + 9) , sum = 0;

            for(int j = i + 1;j <= len;j++){
                sum = sum * 10 + (s[j - 1] - '0');
                if(sum > k) break;
                f[j] = min(f[i] + 1 , f[j]);
            }
        }

        //for(int i = 1;i <= n;i++) cout<<f[i]<<" ";

        return f[n] == 1e9 ? -1 : f[n];
    }
};

解法二:贪心

我们每次分割的时候,让 好分割 尽可能的大,剩下的子串就更少,所能得到的 好分割 也就越少。

所以贪心策略就是,每次分割的时候让 好分割 尽可能地大,这样最终的答案就是最少的。

时间复杂度: O ( n ) O(n) O(n)

C++代码:

cpp 复制代码
using LL = long long;

class Solution {
public:
    int minimumPartition(string s, int k) {
        int n = s.size() , ans = 0;
        for(int i = 0;i < n;i++){
            //可能会溢出 所以要用 long long
            LL sum = 0;
            int j = i;
            for(;j < n;j++){
                if((s[j] - '0') > k) return -1;
                sum = sum * 10 + (s[j] - '0');
                if(sum > k) break;
            }
            ans++;
            i = j - 1;
        }

        return ans;
    }
};
相关推荐
青山木7 小时前
Hot 100 --- 滑动窗口最大值
java·数据结构·算法·leetcode·动态规划
xhtdj1 天前
智源大会圆桌大模型没有终局具身智能可能是中国的 AlphaGo 时刻
人工智能·clickhouse·安全·动态规划
2301_764441331 天前
番茄钟+AI:高效专注的秘密武器
人工智能·算法·数学建模·动态规划·交互
wabs6661 天前
关于动态规划【0-1背包思想在实际问题中是怎么转化的?】
算法·动态规划
随意起个昵称1 天前
区间dp-进阶题目1(进阶合并)
c++·算法·动态规划
2601_961875242 天前
法考资料2026|全套|资料已整理
数据结构·算法·链表·贪心算法·eclipse·线性回归·动态规划
汉克老师2 天前
GESP2026年3月认证C++六级真题与解析(编程题1 选数)
c++·动态规划·线性dp·gesp六级·状态转移·选与不选
渡之2 天前
GRiM-Net 深度解析 | 无人机 GNSS 拒止场景下两阶段跨视角视觉定位框架
深度学习·算法·动态规划·无人机
xhtdj2 天前
Uber 如何通过批处理实现单账户每秒30+次更新
大数据·数据库·人工智能·安全·动态规划
wabs6662 天前
关于动态规划【纯粹的0-1背包需要思考的问题】
算法·动态规划