soonlive / codewars Goto Github PK
View Code? Open in Web Editor NEWSolutions to codewars
Solutions to codewars
Description:
The Decorator Pattern is a design pattern that allows behaviour to be added to an existing object/function dynamically without affecting its implementation.
This pattern is designed so that multiple decorators can be stacked on top of each other, each time adding a new functionality to the overridden function(s).
The decorator pattern is an alternative to subclassing. Subclassing adds behavior at compile time, and the change affects all instances of the original class; decorating can provide new behavior at run-time for individual objects/functions.
Motivation:
We will explain the utility of the decorator pattern with a simple example.
Suppose we have the sum() function:
//returns the sum of the arguments function sum() { return Array.prototype.reduce.call(arguments, function(sum, value) { return sum + value; }, 0); } sum(1, 4, 8, 9) //22
Now suppose we want to sum only the numbers are between 1 and 9. An intrusive and non-reusable solution could be:
//returns the sum of the arguments between 1 and 9 function sum() { return Array.prototype.reduce.call(arguments, function(sum, value) { if (value >= 1 && value <= 9) { return sum + value; } else { return sum; } }, 0); } sum(1, 9, -3, 1, 0, 4, 8, 9, 12); // 22
Although this solution is correct, it is not reusable because it is difficult to modify the minimum and maximum limits or add new functionality.
A better solution would be to define the filter(min, max) function:
//returns an array containing the numbers that are between min and max //the numbers are passed from third position function filter(min, max) { return Array.prototype.slice.call(arguments, 2).filter(function(value) { return value >= min && value <= max; }); } filter(1, 9, -3, 1, 0, 4, 8, 9, 12); // [1, 4, 8, 9]
Now we can call the sum() function like this:
//returns the sum of the arguments between 1 and 9 sum.apply(null, filter(1, 9, -3, 1, 0, 4, 8, 9, 12)); //22
This looks great. We have now achieved the same result without affecting the sum() function and we have an independent function, filter(min, max), we can apply to other functions in addition to the sum() function.
For example:
//returns the multiplication of the arguments function multiplication() { return Array.prototype.reduce.call(arguments, function(product, value) { return product * value; }, 1); } multiplication.apply(null, filter(1, 9, -3, 1, 0, 4, 8, 9, 12)); //288
Now suppose we define the noNumbersFilter() function that removes those values that can not be added because they are not numeric:
function filterNoNumbers() { return Array.prototype.filter.call(arguments, function(value) { return typeof value === 'number' && value === value && value !== Number.POSITIVE_INFINITY && value !== Number.NEGATIVE_INFINITY; }); } filterNoNumbers(-3, NaN, 1, 0, "2", 4, 8, 9, 12); // [-3, 1, 0, 4, 8, 9, 12]
We could do the same and apply the filterNoNumbers() function in this way:
sum.apply(null, filter.apply(null, [1, 9].concat(filterNoNumbers(-3, NaN, 1, 0, "2", 4, 8, 9, 12)))); // 22
Even if it works, it starts to be a challenge to do this without errors.We can further complicate the problem if we want the result of the sum has to be rounded to two decimal digits. To do this, we define the round(decimals) function:
function round(decimals) { if (arguments.length === 2) { return arguments[1].toFixed(decimals); } else { return Array.prototype.splice.call(arguments, 1).map(function(value) { return value.toFixed(decimals); }); } } round(2, 1, 2.1, 2.346); // ["1.00", "2.10", "2.35"] round(2, 1.3); // "1.30"
And we use it in this way:
round.apply(null, [2].concat(sum.apply(null, filter.apply(null, [1, 9].concat(filterNoNumbers(-3, 1.016, 0, 4, NaN, 8.041, '27', 9, 12)))))); // "22.06"
It would be better if we could generalize the solution. This is where the decorator pattern comes into play.
Work to do:
Your work is implement the decorate(fn) function. Note that this function takes the function to decorate. The decorate(fn) function can also receive the parameters passed to the decorator functions. See the example below.
When you call the decorate(fn) function, a decorated function will be returned. When this returned function is called, the function fn() passed in decorate(fn) will be called applying decorator functions.
The Decorator(options) function is already implemented. Note that the function receives an object with two attributes before and after. These attributes are the decorator functions which apply before and after calling the function passed in decorate(fn), respectively. One or both may be null.
The way to use these functions are as follows:
var filterDecorator = new Decorator({ before : filter }); var filterNoNumbersDecorator = new Decorator({ before : filterNoNumbers }); var roundDecorator = new Decorator({ after: round }); var decoratedSum = filterDecorator.decorate(sum, 1, 9); // 1 and 9 are the min and max parameters passed to the filter function decoratedSum = filterNoNumbersDecorator.decorate(decoratedSum); decoratedSum = roundDecorator.decorate(decoratedSum, 2); // rounded to two decimals decoratedSum(-3, 1.016, 0, 4, NaN, 8.041, '27', 9, 12); // "22.06"
作者用了大篇幅为我们诠释装饰者模式,要求就是定义一个名为 Decorator 的 function,实现该模式。
我想到了 java 的 AOP 切面编程
function Decorator(options) {
if (!options) {
options = {};
}
this.before = options.before;
this.after = options.after;
}
Decorator.prototype.decorate = function decorate(fn) {
if (!this.before && !this.after) {
return typeof fn === 'function' ? fn : fn.apply(null, arguments);
}
var _this = this;
var args = [].slice.call(arguments).filter(function (a) {
return typeof a !== 'function';
});
return function () {
var result;
var innerArgs = [].slice.call(arguments);
if (_this.before) {
result = fn.apply(null, _this.before && _this.before.apply(null, args.concat(innerArgs)));
}
if (_this.after) {
result = _this.after && _this.after.apply(null, args.concat(fn.apply(null, _this.before ? result : innerArgs)));
}
return result
};
};
Find heavy ball - level: master
Description:
There are 8 balls numbered from 0 to 7. Seven of them have the same weight. One is heavier. Your task is to find it's number.
Your function findBall will receive single argument - scales object. The scales object contains an internally stored array of 8 elements (indexes 0-7), each having the same value except one, which is greater. It also has a public method named getWeight(left, right) which takes two arrays of indexes and returns -1, 0, or 1 based on the accumulation of the values found at the indexes passed are heavier, equal, or lighter.
getWeight returns:
-1 if left pan is heavier
1 if right pan is heavier
0 if both pans weigh the same
Examples of scales.getWeight() usage:
scales.getWeight([3], [7]) returns -1 if ball 3 is heavier than ball 7, 1 if ball 7 is heavier, or 0 i these balls have the same weight.
scales.getWeight([3, 4], [5, 2]) returns -1 if weight of balls 3 and 4 is heavier than weight of balls 5 and 2 etc.
So where's the catch, you may ask. Well - the scales is very old. You can use it only TWICE before the scale breaks.
8 个球,7 个的重量是相同的,另一个重量比较重,用天平称两次,找出最重的球
先拿 6个左右各 3个称一次,根据称的结果,再拿 2 个左右各一个称一次,即可得出
function findBall(scales) {
var idx = -1;
var w = scales.getWeight([0, 1, 2], [3, 4, 5]);
if (w > 0) {
w = scales.getWeight([3], [4]);
if (w > 0) {
idx = 4
} else if (w < 0) {
idx = 3
} else {
idx = 5
}
} else if (w < 0) {
w = scales.getWeight([0], [1]);
if (w > 0) {
idx = 1
} else if (w < 0) {
idx = 0
} else {
idx = 2
}
} else {
w = scales.getWeight([6], [7]);
idx = w > 0 ? 7 : 6;
}
return idx;
}
Description:
You are given a node that is the beginning of a linked list. This list always contains a tail and a loop.
Your objective is to determine the length of the loop.
For example in the following picture the tail's size is 3 and the loop size is 11.
// Use the `getNext' method or 'next' property to get the following node. node.getNext() node.next
找出循环链表的长度
function loop_size(node) {
var loopArr = [];
while (node && loopArr.indexOf(node) < 0) {
loopArr.push(node);
node = node.next;
}
var firstIndex = Math.max(0, loopArr.indexOf(node));
return loopArr.length - firstIndex;
}
Description:
How can you tell an extrovert from an introvert at NSA? Va gur ryringbef, gur rkgebireg ybbxf ng gur BGURE thl'f fubrf.
I found this joke on USENET, but the punchline is scrambled. Maybe you can decipher it? According to Wikipedia, ROT13 (http://en.wikipedia.org/wiki/ROT13) is frequently used to obfuscate jokes on USENET.
Hint: For this task you're only supposed to substitue characters. Not spaces, punctuation, numbers etc. Test examples:
Test.expect(rot13("EBG13 rknzcyr.") == "ROT13 example."); Test.expect(rot13("This is my first ROT13 excercise!") == "Guvf vf zl svefg EBG13 rkprepvfr!")
将字符串中的字母替换为在26个字母表中向右移动13个位置后的字母,区分大小写
function rot13(str) {
return str.split('').map(function (n) {
if(/[A-Za-z]/.test(n)){
var charCode = n.charCodeAt(0);
n = String.fromCharCode(charCode>109 || (charCode>77 && charCode<91)?charCode-13:charCode+13);
}
return n;
}).join('');
}
Description:
At a job interview, you are challenged to write an algorithm to check if a given string, s, can be formed from two other strings, part1 and part2.
The restriction is that the characters in part1 and part2 are in the same order as in s.
The interviewer gives you the following example and tells you to figure out the rest from the given test cases.
For example:
'codewars' is a merge from 'cdw' and 'oears': s: c o d e w a r s = codewars part1: c d w = cdw part2: o e a r s = oears
判断字符 s 是否由另外两个字符 part1、part2 合并而成,要考虑合并字符的顺序是否正确
function isMerge(s, part1, part2) {
var arr = new Array(s.length);
for(var i =0;i< s.length;++i){
if(part1.indexOf(s[i]) > -1 && arr[i] === null){
arr[i] = s[i];
}
if(part2.indexOf(s[i]) > -1 && arr[i] === null){
arr[i] = s[i];
}
}
return s.length === (part1.length + part2.length) && isOrderCorrect(s,part1) && isOrderCorrect(s,part2) && arr.join('') === s;
}
function isOrderCorrect(s,part){
var o=-1;
return part.split('').every(function(c) {
return (o=s.indexOf(c,o+1)) !== -1;
});
}
Description:
Number is a palindrome if it is equal to the number with digits in reversed order. For example, 5, 44, 171, 4884 are palindromes and 43, 194, 4773 are not palindromes.
Write a method palindrome_chain_length which takes a positive number and returns the number of special steps needed to obtain a palindrome. The special step is: "reverse the digits, and add to the original number". If the resulting number is not a palindrome, repeat the procedure with the sum until the resulting number is a palindrome.
If the input number is already a palindrome, the number of steps is 0.
Input will always be a positive integer.
For example, start with 87:
87 + 78 = 165; 165 + 561 = 726; 726 + 627 = 1353; 1353 + 3531 = 4884
4884 is a palindrome and we needed 4 steps to obtain it, so palindrome_chain_length(87) == 4
给定一个数字,求需要经过多少次与自身的镜像数字相加才能变成回文
var palindromeChainLength = function (n) {
var count = 0;
var palindrome = parseInt((n + '').split('').reverse().join(''));
while (palindrome !== n) {
n = parseInt(n) + parseInt(palindrome);
palindrome = parseInt((n + '').split('').reverse().join(''));
++count;
}
return count;
};
Next bigger number with the same digits
Description:
You have to create a function that takes a positive integer number and returns the next bigger number formed by the same digits:
nextBigger(12)==21 nextBigger(513)==531 nextBigger(2017)==2071
If no bigger number can be composed using those digits, return -1:
nextBigger(9)==-1 nextBigger(111)==-1 nextBigger(531)==-1
给定一个正整数 n, 找出下一个由组成 n 的数字组成的比 n 大的数(有点绕口。。)
高位的数是相同的,关键点在于找到 n[i] < n[i+1],然后保持左侧高位数字不变,将右侧数字按从小到大进行排序,找到第一个比 n[i] 大的数字,然后与 n[i] 进行调换,即得到下一个比 n 大的数字。
/**
*
* @param {number} n
* @returns {number}
*/
function nextBigger(n) {
var nextBigNum = -1;
var nums = n.toString().split('');
for (var i = nums.length - 1; i >= 0; --i) {
if (nums[i] < nums[i + 1]) {
var rightPartNums = nums.splice(i + 1).sort();
for (var j = 0; j < rightPartNums.length; ++j) {
if (rightPartNums[j] > nums[i]) {
nums[i] = rightPartNums[j] - nums[i];
rightPartNums[j] = rightPartNums[j] - nums[i];
nums[i] = rightPartNums[j] + nums[i];
nextBigNum = parseInt(nums.concat(rightPartNums).join(''), 10);
i = 0;
break;
}
}
}
}
return nextBigNum;
}
Description:
We need prime numbers and we need them now!
Write a method that takes a maximum bound and returns all primes starting with 0 up-to and including the maximum bound.
For example:
prime(11);
Should return an array that looks like this:
[2,3,5,7,11]
给定一个 n,返回包含 0 ~ n 的所有质数
这道题脑洞开的有点大,用 n 个 ‘0’表示n
00 2
000 3
0000 4
00000 5
000000 6
0000000 7
00000000 8
000000000 9
0000000000 10
00000000000 11
能平均分组的都不是质数,用正则进行匹配
00 2
0(00) 3
(00)(00) 4
0(00)(00) 5
(000)(000) 6
0(000)(000) 7
(0000)(0000) 8
(000)(000)(000) 9
(00000)(00000) 10
0(00000)(00000) 11
function prime(num) {
var arr = [];
while (num >= 2) {
if (!/^(11+?)\1+$/g.test('0'.repeat(num))) {
arr.unshift(num);
}
--num;
}
return arr;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.