返回介绍

solution / 2800-2899 / 2801.Count Stepping Numbers in Range / README_EN

发布于 2024-06-17 01:02:59 字数 10486 浏览 0 评论 0 收藏 0

2801. Count Stepping Numbers in Range

中文文档

Description

Given two positive integers low and high represented as strings, find the count of stepping numbers in the inclusive range [low, high].

A stepping number is an integer such that all of its adjacent digits have an absolute difference of exactly 1.

Return _an integer denoting the count of stepping numbers in the inclusive range_ [low, high]_. _

Since the answer may be very large, return it modulo 109 + 7.

Note: A stepping number should not have a leading zero.

 

Example 1:

Input: low = "1", high = "11"
Output: 10
Explanation: The stepping numbers in the range [1,11] are 1, 2, 3, 4, 5, 6, 7, 8, 9 and 10. There are a total of 10 stepping numbers in the range. Hence, the output is 10.

Example 2:

Input: low = "90", high = "101"
Output: 2
Explanation: The stepping numbers in the range [90,101] are 98 and 101. There are a total of 2 stepping numbers in the range. Hence, the output is 2. 

 

Constraints:

  • 1 <= int(low) <= int(high) < 10100
  • 1 <= low.length, high.length <= 100
  • low and high consist of only digits.
  • low and high don't have any leading zeros.

Solutions

Solution 1: Digit DP

We notice that the problem is asking for the number of stepping numbers in the interval $[low, high]$. For such an interval $[l,..r]$ problem, we can usually consider transforming it into finding the answers for $[1, r]$ and $[1, l-1]$, and then subtracting the latter from the former. Moreover, the problem only involves the relationship between different digits, not the specific values, so we can consider using Digit DP to solve it.

We design a function $dfs(pos, pre, lead, limit)$, which represents the number of schemes when we are currently processing the $pos$-th digit, the previous digit is $pre$, whether the current number only contains leading zeros is $lead$, and whether the current number has reached the upper limit is $limit$. The range of $pos$ is $[0, len(num))$.

The execution logic of the function $dfs(pos, pre, lead, limit)$ is as follows:

If $pos$ exceeds the length of $num$, it means that we have processed all the digits. If $lead$ is true at this time, it means that the current number only contains leading zeros and is not a valid number. We can return $0$ to indicate that the number of schemes is $0$; otherwise, we return $1$ to indicate that the number of schemes is $1$.

Otherwise, we calculate the upper limit $up$ of the current digit, and then enumerate the digit $i$ in the range $[0,..up]$:

  • If $i=0$ and $lead$ is true, it means that the current number only contains leading zeros. We recursively calculate the value of $dfs(pos+1,pre, true, limit\ and\ i=up)$ and add it to the answer.
  • Otherwise, if $pre$ is $-1$, or the absolute difference between $i$ and $pre$ is $1$, it means that the current number is a valid stepping number. We recursively calculate the value of $dfs(pos+1,i, false, limit\ and\ i=up)$ and add it to the answer.

Finally, we return the answer.

In the main function, we calculate the answers $a$ and $b$ for $[1, high]$ and $[1, low-1]$ respectively. The final answer is $a-b$. Note the modulo operation of the answer.

The time complexity is $O(\log M \times |\Sigma|^2)$, and the space complexity is $O(\log M \times |\Sigma|)$, where $M$ represents the size of the number $high$, and $|\Sigma|$ represents the digit set.

Similar problems:

class Solution:
  def countSteppingNumbers(self, low: str, high: str) -> int:
    @cache
    def dfs(pos: int, pre: int, lead: bool, limit: bool) -> int:
      if pos >= len(num):
        return int(not lead)
      up = int(num[pos]) if limit else 9
      ans = 0
      for i in range(up + 1):
        if i == 0 and lead:
          ans += dfs(pos + 1, pre, True, limit and i == up)
        elif pre == -1 or abs(i - pre) == 1:
          ans += dfs(pos + 1, i, False, limit and i == up)
      return ans % mod

    mod = 10**9 + 7
    num = high
    a = dfs(0, -1, True, True)
    dfs.cache_clear()
    num = str(int(low) - 1)
    b = dfs(0, -1, True, True)
    return (a - b) % mod
import java.math.BigInteger;

class Solution {
  private final int mod = (int) 1e9 + 7;
  private String num;
  private Integer[][] f;

  public int countSteppingNumbers(String low, String high) {
    f = new Integer[high.length() + 1][10];
    num = high;
    int a = dfs(0, -1, true, true);
    f = new Integer[high.length() + 1][10];
    num = new BigInteger(low).subtract(BigInteger.ONE).toString();
    int b = dfs(0, -1, true, true);
    return (a - b + mod) % mod;
  }

  private int dfs(int pos, int pre, boolean lead, boolean limit) {
    if (pos >= num.length()) {
      return lead ? 0 : 1;
    }
    if (!lead && !limit && f[pos][pre] != null) {
      return f[pos][pre];
    }
    int ans = 0;
    int up = limit ? num.charAt(pos) - '0' : 9;
    for (int i = 0; i <= up; ++i) {
      if (i == 0 && lead) {
        ans += dfs(pos + 1, pre, true, limit && i == up);
      } else if (pre == -1 || Math.abs(pre - i) == 1) {
        ans += dfs(pos + 1, i, false, limit && i == up);
      }
      ans %= mod;
    }
    if (!lead && !limit) {
      f[pos][pre] = ans;
    }
    return ans;
  }
}
class Solution {
public:
  int countSteppingNumbers(string low, string high) {
    const int mod = 1e9 + 7;
    int m = high.size();
    int f[m + 1][10];
    memset(f, -1, sizeof(f));
    string num = high;

    function<int(int, int, bool, bool)> dfs = [&](int pos, int pre, bool lead, bool limit) {
      if (pos >= num.size()) {
        return lead ? 0 : 1;
      }
      if (!lead && !limit && f[pos][pre] != -1) {
        return f[pos][pre];
      }
      int up = limit ? num[pos] - '0' : 9;
      int ans = 0;
      for (int i = 0; i <= up; ++i) {
        if (i == 0 && lead) {
          ans += dfs(pos + 1, pre, true, limit && i == up);
        } else if (pre == -1 || abs(pre - i) == 1) {
          ans += dfs(pos + 1, i, false, limit && i == up);
        }
        ans %= mod;
      }
      if (!lead && !limit) {
        f[pos][pre] = ans;
      }
      return ans;
    };

    int a = dfs(0, -1, true, true);
    memset(f, -1, sizeof(f));
    for (int i = low.size() - 1; i >= 0; --i) {
      if (low[i] == '0') {
        low[i] = '9';
      } else {
        low[i] -= 1;
        break;
      }
    }
    num = low;
    int b = dfs(0, -1, true, true);
    return (a - b + mod) % mod;
  }
};
func countSteppingNumbers(low string, high string) int {
  const mod = 1e9 + 7
  f := [110][10]int{}
  for i := range f {
    for j := range f[i] {
      f[i][j] = -1
    }
  }
  num := high
  var dfs func(int, int, bool, bool) int
  dfs = func(pos, pre int, lead bool, limit bool) int {
    if pos >= len(num) {
      if lead {
        return 0
      }
      return 1
    }
    if !lead && !limit && f[pos][pre] != -1 {
      return f[pos][pre]
    }
    var ans int
    up := 9
    if limit {
      up = int(num[pos] - '0')
    }
    for i := 0; i <= up; i++ {
      if i == 0 && lead {
        ans += dfs(pos+1, pre, true, limit && i == up)
      } else if pre == -1 || abs(pre-i) == 1 {
        ans += dfs(pos+1, i, false, limit && i == up)
      }
      ans %= mod
    }
    if !lead && !limit {
      f[pos][pre] = ans
    }
    return ans
  }
  a := dfs(0, -1, true, true)
  t := []byte(low)
  for i := len(t) - 1; i >= 0; i-- {
    if t[i] != '0' {
      t[i]--
      break
    }
    t[i] = '9'
  }
  num = string(t)
  f = [110][10]int{}
  for i := range f {
    for j := range f[i] {
      f[i][j] = -1
    }
  }
  b := dfs(0, -1, true, true)
  return (a - b + mod) % mod
}

func abs(x int) int {
  if x < 0 {
    return -x
  }
  return x
}
function countSteppingNumbers(low: string, high: string): number {
  const mod = 1e9 + 7;
  const m = high.length;
  let f: number[][] = Array(m + 1)
    .fill(0)
    .map(() => Array(10).fill(-1));
  let num = high;
  const dfs = (pos: number, pre: number, lead: boolean, limit: boolean): number => {
    if (pos >= num.length) {
      return lead ? 0 : 1;
    }
    if (!lead && !limit && f[pos][pre] !== -1) {
      return f[pos][pre];
    }
    let ans = 0;
    const up = limit ? +num[pos] : 9;
    for (let i = 0; i <= up; i++) {
      if (i == 0 && lead) {
        ans += dfs(pos + 1, pre, true, limit && i == up);
      } else if (pre == -1 || Math.abs(pre - i) == 1) {
        ans += dfs(pos + 1, i, false, limit && i == up);
      }
      ans %= mod;
    }
    if (!lead && !limit) {
      f[pos][pre] = ans;
    }
    return ans;
  };
  const a = dfs(0, -1, true, true);
  num = (BigInt(low) - 1n).toString();
  f = Array(m + 1)
    .fill(0)
    .map(() => Array(10).fill(-1));
  const b = dfs(0, -1, true, true);
  return (a - b + mod) % mod;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文