The cause of
Yesterday, I scanned a LeetCode, and after successfully submitting it, I found that the execution time was still a little too long, so I beat 5% of JS users. This is no good, I have to explore and break through myself, it must be because my algorithm and writing method are too low!
The question went like this:
Leetcode title – 1170. Compare the frequency of the smallest letters in a string
Here’s my line of thought, very conventional:
-
Write a function to calculate the frequency of the minimum letter
-
Create an empty array answer and count variable time
-
Double iterate through queries and words, calculate the frequency of the items of these two arrays respectively, and then compare them. If the items meet the conditions, then time+1. After traversing the inner layer, push the final count into the answer, and return answer after traversing the outer layer
Here is my code implementation:
/**
* @param {string[]} queries
* @param {string[]} words
* @return {number[]}
*/
var numSmallerByFrequency = function(queries, words) {const answer = [] // Double traversal startsfor (leti = 0; i < queries.length; I ++) {// counter time is used to record the number of entries matching queries[I] and wordslet timesQueries [I] const queries_statisticsFrequency = statisticsFrequency(QUERIES [I])for (letj = 0; j < words.length; Const words_statisticsFrequency = statisticsFrequency(words[j]) {// Calculate words[j]if (queries_statisticsFrequency < words_statisticsFrequency) {
times += 1
}
}
answer.push(times)}returnanswer }; /** * this function is used to find the minimum number of letters * 1. Go through the number group, get the frequency of the minimum letter repetition, and return the frequency */ var statisticsFrequency =function (s) {
let frenquencyObj = {}
const arrayFromS = s.split(' ').sort()
for(leti=0; i<arrayFromS.length; i++){ const value = frenquencyObj[arrayFromS[i]] frenquencyObj[arrayFromS[i]] = value ? Value +1:1 /** If the next letter is different from the current letter, * indicates that the minimum number of repeated letters has been accumulated, and the value */ can be returnedif(arrayFromS[i] ! == arrayFromS[i+1]){return frenquencyObj[arrayFromS[0]]
}
}
}
Copy the code
I submitted three times and failed twice, because some test cases exceeded the time limit. I used some scheme modification to submit the third time successfully:
- When converting a string to an array
s.split('')
Than usingArray.from(s)
More efficient. - Start with
Array.map
Let’s go through the loopArray.forEach
After more efficient. - use
for
Instead of a loopArray.forEach
This is just to optimize the algorithm, in the case of certain conditions, do not need to continue to loop, usefor
You can jump out of the loop. - At first it was straight in the double loop
statisticsFrequency(queries[i])
与statisticsFrequency(words[j])
Written in the bookif
Statement, causing the two values to be evaluated twice each time. And then I bring the values upif
Outside of the calculation, and assign values to variables, variables to compare, also save some time.
To optimize the
How to find the minimum number of occurrences of a character in a string
/** * this function is used to find the minimum number of letters * 1. Go through the number group, get the frequency of the minimum letter repetition, and return the frequency */ 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
}
}
}
Copy the code
With this change, we can finally beat 7.69% of JS users.
Come to think of it, why do you need an object to keep in the first place?
Using objects, you can see what the smallest character is and how many times it occurs. But this problem doesn’t really need to know what the smallest character is.
Is there a better way to do this than double traversal?
- First, calculate the minimum frequency of the occurrence of characters for the two array elements respectively, and store them in the new array (
queriesCount
/wordsCount
) - right
wordsCount
Is sorted in descending order - Try using dichotomy for traversal comparison: take
queriesCount
And is divided again and againwordsCount
To compare
/**
* @param {string[]} queries
* @param {string[]} words
* @return {number[]}
*/
var numSmallerByFrequency = function(queries, words) {const answer = [] // Calculate the frequency of the smallest characters in the queries array and store them in a new array const queriesCount = queries. Map (item => {returnStatisticsFrequency (item)}) // Count the minimum occurrences of characters in words array elements in descending order to store them in a new array const wordsCount = words.map(item => {returnStatisticsFrequency (item)}).sort(compare).reverse()let front = 0,
end = wordsCount.length,
mid
while (front <= end) {
mid = parseInt((front + end) / 2)
if(mid ! == front && mid ! == end) {// dichotomyif (item >= wordsCount[mid]) {
end = mid
} else{front = mid}} // When wordsCount[0] is searched, if item >= wordsCount[mid], 0 is returnedelse if(mid === 0 && item >= wordsCount[mid]) {
answer.push(0)
return
}
else{// Since mid is the index of the array, the index starts from 0, so it should return +1 answer.push(mid +1)return}}})returnanswer }; Var compare =function (a,b){
return a-b
}
Copy the code
This is good, beat 80.77% of JS users!
extension
Note: The following code has not undergone extensive test case testing and performance testing
How do I find the most frequently occurring character in a string
Such as:
- The input
'abfeigeaabjgeba'
, the result should be returneda
. Explanation: Becausea
It appears four times, and all other characters appear less than four times. - The input
'bfeigeaabjgeba'
, the result should be returnedabe
. Explain becausea
,b
,e
All appear 3 times, and all other characters appear less than 3 times.
The code implementation is as follows:
var maxTimeCharacter = function (s) {
let frenquencyObj = {},
maxTime = 0,
character = ' '
const arrayFromS = s.split(' ').sort() arrayfroms.foreach (item => {// treat characters as keys and occurrences as valueslet value = frenquencyObj[item]
frenquencyObj[item] = value ? (++value) : 1
if (maxTime <= value) {
maxTime = value
if(character ! == item) { character += item }else {
character = item
}
}
})
return character
}
Copy the code
How to find the smallest character in a string that occurs more than 1 times
Such as:
- The input
'abfeigeaabjgeba'
, the result should be returneda
. Explanation: Becausea
It appears four times, and all other characters appear less than four times. - The input
'bfeigeaabjgeba'
, the result should be returneda
. Explain becausea
,b
,e
All the other characters are less than 3 times, buta
The character is the smallest character
The code implementation is as follows:
var moreTimeCharacter = function (s) {
let frenquencyObj = {},
maxTime = 0,
character = ' '
const arrayFromS = s.split(' ').sort() arrayfroms.foreach (item => {// treat characters as keys and occurrences as valueslet 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)
}
Copy the code