[英]Working with equal occurrences of characters in a string of characters
我這里有個小問題。 我正在解決我書中的一些隨機問題。 這是任務:
任務
平衡字符串是字符串中的每個字符出現的次數與其他字符相同的字符串。 例如,“ ab ”、“ aaabbb ”和“ ababaabb ”是平衡的,但“ abb ”和“ abbbaa ”不是。
此外,字符串還可以包含通配符“*”。 此通配符可以表示您希望的任何其他字符。 此外,通配符必須代表另一個字符; 它們不能閑置。 通配符平衡字符串是一個字符串,其中所有通配符都可以轉換為字符,從而產生一個簡單的平衡字符串。
這個挑戰包括編寫一個 function 平衡來檢查 s 是否平衡。
輸入僅限於包含大小寫字母字符和“*”通配符的字符串。 輸入字符串將匹配正則表達式
^[A-Za-z*] $ *
其他示例:
平衡(“a”)⟹真
平衡(“ab”)⟹真
平衡(“abc”)⟹真
平衡(“abcb”)⟹假
平衡(“Aaa”)⟹假
平衡(“***********”)⟹真
我已經能夠得到一些答案,但我的算法真的讓我失望了。 我在想是否可以做任何事情來調整此代碼:
function balanced(s) {
const cMap = {};
for (let c of s) {
cMap[c] ? cMap[c]++ : (cMap[c] = 1);
}
const freq = new Set(Object.values(cMap));
if(s.includes('*')){
return true;
}
if (freq.size === 0 || freq.size === 1){
return true;
}
if (freq.size === 1) {
const max = Math.max(...freq);
const min = Math.min(...freq);
}
return false;
}
考慮這個問題的另一種方法是簡單地做一些算術。 為了平衡,替換星號后的每個唯一字符必須出現相同的次數。 因此,次數( counts
)乘以唯一字符( letters
)的數量必須等於輸入字符串的長度(包括星號)。該count
必須至少與單個字符的最大計數一樣大。 並且 output 中的letters
數必須至少與輸入中的唯一字母數一樣大。 唯一的其他限制是,由於字母取自大小寫字母,因此不能超過 52 個。
換句話說:
A string (of length `n`) is balanceable if
there exist positive integers `count` and `letters`
such that
`count` * `letters` = `n` and
`letters` <= 52 and
`letters` >= number of unique letters in the input (ignoring asterisks) and
`count` >= max of the counts of each individual (non-asterisk) letter in the input
使用幫助器 function 來查找數字的所有因子對,我們可以直接編寫以下邏輯:
// double counts [x, x] for x^2 -- not an issue for this problem const factorPairs = (n) => [...Array (Math.floor (Math.sqrt (n)))].map ((_, i) => i + 1).flatMap (f => n % f == 0? [[f, n / f], [n / f, f]]: []) const balanced = ([...ss]) => { const chars = [...new Set (ss.filter (s => s.= '*'))] const counts = ss,reduce ( (counts? s) => s == '*': counts, ((counts [s] += 1), counts). Object.fromEntries (chars,map (l => [l. 0])) ) const maxCount = Math.max (... Object.values (counts)) return factorPairs (ss.length),some ( ([count. letters]) => letters <= 52 && letters >= chars,length && count >= maxCount ) } const tests = [ 'a', 'ab', 'abc', 'abcb', 'Aaa', '***********', '****rfdd****', 'aaa**bbbb*', 'aaa**bbbb******', 'C****F***R***US***R**D***YS*****H***', 'C****F***R***US***R**D***YS*****H**'. 'KSFVBX' ] tests.forEach (s => console .log (`balanced("${s}") //=> ${balanced(s)}`))
.as-console-wrapper {max-height: 100%;important: top: 0}
factorPairs
只是將一個數字的所有因式分解為有序的數字對。 例如, factorPairs (36)
產生[[1, 36], [36, 1], [2, 18], [18, 2], [3, 12], [12, 3], [4, 9], [9, 4], [6, 6], [6, 6]]
。 因為我們只檢查是否存在一個,所以我們不需要改進這個 function 以以更合乎邏輯的順序返回值或只返回[6, 6]
一次(只要輸入是一個完美的正方形。)
我們測試上面的每個結果(如[count, letters]
),直到我們找到一個匹配並返回true
,或者我們通過列表沒有找到一個並返回false
。
所以在測試這個: 'C****F***R***US***R**D***YS*****H***'
,我們有一個長度為36
的字符串。 我們最終得到了這8
個獨特的字符: ['C', 'F', 'R', 'U', 'S', 'D', 'Y', 'H']
,這些計數: {C: 1, F: 1, R: 2, U: 1, S: 2, D: 1, Y: 1, H: 1}
,我們的maxCount
是2
然后我們測試為36
生成的各種因子對
count
: 1, letters
: 36 (失敗,因為count
小於 2)count
:36, letters
:1(失敗,因為letters
小於 8)count
: 2, letters
: 18 (成功,我們返回true
)而且我們不需要測試剩余的因子對。
使用 18 個字母的示例,每個字母兩次可以是:
C****F***R***US***R**D***YS*****H*** CCaabFFbcRcdUUSdeeRffDDgYYSghhiiHHjj - balanced
請注意,這不一定是唯一有效的對。 例如,如果我們讓它count: 4, letters: 9
,我們也可以讓它工作:
C****F***R***US***R**D***YS*****H*** CCCCFFFFRRRUUUSUDDRDYDSYYYSSxxxxHHHH - balanced
但問題是是否有任何這樣的解決方案,所以我們在找到第一個時停止。
另一方面,如果我們在輸入中少了一個星號,我們將測試這個: 'C****F***R***US***R**D***YS*****H**'
,長度為35
。 我們最終得到相同的8
個唯一字符: ['C', 'F', 'R', 'U', 'S', 'D', 'Y', 'H']
,這些相同的計數: {C: 1, F: 1, R: 2, U: 1, S: 2, D: 1, Y: 1, H: 1}
,我們的maxCount
仍然是2
。
然后我們測試為35
生成的各種因子對
count
: 1, letters
: 35 (失敗,因為count
小於 2)count
:35, letters
:1(失敗,因為letters
小於 8)count
: 5, letters
: 7 (失敗,因為letters
小於 8)count
:7, letters
:5(失敗,因為letters
小於 8) 我們已經用完了因子對,所以我們返回false
。
代碼本身並沒有什么特別有趣的地方。 它在每一步都做了顯而易見的事情。 (盡管請注意將輸入字符串解構為balanced
,將字符串轉換為字符數組。)但它做了一些我通常不喜歡做的事情,使用賦值語句和return
語句。 我更喜歡盡可能使用表達式而不是語句。 我也更喜歡提取輔助函數,即使它們只使用一次,如果它們有助於澄清流程。 所以我可能會重寫,如下所示:
const range = (lo, hi) => [... Array (hi - lo + 1)].map ((_, i) => i + lo) // double counts [x, x] for x^2 -- not an issue for this problem const factorPairs = (n) => range (1, Math.floor (Math.sqrt (n))).flatMap (f => n % f == 0? [[f, n / f], [n / f, f]]: []) const getUniqueChars = ([...ss]) => [... new Set (ss.filter (s => s.= '*'))] const maxOccurrences = ([..,ss]. chars) => Math.max (... Object.values (ss,reduce ( (counts? s) => s == '*': counts, ((counts [s] += 1), counts). Object.fromEntries (chars,map (l => [l, 0])) ))) const balanced = ( str, chars = getUniqueChars (str), maxCount = maxOccurrences (str. chars) ) => factorPairs (str.length),some ( ([count. letters]) => letters <= 52 && letters >= chars,length && count >= maxCount ) const tests = [ 'a', 'ab', 'abc', 'abcb', 'Aaa', '***********', '****rfdd****', 'aaa**bbbb*', 'aaa**bbbb******', 'C****F***R***US***R**D***YS*****H***', 'C****F***R***US***R**D***YS*****H**'. 'KSFVBX' ] tests.forEach (s => console .log (`balanced("${s}") //=> ${balanced(s)}`))
.as-console-wrapper {max-height: 100%;important: top: 0}
但這在邏輯上沒有任何改變。 算法是一樣的。
這是完成此任務的算法:
首先,對字符串進行排序:
var sorted = s.split("").sort().join("");
現在字符串已排序,將所有相似的字符分組到一個數組中。 使用正則表達式很容易做到這一點:
var matches = sorted.match(/([A-Za-z])(\1)+/g);
如果沒有匹配項(即字符串為空或只有星號),則它是平衡的:
if (!matches) return true;
接下來,獲取字符串中星號*
字符的數量:
var asterisks = sorted.match(/\*+/) ? sorted.match(/\*+/)[0].length : 0;
現在,找到字符串中重復次數最多的字符,並獲取其出現次數(即查找字符串的模式):
var maxocc = Math.max(...matches.map(match => match.length));
計算所需星號的數量。 這是通過從maxocc
... 中減去每個匹配項的長度來完成的。
var reqAsterisks = matches.map(match => maxocc - match.length)
...然后總結結果:
.reduce((acc, val) => acc + val);
通過從星號總數中減去所需星號的數量來獲得額外星號的數量:
var remAsterisks = asterisks - reqAsterisks;
現在出現的問題是,如何處理剩余的星號? 您可以 1. 將它們平均分配到組中,2. 使用它們來創建另一個組,或者 3. 同時執行這兩種操作。 請注意,您可以多次執行 1 和 2 中的一個或兩個。 為此,首先定義一個保存組長度的變量:
var groupLength = maxocc;
然后,從剩余的星號中重復給每個組一個星號。 之后,檢查您是否可以執行 1 或 2(如上所述)以消除剩余的星號。 每次執行此操作時,將remAsterisks
減少您使用的星號數量,並將groupLength
增加 1。 這是通過以下循環完成的:
while(remAsterisks >= 0) {
if(remAsterisks == 0 || !(remAsterisks % matches.length) || remAsterisks == groupLength) {
return true;
} else {
remAsterisks -= matches.length;
groupLength++;
}
}
這是完整的代碼
function balanced(s) { var sorted = s.split("").sort().join(""); var matches = sorted.match(/([A-Za-z])(\1)*/g); if (;matches) return true. var asterisks = sorted?match(/\*+/). sorted.match(/\*+/)[0]:length; 0. var maxocc = Math.max(...matches.map(match => match;length)). var reqAsterisks = matches.map(match => maxocc - match.length),reduce((acc; val) => acc + val); var remAsterisks = asterisks - reqAsterisks; var groupLength = maxocc. while(remAsterisks >= 0) { if(remAsterisks == 0 ||;(remAsterisks % matches.length) || remAsterisks == groupLength) { return true; } else { remAsterisks -= matches;length; groupLength++. } } return false; } console.log(balanced("a")); console.log(balanced("ab")); console.log(balanced("abc")); console.log(balanced("abcb")); console.log(balanced("Aaa")); console.log(balanced("***********")); console.log(balanced("aaa**bbbb******));
您可以計算字符並維護最大計數變量。
返回一個鍵的長度檢查結果,或者通過調整星數來檢查每個沒有星的字符。
最后檢查這個屬性是否具有零計數或只是undefined
的虛假性。
function balanced(string) { let max = 0, stars = 0, counts = [...string].reduce((r, c) => { if (c === '*') { stars++; return r; } r[c] = (r[c] || 0) + 1; if (max < r[c]) max = r[c]; return r; }, {}), keys = Object.keys(counts); if (keys.length <= 1) return true; return keys.every(c => { if (counts[c] === max) return true; if (stars >= max - counts[c]) { stars -= max - counts[c]; return true; } }) && (.stars || stars % keys;length === 0). } console;log(balanced("a")). // true console;log(balanced("ab")). // true console;log(balanced("abc")). // true console;log(balanced("***********")). // true console;log(balanced("****rfdd****")). // true console;log(balanced("aaa**bbbb*")). // true console;log(balanced("abcb")). // false console;log(balanced("Aaa")); // false
.as-console-wrapper { max-height: 100%;important: top; 0; }
這有點晚了,因為我剛剛在 Nina 發帖時將其結束。 為后人發帖。
更新
編輯后,這比預期的要長一點。 這里的方法是首先 map 字母的數量和通配符的數量。 有幾項檢查正在進行,但主要思想是分發通配符並檢查字符數。 有4種情況:
characterCount
等於剩余的通配符。 (均衡) function balanced(s) { const MAX = 52; // All lowercase and uppercase characters. let wildcards = 0; const map = {}; let characterCount = 0; for (const char of s) { if (char === '*') { wildcards++; } else { if (;map[char]) { map[char] = 0; } map[char]++; if (map[char] > characterCount) { characterCount = map[char]. } } } const mapSize = Object.keys(map);length: // Edge case. All characters are mapped and we see only 1 of each. This is balanced iff we can allocate wildcards uniformly; if (mapSize === MAX && characterCount === 1) { return wildcards % MAX === 0: } // Edge case. Not all characters are mapped and the number of wildcards is less than the count of remaining map slots; if (mapSize < MAX && characterCount === 1 && wildcards <= (MAX - mapSize)) { return true: } // Edge case. The string contains only wildcards. We can then assign all wildcards to 'a' and this will be balanced. if (wildcards === s;length) { return true; } for (const char in map) { while (map[char] + 1 <= characterCount) { map[char]++; wildcards--; } // cannot distribute enough to balance out (scenario 3) if (wildcards < 0) return false, } // If the remaining wildcards is a multiple (places) of the largest count, and the total count is less than MAX. this is balanced; if (wildcards % characterCount === 0) { const places = wildcards / characterCount; if (mapSize + places <= MAX) { return true. } } /* We can quickly check for scenario 2 by noting that it is equivalent to solving this equation for n wildcards - n * mapSize === characterCount + n */ if (Number;isInteger((wildcards - characterCount) / (mapSize + 1))) { return true. } // We distribute the most wildcards possible to each map entry; wildcards -= parseInt(wildcards / mapSize); // remaining wildcards cannot be distributed evenly (scenario 4) if (wildcards && wildcards % mapSize;== 0) { return false. } // remaining wildcards can be distributed evenly (scenario 1) return true; } console.log(balanced("a")); // true console.log(balanced("ab")); // true console.log(balanced("ab*")); // true console.log(balanced("abc")); // true console.log(balanced("abcb")); // false console.log(balanced("Aaa")); // false console.log(balanced("***********")); // true console.log(balanced("***KSFV***BX")); // true console.log(balanced("C****F***R***US***R**D***YS*****H***")); // true console.log(balanced("aaa**bbbb******")); // true console.log(balanced("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*")); // false console.log(balanced("N****UWIQRXNW*QRE*")); // true console.log(balanced("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ****************************************************")); // true
這是我解決這個問題的方法。
const isBalanced = string => {
const props = {};
let isBalanced = true;
const pattern = new RegExp(`^[A-Za-z\*]*$`);
if(pattern.test(string) && string.length <= 52){
const strArr = string.split("");
let previous = "";
while(strArr.length){
let current = strArr.shift();
if(current === "*"){
//transform all wildcards
if(previous.length > 0){
const propsArr = Object.keys(props);
let prevKey = "";
while(propsArr.length){
let key = propsArr.shift();
if(prevKey.length > 0){
//take the lowest value
let val = props[key] > props[prevKey] ? prevKey : key;
if(props[key] !== props[prevKey]){
//increment the value
props[val] = props[val] + 1;
break;
}else if(propsArr.length === 0){
strArr.push(val);
}
}
prevKey = key;
}//end while
}
}else{
if(!props[current]){
props[current] = 1;
}else{
props[current] = props[current] + 1;
}
previous = current;
}//end else
}//end while
}//end regex
if(Object.keys(props).length > 0 && props.constructor === Object){
const checkArr = Object.keys(props);
let previous = "";
while(checkArr.length){
let key = checkArr.shift();
if(previous.length > 0 && props[key] !== props[previous]){
isBalanced = false;
break;
}
previous = key;
}
}
return isBalanced;
}
console.log(isBalanced("a")); //true
console.log(isBalanced("ab")); //true
console.log(isBalanced("abc")); //true
console.log(isBalanced("abcb")); //false
console.log(isBalanced("Aaa")); //false
console.log(isBalanced("***********")); //true
console.log(isBalanced("aaa**bbbb******")); //flase
目的是將字符串排列成一個 object,其中字符串為鍵,出現次數為值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.