String Mix
链接
题目
给出两个字符串s1和s2,我们想要可视化两个字符串的差别。我们只计算小写字母(a到z)。首先让我们计算s1和s2中每个小写字母出现的频率。
s1 = "A aaaa bb c"
s2 = "& aaa bbb c d"
s1 has 4 'a', 2 'b', 1 'c'
s2 has 3 'a', 3 'b', 1 'c', 1 'd'
所以s1和s2中’a’的最大值是来自s1的4;'b’的最大值是来自s2的3。接下来我们不考虑最高出现频率小于或者等于1的字母。
我们可以通过下面这个字符串来简要概括s1和s2之间的差别:“1:aaaa/2:bbb”。其中1:aaaa
的1
代表字符串s1,aaaa
是因为a
的最大值为4。同理,2:bbb
代表字符串s2,bbb
是由于b
的最大值是3。
任务是产生一个字符串使得s1和s2中每一个小写字母如果出现的最大值大于1,则在字符串中出现和最大值相同的次数。这些字母将会由数字作为前缀,并且加上:
。如果s1和s2中的最大值相等则前缀是=:
。
在结果中,子字符串(一个子字符串是例如2:nnnnn或者1:hhh;它包含前缀)将会根据它们的长度降序排列,当它们的长度相同时,按上升词典序排列。不同的分组由’/'分割。详见例子。
希望其他例子能把这个表达清晰一些。
s1 = "my&friend&Paul has heavy hats! &"
s2 = "my friend John has many many friends &"
mix(s1, s2) --> "2:nnnnn/1:aaaa/1:hhh/2:mmm/2:yyy/2:dd/2:ff/2:ii/2:rr/=:ee/=:ss"
s1 = "mmmmm m nnnnn y&friend&Paul has heavy hats! &"
s2 = "my frie n d Joh n has ma n y ma n y frie n ds n&"
mix(s1, s2) --> "1:mmmmmm/=:nnnnnn/1:aaaa/1:hhh/2:yyy/2:dd/2:ff/2:ii/2:rr/=:ee/=:ss"
s1="Are the kids at home? aaaaa fffff"
s2="Yes they are here! aaaaa fffff"
mix(s1, s2) --> "=:aaaaaa/2:eeeee/=:fffff/1:tt/2:rr/=:hh"
我的思路及实现
function mix(s1, s2) {
var regs = /[^a-z]/g;
var arr1 = s1.replace(regs, "").split("").sort().join('').match(/([^])\1+/g) || [];
var arr2 = s2.replace(regs, "").split("").sort().join('').match(/([^])\1+/g) || [];
function sort2(a,b){
if (a.length > b.length) {
return -1;
} else if (a.length < b.length) {
return 1;
} else {
if (b<a) {
return 1;
} else if (b>a) {
return -1
}
}
}
arr1.sort(sort2);
arr2.sort(sort2);
var arrNew = [];
arr1.forEach((element, i) => {
var str1 = element.slice(0,1);
var f = true;
arr2.forEach((ele,i) => {
var str2 = ele.slice(0,1);
if (str1 == str2) {
if (element.length > ele.length) {
var obj = {
ele: element,
index: '1:'
};
arrNew.push(obj);
} else if (element.length == ele.length) {
var obj = {
ele: element,
index: '=:'
};
arrNew.push(obj);
} else if (element.length < ele.length) {
var obj = {
ele: ele,
index: '2:'
};
arrNew.push(obj);
}
arr2.splice(i, 1);
f = false;
}
})
if (f) {
var obj = {
ele: element,
index: '1:'
};
arrNew.push(obj);
}
});
arr2.forEach(ele2 => {
var obj = {
ele: ele2,
index: '2:'
};
arrNew.push(obj);
})
arrNew.sort((a, b) => {
if (a.ele.length > b.ele.length) {
return -1;
} else if (a.ele.length < b.ele.length) {
return 1;
} else {
if (a.index > b.index) {
return 1;
} else if (a.index < b.index) {
return -1;
} else {
var t1 = b.ele.slice(0,1);
var t2 = a.ele.slice(0,1);
return 0-(t1.charCodeAt(0)-t2.charCodeAt(0));
}
}
})
var result = "";
arrNew.forEach(ele => {
result += ele.index + ele.ele + '/';
})
return result.slice(0, result.length-1);
}
Best Practice
function mix(s1, s2) {
var counter = s => s.replace(/[^a-z]/g,'').split('').sort().reduce((x,y)=> (x[y] = 1 + (x[y]||0), x),{});
s1 = counter(s1); s2 = counter(s2);
var res = [], keys = new Set(Object.keys(s1).concat(Object.keys(s2)));
keys.forEach(key => {
var c1 = s1[key]||0, c2 = s2[key]||0, count = Math.max(c1, c2);
if (count>1) {
var from = [1, '=', 2][Math.sign(c2-c1)+1];
var str = [...Array(count)].map(_=>key).join('');
res.push(from+':'+str);
}
});
return res.sort((x, y) => y.length - x.length || (x < y ? -1 : 1)).join('/');
}
const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
function mix(s1, s2) {
return alphabet
.map(char => {
const s1Count = s1.split('').filter(x => x === char).length,
s2Count = s2.split('').filter(x => x === char).length,
maxCount = Math.max(s1Count, s2Count);
return {
char: char,
count: maxCount,
src: maxCount > s1Count ? '2' : maxCount > s2Count ? '1' : '='
};
})
.filter(c => c.count > 1)
.sort((objA, objB) => objB.count - objA.count || (objA.src + objA.char > objB.src + objB.char ? 1 : -1))
.map(c => `${c.src}:${c.char.repeat(c.count)}`)
.join('/');
}
const group = (a) => a.reduce((g, v) => Object.assign(g, { [v]: ++g[v] || 1 }), {})
const mix = (s1, s2) => {
const s1_values = group(s1.match(/[a-z]/g))
const s2_values = group(s2.match(/[a-z]/g))
return Object.keys(Object.assign({}, s1_values, s2_values))
.map((key) => {
const s1len = s1_values[key] || 0
const s2len = s2_values[key] || 0
const l = Math.max(s1len, s2len)
return l > 1 && `${s1len === s2len ? '=' : s1len > s2len && '1' || '2'}:${key.repeat(l)}`
})
.filter(Boolean)
.sort((a, b) => a.length < b.length
? 1
: a.length > b.length
? -1
: a > b ? 1 : a < b ? -1 : 0
)
.join('/')
}