Permalänk
Medlem

Progblemet #8 - Bruteforce

Nu kör vi ett till progblem!

Progblemet: Skapa en program som tar två inputs, $charset och $maxLength, och sedan listar alla permutationer upp till och med $maxLength.

Exempel:

$ mitt-program --charset="abc" --maxLength=3 a b c aa ab ac ba bb bc ca cb cc aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cab cac cba cbb cbc cca ccb ccc

Dold text

Protip: Detta går att göra väldigt kort och snyggt med rekursion

Btw vad heter detta? Kom bara på ordet bruteforce men det är ju lite fel..

Visa signatur

Programmerare -> PHP | HTML | CSS | JS | Java.

Permalänk
Moderator

bruteforce hade varit lite fel där hehe

Visa signatur

Citera om du vill ha svar!
Tycker du om sidospår? :D Besök The Wiki Game
Har du fråga angående modereringen? PM till Moderatorerna eller Kontaktformulär

Permalänk
Inaktiv

Tänker mig att det heter "lista kombinationer".

Det går ju att lösa fint med rekursion. Men en enklare lösning är ju att loopa. Lösningen med en loop kommer heller inte att förstöra stacken om man har för stora tal

Tänker mig att man går igenom och inkrementerar den sista siffran. Når någon siffra når maxLength så sätter man den till 0 och ökar siffran till vänster med 1. Avsluta när siffra [0] == maxLength.

Permalänk
Medlem
Skrivet av anon81912:

Tänker mig att det heter "lista kombinationer".

Det går ju att lösa fint med rekursion. Men en enklare lösning är ju att loopa. Lösningen med en loop kommer heller inte att förstöra stacken om man har för stora tal

Tänker mig att man går igenom och inkrementerar den sista siffran. Når någon siffra når maxLength så sätter man den till 0 och ökar siffran till vänster med 1. Avsluta när siffra [0] == maxLength.

Det luriga där är ju definitionen av "kombinationer", specifikt om ordningen har betydelse eller ej. Om man är strikt (vilket väl är lämpligt i sammanhanget) så är det väl så att 'a' följt av 'b' respektive 'b' följt av 'a' inte är olika kombinationer.

Vad gäller resten så håller jag med, i praktiken är det nog en "snällare" lösning att bara loopa men det kanske blir aningen mer elegant med rekursion.

Visa signatur

AMD Ryzen9 5900X || Gigabyte X570 Ultra || RTX 3090 FE || Gskill Trident Z 3600 64GB || Samsung 950 Pro 512GB || Samsung 960 Pro 1024GB || XB270HU 1440p IPS G-Sync

Permalänk
Avstängd

denna använde jag i mitt exjobb för 7 år sedan, koden ser ju fortfarande helt okej ut faktiskt :D using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace PaperSim.Backend.ApplicationLayer.Engine.Combination { /// <summary> /// Stores a full specification of combinations to generate, and allows the construction of enumerators to generate the combinations. /// </summary> /// <typeparam name="T">the type to generate combinations of</typeparam> internal class Combinations<T> : IEnumerable<T[]> { #region Combinations Members private ElementSet<T> _Elements; private int _Choose; /// <summary> /// Constructs a new <c>Combinations</c> given a collection of elements and how many elements should be present in each combination. Note that if the same collection of elements is used with multiple <paramref name="choose"/> values, it is faster to construct an <see cref="ElementSet{T}"/> once and use <see cref="Combinations{T}(ElementSet{T}, int)"/>. /// </summary> /// <param name="elements">the collection of elements</param> /// <param name="choose">the length of a combination</param> public Combinations(IEnumerable<T> elements, int choose) : this(new ElementSet<T>(elements, null), choose) { } /// <summary> /// Constructs a new <c>Combinations</c> given a collection of elements and how many elements should be present in each combination. Note that if the same collection of elements is used with multiple <paramref name="choose"/> values, it is faster to construct an <see cref="ElementSet{T}"/> once and use <see cref="Combinations{T}(ElementSet{T}, int)"/>. /// </summary> /// <param name="elements">the collection of elements</param> /// <param name="choose">the length of a combination</param> /// <param name="comparer">the comparer used to order the elements</param> public Combinations(IEnumerable<T> elements, IComparer<T> comparer, int choose) : this(new ElementSet<T>(elements, comparer), choose) { } /// <summary> /// Constructs a new <c>Combinations</c> given a collection of elements and how many elements should be present in each combination. If the same set of elements will be used with different values of <paramref name="choose"/>, this constructor is the best choice as the elements are processed only once, during the construction of the <see cref="ElementSet{T}"/>. /// </summary> /// <param name="elements">the collection of elements</param> /// <param name="choose">the length of a combination</param> public Combinations(ElementSet<T> elements, int choose) { if (elements == null) { throw new ArgumentNullException("elements"); } if (choose < 0 || choose > elements.Count) { throw new ArgumentOutOfRangeException("choose"); } _Elements = elements; _Choose = choose; } #endregion #region IEnumerable<T[]> Members /// <summary> /// Creates and returns an enumerator over the combinations. Each combination's elements will be returned in ascending order as defined by the compararer. The combinations themselves will also be returned in ascending order. /// </summary> /// <returns>an enumerator</returns> /// <seealso cref="IEnumerable{T}.GetEnumerator"/> public IEnumerator<T[]> GetEnumerator() { if (_Choose == 0) { return new ChooseZeroEnumerator(); } else { return new Enumerator(this); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region Enumerator Class private class Enumerator : IEnumerator<T[]> { #region Enumerator Members private Combinations<T> _Combinations; private int[] _Indices, _IndicesAt; private bool _PastEnd; internal Enumerator(Combinations<T> combinations) { _Combinations = combinations; _Indices = new int[_Combinations._Choose]; _IndicesAt = new int[_Combinations._Elements.Elements.Count]; Reset(); } private void MoveFirst() { // Move all the indices as far left as possible. // Lower-numbered indices go further left. int currentIndex = 0; int usedCurrent = 0; for (int i = 0; i < _Indices.Length; i++) { Debug.Assert(currentIndex < _Combinations._Elements.Elements.Count); _Indices[i] = currentIndex; _IndicesAt[currentIndex]++; usedCurrent++; if (usedCurrent == _Combinations._Elements.Elements.Values[currentIndex]) { // We've used all of the current element. Go to the next element. currentIndex++; usedCurrent = 0; } } } private void MoveIndex(int index, int offset) { if (_Indices[index] >= 0 && _Indices[index] < _IndicesAt.Length) { _IndicesAt[_Indices[index]]--; } _Indices[index] += offset; if (_Indices[index] >= 0 && _Indices[index] < _IndicesAt.Length) { _IndicesAt[_Indices[index]]++; } } private bool IsFull(int position) { // True if (position) has as many indices as it can hold. return _IndicesAt[position] == _Combinations._Elements.Elements.Values[position]; } private bool CanFitRemainingIndices(int index) { int space = _Combinations._Elements.ElementsAtOrAfter[_Indices[index]]; return space >= _Indices.Length - index; } private bool AdvanceIndex(int index, int doNotReach) { // First move the index one position to the right. MoveIndex(index, 1); // If we've found an existing position with no other index, and there's room at-and-to-the-right-of us for all the indices greater than us, we're good. if (_Indices[index] < doNotReach) { if (_IndicesAt[_Indices[index]] == 1) { if (CanFitRemainingIndices(index)) { return true; } } } // We've either fallen off the right hand edge, or hit a position with another index. If we're index 0, we're past the end of the enumeration. If not, we need to advance the next lower index, then push ourself left as far as possible until we hit another occupied position. if (index == 0) { _PastEnd = true; return false; } if (!AdvanceIndex(index - 1, _Indices[index])) { return false; } // We must move at least one space to the left. If we can't, the enumeration is over. // If the position immediately to the left is already full, we can't move there. if (IsFull(_Indices[index] - 1)) { _PastEnd = true; return false; } // Move left until the next leftmost element is full, or the current element has an index. do { MoveIndex(index, -1); } while (_IndicesAt[_Indices[index]] == 1 && !IsFull(_Indices[index] - 1)); return true; } #endregion #region IEnumerator<T[]> Members public T[] Current { get { if (_Indices[0] == -1 || _PastEnd) { // Before first or after last. throw new InvalidOperationException(); } else { T[] current = new T[_Indices.Length]; for (int i = 0; i < _Indices.Length; i++) { current[i] = _Combinations._Elements.Elements.Keys[_Indices[i]]; } return current; } } } #endregion #region IDisposable Members public void Dispose() { // Do nothing. } #endregion #region IEnumerator Members object IEnumerator.Current { get { return Current; } } public bool MoveNext() { if (_PastEnd) { return false; } if (_Indices[0] == -1) { MoveFirst(); return true; } else { bool ret = AdvanceIndex(_Indices.Length - 1, _IndicesAt.Length); return ret; } } public void Reset() { for (int i = 0; i < _Indices.Length; i++) { _Indices[i] = -1; } Array.Clear(_IndicesAt, 0, _IndicesAt.Length); _PastEnd = false; } #endregion } #endregion #region ChooseZeroEnumerator Class private class ChooseZeroEnumerator : IEnumerator<T[]> { #region ChooseZeroEnumerator Members private enum State { BeforeBeginning, OnElement, PastEnd, } private State _State; internal ChooseZeroEnumerator() { Reset(); } #endregion #region IEnumerator<T[]> Members public T[] Current { get { if (_State == State.OnElement) { return new T[0]; } else { throw new InvalidOperationException(); } } } #endregion #region IDisposable Members public void Dispose() { // Do nothing. } #endregion #region IEnumerator Members object IEnumerator.Current { get { return Current; } } public bool MoveNext() { switch (_State) { case State.BeforeBeginning: _State = State.OnElement; return true; case State.OnElement: case State.PastEnd: _State = State.PastEnd; return false; default: throw new InvalidOperationException(); } } public void Reset() { _State = State.BeforeBeginning; } #endregion } #endregion } }

edit: Jag använde den för att brutforca ett problem, vi behövde lista ut om en nod i vår graf hade återkoppling

Visa signatur
Permalänk
Medlem
Skrivet av evil penguin:

Det luriga där är ju definitionen av "kombinationer", specifikt om ordningen har betydelse eller ej. Om man är strikt (vilket väl är lämpligt i sammanhanget) så är det väl så att 'a' följt av 'b' respektive 'b' följt av 'a' inte är olika kombinationer.

Vad gäller resten så håller jag med, i praktiken är det nog en "snällare" lösning att bara loopa men det kanske blir aningen mer elegant med rekursion.

AB och BA är inte olika kombinationer, men permutationer..

Så:
Lista alla möjliga permutationer?

Visa signatur

Outtröttlig, löpartokig besserwisser!

Bli vegan! För djuren, planeten, hälsan och våra barns skull!

Permalänk
Medlem
Skrivet av NisseG91:

AB och BA är inte olika kombinationer, men permutationer..

Så:
Lista alla möjliga permutationer?

Men om man utgår från ABC så är ju inte AB en permutation av detta. Och t.ex. ABB är inte heller en permutation av ABC....?

Visa signatur

AMD Ryzen9 5900X || Gigabyte X570 Ultra || RTX 3090 FE || Gskill Trident Z 3600 64GB || Samsung 950 Pro 512GB || Samsung 960 Pro 1024GB || XB270HU 1440p IPS G-Sync

Permalänk
Avstängd

Det är väll ganska uppenbart att han vill ha alla kombinationer av A,B,C?

Visa signatur
Permalänk
Medlem

Ja, exakt och 1+1 blir väl 2 ? , alltså jag är så jävla impad av folk som kan kodning !

ni är riktiga förebilder för mig!

Visa signatur

Sweclockers.se världens bästa sida för alla sorts konspirationsteorier mot ryssar.

Permalänk
Medlem
Skrivet av evil penguin:

Men om man utgår från ABC så är ju inte AB en permutation av detta. Och t.ex. ABB är inte heller en permutation av ABC....?

Just det, bra där!

Visa signatur

Outtröttlig, löpartokig besserwisser!

Bli vegan! För djuren, planeten, hälsan och våra barns skull!

Permalänk
Medlem
Skrivet av CyberVillain:

Det är väll ganska uppenbart att han vill ha alla kombinationer av A,B,C?

Njae, ABC och CAB är samma kombination men olika permutationer..
Men som sagts tidigare så är ABC och AB inte olika permutationer.

Svårt att säga exakt vad TS är ute efter, men alla förstår nog iaf

Visa signatur

Outtröttlig, löpartokig besserwisser!

Bli vegan! För djuren, planeten, hälsan och våra barns skull!

Permalänk
99:e percentilen
Skrivet av CyberVillain:

Det är väll ganska uppenbart att han vill ha alla kombinationer av A,B,C?

Inte om man med "kombinationer" menar den matematiska definitionen. TS har i sitt exempel både ab och ba. Dessa är inte olika kombinationer, men olika permutationer.

Visa signatur

Skrivet med hjälp av Better SweClockers

Permalänk
Avstängd

Ni tänker så

Visa signatur
Permalänk
Medlem

Så mao, han vill ha höljet "the closure" av en mängd som man får som indata upp till en viss storlek.

Permalänk
Medlem
Skrivet av anon81912:

Tänker mig att det heter "lista kombinationer".

Det går ju att lösa fint med rekursion. Men en enklare lösning är ju att loopa. Lösningen med en loop kommer heller inte att förstöra stacken om man har för stora tal

Tänker mig att man går igenom och inkrementerar den sista siffran. Når någon siffra når maxLength så sätter man den till 0 och ökar siffran till vänster med 1. Avsluta när siffra [0] == maxLength.

Vill gärna se hur det går att lösa med en loop, ska bli intressant att se

Skrivet av NisseG91:

AB och BA är inte olika kombinationer, men permutationer..

Så:
Lista alla möjliga permutationer?

Där lärde jag mig ett nytt ord. Uppdaterar tråden, menar alla möjliga permutationer.

Visa signatur

Programmerare -> PHP | HTML | CSS | JS | Java.

Permalänk
Medlem
Skrivet av NisseG91:

Njae, ABC och CAB är samma kombination men olika permutationer..
Men som sagts tidigare så är ABC och AB inte olika permutationer.

Svårt att säga exakt vad TS är ute efter, men alla förstår nog iaf

Uhm, är ABC och AB samma permutation? Nu blir jag förvirrad..

Hur som heslt, här har du ett till mer tydligt exempel på vad jag är ute efter:

$ mitt-program --charset="abc" --maxLength=2 a b c aa ab <-- Notera ac ba <-- Notera (ab OCH ba ska vara med) bb bc ca cb cc

Dold text
Visa signatur

Programmerare -> PHP | HTML | CSS | JS | Java.

Permalänk
Medlem
Skrivet av Sony?:

Uhm, är ABC och AB samma permutation? Nu blir jag förvirrad..

Hur som heslt, här har du ett till mer tydligt exempel på vad jag är ute efter:

$ mitt-program --charset="abc" --maxLength=2 a b c aa ab <-- Notera ac ba <-- Notera (ab OCH ba ska vara med) bb bc ca cb cc

Dold text

Inte samma permutation, AB är inte en permutation av ABC öht.

Visa signatur

Outtröttlig, löpartokig besserwisser!

Bli vegan! För djuren, planeten, hälsan och våra barns skull!

Permalänk
Hedersmedlem
Skrivet av Sony?:

Uhm, är ABC och AB samma permutation? Nu blir jag förvirrad..

Man kan inte erhålla AB genom att ordna om elementen i ABC, så de är inte permutationer av samma elementmängd.

Permalänk
Medlem

Löst med java

public class HejHopp { static String charset = "ABDC"; static int maxLength = 3; public static void main(String[] args) { if(args.length > 0) { charset = args[0]; maxLength = Integer.parseInt(args[1]); } closure("", maxLength); } static void closure(String current, int workLeft) { if(workLeft < 0) return; //else System.out.println(current); for(int i = 0; i < charset.length(); ++i) { closure((current + charset.charAt(i)), (workLeft-1)); } } }

Dold text

Hölje av en mängd är problembeskrivningen du letar efter

EDIT
Onödigt med en ArrayList

Permalänk
Medlem

Att lösa problemet är inte svårt, dock så blir det lätt en extremt ineffektiv kod, roligare att köra typ alla kombinationer av "abcdefghij" med längd 10 på överskådlig tid, så man måste tänka lite på hur man skriver

import java.util.ArrayList; public class testAlgorithm { private ArrayList<String> charList = new ArrayList<String>(); private ArrayList<String> completeList = new ArrayList<String>(); public static void main(String[] args) { testAlgorithm tA = new testAlgorithm(); tA.print("abc", 20); } public void print(String charSet, int maxLength) { for (int i = 0; i < charSet.length(); i++) { charList.add(((Character) charSet.charAt(i)).toString()); } for (int i = 1; i <= maxLength; i++) { run(i, ""); } System.out.println(completeList.toString()); } private void run(int round, String s) { if (round == 0) { completeList.add(s); } else { for (String ch : charList) { run(round - 1, s + ch); } } } }

Dold text
Permalänk
Medlem

Intressanta lösningar.

Min PHP lösning: (vilken jag är mycket nöjd över )

<?php $charset = "abc"; $maxLength = 3; $chrLen = strlen($charset); //Hämtar premutationen på plats $num function nxt($num) { global $charset, $maxLength, $chrLen; if($num < $chrLen) return $charset[$num]; //Minskar $num och utför rekursion $combination = nxt((int) floor($num / $chrLen) - 1) . $charset[$num % $chrLen]; return (strlen($combination) <= $maxLength) ? $combination : false; } $i = 0; while(($combination = nxt($i++))) echo $combination ."\n"; ?>

Dold text

Hur den funkar:

Tänk att vi redan har listan med permutationer som vi vill generera.

A
B
C
AA
AB
AC
BA
BB
BC
...

Dold text

Tänk nu att vi vill åt nummer 0 (A). Det är enkelt. Bara att hämta ut 0 ur vår $charset lista.

$charset[0] => A
Samma med 1 (B) och 2 (C).

Men om vi vill ha nummer 3 (AA), hur gör vi då?

Jo vi tar 3 / $charsetLength (abc = 3 tecken) -> 3/3 = 1 (avrundat neråt(!)). Sedan tar vi minus 1 då arrays börjar med index 0 och inte 1 ($charset[0] => A, inte $charset[1] då array index börjar på 0). Nu har vi numret 0.

Vi tar det nya numret (0) och kör funktionen igen. Vi hämtar alltså ut 0 ur $charset, vilket är bokstaven A. (RETURN; UPP EN NIVÅ; $nummer är nu 3)
Detta sätter vi ihop med $numret % (mod) $charsetLength -> 3%3 = 0 (A).

A+A = AA

Tada! Nu har vi AA.

$combination = nxt((int) floor($num / $chrLen) - 1) . $charset[$num % $chrLen];

Ok, ok. Men om vi vill ha nummer 17 (ABC), hur gör vi då? På samma sätt!

17 / $charsetLength (abc = 3 tecken) -> 17/3 = 5 (avrundat neråt(!)). Sedan tar vi minus 1. Nu har vi numret 4.

Vi tar det nya numret (4) och kör funktionen igen. 4 finns inte i $charset, så vi får göra som vi gjorde med 17.

4 / $charsetLength -> 4/3 = 1 (avrundat neråt(!)). Sedan tar vi minus 1. Nu har vi numret 0.

Vi tar det nya numret (0) och kör funktionen igen. Vi hämtar alltså ut 0 ur $charset, vilket är bokstaven A. (RETURN; UPP EN NIVÅ; $nummer är nu 4)
Detta sätter vi ihop med $numret % $charsetLength -> 4%3 = 1 (B). (RETURN; UPP EN NIVÅ; $nummer är nu 5)

A+B = AB

Detta sätter vi ihop med $numret % $charsetLength -> 17%3 = 2 (C).

A+B+C = ABC

Tada! Nu har vi ABC.

Visa signatur

Programmerare -> PHP | HTML | CSS | JS | Java.

Permalänk
Hedersmedlem

(Massa citeringar)

Skrivet av Sony?:

Btw vad heter detta? Kom bara på ordet bruteforce men det är ju lite fel..

Skrivet av anon81912:

Tänker mig att det heter "lista kombinationer".

[QUOTE=evil penguin;13339871]Det luriga där är ju definitionen av "kombinationer", specifikt om ordningen har betydelse eller ej. Om man är strikt (vilket väl är lämpligt i sammanhanget) så är det väl så att 'a' följt av 'b' respektive 'b' följt av 'a' inte är olika kombinationer.[/QUOTE]

Skrivet av NisseG91:

AB och BA är inte olika kombinationer, men permutationer..

Så:
Lista alla möjliga permutationer?

[QUOTE=evil penguin;13339904]Men om man utgår från ABC så är ju inte AB en permutation av detta. Och t.ex. ABB är inte heller en permutation av ABC....?[/QUOTE]

Skrivet av CyberVillain:

Det är väll ganska uppenbart att han vill ha alla kombinationer av A,B,C?

Skrivet av NisseG91:

Njae, ABC och CAB är samma kombination men olika permutationer..
Men som sagts tidigare så är ABC och AB inte olika permutationer.

Svårt att säga exakt vad TS är ute efter, men alla förstår nog iaf

Skrivet av HurMycket:

Inte om man med "kombinationer" menar den matematiska definitionen. TS har i sitt exempel både ab och ba. Dessa är inte olika kombinationer, men olika permutationer.

Skrivet av Sony?:

Uppdaterar tråden, menar alla möjliga permutationer.

Skrivet av Sony?:

Uhm, är ABC och AB samma permutation? Nu blir jag förvirrad..

Skrivet av NisseG91:

Inte samma permutation, AB är inte en permutation av ABC öht.

Dold text

Det matematiska namnet är kartesisk produkt. Tråden frågar efter ett program som skriver ut elementen i den kartesiska produkten av en mängd A med sig själv i gånger, där i går från 1 till mängdens kardinalitet (antal element i mängden).

Här används mängden (a, b, c). Alltså skrivs först A¹, sedan A² och sedan A³ ut (där exponenten betecknar kartesisk produkt).

När jag ändå är här: Python för den late (varför programmera mer än man behöver? ):

#!/usr/bin/env python3 import itertools def print_prog_8(elements): for i in range(len(elements)): for j in itertools.product(elements, repeat=i+1): print ''.join(j) print_prog_8('abc')

Masochisten kan komprimera detta till exempelvis:

#!/usr/bin/env python3 from itertools import product as p f = lambda e: [print(''.join(j)) for i in range(len(e)) for j in p(e, repeat=i+1)] f('abc')

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Datavetare

Python

phz visade den enkla lösning så kommer här lösningen för gör-det-självaren

def flatten1(aList): "Flattens a list one level, [['a'], ['b']] -> ['a', 'b']" return reduce(lambda result, lst: result + lst, aList, []) def prod(chrSet, maxLen, prefix=''): if maxLen < 0: return [] return [prefix] + flatten1([ prod(chrSet, maxLen - 1, prefix + c) for c in chrSet ]) for x in prod("abc", 3): print x

Dold text

Edit: insåg att jag löste fel uppgift, nu ska det vara rätt!

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk

Generator.

def progblem(chars, num): if num == 0: return for c in chars: yield c for s in progblem(chars, num - 1): yield c + s for s in progblem('abc', 3): print s

Dold text
Permalänk
Datavetare

C

Sällan någon gör en lösning i gamla heliga C i progblemet, så här kommer en sådan version. Skriver ner resultatet i RAM innan det skrivs ut då jag ville se hur långt tid det tar att köra t.ex. chrSet="abcdefghi" och maxLen=9.

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> /* * Returns base^exp */ size_t ipow(size_t base, size_t exp) { if (exp == 0) return 1; return base * ipow(base, exp - 1); } /* * Returns the number of elements that will be generated for a * character set of a specific length and a resulting maximum string * length */ size_t elem_cnt(size_t chr_set_len, size_t max_len) { if (max_len == 0) return 0; return ipow(chr_set_len, max_len) + elem_cnt(chr_set_len, max_len - 1); } char *prod(const char *chr_set, char *prefix, unsigned prefix_len, unsigned max_len, char *res) { const char *c = chr_set; if (prefix_len < max_len) while (*c != '\0') { *stpcpy(res, prefix) = *c++; res = prod(chr_set, res, prefix_len + 1, max_len, res + max_len); } return res; } void make_fmt_str(size_t max_len, char *fmt) { sprintf(fmt, "%%.%lds\n", max_len); } void parse_args(int argc, char *argv[], const char **pchr_set, unsigned *pmax_len, int *pprint_summary) { int tkn; /* Default values */ *pchr_set = "abc"; *pmax_len = 3; *pprint_summary = 0; while (0 < (tkn = getopt(argc, argv, "c:l:p:"))) { switch (tkn) { case 'c': *pchr_set = optarg; break; case 'l': *pmax_len = atoi(optarg); break; case 'p': *pprint_summary = atoi(optarg); break; } } } int main(int argc, char *argv[]) { const char *chr_set; unsigned max_len; int print_summary; size_t i; size_t cnt; char *result; parse_args(argc, argv, &chr_set, &max_len, &print_summary); cnt = elem_cnt(strlen(chr_set), max_len); result = calloc(cnt, max_len); if (result == NULL) { fprintf(stderr, "Not enough memory\n"); return EXIT_FAILURE; } prod(chr_set, "", 0, max_len, result); if (print_summary) printf("%ld lines\n", cnt); else { char fmt[8]; make_fmt_str(max_len, fmt); for (i = 0; i < cnt; i++) printf(fmt, result + (i * max_len)); } free(result); return EXIT_SUCCESS; }

Dold text

Det är egentligen bara de tre första funktionerna som är till för att lösa uppgiften, resten är hjälp funktioner för att skriva ut resultatet och ta hand argument till programmet.

Exempel körningar

$ ./perm a aa aaa aab aac ab aba abb abc ac aca acb acc b ba baa bab bac bb bba bbb bbc bc bca bcb bcc c ca caa cab cac cb cba cbb cbc cc cca ccb ccc

Dold text

$ time ./perm -c abcdefghi -l 9 -p 1 435848049 lines real 0m4.045s user 0m2.988s sys 0m1.048s

Dold text

435848049 strängar skapades på runt 4 sekunder på en i7 2600, tar lite längre tid med lösningarna skrivna i Java eller Python...

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

public class HejHopp { static String charset = "abcdefghi"; static int maxLength = 9; static int amount = 0; public static void main(String[] args) { if(args.length > 0) { charset = args[0]; maxLength = Integer.parseInt(args[1]); } long delta = System.nanoTime(); closure("", maxLength); delta = (System.nanoTime() - delta)/1000000; System.out.println("took " + delta + " ms."); System.out.println("generated " + amount + " Strings."); } static void closure(String current, int workLeft) { if(workLeft < 0) return; //else //System.out.println(current); amount++; for(int i = 0; i < charset.length(); ++i) { closure((current + charset.charAt(i)), (workLeft-1)); } } }

Dold text

Med argumenten
charset = "abcdefghi"
maxLength = 9

Så tog mitt javaprogram 112s på sig att generera alla lösningar (tog bort utskrifter).
Dator i sign.

took 112322 ms. generated 435848050 Strings.

Den extra strängen är den tomma strängen, tyckte den borde vara med;)

Permalänk
Medlem

Rekursiv lösning

Behöver kartesista produkten från clojure.contrib.combinatorics (https://github.com/richhickey/clojure-contrib/blob/2ede388a92...)

(defn permutations
"Take cartesian product n times on set"
[set n]
(if (= n 1) set
(cartesian-product set (permutations set (- n 1)))))

(defn print-permutations
"Turn list into strings for sake of argument"
[set n]
(map (fn [x] (apply str (flatten x))) (permutations set n)))

Dold text

user=> (print-permutations '(a b c) 3)
("aaa" "aab" "aac" "aba" "abb" "abc" "aca" "acb" "acc" "baa" "bab" "bac" "bba" "bbb" "bbc" "bca" "bcb" "bcc" "caa" "cab" "cac" "cba" "cbb" "cbc" "cca" "ccb" "ccc")

Sämsta var att det fanns en funktion för detta redan i samma bibliotek (https://github.com/richhickey/clojure-contrib/blob/2ede388a92...) men vad gör man inte för att spendera tid.

Permalänk
Medlem

Tja försökte få ihop en LINQ variant av denna men gav upp hittade dock en väldigt intressant implementation http://stackoverflow.com/a/9637161/885860

Visa signatur

Speldator: i7-8700k, 32GB DDR4, RTX2080
Server 1: SB 2500k, MZI -P67GD55, 32GB DDR3, Corsair MX 240GB SSD
Surface Pro 2017, Konsoler: Typ alla, Oculus Rift

Permalänk
Datavetare
Skrivet av osmig:

public class HejHopp { static String charset = "abcdefghi"; static int maxLength = 9; static int amount = 0; public static void main(String[] args) { if(args.length > 0) { charset = args[0]; maxLength = Integer.parseInt(args[1]); } long delta = System.nanoTime(); closure("", maxLength); delta = (System.nanoTime() - delta)/1000000; System.out.println("took " + delta + " ms."); System.out.println("generated " + amount + " Strings."); } static void closure(String current, int workLeft) { if(workLeft < 0) return; //else //System.out.println(current); amount++; for(int i = 0; i < charset.length(); ++i) { closure((current + charset.charAt(i)), (workLeft-1)); } } }

Dold text

Med argumenten
charset = "abcdefghi"
maxLength = 9

Så tog mitt javaprogram 112s på sig att generera alla lösningar (tog bort utskrifter).
Dator i sign.

took 112322 ms. generated 435848050 Strings.

Den extra strängen är den tomma strängen, tyckte den borde vara med;)

Dold text

För att göra en exakt äpplen mot äpplen, kör jag ditt program på min maskin (i7 2600 @ 3.4GHz körandes 64-bitars Ubuntu 12.04LTS) så blev det

$ java -server HejHopp took 110495 ms. generated 435848050 Strings.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

Lyckades efter lite testade få ihop ett sql-statement som fixar problemet med en CTE (t-sql):

declare @s varchar(max) = 'abcdefg' ;with b as (select distinct SUBSTRING(@s, number+1, 1) as c from master..spt_values where type = 'P' and number < LEN(@s)), a AS ( select cast('' as varchar(max)) as c union ALL select a.c + b.c c from a cross join b where LEN(a.c) < len(@s) ) SELECT c FROM a where c != '' order by LEN(c), 1

På min ändå hyfsade dator körde den 7 tecken på 37 sek, så är väl inte den snabbaste lösningen direkt, men det trodde jag nog inte heller

Visa signatur

AK47s for everyone! - Angry mob
Since NaN /= NaN, I think, we should decipher 'NaN' as 'Not a NaN' - Miguel Mitrofanov
(Varför är människan så benägen att tro på Gud?) Antagligen har det lönat sig och evolutionen har drivit fram sådana hjärnor. - Anon