Avènement du Code 2024 Jour 7
Partie 1
Première récursion de l'année
C'est du moins comme ?a que j'ai l'intention de gagner une étoile d'or aujourd'hui?:
- Commencez par la liste complète
- Vérifiez l'addition et la multiplication
- Pour chaque résultat, continuez avec le reste de la liste
- Jusqu'à ce que j'aie dépassé ou égalé le total
La difficulté sera dans les détails.
Faisons ?a?!
Créer mon algorithme
Tout d'abord, je dois analyser chaque ligne en une liste de nombres?:
let eqs = input.split('\n').map(line => { return [...line.matchAll(/\d+/g)].map(el => +el[0]) })
Le premier élément est le total souhaité.
Le reste sont les opérandes ordonnés de l'équation.
Je devrai en tenir compte dans ma fonction récursive.
Voici ma fonction récursive?:
function eqChecker(operands, amount, test) { if (amount > test) { return false } else if (amount == test && operands.length == 0) { return true } else if (operands.length) { let copy = operands.slice() let first = copy.shift() return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test) } }
Et voici la réduction qui l'utilise :
let part1 = eqs.reduce((count, eq) => { if (eqChecker(eq.slice(2), eq[1], eq[0])) { count += eq[0] } return count }, 0)
Comme je l'espérais mais ne m'y attendais jamais, cela génère la bonne réponse pour l'exemple d'entrée?!
Est-ce que le traitement de ma saisie de puzzle sera terminé??
Et si oui, cela générera-t-il la bonne réponse??
Honnêtement, je ne suis pas s?r...
C'EST FAIT !!!
Waouh !!!
Aussi excité que je sois, je crains que la prochaine partie ajoute plus d'opérateurs ou nécessite du CS avancé pour que la récursion ne soit plus une solution viable.
Partie 2
Totalement inattendu ! Et bien plus difficile
Comment vais-je faire ?a ?
...
Quelques jours plus tard...
Un récapitulatif de mon processus de réflexion?:
- Est-ce aussi simple que d'ajouter une troisième clause à ma condition de retour?? Non
- Ma fonction récursive de la partie 1 est-elle correctement configurée pour réussir?? Non
- Oh non, est-il même possible d'accumuler un montant résultant d'opérations antérieures?? Non
- Est-ce que je vais vraiment devoir aborder cela avec une nouvelle stratégie ? Ouais
Compte tenu de toutes les nouvelles variantes
Pour cette équation?:
292: 11 6 16 20
Ce sont toutes les équations possibles étant donné les trois opérateurs?:
11 11+6 11+6+16 11+6+16+20 11+6+16*20 11+6+1620 11+6*16 11+6*16+20 11+6*16*20 11+6*1620 11+616 11*6 11*6+16 11*6+16+20 11*6+16*20 11*6+1620 11*6*16 11*616 116 116+16 116+16+20 116+16*20 116+1620 116*16 11616
Peut-être que je peux créer une cha?ne de chaque équation et l'évaluer manuellement dans ma fonction récursive.
Par exemple?:
Je commence par une cha?ne vide dans l'appel de fonction le plus externe?:
""
à partir de là, je crée trois variantes en utilisant le numéro suivant?:
"" + "+N" "" + "*N" "" + "N"
Hmm, mais cela ne fonctionnera pas pour le premier numéro.
Je dois démarrer mon premier appel de fonction avec le premier numéro, pas une cha?ne vide?:
"N"
Même chose à partir de là?:
"N" + "+N" "N" + "*N" "N" + "N"
Ouais, ?a devrait marcher.
à la fin, j'aurai ces exemples de variations, tous évaluables?:
let eqs = input.split('\n').map(line => { return [...line.matchAll(/\d+/g)].map(el => +el[0]) })
Passer à?: Je l'ai codé... et j'ai découvert un problème plus important
J'ai écrit du code qui génère avec succès toutes les variantes de l'équation.
function eqChecker(operands, amount, test) { if (amount > test) { return false } else if (amount == test && operands.length == 0) { return true } else if (operands.length) { let copy = operands.slice() let first = copy.shift() return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test) } }
- j'ai l'habitude de parcourir la liste des numéros
- La dernière clause ne se poursuit que si i est avant ou à l'avant-dernier index
La fonction obtient quatre valeurs?:
- Une copie de la liste des numéros, moins le total attendu
- Le prochain indice
- La cha?ne d'équation avec l'une des trois cha?nes concaténées
- Le même numéro de test
J'appelle la fonction en utilisant presque la même signature que dans la partie 1?:
let part1 = eqs.reduce((count, eq) => { if (eqChecker(eq.slice(2), eq[1], eq[0])) { count += eq[0] } return count }, 0)
La différence réside dans ce que je passe comme arguments?:
- La liste sans le montant total attendu
- Commencer à l'index 0
- Une cha?ne contenant le premier nombre
- Le montant total attendu
Excellente nouvelle?:
- Il génère toutes les variations d'équation
Mauvaise nouvelle?:
- Il évalue toutes les équations en utilisant PEMDAS, et non de gauche à droite
J'aurais d? savoir mieux... que l'évaluateur JavaScript intégré utiliserait par défaut le bon ordre des opérations, et non de gauche à droite.
Cela met vraiment une clé encore plus grande dans mon algorithme?:
- Je vais devoir décomposer chaque équation et l'évaluer partie par partie
Uggghhh.
Heureusement, je pense que je sais exactement comment faire ?a.
Faire des calculs manuellement
J'ai besoin d'obtenir du JavaScript pour évaluer une équation comme celle-ci?:
292: 11 6 16 20
Dans cet ordre?:
11 11+6 11+6+16 11+6+16+20 11+6+16*20 11+6+1620 11+6*16 11+6*16+20 11+6*16*20 11+6*1620 11+616 11*6 11*6+16 11*6+16+20 11*6+16*20 11*6+1620 11*6*16 11*616 116 116+16 116+16+20 116+16*20 116+1620 116*16 11616
J'aimerais diviser cette équation en plusieurs parties?:
""
La seule fa?on pour moi de voir comment, c'est avec cette expression à triple cha?ne?:
"" + "+N" "" + "*N" "" + "N"
Je remplis chaque opérateur avec un espace blanc uniquement pour l'utiliser comme séparateur.
Un fait sur cette liste de parties d'équation?:
- Il contiendra toujours une quantité impaire d'éléments égale ou supérieure à 3
Comment puis-je exploiter ce fait dans une boucle qui parcourt chaque paire opérande-opérateur-opérande??
Voici mon idée?:
- Supprimez les trois premiers éléments
- Rejoignez-les sous forme de cha?ne et évaluez-la comme une expression mathématique
- Rattachez le résultat au début de la liste d'équations
- Répétez jusqu'à ce que la liste des équations soit vide
J'espère que ?a marchera?!
Mon simulateur de mathématiques de travail en JavaScript?:
"N"
Excellente nouvelle?:
- Il me montre les valeurs calculées attendues
Mauvaise nouvelle?:
- Je n'obtiens toujours pas la bonne réponse pour une équation dans l'exemple d'entrée
L'exemple de réponse ne peut pas être faux... n'est-ce pas ??
La réponse que je continue de générer est environ 7k inférieure à la réponse attendue.
Cela me fait penser que mon algorithme n'identifie pas cette équation comme correcte?:
let eqs = input.split('\n').map(line => { return [...line.matchAll(/\d+/g)].map(el => +el[0]) })
Dans l'explication de l'exemple de saisie, voici l'équation gagnante?:
function eqChecker(operands, amount, test) { if (amount > test) { return false } else if (amount == test && operands.length == 0) { return true } else if (operands.length) { let copy = operands.slice() let first = copy.shift() return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test) } }
Mon algorithme évalue cette équation et génère ce résultat?:
let part1 = eqs.reduce((count, eq) => { if (eqChecker(eq.slice(2), eq[1], eq[0])) { count += eq[0] } return count }, 0)
C'est parce que mon algorithme fonctionne comme ceci?:
292: 11 6 16 20
Je ne vois pas comment cela pourrait être un autre numéro.
Alors... j'ai cherché sur Google.
Et j'ai trouvé ma réponse, qui se cachait en clair dans l'explication, comme toujours?:
Tous les opérateurs sont toujours évalués de gauche à droite.
Je pré-concaténais les valeurs à chaque appel de fonction récursive.
Au lieu de cela, mon algorithme devrait faire ceci?:
11 11+6 11+6+16 11+6+16+20 11+6+16*20 11+6+1620 11+6*16 11+6*16+20 11+6*16*20 11+6*1620 11+616 11*6 11*6+16 11*6+16+20 11*6+16*20 11*6+1620 11*6*16 11*616 116 116+16 116+16+20 116+16*20 116+1620 116*16 11616
Maintenant que je comprends ce qui est censé se produire, puis-je ajuster mon algorithme pour qu'il corresponde à ce comportement de traitement??
De gauche à droite... pour de vrai cette fois
Heureusement, ajuster mon algorithme a été relativement simple.
J'ai ajouté une clause replaceAll() pour tenir compte de ||.
La nouvelle boucle while dans laquelle je traite tous les trois éléments ressemble à ceci?:
""
Et j'ai ajusté le || de ma déclaration de retour. clause pour inclure ces caractères, au lieu de concaténer instantanément les deux nombres.
Tests et re-tests
J'ai exécuté l'algorithme sur l'exemple d'entrée.
Il enfin a généré la bonne réponse !!
Quel soulagement !!
Je me demande s'il va finir de fonctionner et générer la bonne réponse sur ma saisie de puzzle.
Appuyer sur courir...
...
...
J'ai une réponse?!
C'est énorme, donc c'est probablement bon signe.
Est-ce la bonne réponse ?
...
Non. Trop haut.
Déception.
Est-ce qu'il me manque un cas limite??
Ma condition pour une équation gagnante est simplement que le résultat mathématique traité soit égal au montant du test.
Mais que se passe-t-il si l'une des variantes d'équations permet à un sous-ensemble de nombres de générer une réponse correcte??
Pour détecter et exclure ce scénario, j'ai mis à jour ma condition if pour inclure une clause supplémentaire?:
"" + "+N" "" + "*N" "" + "N"
De cette fa?on, ce n'est que si tous les nombres sont traités et que le montant résultant est égal au numéro du test que l'équation sera comptée.
La grande question?:
- Est-ce que cela change la réponse que j'obtiens??
Appuyer à nouveau sur Exécuter...
...
Hmm, cela ressemble toujours à la même réponse.
Oh, attendez, il y a deux chiffres vers la fin qui sont différents?!
Ma nouvelle réponse est exactement 80 de moins qu'avant.
Existe-t-il une équation avec 80 comme montant attendu??
Oui !
"N"
Existe-t-il un moyen d'obtenir 80 sans utiliser tous les nombres??
Oui !
"N" + "+N" "N" + "*N" "N" + "N"
était-ce le seul cas limite que je devais exclure??
Envoi de ma nouvelle réponse...
C'EST CORRECT !!!
Woohoo!!!
Je l'ai fait !!!
?a. était. épuisant. Et exaltant. Et vraiment courir. Et un défi.
Et toutes les raisons pour lesquelles j'aime faire ces puzzles.
En avant le suivant?!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1
éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Il existe trois fa?ons courantes d'initier des demandes HTTP dans Node.js: utilisez des modules intégrés, Axios et Node-Fetch. 1. Utilisez le module HTTP / HTTPS intégré sans dépendances, ce qui convient aux scénarios de base, mais nécessite un traitement manuel de la couture des données et de la surveillance des erreurs, tels que l'utilisation de https.get () pour obtenir des données ou envoyer des demandes de post via .write (); 2.AXIOS est une bibliothèque tierce basée sur la promesse. Il a une syntaxe concise et des fonctions puissantes, prend en charge l'async / attendre, la conversion JSON automatique, l'intercepteur, etc. Il est recommandé de simplifier les opérations de demande asynchrones; 3.Node-Fetch fournit un style similaire à la récupération du navigateur, basé sur la promesse et la syntaxe simple

Les types de données JavaScript sont divisés en types primitifs et types de référence. Les types primitifs incluent la cha?ne, le nombre, le booléen, le nul, un non défini et le symbole. Les valeurs sont immuables et les copies sont copiées lors de l'attribution des valeurs, de sorte qu'elles ne se affectent pas; Les types de référence tels que les objets, les tableaux et les fonctions stockent les adresses de mémoire, et les variables pointant vers le même objet s'afferchent mutuellement. Le typeof et l'instance de OFF peuvent être utilisés pour déterminer les types, mais prêtent attention aux problèmes historiques de typeofnull. Comprendre ces deux types de différences peut aider à écrire un code plus stable et fiable.

Bonjour, développeurs JavaScript! Bienvenue dans JavaScript News de cette semaine! Cette semaine, nous nous concentrerons sur: le différend de marque d'Oracle avec Deno, les nouveaux objets Time JavaScript sont pris en charge par les navigateurs, les mises à jour Google Chrome et certains outils de développeurs puissants. Commen?ons! Le différend de marque d'Oracle avec la tentative de Deno Oracle d'enregistrer une marque "JavaScript" a provoqué la controverse. Ryan Dahl, le créateur de Node.js et Deno, a déposé une pétition pour annuler la marque, et il pense que JavaScript est un niveau ouvert et ne devrait pas être utilisé par Oracle

Cacheapi est un outil fourni par le navigateur pour mettre en cache les demandes de réseau, qui est souvent utilisée en conjonction avec travailleur de service pour améliorer les performances du site Web et l'expérience hors ligne. 1. Il permet aux développeurs de stocker manuellement des ressources telles que des scripts, des feuilles de style, des photos, etc.; 2. Il peut faire correspondre les réponses du cache en fonction des demandes; 3. Il prend en charge la suppression des caches spécifiques ou la nettoyage du cache entier; 4. Il peut mettre en ?uvre des stratégies de priorité de cache ou de priorité de réseau grace à l'écoute des événements Fetch; 5. Il est souvent utilisé pour le support hors ligne, accélérez la vitesse d'accès répétée, préchargement des ressources clés et du contenu de mise à jour des antécédents; 6. Lorsque vous l'utilisez, vous devez faire attention au contr?le de la version du cache, aux restrictions de stockage et à la différence entre le mécanisme de mise en cache HTTP.

La promesse est le mécanisme central pour gérer les opérations asynchrones en JavaScript. Comprendre les appels de cha?ne, la gestion des erreurs et les combinants est la clé pour ma?triser leurs applications. 1. L'appel de la cha?ne renvoie une nouvelle promesse à travers. Puis () pour réaliser la concaténation des processus asynchrones. Chaque .then () re?oit le résultat précédent et peut renvoyer une valeur ou une promesse; 2. La gestion des erreurs doit utiliser .catch () pour attraper des exceptions pour éviter les défaillances silencieuses, et peut renvoyer la valeur par défaut dans Catch pour continuer le processus; 3. Combinateurs tels que promesse.all () (réussi avec succès uniquement après tout succès), promesse.race () (le premier achèvement est retourné) et promesse.allsetTled () (en attente de toutes les achèvements)

Des méthodes intégrées de la matrice JavaScript telles que .map (), .filter () et .reduce () peuvent simplifier le traitement des données; 1) .map () est utilisé pour convertir les éléments un en un pour générer de nouveaux tableaux; 2) .filter () est utilisé pour filtrer les éléments par condition; 3) .reduce () est utilisé pour agréger les données en tant que valeur unique; Une mauvaise utilisation doit être évitée lorsqu'elle est utilisée, entra?nant des effets secondaires ou des problèmes de performance.

La boucle d'événement de JavaScript gère les opérations asynchrones en coordonnant les piles d'appels, les webapis et les files d'attente de taches. 1. La pile d'appels exécute du code synchrone, et lors de la rencontre de taches asynchrones, il est remis à WebAPI pour le traitement; 2. Une fois que le WebAPI a terminé la tache en arrière-plan, il met le rappel dans la file d'attente correspondante (macro tache ou micro tache); 3. La boucle d'événement vérifie si la pile d'appels est vide. S'il est vide, le rappel est retiré de la file d'attente et poussé dans la pile d'appels pour l'exécution; 4. Micro taches (comme Promise. puis) ??prendre la priorité sur les taches macro (telles que Settimeout); 5. Comprendre la boucle d'événements permet d'éviter de bloquer le thread principal et d'optimiser l'ordre d'exécution du code.

Les bulles d'événements se propagent de l'élément cible vers l'extérieur vers le n?ud d'ancêtre, tandis que la capture d'événements se propage de la couche externe vers l'intérieur vers l'élément cible. 1. événements Bubbles: Après avoir cliqué sur l'élément enfant, l'événement déclenche l'auditeur de l'élément parent vers le haut. Par exemple, après avoir cliqué sur le bouton, il sortira d'abord cliqué sur l'enfant, puis parent. 2. Capture d'événement: définissez le troisième paramètre sur true, afin que l'auditeur soit exécuté dans l'étape de capture, tels que le déclenchement de l'écouteur de capture de l'élément parent avant de cliquer sur le bouton. 3. Les utilisations pratiques incluent la gestion unifiée des événements d'éléments enfants, le prétraitement d'interception et l'optimisation des performances. 4. Le flux d'événements DOM est divisé en trois étapes: capture, cible et bulle, et l'écouteur par défaut est exécuté dans l'étape de la bulle.
