leetcode
leetcode 2251 ~ 2300
找出字符串的可整除数组

找出字符串的可整除数组

难度:

标签:

题目描述

You are given a 0-indexed string word of length n consisting of digits, and a positive integer m.

The divisibility array div of word is an integer array of length n such that:

  • div[i] = 1 if the numeric value of word[0,...,i] is divisible by m, or
  • div[i] = 0 otherwise.

Return the divisibility array of word.

 

Example 1:

Input: word = "998244353", m = 3
Output: [1,1,0,0,0,1,1,0,0]
Explanation: There are only 4 prefixes that are divisible by 3: "9", "99", "998244", and "9982443".

Example 2:

Input: word = "1010", m = 10
Output: [0,1,0,1]
Explanation: There are only 2 prefixes that are divisible by 10: "10", and "1010".

 

Constraints:

  • 1 <= n <= 105
  • word.length == n
  • word consists of digits from 0 to 9
  • 1 <= m <= 109

代码结果

运行时间: 77 ms, 内存: 19.0 MB


/*
 * 题目思路:
 * 1. 使用 Java Stream 处理字符串 word 的每个字符,逐个累加形成前缀数字。
 * 2. 对每个前缀数字检查是否能被 m 整除。
 * 3. 如果能被整除,则在结果数组的相应位置标记 1,否则标记 0。
 */
import java.util.stream.IntStream;

public class Solution {
    public int[] divisibilityArray(String word, int m) {
        int n = word.length();
        final long[] num = {0};
        return IntStream.range(0, n).map(i -> {
            num[0] = num[0] * 10 + (word.charAt(i) - '0');
            int result = (num[0] % m == 0) ? 1 : 0;
            num[0] %= m; // 避免溢出,保留余数
            return result;
        }).toArray();
    }
}

解释

方法:

这道题要求对于字符串 'word' 中的每个前缀,判断其转换成整数后是否能被 'm' 整除。直接计算每个前缀的整数值会非常耗时,尤其是前缀很长的情况。因此,题解采用了模运算的性质来逐步构建每个前缀的模 'm' 值。通过维护一个当前值 'cur',每次读取一个新的字符,都将 'cur' 更新为 '(cur * 10 + 当前字符值) % m'。这样,'cur' 始终保持为当前前缀对 'm' 的模。如果 'cur' 为0,则说明当前前缀可以被 'm' 整除,反之则不能。这种方法避免了直接计算大数的除法,是一种时间效率和空间效率较高的解决方案。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在计算前缀的模时使用`(cur * 10 + ord(char) - 48) % m`这种表达式?
这种表达式是为了逐步构建和更新字符串前缀所表示的数值的模`m`。其中,`ord(char) - 48`是将字符(假设是'0'到'9'的数字字符)转换成对应的整数值(例如,将字符'2'转换为整数2)。`cur * 10`是将当前已构建的数值左移一位(即数值乘以10),然后加上新的数字,形成新的更长的前缀数值。最后,取这个结果对`m`的模,得到当前前缀对`m`的余数。这种计算方式有效地避免了大整数的直接运算,同时利用模运算的性质(`(a * b) % c == ((a % c) * (b % c)) % c`),确保结果的正确性。
🦆
这个解法中,`cur`变量的更新方式是否能保证在所有情况下正确表示前缀的模值?
是的,这种更新方式能够确保在所有情况下正确表示前缀的模值。由于模运算的性质,每一步的`(cur * 10 + 数字) % m`计算都是基于之前的模值进行的,这保证了即使数值非常大,也能通过分步计算获得准确的模值。因此,`cur`的更新方式是有效且正确的,无论前缀有多长。
🦆
如果输入的`m`值非常大,这种方法计算模的效率是否会受到影响?
虽然输入的`m`值非常大可能会稍微影响计算效率,但由于现代计算机处理大整数的模运算相当高效,这种影响通常是可以接受的。模运算是一个快速的算术操作,即使对于较大的数字,现代处理器也能够快速执行。因此,即使`m`的值很大,该方法的效率仍然是较高的,不会有显著的性能下降。
🦆
此算法是否适用于字符串中包含非数字字符的情况,如果不是,应该如何修改?
当前算法假设字符串中只包含数字字符。如果字符串包含非数字字符,则`ord(char) - 48`的结果可能不是一个有效的0到9之间的数字,从而导致错误的计算。如果需要处理包含非数字字符的字符串,算法需要修改以先检测字符是否为数字。可以在计算前添加一个判断条件,例如使用`char.isdigit()`来检查字符是否为数字,如果不是数字,则可以跳过该字符或者将其处理为特定的逻辑(例如错误处理或返回特定结果)。

相关问题