88
99我们可以先计算 $s$ 的每个前缀(包括空前缀)对应的数字,即 $\textit{preNum} = [ 0,1,12,123,1234,12345] $。
1010
11- 想一想,如何得到 $34$?
11+ 想一想,如何从这些数中得到 $34$?
1212
13- 我们可以计算 $1234 - 12\cdot 10^2 = 1234-1200 = 34$。其中 $2$ 是子串的长度 。
13+ 我们可以计算 $1234 - 12\cdot 10^2 = 1234-1200 = 34$。其中 $2$ 是子串 $34$ 的长度 。
1414
1515一般地,子串 $[ l,r] $ 对应的数字为
1616
2222
2323这意味着我们还需要计算子串中的非零字符个数,代替上式中的 $r-l+1$。
2424
25- 维护把非零字符视作 $1$,计算其前缀和。
25+ 把 $s$ 中的非零字符视作 $1$,计算其前缀和。
2626
27- 注意取模, 原理见 [ 模运算的世界:当加减乘除遇上取模] ( https://leetcode.cn/circle/discuss/mDfnkW/ ) 。
27+ 代码实现时,注意取模。为什么可以在中途取模? 原理见 [ 模运算的世界:当加减乘除遇上取模] ( https://leetcode.cn/circle/discuss/mDfnkW/ ) 。
2828
29- 下午两点 [ B站@灵茶山艾府 ] ( https://space .bilibili.com/206214 ) 直播讲题,欢迎关注 ~
29+ [ 本题视频讲解 ] ( https://www .bilibili.com/video/BV1arUKBbEks/?t=52m5s ) ,欢迎点赞关注 ~
3030
3131``` py [sol-Python3]
3232MOD = 1_000_000_007
@@ -40,17 +40,17 @@ for i in range(1, MAX_N):
4040class Solution :
4141 def sumAndMultiply (self , s : str , queries : List[List[int ]]) -> List[int ]:
4242 n = len (s)
43- sum_d = [0 ] * (n + 1 ) # s 的前缀和
44- pre_num = [0 ] * (n + 1 ) # s 的前缀对应的数字(模 MOD)
45- sum_non_zero = [0 ] * (n + 1 ) # s 的前缀的非零数字个数
43+ sum_d = [0 ] * (n + 1 ) # s 的前缀和
44+ pre_num = [0 ] * (n + 1 ) # s 的前缀对应的数字(模 MOD)
45+ sum_non_zero = [0 ] * (n + 1 ) # s 的前缀中的非零数字个数
4646 for i, d in enumerate (map (int , s)):
4747 sum_d[i + 1 ] = sum_d[i] + d
4848 pre_num[i + 1 ] = (pre_num[i] * 10 + d) % MOD if d else pre_num[i]
4949 sum_non_zero[i + 1 ] = sum_non_zero[i] + (d > 0 )
5050
5151 ans = []
5252 for l, r in queries:
53- r += 1 # 注意这里把 r 加一了
53+ r += 1 # 避免下面多次计算 r+1
5454 length = sum_non_zero[r] - sum_non_zero[l]
5555 x = pre_num[r] - pre_num[l] * pow10[length]
5656 ans.append(x * (sum_d[r] - sum_d[l]) % MOD )
@@ -62,8 +62,15 @@ class Solution {
6262 private static final int MOD = 1_000_000_007 ;
6363 private static final int MAX_N = 100_001 ;
6464 private static final int [] pow10 = new int [MAX_N ];
65+ private static boolean initialized = false ;
66+
67+ // 这样写比 static block 快
68+ private void init () {
69+ if (initialized) {
70+ return ;
71+ }
72+ initialized = true ;
6573
66- static {
6774 // 预处理 10 的幂
6875 pow10[0 ] = 1 ;
6976 for (int i = 1 ; i < MAX_N ; i++ ) {
@@ -72,24 +79,26 @@ class Solution {
7279 }
7380
7481 public int [] sumAndMultiply (String s , int [][] queries ) {
82+ init();
83+
7584 int n = s. length();
7685 int [] sumD = new int [n + 1 ]; // s 的前缀和
7786 int [] preNum = new int [n + 1 ]; // s 的前缀对应的数字(模 mod)
78- int [] sumNonZero = new int [n + 1 ]; // s 的前缀的非零数字个数
87+ int [] sumNonZero = new int [n + 1 ]; // s 的前缀中的非零数字个数
7988 for (int i = 0 ; i < n; i++ ) {
8089 int d = s. charAt(i) - ' 0' ;
81- sumD[i + 1 ] = sumD[i] + d; // s 的前缀和
82- preNum[i + 1 ] = d > 0 ? (int ) ((preNum[i] * 10L + d) % MOD ) : preNum[i]; // s 的前缀对应的数字(模 MOD)
83- sumNonZero[i + 1 ] = sumNonZero[i] + (d > 0 ? 1 : 0 ); // s 的前缀的非零数字个数
90+ sumD[i + 1 ] = sumD[i] + d;
91+ preNum[i + 1 ] = d > 0 ? (int ) ((preNum[i] * 10L + d) % MOD ) : preNum[i];
92+ sumNonZero[i + 1 ] = sumNonZero[i] + (d > 0 ? 1 : 0 );
8493 }
8594
8695 int [] ans = new int [queries. length];
8796 for (int i = 0 ; i < queries. length; i++ ) {
8897 int l = queries[i][0 ];
89- int r = queries[i][1 ] + 1 ; // 注意这里把 r 加一了
98+ int r = queries[i][1 ] + 1 ; // 注意这里已经把 r 加一了
9099 int length = sumNonZero[r] - sumNonZero[l];
91- long x = preNum[r] - (long ) preNum[l] * pow10[length] % MOD ; // 注意结果可能是负数,所以下面 +MOD
92- ans[i] = (int ) ((x + MOD ) * (sumD[r] - sumD[l]) % MOD );
100+ long x = preNum[r] - (long ) preNum[l] * pow10[length] % MOD + MOD ; // +MOD 保证结果非负
101+ ans[i] = (int ) (x * (sumD[r] - sumD[l]) % MOD );
93102 }
94103 return ans;
95104 }
@@ -119,16 +128,16 @@ public:
119128 int d = s[ i] - '0';
120129 sum_d[ i + 1] = sum_d[ i] + d; // s 的前缀和
121130 pre_num[ i + 1] = d > 0 ? (pre_num[ i] * 10LL + d) % MOD : pre_num[ i] ; // s 的前缀对应的数字(模 MOD)
122- sum_non_zero[ i + 1] = sum_non_zero[ i] + (d > 0); // s 的前缀的非零数字个数
131+ sum_non_zero[ i + 1] = sum_non_zero[ i] + (d > 0); // s 的前缀中的非零数字个数
123132 }
124133
125134 vector<int> ans;
126135 ans.reserve(queries.size()); // 预分配空间
127136 for (auto& q : queries) {
128- int l = q[0], r = q[1] + 1; // 注意这里把 r 加一了
137+ int l = q[0], r = q[1] + 1; // 注意这里已经把 r 加一了
129138 int length = sum_non_zero[r] - sum_non_zero[l];
130- long long x = pre_num[r] - 1LL * pre_num[l] * pow10[length] % MOD; // 注意结果可能是负数,所以下面 +mod
131- ans.push_back((x + MOD) * (sum_d[r] - sum_d[l]) % MOD);
139+ long long x = pre_num[r] - 1LL * pre_num[l] * pow10[length] % MOD + MOD ; // +MOD 保证结果非负
140+ ans.push_back(x * (sum_d[r] - sum_d[l]) % MOD);
132141 }
133142 return ans;
134143 }
@@ -152,7 +161,7 @@ func sumAndMultiply(s string, queries [][]int) []int {
152161n := len (s)
153162sumD := make ([]int , n+1 ) // s 的前缀和
154163preNum := make ([]int , n+1 ) // s 的前缀对应的数字(模 mod)
155- sumNonZero := make ([]int , n+1 ) // s 的前缀的非零数字个数
164+ sumNonZero := make ([]int , n+1 ) // s 的前缀中的非零数字个数
156165for i , ch := range s {
157166d := int (ch - ' 0' )
158167sumD[i+1 ] = sumD[i] + d
@@ -168,8 +177,8 @@ func sumAndMultiply(s string, queries [][]int) []int {
168177for i , q := range queries {
169178l , r := q[0 ], q[1 ]+1
170179length := sumNonZero[r] - sumNonZero[l]
171- x := preNum[r] - preNum[l]*pow10[length]%mod // 注意结果可能是负数,所以下面 +mod
172- ans[i] = (x + mod) * (sumD[r] - sumD[l]) % mod
180+ x := preNum[r] - preNum[l]*pow10[length]%mod + mod // +mod 保证结果非负
181+ ans[i] = x * (sumD[r] - sumD[l]) % mod
173182}
174183return ans
175184}
@@ -182,6 +191,10 @@ func sumAndMultiply(s string, queries [][]int) []int {
182191- 时间复杂度:$\mathcal{O}(n+q)$,其中 $n$ 是 $\textit{nums}$ 的长度,$q$ 是 $\textit{queries}$ 的长度。
183192- 空间复杂度:$\mathcal{O}(n)$。返回值不计入。
184193
194+ ## 相似题目
195+
196+ [ 2156. 查找给定哈希值的子串] ( https://leetcode.cn/problems/find-substring-with-given-hash-value/ )
197+
185198## 专题训练
186199
187200见下面数据结构题单的「** 一、前缀和** 」。
0 commit comments