这是一个编程难题,类似于:“如果一个数字的子字符串的所有数字的乘积都具有唯一值,则该数字被认为是出色的。”
示例:263 (2, 6, 3, 2*6 = 12, 6*3 = 18) 非常棒。
但是 236 (2, 3, 6 , 2*3 = 6 , 3*6 = 18) 并不出色。
我们只取子串,不取子序列。
我在想,由于重复的产品计算,我们可以在这里应用动态编程吗?我们还有什么其他的解决方案?(这不是作业问题。)
这是一个编程难题,类似于:“如果一个数字的子字符串的所有数字的乘积都具有唯一值,则该数字被认为是出色的。”
示例:263 (2, 6, 3, 2*6 = 12, 6*3 = 18) 非常棒。
但是 236 (2, 3, 6 , 2*3 = 6 , 3*6 = 18) 并不出色。
我们只取子串,不取子序列。
我在想,由于重复的产品计算,我们可以在这里应用动态编程吗?我们还有什么其他的解决方案?(这不是作业问题。)
这是使用动态编程解决它的一种方法:
假设我们有数字d 0 d 1 ... d N作为输入。
这个想法是创建一个表格,其中单元格 ( i , j ) 存储产品d i · d i+1 · ... · d j。这可以有效地完成,因为 ( i , j ) 处的单元格可以通过将 ( i -1, j )处的数字乘以d i来计算。
由于i(起始索引)必须小于或等于j(结束索引),因此我们将关注表格的左下三角形。
生成表后,我们检查重复条目。
这是输入 2673 的具体示例解决方案:
我们分配一个矩阵M,尺寸为 4 × 4。
我们首先用d i填充对角线M i, i :
然后我们逐行,用d i · M i-1,j填写M i ,j
结果看起来像
为了检查重复,我们收集产品 (2, 12, 6, 84, 42, 7, 252, 126, 21, 3),对它们进行排序 (2, 3, 6, 7, 12, 21, 42, 84, 126, 252),然后循环查看两个连续的数字是否相等。如果是,我们返回 false,否则返回 true。
在 Java 代码中:
这是一个有效的 DP 解决方案,O(n 2 )。
public static boolean isColorful(int num) {
// Some initialization
String str = "" + num;
int[] digits = new int[str.length()];
for (int i = 0; i < str.length(); i++)
digits[i] = str.charAt(i) - '0';
int[][] dpmatrix = new int[str.length()][str.length()];
// Fill in diagonal: O(N)
for (int i = 0; i < digits.length; i++)
dpmatrix[i][i] = digits[i];
// Fill in lower left triangle: O(N^2)
for (int i = 0; i < str.length(); i++)
for (int j = 0; j < i; j++)
dpmatrix[i][j] = digits[i] * dpmatrix[i-1][j];
// Check for dups: O(N^2)
int[] nums = new int[digits.length * (digits.length+1) / 2];
for (int i = 0, j = 0; i < digits.length; i++, j += i)
System.arraycopy(dpmatrix[i], 0, nums, j, i+1);
Arrays.sort(nums);
for (int i = 0; i < nums.length - 1; i++)
if (nums[i] == nums[i+1])
return false;
return true;
}
对于对 DP 感兴趣的读者,我可以在这里推荐一些类似的问题/答案:
使用动态规划可能是要走的路:不是计算所有 O(n^2) 子串,然后使用 ~n 乘法命令来计算它们中的每一个,而是将先前计算的结果存储在矩阵 M 中,其中 M(i ,j) 是长度为 j 的子串的结果,从位置 i 开始。
(即,如果您的号码是 123456789,那么 M(1,5) 是 5!,而 M(1,6) 是 6!,只需将 M(1,5) 乘以 6 - 恒功)
这会将运行时间从 n 位的 O(n^3) 提高到 O(n^2)。
动态规划解决方案实际上是没有必要的,因为没有具有大量数字的出色数字(如果任何数字出现不止一次,则该数字不是出色的)。
这是每个出色数字的列表。共有 57,281 个。
这个文件在我的电脑上生成的时间不到一秒钟,即使没有使用动态编程:)
如果我们不将数字视为大字符串,那么散列会有所帮助;
int brill(int A) {
map<long long int,bool> m;
vector<int> arr(10,0);
int i=0;
while(A){
arr[i++]=A%10;
A/=10;
}
for(int j=0;j<i;j++){
long long int temp=1;
for(int k=j;k>=0;k--){
temp*=arr[k];
if(m.find(temp)!=m.end()){
return 0;
}
else{
m[temp]=true;
}
}
}
return 1;
}
n 是包含数字的字符串。
由于在失败状态之前该数字不能大于 8 位,因此它的 O(1)。
function isBrill(n) {
var set = {};
set[parseInt(n.charAt(0))] = true;
for(var i=0; i < n.length - 1; i++) {
var a = parseInt(n.charAt(i));
var b = parseInt(n.charAt(i+1));
if(set[b] === true) { return false; }
set[b] = true;
if(set[a * b] === true) { return false; }
set[a * b] = true;
}
return true;
}
isBrill("263"); // true
isBrill("236"); // false