输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数
题目:
输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数
首先,这道题肯定可以用动态规划来解,
n为整数时,n的解为 n/2 的解加1
n为奇数时,n的解为 (n+1)/2 和 (n-1)/2 的解中较小的解加2
通过这个思路,我们可以自底向上依次计算出n的解,代码如下
public static int getNum(int n) {
if(n<1) {
return 0;
}
int[] res = new int[n+1];
res[0] = 0;
res[1] = 0;
for(int i=2;i<=n;i++) {
if((i&1) == 0) {
res[i] = res[i/2] + 1;
}else {
res[i] = Math.min(res[(i+1)/2], res[(i-1)/2]) + 2;
}
}
return res[n];
}
通过上面的思路可以得到问题的解,但是由于是自底向上依次计算n的解,所以有很多不必要的计算,时间效率和空间效率都不高。
比如,当计算n=100时,如果已经知道n=50的解,那么就可以得出n=100的解,所以n=51到n=99都是没有必要计算的。
如果仍然通过自底向上计算,那么想要忽略51到99这一区间的数字的计算是比较麻烦的,如果是自顶向下计算则容易做到,通过n可以确定只要计算 n/2,(n-1)/2 , (n+1)/2,这三个数就 行,利用递归来做代码如下
public static int getNum2(long n) {
if(n<=1) {
return 0;
}
if((n&1) == 0) {
return getNum2(n/2) + 1;
}else {
long a = (n-1) / 2;
long b = (n+1) / 2;
return Math.min(getNum2(a), getNum2(b)) + 2;
}
}
递归来做这道题简单明了。
递归也有递归的坏处,首先递归最可能问题就是递归深度的问题,很可能造成栈溢出。虽然对这道题来说,几乎不会出现这个问题,但是在用递归做其他问题的时候一定要考虑到这一点。
至于为什么这道题不会造成栈溢出,自己想吧
所有的递归算法都可以转化成非递归算法,这道题也一样,同样的,递归时还有一个小问题,就是它没有复用子问题的解,对于每个子问题,不管之前是否已经计算过解,都要再重新计算一次,转化成非递归算法时可以一并解决这个问题,代码如下
public static int getNum3(long n) {
MyTask task = new MyTask(n);
ForkJoinPool pool = new ForkJoinPool();
int res = pool.invoke(task);
pool.shutdown();
return res;
}
static class MyTask extends RecursiveTask<Integer> {
private long number;
private static final Map<Long,Integer> map = new ConcurrentHashMap<>();
public MyTask(long number) {
super();
this.number = number;
}
private synchronized void put(Long a,Integer b) {
if(map.containsKey(a)) {
System.out.println("had existed!");
}else {
map.put(a, b);
}
}
private Integer get(Long a) {
System.out.println("success");
return map.get(a);
}
@Override
protected Integer compute() {
if(number<=1) {
put(number, 0);
return 0;
}else if(map.containsKey(number)) {
return get(number);
}
int res = 0;
if((number&1) == 0) {
MyTask task = new MyTask(number / 2);
try {
res = task.fork().get() + 1;
put(number, res);
} catch (Exception e) {
e.printStackTrace();
}
return res;
}else {
MyTask task1 = new MyTask((number-1) / 2);
MyTask task2 = new MyTask((number+1) / 2);
try {
int a = task1.fork().get() + 2;
int b = task2.fork().get() + 2;
res = Math.min(a,b);
put(number, res);
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
}
}
这个解法是将第二种解法的递归算法转化成了非递归算法,同时保存了之前已经计算过的子问题的解,并且用到了java中的fork/join框架,至于为什么要用这个框架,原因是,不用它我不知道怎么把这个递归算法转化成非递归算法,望各路大神指点指点
对于这道题来说,第二种方式最快,第三种方式其次,最后是第一种方式,而且第一种方式计算的n的最大值,也远远小于后两种。
好了,就先写到这,人生的第一篇博文就此诞生!庆祝!虽然写的我自己看了都觉得很烂,但是一步一步来嘛
输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数的更多相关文章
- input验证码框,输入非数字或非12位时,红框提示;每4位加一个空格
以下代码:input验证码框,输入非数字或非12位时,红框提示;每4位加一个空格 //input验证码框,输入非数字或非12位时,红框提示;每3位加一个空格 $(".text"). ...
- 如何写出一个让人很难发现的bug?
程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因为我的眼里常含bug. 那么如何写出一个让(坑)人(王)很(之)难(王)发现的bug呢? - 1 -新手开发+ ...
- 浅谈如何写出一个让(坑)人(王)很(之)难(王)发现的bug
该文章内容来自脚本之家,原文链接:https://www.jb51.net/news/598404.html 程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因 ...
- java————数组 简单写出一个管理系统
数组的特点 1, 数组是一块连续的空间,下标描述空间的位置. 2, 下标从0开始,最大下标为数组长度—1.(*.length-1) 3, 数组元素都是变量.(就是每个下标对应的内容).变量的类型 ...
- 请写出一个超链接,点击链接后可以向zhangsan@d-heaven.com发送电子邮件。
请写出一个超链接,点击链接后可以向zhangsan@d-heaven.com发送电子邮件. <a href=”mailto: zhangsan@d-heaven.com”>发邮件</ ...
- 2019-8-31-C#-如何写出一个不能被其他程序集继承的抽象类
title author date CreateTime categories C# 如何写出一个不能被其他程序集继承的抽象类 lindexi 2019-08-31 16:55:58 +0800 20 ...
- JS函数 编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数。
编程练习 使用javascript代码写出一个函数:实现传入两个整数后弹出较大的整数. 任务 第一步: 编写代码完成一个函数的定义吧. 第二步: 我们来补充函数体中的控制语句,完成函数功能吧. 提示: ...
- C# 如何写出一个不能被其他程序集继承的抽象类
我需要限定某个抽象类只能在我程序集类实现,而不支持其他程序集实现,也就是我需要一个不能被继承的抽象类 在 C# 里面有抽象类和接口,这两个都是期望被继承才能被使用,而抽象类是可以做到只能在自己程序集和 ...
- 用js写出一个漂亮的单选框选中效果
一般的input框比较简单,我们可以用JavaScript配合css背景图片定位让我们模拟写出一个点击选中效果 首先需要有个图片素材,当页面加载的时候是背景图片定位到左图,当我们点击图片的时候,背景图 ...
随机推荐
- Isomorphic Strings leetcode
Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the chara ...
- yii中调整ActiveForm表单样式
Yii2中对于表单和字段的支持组件为ActiveForm和ActiveField, <?php $form = ActiveForm::begin([ 'id' => 'login-for ...
- JavaScript 方法调用模式和函数调用模式
这两天在读<JavaScript语言精粹>关于第4章函数调用的几种模式琢磨了半天. 这里就说一下方法调用模式跟函数调用模式. 方法调用模式: 当一个函数被保存为对象的一个属性时,我们称它为 ...
- HTML中的table布局
<table width="100" height="50" border="1" bgcolor="blue"& ...
- android中在java代码中设置Button按钮的背景颜色
android中在java代码中设置Button按钮的背景颜色 1.设置背景图片,图片来源于drawable: flightInfoPanel.setBackgroundDrawable(getRes ...
- 蓄水池抽样(原理&实现)
前言: 蓄水池抽样:从N个元素中随机的等概率的抽取k个元素,其中N无法确定. 适用场景: 模式识别等概率抽样,抽样查看渐增的log日志(无法先保存整个数据流然后再从中选取,而是期望有一种将数据流遍历一 ...
- [Oracle]同义词(synonym)
(一)同义词的概念 同义词是数据库中表.视图.索引或其他模式对象的别名,与视图相似,同义词不占用实际的存储空间,在数据字典中只存同义词的定义. 在开发数据库时,应尽量避免直接引用表.视图或其他数据库对 ...
- 初步认识Thymeleaf:简单表达式和标签。(二)
本篇文章是对上篇文章中Thymeleaf标签的补充. 1.th:each:循环,<tr th:each="user,userStat:${users}">,userSt ...
- bootstrap file input 官方文档翻译
file Input官方文档 中文翻译 file input 特性 1.这个插件会把简单的html文件变成一个更好用的文件选择输入控件,通过一个html的文件输入框,能兼容那些不支持jquery或js ...
- iOS面试必看经典试题分析
> **不用临时变量怎么实现两个数据的交换?** 方式一:加减法的运算方式求解new_b = a - b + b = a;new_a = a + b - a = b;一个简单的运算方式,最重要的 ...