这里所有的算法练习均来自codewars上的练习,每周两练
1、实现简易计算器
要求:实现加减乘除,乘除优先级高于加减
这里输入用例中符号与数字之间都有空格
| 输入用例 | 输出 |
|---|---|
| '127' | 127 |
| '2 + 3' | 5 |
| '1 + 2 * 3 + 2 / 1' | 9 |
我的想法
首先对输入的字符串进行判断是否有空格,如果没有空格说明是纯数字可以直接转化;如果有空格,说明有运算符号。
对于有运算符号的字符串首先将字符串转换为数组1,该数组1里包含所有的数字和运算符号。对数组1进行遍历,如果没有碰到乘号和除号,将是数字的元素放到空数组2中,将运算符号的元素放到数组2中。如果碰到乘号或者除号就对该符号前后的数字进行运算,将运算后的数字放到数组2中。
注意两点
- 遍历到乘号或者除号时,对两个数进行了运算,所以遍历需要往后+1,因为后面的一个元素已经被运算掉了;
- 遍历到乘号或者除号时,对两个数进行了运算,这个符号前面的数之前已经放入了数组2中,所以在运算后,需要将数组2中最后一个元素去掉,再将运算得到的结果放入数组2中
代码
function evaluate (string) {
let newString
if (string.match(' ')) {
newString = string.split(' ');
let dataArr = []
let stringArr = []
for (var i=0; i<newString.length; i++) {
let newValue = parseInt(newString[i]);
if (newString[i] !== '*' && newString[i] !== '/') {
if (isNaN(newValue)) {
stringArr.push(newString[i])
} else {
dataArr.push(newValue)
}
} else if (newString[i] === '*') {
let newData = dataArr.pop() * newString[i+1]
dataArr.push(newData)
i++
} else if (newString[i] === '/') {
let newData = dataArr.pop() / newString[i+1]
dataArr.push(newData)
i++
}
}
stringArr.forEach((value, index, arr) => {
if (value === '+') {
let newData = dataArr[0] + dataArr[1];
dataArr.splice(0, 2, newData)
}
if (value === '-') {
let newData = dataArr[0] - dataArr[1];
dataArr.splice(0, 2, newData)
}
})
newString = dataArr[0]
} else {
newString = string.replace('\'', '')
}
return newString
}
console.log(evaluate('1 + 2 * 3 + 2 / 1'))
小小总结
- 字符串转换为数字的方法
- 怎么判断是否为NaN
2、求最小公倍数
var lst = [ [1, 2], [1, 3], [1, 4]]求的分母最小公倍数,且改变返回的形式
用例
Test.assertEquals(convertFrac(lst), "(6,12)(4,12)(3,12)")
我的思想:
- 遍历传入的数组,找到每个分母构成一个新数组newArr,并找到其中最大的数max,其知道最小公倍数一定小于每个分母相乘的值maxNum
- 我们可以知道我们求的最小公倍数t肯定大于等于max,小于等于maxNum,在这个范围内循环,对newArr里的每个数与max取余数,如果不为0,max+1
- 这里注意跳出循环的条件,我们新建了一个长度和newArr相等的空数组,当数组中每一个值都为1,说明这三个都可以整数,那么结束循环
代码
function convertFrac(lst){
if (lst.length == 1) {
return "(" + lst[0][0] + ',' + lst[0][1] + ')'
} else {
let maxNum = 1
let newArr = []
lst.forEach((value, index, arr) => {
newArr.push(value[1])
maxNum *= value[1]
})
newArr.sort(function (a, b) {
return b-a
})
let max = newArr[0]
var arr2 = new Array(lst.length);
var k = 1
for (var j = max; j<=maxNum; j++) {
k = 1
newArr.forEach((value, index, arr) => {
if ((max % arr[index]) > 0 ) {
max++
arr2[index] = 0
} else {
arr2[index] = 1
}
k = k * arr2[index]
})
if (k==1) {
for (var j=0; j<lst.length; j++) {
lst[j][0] = max/lst[j][1] * lst[j][0]
lst[j][1] = max
result += '(' + lst[j][0] + ',' + max +')'
}
return result
}
}
}
}
console.log(convertFrac([[1,2]]))
console.log(convertFrac([[1,7], [1,5], [2, 14]]))
console.log(convertFrac([[1,2],[1,3],[2,18]]))
欢迎大神们指出我冗余的地方
我的代码有点长了,看到别的大神们写的算得,真的是惭愧的要命。。希望自己可以灵活运用其数组的一些方法和正则表达式。。。
3、求字符串所有排序中,最中间的排序
对任意一个字符串,对其里面的字符进行任意换顺序,对组合按照ascii值排序,求最中间的排序
| 输入用例 | 输出用例 |
|---|---|
| 'abc' | 'bac' |
| 'abcd' | 'bdca' |
| 'obcxd' | 'dcxob' |
我的想法
abc的所有排序有abc acb bac bca cab cba
abcd 的所有排序有:
abcd abdc acbd acdb adbc adcb
bacd badc bcad bcda bdac bdca
cabd cadb cbad cbda cdab cdba
dabc dacb dbac dbca dcab dcba
首先对字符串按照ascii值进行排序,对排序后的字符串按照其首字符不同进行分类排序,观察可以得到对于长度n为偶数的字符串,最中间的数永远是第n/2类字符串的最后一个。对于长度n为奇数的字符串,取出第一个字符串肯定是第Math.floor(n/2)个字符,剩下的字符串还是长度为偶数的,那么可以用递归的方法。
代码
function middlePermutation(s) {
let length = s.length
let newArr = s.split('')
newArr.sort(function (a,b) {return a.charCodeAt(0) - b.charCodeAt(0)})
if (length > 2) {
let t = Math.floor(length / 2)
if (length % 2 === 0) {
let newData1 = [newArr[t-1]]
newArr.splice(t-1, 1)
let newArr2 = newArr.sort(function (a, b) {return b.charCodeAt(0) - a.charCodeAt(0)})
return newData1.concat(newArr2).join('')
} else {
let newData2 = [newArr[t]]
newArr.splice(t, 1)
let length2 = newArr.length
if (length2 > 3) {
newArr2 = middlePermutation(newArr.join(''))
} else {
newArr2 = newArr.sort(function (a, b) {return a.charCodeAt(0) - b.charCodeAt(0)})
}
return newData2.concat(newArr2).join('')
}
} else {
return newArr.join('')
}
}
4、大数乘法计算
由于计算机有长度限制,当数多大时,其计算的结果是1.2345679012345677e+36这样的形式,现在的要求就是展示所有的数字,不可以使用这样的方式。
我的思想
取出两个数都转换为数组,对数组b的每一位分别与数组a的每一位数求乘积,然后保存到新的数组中,这样最后获得一个二维数组(该数组的长度等于数组b的长度),该二维数组里的数组是数组b中每一位与数组a进行运算得到的结果。再将这个二维数组中的每一项进行累加计算。
代码
function multiply(a, b)
{
let arr1 = arguments[0].split('')
let arr2 = arguments[1].split('')
let newArr = []
let result = (parseInt(arguments[0]) * parseInt(arguments[1])).toString().replace(/^[\s|0]+([0-9])/, '$1')
if (/e\+/.test(result) || result == Infinity) {
for (let k = arr1.length-1; k >= 0; k--) {
newArr[k] = []
let x = 0
for (let i = arr2.length-1; i>=0; i--) {
let t = x + (arr2[i] * arr1[k])
x = Math.floor(t / 10)
t = t >= 10 && i!==0 ? t % 10 : t
if (t >= 10 && i === 0) {
newArr[k].unshift(x, t%10)
} else {
newArr[k].unshift(t)
}
}
pushZero(arr1.length-k-1, newArr[k])
}
let data = 0
let arr = newArr[0]
let result = []
for (let j=1; j<newArr.length; j++) {
let y = 0
for (let i=arr.length-1; i>=0; i--) {
let dis = arr.length-newArr[j].length
newArr[j] = pushZero(dis, newArr[j], 1)
arr[i] = newArr[j][i] + arr[i] + y
y = Math.floor(arr[i]/10)
arr[i] = arr[i] >= 10 && i!==0 ? arr[i]%10 : arr[i]
if (arr[i]>= 10 && i === 0) {
result.unshift(y, arr[i]%10)
} else {
result.unshift(arr[i])
}
}
arr = result;
result = []
}
result = arr.join('').replace(/^0+([0-9])/, '$1')
return result
}
return result
}
function pushZero (a, arr, k) {
for (let i=0; i<a; i++) {
if (k) {
arr.unshift(0)
} else {
arr.push(0)
}
}
return arr
}
5、将0和"0"移到数组的最后
不能使用object.prototype和array.prototype的方法,也不可以使用任何临时数组或对象
我的思想
遍历数组,找到一个0或者"0"(假设为arr[i])的时候,在对这个0和"0"后面的数进行遍历,找到一个非(0或者"0")的数字(假设为arr[j])时将arr[i]和arr[j]替换,注意:为了不影响数组中所有0和"0"的排序,需要确定i和j之间是否还有0或者"0",如果有就将该0和后面的arr[j]置换一下,保证最后出来的数组的0和"0"的顺序与原始数组一致且注意数组中如果出现null,false,不需要将其移动到最后
代码
function removeZeros(array) {
for (let i=0; i<array.length; i++) {
if (array[i] === 0 || array[i] === "0") {
for (let j = i; j< array.length; j++) {
if (array[j] !== 0 && array[j] !== '0') {
[array[i], array[j]] = [array[j], array[i]]
if (j-i >1) {
for (let k=i+1; k<j; k++) {
[array[k], array[j]] = [array[j], array[k]]
}
}
break;
}
}
}
}
return array
}
console.log(removeZeros(["0",null,0,"0",false]))
console.log(removeZeros(["0",0, "0",1]))