ieydpl 2008-6-17 23:17
两问题想问一下
最好最快的方法
计算从1到2008080808之间的整数有多少个含有数字7
将给定的字符串以词为单位倒序,同时给定一个子串,若字符串中有部分内容与子串相同则该部分不倒序。
例: 给定字符串"The quick brown fox jumps over the lazy dog"和子串"brown fox", 倒序结果是"dog lazy the over jumps brown fox quick The"
ieydpl 2008-6-18 12:59
怎么写
我想要 1到2008080808之间的整数有多少个含有数字7
如7,107,77,175,176,17。。。。。。。。。。。。。。
这是金山的考试题
Poshidon 2008-6-18 13:55
1、1个7-2个7+3个7-4个7+5个7-6个7+7个7-8个7+9个7
2、不需要用到正则表达式么?
Poshidon 2008-6-18 14:09
讨厌的算法有问题哦.....但是可以参考......
Poshidon 2008-6-18 15:08
2008080808这个数不是也太大了点!
Poshidon 2008-6-18 15:11
这个是从0到100的,1008080808太大了...
[code]var N:int =100;
var L:int;//数的位数;
var firstNumber:int;//数的第一个数字
var total:int;
for (var i:int = 0; i < N; i++) {
check7(i);
function check7(n:int) {
L = Math.floor(Math.log(n)/Math.LN10);//计算该数有多少位(十进制)
firstNumber = Math.floor(n/Math.pow(10,L));//求出第一位的数字
if (firstNumber == 7) {//如果这个数字是7,满足条件,计数加1;
total++;
trace(i);
return;
} else if (L>0) {如果这个数字不是7,如果它是2位及2位以上的数,将首数字去掉,重复上述操作;
n = n - firstNumber*Math.pow(10,L);
check7(n);
} else {如果这个数是一位数了,中止.
return;
}
}
}
trace("total=",total);[/code]
[[i] 本帖最后由 Poshidon 于 2008-6-18 15:17 编辑 [/i]]
wyang 2008-6-18 17:09
var vTotal:int = 0;
for(var i:int = 0; i < 8080808; i++)
{
if(i.toString().indexOf("7") != -1)
{
vTotal++;
}
}
trace(vTotal);
Poshidon 2008-6-18 17:18
每次看完别人写的东西,我的第一个反应总是——我为什么就没有想到呢...:'(
wyang 2008-6-18 17:19
import flash.utils.*;
var vTotal:int = 0;
var i = 0;
var vMax = 10000;
var vMaxNum = 80808;
function count()
{
for(i;i < vMax; i++)
{
if(i.toString().indexOf("7") != -1)
{
vTotal++;
}
}
setTimeout(reStart, 1);
}
function reStart()
{
if(i >= vMaxNum)
{
trace(vTotal);
}
else
{
vMax+= 10000;
if(vMax > vMaxNum)
vMax = vMaxNum;
count();
}
}
count();
数太大了,慢慢等吧
[[i] 本帖最后由 wyang 于 2008-6-18 17:31 编辑 [/i]]
Poshidon 2008-6-18 17:27
思维定势.....
Poshidon 2008-6-18 17:37
flash貌似超过15秒就没有响应了
终极讨厌 2008-6-18 17:54
我最先想到的也是 wyang 的这种方法,但我想,我上面的思路没有错吧?
难道还有漏掉的?
zhangancfan 2008-6-18 22:04
是啊...超过15秒就出错了...
ycccc8202 2008-6-19 01:34
就这个题目而言,可以通过找规律来进行计算,不然数字这么大怎么运算得动......
我找的规律 :
//===================
首位数字小于7
10==>1
100==>1*10+1 * 9^1=19
1000==>19*10+1 * 9^2=271
10000==>271*10+1 * 9^3=3439
....
20==>2
200==>2*10+2*9^1=38
2000==>38*10+2*9^2=542
20000==>542*10+2*9^3=6878
....
//======================
首位数字大于7
80==>10+7*9^0=17
800==>17*10+7*9^1=233
8000==>233*10+7*9^2=2897
80000==>2897*10+7*9^3=34073
....
90==>10+8*9^0=18
900==>18*10+8*9^1=252
9000==>252*10+8*9^2=3168
90000==>3168*10+8*9^3=37512
....
//PS:其中首位数字为7的规律我还没找出...还好这里给的数字2008080808里没有“7”,哈,先略过(把这数字的先解决再说),找出7的话能做出个通用式求任意的了~
通过以上规律得两方法:[code]/**
* @function downFunc //---- 7以下的计算 类似 10,100,1000,10000的计算
* @param m:uint //---- 首位数字
* @param n:uint //---- 跟随的零的个数
*/
function downFunc(m:uint,n:uint):uint {
if (n==1) {
return m;
}
return downFunc(m,n - 1) * 10 + m * Math.pow(9,n - 1);
}
/**
* @function upFunc //---- 7以上的计算 类似 80,800,8000的计算
* @param m:uint //---- 首位数字
* @param n:uint //---- 跟随的零的个数
*/
function upFunc(m:uint,n:uint):uint{
if (n==1) {
return (m + 9);
}
return upFunc(m,n - 1) * 10 + (m - 1) * Math.pow(9,n - 1);
}
//然后最后取结果就是这样的:
var n:uint=2008080808;
function getNum(n:uint):uint {
var tempArr:Array=String(n).split("");
trace(tempArr);
var result:uint=0;
while (tempArr.length) {
var m:uint=uint(tempArr.shift());
if (m==0) {
continue;
}
if (tempArr.length==0) {
if (m>7) {
result++;
}
continue;
}
result+=m<7?downFunc(m,tempArr.length):upFunc(m,tempArr.length)
}
return result;
}
trace(n,"中有","<",getNum(n),">","个7");[/code]//就是把数字先拆开,比如求8888就相当于是求(8000+800+80+8)来得到结果!
//我这里计算的结果是1229473242个,由于给的数字中没有7(7的规律还没找到),这样的结果应该是对的,哈~
//大家可以测试300000,800000这样的数字
trace(downFunc(3,5))//测试300000的结果
trace(upFunc(8,5))//测试800000的结果
......终极兄弟的结果一看也应该是错了,未免太小了点~
//第二个字符串排列的问题相对比较简单:[code]var str:String="The quick brown fox jumps over the lazy dog";
var p:String="brown fox";
function reRank(str:String,p:String) {
var a:Array=str.split(p);
return a[1].split(" ").reverse().join(" ") + p + a[0].split(" ").reverse().join(" ");
}
trace(reRank(str,p));[/code]
[[i] 本帖最后由 ycccc8202 于 2008-6-19 13:45 编辑 [/i]]
终极讨厌 2008-6-19 09:31
:lol 看完大虾的分析
我上面的计算方法确实是错的,而且是很错:L
[[i] 本帖最后由 终极讨厌 于 2008-6-19 09:32 编辑 [/i]]
Poshidon 2008-6-19 10:28
我首先想到的是集合中的一个定理,定理名字忘了,但是内容是这样的:几个集合的并集的元素个数=每个集合的元素数目-至少2个集合交集中的元素数目+至少3个集合交集中的元素数目-4个...+5个.........直到所有集合的交集的元素数目。
于是就想出1个7-2个7+3个7-4个7....的算法。不知道对不对?
Poshidon 2008-6-19 10:37
或者将这个数用8进制考虑....
错了...不考虑了..
[[i] 本帖最后由 Poshidon 于 2008-6-19 12:28 编辑 [/i]]
ycccc8202 2008-6-19 11:44
最后摸索出有7的规律了,整理如下:
70==>7+1
700==>7*10+7*9^0+1=134
7000==>133*10+7*9^1+1=1898
70000==>1897*10+7*9^2+1=24074
计算方法需要有点改动,还在整下,刚刚发的有点问题哈~
[[i] 本帖最后由 ycccc8202 于 2008-6-19 13:56 编辑 [/i]]
终极讨厌 2008-6-19 11:48
:lol :lol
UP楼上!!
ycccc8202 2008-6-19 12:43
[code]/**
* @function getNum //---- 取得1-n的整数中有多少个含有数字k的数字
* @param n:uint //---- 1-n的整数范围
* @param k:uint //---- 含有数字k 范围是1-9
*/
function getNum(n:uint,k:uint):uint {
if(k==0){
trace("k的范围应该是1-9!")
return 0;}
var tempArr:Array=String(n).split("");
trace(tempArr);
var result:uint=0;
var m:uint;
while (tempArr.length) {
m=uint(tempArr.shift());
if (m==0) {
continue;
}
if (tempArr.length==0) {
if (m>=k) {
result++;
}
continue;
}
result+=getF(m,tempArr.length,k);
if (m==k) {
return result + Number(tempArr.join(""));
}
}
return result;
}
/**
* @function getF //---- 首字母为m其余为0的计算 类似 80,900,4000等的计算求含有k的个数
* @param m:uint //---- 首位数字
* @param n:uint //---- 跟随的零的个数
* @param k:uint //---- 含有的数字k
*/
function getF(m:uint,n:uint,k:uint):uint {
switch (true) {
case m<k :
if (n==1) {
return m;
}
return getF(m,n - 1,k) * 10 + m * Math.pow(9,n - 1);
case m==k :
if (n==1) {
return m + 1;
}
return (getF(m,n - 1,k) - 1) * 10 + m * Math.pow(9,n - 1) + 1;
case m>k :
if (n==1) {
return m + 9;
}
return getF(m,n - 1,k) * 10 + (m - 1) * Math.pow(9,n - 1);
}
return null;
}
var n1:uint=2008080808;
var n2:uint=1000
var n3:uint=3979385;
trace(n1,"中有","<",getNum(n1,7),">","个",7);
trace(n2,"中有","<",getNum(n2,8),">","个",8);
trace(n3,"中有","<",getNum(n3,4),">","个",4);[/code]//现在可以计算出正整数范围内的含有数字k的个数了,k的范围是1-9,这里还不能计算出含有多少个0....含有0的还得找下规律:)
//大家可以用循环或者真循环来测试下,结果应该是吻合的,我这样总结出公式来计算效率就高了哈~
//以下是循环的检测方法,数字大了会很卡哦,不过用些小点的数字来验证下我上面公式的正确性[code]var n:uint=3979385
var result:uint;
for (var j:uint; j<=n; j++) {
if (String(j).indexOf("4")!=-1) {
result++;
}
}
trace(result)[/code]
[[i] 本帖最后由 ycccc8202 于 2008-6-19 13:44 编辑 [/i]]
Poshidon 2008-6-19 16:47
因为打字不如在本子上写字方便,所以在开始,我声明一个式子的意义:
C(n,r) = n!/(r!*(n-r)!)——表示从n个元素取R个,不进行排列,即是组合。这里的"!",也不是大家熟悉的逻辑运算符,而是阶乘运算符。
我在上面的帖子中提到过:1个7-2个7+3个7-4个7.....这里就讨论找7吧。
范围是1位数,0~9,那么结果是C(1,1)=1——只有一位,已经钉死是被找数了;
范围是2位数,00~99,C(2,1)*C(10,1)-C(2,2)*C(1,1)=2*10-1*1 = 19;开始的C(2,1)是从这2位数中选出7的选法,可以放十位,也可以放个位;C(10,1)很明确,当确定7后,别的位数可能的所有组合,这里也就是“1个7”的个数;C(2,2)*C(1,1),C(2,2)是从2个数位中选2个数位来放2个7,C(1,1)是7放好后别的数和它的所有组合,这里也就是“2个7”的个数;
范围是3位数,000~999,C(3,1)*C(100,1)-C(3,2)*C(10,1)+C(3,3)*C(1,1)=300-3-+1=271;同上,1个7-2个7+3个7;
范围是4位数,0000~9999,C(4,1)*C(1000,1)-C(4,2)*C(100,1)+C(4,3)*C(10,1)-C(4,4)*C(1,1)=4000-600+40-1=3439;
根据xxx定理(我实在是记不得那外国人叫什么了)可得通项公式:
F(n)=(-1)^(n+1)*C(n,1)*C(10^n,1)
待求数N = Σ(1~n)F(n)————此处n是目标数的位数,式子表示以n为参数的通项公式从1到n求和。
有了这个公式,我们所要做的就是将目标数按照春叶大哥的方法拆解成10次幂的倍数和,即几个m*10^x的和,然后用这个m和公式相乘。待查数k的用处是用来和m比大小的,小于则直接相乘,若是大于或等于,则先相乘,计算出忽略首数所有符合的数目,然后单独计算仅首数符合,别的数位都不符合的数,很简单,C(9,1)^(n-1)=9^(n-1);
举个例子吧,2887,
2*271+(8*19+9^2)+(8*1+9^1)+(9^0)=793.
知道了被找数k究竟在这个问题中扮演什么样一个角色后,就不难解决"0"的问题了,其实它是所有情况中最简单的一种,因为它不用讨论在数首的问题。不过到目前为止,我都是0~9,00~99,000~999这样讨论的,而题目是从“1”开始,所以记得最后的结果要-1.
好了,啰嗦了许多,接下来写成程序去...
Poshidon 2008-6-20 15:23
[code]
//=========组合===========
function comb(n:uint,r:uint):Number {
var N:Number = 1;
if (r>n/2) {
r = n - r;
}
for (var i:uint = 0; i<r; i++) {
N *= (n-i)/(r-i);
}
return N;
}
/*通项公式求和,先前的公式上标有误,
更正之(-1)^(i+1)*C(n,i)*C(10^(n-i),1)*/
function F(n:uint):uint {
var N:uint;
for (var i:uint = 1; i<=n; i++) {
N += Math.pow((-1),(i+1))*comb(n,i)*comb(Math.pow(10,n-i),1);
}
return N;
}
//=====主函数==========
function main_fun(n:uint,k:uint):uint {
var N:uint;
var firstSameNumber:Boolean;
var tempArr:Array=String(n).split("");
tempArr.forEach(tempArrCallBack);
function tempArrCallBack(item:*,index:int,arr:Array) {
var m:uint = uint(item);
var n:uint = tempArr.length-index-1;
if (!firstSameNumber) {//当首个等于k的数字没有出现时运行如下,出现了就终止
if (m<k) {
N += m*F(n);
} else if (m==k) {
firstSameNumber=true;
N += m*F(n)+uint(tempArr.slice(index+1).join(""))+1;//当首个等于k的数字出现后,不再统计了,直接将后面的数字+1后累加到原来的N上;
//trace(uint(tempArr.slice(index+1).join("")));
} else {
N += m*F(n)+Math.pow(9,n);
}
}
}
//====处理0的情况======
/*将0作为普通数字处理,得到N,然后考虑到0不能作为数首,
于是将所有仅数首数字为0的数字排除,故而对所有首位为0,
其它数位均不为0的数进行统计.
*/
if (k) {
return N;
} else {
var headIsZero:uint;
for (var i:uint=0; i<tempArr.length; i++) {
headIsZero += Math.pow(9,tempArr.length - i-1);//以4位数为例:0xxx,00xx,0x,0
}
//trace(N,headIsZero);
return N - headIsZero;
}
}
trace(main_fun(2008080808,0));
trace(main_fun(2008080808,7));[/code]
Poshidon 2008-6-20 15:30
我的确将0的情况轻看了。之前的想法有些地方欠妥。现在为了0牺牲了运行效率,采用的是将0当作普通数字统计,最后将特殊情况下——0作为数首的数字排除。不知道正确与否。只作抛砖引玉用。
ycccc8202 2008-6-20 18:01
恩,不错
这里把范围数字改成字符串形式的话,可以求很大的数字。
比如""2008080808200808080820080808082008080808200808080820080808082008080808""
因为我的方法中没有减法,所以反而能够得到结果
2.00668164238471e+69
//所以这里比较想知道没有减法参与的公式是杂样的,那样可以求很大的数字了
[[i] 本帖最后由 ycccc8202 于 2008-6-20 18:02 编辑 [/i]]
Poshidon 2008-6-23 11:40
"没有减法参与的公式"不能理解这句话的意思。可以求很大的数字和有没有减法有什么关系呢?容斥原理中本来就是1+2-3+4-5+6-7+8-9..不过,我觉得春叶用的递归方法应该要好点吧,我在计算组合的时候,因为组合公式是C(n,r) = n!/r!*(n-r)!,而阶乘这个东西涨起来是很快的,几下就超过上限了,因此将公式化简成
function comb(n:uint,r:uint):Number {
var N:Number = 1;
if (r>n/2) {
r = n - r;
}
for (var i:uint = 0; i<r; i++) {
N *= (n-i)/(r-i);
}
return N;
}
这样是几个小数的累乘,虽然数学结果肯定是正整数,但是不敢保证计算机在这里计算的时候完全没有误差。可能范围数太大了,这个公式的误差累计就明显了吧,也就没有意义了。不过求2008080808,7的结果和春叶的一致。
Poshidon 2008-6-23 11:42
虽然组合数肯定是uint的,但是我不知道计算机这样计算几个小数的累乘是否能保证是uint的,所以选择了Number
ycccc8202 2008-6-23 15:49
恩,是的~
我得好好学学公式,自己弄很痛苦,哈~
Poshidon 2008-6-23 17:55
呵呵,探索精神很好啊,找出来0的规律没有?
ycccc8202 2008-6-25 06:47
恩,0的情况也找出规律,下面是完整的结果:[code]/**
* @author : CYPL
* @function getNum //---- 取得1-n的整数字符串中有多少个含有数字k的数字
* @param n:uint //---- 1-n的整数范围
* @param k:uint //---- 含有数字k 范围是1-9
*/
function getNum(n:String,k:uint):Number {
if (k>9) {
return 0;
}
if (!isNaN(Number(n))) {
n=Number(n).toString();
} else {
return 0;
}
var tempArr:Array=n.split("");
var zlen:uint=tempArr.length;
var result:Number=0;
var m:uint;
var obj:Object;
while (tempArr.length) {
m=uint(tempArr.shift());
if (!k) {
if (!tempArr.length) {
break;
}
if (!m) {
result +=Number(tempArr.join(""))-(obj.k+1)*9;
break;
}
obj=getFObj0(m,tempArr.length);
result+=obj.result+(obj.k+1)*9;
} else {
if (!m) {
continue;
}
if (!tempArr.length) {
if (m>=k) {
result++;
}
break;
}
result+=getF(m,tempArr.length,k);
if (m==k) {
result +=Number(tempArr.join(""));
break;
}
}
}
return result;
}
/**
* @function getF //---- 首字母为m其余为0的计算 类似 80,900,4000等的计算求含有k的个数
* @param m:uint //---- 首位数字
* @param n:uint //---- 跟随的零的个数
* @param k:uint //---- 含有的数字k
*/
function getF(m:uint,n:uint,k:uint):uint {
switch (true) {
case m<k :
if (n==1) {
return m;
}
return getF(m,n - 1,k) * 10 + m * Math.pow(9,n - 1);
case m==k :
if (n==1) {
return m + 1;
}
return (getF(m,n - 1,k) - 1) * 10 + m * Math.pow(9,n - 1) + 1;
case m>k :
if (n==1) {
return m + 9;
}
return getF(m,n - 1,k) * 10 + (m - 1) * Math.pow(9,n - 1);
}
return null;
}
/**
* @function getFObj0 //---- 首字母为m其余为0的计算 类似 80,900,4000等的计算求含有0的个数的对象
* @param m:uint //---- 首位数字
* @param n:uint //---- 跟随的零的个数
*/
function getFObj0(m:uint,n:uint):Object {
if (n==1) {
return {result:m,k:-1};
}
var obj:Object=getFObj0(1,n-1);
var k:uint=(obj.k + 1) * 9;
obj={result:obj.result * 10 + 9 * k,k:k};
m && (obj.result=obj.result*m+(m-1)*(k+1)*9);
return obj;
}
var nStr1:String="62572457405820348";
var k1:uint=0;
var nStr2:String="2008080808";
var k2:uint=0;
var nStr3:String="2008080808";
var k3:uint=7;
trace(nStr1,"范围内含有",getNum(nStr1,k1),"个",k1);
trace(nStr2,"范围内含有",getNum(nStr2,k2),"个",k2);
trace(nStr3,"范围内含有",getNum(nStr3,k3),"个",k3);[/code]
beijing1995xz 2008-6-28 17:00
偶
晕:b35
beijing1995xz 2008-6-28 17:07
感谢你发表这么好的东东!
result:obj.result * 10 +
beijing1995xz 2008-6-28 17:08
感谢你发表这么好的东东!
两问题想问一下
beijing1995xz 2008-6-28 17:08
最好最快的方法
页:
[1]