跳转至

1849. 将字符串拆分为递减的连续值

题目描述

给你一个仅由数字组成的字符串 s

请你判断能否将 s 拆分成两个或者多个 非空子字符串 ,使子字符串的 数值降序 排列,且每两个 相邻子字符串 的数值之 等于 1

  • 例如,字符串 s = "0090089" 可以拆分成 ["0090", "089"] ,数值为 [90,89] 。这些数值满足按降序排列,且相邻值相差 1 ,这种拆分方法可行。
  • 另一个例子中,字符串 s = "001" 可以拆分成 ["0", "01"]["00", "1"]["0", "0", "1"] 。然而,所有这些拆分方法都不可行,因为对应数值分别是 [0,1][0,1][0,0,1] ,都不满足按降序排列的要求。

如果可以按要求拆分 s ,返回 true ;否则,返回 false

子字符串 是字符串中的一个连续字符序列。

 

示例 1:

输入:s = "1234"
输出:false
解释:不存在拆分 s 的可行方法。

示例 2:

输入:s = "050043"
输出:true
解释:s 可以拆分为 ["05", "004", "3"] ,对应数值为 [5,4,3] 。
满足按降序排列,且相邻值相差 1 。

示例 3:

输入:s = "9080701"
输出:false
解释:不存在拆分 s 的可行方法。

示例 4:

输入:s = "10009998"
输出:true
解释:s 可以拆分为 ["100", "099", "98"] ,对应数值为 [100,99,98] 。
满足按降序排列,且相邻值相差 1 。

 

提示:

  • 1 <= s.length <= 20
  • s 仅由数字组成

解法

方法一:DFS

我们可以从字符串的第一个字符开始,尝试将其拆分成一个或多个子字符串,然后递归处理剩余的部分。

具体地,我们设计一个函数 $\textit{dfs}(i, x)$,其中 $i$ 表示当前处理到的位置,而 $x$ 表示上一个拆分出的数值。初始时 $x = -1$,表示我们还没有拆分出任何数值。

在 $\textit{dfs}(i, x)$ 中,我们首先计算当前拆分出的数值 $y$,如果 $x = -1$,或者 $x - y = 1$,那么我们可以尝试将 $y$ 作为下一个数值,继续递归处理剩余的部分。如果递归的结果为 $\textit{true}$,我们就找到了一种拆分方法,返回 $\textit{true}$。

遍历完所有的拆分方法后,如果没有找到合适的拆分方法,我们返回 $\textit{false}$。

时间复杂度 $O(n^2)$,空间复杂度 $O(n)$,其中 $n$ 是字符串的长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution:
    def splitString(self, s: str) -> bool:
        def dfs(i: int, x: int) -> bool:
            if i >= len(s):
                return True
            y = 0
            r = len(s) - 1 if x < 0 else len(s)
            for j in range(i, r):
                y = y * 10 + int(s[j])
                if (x < 0 or x - y == 1) and dfs(j + 1, y):
                    return True
            return False

        return dfs(0, -1)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
    private char[] s;

    public boolean splitString(String s) {
        this.s = s.toCharArray();
        return dfs(0, -1);
    }

    private boolean dfs(int i, long x) {
        if (i >= s.length) {
            return true;
        }
        long y = 0;
        int r = x < 0 ? s.length - 1 : s.length;
        for (int j = i; j < r; ++j) {
            y = y * 10 + s[j] - '0';
            if ((x < 0 || x - y == 1) && dfs(j + 1, y)) {
                return true;
            }
        }
        return false;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
    bool splitString(string s) {
        auto dfs = [&](this auto&& dfs, int i, long long x) -> bool {
            if (i >= s.size()) {
                return true;
            }
            long long y = 0;
            int r = x < 0 ? s.size() - 1 : s.size();
            for (int j = i; j < r; ++j) {
                y = y * 10 + s[j] - '0';
                if (y > 1e10) {
                    break;
                }
                if ((x < 0 || x - y == 1) && dfs(j + 1, y)) {
                    return true;
                }
            }
            return false;
        };
        return dfs(0, -1);
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func splitString(s string) bool {
    var dfs func(i, x int) bool
    dfs = func(i, x int) bool {
        if i >= len(s) {
            return true
        }
        y := 0
        r := len(s)
        if x < 0 {
            r--
        }
        for j := i; j < r; j++ {
            y = y*10 + int(s[j]-'0')
            if (x < 0 || x-y == 1) && dfs(j+1, y) {
                return true
            }
        }
        return false
    }
    return dfs(0, -1)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
function splitString(s: string): boolean {
    const dfs = (i: number, x: number): boolean => {
        if (i >= s.length) {
            return true;
        }
        let y = 0;
        const r = x < 0 ? s.length - 1 : s.length;
        for (let j = i; j < r; ++j) {
            y = y * 10 + +s[j];
            if ((x < 0 || x - y === 1) && dfs(j + 1, y)) {
                return true;
            }
        }
        return false;
    };
    return dfs(0, -1);
}

评论