缘由本论坛年度征文邀请
之前论坛给的一个笔耕不辍实体已经给后辈玩了,那波浪上的孙猴儿会随波逐流摇来晃去的,后辈挺喜欢的。
前几天回复了一个整数正序分解,虽说是老话题了,不过常有新想法,其实整数正序分解整合不止一种解法,我个人总结有4种解法,其一用2个倒序,其二用升幕合成,其三用降幕,其四数组。
历年都有接触这样的老题目,也都有一种解法,今天又兴起写了一个解法,那么,就来看看我历年都有哪些回复有关整数正序的博文:
这样数来历年回复写了9个,当然这些代码都会逐渐公布的,但未必就去详解,那么,今天趁着这个年度征文主题,就今天刚写的降幕和之前写的升幕2种解法做详解。
void 整数正序分解升幕()
{int a = INT_MAX, aa = 0, m = 1;fj:if (a){ aa = a % 10 * m + aa, m *= 10, a /= 10; goto fj; }std::cout << aa << "\n";
}
void 整数正序分解降幕()
{int a = INT_MAX, aa = 0, m = a<1e+1 ? 1 : a<1e+2 ? 1e+1 : a<1e+3 ? 1e+2 : a<1e+4 ? 1e+3 : a<1e+5 ? 1e+4 : a<1e+6 ? 1e+5 : a<1e+7 ? 1e+6 : a<1e+8 ? 1e+7 : a<1e+9 ? 1e+8: a<1e+10 ? 1e+9 : 0;fj:if (a){std::cout << a / m;a %= m;m /= 10;goto fj; }
}
升幕和降幕整数直接用INT最大值来分解,升序采用的是合成后一次输出解法,分解种用10幕逐渐上升之法,从代码可以看到m初始化为1,之后一直乘以10,即循环第一次为1第二次为10第三次为100第四次为1000这样一直升起来的算法,整数分解采用的是倒序法,从代码也可以看到整合的正序是从个位合成开始的,然后是十位,然后是百位,然后是千位,直到整数分解完毕,当然这种算法自有用武之地,如果逐次显示的话就会是显示1位数再显示2位数再显示3位数再显示4位数直到结束。
降序采用的是判断获得10的幕次值,在分解中用除法输出整数最高位,逐个输出的解法,从代码可以看到解法循环中除法输出整数的最高位后,整数求余就会减去最高位,整数则成为一个减去最高位的新数,然后幕值除以10,这样就变为了降幕求法,直到整数分解完成。
以上2个算法都是用一个循环完成的,当然采用数组和2次倒序用2个循环才能完成。
另外,前些天也回复了一个老问题有序数组合并,我写的新解是不用第三数组也能实现:
同样也会逐渐公布的,今天就描述一下不用第三数组的新解法。
int a[]{2, 4, 6, 8}, b[]{1, 3, 5, 7}, al = 4, bl = 4;int x = 0, xx = 0, t = 0;
hb:if (x < al)
{//缘由https://ask.csdn.net/questions/8046940/54437706if (a[x] > b[xx])t = a[x], a[x] = b[xx], b[xx] = t;
px:if (xx<bl)
{if (b[xx] > b[xx + 1]){t = b[xx], b[xx] = b[xx + 1], b[xx + 1] = t, ++xx;goto px;}
}++x; xx = 0;goto hb;
}x = xx = 0;
sc:if (x < al || xx < bl)
{if (x < al)cout << a[x], ++x;elsecout << b[xx], ++xx;goto sc;
}
目标是不使用第三数组,至于其他指标,如空间时间就不进行分析了,留给他人玩去,只说解法,首先按升序来实现,用其中一个数组对另一个数组逐个从头对比,若条件符合则交换2个数组的数据,并对被对比的数组进行一次排序,然而这个排序非同普通的排序,排序的条件限制不会每次都循环到数组全部的,只要交换后的数组变为有序即可,有点类似插入排序,这样就实现交换后2个数组依然有序,直到循环到主对比数组的最后结束,很显然用小数组作为主对比交换的次数就小,这样最后输出的顺序是主对比数组再被对比数组轮流输出即可,这样就不用第三数组,也不会出现数组越界灯系列问题,也节约空间。
还有自守数的新解,还有判断质数的新解,还有数字转人民币的新解法,还有开方的新算法,还有求因子,这些都是老问题新解法,不过不是今年的了,若想了解的话可以阅读我已经公布的博文或将来公布的博文。
已经公布的博文就说一下自守数同构数:
bool 自守数新解(int n)
{return (n * n - n) % (n < 10 ? 10 : n < 100 ? 100 : n < 1000 ? 1000 : n < 10000 ? 10000 : n < 100000 ? 100000 : n < 1000000 ? 1000000 :n < 10000000 ? 10000000 :n < 100000000 ? 100000000 :n < 1000000000 ? 1000000000 :n < 10000000000 ? 10000000000 :1);
}
这个算法是平方减去本数再检查是否为0,各位为0就是,否则不是。
bool 自守数新解(int n)
{int a = n, b = 10;while ((a/=10))b *= 10;return (n * n - n) % b;
}
这个算法是分解求得幕值,然后道理同上面,代码比较简洁。
再说一下已经公布的比较高效求质数:
bool sushu(int n)
{//偶数只有2之后都是奇数,因此写时可跳过偶数即奇数步进2;终止为商大等于除数;使用之前求出的质数数组作为除数。if(n == 2 || n == 1) return 1;if (n % 2 == 0) return 0;//在这题可有可无,示意可单独处理 && a > 2for (int a = 3; a <= n/a; a += 2)//媲美sqrt,更高级的使用即时质数数组if (n%a == 0) return 0;return 1;
}
这个算法已经有比较详细注释,我采用的是除法作为结束条件,有人曾经说比较复杂,后发现论坛就有用乘方的,道理都是一样的同开方,不过我不是用的步进1,而是步进2,这样就更节约时间。
再说一下已经公布的数字转中文金额无限位数终极算法,曾经有人断言我肯定要用非常多的判断语句,结果我一个判断都不用:
string 标准人民币金额制式模板 = "零仟·零佰·零拾·零☆不可说☆·零仟·零佰·零拾·零☆无量·零仟·零佰·零拾·零不可思议·零仟·零佰·零拾·零那由他·零仟·零佰·零拾·零阿僧祇·零仟·零佰·零拾·零恒河沙·零仟·零佰·零拾·零极·零仟·零佰·零拾·零载·零仟·零佰·零拾·零正·零仟·零佰·零拾·零涧·零仟·零佰·零拾·零沟·零仟·零佰·零拾·零穰·零仟·零佰·零拾·零秭·零仟·零佰·零拾·零垓·零仟·零佰·零拾·零京·零仟·零佰·零拾·零兆·零仟·零佰·零拾·零亿·零仟·零佰·零拾·零万·零仟·零佰·零拾·零元", 中文值 = "零壹贰叁肆伍陆柒捌玖", 转换输出标准 = "", 缩读处理 = "零仟零佰零拾";string[] 反转单位集合 = 标准人民币金额制式模板.Split('·').Reverse().ToArray();long 要转换的数字 = new Random().Next(int.MaxValue);int 位数 = 0, 读单位 = 0;Console.WriteLine("要转换的数字:" + 要转换的数字.ToString() + "转换:");do{转换输出标准 = 转换输出标准.Insert(0, 反转单位集合[位数].Replace("零", 中文值[(int)(要转换的数字 % 10)].ToString()));++位数;} while ((要转换的数字 /= 10) > 0);Console.WriteLine(转换输出标准);/*会计标准的输出就是上面这样了,来看看如何生成读的文字,首先说明,代码修改和优化在写完后期进行,这是个人习惯了.其实规则还是很单纯的,首先处理最多4项,再处理左右321项,从最多处理开始,左补零,右单位,最后处理单项进阶单位*/
————————————————
版权声明:本文为CSDN博主「智者知已应修善业」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xianfajushi/article/details/44810753
算法注明都说了,就不赘言了。
再说一下已经公布的C++平方开方(任意开方):
void 平方开方(int n)
{int a = 0, f = 0;double z = 0, m = 0.1;while ((f = a*a) < n)++a;if (f == n)cout << a << "\t";else{z = --a; a = 5;while (m>1e-14){while ((z + a*m)*(z + a*m) < n)++a;while ((z + a*m)*(z + a*m) > n)--a;z += a*m; a = 5;m *= 0.1;}cout << setprecision(17) << z << "\t";}
}int p = 1;while(p<=100) 平方开方(p++);
这个算法用平方的办法对比,并且使用二分法的思路跳跃式进行以节约时间提高效率,求开方多见提问的使用国外公式,也见有国内使用系数的,我是自己思路设计实现的。
再说一下求因子,通常提问和回复的都是从1顺序求到数本身,而我则用除法,求到小等于商即可:
void 完美数新解()
{//缘由https://ask.csdn.net/questions/7818030?spm=1005.2025.3001.5141int n = 1, j = 0, c = 0;while (++n <= 1000){while (++c <= n / c)if (n%c == 0)j += c + (c==n/c?0:n / c); else;if (j - n == n)cout << n << "\t"; else;j = c = 0;}
}
有关因子的算法,用除法限制结束条件可以提高运算效率,通常的算法是从1开始要计数到数本身结束,而我采用除法为结束条件则不需要计算到数本身,只要商大于除数就结束,则效率大为提高,例如求4的全因子,1开始商是4即数本身,2则商2,3就结束不会进入循环体了,或许有人看到这里会窃笑或提出强烈抗议,要说这样求是错的,其实不然,看我输出的条件就知道,虽然因子和是包含了数本身,但是,我采用的是所有因子和减去数本身,这样就符合完美数的定义了,从代码看和是除数和商的集合,因此除数不用逐步求到数本身就能大大提高运输效率,其实与求因子有关的都可以用这种方法,这个是含1不含本身,还有是不含1的减去1即可,不含1和本身的减去1和本身即可,都通用这个算法,这个算法还有一个重点是除数和商不相等则加商,相等则不加商,因此4的全因子是1,2,4,那么,含1不含本身的和就是3。
当然这些都不是老用着一种解法回复所有提问,都是新思路,新解法,也是最为合理的解法,不做多余的浪费运算,当然还有一些是未公布的,将来逐渐公布。
还有3个数排序不用循环,还有求1到N的和公式,还有求年的月的天数,还有求星期几的400年规律,还有头尾双向双数据排序法,这些都是可圈可点的,就不一一详细罗列,可以看博客。