|
|
package class_2022_04_3_week;
|
|
|
|
|
|
// 来自微众
|
|
|
// 4.11笔试
|
|
|
// 给定n位长的数字字符串和正数k,求该子符串能被k整除的子串个数
|
|
|
// (n<=1000,k<=100)
|
|
|
public class Code05_ModKSubstringNumbers {
|
|
|
|
|
|
// 暴力方法
|
|
|
// 为了验证
|
|
|
public static int modWays1(String s, int k) {
|
|
|
int n = s.length();
|
|
|
int ans = 0;
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
for (int j = i; j < n; j++) {
|
|
|
if (Long.valueOf(s.substring(i, j + 1)) % k == 0) {
|
|
|
ans++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
// 正式方法
|
|
|
// 时间复杂度O(N * k)
|
|
|
public static int modWays2(String s, int k) {
|
|
|
int[] cur = new int[k];
|
|
|
// 帮忙迁移
|
|
|
int[] next = new int[k];
|
|
|
// 0...i 整体余几?
|
|
|
int mod = 0;
|
|
|
// 答案:统计有多少子串的值%k == 0
|
|
|
int ans = 0;
|
|
|
for (char cha : s.toCharArray()) {
|
|
|
for (int i = 0; i < k; i++) {
|
|
|
// i -> 10个
|
|
|
// (i * 10) % k
|
|
|
next[(i * 10) % k] += cur[i];
|
|
|
cur[i] = 0;
|
|
|
}
|
|
|
int[] tmp = cur;
|
|
|
cur = next;
|
|
|
next = tmp;
|
|
|
mod = (mod * 10 + (cha - '0')) % k;
|
|
|
ans += (mod == 0 ? 1 : 0) + cur[mod];
|
|
|
cur[mod]++;
|
|
|
}
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
// 为了测试
|
|
|
public static String randomNumber(int n) {
|
|
|
char[] ans = new char[n];
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
ans[i] = (char) ((int) (Math.random() * 10) + '0');
|
|
|
}
|
|
|
return String.valueOf(ans);
|
|
|
}
|
|
|
|
|
|
// 为了测试
|
|
|
public static void main(String[] args) {
|
|
|
int N = 18;
|
|
|
int K = 20;
|
|
|
int testTime = 10000;
|
|
|
System.out.println("测试开始");
|
|
|
for (int i = 0; i < testTime; i++) {
|
|
|
String str = randomNumber((int) (Math.random() * N) + 1);
|
|
|
int k = (int) (Math.random() * K) + 1;
|
|
|
int ans1 = modWays1(str, k);
|
|
|
int ans2 = modWays2(str, k);
|
|
|
if (ans1 != ans2) {
|
|
|
System.out.println("出错了!");
|
|
|
System.out.println(str);
|
|
|
System.out.println(k);
|
|
|
System.out.println(ans1);
|
|
|
System.out.println(ans2);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
System.out.println("测试结束");
|
|
|
}
|
|
|
|
|
|
}
|