[算法/java]多项式运算
问题描述
给两个多项式
例如
p1: 3x^3+2x^2+x+1
p2: x^2+x+1
给出p1和p2的加减乘除四则运算的结果
前要知识
List类、Set类、Map和HashMap
算法描述
对于多项式来说,一个多项式可以分成多个单元相加(减),(3x^3)+(2x^2)+(x)+(1)
对于每个单元(3x^3),(2x^2),(x)和(1)
我们可以用List结构来存储,而对于符号位+,+,+
同样可以用List结构存储。而对于整个多项式,可以用一个类进行表达。
当然,对于整体性来说,我们希望看到的是每一个自变量的指数和系数存储在一个数据结构中,因此引入含有Key主键的HashMap存储指数和系数。key值为指数,value值为系数。
//类Polynomial 的基本信息
public static class Polynomial {List<Character> symbolList = new LinkedList<>(); //用于记录 + - 符号List<String> specPolynomial = new LinkedList<>(); //用于记录分割多项式后的部分Map<Integer, Integer> powerAndCoefficient = new HashMap<>(); //power幂 coefficient系数 hashmap存储
}
具体描述
1.构造函数
因为我们输入的是String字符串,为了方便起见,需要将String字符串构造为Polynomial类型,代码如下:
Polynomial(String string) { //多项式的构造函数int left = 0, right = 0;while (left < string.length() - 1 && right < string.length()) { //当左边到达最后一位 或 右边超出string位数时结束循环if (string.charAt(right) == '+' || string.charAt(right) == '-') { //如果是加号或减号 前面left到right就是分割后的部分 right位置就是符号位specPolynomial.add(string.substring(left, right)); //将分割后的部分加入到specPolynomial 列表中left = right + 1;symbolList.add(string.charAt(right)); //将符号加入symbol 列表中}right++; //继续循环}specPolynomial.add(string.substring(left)); //将最后一段加入specPolynomial 列表中for (int j = 0; j < specPolynomial.size(); j++) { //遍历specPolynomial 取出每一个元素String temp = specPolynomial.get(j);char symbol = '+'; //定义一个symbolif (j > 0)symbol = symbolList.get(j - 1); //symbol的值为symbolList列表中的前一位int mul = 1;if (symbol == '+') //如果symbol为正号 则mul为1 即为原值mul = 1;else //如果symbol为负号 则mul为-1 即为相反值mul = -1;boolean notHasX = true; //判定有无xfor (int i = 0; i < temp.length(); i++) {if (temp.charAt(i) == 'x') { //如果查询到x notHasX置为否notHasX = false;break;}}if (notHasX) { //当没有x时,即常系数powerAndCoefficient.put(0, Integer.valueOf(temp) * mul);} else {int powerLocation = 0;//定义power符号的位置boolean flag = false; //找到^字符while (powerLocation < temp.length()) { //遍历temp字符串if (temp.charAt(powerLocation) == '^') { //如果找到^符号 flag置为true 并跳出循环flag = true;break;} else {powerLocation++; //如果还没找到 则向下移一位}}if (flag) {//有^符号if (temp.charAt(0) != 'x') //如果temp 的第一个字母不是x 即有不为1的系数powerAndCoefficient.put(Integer.valueOf(temp.substring(powerLocation + 1)), Integer.valueOf(temp.substring(0, powerLocation - 1)) * mul);else //如果temp的第一个字母是x 即系数为1powerAndCoefficient.put(Integer.valueOf(temp.substring(powerLocation + 1)), mul);} else {//没有^符号 x的一次项if (temp.substring(0, powerLocation - 1).equals(""))//没有系数 即为系数为1powerAndCoefficient.put(1, mul);else//系数不为1powerAndCoefficient.put(1, Integer.valueOf(temp.substring(0, powerLocation - 1)) * mul);}}}}
2.加法与减法
第一种情况:有相同的幂(map中存储的key值相同),将他们对应的value值相加,存入新的HashMap中。
第二种情况:该幂是两者中唯一的,将其key值和value值存入HashMap中。
代码如下:
public static String add(Polynomial p1, Polynomial p2) {StringBuilder res = new StringBuilder(); //构建StringBuilding 函数 构造res变量boolean flag = false;Map<Integer, Integer> map = new HashMap<>();for (int i = 0; i <= 10; i++) { //假设最高幂为10if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) != null) { //如果p1没有找到幂值而在p2中找到幂值map.put(i, p2.powerAndCoefficient.get(i)); //在hashmap中加入key 和 value} else if (p1.powerAndCoefficient.get(i) != null && p2.powerAndCoefficient.get(i) == null) {//如果p1找到幂值而在p2中没有找到幂值map.put(i, p1.powerAndCoefficient.get(i));} else if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) == null) //如果都没有 直接跳过continue;else { //如果都有 两个值相加map.put(i, p1.powerAndCoefficient.get(i) + p2.powerAndCoefficient.get(i));}}Set<Integer> set = map.keySet(); //设置Set集合 把map中的key值放到set集合中Object[] array; //将set放到object类数组中array = set.toArray();res = resCalculate(map, set, array, flag, res);//计算res值if (res.length() == 0) //如果res的长度为0 说明值就是0res.append("0");return res.toString();}
减法算法与加法算法相同,代码如下:
public static String sub(Polynomial p1, Polynomial p2) {StringBuilder res = new StringBuilder();boolean flag = false;Map<Integer, Integer> map = new HashMap<>();for (int i = 0; i <= 10; i++) {if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) != null) {map.put(i, p2.powerAndCoefficient.get(i));} else if (p1.powerAndCoefficient.get(i) != null && p2.powerAndCoefficient.get(i) == null) {map.put(i, p1.powerAndCoefficient.get(i));} else if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) == null)continue;else {map.put(i, p1.powerAndCoefficient.get(i) - p2.powerAndCoefficient.get(i));}}Set<Integer> set = map.keySet();Object[] array;array = set.toArray();res = resCalculate(map, set, array, flag, res);if (res.length() == 0)res.append("0");return res.toString();}
3.乘法
多项式的乘法法则是多项式1中的每一项与多项式2中的每一项相乘,结果再相加。因此通过两个循环得出新的key值和value值。但是如果对于已存在的键值,每一次加入一个相同的键值,会造成键值重复,使结果为最新输入的键值和数值。因此每一次 put 时,要加上上一次的value值。
代码如下:
public static Map<Integer, Integer> multiplyTwoPowerAndCoefficient(Map<Integer, Integer> pac1, Map<Integer, Integer> pac2) {Map<Integer, Integer> map = new HashMap<>();Set<Integer> set1 = pac1.keySet(); Set<Integer> set2 = pac2.keySet();Object object1[] = set1.toArray(); Object object2[] = set2.toArray();for (int i = 0; i < object1.length; i++) {for (int j = 0; j < object2.length; j++) { //依次遍历两个object集合if (map.get((int) object1[i] + (int) object2[j]) == null) //如果没有指数相加结果的值存在map.put((int) object1[i] + (int) object2[j], pac1.get(object1[i]) * pac2.get(object2[j])); //创建一个新的keyelse { //如果存在指数相加结果 更新该key值的value value等于循环该次结果的值加上以前存储的该key对应value值map.put((int) object1[i] + (int) object2[j], map.get((int) object1[i] + (int) object2[j]) + ((int) pac1.get(object1[i]) * pac2.get(object2[j])));}}}return map;}public static String multiply(Polynomial p1, Polynomial p2) {Map<Integer, Integer> map = new HashMap<>();map = multiplyTwoPowerAndCoefficient(p1.powerAndCoefficient, p2.powerAndCoefficient); //输入map的值Set<Integer> set = map.keySet();Object array[] = set.toArray();boolean flag = false;StringBuilder res = new StringBuilder();res = resCalculate(map, set, array, flag, res);if (res.length() == 0) res.append("0");return res.toString();}
4.除法
除法应该是最难的一步,在我们人类的思维中,小学就学过,除法的分母分子可以因式分解,再通过约分得到最简式,可是在我的计算机能力范围内,这时不允许的。因此我想了一个投机取巧的办法,直接打“/”号,但是又写了一种情况来解决能够整除的多项式,代码如下:
public static boolean judgeComplitedDivide(Map<Integer, Integer> p1, Map<Integer, Integer> p2) {//判断可不可以被整除if (p1.size() != p2.size()) //如果p1和p2的长度不一样 直接返回falsereturn false;else {Set<Integer> set1 = p1.keySet();Set<Integer> set2 = p2.keySet();Object object1[]=set1.toArray();Object object2[]=set2.toArray();float temp[]=new float[object1.length];for(int i=0;i<object1.length;i++){ //由于set集合里的数是顺序递增排列 所以只考虑对应位置的值是否相同即可得出结果if(object1[i]!=object2[i]){ //对应的key值不同return false;}else{ //对应的key值相同 存入数组中temp[i]=p1.get(object1[i])/p2.get(object2[i]);}}for(int i=1;i<temp.length;i++){ //遍历这个数组 如果有不同的元素 直接返回falseif(temp[i]!=temp[i-1])return false;}divideCoedfficient=temp[0]; //将全局变量divideCoedfficient设为temp[0] 随后返回truereturn true;}}public static String divide(Polynomial p1, Polynomial p2,String s1,String s2) {boolean isComplitedlyDivided = false;isComplitedlyDivided=judgeComplitedDivide(p1.powerAndCoefficient, p2.powerAndCoefficient);StringBuilder res = new StringBuilder();if (!isComplitedlyDivided) { //如果不能整除 直接输出res.append("(").append(s1).append(")/(").append(s2).append(")");} else { //如果可以整除 直接输出divideCoedfficientres.append(divideCoedfficient);}return res.toString();}
5.输出map中的结果
遍历每一个key值,得到相对应的value值,按照格式进行输出即可
代码如下:
public static StringBuilder resCalculate(Map<Integer, Integer> map, Set<Integer> set, Object[] array, boolean flag, StringBuilder res) {for (Integer i = 0; i < set.size(); i++) { //array[i]是指数if (map.get(array[i]) == 0) //如果key值对应的value值为0 直接跳过;else if ((Integer) array[i]== 0) { //如果指数为0 常数项if (!flag) { //第一项flag = true;res.append(map.get((Integer) array[i]));} else { //非第一项if (map.get((Integer) array[i]) > 0) //如果这个数大于0res.append("+").append(map.get((Integer) array[i]));else //这个数小于0res.append(map.get((Integer) array[i]));}} else if ((Integer) array[i] == 1) { //如果指数为1if (!flag) {flag = true;res.append(map.get((Integer) array[i])).append("x");} else {if (map.get((Integer) array[i]) == 1) //系数为1res.append("+x");else if (map.get(i) > 0) //系数不为1res.append("+").append(map.get((Integer) array[i])).append("x");else //系数小于0res.append(map.get((Integer) array[i])).append("x");}} else { //如果指数不为0或1if (!flag) {flag = true;res.append(map.get((Integer) array[i])).append("x^").append((Integer) array[i]);} else {if (map.get((Integer) array[i]) == 1)res.append("+x^").append((Integer) array[i]);else if (map.get((Integer) array[i]) > 0) //如果系数大于0res.append("+").append(map.get((Integer) array[i])).append("x^").append((Integer) array[i]);elseres.append(map.get((Integer) array[i])).append("x^").append((Integer) array[i]);}}}return res;}
输出结果
已知问题
1.除法问题
2.部分情况会出现崩溃
3.输出结果的时候会从幂低级到幂高级输出 其实我会改,但是我懒
4.······
本人不才,如有错误,烦请各路大佬斧正!!!
[算法/java]多项式运算相关推荐
- java大数运算详解【其三】大数乘法之平方算法之按位二次展开式算法
目录 java大数运算详解[其一]大数加减法 java大数运算详解[其二]大数乘法 java大数运算详解[其三]大数乘法之平方算法之按位二次展开式算法 java大数运算详解[其四]大数乘法之平方算法之 ...
- Java数据结构和算法:位运算
位运算因为是CPU直接支持的操作指令,也是基于二进制的操作,所以具有相当高的效率,在一些场合,合理应用位运算将具有很高的性能.通常在一些加密算法,图型算法中都会使用到位运算. 移位运算符 运算符 含义 ...
- Java位运算优化:位域、位图棋盘等
快速小测试:如何重写下面的语句?要求不使用条件判断语句交换两个常量的值. if (x == a) x= b; else x= a; 答案: x= a ^ b ^ x; //此处变量x等于a或者等于b ...
- 小博老师解读经典Java面试题—Java位运算
[面试原题] 我们经常会看到类似于下面这样的Java面试题: 请编写出效率最高的2乘以8的运算结果. [正确答案] 2<<3 [面试技术点] 面试者是否了解.灵活运用java位运算技术. ...
- java赋值运算的类型转换出新的问题_Java中byte、short、char、int、long运算时自动类型转化问题...
-------------------------------------------------------------------------------------------------- ★ ...
- Java位运算,常见的位运算
前提 位运算符中 ,操作数只能为整型和字符型数据 运算符号 按位与(&):同1则1 → true&&true 操作数1 0 0 1 1 操作数2 0 1 0 1 按位与 0 0 ...
- Java算法:华为机试算法(下),华为算法Java版,牛客网华为算法73~108题
接上篇:Java算法:华为机试算法(中),华为算法Java版,牛客网华为算法55~72题 HJ73 计算日期到天数转换 计算日期到天数转换 题目描述 根据输入的日期,计算是这一年的第几天.. 测试 ...
- Leetcode算法Java全解答--41. 缺失的第一个正数
Leetcode算法Java全解答–41. 缺失的第一个正数 文章目录 Leetcode算法Java全解答--41. 缺失的第一个正数 题目 想法 结果 总结 代码 我的答案 大佬们的答案 测试用例 ...
- 求一个数的二进制中有多少了 1 的三种算法 ——Java篇
求一个数的二进制中有多少了 1 的三种算法 --Java篇 文章目录 求一个数的二进制中有多少了 1 的三种算法 --Java篇 算法一:通过取模 % 运算就取出每一比特位数值,再判断 思路: 代码: ...
最新文章
- 12门课100分直博清华!这份成绩单冲上热搜,但学霸小伙也曾考过25分
- 洛谷 1072 Hankson 的趣味题——质因数界限讨论
- [图神经网络] 图节点Node表示---GraphSAGE与PinSAGE
- 【Qt开发】V4L2 API详解 Buffer的准备和数据读取
- FreeRTOS系统配置文件FreeRTOSConfig.h
- Oracle备份还原
- oracle sequence使用多,Oracle中Sequence使用的限制
- NERSim v1.09a 1CD+HyperMILL 2018.1
- 磊科路由器信号按键_磊科路由器怎么设置中继? | 192路由网
- 百度云网盘一直显示“下载请求中”,一个 解决办法
- 光纤收发器和交换机之间有什么区别?
- MySql生日闰月处理
- 图像特征提取现成的方法
- QNAP文件系统不干净,qFinder搜索不到nas,可以ping通
- android room 简书,android Room库使用问题
- 计算机二级考试应用与分值,计算机二级考试题型及分值
- 成都中医药大学计算机基础试题,成都中医药大学2016年春季学期期末考试计算机基础-成教()解剖.doc...
- npm install 报错up to date, audited 1 package in 133msfound 0 vulnerabilities
- Android 9.0 新特性
- 碎影录·番外·梦之章济南 by郝宗铎