google面试题之一,(不为蹭分只求探讨者进)

sword281 2005-11-14 01:50:40
前日,从网上看到一个google面试题之一,即做之,因而带出些问题望各位大侠不吝赐教。
题目如下:
有这样一个函数,对于任意整数n,都能返回写出0到n之间出现“1”的个数。例如,f(13)=6。请注意f(1)=1,那么下一个能实现f(n)=n的最大数字是什么?

本人写了两个程序求解,-用递归、一用非递归程序,

解法1 递归程序:
它包含1公共模块(模块内容如下)。
**************************************************************
Public Const BitNum = 8
Public Function OneOfNum(ByVal Number As Long, ByVal BitNum As Long) As Long
Dim i As Integer
If Number < (10 ^ BitNum) Then

For i = BitNum To 0 Step -1

Dim j As Integer
j = Number \ (10 ^ i)
If 1 = j Then
OneOfNum = OneOfNum + 1
End If

Number = Number - j * (10 ^ i)
Next
End If
End Function



Public Function FindOne(ByVal num As Long) As Long
If num = 1 Then
FindOne = 1
Else
FindOne = OneOfNum(num, BitNum) + FindOne(num - 1)
End If
End Function
**********************************************************





窗体程序如下(窗体上有两文本框text1和text2)

**********************************************************
Dim sumofone As Long
Private Sub Command1_Click()
Dim k As Long

For k = Val(Text1.Text) To 1
Dim L As Long
L = FindOne(Val(Text1.Text))
If k = L Then
Text2.Text = Str(k)
Exit For
End If
Next
End Sub
*********************************************

当text1中输入超过某个值(不大,如5000)时,它会报溢出,故求解不能进行下去。

因而带出问题是:
vb的递归最大支持多少层?如何做一个满足自己的堆栈?(足够大,能满足本题)

_____________________________________________________________________________



解法2 非递归程序 窗体程序如下(窗体上有两文本框text1和text2,text1输入最大范围,text2输出结果):
*****************************************************************************************

Dim MaxVal As Long
Dim BitLong As Integer
Dim a() As Integer
Dim Find As Boolean

Private Sub Command1_Click()
Find = False
Dim Maxlong As Integer
Maxlong = 10
Dim Count As Long
MaxVal = Val(Text1.Text)
For Count = 2 To MaxVal
Dim i As Integer
BitLong = 0
For i = Maxlong To 1 Step -1
If Not ((Count \ 10 ^ (i - 1)) = 0) Then
BitLong = i '找出数的位数长度。
Exit For
End If
Next i
ReDim a(1 To BitLong) As Integer
Dim Temp As Long
Temp = Count
For i = BitLong To 1 Step -1 '从高位到低位分离出该数中的各个位上的数字至a()数组中
Dim bit As Integer
bit = Temp \ 10 ^ (i - 1)
a(BitLong - i + 1) = bit
Temp = Temp - bit * 10 ^ (i - 1)
Next

Dim SumofOne As Long
Dim Num As Long
Num = Count
SumofOne = 0
SumofOne = SumofOne + Num \ 10 '找出个位上1的个数
If (Num Mod 10) >= 1 Then
SumofOne = SumofOne + 1
End If
Dim BitNo As Integer 'BitNo 指明是第几位
For BitNo = 2 To BitLong - 1

Dim k As Long
k = Num \ 10 ^ BitNo
Dim preNum As Long
preNum = k * 10 ^ (BitNo - 1)
If a(BitNo) = 0 Then
SumofOne = SumofOne + preNum
ElseIf a(BitNo) = 1 Then
SumofOne = SumofOne + Val(Right(Num, BitNo)) + 1 '当有一位数字为1时,它后面的几位数字组成的数要加1
ElseIf a(BitNo) > 1 Then
SumofOne = SumofOne + (k + 1) * 10 ^ (BitNo - 1)
End If
Next
If BitLong = 1 Then '1位数时不加1
SumofOne = SumofOne + Val(Right(Num, BitLong - 1))
ElseIf a(1) = 1 Then '最高位的数为1时它后面的几位数字组成的数要加1
SumofOne = SumofOne + Val(Right(Num, BitLong - 1)) + 1
Else
SumofOne = SumofOne + 10 ^ (BitLong - 1)
End If
'MsgBox (Str(SumofOne))
If Num = SumofOne Then
Text2.Text = Str(Num)
Find = True
Exit For
End If
Next Count
If Find = False Then Text2.Text = "NO Find"
End Sub

******************************************************************************************

解出google问题结果为199981,这两种解法对吗?如若不对请指出。
如果正确,还有更简单的算法吗?(从时间复杂度及空间复杂度考虑)
在此谢谢各位高手、大侠了!!!!


...全文
226 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsftest 2005-11-14
  • 打赏
  • 举报
回复
>函数CountOne的算法个人认为还是用回字符串好:
虽然代码简单,但是执行速度慢 3 倍。
======================================
的确。。。。。字符串操作就是开销大,速度慢不好。。。。。
Tiger_Zhao 2005-11-14
  • 打赏
  • 举报
回复
>函数CountOne的算法个人认为还是用回字符串好:
虽然代码简单,但是执行速度慢 3 倍。
northwolves 2005-11-14
  • 打赏
  • 举报
回复
redim 确实多余了:

Private Sub Command1_Click()
Dim sumn As Long, i As Long, temp As String
sumn = 1
i = 1
Do
i = i + 1
temp = i
sumn = sumn + Len(temp) - Len(Replace(temp, "1", ""))
Loop Until sumn = i
MsgBox i
End Sub

其实:

num=anan-1an-2...a2a1 中1的个数:

个位: anan-1an-2...a2 个1
十位:anan-1an-2...a2 *10 个1
百位:anan-1an-2..a3 *100 个1
...
最高位 a1* 10^(n-1) 个1


即:

len(num)-1
----------
\
\
\ int(num/10^i)*10^(i-1)
/
/
/
----------
i = 1
lsftest 2005-11-14
  • 打赏
  • 举报
回复
函数CountOne的算法个人认为还是用回字符串好:

Function CountOne(ByVal number As Long) As Long
CountOne =len(cstr(number))-len(replace(cstr(number),"1",""))
End Function
Tiger_Zhao 2005-11-14
  • 打赏
  • 举报
回复
这样最快

Sub Main()
Dim count As Long
Dim i As Long

count = 1
i = 1
Do
i = i + 1
count = count + CountOne(i)
Loop While count <> i
Debug.Print i
End Sub

Function CountOne(ByVal number As Long) As Long
Dim count As Long

While number > 0
If (number Mod 10) = 1 Then count = count + 1
number = number \ 10
Wend

CountOne = count
End Function
------------------------------
199981
lsftest 2005-11-14
  • 打赏
  • 举报
回复
northwolves(狼行天下) 的代码思路是差不多了,但其实也不必再去redim了,反正从1开始,每次比对都把相差多少个1记录下来,然后到下个数的时候就直接判断这个数里是否有这么多个1就是了。。。
例如
n=1,1的总数是1。。相差0
n=2,1的总数是1。。相差1
n=3,根据上次的比较结果,今次n值要有1+1个1才符合要求,结果:不符合。。相差2...
n=4,根据上次的比较结果,今次n值要有2+1个1才符合要求,结果:不符合。。相差3...
n=5,根据上次的比较结果,今次n值要有3+1个1才符合要求,结果:不符合。。相差4...
..
.
n=9,根据上次的比较结果,今次n值要有7+1个1才符合要求,结果:不符合。。相差8...
n=10,根据上次的比较结果,今次n值要有8+1个1才符合要求,结果:不符合。。相差8...
n=11,根据上次的比较结果,今次n值要有8+1个1才符合要求,结果:不符合。。相差7...
n=12,根据上次的比较结果,今次n值起码要有7+1个1才符合要求,结果:不符合。。相差7...
..
.
思路如此。。。。但手边没有vb,不能测试。。。





elei 2005-11-14
  • 打赏
  • 举报
回复
题目应该求的是:“下一个能实现f(n)=n的最 小 数字”吧。
northwolves 2005-11-14
  • 打赏
  • 举报
回复
楼上指教的是.

Private Sub Command1_Click()
Dim sumn() As Long, i As Long, temp As String
ReDim sumn(1 To 1)
sumn(1) = 1
i = 1
Do
i = i + 1
temp = i
ReDim Preserve sumn(1 To i)
sumn(i) = sumn(i - 1) + Len(temp) - Len(Replace(temp, "1", ""))
Loop Until sumn(i) = i
MsgBox i
End Sub
junki 2005-11-14
  • 打赏
  • 举报
回复
先不要急于写程序,分析一下就很容易发现其中的规律
1 to 9的机会都是一样的,当你的数无限大的时候,回去自己写一个算法,
保证很简单,呵呵...
province_ 2005-11-14
  • 打赏
  • 举报
回复
楼上的简单可行,但直接给出上限不好,应该用步长比如100来增量测试比较有通用性。
VB的栈和其他语言一样当然有限制,所以对这种不知道上限的题目是不合适的。

Private Sub Command1_Click()
Dim i As Long, j As Long, count As Long, step As Long, str As String, flag As Boolean

flag = False
count = 0
step = 100
j = 1

While flag = False

For i = step * (j - 1) + 1 To step * j
str = "" & i
count = count + Len(str) - Len(Replace(str, "1", ""))
If count = i And i <> 1 Then
flag = True
Exit For
End If
Next
If flag = False Then j = j + 1
Wend
MsgBox i
End Sub
northwolves 2005-11-14
  • 打赏
  • 举报
回复
结果是对的,但代码太多了:

Private Sub Command1_Click()
Dim sumn(1 To 1000000) As Long, i As Long, temp As String
sumn(1) = 1
For i = 2 To 1000000
temp = i
sumn(i) = sumn(i - 1) + Len(temp) - Len(Replace(temp, "1", ""))
If i = sumn(i) Then Exit For
Next
MsgBox i
End Sub

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧