我昨天刷到一道 LeetCode,成功提交後發現執行時間仍是有點兒太長,才戰勝了 5% 的 JS 用戶,這可不行,我得自我探索和突破一下,必定是我算法和寫法太 low 了!算法
那道題目是這樣的: 數組
想動手試試的能夠點這裏: leetcode 題目 - 1170. 比較字符串最小字母出現頻次個人思路是這樣,很常規:bash
寫一個函數用來計算最小字母的出現頻次函數
新建一個空數組 answer
和計數變量 time
性能
雙重遍歷 queries
和 words
,分別對這兩個數組的數組項進行頻次的計算,進行對比後,符合條件的則time+1
,遍歷完內層後,把最後的計數值推入 answer
中,遍歷完外層後,返回 answer
測試
如下是個人代碼實現:優化
/**
* @param {string[]} queries
* @param {string[]} words
* @return {number[]}
*/
var numSmallerByFrequency = function (queries, words) {
const answer = []
// 雙重遍歷開始
for (let i = 0; i < queries.length; i++) {
// 計數器 time 用來記錄 queries[i] 與 words 數組每項對比後符合條件的個數
let times = 0
// 計算 queries[i] 最小字母重複出現的頻次
const queries_statisticsFrequency = statisticsFrequency(queries[i])
for (let j = 0; j < words.length; j++) {
// 計算 words[j] 最小字母重複出現的頻次
const words_statisticsFrequency = statisticsFrequency(words[j])
if (queries_statisticsFrequency < words_statisticsFrequency) {
times += 1
}
}
answer.push(times)
}
return answer
};
/**
* 此函數用來求得最小字母的出現頻次
* 1. 先將字符串 s 轉爲數組,並按字母順序排列
* 2. 遍歷數組,求得最小字母重複出現的頻次,並返回頻次數
*/
var statisticsFrequency = function (s) {
let frenquencyObj = {}
const arrayFromS = s.split('').sort()
for(let i=0;i<arrayFromS.length;i++){
const value = frenquencyObj[arrayFromS[i]]
frenquencyObj[arrayFromS[i]] = value ? value+1 : 1
/** 若是下一個字母和目前的這個字母不同,
* 則說明最小字母重複出現的頻次已累計完畢,能夠直接返回值了
*/
if(arrayFromS[i] !== arrayFromS[i+1]){
return frenquencyObj[arrayFromS[0]]
}
}
}
複製代碼
提交了三次,兩次失敗,失敗緣由是某些測試用例超過了時間限制,我用了一些方案修改後提交第三次才成功:ui
s.split('')
比使用 Array.from(s)
更加高效。Array.map
進行循環,改爲 Array.forEach
後更加高效。for
循環來替代了 Array.forEach
,這只是爲了優化算法,在符合某種條件的狀況下,不須要繼續循環,使用 for
能夠跳出循環體。statisticsFrequency(queries[i])
與 statisticsFrequency(words[j])
寫在 if
語句裏進行對比,致使每次都要重複計算這兩個值。後來把值提到 if
以外計算,並賦值給變量,拿變量進行對比,也節省了一些時間。/**
* 此函數用來求得最小字母的出現頻次
* 1. 先將字符串 s 轉爲數組,並按字母順序排列
* 2. 遍歷數組,求得最小字母重複出現的頻次,並返回頻次數
*/
var statisticsFrequency = function (s) {
const arrayFromS = s.split('').sort()
let time = 0
for (let i = 0; i < arrayFromS.length; i++) {
time += 1
if (arrayFromS[i] !== arrayFromS[i + 1]) {
return time
}
}
}
複製代碼
這麼一改,終於能夠戰勝 7.69% 的 JS 用戶了。spa
回想一下,原來爲何還要弄個對象來保存?code
用對象來保存,能夠知道最小的字符是什麼,一共出現了幾回。可是這道題其實並無這個必要,不須要知道什麼是最小的字符。
queriesCount
/ wordsCount
)中wordsCount
中的數組進行降序排列queriesCount
的數組項和被一次次二分的 wordsCount
進行對比/**
* @param {string[]} queries
* @param {string[]} words
* @return {number[]}
*/
var numSmallerByFrequency = function (queries, words) {
const answer = []
// 計算 queries 數組元素最小字符出現的頻次,並存到一個新數組中
const queriesCount = queries.map(item => {
return statisticsFrequency(item)
})
// 計算 words 數組元素最小字符出現的頻次,降序排列後,存到一個新數組中
const wordsCount = words.map(item => {
return statisticsFrequency(item)
}).sort(compare).reverse()
// 利用二分法,進行遍歷對比
queriesCount.forEach(item => {
let front = 0,
end = wordsCount.length,
mid
while (front <= end) {
mid = parseInt((front + end) / 2)
if (mid !== front && mid !== end) {
// 二分法
if (item >= wordsCount[mid]) {
end = mid
} else {
front = mid
}
}
// 當查找 wordsCount[0] 時,若是 item >= wordsCount[mid],說明沒有符合小於條件的狀況,應該返回 0
else if(mid === 0 && item >= wordsCount[mid]) {
answer.push(0)
return
}
else {
// 因爲 mid 記錄的實際上是數組的下標,下標從 0 開始,因此這裏返回時應該 +1
answer.push(mid + 1)
return
}
}
})
return answer
};
// 用於數組項排序
var compare = function (a,b){
return a-b
}
複製代碼
這下子好了,擊敗了 80.77% 的 JS 用戶了!
說明:如下代碼並無通過大量的測試用例測試以及性能測試
例如:
'abfeigeaabjgeba'
,結果應該返回 a
。解釋:由於 a
出現了 4 次,其餘字符出現的次數都小於 4 次。'bfeigeaabjgeba'
,結果應該返回 abe
。解釋由於 a
、b
、e
都出現了 3 次,其餘字符出現的次數都小於 3 次。代碼實現以下:
var maxTimeCharacter = function (s) {
let frenquencyObj = {},
maxTime = 0,
character = ''
const arrayFromS = s.split('').sort()
arrayFromS.forEach(item => {
// 把字符當作 key,把出現的次數當作 value
let value = frenquencyObj[item]
frenquencyObj[item] = value ? (++value) : 1
if (maxTime <= value) {
maxTime = value
if (character !== item) {
character += item
} else {
character = item
}
}
})
return character
}
複製代碼
例如:
'abfeigeaabjgeba'
,結果應該返回 a
。解釋:由於 a
出現了 4 次,其餘字符出現的次數都小於 4 次。'bfeigeaabjgeba'
,結果應該返回 a
。解釋由於 a
、b
、e
都出現了 3 次,其餘字符出現的次數都小於 3 次,可是 a
字符是其中最小的字符代碼實現以下:
var moreTimeCharacter = function (s) {
let frenquencyObj = {},
maxTime = 0,
character = ''
const arrayFromS = s.split('').sort()
arrayFromS.forEach(item => {
// 把字符當作 key,把出現的次數當作 value
let value = frenquencyObj[item]
frenquencyObj[item] = value ? (++value) : 1
if (maxTime <= value) {
maxTime = value
if (character !== item) {
character += item
} else {
character = item
}
}
})
return character.charAt(0)
}
複製代碼