英文:
Minimum Steps To 1
问题
给定一个正整数'n',找到并返回使'n'减少到1所需的最小步数。您可以执行以下三种操作中的任何一种:
- 从中减去1。 (n = n - 1)
- 如果'n'可以被2整除,将其除以2。 (如果 n % 2 == 0,则 n = n / 2)
- 如果'n'可以被3整除,将其除以3。 (如果 n % 3 == 0,则 n = n / 3)
输入格式:
输入的第一行仅包含一个整数值'n'。
输出格式:
打印最小步数。
约束条件:
1 <= n <= 10 ^ 6
时间限制:1秒
以下是代码:
from sys import maxsize as MAX_VALUE
dic = {}
def countMinStepsToOne(n) :
if n == 1:
return 0
if n % 3 == 0:
if n/3 not in dic:
dic[n/3] = countMinStepsToOne(n/3)
if n % 2 == 0:
if n/2 not in dic:
dic[n/2] = countMinStepsToOne(n/2)
if n-1 not in dic:
dic[n-1] = countMinStepsToOne(n-1)
return 1 + min(dic.get(n/3,MAX_VALUE),dic.get(n/2,MAX_VALUE),dic.get(n-1,MAX_VALUE))
# 主函数
n = int(input())
print(countMinStepsToOne(n))
对于较小的'n'值,它可以正确输出,但是当尝试较大的值(例如5685)时,PowerShell会终止进程而没有输出,在Jupyter笔记本中内核会变成无响应。根据您的描述,您认为字典可能是问题的原因,因为当您尝试打印dic
时,它是空的。但仍然不清楚为什么它适用于较小的值而不适用于较大的值。
英文:
Given a positive integer 'n', find and return the minimum number of steps that 'n' has to take to get reduced to 1. You can perform any one of the following 3 steps:
- Subtract 1 from it. (n = n - 1)
- If n is divisible by 2, divide by 2.( if n % 2 == 0, then n = n / 2)
- If n is divisible by 3, divide by 3. (if n % 3 == 0, then n = n / 3)
Input format :
> The first and the only line of input contains an integer value, 'n'.
Output format :
> Print the minimum number of steps.
Constraints :
> 1 <= n <= 10 ^ 6 <br>
Time Limit: 1 sec
Following is Code
from sys import maxsize as MAX_VALUE
dic = {}
def countMinStepsToOne(n) :
if n == 1:
return 0
if n % 3 == 0:
if n/3 not in dic:
dic[n/3] = countMinStepsToOne(n/3)
if n % 2 == 0:
if n/2 not in dic:
dic[n/2] = countMinStepsToOne(n/2)
if n-1 not in dic:
dic[n-1] = countMinStepsToOne(n-1)
return 1 + min(dic.get(n/3,MAX_VALUE),dic.get(n/2,MAX_VALUE),dic.get(n-1,MAX_VALUE))
#main
n = int(input())
print(countMinStepsToOne(n))
For small values of n it is giveing correct output but when I try bigger value, lets take 5685 the powershell kill the process without output and in jupyter notebook kernel goes dead.<br>
According to me I think dictionary is cause problem because when I tried to print dic
it was empty, But still not getting how it worked for smaller value not bigger ones.
答案1
得分: 3
递归方式意味着您实际上正在进行可能性空间的深度优先搜索(DFS),这将创建一个非常深的堆栈(在大输入上运行代码时,我得到了RecursionError
),并且可能会浪费大量时间计算非常长的路径,最终您会重新计算以找到相同值的较短路径。输入越大,这种效果就越糟糕。
我建议改用广度优先搜索(BFS)来完成,如下所示:
def steps_to_one(n):
visited = set()
depth = 0
level = {n}
while 1 not in level:
depth += 1
next_level = set()
for n in level:
if n in visited:
continue
visited.add(n)
if n % 3 == 0:
next_level.add(n // 3)
if n % 2 == 0:
next_level.add(n // 2)
next_level.add(n - 1)
level = next_level
return depth
这可以在输入5685的情况下非常快速地返回结果15。
在每次迭代中,level
是当前搜索空间的级别,depth
是迄今为止我们已经遍历的级别数量。
我们使用visited
来跟踪,以便如果我们最终到达一个在以前搜索路径中已经访问过的值,我们可以快速忽略它(例如,如果我们走下n - 1
路径并发现一个值,我们已经以更快的方式到达,那么重新计算从那个点开始的路径就没有意义)。我们不需要字典来跟踪我们找到该值时的深度,我们只需要知道它是一个正在探索过程中的可能性。
如果我们在while
循环的底部添加一个print
语句:
print(depth, sorted(level - visited))
我们可以看到在BFS的每个级别上正在探索什么:
1000
1 [500, 999]
2 [250, 333, 499, 998]
3 [111, 125, 249, 332, 498, 997]
4 [37, 83, 110, 124, 166, 248, 331, 497, 996]
5 [36, 55, 62, 82, 109, 123, 165, 247, 330, 496, 995]
6 [12, 18, 31, 35, 41, 54, 61, 81, 108, 122, 164, 246, 329, 495, 994]
7 [4, 6, 9, 11, 17, 27, 30, 34, 40, 53, 60, 80, 107, 121, 163, 245, 328, 494, 993]
8 [2, 3, 5, 8, 10, 15, 16, 20, 26, 29, 33, 39, 52, 59, 79, 106, 120, 162, 244, 327, 493, 992]
9 [1, 7, 13, 14, 19, 25, 28, 32, 38, 51, 58, 78, 105, 119, 161, 243, 326, 492, 991]
9
英文:
Doing this recursively means you're essentially doing a DFS of the possibility space, which is going to create a very deep stack (I got a RecursionError
when running your code on a large input) and potentially waste a lot of time computing very long paths that you'll end up recomputing later to find a shorter route to the same value. The larger the input, the worse this effect gets.
I'd suggest doing this as a BFS instead, e.g.:
def steps_to_one(n):
visited = set()
depth = 0
level = {n}
while 1 not in level:
depth += 1
next_level = set()
for n in level:
if n in visited:
continue
visited.add(n)
if n % 3 == 0:
next_level.add(n // 3)
if n % 2 == 0:
next_level.add(n // 2)
next_level.add(n - 1)
level = next_level
return depth
This very quickly returns the result 15 for the input 5685.
At each iteration, level
is the current level of the search space, and depth
is the number of levels we've traversed so far.
We keep track of visited
so that if we end up at a value that we've already visited in a previous search path, we can ignore it quickly (e.g. if we go down the n - 1
path and discover a value that we were already able to get to a faster way, there's no point in re-computing the path from that point). We don't need a dict to keep track of what the depth was when we found that value, we just need to know that it's a possibility that's already in the process of being explored.
If we add a print
to the bottom of the while
loop:
print(depth, sorted(level - visited))
we can see what's being explored at each level of the BFS:
1000
1 [500, 999]
2 [250, 333, 499, 998]
3 [111, 125, 249, 332, 498, 997]
4 [37, 83, 110, 124, 166, 248, 331, 497, 996]
5 [36, 55, 62, 82, 109, 123, 165, 247, 330, 496, 995]
6 [12, 18, 31, 35, 41, 54, 61, 81, 108, 122, 164, 246, 329, 495, 994]
7 [4, 6, 9, 11, 17, 27, 30, 34, 40, 53, 60, 80, 107, 121, 163, 245, 328, 494, 993]
8 [2, 3, 5, 8, 10, 15, 16, 20, 26, 29, 33, 39, 52, 59, 79, 106, 120, 162, 244, 327, 493, 992]
9 [1, 7, 13, 14, 19, 25, 28, 32, 38, 51, 58, 78, 105, 119, 161, 243, 326, 492, 991]
9
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论