有一个整型变量最大的取值范围是1到这个值
1、如a:=39时,它可能的取值有39个,从1、2、3...39
2、有一个动态数组 b: array of [0..9] 取值范围仅仅为0,1,2,3,4,5,6,7,8,9这十个数,如
length(b,3)
b[0]=3;
b[1]=7;
b[2]=9;
3、请问如何计算,在a所有的取值范围内,其值中不出现b中的数字,有多少个?
如此例中 a=1,a=2,a=4..a=25都是合要求的,而a=31是不合要求的,因为31中有3这个数字(b[0]=3) 有一个笨算法
k:=0;for i:=1 to 39 do begin
isno:=false;
for j:=low(b) to high(b) do begin
if pos(inttostr(b[j]), inttsotr(i))>=1 then begin
isno:=true;
break;
end;
end;
if isno=false then k:=k+1;
end;最后k就是结果
1、如a:=39时,它可能的取值有39个,从1、2、3...39
2、有一个动态数组 b: array of [0..9] 取值范围仅仅为0,1,2,3,4,5,6,7,8,9这十个数,如
length(b,3)
b[0]=3;
b[1]=7;
b[2]=9;
3、请问如何计算,在a所有的取值范围内,其值中不出现b中的数字,有多少个?
如此例中 a=1,a=2,a=4..a=25都是合要求的,而a=31是不合要求的,因为31中有3这个数字(b[0]=3) 有一个笨算法
k:=0;for i:=1 to 39 do begin
isno:=false;
for j:=low(b) to high(b) do begin
if pos(inttostr(b[j]), inttsotr(i))>=1 then begin
isno:=true;
break;
end;
end;
if isno=false then k:=k+1;
end;最后k就是结果
var
numset:set of 0..9;
i:Integer;
begin
numset:=[];
for i:=0 to len-1 do
begin
numset:=numset+[b[i]];
end;
Result:=True;
repeat
if (a mod 10) in numset then
begin
Result:=False;
break;
end;
a:=a div 10;
until a=0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
b:array[0..9] of Integer;
begin
b[0]:=3;
b[1]:=7;
b[2]:=9;
if TestArray(21,b,3) then ShowMessage('ok');
end;
首先对问题做如下分析:
假如从从 0 到 9 的扫描中只有a,b,c三个数满足要求,那么在接下来的判断中
只用判断1a,1b,1c,2a,2b,2c,....9a,9b,9c几组数,很容易看出这组扫描中仍然只有
aa,ab,ac,ba,bb,bc,ca,cb,cc几组满足要求,继续很容易发现只有包含a,b,c几个数字
组成的数(在允许范围内)才有可能满足要求。
所以不难得出如下算法。}function GetTheBaseNum(num,base:Integer):String;
begin
if num<base then
Result:=IntToStr(num)
else
Result:=GetTheBaseNum(num div base,base)+IntToStr((num mod base));
end;
function GetOkNum(a:Integer;b:array of Integer;len:Integer=10):Integer;
var
numset:set of 0..9;
tb:array[0..9] of Integer;
astr,numstr:String;
num,oknum,la,ma,l,i,j:Integer;
begin
Result:=0;
oknum:=0;
numset:=[];
la:=Length(IntToStr(a));
for i:=0 to len-1 do
begin
numset:=numset+[b[i]];
end;
for i:=0 to 9 do
begin
if not (i in numset) then
begin
tb[oknum]:=i;//得到了一个从小到大的不包含在数组b中的数字序列。
Inc(oknum);//为满足条件的数字计数
end;
end;
i:=1;
repeat
astr:=GetTheBaseNum(i,oknum);
la:=length(astr);
numstr:='';
for j:=1 to la do
begin
ma:=ord(astr[j])-ord('0');
numstr:=numstr+inttostr(tb[ma]);
end;
inc(i);
until strtoint(numstr)>a;
Result:=i-1;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
b:array[0..9] of Integer;
begin
b[0]:=8;
b[1]:=9;
b[2]:=7;
showmessage(IntToStr(GetOkNum(31236,b,3)));
end;
wizardqi(男巫)
您的算法我测试了一个
1、普通的情况结果值比我用笨办法计算的值大了1
2、没有考虑exclude为0 的情况: 如b[1]:=0
3、最致命的是,您的算法似乎不比笨办法快
b[0]:=8;
b[1]:=9;
b[2]:=7;
showmessage(IntToStr(GetOkNum(31236,b,3)));您的值是7672,而我的是7671 b[0]:=8;
b[1]:=0;
b[2]:=7;
showmessage(IntToStr(GetOkNum(31236,b,3)));
您的值是4871,而我的是7671
我觉得最大改进是有几种有效组合就循环几次,其实我早先作了个办法只是计算次数,但后来想想如果要输出这样数的序列就没法了,所以想了上面的办法。我使用了一个最精密的计数器来测量你我的代码的效率,你可以看看结果。计数器如下:
function GetCounter:Int64;
asm
dw 310fh;
end;
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,Math;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
s1,s2:Int64;
end;var
Form1: TForm1;implementation{$R *.DFM}
function GetCounter:Int64;
asm
dw 310fh;
end;
function GetTheBaseNum(num,base:Integer):String;
begin
if num<base then
Result:=IntToStr(num)
else
Result:=GetTheBaseNum(num div base,base)+IntToStr((num mod base));
end;
function GetOkNum(a:Integer;b:array of Integer;len:Integer=10):Integer;
const
num0asc=48;
var
numset:set of 0..9;
tb:array[0..9] of char;//Integer;
numstr:array[0..15] of char;
astr:String;
num,oknum,la,ma,l,i,j:Integer;
begin
Result:=0;
oknum:=0;
numset:=[];
for i:=0 to len-1 do
begin
numset:=numset+[b[i]];
end;
for i:=0 to 9 do
begin
if not (i in numset) then
begin
tb[oknum]:=Char(i+num0asc);//得到了一个从小到大的不包含在数组b中的数字序列。
Inc(oknum);//为满足条件的数字计数
end;
end;
i:=1;
repeat
astr:=GetTheBaseNum(i,oknum);
la:=length(astr);
numstr[la]:=#0;
for j:=1 to la do
begin
ma:=Byte(astr[j])-48;
numstr[j-1]:=tb[ma];
end;
inc(i);
until StrToInt(numstr)>a;
Result:=i-1;
end;
function GetOkNum2(a:Integer;b:array of Integer;len:Integer=10):Integer;
var
i,j,k:Integer;
isno:Boolean;
begin
k:=0;for i:=1 to a do begin
isno:=false;
for j:=0 to len-1 do begin
if pos(inttostr(b[j]), inttostr(i))>=1 then begin
isno:=true;
break;
end;
end;
if isno=false then k:=k+1;
end;
Result:=k;
end;procedure TForm1.Button1Click(Sender: TObject);//使用我的算法
var
b:array[0..9] of Integer;
begin
b[0]:=8;
b[1]:=1;
b[2]:=7;
s1:=GetCounter;
showmessage(IntToStr(GetOkNum(9999999,b,3)));
s1:=GetCounter-s1;
end;procedure TForm1.Button2Click(Sender: TObject);//使用楼主的算法
var
b:array[0..9] of Integer;
begin
b[0]:=8;
b[1]:=1;
b[2]:=7;
s2:=GetCounter;
showmessage(IntToStr(GetOkNum2(9999999,b,3)));
s2:=GetCounter-s2;
end;procedure TForm1.Button3Click(Sender: TObject);//cpu时钟周期差
begin
ShowMessage(IntToStr(s2-s1));
end;